From f9f460c0314c5697ad08d3ec2f5bdb20f04cfdc1 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 24 May 2025 22:02:30 -0400 Subject: [PATCH] Enable ruff ANN ruleset to warn about missing type annotations for arguments and return values However, globally disabled rule ANN401 which disallows use of `typing.Any` because that is just too strict for now. --- cmd2/utils.py | 2 +- pyproject.toml | 3 ++- tasks.py | 46 ++++++++++++++++++++++++---------------------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/cmd2/utils.py b/cmd2/utils.py index 6ac6b3be..a520b417 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -150,7 +150,7 @@ def __init__( """ if val_type is bool: - def get_bool_choices(_) -> list[str]: # type: ignore[no-untyped-def] + def get_bool_choices(_: str) -> list[str]: """Used to tab complete lowercase boolean values.""" return ['true', 'false'] diff --git a/pyproject.toml b/pyproject.toml index a3f7e9f0..4066cf20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -158,7 +158,7 @@ select = [ # https://docs.astral.sh/ruff/rules "A", # flake8-builtins (variables or arguments shadowing built-ins) # "AIR", # Airflow specific warnings - # "ANN", # flake8-annotations (missing type annotations for arguments or return types) + "ANN", # flake8-annotations (missing type annotations for arguments or return types) # "ARG", # flake8-unused-arguments (functions or methods with arguments that are never used) "ASYNC", # flake8-async (async await bugs) # "B", # flake8-bugbear (various likely bugs and design issues) @@ -222,6 +222,7 @@ select = [ ] ignore = [ # `uv run ruff rule E501` for a description of that rule + "ANN401", # Dynamically typed expressions (typing.Any) are disallowed (would be good to enable this later) "COM812", # Conflicts with ruff format (see https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules) "COM819", # Conflicts with ruff format "D206", # Conflicts with ruff format diff --git a/tasks.py b/tasks.py index e0163c03..74b8b210 100644 --- a/tasks.py +++ b/tasks.py @@ -12,8 +12,10 @@ import re import shutil import sys +from typing import Union import invoke +from invoke.context import Context from plugins import ( tasks as plugin_tasks, @@ -24,7 +26,7 @@ # shared function -def rmrf(items, verbose=True) -> None: +def rmrf(items: Union[str, list[str], set[str]], verbose: bool = True) -> None: """Silently remove a list of directories or files.""" if isinstance(items, str): items = [items] @@ -51,7 +53,7 @@ def rmrf(items, verbose=True) -> None: @invoke.task() -def pytest(context, junit=False, pty=True, base=False, isolated=False) -> None: +def pytest(context: Context, junit: bool = False, pty: bool = True, base: bool = False, isolated: bool = False) -> None: """Run tests and code coverage using pytest.""" with context.cd(TASK_ROOT_STR): command_str = 'pytest ' @@ -79,7 +81,7 @@ def pytest(context, junit=False, pty=True, base=False, isolated=False) -> None: @invoke.task(post=[plugin_tasks.pytest_clean]) -def pytest_clean(context) -> None: +def pytest_clean(context: Context) -> None: """Remove pytest cache and code coverage files and directories.""" # pylint: disable=unused-argument with context.cd(str(TASK_ROOT / 'tests')): @@ -92,7 +94,7 @@ def pytest_clean(context) -> None: @invoke.task() -def mypy(context) -> None: +def mypy(context: Context) -> None: """Run mypy optional static type checker.""" with context.cd(TASK_ROOT_STR): context.run("mypy .") @@ -102,7 +104,7 @@ def mypy(context) -> None: @invoke.task() -def mypy_clean(context) -> None: +def mypy_clean(context: Context) -> None: """Remove mypy cache directory.""" # pylint: disable=unused-argument with context.cd(TASK_ROOT_STR): @@ -123,7 +125,7 @@ def mypy_clean(context) -> None: @invoke.task() -def docs(context, builder='html') -> None: +def docs(context: Context, builder: str = 'html') -> None: """Build documentation using MkDocs.""" with context.cd(TASK_ROOT_STR): context.run('mkdocs build', pty=True) @@ -133,7 +135,7 @@ def docs(context, builder='html') -> None: @invoke.task -def docs_clean(context) -> None: +def docs_clean(context: Context) -> None: """Remove rendered documentation.""" # pylint: disable=unused-argument with context.cd(TASK_ROOT_STR): @@ -144,7 +146,7 @@ def docs_clean(context) -> None: @invoke.task -def livehtml(context) -> None: +def livehtml(context: Context) -> None: """Launch webserver on http://localhost:8000 with rendered documentation.""" with context.cd(TASK_ROOT_STR): context.run('mkdocs serve', pty=True) @@ -163,7 +165,7 @@ def livehtml(context) -> None: @invoke.task(post=[plugin_tasks.build_clean]) -def build_clean(context) -> None: +def build_clean(context: Context) -> None: """Remove the build directory.""" # pylint: disable=unused-argument with context.cd(TASK_ROOT_STR): @@ -174,7 +176,7 @@ def build_clean(context) -> None: @invoke.task(post=[plugin_tasks.dist_clean]) -def dist_clean(context) -> None: +def dist_clean(context: Context) -> None: """Remove the dist directory.""" # pylint: disable=unused-argument with context.cd(TASK_ROOT_STR): @@ -185,7 +187,7 @@ def dist_clean(context) -> None: @invoke.task() -def eggs_clean(context) -> None: +def eggs_clean(context: Context) -> None: """Remove egg directories.""" # pylint: disable=unused-argument with context.cd(TASK_ROOT_STR): @@ -203,7 +205,7 @@ def eggs_clean(context) -> None: @invoke.task() -def pycache_clean(context) -> None: +def pycache_clean(context: Context) -> None: """Remove __pycache__ directories.""" # pylint: disable=unused-argument with context.cd(TASK_ROOT_STR): @@ -220,7 +222,7 @@ def pycache_clean(context) -> None: # ruff fast linter @invoke.task() -def lint(context) -> None: +def lint(context: Context) -> None: """Run ruff fast linter.""" with context.cd(TASK_ROOT_STR): context.run("ruff check") @@ -231,7 +233,7 @@ def lint(context) -> None: # ruff fast formatter @invoke.task() -def format(context) -> None: # noqa: A001 +def format(context: Context) -> None: # noqa: A001 """Run ruff format --check.""" with context.cd(TASK_ROOT_STR): context.run("ruff format --check") @@ -241,7 +243,7 @@ def format(context) -> None: # noqa: A001 @invoke.task() -def ruff_clean(context) -> None: +def ruff_clean(context: Context) -> None: """Remove .ruff_cache directory.""" with context.cd(TASK_ROOT_STR): context.run("ruff clean") @@ -256,7 +258,7 @@ def ruff_clean(context) -> None: @invoke.task(pre=clean_tasks, default=True) -def clean_all(_) -> None: +def clean_all(_: Context) -> None: """Run all clean tasks.""" # pylint: disable=unused-argument @@ -265,7 +267,7 @@ def clean_all(_) -> None: @invoke.task -def tag(context, name, message='') -> None: +def tag(context: Context, name: str, message: str = '') -> None: """Add a Git tag and push it to origin.""" # If a tag was provided on the command-line, then add a Git tag and push it to origin if name: @@ -277,7 +279,7 @@ def tag(context, name, message='') -> None: @invoke.task() -def validatetag(context) -> None: +def validatetag(context: Context) -> None: """Check to make sure that a tag exists for the current HEAD and it looks like a valid version number.""" # Validate that a Git tag exists for the current commit HEAD result = context.run("git describe --exact-match --tags $(git log -n1 --pretty='%h')") @@ -297,7 +299,7 @@ def validatetag(context) -> None: @invoke.task(pre=[clean_all], post=[plugin_tasks.sdist]) -def sdist(context) -> None: +def sdist(context: Context) -> None: """Create a source distribution.""" with context.cd(TASK_ROOT_STR): context.run('python -m build --sdist') @@ -307,7 +309,7 @@ def sdist(context) -> None: @invoke.task(pre=[clean_all], post=[plugin_tasks.wheel]) -def wheel(context) -> None: +def wheel(context: Context) -> None: """Build a wheel distribution.""" with context.cd(TASK_ROOT_STR): context.run('python -m build --wheel') @@ -317,7 +319,7 @@ def wheel(context) -> None: @invoke.task(pre=[validatetag, sdist, wheel]) -def pypi(context) -> None: +def pypi(context: Context) -> None: """Build and upload a distribution to pypi.""" with context.cd(TASK_ROOT_STR): context.run('twine upload dist/*') @@ -327,7 +329,7 @@ def pypi(context) -> None: @invoke.task(pre=[validatetag, sdist, wheel]) -def pypi_test(context) -> None: +def pypi_test(context: Context) -> None: """Build and upload a distribution to https://test.pypi.org.""" with context.cd(TASK_ROOT_STR): context.run('twine upload --repository testpypi dist/*')