From 772a17c8c46f9bc8d2ea276c769bba0e6d788f17 Mon Sep 17 00:00:00 2001 From: adehad <26027314+adehad@users.noreply.github.com> Date: Fri, 31 May 2024 18:11:18 +0100 Subject: [PATCH] Drop Py3.8 support, enable strict mypy and address --- .pre-commit-config.yaml | 1 + pyproject.toml | 26 +++++++-------- .../arabic_presentation_form/__init__.py | 17 ++++++---- .../arabic_presentation_form/char_map.py | 32 ++++++++++--------- src/pre_commit_hooks/check_header_footer.py | 5 +-- src/pre_commit_hooks/util.py | 15 +++++---- tests/ruff.toml | 1 + 7 files changed, 54 insertions(+), 43 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ab5ca4..f5e881d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,3 +45,4 @@ repos: - . args: [--no-strict-optional, --ignore-missing-imports, --show-error-codes] + exclude: tests/ diff --git a/pyproject.toml b/pyproject.toml index 86d408b..380bde4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,15 +6,13 @@ build-backend = "hatchling.build" name = "pre_commit_hooks" description = "A selection of pre-commit hooks for pre-commit.com." readme = "README.md" -requires-python = ">=3.8" +requires-python = ">=3.10" license = "GPL-3.0-or-later" keywords = ["pre-commit"] authors = [{ name = "adehad", email = "26027314+adehad@users.noreply.github.com" }] classifiers = [ "Development Status :: 4 - Beta", "Programming Language :: Python", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", @@ -67,19 +65,20 @@ lint = "python -m pre_commit run --color=always {args:--all-files}" # Tests ######################################################################################## [[tool.hatch.envs.test.matrix]] -python = ["38", "39", "310", "311"] +python = ["310", "311"] ######################################################################################## # External Tool Config ######################################################################################## [tool.mypy] -python_version = '3.8' +python_version = '3.10' strict = true ignore_missing_imports = true namespace_packages = true show_error_codes = true strict_optional = true warn_unused_configs = true +exclude = ["tests/"] [tool.coverage.run] branch = true @@ -89,7 +88,7 @@ omit = ["src/pre_commit_hooks/__about__.py"] [tool.coverage.report] exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"] -[tool.ruff] +[tool.ruff.lint] select = [ "E", # pycodestyle "W", # pycodestyle @@ -101,22 +100,23 @@ select = [ ] ignore = [] -# Same as Black. -line-length = 88 - # Allow unused variables when underscore-prefixed. dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" -# Assume Python 3.8. (minimum supported) -target-version = "py38" +[tool.ruff] +# Same as Black. +line-length = 88 + +# Assume Python 3.10. (minimum supported) +target-version = "py310" # The source code paths to consider, e.g., when resolving first- vs. third-party imports src = ["pre_commit_hooks", "tests"] -[tool.ruff.isort] +[tool.ruff.lint.isort] known-first-party = ["pre_commit_hooks", "tests"] required-imports = ["from __future__ import annotations"] -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] # Use Google-style docstrings. convention = "google" diff --git a/src/pre_commit_hooks/arabic_presentation_form/__init__.py b/src/pre_commit_hooks/arabic_presentation_form/__init__.py index 24e6073..7ac63fb 100644 --- a/src/pre_commit_hooks/arabic_presentation_form/__init__.py +++ b/src/pre_commit_hooks/arabic_presentation_form/__init__.py @@ -6,7 +6,8 @@ import pathlib import re import sys -from typing import Any, Dict, Sequence +from collections.abc import Sequence +from typing import Any from ..util import ( ABCArgs, @@ -17,16 +18,18 @@ ) from . import char_map -sys.stdout.reconfigure(encoding="utf-8") # For Windows: we want to be sure to use UTF-8 -RulesDict = Dict[re.Pattern[Any], str] +sys.stdout.reconfigure( # type: ignore[attr-defined] + encoding="utf-8" # For Windows: we want to be sure to use UTF-8 +) +RulesDict = dict[re.Pattern[Any], str] def apply_rules_to_lines( line: str, rules: RulesDict, - exclude: re.Pattern, - file_name: str, - line_no: str, + exclude: re.Pattern[str], + file_name: pathlib.Path | str, + line_no: str | int, ) -> tuple[ExitCode, str]: """Check the text for rules. @@ -73,7 +76,7 @@ def apply_rules_to_lines( return exit_code, new_line -def get_rules(custom_rules: dict[str, dict[str, str]]) -> RulesDict: +def get_rules(custom_rules: char_map.CHAR_MAP_TYPE) -> RulesDict: """Return the rules from a given config string. Args: diff --git a/src/pre_commit_hooks/arabic_presentation_form/char_map.py b/src/pre_commit_hooks/arabic_presentation_form/char_map.py index bd8eeb3..d5d5176 100644 --- a/src/pre_commit_hooks/arabic_presentation_form/char_map.py +++ b/src/pre_commit_hooks/arabic_presentation_form/char_map.py @@ -7,7 +7,8 @@ import enum -CHAR_MAP_TYPE = dict[str, dict[str, dict[str, str]]] +REMAP_RULE_TYPE = dict[str, dict[str, str]] +CHAR_MAP_TYPE = dict[str, REMAP_RULE_TYPE] # spell-checker: disable # ruff: noqa: E501, RUF001, RUF003 @@ -84,32 +85,33 @@ class ArabicUnicodeGroup(enum.Enum): """143 characters""" @classmethod - def get_type(cls: ArabicUnicodeGroup, input_char: str) -> ArabicUnicodeGroup: + def get_type(cls: type[ArabicUnicodeGroup], input_char: str) -> ArabicUnicodeGroup: """Return the Arabic Unicode Group.""" + unicode_group = cls.Unknown if "\u0600" <= input_char <= "\u06ff": - return cls.Arabic + unicode_group = cls.Arabic elif "\u0750" <= input_char <= "\u077f": - return cls.ArabicSupplement + unicode_group = cls.ArabicSupplement elif "\u0870" <= input_char <= "\u089f": - return cls.ArabicExtendedB + unicode_group = cls.ArabicExtendedB elif "\u08a0" <= input_char <= "\u08ff": - return cls.ArabicExtendedA + unicode_group = cls.ArabicExtendedA elif "\ufb50" <= input_char <= "\ufdff": - return cls.ArabicPresentationFormsA + unicode_group = cls.ArabicPresentationFormsA elif "\ufe70" <= input_char <= "\ufeff": - return cls.ArabicPresentationFormsB + unicode_group = cls.ArabicPresentationFormsB elif "\u10e60" <= input_char <= "\u10e7F": - return cls.RumiNumeralSymbols + unicode_group = cls.RumiNumeralSymbols elif "\u10ec0" <= input_char <= "\u10efF": - return cls.ArabicExtendedC + unicode_group = cls.ArabicExtendedC elif "\u1ec70" <= input_char <= "\u1ecbF": - return cls.IndicSiyaqNumbers + unicode_group = cls.IndicSiyaqNumbers elif "\u1ed00" <= input_char <= "\u1ed4F": - return cls.OttomanSiyaqNumbers + unicode_group = cls.OttomanSiyaqNumbers elif "\u1ee00" <= input_char <= "\u1eefF": - return cls.ArabicMathematicalAlphabeticSymbols - else: - return cls.Unknown + unicode_group = cls.ArabicMathematicalAlphabeticSymbols + + return unicode_group def is_contains_non_general_form(char: str) -> bool: diff --git a/src/pre_commit_hooks/check_header_footer.py b/src/pre_commit_hooks/check_header_footer.py index a1a2c46..a7c6a45 100644 --- a/src/pre_commit_hooks/check_header_footer.py +++ b/src/pre_commit_hooks/check_header_footer.py @@ -7,7 +7,8 @@ import json import pathlib import re -from typing import Any, Dict, NamedTuple, Sequence +from collections.abc import Sequence +from typing import Any, NamedTuple from .util import ( ABCArgs, @@ -17,7 +18,7 @@ sanitize_rb_line, ) -RulesDict = Dict[str, re.Pattern[Any]] +RulesDict = dict[str, re.Pattern[Any]] def check_rules_in_file( diff --git a/src/pre_commit_hooks/util.py b/src/pre_commit_hooks/util.py index 5c4b45e..68db788 100644 --- a/src/pre_commit_hooks/util.py +++ b/src/pre_commit_hooks/util.py @@ -9,7 +9,9 @@ import json import os import pathlib -from typing import Any, Sequence +import typing +from collections.abc import Sequence +from typing import Any class ExitCode(enum.IntEnum): @@ -108,21 +110,22 @@ def load_json_source(file_or_json_str: str) -> dict[str, Any]: Returns: dict[str, Any]: Loaded JSON. """ + default: dict[str, Any] = {} file_source = pathlib.Path(file_or_json_str) if file_source.is_file(): with file_source.open(encoding="utf-8") as fp: - return json.load(fp) + return typing.cast(dict[str, Any], json.load(fp)) try: - return json.loads(file_or_json_str) + return json.loads(file_or_json_str) # type: ignore[no-any-return] except Exception: print("Unsupported JSON source, no custom rules applied!") - return {} + return default -class HashableDict(dict): +class HashableDict(dict): # type: ignore[type-arg] """Hashable dict but not immutable.""" - def __hash__(self) -> int: + def __hash__(self) -> int: # type: ignore[override] """Hash.""" return hash((frozenset(self), frozenset(self.values()))) diff --git a/tests/ruff.toml b/tests/ruff.toml index ffb16fb..36aac9b 100644 --- a/tests/ruff.toml +++ b/tests/ruff.toml @@ -1,4 +1,5 @@ extend = "../pyproject.toml" +[lint] ignore = [ "D", # Allow undocumented test functions ]