Skip to content

Commit

Permalink
Move mypy configuration to pyproject.toml from setup.cfg (#1344)
Browse files Browse the repository at this point in the history
* Move mypy configuration to pyproject.toml from setup.cfg

* Fix mypy GitHub Action to directly call mypy
  • Loading branch information
tleonhardt authored Oct 23, 2024
1 parent ad1f0d6 commit e9e232f
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 45 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/mypy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ jobs:
# Only a single commit is fetched by default, for the ref/SHA that triggered the workflow.
# Set fetch-depth: 0 to fetch all history for all branches and tags.
fetch-depth: 0 # Needed for setuptools_scm to work correctly
- run: pip install -U --user pip setuptools setuptools-scm nox
- run: python -m nox --non-interactive --session validate-3.13 -k mypy # Run nox for mypy
- run: pip install -U --user pip mypy
- run: mypy .
7 changes: 0 additions & 7 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,3 @@ def tests(session, plugin):
'--no-pty',
'--append-cov',
)


@nox.session(python=['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'])
@nox.parametrize('step', ['mypy', 'flake8'])
def validate(session, step):
session.install('invoke', './[validate]')
session.run('invoke', step)
194 changes: 194 additions & 0 deletions plugins/ext_test/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
[build-system]
requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4"]

[tool.mypy]
disallow_incomplete_defs = true
disallow_untyped_calls = true
disallow_untyped_defs = true
exclude = [
"^examples/", # examples directory
"^noxfile\\.py$", # nox config file
"setup\\.py$", # any files named setup.py
"^tasks\\.py$", # tasks.py invoke config file
"^tests/", # tests directory
]
show_column_numbers = true
show_error_codes = true
show_error_context = true
strict = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
warn_unused_ignores = false

[tool.ruff]
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]

# Same as Black.
line-length = 127
indent-width = 4

# Assume Python 3.13
target-version = "py313"
output-format = "full"

[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = [
# https://beta.ruff.rs/docs/rules
# "A", # flake8-builtins
# "ANN", # flake8-annotations
# "ARG", # flake8-unused-arguments
"ASYNC", # flake8-async
# "B", # flake8-bugbear
# "BLE", # flake8-blind-except
# "C4", # flake8-comprehensions
"C90", # McCabe cyclomatic complexity
# "COM", # flake8-commas
# "D", # pydocstyle
"DJ", # flake8-django
# "DTZ", # flake8-datetimez
"E", # pycodestyle
# "EM", # flake8-errmsg
# "ERA", # eradicate
# "EXE", # flake8-executable
"F", # Pyflakes
"FA", # flake8-future-annotations
# "FBT", # flake8-boolean-trap
"G", # flake8-logging-format
# "I", # isort
"ICN", # flake8-import-conventions
# "INP", # flake8-no-pep420
"INT", # flake8-gettext
# "ISC", # flake8-implicit-str-concat
# "N", # pep8-naming
"NPY", # NumPy-specific rules
"PD", # pandas-vet
# "PGH", # pygrep-hooks
# "PIE", # flake8-pie
# "PL", # Pylint
# "PT", # flake8-pytest-style
# "PTH", # flake8-use-pathlib
# "PYI", # flake8-pyi
# "RET", # flake8-return
"RSE", # flake8-raise
# "Q", # flake8-quotes
# "RUF", # Ruff-specific rules
# "S", # flake8-bandit
# "SIM", # flake8-simplify
# "SLF", # flake8-self
# "T10", # flake8-debugger
# "T20", # flake8-print
# "TCH", # flake8-type-checking
# "TD", # flake8-todos
# "TID", # flake8-tidy-imports
# "TRY", # tryceratops
# "UP", # pyupgrade
# "W", # pycodestyle
# "YTT", # flake8-2020
]
ignore = [
# `ruff rule S101` for a description of that rule
"B904", # Within an `except` clause, raise exceptions with `raise ... from err` -- FIX ME
"B905", # `zip()` without an explicit `strict=` parameter -- FIX ME
"E501", # Line too long
"EM101", # Exception must not use a string literal, assign to variable first
"EXE001", # Shebang is present but file is not executable -- DO NOT FIX
"G004", # Logging statement uses f-string
"PLC1901", # `{}` can be simplified to `{}` as an empty string is falsey
"PLW060", # Using global for `{name}` but no assignment is done -- DO NOT FIX
"PLW2901", # PLW2901: Redefined loop variable -- FIX ME
"PT011", # `pytest.raises(Exception)` is too broad, set the `match` parameter or use a more specific exception
"PT018", # Assertion should be broken down into multiple parts
"S101", # Use of `assert` detected -- DO NOT FIX
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes -- FIX ME
"SLF001", # Private member accessed: `_Iterator` -- FIX ME
"UP038", # Use `X | Y` in `{}` call instead of `(X, Y)` -- DO NOT FIX
]

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

mccabe.max-complexity = 49

per-file-ignores."cmd2/__init__.py" = [
"E402", # Module level import not at top of file
"F401", # Unused import
]

per-file-ignores."docs/conf.py" = [
"F401", # Unused import
]

per-file-ignores."examples/override_parser.py" = [
"E402", # Module level import not at top of file
]

per-file-ignores."examples/scripts/*.py" = [
"F821", # Undefined name `app`
]

per-file-ignores."tests/pyscript/*.py" = [
"F821", # Undefined name `app`
]

[tool.ruff.format]
# Like Black, use double quotes for strings.
quote-style = "preserve"

# Like Black, indent with spaces, rather than tabs.
indent-style = "space"

# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false

# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"

# Enable auto-formatting of code examples in docstrings. Markdown,
# reStructuredText code/literal blocks and doctests are all supported.
#
# This is currently disabled by default, but it is planned for this
# to be opt-out in the future.
docstring-code-format = false

# Set the line length limit used when formatting code snippets in
# docstrings.
#
# This only has an effect when the `docstring-code-format` setting is
# enabled.
docstring-code-line-length = "dynamic"
26 changes: 16 additions & 10 deletions plugins/ext_test/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ def pytest_clean(context):
def mypy(context):
"""Run mypy optional static type checker"""
with context.cd(TASK_ROOT_STR):
context.run("mypy cmd2_ext_test")
namespace.add_task(mypy)
context.run("mypy .")


namespace.add_task(mypy)
Expand Down Expand Up @@ -194,15 +193,22 @@ def pypi_test(context):
namespace.add_task(pypi_test)


# Flake8 - linter and tool for style guide enforcement and linting
# ruff fast linter
@invoke.task
def flake8(context):
"""Run flake8 linter and tool for style guide enforcement"""
def lint(context):
"""Run ruff fast linter"""
with context.cd(TASK_ROOT_STR):
context.run(
"flake8 --ignore=E252,W503 --max-complexity=26 --max-line-length=127 --show-source --statistics "
"--exclude=.git,__pycache__,.tox,.nox,.eggs,*.egg,.venv,.idea,.pytest_cache,.vscode,build,dist,htmlcov"
)
context.run("ruff check")


namespace.add_task(flake8)
namespace.add_task(lint)


@invoke.task
def format(context):
"""Run ruff format --check"""
with context.cd(TASK_ROOT_STR):
context.run("ruff format --check")


namespace.add_task(format)
28 changes: 22 additions & 6 deletions plugins/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
- setuptools >= 39.1.0
"""

import pathlib

import invoke

from plugins.ext_test import (
Expand All @@ -32,6 +34,9 @@
#
#####

TASK_ROOT = pathlib.Path(__file__).resolve().parent
TASK_ROOT_STR = str(TASK_ROOT)


@invoke.task(pre=[ext_test_tasks.pytest])
@invoke.task()
Expand Down Expand Up @@ -130,11 +135,22 @@ def wheel(_):
namespace.add_task(wheel)


# Flake8 - linter and tool for style guide enforcement and linting
@invoke.task(pre=[ext_test_tasks.flake8])
def flake8(_):
"""Run flake8 linter and tool for style guide enforcement"""
pass
# ruff linter
@invoke.task(pre=[ext_test_tasks.lint])
def lint(context):
with context.cd(TASK_ROOT_STR):
context.run("ruff check")


namespace.add_task(lint)


# ruff formatter
@invoke.task(pre=[ext_test_tasks.format])
def format(context):
"""Run formatter"""
with context.cd(TASK_ROOT_STR):
context.run("ruff format --check")


namespace.add_task(flake8)
namespace.add_task(format)
23 changes: 23 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,29 @@ ignore-path = [
max-line-length = 120
verbose = 0

[tool.mypy]
disallow_incomplete_defs = true
disallow_untyped_calls = true
disallow_untyped_defs = true
exclude = [
"^docs/", # docs directory
"^examples/", # examples directory
"^plugins/*", # plugins directory
"^noxfile\\.py$", # nox config file
"setup\\.py$", # any files named setup.py
"^tasks\\.py$", # tasks.py invoke config file
"^tests/", # tests directory
"^tests_isolated/" # tests_isolated directory
]
show_column_numbers = true
show_error_codes = true
show_error_context = true
strict = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
warn_unused_ignores = false

[tool.ruff]
# Exclude a variety of commonly ignored directories.
exclude = [
Expand Down
13 changes: 0 additions & 13 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,3 @@ addopts =
--cov-append
--cov-report=term
--cov-report=html

[mypy]
disallow_incomplete_defs = True
disallow_untyped_defs = True
disallow_untyped_calls = True
warn_redundant_casts = True
warn_unused_ignores = False
warn_return_any = True
warn_unreachable = True
strict = True
show_error_context = True
show_column_numbers = True
show_error_codes = True
12 changes: 5 additions & 7 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,17 @@ def pytest_clean(context):
namespace_clean.add_task(pytest_clean, 'pytest')


@invoke.task(post=[plugin_tasks.mypy])
@invoke.task()
def mypy(context):
"""Run mypy optional static type checker"""
with context.cd(TASK_ROOT_STR):
context.run("mypy cmd2")
with context.cd(str(TASK_ROOT / 'examples')):
context.run("mypy decorator_example.py")
context.run("mypy .")


namespace.add_task(mypy)


@invoke.task(post=[plugin_tasks.mypy_clean])
@invoke.task()
def mypy_clean(context):
"""Remove mypy cache directory"""
# pylint: disable=unused-argument
Expand Down Expand Up @@ -348,7 +346,7 @@ def pypi_test(context):


# ruff fast linter
@invoke.task(post=[plugin_tasks.flake8])
@invoke.task()
def lint(context):
"""Run ruff fast linter"""
with context.cd(TASK_ROOT_STR):
Expand All @@ -361,7 +359,7 @@ def lint(context):
# ruff fast formatter
@invoke.task()
def format(context):
"""Run ruff format --checkt"""
"""Run ruff format --check"""
with context.cd(TASK_ROOT_STR):
context.run("ruff format --check")

Expand Down

0 comments on commit e9e232f

Please sign in to comment.