diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3c31560..b4ae0bf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -66,7 +66,7 @@ repos: # General - repo: https://github.com/codespell-project/codespell - rev: v2.4.2 + rev: v2.4.3 hooks: - id: codespell args: [--write-changes] @@ -101,7 +101,7 @@ repos: - id: actionlint - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: v1.26.1 + rev: v1.27.0 hooks: - id: zizmor args: [--no-progress, --persona=auditor] @@ -113,7 +113,7 @@ repos: # Python - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.21 + rev: v0.15.22 hooks: - id: ruff-check args: [--fix] @@ -145,7 +145,7 @@ repos: - packaging==26.2 - repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.25.2 + rev: v2.25.3 hooks: - id: pyproject-fmt exclude: ^tests/ @@ -157,12 +157,12 @@ repos: args: [src] - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.11.28 + rev: 0.11.29 hooks: - id: uv-lock - repo: https://github.com/sco1/pre-commit-python-eol - rev: v2026.1.0 + rev: v2026.7.0 hooks: - id: check-eol-cached diff --git a/pyproject.toml b/pyproject.toml index 14a32d8..f001855 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,29 +55,29 @@ format.preview = true format.nested-string-quote-style = "preferred" lint.select = [ "ALL", - "DTZ002", # Useful outside of timezones + "call-datetime-today", # Useful outside of timezones ] lint.ignore = [ - "COM812", # Conflict with formatter - "CPY", # No copyright statements - "D1", # Docstrings should not be enforced by default - "D203", # Choose D203 or D211 - "D212", # Choose D212 or D213 - "FIX002", # (project) - "G004", # (project) We don't use `logging` - "G010", # (project) We don't use `logging` - "PLW2901", # (project) Re-assignments are really convenient here - "S404", # Uses of subprocess are rejected, no need to reject the imports as well - "T201", # (project) Print is allowed - "TD003", # (project) - "TRY400", # (project) We don't use `logging` + "CPY", # No copyright statements + "D1", # Docstrings should not be enforced by default + "error-instead-of-exception", # (project) We don't use `logging` + "incorrect-blank-line-before-class", # Choose D203 or D211 + "line-contains-todo", # (project) + "logging-f-string", # (project) We don't use `logging` + "logging-warn", # (project) We don't use `logging` + "missing-todo-link", # (project) + "missing-trailing-comma", # Conflict with formatter + "multi-line-summary-first-line", # Choose D212 or D213 + "print", # (project) Print is allowed + "redefined-loop-name", # (project) Re-assignments are really convenient here + "suspicious-subprocess-import", # Uses of subprocess are rejected, no need to reject the imports as well ] lint.per-file-ignores."tests/**/*.py" = [ - "E501", # If the formatter doesn't fix the line length, it's good enough - "FBT", # We don't care about boolean parameters in tests - "INP001", # Tests are supposed to be an implicit namespace - "PLR2004", # Magic values are allowed in tests - "S101", # Assert is allowed in tests + "assert", # Assert is allowed in tests + "FBT", # We don't care about boolean parameters in tests + "implicit-namespace-package", # Tests are supposed to be an implicit namespace + "line-too-long", # If the formatter doesn't fix the line length, it's good enough + "magic-value-comparison", # Magic values are allowed in tests ] lint.flake8-tidy-imports.ban-relative-imports = "all" # For consistency lint.isort.combine-as-imports = true diff --git a/src/pre_commit_hooks/common/lines.py b/src/pre_commit_hooks/common/lines.py index 6f7b60c..421d086 100644 --- a/src/pre_commit_hooks/common/lines.py +++ b/src/pre_commit_hooks/common/lines.py @@ -7,10 +7,10 @@ from pre_commit_hooks.logger import Logger -def line_replace(line: str, a: str, b: str, *, logger: Logger) -> str: # noqa: ARG001 +def line_replace(line: str, a: str, b: str, *, logger: Logger) -> str: # ruff:ignore[unused-function-argument] if line.count(a) == 0: msg = f"Expected to find {a!r} in {line!r}" - raise Exception(msg) # noqa: TRY002 + raise Exception(msg) # ruff:ignore[raise-vanilla-class] return line.replace(a, b, 1) diff --git a/src/pre_commit_hooks/common/util.py b/src/pre_commit_hooks/common/util.py index 7e4c552..ce7f643 100644 --- a/src/pre_commit_hooks/common/util.py +++ b/src/pre_commit_hooks/common/util.py @@ -13,13 +13,13 @@ def remove_ws_splitted_part(orig_line: str, s: str) -> str: "a space before or after the result. Are you " "using tabs or other whitespace?" ) - raise Exception(msg) # noqa: TRY002 + raise Exception(msg) # ruff:ignore[raise-vanilla-class] return orig_line.replace(to_replace, "") def is_valid_sha256(s: str) -> bool: - return len(s) == 64 and all(c in string.hexdigits for c in s) # noqa: PLR2004 + return len(s) == 64 and all(c in string.hexdigits for c in s) # ruff:ignore[magic-value-comparison] def is_valid_sha1(s: str) -> bool: - return len(s) == 40 and all(c in string.hexdigits for c in s) # noqa: PLR2004 + return len(s) == 40 and all(c in string.hexdigits for c in s) # ruff:ignore[magic-value-comparison] diff --git a/src/pre_commit_hooks/common/versions.py b/src/pre_commit_hooks/common/versions.py index b2b34f7..e961c05 100644 --- a/src/pre_commit_hooks/common/versions.py +++ b/src/pre_commit_hooks/common/versions.py @@ -6,13 +6,13 @@ def process_version(version: str) -> Error | None: version = version.removeprefix("v") # Optional prefix parts = version.split(".") - if len(parts) > 3: # noqa: PLR2004 + if len(parts) > 3: # ruff:ignore[magic-value-comparison] # major.minor.patch.??? return Error( id="weird-version", msg="version contains more than three parts (major.minor.patch.???)", ) - if len(parts) == 2: # noqa: PLR2004 + if len(parts) == 2: # ruff:ignore[magic-value-comparison] # major.minor return Error( id="major-minor", @@ -35,5 +35,5 @@ def process_version(version: str) -> Error | None: msg = "Unreachable" raise AssertionError(msg) - assert len(parts) == 3 # noqa: PLR2004, S101 + assert len(parts) == 3 # ruff:ignore[magic-value-comparison, assert] return None diff --git a/src/pre_commit_hooks/docker.py b/src/pre_commit_hooks/docker.py index 7fbbc6a..0d58b19 100644 --- a/src/pre_commit_hooks/docker.py +++ b/src/pre_commit_hooks/docker.py @@ -15,7 +15,7 @@ class Processor(LineProcessor): # TODO(GideonBear): query and replace the version with latest, if online # also add sha hashes to docker, etc. - def process_line_internal( # noqa: PLR6301 + def process_line_internal( # ruff:ignore[no-self-use] self, _orig_line: str, line: str, logger: Logger ) -> None: if not line.strip().startswith(("image:", "FROM")): diff --git a/src/pre_commit_hooks/docker_apt_renovate.py b/src/pre_commit_hooks/docker_apt_renovate.py index 9f41c70..b2a9b8e 100644 --- a/src/pre_commit_hooks/docker_apt_renovate.py +++ b/src/pre_commit_hooks/docker_apt_renovate.py @@ -70,7 +70,7 @@ def install_command() -> str: ... @classmethod def from_from_line(cls, line: str, *, logger: Logger) -> OsRelease | None: for type_ in cls.types: - ret = type_._from_from_line_single(line, logger=logger) # noqa: SLF001 + ret = type_._from_from_line_single(line, logger=logger) # ruff:ignore[private-member-access] if ret: return ret @@ -229,7 +229,7 @@ def make_renovate_line(self, depname: str) -> str: def get_version(self, depname: str, *, logger: Logger) -> str | None: if not is_connected(): msg = "This function is only supposed to be called in connected contexts" - raise Exception(msg) # noqa: TRY002 + raise Exception(msg) # ruff:ignore[raise-vanilla-class] url = f"https://packages.debian.org/{self.codename}/{depname}" text = request(url, json=False) @@ -301,7 +301,7 @@ def renovate_re() -> Pattern[str]: @classmethod def from_docker_tag(cls, tag: str, *, logger: Logger) -> AlpineRelease | None: # Tags like 20251224, which is edge - if tag.isdecimal() and len(tag) == 8: # noqa: PLR2004 + if tag.isdecimal() and len(tag) == 8: # ruff:ignore[magic-value-comparison] return cls("edge") if tag.count(".") == 0 and tag != "edge": @@ -353,7 +353,7 @@ def make_renovate_line(self, depname: str) -> str: def get_version(self, depname: str, *, logger: Logger) -> str | None: if not is_connected(): msg = "This function is only supposed to be called in connected contexts" - raise Exception(msg) # noqa: TRY002 + raise Exception(msg) # ruff:ignore[raise-vanilla-class] url = f"https://pkgs.alpinelinux.org/package/{self.version_with_v()}/main/x86_64/{depname}" text = request(url, json=False) @@ -449,7 +449,7 @@ def process_line_internal( return None # We checked when setting bump_version_next - assert self.current_os is not None # noqa: S101 + assert self.current_os is not None # ruff:ignore[assert] return self.current_os.make_env_line(depname, logger=logger) @@ -507,7 +507,7 @@ def process_line_renovate( return None - def process_line_in_run( # noqa: C901, PLR0912 + def process_line_in_run( # ruff:ignore[complex-structure, too-many-branches] self, orig_line: str, line: str, logger: Logger ) -> str | None: in_run = self.in_run @@ -536,7 +536,7 @@ def process_line_in_run( # noqa: C901, PLR0912 self.in_install = True if self.in_install: - assert in_run is not None # noqa: S101 + assert in_run is not None # ruff:ignore[assert] if line.startswith("#"): return None @@ -567,7 +567,7 @@ def process_line_in_run( # noqa: C901, PLR0912 return line_replace( orig_line, arg, replacement, logger=logger ) - else: # If it isn't the only thing on this line # noqa: RET505 + else: # If it isn't the only thing on this line # ruff:ignore[superfluous-else-return] # Remove it from the line, keeping the rest intact orig_line = remove_ws_splitted_part(orig_line, arg) indent = " " * self.indent * 2 @@ -586,7 +586,7 @@ def process_line_in_run( # noqa: C901, PLR0912 # Remove the backslash from the last line new_lines[-1] = new_lines[-1].replace(" \\\n", "\n") # And add it back to the original line - assert "\n" in orig_line # noqa: S101 # sanity + assert "\n" in orig_line # ruff:ignore[assert] # sanity orig_line = orig_line.replace("\n", " \\\n") # If we removed all args from the line, and nothing (only a # continuation) remains, we remove the line entirely. If it was diff --git a/src/pre_commit_hooks/gha.py b/src/pre_commit_hooks/gha.py index e7ce03b..335197d 100644 --- a/src/pre_commit_hooks/gha.py +++ b/src/pre_commit_hooks/gha.py @@ -17,7 +17,7 @@ class Processor(LineProcessor): remove_comments = False # GHA expects a comment. - def process_line_internal( # noqa: PLR6301 + def process_line_internal( # ruff:ignore[no-self-use] self, orig_line: str, line: str, logger: Logger ) -> str | None: line = line.strip().removeprefix("- ") @@ -47,7 +47,7 @@ def process_line_internal( # noqa: PLR6301 return process_version_gha(orig_line, action, digest, version, logger=logger) -def process_line_no_comment( # noqa: PLR0911 +def process_line_no_comment( # ruff:ignore[too-many-return-statements] orig_line: str, line: str, logger: Logger ) -> str | None: try: @@ -91,7 +91,7 @@ def process_line_no_comment( # noqa: PLR0911 return process_version_gha(orig_line, action, None, version, logger=logger) -def process_version_gha( # noqa: PLR0911 +def process_version_gha( # ruff:ignore[too-many-return-statements] orig_line: str, action: str, digest: str | None, @@ -146,7 +146,7 @@ def process_version_gha( # noqa: PLR0911 def get_full_version( action: str, digest: str, - id: str, # noqa: A002 + id: str, # ruff:ignore[builtin-argument-shadowing] *, logger: Logger, ) -> str | None: @@ -177,7 +177,7 @@ def get_full_version( return None -def get_digest(action: str, ref: str, *, logger: Logger) -> str | None: # noqa: ARG001 +def get_digest(action: str, ref: str, *, logger: Logger) -> str | None: # ruff:ignore[unused-function-argument] if not is_connected(): return None diff --git a/src/pre_commit_hooks/logger.py b/src/pre_commit_hooks/logger.py index 370cc8e..7ed492f 100644 --- a/src/pre_commit_hooks/logger.py +++ b/src/pre_commit_hooks/logger.py @@ -78,7 +78,7 @@ def error( self, error: Error | str | None = None, *, - id: str | None = None, # noqa: A002 # This is nice for caller + id: str | None = None, # ruff:ignore[builtin-argument-shadowing] # This is nice for caller msg: str | None = None, ) -> bool: """ @@ -90,8 +90,8 @@ def error( """ if error is None: # Guaranteed because of the overload - assert id is not None # noqa: S101 - assert msg is not None # noqa: S101 + assert id is not None # ruff:ignore[assert] + assert msg is not None # ruff:ignore[assert] error = Error(id, msg) if isinstance(error, Error) and error.id == self.allow: diff --git a/src/pre_commit_hooks/network.py b/src/pre_commit_hooks/network.py index 66f2e85..ec0b4d5 100644 --- a/src/pre_commit_hooks/network.py +++ b/src/pre_commit_hooks/network.py @@ -21,8 +21,8 @@ def is_connected() -> bool: # Connect to the host - tells us if the host is actually reachable s = socket.create_connection((host, 80), 2) s.close() - return True # noqa: TRY300 - except Exception as err: # noqa: BLE001 + return True # ruff:ignore[try-consider-else] + except Exception as err: # ruff:ignore[blind-except] print( colored("Warning", "yellow") + f": no network connection detected " f"(error: {err}), running without autofixes. " @@ -41,11 +41,11 @@ def request( @overload def request( # type: ignore[explicit-any] url: str, params: frozenset[tuple[str, str]] | None = None, *, json: Literal[True] -) -> Any: ... # noqa: ANN401 +) -> Any: ... # ruff:ignore[any-type] @overload def request( # type: ignore[explicit-any] url: str, params: frozenset[tuple[str, str]] | None = None -) -> Any: ... # noqa: ANN401 +) -> Any: ... # ruff:ignore[any-type] @cache def request( # type: ignore[explicit-any, misc] url: str, params: frozenset[tuple[str, str]] | None = None, *, json: bool = True diff --git a/src/pre_commit_hooks/pcad.py b/src/pre_commit_hooks/pcad.py index 6b2fcca..49d0c21 100644 --- a/src/pre_commit_hooks/pcad.py +++ b/src/pre_commit_hooks/pcad.py @@ -59,10 +59,10 @@ def __init__(self, args: Args) -> None: for requirement in requirements: if requirement.url: msg = "Requirement urls not supported" - raise Exception(msg) # noqa: TRY002 + raise Exception(msg) # ruff:ignore[raise-vanilla-class] if requirement.marker: msg = "Requirement markers not supported" - raise Exception(msg) # noqa: TRY002 + raise Exception(msg) # ruff:ignore[raise-vanilla-class] if ( "dependency-groups" in pyproject_data @@ -96,7 +96,7 @@ def get_dep(self, pak: str, lockfile_packages: dict[str, dict[str, str]]) -> str return f"{pak}=={lockfile_version}" - def process_file_path_internal(self, file: Path, *, logger: Logger) -> None: # noqa: ARG002 + def process_file_path_internal(self, file: Path, *, logger: Logger) -> None: # ruff:ignore[unused-method-argument] with file.open("rb") as f: data = yaml.load(f) diff --git a/src/pre_commit_hooks/pccf.py b/src/pre_commit_hooks/pccf.py index 7b87808..d35afb7 100644 --- a/src/pre_commit_hooks/pccf.py +++ b/src/pre_commit_hooks/pccf.py @@ -12,15 +12,15 @@ class Processor(FileContentProcessor): - def process_file_internal( # noqa: C901, PLR0912, PLR6301 + def process_file_internal( # ruff:ignore[complex-structure, too-many-branches, no-self-use] self, content: str, *, - logger: Logger, # noqa: ARG002 + logger: Logger, # ruff:ignore[unused-method-argument] ) -> str | None: output = "" it = peekable(content.splitlines(keepends=True)) - while line := next(it, None): # noqa: PLR1702 + while line := next(it, None): # ruff:ignore[too-many-nested-blocks] if line.startswith("#"): output += line continue diff --git a/src/pre_commit_hooks/pccs.py b/src/pre_commit_hooks/pccs.py index 76a179b..6edd21e 100644 --- a/src/pre_commit_hooks/pccs.py +++ b/src/pre_commit_hooks/pccs.py @@ -13,11 +13,11 @@ class Processor(FileProcessor): - def process_file_path_internal( # noqa: PLR6301 + def process_file_path_internal( # ruff:ignore[no-self-use] self, file: Path, *, - logger: Logger, # noqa: ARG002 + logger: Logger, # ruff:ignore[unused-method-argument] ) -> None: with file.open("rb") as f: data = yaml.load(f) diff --git a/src/pre_commit_hooks/processors.py b/src/pre_commit_hooks/processors.py index eb99e45..ff59c37 100644 --- a/src/pre_commit_hooks/processors.py +++ b/src/pre_commit_hooks/processors.py @@ -21,7 +21,7 @@ class Args(argparse.Namespace): class FileProcessor(ABC): - def __init__(self, _args: Args) -> None: # noqa: B027 + def __init__(self, _args: Args) -> None: # ruff:ignore[empty-method-without-abstract-decorator] pass def process_files(self, files: Iterable[Path], *, logger_type: type[Logger]) -> int: @@ -160,7 +160,7 @@ def process_line_internal( class Bookmark: def __init__(self) -> None: - self.id = "".join(random.choices(string.ascii_letters + string.digits, k=10)) # noqa: S311 + self.id = "".join(random.choices(string.ascii_letters + string.digits, k=10)) # ruff:ignore[suspicious-non-cryptographic-random-usage] self.lines: list[str] = [] def placeholder(self) -> str: diff --git a/src/pre_commit_hooks/shfuncdecfmt.py b/src/pre_commit_hooks/shfuncdecfmt.py index e6e3635..88ac698 100644 --- a/src/pre_commit_hooks/shfuncdecfmt.py +++ b/src/pre_commit_hooks/shfuncdecfmt.py @@ -11,11 +11,11 @@ class Processor(FileContentProcessor): - def process_file_internal( # noqa: PLR6301 + def process_file_internal( # ruff:ignore[no-self-use] self, content: str, *, - logger: Logger, # noqa: ARG002 + logger: Logger, # ruff:ignore[unused-method-argument] ) -> str | None: return re.sub( r"^(\s*)(function\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\s*(?:\(\s*\))?\s*\{", diff --git a/tests/base.py b/tests/base.py index 3fbe1fe..82685d5 100644 --- a/tests/base.py +++ b/tests/base.py @@ -154,15 +154,15 @@ def run(self) -> None: assert Path(tmp).read_text(encoding="utf-8") == inp_m.read_text() @classmethod - def out_double(cls, *args: Any, **kwargs: Any) -> Iterator[TCBase]: # noqa: ANN401 + def out_double(cls, *args: Any, **kwargs: Any) -> Iterator[TCBase]: # ruff:ignore[any-type] """ Return two test cases. One with out, and one on that out without out, to verify a second pass will not have any effect. Any kwargs will be passed to both test cases, any args only to the first. - """ # noqa: DOC402 + """ # ruff:ignore[docstring-missing-yields] first = cls(*args, **kwargs).out() yield first - yield cls(first._out.name, retval=0, **kwargs) # noqa: SLF001 + yield cls(first._out.name, retval=0, **kwargs) # ruff:ignore[private-member-access] class TCFormatterBase(TCBase, ABC): @@ -170,7 +170,7 @@ def __init__(self, inp: str, args: Sequence[str]) -> None: super().__init__(inp, 0, args) @classmethod - def out_double(cls, *args: Any, **kwargs: Any) -> Iterator[TCBase]: # noqa: ANN401 + def out_double(cls, *args: Any, **kwargs: Any) -> Iterator[TCBase]: # ruff:ignore[any-type] first = cls(*args, **kwargs).out() yield first - yield cls(first._out.name, **kwargs) # noqa: SLF001 + yield cls(first._out.name, **kwargs) # ruff:ignore[private-member-access] diff --git a/tests/test_gha.py b/tests/test_gha.py index 484ef34..3a8da14 100644 --- a/tests/test_gha.py +++ b/tests/test_gha.py @@ -14,7 +14,7 @@ class TC(TCBase): def __init__(self, inp: str, retval: int) -> None: super().__init__(inp, retval, [inp]) - def run(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003 + def run(self, *args, **kwargs) -> None: # ruff:ignore[missing-type-args, missing-type-kwargs] removed = { "dawidd6/action-homebrew-bump-formula": default_allows["gha"].pop( "dawidd6/action-homebrew-bump-formula"