From fe563c0da424ad9c4ade1e99dc5994a556fbb795 Mon Sep 17 00:00:00 2001 From: Anton Agestam Date: Tue, 13 Dec 2022 19:47:45 +0100 Subject: [PATCH] Introduce linting with ruff --- .pre-commit-config.yaml | 19 +++---------- docs/conf.py | 6 ++-- pyproject.toml | 50 +++++++++++++++++++++++++++++++++ setup.cfg | 9 ------ src/phantom/ext/phonenumbers.py | 2 +- src/phantom/schema.py | 4 +-- src/phantom/sized.py | 12 +++++--- tests/pydantic/test_datetime.py | 12 ++++---- 8 files changed, 74 insertions(+), 40 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 23ebc21..7efe55a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,18 +23,14 @@ repos: - id: pyupgrade args: - --py37-plus - - repo: https://github.com/pycqa/autoflake - rev: "v1.7.7" - hooks: - - id: autoflake - args: - - --in-place - - --remove-all-unused-imports - - --ignore-init-module-imports - repo: https://github.com/pycqa/isort rev: "5.10.1" hooks: - id: isort + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.0.178" + hooks: + - id: ruff - repo: https://github.com/psf/black rev: "22.10.0" hooks: @@ -44,13 +40,6 @@ repos: hooks: - id: blacken-docs additional_dependencies: ["black==22.10.0"] - - repo: https://github.com/pycqa/flake8 - rev: "5.0.4" - hooks: - - id: flake8 - additional_dependencies: - - flake8-bugbear - - flake8-comprehensions - repo: https://github.com/sirosen/check-jsonschema rev: "0.19.2" hooks: diff --git a/docs/conf.py b/docs/conf.py index c2cba70..1070876 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,9 +16,9 @@ def get_copyright_from_license() -> str: - license = current_dir.parent / "LICENSE" + license_path = current_dir.parent / "LICENSE" prefix = "Copyright (c) " - for line in license.read_text().split("\n"): + for line in license_path.read_text().split("\n"): if line.startswith(prefix): return line[len(prefix) :] raise RuntimeError("Couldn't parse copyright from LICENSE") @@ -26,7 +26,7 @@ def get_copyright_from_license() -> str: # Project information project = "phantom-types" -copyright = get_copyright_from_license() +copyright = get_copyright_from_license() # noqa: A001 author = "Anton Agestam" version = phantom.__version__ release = version diff --git a/pyproject.toml b/pyproject.toml index af25266..a728676 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,3 +12,53 @@ markers = [ "external: mark tests that require extra dependencies", "no_external: mark tests that will fail if run with extra dependencies", ] + +[tool.ruff] +fix = true +target-version = "py37" +extend-select = [ + # bugbear + "B", + # comprehensions + "C4", + # mccabe + "C90", + # bandit + "S", + # blind exception + # Bare excepts are caught without this, but this also catches `except Exception: ...`. + "BLE", + # builtins + "A", + # Enforce valid noqa comments. + "RUF100", + # pycodestyle + "W", + # pyupgrade + "UP", + # debugger + "T10", + # print + "T20", + # quotes + "Q", + # return + # This gives 3 false positives, would be nice otherwise probably. + # "RET", + # simplify + "SIM", + # tidy imports + # We use this to only outlaw relative parent imports. + "TID", +] +extend-ignore = [ + # There's no reason to outlaw asserts. + # https://stackoverflow.com/a/68429294/1220706 + "S101", +] + +[tool.ruff.mccabe] +max-complexity = 8 + +[tool.ruff.flake8-tidy-imports] +ban-relative-imports = "parents" diff --git a/setup.cfg b/setup.cfg index f045f94..726db0b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -60,15 +60,6 @@ test = pytest-mypy-plugins>=1.9.3 coverage -[flake8] -exclude = appveyor,.idea,.git,.venv,.tox,__pycache__,*.egg-info,build -max-complexity = 8 -max-line-length = 88 -# B008: It's ok to instantiate instances as defaults. -# E203: Black does the right thing, flake8 doesn't. -# B024: Abstract base classes should not be expected to introduce abstract methods. -extend-ignore = E203 B008 B024 - [isort] profile = black src_paths = src, tests diff --git a/src/phantom/ext/phonenumbers.py b/src/phantom/ext/phonenumbers.py index 48bb99c..eeda442 100644 --- a/src/phantom/ext/phonenumbers.py +++ b/src/phantom/ext/phonenumbers.py @@ -42,7 +42,7 @@ def _deconstruct_phone_number( try: parsed_number = phonenumbers.parse(phone_number, region=country_code) except phonenumbers.NumberParseException as e: - raise InvalidPhoneNumber(e.error_type, e._msg) + raise InvalidPhoneNumber(e.error_type, e._msg) from e if not phonenumbers.is_valid_number(parsed_number): raise InvalidPhoneNumber return parsed_number diff --git a/src/phantom/schema.py b/src/phantom/schema.py index 18c260c..58c2cfd 100644 --- a/src/phantom/schema.py +++ b/src/phantom/schema.py @@ -9,8 +9,8 @@ class Schema(TypedDict, total=False): title: str description: str - type: Literal["array", "string", "float", "number"] - format: str + type: Literal["array", "string", "float", "number"] # noqa: A003 + format: str # noqa: A003 examples: Sequence[object] minimum: Optional[float] maximum: Optional[float] diff --git a/src/phantom/sized.py b/src/phantom/sized.py index c114c1d..78353c1 100644 --- a/src/phantom/sized.py +++ b/src/phantom/sized.py @@ -91,7 +91,11 @@ class PhantomSized( schema generation. """ - def __init_subclass__(cls, len: Predicate[int], **kwargs: Any) -> None: + def __init_subclass__( + cls, + len: Predicate[int], # noqa: A002 + **kwargs: Any, + ) -> None: super().__init_subclass__( predicate=boolean.both( is_not_known_mutable_instance, @@ -129,10 +133,10 @@ class PhantomBound( __min__: int | None __max__: int | None - def __init_subclass__( # noqa + def __init_subclass__( cls, - min: int | None = None, - max: int | None = None, + min: int | None = None, # noqa: A002 + max: int | None = None, # noqa: A002 abstract: bool = False, **kwargs: Any, ) -> None: diff --git a/tests/pydantic/test_datetime.py b/tests/pydantic/test_datetime.py index c85179c..3227193 100644 --- a/tests/pydantic/test_datetime.py +++ b/tests/pydantic/test_datetime.py @@ -19,9 +19,9 @@ class HasTZAware(pydantic.BaseModel): class TestPydanticTZAware: @parametrize_aware_str def test_can_parse_tz_aware(self, value: str, expected: datetime.datetime): - object = HasTZAware.parse_obj({"created_at": value}) - assert type(object.created_at) is datetime.datetime - assert object.created_at == expected + obj = HasTZAware.parse_obj({"created_at": value}) + assert type(obj.created_at) is datetime.datetime + assert obj.created_at == expected def test_tz_aware_rejects_naive_datetime(self): with pytest.raises(ValidationError): @@ -35,9 +35,9 @@ class HasTZNaive(pydantic.BaseModel): class TestPydanticTZNaive: @parametrize_naive_str def test_can_parse_tz_naive(self, value: str, expected: datetime.datetime): - object = HasTZNaive.parse_obj({"time_of_day": value}) - assert type(object.time_of_day) is datetime.datetime - assert object.time_of_day == expected + obj = HasTZNaive.parse_obj({"time_of_day": value}) + assert type(obj.time_of_day) is datetime.datetime + assert obj.time_of_day == expected def test_tz_naive_rejects_aware_datetime(self): with pytest.raises(ValidationError):