From d75ee44066973164b66142f9fdb4a07bf6c3950b Mon Sep 17 00:00:00 2001 From: Joe Lynch Date: Fri, 27 Sep 2024 11:17:19 +0000 Subject: [PATCH 1/2] Migrate mypy to pyproject.toml * Bump mypy version * Use pydantic.v1 mypy plugin --- astacus/common/progress.py | 3 +- mypy.ini | 94 -------------------------------------- pyproject.toml | 43 ++++++++++++++++- 3 files changed, 44 insertions(+), 96 deletions(-) delete mode 100644 mypy.ini diff --git a/astacus/common/progress.py b/astacus/common/progress.py index ef95e815..1866e932 100644 --- a/astacus/common/progress.py +++ b/astacus/common/progress.py @@ -59,7 +59,8 @@ def wrap(self, i: Sequence[T]) -> Iterator[T]: self.add_total(len(i)) except TypeError: # Can't compute progress for this iterator - return i + yield from i + return None for item in i: yield item diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index c4aa7244..00000000 --- a/mypy.ini +++ /dev/null @@ -1,94 +0,0 @@ -[mypy] -python_version = 3.11 -plugins = pydantic.mypy -exclude = (?x)( - ^setup.py - | ^vendor/ - | ^venv/ - | ^astacus/proto/ - ) - -show_error_codes = True - -# Dead code is bad -warn_unreachable = True - -# Re-export is bit bad - __all__ should be used if we really want re-export -no_implicit_reexport = True - -# casting is bad, unnecessary casting worse -warn_redundant_casts = True - -# unused type disables are confusing -warn_unused_ignores = True - -# Replacing typing with non-typing is bad -# (This is quite painful to do though, TBD later) -#disallow_untyped_decorators = True - -# Any subclassing is probably an error -disallow_subclassing_any = true - -# This codebase should be typed -#disallow_incomplete_defs = true -#disallow_untyped_defs = true - -# configure pydantic.mypy plugin -[pydantic-mypy] - -# even if Config.extra != forbid, prevent extra args -init_forbid_extra = True - -# validate types on __init__, do not go for type coercion -init_typed = True - -# We don't want use of indirect population without explicit alias -warn_required_dynamic_aliases=True - -# We want types for all fields -# (but some hacks like validators do not work with this well, sadly) -#warn_untyped_fields=True - - -# Ignores start here (toml format would be nicer but guess this works) - -[mypy-astacus.proto.*] -ignore_errors = True - -[mypy-cassandra.*] -ignore_missing_imports = True - -[mypy-google.protobuf.*] -ignore_errors = True - -[mypy-graphlib.*] -ignore_missing_imports = True - -# types-kazoo does not unfortunately fix this -[mypy-kazoo.*] -ignore_missing_imports = True - -# httpcore dependency -[mypy-h11.*] -ignore_missing_imports = True - -[mypy-systemd.*] -ignore_missing_imports = True - -# uvicorn has types starting version 0.19, but we are using 0.15 -[mypy-uvicorn.*] -ignore_missing_imports = True - -# TBD: When someone has time, implement these for whole codebase - -[mypy-astacus.common.cassandra.*] -disallow_incomplete_defs = true -disallow_untyped_defs = true - -[mypy-astacus.coordinator.plugins.cassandra.*] -disallow_incomplete_defs = true -disallow_untyped_defs = true - -[mypy-astacus.node.cassandra] -disallow_incomplete_defs = true -disallow_untyped_defs = true diff --git a/pyproject.toml b/pyproject.toml index b465e003..de6c3b52 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ classifiers=[ "Intended Audience :: System Administrators", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Database :: Database Engines/Servers", "Topic :: Software Development :: Libraries", ] @@ -101,7 +102,7 @@ dev = [ "pytest-timeout==2.1.0", "pytest-watch==4.2.0", "pytest==7.2.2", - "mypy==1.9.0", + "mypy==1.11.2", # Types for things that don't seem to have them "types-botocore>=1.0.2", "types-PyYAML>=6.0.12.2", @@ -148,3 +149,43 @@ source = [ "astacus", "tests" ] + +[tool.mypy] +python_version = "3.12" +plugins = [ + "pydantic.v1.mypy", + "pydantic.mypy", +] +exclude = [ + "setup.py", + "vendor/", + "venv/", + "astacus/proto/", +] +show_error_codes = true +warn_unreachable = true +no_implicit_reexport = true +warn_redundant_casts = true +warn_unused_ignores = true +disallow_subclassing_any = true + +[tool.pydantic-mypy] +# even if Config.extra != forbid, prevent extra args +init_forbid_extra = true +# validate types on __init__, do not go for type coercion +init_typed = true +# We don't want use of indirect population without explicit alias +warn_required_dynamic_aliases = true + +[[tool.mypy.overrides]] +module = "cassandra.*,graphlib,kazoo.*,systemd" +ignore_missing_imports = true + +[[tool.mypy.overrides]] +module = "google.protobuf" +ignore_errors = true + +[[tool.mypy.overrides]] +module = "astacus.common.cassandra,astacus.coordinator.cassandra,astacus.node.cassandra" +disallow_incomplete_defs = true +disallow_untyped_defs = true From 3d89db7339b6c75512aeadbb78fb4404c3892973 Mon Sep 17 00:00:00 2001 From: Joe Lynch Date: Wed, 2 Oct 2024 08:40:17 +0000 Subject: [PATCH 2/2] Put mypy and pytest config in pyproject.toml Consolidates tool configuration in a single place (and single format). --- .pre-commit-config.yaml | 1 - pyproject.toml | 133 +++++++++++++++++++++++++++++++++-- ruff.toml | 151 ---------------------------------------- tox.ini | 11 --- 4 files changed, 129 insertions(+), 167 deletions(-) delete mode 100644 ruff.toml delete mode 100644 tox.ini diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 242d7ac7..a2ef6e93 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,6 @@ repos: hooks: # Run the formatter. - id: ruff-format - args: [--config=ruff.toml] - repo: https://github.com/timothycrosley/isort rev: 5.12.0 diff --git a/pyproject.toml b/pyproject.toml index de6c3b52..c6230cb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -152,10 +152,7 @@ source = [ [tool.mypy] python_version = "3.12" -plugins = [ - "pydantic.v1.mypy", - "pydantic.mypy", -] +plugins = ["pydantic.mypy"] exclude = [ "setup.py", "vendor/", @@ -189,3 +186,131 @@ ignore_errors = true module = "astacus.common.cassandra,astacus.coordinator.cassandra,astacus.node.cassandra" disallow_incomplete_defs = true disallow_untyped_defs = true + +[tool.ruff] +target-version = "py311" +line-length = 125 +force-exclude = true + +[tool.ruff.lint] +# A list of rule codes or prefixes to enable, in addition to those specified by 'select'. +extend-select = [ + # flake8-bugbear + # mutable-argument-default - Do not use mutable data structures for argument defaults. + "B006", + # pydocstyle + "D", + # flake8-datetimez + "DTZ", + # pycodestyle + "E", + # pyflakes + "F", + # flake8-logging-format + # logging-warn - Logging statement uses warn instead of warning. + "G010", + # isort + "I", + # flake8-no-pep420 + "INP", + # flake8-pytest-style + "PT", + # Ruff-specific rules + # explicit-f-string-type-conversion - Use explicit conversion flag. + "RUF010", + # unused-noqa - Unused 'noqa' directive. + "RUF100", + # flake8-tidy-imports + "TID", + # pyupgrade + "UP", + # Open file with context handler. + "SIM115", +] +# A list of rule codes or prefixes to ignore. +ignore = [ + # pydocstyle + # undocumented-public-module - Missing docstring in public module. + "D100", + # undocumented-public-class - Missing docstring in public class. + "D101", + # undocumented-public-method - Missing docstring in public method. + "D102", + # undocumented-public-function - Missing docstring in public function. + "D103", + # undocumented-public-package - Missing docstring in public package. + "D104", + # undocumented-magic-method - Missing docstring in magic method. + "D105", + # undocumented-public-nested-class - Missing docstring in public nested class. + "D106", + # undocumented-public-init - Missing docstring in __init__. + "D107", + # one-blank-line-before-class - 1 blank line required before class docstring. + # This configuration can't be enabled as it's incompatible with 'D211' (no-blank-line-before-class). + "D203", + # blank-line-after-summary - 1 blank line required between summary line and description. + # This configuration can't be enabled because automatic fix available is minimal. + "D205", + # non-imperative-mood - First line of docstring should be in imperative mood: "{first_line}". + "D401", + # one-blank-line-after-class - 1 blank line required after class docstring. + "D402", + # docstring-starts-with-this - First word of the docstring should not be "This". + "D404", + # multi-line-summary-second-line - Multi-line docstring summary should start at the second line. + # This configuration can't be enabled as it's incompatible with 'D212' (multi-line-summary-first-line). + "D213", + # undocumented-param - Missing argument description in the docstring for {definition}: {name}. + "D417", + # pycodestyle + # bare-except - Do not use bare except. + "E722", + # line-too-long - Line too long ({width} > {limit}). + "E501", + # flake8-pytest-style + # pytest-missing-fixture-name-underscore - Fixture '{function}' does not return anything, add leading underscore. + "PT004", + # pytest-incorrect-fixture-name-underscore - Fixture '{function}' returns a value, remove leading underscore. + "PT005", + # pytest-parametrize-values-wrong-type - Wrong values type in '@pytest.mark.parametrize' expected '{values}' of '{row}'. + "PT007", + # pytest-raises-too-broad - 'pytest.raises({exception})' is too broad, set the 'match' parameter or use a more specific exception. + "PT011", + # pytest-raises-with-multiple-statements - 'pytest.raises()' block should contain a single simple statement. + "PT012", + # pytest-incorrect-pytest-import - Found incorrect import of pytest, use simple 'import pytest' instead. + "PT013", + # pytest-assert-in-except - Found assertion on exception '{name}' in 'except' block, use 'pytest.raises()' instead. + "PT017", + # pytest-fixture-param-without-value - Fixture '{name}' without value is injected as parameter, use '@pytest.mark.usefixtures' instead. + "PT019", + # pyupgrade + # printf-string-formatting - Use format specifiers instead of percent format. + "UP031", + # f-string - Use f-string instead of 'format' call. + # This configuration can't be enabled since certain operations in f-strings are forbidden. + # For further details, refer to: 'ci/check_string_formats.py'. + "UP032", +] +# A list of rule codes or prefixes for which unsafe fixes should be considered safe. +extend-safe-fixes = [ + # pydocstyle + "D" +] + +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.ruff.lint.isort] +# Combines as imports on the same line. +combine-as-imports = true +# Whether to place import from imports before straight imports when sorting. +from-first = true +# The number of lines to place between "direct" and 'import from' imports. +lines-between-types = 1 +# Put all imports into the same section bucket. +# This configuration breaks the Python convention. +no-sections = true +# Order imports by type, which is determined by case, in addition to alphabetically. +order-by-type = false diff --git a/ruff.toml b/ruff.toml deleted file mode 100644 index 6acd18e6..00000000 --- a/ruff.toml +++ /dev/null @@ -1,151 +0,0 @@ -# This is a configuration file for Ruff, a Python linter and code formatter. -# It specifies the target Python version, line length, exclusion rules, and linting/formatting options, among others. - -# For more information about how Ruff is configured, refer to: -# https://docs.astral.sh/ruff/configuration/ - -# For a complete enumeration of the available configuration options, refer to: -# https://docs.astral.sh/ruff/settings/ - -# For a complete enumeration of the available rule set, refer to: -# https://docs.astral.sh/ruff/rules/ - -# The minimum Python version to target, e.g., when considering automatic code upgrades, like rewriting type annotations. -target-version = "py311" - -# The line length to use when enforcing long-lines violations (like 'E501') and at which isort and the formatter prefers to wrap lines. -line-length = 125 - -# Whether to enforce 'exclude' and 'extend-exclude' patterns, even for paths that are passed to Ruff explicitly. -force-exclude = true - -[lint] - -# A list of rule codes or prefixes to enable, in addition to those specified by 'select'. -extend-select = [ - # flake8-bugbear - # mutable-argument-default - Do not use mutable data structures for argument defaults. - "B006", - # pydocstyle - "D", - # flake8-datetimez - "DTZ", - # pycodestyle - "E", - # pyflakes - "F", - # flake8-logging-format - # logging-warn - Logging statement uses warn instead of warning. - "G010", - # isort - "I", - # flake8-no-pep420 - "INP", - # flake8-pytest-style - "PT", - # Ruff-specific rules - # explicit-f-string-type-conversion - Use explicit conversion flag. - "RUF010", - # unused-noqa - Unused 'noqa' directive. - "RUF100", - # flake8-tidy-imports - "TID", - # pyupgrade - "UP", - # Open file with context handler. - "SIM115", -] - -# A list of rule codes or prefixes to ignore. -ignore = [ - # pydocstyle - # undocumented-public-module - Missing docstring in public module. - "D100", - # undocumented-public-class - Missing docstring in public class. - "D101", - # undocumented-public-method - Missing docstring in public method. - "D102", - # undocumented-public-function - Missing docstring in public function. - "D103", - # undocumented-public-package - Missing docstring in public package. - "D104", - # undocumented-magic-method - Missing docstring in magic method. - "D105", - # undocumented-public-nested-class - Missing docstring in public nested class. - "D106", - # undocumented-public-init - Missing docstring in __init__. - "D107", - # one-blank-line-before-class - 1 blank line required before class docstring. - # This configuration can't be enabled as it's incompatible with 'D211' (no-blank-line-before-class). - "D203", - # blank-line-after-summary - 1 blank line required between summary line and description. - # This configuration can't be enabled because automatic fix available is minimal. - "D205", - # non-imperative-mood - First line of docstring should be in imperative mood: "{first_line}". - "D401", - # one-blank-line-after-class - 1 blank line required after class docstring. - "D402", - # docstring-starts-with-this - First word of the docstring should not be "This". - "D404", - # multi-line-summary-second-line - Multi-line docstring summary should start at the second line. - # This configuration can't be enabled as it's incompatible with 'D212' (multi-line-summary-first-line). - "D213", - # undocumented-param - Missing argument description in the docstring for {definition}: {name}. - "D417", - # pycodestyle - # bare-except - Do not use bare except. - "E722", - # line-too-long - Line too long ({width} > {limit}). - "E501", - # flake8-pytest-style - # pytest-missing-fixture-name-underscore - Fixture '{function}' does not return anything, add leading underscore. - "PT004", - # pytest-incorrect-fixture-name-underscore - Fixture '{function}' returns a value, remove leading underscore. - "PT005", - # pytest-parametrize-values-wrong-type - Wrong values type in '@pytest.mark.parametrize' expected '{values}' of '{row}'. - "PT007", - # pytest-raises-too-broad - 'pytest.raises({exception})' is too broad, set the 'match' parameter or use a more specific exception. - "PT011", - # pytest-raises-with-multiple-statements - 'pytest.raises()' block should contain a single simple statement. - "PT012", - # pytest-incorrect-pytest-import - Found incorrect import of pytest, use simple 'import pytest' instead. - "PT013", - # pytest-assert-in-except - Found assertion on exception '{name}' in 'except' block, use 'pytest.raises()' instead. - "PT017", - # pytest-fixture-param-without-value - Fixture '{name}' without value is injected as parameter, use '@pytest.mark.usefixtures' instead. - "PT019", - # pyupgrade - # printf-string-formatting - Use format specifiers instead of percent format. - "UP031", - # f-string - Use f-string instead of 'format' call. - # This configuration can't be enabled since certain operations in f-strings are forbidden. - # For further details, refer to: 'ci/check_string_formats.py'. - "UP032", -] - -# A list of rule codes or prefixes for which unsafe fixes should be considered safe. -extend-safe-fixes = [ - # pydocstyle - "D" -] - -[lint.pydocstyle] -convention = "google" - -[lint.isort] - -# Combines as imports on the same line. -combine-as-imports = true - -# Whether to place import from imports before straight imports when sorting. -from-first = true - -# The number of lines to place between "direct" and 'import from' imports. -lines-between-types = 1 - -# Put all imports into the same section bucket. -# This configuration breaks the Python convention. -no-sections = true - -# Order imports by type, which is determined by case, in addition to alphabetically. -order-by-type = false diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 98e0f5a9..00000000 --- a/tox.ini +++ /dev/null @@ -1,11 +0,0 @@ -[tox] -envlist = py311 - - -[testenv] -deps = - -Ur{toxinidir}/requirements.testing.txt - pytest-cov - -commands = - py.test