From fd2f76325c2d73d08fb98c2f7df45234be9417fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Avil=C3=A9s?= Date: Wed, 27 Sep 2023 04:08:23 +0200 Subject: [PATCH] Fix import errors in Python 3.9 --- src/unbeheader/config.py | 13 ++++++++----- src/unbeheader/headers.py | 9 ++++++--- src/unbeheader/typing.py | 9 ++++++--- src/unbeheader/util.py | 9 +++++++-- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/unbeheader/config.py b/src/unbeheader/config.py index cd9c1d9..f69eb8b 100644 --- a/src/unbeheader/config.py +++ b/src/unbeheader/config.py @@ -4,11 +4,13 @@ import sys from collections.abc import Iterator from pathlib import Path +from typing import TYPE_CHECKING import click import yaml -from .typing import ConfigDict +if TYPE_CHECKING: + from .typing import ConfigDict # The substring which must be part of a comment block in order for the comment to be updated by the header DEFAULT_SUBSTRING = 'This file is part of' @@ -17,7 +19,7 @@ CONFIG_FILE_NAME = '.header.yaml' -def get_config(path: Path, end_year: int) -> ConfigDict: +def get_config(path: Path, end_year: int) -> 'ConfigDict': """Get configuration from headers files.""" config = _load_config(path) _validate_config(config) @@ -26,8 +28,9 @@ def get_config(path: Path, end_year: int) -> ConfigDict: return config -def _load_config(path: Path) -> ConfigDict: - config: ConfigDict = {} +def _load_config(path: Path) -> 'ConfigDict': + # TODO: remove noqa when py3.9 is dropped + config: 'ConfigDict' = {} # noqa: UP037 (py3.9 compat) found = False for dir_path in _walk_to_root(path): check_path = dir_path / CONFIG_FILE_NAME @@ -42,7 +45,7 @@ def _load_config(path: Path) -> ConfigDict: return config -def _validate_config(config: ConfigDict) -> None: +def _validate_config(config: 'ConfigDict') -> None: valid_keys = {'owner', 'start_year', 'substring', 'template'} mandatory_keys = {'owner', 'template'} config_keys = set(config) diff --git a/src/unbeheader/headers.py b/src/unbeheader/headers.py index b20ce8d..e2fe2f2 100644 --- a/src/unbeheader/headers.py +++ b/src/unbeheader/headers.py @@ -6,15 +6,18 @@ from dataclasses import asdict from pathlib import Path from re import Pattern +from typing import TYPE_CHECKING import click from . import SUPPORTED_FILE_TYPES from .config import get_config from .typing import CommentSkeleton -from .typing import ConfigDict from .util import cformat +if TYPE_CHECKING: + from .typing import ConfigDict + def update_header(file_path: Path, year: int, check: bool = False) -> bool: """Update the header of a file.""" @@ -29,7 +32,7 @@ def update_header(file_path: Path, year: int, check: bool = False) -> bool: ) -def _do_update_header(file_path: Path, config: ConfigDict, regex: Pattern[str], comments: CommentSkeleton, +def _do_update_header(file_path: Path, config: 'ConfigDict', regex: Pattern[str], comments: CommentSkeleton, check: bool) -> bool: found = False content = orig_content = file_path.read_text() @@ -70,7 +73,7 @@ def _do_update_header(file_path: Path, config: ConfigDict, regex: Pattern[str], return True -def _generate_header(data: ConfigDict) -> str: +def _generate_header(data: 'ConfigDict') -> str: if 'start_year' not in data: data['start_year'] = data['end_year'] if data['start_year'] == data['end_year']: diff --git a/src/unbeheader/typing.py b/src/unbeheader/typing.py index 1003cc8..8089449 100644 --- a/src/unbeheader/typing.py +++ b/src/unbeheader/typing.py @@ -4,12 +4,15 @@ from dataclasses import dataclass from pathlib import Path from re import Pattern +from typing import TYPE_CHECKING from typing import Any from typing import NamedTuple -from typing import TypeAlias -ConfigDict: TypeAlias = dict[str, Any] -PathCache: TypeAlias = dict[Path, bool] +# XXX: Backwards compatibility with Python 3.9 +if TYPE_CHECKING: + from typing import TypeAlias + ConfigDict: TypeAlias = dict[str, Any] + PathCache: TypeAlias = dict[Path, bool] @dataclass diff --git a/src/unbeheader/util.py b/src/unbeheader/util.py index b918792..d71116b 100644 --- a/src/unbeheader/util.py +++ b/src/unbeheader/util.py @@ -4,10 +4,13 @@ import re from pathlib import Path from re import Match +from typing import TYPE_CHECKING +from typing import Union from colorclass import Color -from .typing import PathCache +if TYPE_CHECKING: + from .typing import PathCache # The name of the files that exclude the directory from header updates EXCLUDE_FILE_NAME = '.no-header' @@ -35,7 +38,9 @@ def repl(m: Match[str]) -> Color: return Color(string) -def is_excluded(path: Path, root_path: Path | None = None, cache: PathCache | None = None) -> bool: +# TODO: remove noqa when py3.9 is dropped +def is_excluded(path: Path, root_path: Union[Path, None] = None, # noqa: UP007 (py3.9 compat) + cache: Union['PathCache', None] = None) -> bool: # noqa: UP007 (py3.9 compat) """"Whether the path is excluded by a .no-headers file. The .no-headers file is searched for in the path and all parents up to the root.