From a08dfd2509e1d7285bcc0e8b2ca39cfc491c8612 Mon Sep 17 00:00:00 2001 From: Peter Bittner Date: Fri, 9 Jan 2026 10:15:12 +0100 Subject: [PATCH 1/2] Use ty instead of MyPy for type checking --- .github/workflows/check.yml | 2 +- pyproject.toml | 13 ------------- tox.ini | 17 ++++++++++------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f307fd0..47f169e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -25,7 +25,7 @@ jobs: env: - lint - format - - mypy + - types - package - license steps: diff --git a/pyproject.toml b/pyproject.toml index bda6fda..b871f6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,19 +58,6 @@ exclude_also = ["if __name__ == .__main__.:"] show_missing = true skip_covered = true -[tool.mypy] -exclude = [ - "tests/", - "tests\\.py$", - "test_.*\\.py$", - ".*_tests\\.py$", -] -ignore_missing_imports = true -pretty = true -warn_redundant_casts = true -warn_unreachable = true -warn_unused_ignores = true - [tool.pytest.ini_options] addopts = "--color=yes --doctest-modules --junitxml=tests/junit-report.xml --verbose" diff --git a/tox.ini b/tox.ini index fce4fb2..91deffc 100644 --- a/tox.ini +++ b/tox.ini @@ -8,8 +8,8 @@ envlist = lint format + types license - mypy py3{9,10,11,12,13,14} pypy3{9,10,11} package @@ -59,12 +59,6 @@ skip_install = true deps = ruff commands = ruff check {posargs:.} -[testenv:mypy] -description = Perform static type checking -skip_install = true -deps = mypy -commands = mypy {posargs:.} - [testenv:package] description = Build package and check metadata (or upload package) skip_install = true @@ -78,3 +72,12 @@ passenv = TWINE_USERNAME TWINE_PASSWORD TWINE_REPOSITORY_URL + +[testenv:types] +description = Perform static type checking +skip_install = true +deps = + cli-test-helpers + pytest + ty +commands = ty check {posargs} From 169b38a19a807a5fefcf2df43b20fd36228b096e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 9 Jan 2026 23:44:16 +0000 Subject: [PATCH 2/2] Add type annotations to fix ty type checking issues Co-authored-by: bittner <665072+bittner@users.noreply.github.com> --- pyclean/runner.py | 37 ++++++++++++++++++++++++------------- pyclean/traversal.py | 4 +++- tests/test_traversal.py | 6 ++---- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/pyclean/runner.py b/pyclean/runner.py index 6032579..4cd167e 100644 --- a/pyclean/runner.py +++ b/pyclean/runner.py @@ -4,25 +4,36 @@ """Cleanup runner with dry-run and file operations functionality.""" +from __future__ import annotations + import logging +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from argparse import Namespace + from pathlib import Path log = logging.getLogger(__name__) +def noop(_: Path) -> None: + """No-op function for uninitialized runner.""" + + class CleanupRunner: """Execution engine with object counting, logging and optional dry-run.""" def __init__(self): """Cleanup runner with optional dry-run behavior.""" - self.unlink = None - self.rmdir = None - self.ignore = None - self.unlink_count = None - self.unlink_failed = None - self.rmdir_count = None - self.rmdir_failed = None - - def configure(self, args): + self.unlink = noop + self.rmdir = noop + self.ignore: list[str] = [] + self.unlink_count = 0 + self.unlink_failed = 0 + self.rmdir_count = 0 + self.rmdir_failed = 0 + + def configure(self, args: Namespace) -> None: """Set up runner according to command line options.""" self.unlink = print_filename if args.dry_run else remove_file self.rmdir = print_dirname if args.dry_run else remove_directory @@ -36,7 +47,7 @@ def configure(self, args): Runner = CleanupRunner() -def remove_file(fileobj): +def remove_file(fileobj: Path) -> None: """Attempt to delete a file object for real.""" log.debug('Deleting file: %s', fileobj) try: @@ -47,7 +58,7 @@ def remove_file(fileobj): Runner.unlink_failed += 1 -def remove_directory(dirobj): +def remove_directory(dirobj: Path) -> None: """Attempt to remove a directory object for real.""" log.debug('Removing directory: %s', dirobj) try: @@ -58,13 +69,13 @@ def remove_directory(dirobj): Runner.rmdir_failed += 1 -def print_filename(fileobj): +def print_filename(fileobj: Path) -> None: """Only display the file name, used with --dry-run.""" log.debug('Would delete file: %s', fileobj) Runner.unlink_count += 1 -def print_dirname(dirobj): +def print_dirname(dirobj: Path) -> None: """Only display the directory name, used with --dry-run.""" log.debug('Would delete directory: %s', dirobj) Runner.rmdir_count += 1 diff --git a/pyclean/traversal.py b/pyclean/traversal.py index 2a984f0..ddf967d 100644 --- a/pyclean/traversal.py +++ b/pyclean/traversal.py @@ -4,6 +4,8 @@ """Directory traversal and ignore pattern matching.""" +from __future__ import annotations + import logging import os from pathlib import Path @@ -23,7 +25,7 @@ def normalize(path_pattern: str) -> str: return path_pattern.replace(os.sep, os.altsep or os.sep) -def should_ignore(pathname: str, ignore_patterns: list[str]) -> bool: +def should_ignore(pathname: str, ignore_patterns: list[str] | None) -> bool: """ Check if a path should be ignored based on ignore patterns. diff --git a/tests/test_traversal.py b/tests/test_traversal.py index 2fb6559..117c144 100644 --- a/tests/test_traversal.py +++ b/tests/test_traversal.py @@ -92,8 +92,7 @@ def test_should_ignore(path_str, patterns, expected): """ Does should_ignore correctly match path patterns? """ - path = Path(path_str) - result = should_ignore(path, patterns) + result = should_ignore(path_str, patterns) assert result == expected @@ -112,8 +111,7 @@ def test_should_ignore_windows_paths(path_str, patterns, expected): Does should_ignore correctly handle Windows-style backslash patterns? This test only runs on Windows where backslash is a path separator. """ - path = Path(path_str) - result = should_ignore(path, patterns) + result = should_ignore(path_str, patterns) assert result == expected