From 74025814d7c64119f80efbb1633ffb7a5e2d1730 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sun, 8 Jun 2025 14:28:48 -0400 Subject: [PATCH] Set ruff `target-version` to the minimum supported version of Python Ignore warning about adding import for future annotations. I tried it but it wreaked havoc due to how cmd2 actively validates type hints using inspect. If you use future annotations it delays evaluation until necessary, which benefits runtime performance but converts all type annotations to strings instead of types. Also, cleaned up how we specify ruff per-file ignores. --- cmd2/cmd2.py | 17 ++++++++--------- pyproject.toml | 52 +++++++++++++++----------------------------------- 2 files changed, 23 insertions(+), 46 deletions(-) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index f8a1f0ea..1ad7964a 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -3597,8 +3597,8 @@ def _macro_create(self, args: argparse.Namespace) -> None: max_arg_num = 0 arg_nums = set() - while True: - try: + try: + while True: cur_match = normal_matches.__next__() # Get the number string between the braces @@ -3612,9 +3612,8 @@ def _macro_create(self, args: argparse.Namespace) -> None: max_arg_num = max(max_arg_num, cur_num) arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=False)) - - except StopIteration: - break + except StopIteration: + pass # Make sure the argument numbers are continuous if len(arg_nums) != max_arg_num: @@ -3624,16 +3623,16 @@ def _macro_create(self, args: argparse.Namespace) -> None: # Find all escaped arguments escaped_matches = re.finditer(MacroArg.macro_escaped_arg_pattern, value) - while True: - try: + try: + while True: cur_match = escaped_matches.__next__() # Get the number string between the braces cur_num_str = re.findall(MacroArg.digit_pattern, cur_match.group())[0] arg_list.append(MacroArg(start_index=cur_match.start(), number_str=cur_num_str, is_escaped=True)) - except StopIteration: - break + except StopIteration: + pass # Set the macro result = "overwritten" if args.name in self.macros else "created" diff --git a/pyproject.toml b/pyproject.toml index 0b7e69c4..cb14d536 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -147,9 +147,7 @@ exclude = [ # Same as Black. line-length = 127 indent-width = 4 - -# Assume Python 3.13 -target-version = "py313" +target-version = "py39" # Minimum supported version of Python output-format = "full" [tool.ruff.lint] @@ -235,6 +233,7 @@ ignore = [ "E111", # Conflicts with ruff format "E114", # Conflicts with ruff format "E117", # Conflicts with ruff format + "FA100", # Adding from __future__ import annotations screws up cmd2 because of how use inspect to validate type annotations at runtime "ISC002", # Conflicts with ruff format "Q000", # Conflicts with ruff format "Q001", # Conflicts with ruff format @@ -258,36 +257,26 @@ 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 -] +[tool.ruff.lint.per-file-ignores] +# Module level import not at top of file and unused import +"cmd2/__init__.py" = ["E402", "F401"] -per-file-ignores."cmd2/argparse_custom.py" = [ - "B010", # Do not call setattr with a constant attribute value -] +# Do not call setattr with constant attribute value +"cmd2/argparse_custom.py" = ["B010"] -per-file-ignores."examples/*.py" = [ +# Ignore various varnings in examples/ directory +"examples/*.py" = [ "ANN", # Ignore all type annotation rules in examples folder "D", # Ignore all pydocstyle rules in examples folder "INP001", # Module is part of an implicit namespace "PLW2901", # loop variable overwritten inside loop "S", # Ignore all Security rules in examples folder ] +"examples/scripts/*.py" = ["F821"] # Undefined name `app` +"plugins/*.py" = ["INP001"] # Module is part of an implicit namespace -per-file-ignores."examples/scripts/*.py" = [ - "F821", # Undefined name `app` -] - -per-file-ignores."plugins/*.py" = [ - "ANN", # Ignore all type annotation rules in test folders - "D", # Ignore all pydocstyle rules in test folders - "INP001", # Module is part of an implicit namespace - "S", # Ignore all Security rules in test folders - "SLF", # Ignore all warnings about private or protected member access in test folders -] - -per-file-ignores."tests/*.py" = [ +# Ingore various rulesets in test and plugins directories +"{plugins,tests,tests_isolated}/*.py" = [ "ANN", # Ignore all type annotation rules in test folders "ARG", # Ignore all unused argument warnings in test folders "D", # Ignore all pydocstyle rules in test folders @@ -295,19 +284,8 @@ per-file-ignores."tests/*.py" = [ "S", # Ignore all Security rules in test folders "SLF", # Ignore all warnings about private or protected member access in test folders ] - -per-file-ignores."tests/pyscript/*.py" = [ - "F821", # Undefined name `app` - "INP001", # Module is part of an implicit namespace -] - -per-file-ignores."tests_isolated/*.py" = [ - "ANN", # Ignore all type annotation rules in test folders - "ARG", # Ignore all unused argument warnings in test folders - "D", # Ignore all pydocstyle rules in test folders - "S", # Ignore all Security rules in test folders - "SLF", # Ignore all warnings about private or protected member access in test folders -] +# Undefined name `app` and module is part of an implicit namespace +"tests/pyscript/*.py" = ["F821", "INP001"] [tool.ruff.format] # Like Black, use double quotes for strings.