From 773a2764c2776df9ab5d61dd9a995c51532a2943 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 14 Mar 2026 16:52:59 -0400 Subject: [PATCH 1/4] Migrate to prek from pre-commit --- .github/workflows/quality.yml | 4 ++-- Makefile | 8 ++++---- examples/README.md | 2 +- examples/{modular_commands.py => modular_commandsets.py} | 0 pyproject.toml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) rename examples/{modular_commands.py => modular_commandsets.py} (100%) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 2818bd382..6a0606241 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -29,5 +29,5 @@ jobs: python-version: "3.14" - name: Install the project run: uv sync --group quality - - name: Run pre-commit - run: uv run pre-commit run -a --show-diff-on-failure + - name: Run prek + run: uv run prek run -a --show-diff-on-failure diff --git a/Makefile b/Makefile index 914fc664d..747da37f5 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ install: ## Install the virtual environment with dependencies @echo "πŸš€ Creating uv Python virtual environment" @uv python install 3.14 @uv sync --python=3.14 - @echo "πŸš€ Installing Git pre-commit hooks locally" - @uv run pre-commit install + @echo "πŸš€ Installing Git prek hooks locally" + @uv run prek install -f @echo "πŸš€ Installing Prettier using npm" @npm install -q --no-fund --include=dev @@ -16,8 +16,8 @@ install: ## Install the virtual environment with dependencies check: ## Run code quality tools. @echo "πŸš€ Checking lock file consistency with 'pyproject.toml'" @uv lock --locked - @echo "πŸš€ Linting code and documentation: Running pre-commit" - @uv run pre-commit run -a + @echo "πŸš€ Auto-formatting, Linting, and Type Checking code and documentation: Running prek" + @uv run prek run -a @echo "πŸš€ Static type checking: Running mypy" @uv run mypy diff --git a/examples/README.md b/examples/README.md index 43928cda8..f716d9030 100644 --- a/examples/README.md +++ b/examples/README.md @@ -63,7 +63,7 @@ each: - Shows how to use various `cmd2` application lifecycle hooks - [migrating.py](https://github.com/python-cmd2/cmd2/blob/main/examples/migrating.py) - A simple `cmd` application that you can migrate to `cmd2` by changing one line -- [modular_commands.py](https://github.com/python-cmd2/cmd2/blob/main/examples/modular_commands.py) +- [modular_commandsets.py](https://github.com/python-cmd2/cmd2/blob/main/examples/modular_commandsets.py) - Complex example demonstrating a variety of methods to load `CommandSets` using a mix of command decorators - [paged_output.py](https://github.com/python-cmd2/cmd2/blob/main/examples/paged_output.py) diff --git a/examples/modular_commands.py b/examples/modular_commandsets.py similarity index 100% rename from examples/modular_commands.py rename to examples/modular_commandsets.py diff --git a/pyproject.toml b/pyproject.toml index 20daa0227..281032af1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ dev = [ "ipython>=8.23", "mkdocstrings[python]>=1", "mypy>=1.13", - "pre-commit>=3", + "prek>=0.3.5", "pytest>=8.1.1", "pytest-cov>=5", "pytest-mock>=3.14.1", @@ -58,7 +58,7 @@ docs = [ "setuptools_scm>=8", "zensical>=0.0.17", ] -quality = ["pre-commit>=3"] +quality = ["prek>=0.3.5"] test = [ "codecov>=2.1", "coverage>=7.11", From c4bcdc1dc08a7e5f26c1157cc32a6fe1efcc2ca6 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 14 Mar 2026 16:57:56 -0400 Subject: [PATCH 2/4] Reword comment in Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 747da37f5..8319eb89b 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ install: ## Install the virtual environment with dependencies check: ## Run code quality tools. @echo "πŸš€ Checking lock file consistency with 'pyproject.toml'" @uv lock --locked - @echo "πŸš€ Auto-formatting, Linting, and Type Checking code and documentation: Running prek" + @echo "πŸš€ Auto-formatting/Linting code and documentation: Running prek" @uv run prek run -a @echo "πŸš€ Static type checking: Running mypy" @uv run mypy From 3ca77a8118abe02422c3e19372343375ceb2db4b Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 14 Mar 2026 17:38:22 -0400 Subject: [PATCH 3/4] Add typo checker to prek/pre-commit config Fix typos --- .github/CONTRIBUTING.md | 4 ++-- .pre-commit-config.yaml | 16 ++++++++++++++++ README.md | 6 +++--- cmd2/argparse_custom.py | 4 ++-- cmd2/cmd2.py | 6 +++--- docs/doc_conventions.md | 2 +- examples/README.md | 2 +- examples/command_sets.py | 6 +++--- examples/custom_types.py | 2 +- ruff.toml | 2 +- tests/test_cmd2.py | 2 +- tests/test_commandset.py | 2 +- tests/test_pt_utils.py | 2 +- 13 files changed, 36 insertions(+), 20 deletions(-) mode change 100755 => 100644 README.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 111112af7..464b98c6f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -644,12 +644,12 @@ The one plugin we consider essential for PyCharm is [RyeCharm](https://plugins.jetbrains.com/plugin/25230-ryecharm). `RyeCharm` is an all-in-one PyCharm plugin for [Astral](https://astral.sh/)-backed Python tools: [uv](https://github.com/astral-sh/uv), [Ruff](https://github.com/astral-sh/ruff), and [ty](https://github.com/astral-sh/ty). NOTE: `ty` -support is provisional as that new type checker is in early alpha developement. +support is provisional as that new type checker is in early alpha development. #### VSCode Settings While **VSCode** is a phenomenal IDE for developing in Python, the out-of-the-box experience leaves -a lot to be desired. You will need to install a number of extenstions and tweak the default +a lot to be desired. You will need to install a number of extensions and tweak the default configuration for many of them in order to get an optimal developer experience. Recommended VSCode extensions: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2dc629c65..68fa58fc2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,9 +3,15 @@ repos: rev: "v6.0.0" hooks: - id: check-case-conflict + - id: check-executables-have-shebangs - id: check-merge-conflict + - id: check-symlinks - id: check-toml + - id: check-yaml + - id: detect-private-key - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: mixed-line-ending - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit @@ -23,3 +29,13 @@ repos: additional_dependencies: - prettier@3.8.1 - prettier-plugin-toml@2.0.6 + + - repo: https://github.com/crate-ci/typos + rev: v1.44.0 + hooks: + - id: typos + exclude: | + (?x)^( + ruff.toml| + tests/.* + )$ diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 1fb1d286b..bc3455343 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ examples. - [cmd2 example applications](https://github.com/python-cmd2/cmd2/tree/main/examples) - Basic cmd2 examples to demonstrate how to use various features - [Advanced Examples](https://github.com/jayrod/cmd2-example-apps) - - More complex examples that demonstrate more featuers about how to put together a complete + - More complex examples that demonstrate more features about how to put together a complete application - [Cookiecutter](https://github.com/cookiecutter/cookiecutter) Templates from community - Basic cookiecutter template for cmd2 application : @@ -168,7 +168,7 @@ reproduce the bug. At a minimum, please state the following: | [REW Sploit](https://github.com/REW-sploit/REW-sploit) | Emulate and Dissect Metasploit Framework (MSF) and other attacks | [REW-sploit](https://github.com/REW-sploit) | | [tomcatmanager](https://github.com/tomcatmanager/tomcatmanager) | A command line tool and python library for managing a tomcat server | [tomcatmanager](https://github.com/tomcatmanager) | | [Falcon Toolkit](https://github.com/CrowdStrike/Falcon-Toolkit) | Unleash the power of the CrowdStrike Falcon Platform at the CLI | [CrowdStrike](https://github.com/CrowdStrike) | -| [EXPLIoT](https://gitlab.com/expliot_framework/expliot) | Internet of Things Security Testing and Exploitation framework | [expliot_framework](https://gitlab.com/expliot_framework/) | +| [EXPLIoT](https://gitlab.com/expliot_framework/expliot) | Internet of Things Security Testing and Exploitation framework | [exploit_framework](https://gitlab.com/expliot_framework/) | | [Pobshell](https://github.com/pdalloz/pobshell) | A Bash‑like shell for live Python objects: `cd`, `ls`, `cat`, `find` and _CLI piping_ for object code, str values & more | [Peter Dalloz](https://www.linkedin.com/in/pdalloz) | Possibly defunct but still good examples @@ -178,7 +178,7 @@ Possibly defunct but still good examples | [Katana](https://github.com/JohnHammond/katana) | Automatic CTF Challenge Solver | [John Hammond](https://github.com/JohnHammond) | | [SatanSword](https://github.com/Lucifer1993/SatanSword) (in Chinese) | Comprehensive Penetration Framework for Red Teaming | [Lucifer1993](https://github.com/Lucifer1993) | | [Jok3r](http://www.jok3r-framework.com) | Network & Web Pentest Automation Framework | [Koutto](https://github.com/koutto) | -| [Counterfit](https://github.com/Azure/counterfit) | a CLI that provides a generic automation layer for assessing the security of ML models | [Microsoft Azure](https://github.com/Azure) | +| [Counterfeit](https://github.com/Azure/counterfit) | a CLI that provides a generic automation layer for assessing the security of ML models | [Microsoft Azure](https://github.com/Azure) | | [Overlord](https://github.com/qsecure-labs/overlord) | Red Teaming Infrastructure Automation | [QSecure Labs](https://github.com/qsecure-labs) | | [Automated Reconnaissance Pipeline](https://github.com/epi052/recon-pipeline) | An automated target reconnaissance pipeline | [epi052](https://github.com/epi052) | | [JSShell](https://github.com/Den1al/JSShell) | An interactive multi-user web JavaScript (JS) shell | [Den1al](https://github.com/Den1al) | diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py index e96097953..623da8308 100644 --- a/cmd2/argparse_custom.py +++ b/cmd2/argparse_custom.py @@ -397,14 +397,14 @@ def __init__( @property def choices_provider(self) -> ChoicesProviderUnbound[CmdOrSet]: - """Retreive the internal choices_provider function.""" + """Retrieve the internal choices_provider function.""" if self.is_completer: raise AttributeError("This instance is configured as a completer, not a choices_provider") return cast(ChoicesProviderUnbound[CmdOrSet], self.to_call) @property def completer(self) -> CompleterUnbound[CmdOrSet]: - """Retreive the internal completer function.""" + """Retrieve the internal completer function.""" if not self.is_completer: raise AttributeError("This instance is configured as a choices_provider, not a completer") return cast(CompleterUnbound[CmdOrSet], self.to_call) diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index a8f5ee52d..8cb373a3c 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -292,7 +292,7 @@ def remove(self, command_method: CommandFunc) -> None: @dataclass(kw_only=True) class AsyncAlert: - """Contents of an asynchonous alert which display while user is at prompt. + """Contents of an asynchronous alert which display while user is at prompt. :param msg: an optional message to be printed above the prompt. :param prompt: an optional string to dynamically replace the current prompt. @@ -608,7 +608,7 @@ def __init__( # Command parsers for this Cmd instance. self._command_parsers: _CommandParsers = _CommandParsers(self) - # Members related to printing asychronous alerts + # Members related to printing asynchronous alerts self._alert_queue: deque[AsyncAlert] = deque() self._alert_condition = threading.Condition() self._alert_allowed = False @@ -3508,7 +3508,7 @@ def _pre_prompt() -> None: self._alert_allowed = False def _cmdloop(self) -> None: - """Repeatedly issue a prompt, accept input, parse it, and dispatch to apporpriate commands. + """Repeatedly issue a prompt, accept input, parse it, and dispatch to appropriate commands. Parse an initial prefix off the received input and dispatch to action methods, passing them the remainder of the line as argument. diff --git a/docs/doc_conventions.md b/docs/doc_conventions.md index 9981b75be..022eb7738 100644 --- a/docs/doc_conventions.md +++ b/docs/doc_conventions.md @@ -49,7 +49,7 @@ or [The Markdown Guide](https://www.markdownguide.org/) for a more complete refe Code blocks can be created in two ways: -- Indent the block - this will show as a monospace code block, but won't include highighting +- Indent the block - this will show as a monospace code block, but won't include highlighting - use the triple backticks followed by the code language, e.g. `python` and close with triple backticks diff --git a/examples/README.md b/examples/README.md index f716d9030..2727ac64a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -42,7 +42,7 @@ each: - Demonstrates usage of `@with_default_category` decorator to group and categorize commands and `CommandSet` use - [dynamic_commands.py](https://github.com/python-cmd2/cmd2/blob/main/examples/dynamic_commands.py) - - Shows how `do_*` commands can be dynamically created programatically at runtime + - Shows how `do_*` commands can be dynamically created programmatically at runtime - [environment.py](https://github.com/python-cmd2/cmd2/blob/main/examples/environment.py) - Shows how to create custom `cmd2.Settable` parameters which serve as internal environment variables diff --git a/examples/command_sets.py b/examples/command_sets.py index ed51c6f4b..a14cb80c8 100755 --- a/examples/command_sets.py +++ b/examples/command_sets.py @@ -6,7 +6,7 @@ most commands trivial because the intent is to focus on the CommandSet feature set. The `AutoLoadCommandSet` is a basic command set which is loaded automatically at application startup and stays loaded until -application exit. Ths is the simplest case of simply modularizing command definitions to different classes and/or files. +application exit. This is the simplest case of simply modularizing command definitions to different classes and/or files. The `LoadableFruits` and `LoadableVegetables` CommandSets are dynamically loadable and un-loadable at runtime using the `load` and `unload` commands. This demonstrates the ability to load and unload CommandSets based on application state. Each of these @@ -102,7 +102,7 @@ def __init__(self) -> None: self.register_command_set(AutoLoadCommandSet()) - # Store the dyanmic CommandSet classes for ease of loading and unloading + # Store the dynamic CommandSet classes for ease of loading and unloading self._fruits = LoadableFruits() self._vegetables = LoadableVegetables() @@ -147,7 +147,7 @@ def do_unload(self, ns: argparse.Namespace) -> None: @with_argparser(cut_parser) @with_category(COMMANDSET_SUBCOMMAND) def do_cut(self, ns: argparse.Namespace) -> None: - """Intended to be used with dyanmically loaded subcommands specifically.""" + """Intended to be used with dynamically loaded subcommands specifically.""" handler = ns.cmd2_handler.get() if handler is not None: handler(ns) diff --git a/examples/custom_types.py b/examples/custom_types.py index ea8a4062b..39bfeecfa 100644 --- a/examples/custom_types.py +++ b/examples/custom_types.py @@ -51,7 +51,7 @@ def integer(value_str: str) -> int: def hexadecimal(value_str: str) -> int: - """Parse hexidecimal integer, with optional '0x' prefix.""" + """Parse hexadecimal integer, with optional '0x' prefix.""" return int(value_str, base=16) diff --git a/ruff.toml b/ruff.toml index 7d5962b79..706aa072b 100644 --- a/ruff.toml +++ b/ruff.toml @@ -154,7 +154,7 @@ mccabe.max-complexity = 49 # Ignore starting a process with a partial executable path (i.e. git) "scripts/validate_tag.py" = ["S607"] -# Ingore various rulesets in test directories +# Ignore various rulesets in test directories "{tests}/*.py" = [ "ANN", # Ignore all type annotation rules in test folders "ARG", # Ignore all unused argument warnings in test folders diff --git a/tests/test_cmd2.py b/tests/test_cmd2.py index 5cfd0d5e4..7bd349a31 100644 --- a/tests/test_cmd2.py +++ b/tests/test_cmd2.py @@ -2900,7 +2900,7 @@ def test_macro_usage_with_missing_args(base_app) -> None: assert "expects at least 2 arguments" in err[0] -def test_macro_usage_with_exta_args(base_app) -> None: +def test_macro_usage_with_extra_args(base_app) -> None: # Create the macro out, _err = run_cmd(base_app, 'macro create fake help {1}') assert out == normalize("Macro 'fake' created") diff --git a/tests/test_commandset.py b/tests/test_commandset.py index 686c79285..330928f23 100644 --- a/tests/test_commandset.py +++ b/tests/test_commandset.py @@ -159,7 +159,7 @@ def do_builtin(self, _) -> None: # Create a synonym to a command outside of this CommandSet with subcommands. # This will best test the synonym check in cmd2.Cmd._check_uninstallable() when - # we unresgister this CommandSet. + # we unregister this CommandSet. do_alias_synonym = cmd2.Cmd.do_alias cs = SynonymCommandSet("foo") diff --git a/tests/test_pt_utils.py b/tests/test_pt_utils.py index 2664848e3..3051c9716 100644 --- a/tests/test_pt_utils.py +++ b/tests/test_pt_utils.py @@ -474,7 +474,7 @@ def test_get_completions_add_opening_quote_and_return_results( def test_get_completions_allow_finalization( self, line, match, quote_char, end_of_line, expected, mock_cmd_app: MockCmd ) -> None: - """Test that get_completions corectly handles finalizing single matches.""" + """Test that get_completions correctly handles finalizing single matches.""" completer = pt_utils.Cmd2Completer(cast(Any, mock_cmd_app)) # Set up document From 421c889c363830dd91aefad0fac9775fae580680 Mon Sep 17 00:00:00 2001 From: Todd Leonhardt Date: Sat, 14 Mar 2026 17:55:07 -0400 Subject: [PATCH 4/4] Fix things that weren't typos --- .typos.toml | 5 +++++ README.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .typos.toml diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 000000000..1f8079524 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,5 @@ +[default.extend-words] +EXPLIoT = "EXPLIoT" +Counterfit = "Counterfit" +expliot = "expliot" +counterfit = "counterfit" diff --git a/README.md b/README.md index bc3455343..a479d9ea5 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ reproduce the bug. At a minimum, please state the following: | [REW Sploit](https://github.com/REW-sploit/REW-sploit) | Emulate and Dissect Metasploit Framework (MSF) and other attacks | [REW-sploit](https://github.com/REW-sploit) | | [tomcatmanager](https://github.com/tomcatmanager/tomcatmanager) | A command line tool and python library for managing a tomcat server | [tomcatmanager](https://github.com/tomcatmanager) | | [Falcon Toolkit](https://github.com/CrowdStrike/Falcon-Toolkit) | Unleash the power of the CrowdStrike Falcon Platform at the CLI | [CrowdStrike](https://github.com/CrowdStrike) | -| [EXPLIoT](https://gitlab.com/expliot_framework/expliot) | Internet of Things Security Testing and Exploitation framework | [exploit_framework](https://gitlab.com/expliot_framework/) | +| [EXPLIoT](https://gitlab.com/expliot_framework/expliot) | Internet of Things Security Testing and Exploitation framework | [expliot_framework](https://gitlab.com/expliot_framework/) | | [Pobshell](https://github.com/pdalloz/pobshell) | A Bash‑like shell for live Python objects: `cd`, `ls`, `cat`, `find` and _CLI piping_ for object code, str values & more | [Peter Dalloz](https://www.linkedin.com/in/pdalloz) | Possibly defunct but still good examples @@ -178,7 +178,7 @@ Possibly defunct but still good examples | [Katana](https://github.com/JohnHammond/katana) | Automatic CTF Challenge Solver | [John Hammond](https://github.com/JohnHammond) | | [SatanSword](https://github.com/Lucifer1993/SatanSword) (in Chinese) | Comprehensive Penetration Framework for Red Teaming | [Lucifer1993](https://github.com/Lucifer1993) | | [Jok3r](http://www.jok3r-framework.com) | Network & Web Pentest Automation Framework | [Koutto](https://github.com/koutto) | -| [Counterfeit](https://github.com/Azure/counterfit) | a CLI that provides a generic automation layer for assessing the security of ML models | [Microsoft Azure](https://github.com/Azure) | +| [Counterfit](https://github.com/Azure/counterfit) | a CLI that provides a generic automation layer for assessing the security of ML models | [Microsoft Azure](https://github.com/Azure) | | [Overlord](https://github.com/qsecure-labs/overlord) | Red Teaming Infrastructure Automation | [QSecure Labs](https://github.com/qsecure-labs) | | [Automated Reconnaissance Pipeline](https://github.com/epi052/recon-pipeline) | An automated target reconnaissance pipeline | [epi052](https://github.com/epi052) | | [JSShell](https://github.com/Den1al/JSShell) | An interactive multi-user web JavaScript (JS) shell | [Den1al](https://github.com/Den1al) |