From b7be51a944eeb99b33acba9724ff89e7eec12281 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 14 Sep 2025 12:30:01 +0200 Subject: [PATCH 1/8] Enforce more ruff rules --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5396794..43cfc89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,6 +72,8 @@ omit = ["abi3audit/_vendor/*"] [tool.ruff] line-length = 100 +exclude = ["abi3audit/_vendor"] [tool.ruff.lint] -select = ["E", "F", "I", "W", "UP"] +select = ["E", "F", "I", "W", "B", "A", "C4", "EXE", "FA", "ISC", "ICN", "LOG", "PIE", "PYI", "SLOT", "FLY", "PERF", "PGH", "PL", "FURB", "UP"] +ignore = ["PLR1730", "PLR2004"] From 52e3877522b2de6d2bede189306663983843a810 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 13 Sep 2025 23:23:19 +0200 Subject: [PATCH 2/8] Apply ruff/flake8-slots rule SLOT000 SLOT000 Subclasses of `str` should define `__slots__` --- abi3audit/_extract.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/abi3audit/_extract.py b/abi3audit/_extract.py index e14b5e9..0fe0de2 100644 --- a/abi3audit/_extract.py +++ b/abi3audit/_extract.py @@ -50,6 +50,8 @@ class WheelSpec(str): A wheel can contain multiple Python extensions, as shared objects. """ + __slots__ = () + def _extractor(self) -> Extractor: """ Returns an extractor for this wheel's shared objects. @@ -64,6 +66,8 @@ class SharedObjectSpec(str): A shared object may or may not be a Python extension. """ + __slots__ = () + def _extractor(self) -> Extractor: """ Returns a "trivial" extractor for this shared object. @@ -79,6 +83,8 @@ class PyPISpec(str): may be tagged as abi3 compatible. """ + __slots__ = () + def _extractor(self) -> Extractor: """ Returns an extractor for each shared object in each published abi3 wheel. From d6e1139f1a4e48c511cc1272ed4f539122698dd4 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 14 Sep 2025 12:44:51 +0200 Subject: [PATCH 3/8] Apply ruff/flake8-pie rule PIE790 PIE790 Unnecessary `pass` statement --- abi3audit/_extract.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/abi3audit/_extract.py b/abi3audit/_extract.py index 0fe0de2..5a57add 100644 --- a/abi3audit/_extract.py +++ b/abi3audit/_extract.py @@ -40,8 +40,6 @@ class InvalidSpec(ValueError): specification into something that can be extracted. """ - pass - class WheelSpec(str): """ @@ -131,8 +129,6 @@ class ExtractorError(ValueError): from the requested source. """ - pass - class WheelExtractor: """ From 6221208436b524ce937c2220966bbb007ebb6c0c Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 14 Sep 2025 12:46:41 +0200 Subject: [PATCH 4/8] Apply ruff/Perflint rule PERF203 PERF203 `try`-`except` within a loop incurs performance overhead --- abi3audit/_cli.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/abi3audit/_cli.py b/abi3audit/_cli.py index e261359..40080f1 100644 --- a/abi3audit/_cli.py +++ b/abi3audit/_cli.py @@ -228,12 +228,12 @@ def main() -> None: logging.root.setLevel("DEBUG") specs = [] - for spec in args.specs: - try: + try: + for spec in args.specs: specs.extend(make_specs(spec, assume_minimum_abi3=args.assume_minimum_abi3)) - except InvalidSpec as e: - console.log(f"[red]:thumbs_down: processing error: {e}") - sys.exit(1) + except InvalidSpec as e: + console.log(f"[red]:thumbs_down: processing error: {e}") + sys.exit(1) logger.debug(f"parsed arguments: {args}") From 84ee597d038af2986e3f5ad5a03d8d33e4d4464d Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 13 Sep 2025 23:01:23 +0200 Subject: [PATCH 5/8] _object: the assumed ABI version is possibly None --- abi3audit/_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abi3audit/_object.py b/abi3audit/_object.py index 9566612..6eeef55 100644 --- a/abi3audit/_object.py +++ b/abi3audit/_object.py @@ -32,7 +32,7 @@ def __init__(self, extractor: extract.SharedObjectExtractor): self._extractor = extractor self.path = self._extractor.path - def abi3_version(self, assume_lowest: PyVersion) -> PyVersion | None: + def abi3_version(self, assume_lowest: PyVersion | None) -> PyVersion | None: # If we're dealing with a shared object that was extracted from a wheel, # we try and suss out the abi3 version from the wheel's own tags. if self._extractor.parent is not None: From 98a1173c844c6916ec51fe4a453270f0af15ff10 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 13 Sep 2025 23:05:48 +0200 Subject: [PATCH 6/8] Apply ruff/flake8-bugbear rule B008 B008 Do not perform function call in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable --- abi3audit/_audit.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/abi3audit/_audit.py b/abi3audit/_audit.py index ca5fca0..5161809 100644 --- a/abi3audit/_audit.py +++ b/abi3audit/_audit.py @@ -94,10 +94,12 @@ def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderR yield f"[green]:thumbs_up: {self.so}" -def audit(so: SharedObject, assume_minimum_abi3: PyVersion = PyVersion(3, 2)) -> AuditResult: +def audit(so: SharedObject, assume_minimum_abi3: PyVersion | None = None) -> AuditResult: # We might fail to retrieve a minimum abi3 baseline if our context # (the shared object or its containing wheel) isn't actually tagged # as abi3 compatible. + if assume_minimum_abi3 is None: + assume_minimum_abi3 = PyVersion(3, 2) baseline = so.abi3_version(assume_lowest=assume_minimum_abi3) if baseline is None: raise AuditError("failed to determine ABI version baseline: not abi3 tagged?") From ec441d8c316521bc2644370b9f0401cf15b3d77e Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sun, 14 Sep 2025 13:01:44 +0200 Subject: [PATCH 7/8] Enforce ruff flake8-bandit rules (S) Get rid of bandit. --- abi3audit/_cli.py | 2 +- pyproject.toml | 10 +++++----- uv.lock | 18 ------------------ 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/abi3audit/_cli.py b/abi3audit/_cli.py index 40080f1..d8c7e07 100644 --- a/abi3audit/_cli.py +++ b/abi3audit/_cli.py @@ -126,7 +126,7 @@ def json(self) -> dict[str, Any]: # TODO(ww): These inner helpers could definitely be consolidated. def _one_object(results: list[AuditResult]) -> dict[str, Any]: # NOTE: Anything else indicates a logic error. - assert len(results) == 1 + assert len(results) == 1 # noqa: S101 return {"name": results[0].so.path.name, "result": results[0].json()} def _one_wheel(results: list[AuditResult]) -> list[dict[str, Any]]: diff --git a/pyproject.toml b/pyproject.toml index 43cfc89..ff37c47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ Source = "https://github.com/pypa/abi3audit" [project.optional-dependencies] test = ["pytest", "pytest-cov", "pretend", "coverage[toml]"] -lint = ["bandit", "interrogate", "mypy", "ruff", "types-requests"] +lint = ["interrogate", "mypy", "ruff", "types-requests"] dev = ["build", "pdoc3", "abi3audit[test,lint]"] [project.scripts] @@ -64,9 +64,6 @@ warn_unreachable = true warn_unused_configs = true warn_unused_ignores = true -[tool.bandit] -exclude_dirs = ["./test"] - [tool.coverage.run] omit = ["abi3audit/_vendor/*"] @@ -75,5 +72,8 @@ line-length = 100 exclude = ["abi3audit/_vendor"] [tool.ruff.lint] -select = ["E", "F", "I", "W", "B", "A", "C4", "EXE", "FA", "ISC", "ICN", "LOG", "PIE", "PYI", "SLOT", "FLY", "PERF", "PGH", "PL", "FURB", "UP"] +select = ["E", "F", "I", "W", "S", "B", "A", "C4", "EXE", "FA", "ISC", "ICN", "LOG", "PIE", "PYI", "SLOT", "FLY", "PERF", "PGH", "PL", "FURB", "UP"] ignore = ["PLR1730", "PLR2004"] + +[tool.ruff.lint.per-file-ignores] +"test/**.py" = ["S101", "S113"] diff --git a/uv.lock b/uv.lock index 37438e5..7dbdf89 100644 --- a/uv.lock +++ b/uv.lock @@ -22,7 +22,6 @@ dependencies = [ [package.optional-dependencies] dev = [ - { name = "bandit" }, { name = "build" }, { name = "coverage", extra = ["toml"] }, { name = "interrogate" }, @@ -35,7 +34,6 @@ dev = [ { name = "types-requests" }, ] lint = [ - { name = "bandit" }, { name = "interrogate" }, { name = "mypy" }, { name = "ruff" }, @@ -52,7 +50,6 @@ test = [ requires-dist = [ { name = "abi3audit", extras = ["test", "lint"], marker = "extra == 'dev'" }, { name = "abi3info", specifier = ">=2024.6.19" }, - { name = "bandit", marker = "extra == 'lint'" }, { name = "build", marker = "extra == 'dev'" }, { name = "coverage", extras = ["toml"], marker = "extra == 'test'" }, { name = "interrogate", marker = "extra == 'lint'" }, @@ -91,21 +88,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, ] -[[package]] -name = "bandit" -version = "1.8.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "pyyaml" }, - { name = "rich" }, - { name = "stevedore" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fb/b5/7eb834e213d6f73aace21938e5e90425c92e5f42abafaf8a6d5d21beed51/bandit-1.8.6.tar.gz", hash = "sha256:dbfe9c25fc6961c2078593de55fd19f2559f9e45b99f1272341f5b95dea4e56b", size = 4240271, upload-time = "2025-07-06T03:10:50.9Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/ca/ba5f909b40ea12ec542d5d7bdd13ee31c4d65f3beed20211ef81c18fa1f3/bandit-1.8.6-py3-none-any.whl", hash = "sha256:3348e934d736fcdb68b6aa4030487097e23a501adf3e7827b63658df464dddd0", size = 133808, upload-time = "2025-07-06T03:10:49.134Z" }, -] - [[package]] name = "build" version = "1.3.0" From 741590957a3f215d1c28bc2fb0dbb6dc7cfb4a33 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:44:44 +0200 Subject: [PATCH 8/8] Apply reviewer's suggestions Co-authored-by: William Woodruff --- abi3audit/_audit.py | 4 +--- abi3audit/_object.py | 5 ++--- pyproject.toml | 3 +++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/abi3audit/_audit.py b/abi3audit/_audit.py index 5161809..ca5fca0 100644 --- a/abi3audit/_audit.py +++ b/abi3audit/_audit.py @@ -94,12 +94,10 @@ def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderR yield f"[green]:thumbs_up: {self.so}" -def audit(so: SharedObject, assume_minimum_abi3: PyVersion | None = None) -> AuditResult: +def audit(so: SharedObject, assume_minimum_abi3: PyVersion = PyVersion(3, 2)) -> AuditResult: # We might fail to retrieve a minimum abi3 baseline if our context # (the shared object or its containing wheel) isn't actually tagged # as abi3 compatible. - if assume_minimum_abi3 is None: - assume_minimum_abi3 = PyVersion(3, 2) baseline = so.abi3_version(assume_lowest=assume_minimum_abi3) if baseline is None: raise AuditError("failed to determine ABI version baseline: not abi3 tagged?") diff --git a/abi3audit/_object.py b/abi3audit/_object.py index 6eeef55..33c2887 100644 --- a/abi3audit/_object.py +++ b/abi3audit/_object.py @@ -32,7 +32,7 @@ def __init__(self, extractor: extract.SharedObjectExtractor): self._extractor = extractor self.path = self._extractor.path - def abi3_version(self, assume_lowest: PyVersion | None) -> PyVersion | None: + def abi3_version(self, assume_lowest: PyVersion) -> PyVersion | None: # If we're dealing with a shared object that was extracted from a wheel, # we try and suss out the abi3 version from the wheel's own tags. if self._extractor.parent is not None: @@ -59,8 +59,7 @@ def abi3_version(self, assume_lowest: PyVersion | None) -> PyVersion | None: ) return assume_lowest - # With no wheel tags and no filename tag, fall back on the assumed ABI - # version (which is possibly None). + # With no wheel tags and no filename tag, fall back on the assumed ABI version. return assume_lowest def __str__(self) -> str: diff --git a/pyproject.toml b/pyproject.toml index ff37c47..f76da33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,5 +75,8 @@ exclude = ["abi3audit/_vendor"] select = ["E", "F", "I", "W", "S", "B", "A", "C4", "EXE", "FA", "ISC", "ICN", "LOG", "PIE", "PYI", "SLOT", "FLY", "PERF", "PGH", "PL", "FURB", "UP"] ignore = ["PLR1730", "PLR2004"] +[tool.ruff.lint.flake8-bugbear] +extend-immutable-calls = ["abi3info.models.PyVersion"] + [tool.ruff.lint.per-file-ignores] "test/**.py" = ["S101", "S113"]