diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c2b9ca08..66a3cf74 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,34 +19,19 @@ repos: - id: debug-statements - id: end-of-file-fixer exclude: ^cache/ + - id: mixed-line-ending - id: forbid-new-submodules - id: trailing-whitespace -- repo: https://github.com/asottile/pyupgrade - rev: v3.19.1 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.8.5 hooks: - - id: pyupgrade - args: ["--py39-plus"] - -- repo: https://github.com/psf/black - rev: 24.10.0 - hooks: - - id: black - -- repo: https://github.com/PyCQA/isort - rev: 5.13.2 - hooks: - - id: isort - args: ["-a", "from __future__ import annotations"] - exclude: ^tests/integration/.*/src/.*pyx$ - -- repo: https://github.com/PyCQA/flake8 - rev: 7.1.1 - hooks: - - id: flake8 + - id: ruff + args: ["--fix", "--show-fixes"] + - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.14.0 + rev: v1.14.1 hooks: - id: mypy exclude: ^tests/integration/.*/.*$ diff --git a/noxfile.py b/noxfile.py index 3a860f98..1700fc01 100644 --- a/noxfile.py +++ b/noxfile.py @@ -103,7 +103,7 @@ def test_dist(session: nox.Session) -> None: def _test_dist(session: nox.Session, path: str, pattern: str) -> None: (dist_path,) = Path(path).glob(pattern) - session.install(f"{str(dist_path)}[test]") + session.install(f"{dist_path!s}[test]") session.run("pytest", "tests/unit") diff --git a/pyproject.toml b/pyproject.toml index f4e00767..479b34a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,15 +5,6 @@ build-backend = "setuptools.build_meta" [tool.setuptools_scm] # enable version inference -[tool.black] -target-version = ["py39", "py310", "py311", "py312", "py313"] -extend-exclude = "src/auditwheel/_vendor" - -[tool.isort] -py_version = 39 -profile = "black" -extend_skip_glob = "src/auditwheel/_vendor/**/*.py" - [tool.mypy] follow_imports = "silent" ignore_missing_imports = true @@ -23,3 +14,39 @@ warn_unused_ignores = true module = "auditwheel._vendor.*" follow_imports = "skip" ignore_errors = true + +[tool.pytest.ini_options] +log_cli = true +log_cli_level = 20 + +[tool.ruff] +target-version = "py39" +exclude = ["src/auditwheel/_vendor"] + +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "ISC", # flake8-implicit-str-concat + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "TID251", # flake8-tidy-imports.banned-api + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "PYI", # flake8-pyi +] +ignore = [ + "ISC001", # Conflicts with formatter + "PLR", # Design related pylint codes +] diff --git a/scripts/calculate_symbol_versions.py b/scripts/calculate_symbol_versions.py index edd9834a..4759378a 100644 --- a/scripts/calculate_symbol_versions.py +++ b/scripts/calculate_symbol_versions.py @@ -7,6 +7,7 @@ from __future__ import annotations import argparse +import contextlib import json import os import platform @@ -32,7 +33,8 @@ def choose_policy(name, policies): try: return next(policy for policy in policies if policy["name"] == name) except StopIteration: - raise RuntimeError(f"Unknown policy {name}") + msg = f"Unknown policy {name}" + raise RuntimeError(msg) from None def find_library(library): @@ -40,8 +42,8 @@ def find_library(library): path = os.path.join(p, library) if os.path.exists(path): return path - else: - raise RuntimeError(f"Unknown library {library}") + msg = f"Unknown library {library}" + raise RuntimeError(msg) def versionify(version_string): @@ -67,11 +69,8 @@ def calculate_symbol_versions(libraries, symbol_versions, arch): if section: for _, verdef_iter in section.iter_versions(): for vernaux in verdef_iter: - for symbol_name in symbol_versions: - try: - name, version = vernaux.name.split("_", 1) - except ValueError: - pass + with contextlib.suppress(ValueError): + name, version = vernaux.name.split("_", 1) if ( name in calculated_symbol_versions and version != "PRIVATE" diff --git a/setup.cfg b/setup.cfg index 3674ff72..37053729 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,13 +44,3 @@ where = src [options.entry_points] console_scripts = auditwheel = auditwheel.main:main - -[tool:pytest] -log_cli = true -log_cli_level = 20 - -[flake8] -ignore = E203,W503 -max-line-length = 88 -exclude = - _vendor diff --git a/setup.py b/setup.py old mode 100755 new mode 100644 index 89929f7c..b64f20ef --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ "test": ["pytest>=3.4", "jsonschema", "pypatchelf", "pretend", "docker"], "coverage": ["pytest-cov"], } -extras["develop"] = sum(extras.values(), []) extras["coverage"] += extras["test"] +extras["develop"] = list({dep for deps in extras.values() for dep in deps}) setup(extras_require=extras) diff --git a/src/auditwheel/condatools.py b/src/auditwheel/condatools.py index 1af5a51d..a28c231a 100644 --- a/src/auditwheel/condatools.py +++ b/src/auditwheel/condatools.py @@ -32,7 +32,8 @@ def __enter__(self): def iter_files(self) -> list[str]: if self.path is None: - raise ValueError("This function should be called from context manager") + msg = "This function should be called from context manager" + raise ValueError(msg) files = os.path.join(self.path, "info", "files") with open(files) as f: return [line.strip() for line in f.readlines()] diff --git a/src/auditwheel/elfutils.py b/src/auditwheel/elfutils.py index 8927bf00..0cbf6d96 100644 --- a/src/auditwheel/elfutils.py +++ b/src/auditwheel/elfutils.py @@ -16,7 +16,8 @@ def elf_read_dt_needed(fn: str) -> list[str]: elf = ELFFile(f) section = elf.get_section_by_name(".dynamic") if section is None: - raise ValueError("Could not find soname in %s" % fn) + msg = f"Could not find soname in {fn}" + raise ValueError(msg) for t in section.iter_tags(): if t.entry.d_tag == "DT_NEEDED": diff --git a/src/auditwheel/genericpkgctx.py b/src/auditwheel/genericpkgctx.py index 750f8075..684848b6 100644 --- a/src/auditwheel/genericpkgctx.py +++ b/src/auditwheel/genericpkgctx.py @@ -16,7 +16,5 @@ def InGenericPkgCtx( if out_path is not None: raise NotImplementedError() return InCondaPkgCtx(in_path) - - raise ValueError( - "Invalid package: %s. File formats supported: " ".whl, .tar.bz2" % in_path - ) + msg = f"Invalid package: {in_path}. File formats supported: .whl, .tar.bz2" + raise ValueError(msg) diff --git a/src/auditwheel/lddtree.py b/src/auditwheel/lddtree.py index cd529609..2c03259b 100644 --- a/src/auditwheel/lddtree.py +++ b/src/auditwheel/lddtree.py @@ -106,12 +106,12 @@ def parse_ld_paths(str_ldpaths: str, path: str, root: str = "") -> list[str]: for ldpath in str_ldpaths.split(":"): if ldpath == "": # The ldso treats "" paths as $PWD. - ldpath = os.getcwd() + ldpath_ = os.getcwd() elif "$ORIGIN" in ldpath: - ldpath = ldpath.replace("$ORIGIN", os.path.dirname(os.path.abspath(path))) + ldpath_ = ldpath.replace("$ORIGIN", os.path.dirname(os.path.abspath(path))) else: - ldpath = root + ldpath - ldpaths.append(normpath(ldpath)) + ldpath_ = root + ldpath + ldpaths.append(normpath(ldpath_)) return [p for p in dedupe(ldpaths) if os.path.isdir(p)] @@ -140,8 +140,8 @@ def parse_ld_so_conf(ldso_conf: str, root: str = "/", _first: bool = True) -> li try: log.debug("%sparse_ld_so_conf(%s)", dbg_pfx, ldso_conf) with open(ldso_conf) as f: - for line in f.readlines(): - line = line.split("#", 1)[0].strip() + for input_line in f.readlines(): + line = input_line.split("#", 1)[0].strip() if not line: continue if line.startswith("include "): @@ -242,15 +242,7 @@ def compatible_elfs(elf1: ELFFile, elf2: ELFFile) -> bool: """ osabis = frozenset(e.header["e_ident"]["EI_OSABI"] for e in (elf1, elf2)) compat_sets = ( - frozenset( - "ELFOSABI_%s" % x - for x in ( - "NONE", - "SYSV", - "GNU", - "LINUX", - ) - ), + frozenset(f"ELFOSABI_{x}" for x in ("NONE", "SYSV", "GNU", "LINUX")), ) return ( (len(osabis) == 1 or any(osabis.issubset(x) for x in compat_sets)) @@ -302,8 +294,7 @@ def lddtree( ldpaths: dict[str, list[str]] | None = None, display: str | None = None, exclude: frozenset[str] = frozenset(), - _first: bool = True, - _all_libs: dict = {}, + _all_libs: dict | None = None, ) -> dict: """Parse the ELF dependency tree of the specified file @@ -324,8 +315,6 @@ def lddtree( The path to show rather than ``path`` exclude List of soname (DT_NEEDED) to exclude from the tree - _first - Recursive use only; is this the first ELF? _all_libs Recursive use only; dict of all libs we've seen @@ -350,7 +339,8 @@ def lddtree( if not ldpaths: ldpaths = load_ld_paths().copy() - if _first: + _first = _all_libs is None + if _all_libs is None: _all_libs = {} ret: dict[str, Any] = { @@ -363,7 +353,7 @@ def lddtree( "libs": _all_libs, } - log.debug("lddtree(%s)" % path) + log.debug("lddtree(%s)", path) with open(path, "rb") as f: elf = ELFFile(f) @@ -407,7 +397,7 @@ def lddtree( runpaths = parse_ld_paths(t.runpath, path=path, root=root) elif t.entry.d_tag == "DT_NEEDED": if any(fnmatch(t.needed, e) for e in exclude): - log.info(f"Excluding {t.needed}") + log.info("Excluding %s", t.needed) else: libs.append(t.needed) if runpaths: @@ -457,7 +447,6 @@ def lddtree( ldpaths, display=fullpath, exclude=exclude, - _first=False, _all_libs=_all_libs, ) _all_libs[lib]["needed"] = lret["needed"] diff --git a/src/auditwheel/main.py b/src/auditwheel/main.py index 5f1fe8f2..b9775784 100644 --- a/src/auditwheel/main.py +++ b/src/auditwheel/main.py @@ -51,6 +51,4 @@ def main() -> int | None: p.print_help() return None - rval = args.func(args, p) - - return rval + return args.func(args, p) diff --git a/src/auditwheel/main_lddtree.py b/src/auditwheel/main_lddtree.py index d8bf9e60..29e13ce8 100644 --- a/src/auditwheel/main_lddtree.py +++ b/src/auditwheel/main_lddtree.py @@ -1,5 +1,6 @@ from __future__ import annotations +import argparse import logging logger = logging.getLogger(__name__) @@ -12,7 +13,7 @@ def configure_subparser(sub_parsers): p.set_defaults(func=execute) -def execute(args, p): +def execute(args, p: argparse.ArgumentParser): # noqa: ARG001 import json from .lddtree import lddtree diff --git a/src/auditwheel/main_repair.py b/src/auditwheel/main_repair.py index 9f33bc1e..228e6dd8 100644 --- a/src/auditwheel/main_repair.py +++ b/src/auditwheel/main_repair.py @@ -106,7 +106,7 @@ def configure_parser(sub_parsers): p.set_defaults(func=execute) -def execute(args, p): +def execute(args, parser: argparse.ArgumentParser): import os from .repair import repair_wheel @@ -117,7 +117,7 @@ def execute(args, p): for wheel_file in args.WHEEL_FILE: if not isfile(wheel_file): - p.error("cannot access %s. No such file" % wheel_file) + parser.error(f"cannot access {wheel_file}. No such file") logger.info("Repairing %s", basename(wheel_file)) @@ -131,46 +131,48 @@ def execute(args, p): return 1 policy = wheel_policy.get_policy_by_name(args.PLAT) + assert policy is not None reqd_tag = policy["priority"] if reqd_tag > wheel_policy.get_priority_by_name(wheel_abi.sym_tag): msg = ( - 'cannot repair "%s" to "%s" ABI because of the presence ' - "of too-recent versioned symbols. You'll need to compile " - "the wheel on an older toolchain." % (wheel_file, args.PLAT) + f'cannot repair "{wheel_file}" to "{args.PLAT}" ABI because of the ' + "presence of too-recent versioned symbols. You'll need to compile " + "the wheel on an older toolchain." ) - p.error(msg) + parser.error(msg) if reqd_tag > wheel_policy.get_priority_by_name(wheel_abi.ucs_tag): msg = ( - 'cannot repair "%s" to "%s" ABI because it was compiled ' - "against a UCS2 build of Python. You'll need to compile " + f'cannot repair "{wheel_file}" to "{args.PLAT}" ABI because it was ' + "compiled against a UCS2 build of Python. You'll need to compile " "the wheel against a wide-unicode build of Python." - % (wheel_file, args.PLAT) ) - p.error(msg) + parser.error(msg) if reqd_tag > wheel_policy.get_priority_by_name(wheel_abi.blacklist_tag): msg = ( - 'cannot repair "%s" to "%s" ABI because it depends on ' - "black-listed symbols." % (wheel_file, args.PLAT) + f'cannot repair "{wheel_file}" to "{args.PLAT}" ABI because it ' + "depends on black-listed symbols." ) - p.error(msg) + parser.error(msg) abis = [policy["name"]] + policy["aliases"] - if not args.ONLY_PLAT: - if reqd_tag < wheel_policy.get_priority_by_name(wheel_abi.overall_tag): - logger.info( - ( - "Wheel is eligible for a higher priority tag. " - "You requested %s but I have found this wheel is " - "eligible for %s." - ), - args.PLAT, - wheel_abi.overall_tag, - ) - higher_policy = wheel_policy.get_policy_by_name(wheel_abi.overall_tag) - abis = [higher_policy["name"]] + higher_policy["aliases"] + abis + if (not args.ONLY_PLAT) and reqd_tag < wheel_policy.get_priority_by_name( + wheel_abi.overall_tag + ): + logger.info( + ( + "Wheel is eligible for a higher priority tag. " + "You requested %s but I have found this wheel is " + "eligible for %s." + ), + args.PLAT, + wheel_abi.overall_tag, + ) + higher_policy = wheel_policy.get_policy_by_name(wheel_abi.overall_tag) + assert higher_policy is not None + abis = [higher_policy["name"]] + higher_policy["aliases"] + abis patcher = Patchelf() out_wheel = repair_wheel( @@ -187,3 +189,4 @@ def execute(args, p): if out_wheel is not None: logger.info("\nFixed-up wheel written to %s", out_wheel) + return 0 diff --git a/src/auditwheel/main_show.py b/src/auditwheel/main_show.py index d2157ea6..7d736342 100644 --- a/src/auditwheel/main_show.py +++ b/src/auditwheel/main_show.py @@ -1,5 +1,6 @@ from __future__ import annotations +import argparse import logging from auditwheel.policy import WheelPolicies @@ -21,7 +22,7 @@ def printp(text: str) -> None: print("\n".join(wrap(text, break_long_words=False, break_on_hyphens=False))) -def execute(args, p): +def execute(args, parser: argparse.ArgumentParser): import json from os.path import basename, isfile @@ -32,7 +33,7 @@ def execute(args, p): fn = basename(args.WHEEL_FILE) if not isfile(args.WHEEL_FILE): - p.error("cannot access %s. No such file" % args.WHEEL_FILE) + parser.error(f"cannot access {args.WHEEL_FILE}. No such file") try: winfo = analyze_wheel_abi(wheel_policy, args.WHEEL_FILE, frozenset()) @@ -45,8 +46,7 @@ def execute(args, p): ] printp( - '%s is consistent with the following platform tag: "%s".' - % (fn, winfo.overall_tag) + f'{fn} is consistent with the following platform tag: "{winfo.overall_tag}".' ) if ( @@ -59,7 +59,7 @@ def execute(args, p): "#fpectl-builds-vs-no-fpectl-builds)" ) if args.verbose < 1: - return + return None if wheel_policy.get_priority_by_name(winfo.ucs_tag) < wheel_policy.priority_highest: printp( @@ -68,7 +68,7 @@ def execute(args, p): "manylinux1 tag." ) if args.verbose < 1: - return + return None if len(libs_with_versions) == 0: printp( @@ -78,22 +78,19 @@ def execute(args, p): else: printp( "The wheel references external versioned symbols in these " - "system-provided shared libraries: %s" % ", ".join(libs_with_versions) + f"system-provided shared libraries: {', '.join(libs_with_versions)}" ) if wheel_policy.get_priority_by_name(winfo.sym_tag) < wheel_policy.priority_highest: printp( - ( - 'This constrains the platform tag to "%s". ' - "In order to achieve a more compatible tag, you would " - "need to recompile a new wheel from source on a system " - "with earlier versions of these libraries, such as " - "a recent manylinux image." - ) - % winfo.sym_tag + f'This constrains the platform tag to "{winfo.sym_tag}". ' + "In order to achieve a more compatible tag, you would " + "need to recompile a new wheel from source on a system " + "with earlier versions of these libraries, such as " + "a recent manylinux image." ) if args.verbose < 1: - return + return None libs = winfo.external_refs[ wheel_policy.get_policy_name(wheel_policy.priority_lowest) @@ -101,7 +98,7 @@ def execute(args, p): if len(libs) == 0: printp("The wheel requires no external shared libraries! :)") else: - printp("The following external shared libraries are required " "by the wheel:") + printp("The following external shared libraries are required by the wheel:") print(json.dumps(dict(sorted(libs.items())), indent=4)) for p in sorted(wheel_policy.policies, key=lambda p: p["priority"]): @@ -109,23 +106,18 @@ def execute(args, p): libs = winfo.external_refs[p["name"]]["libs"] if len(libs): printp( - ( - 'In order to achieve the tag platform tag "%s" ' - "the following shared library dependencies " - "will need to be eliminated:" - ) - % p["name"] + f'In order to achieve the tag platform tag "{p["name"]}" ' + "the following shared library dependencies " + "will need to be eliminated:" ) printp(", ".join(sorted(libs.keys()))) blacklist = winfo.external_refs[p["name"]]["blacklist"] if len(blacklist): printp( - ( - 'In order to achieve the tag platform tag "%s" ' - "the following black-listed symbol dependencies " - "will need to be eliminated:" - ) - % p["name"] + f'In order to achieve the tag platform tag "{p["name"]}" ' + "the following black-listed symbol dependencies " + "will need to be eliminated:" ) for key in sorted(blacklist.keys()): printp(f"From {key}: " + ", ".join(sorted(blacklist[key]))) + return 0 diff --git a/src/auditwheel/musllinux.py b/src/auditwheel/musllinux.py index d3e8ed38..cdaee3ea 100644 --- a/src/auditwheel/musllinux.py +++ b/src/auditwheel/musllinux.py @@ -22,7 +22,7 @@ def find_musl_libc() -> pathlib.Path: (dl_path,) = list(pathlib.Path("/lib").glob("libc.musl-*.so.1")) except ValueError: LOG.debug("musl libc not detected") - raise InvalidLibc + raise InvalidLibc() from None return dl_path @@ -32,15 +32,13 @@ def get_musl_version(ld_path: pathlib.Path) -> MuslVersion: ld = subprocess.run( [ld_path], check=False, errors="strict", stderr=subprocess.PIPE ).stderr - except FileNotFoundError: - LOG.error("Failed to determine musl version", exc_info=True) - raise InvalidLibc + except FileNotFoundError as err: + LOG.exception("Failed to determine musl version") + raise InvalidLibc() from err - match = re.search( - r"Version " r"(?P\d+)." r"(?P\d+)." r"(?P\d+)", ld - ) + match = re.search(r"Version (?P\d+).(?P\d+).(?P\d+)", ld) if not match: - raise InvalidLibc + raise InvalidLibc() from None return MuslVersion( int(match.group("major")), int(match.group("minor")), int(match.group("patch")) diff --git a/src/auditwheel/patcher.py b/src/auditwheel/patcher.py index 67367c93..0dc551e4 100644 --- a/src/auditwheel/patcher.py +++ b/src/auditwheel/patcher.py @@ -8,16 +8,16 @@ class ElfPatcher: def replace_needed(self, file_name: str, *old_new_pairs: tuple[str, str]) -> None: - raise NotImplementedError + raise NotImplementedError() def set_soname(self, file_name: str, new_so_name: str) -> None: - raise NotImplementedError + raise NotImplementedError() def set_rpath(self, file_name: str, rpath: str) -> None: - raise NotImplementedError + raise NotImplementedError() def get_rpath(self, file_name: str) -> str: - raise NotImplementedError + raise NotImplementedError() def _verify_patchelf() -> None: @@ -26,18 +26,19 @@ def _verify_patchelf() -> None: version can't be found. Otherwise, silence is golden """ if not which("patchelf"): - raise ValueError("Cannot find required utility `patchelf` in PATH") + msg = "Cannot find required utility `patchelf` in PATH" + raise ValueError(msg) try: version = check_output(["patchelf", "--version"]).decode("utf-8") except CalledProcessError: - raise ValueError("Could not call `patchelf` binary") + msg = "Could not call `patchelf` binary" + raise ValueError(msg) from None m = re.match(r"patchelf\s+(\d+(.\d+)?)", version) if m and tuple(int(x) for x in m.group(1).split(".")) >= (0, 14): return - raise ValueError( - f"patchelf {version} found. auditwheel repair requires " "patchelf >= 0.14." - ) + msg = f"patchelf {version} found. auditwheel repair requires " "patchelf >= 0.14." + raise ValueError(msg) class Patchelf(ElfPatcher): diff --git a/src/auditwheel/policy/__init__.py b/src/auditwheel/policy/__init__.py index 79ec72e7..874fb27a 100644 --- a/src/auditwheel/policy/__init__.py +++ b/src/auditwheel/policy/__init__.py @@ -40,13 +40,15 @@ def __init__( if libc is None: libc = get_libc() if musl_policy is None else Libc.MUSL if libc != Libc.MUSL and musl_policy is not None: - raise ValueError(f"'musl_policy' shall be None for libc {libc.name}") + msg = f"'musl_policy' shall be None for libc {libc.name}" + raise ValueError(msg) if libc == Libc.MUSL: if musl_policy is None: musl_version = get_musl_version(find_musl_libc()) musl_policy = f"musllinux_{musl_version.major}_{musl_version.minor}" elif _MUSL_POLICY_RE.match(musl_policy) is None: - raise ValueError(f"Invalid 'musl_policy': '{musl_policy}'") + msg = f"Invalid 'musl_policy': '{musl_policy}'" + raise ValueError(msg) if arch is None: arch = get_arch_name() policies = json.loads(_POLICY_JSON_MAP[libc].read_text()) @@ -63,7 +65,7 @@ def __init__( }: continue if ( - self._arch_name in policy["symbol_versions"].keys() + self._arch_name in policy["symbol_versions"] or policy["name"] == "linux" ): if policy["name"] != "linux": @@ -101,7 +103,8 @@ def get_policy_by_name(self, name: str) -> dict | None: if len(matches) == 0: return None if len(matches) > 1: - raise RuntimeError("Internal error. Policies should be unique") + msg = "Internal error. Policies should be unique" + raise RuntimeError(msg) return matches[0] def get_policy_name(self, priority: int) -> str | None: @@ -109,7 +112,8 @@ def get_policy_name(self, priority: int) -> str | None: if len(matches) == 0: return None if len(matches) > 1: - raise RuntimeError("Internal error. priorities should be unique") + msg = "Internal error. priorities should be unique" + raise RuntimeError(msg) return matches[0] def get_priority_by_name(self, name: str) -> int | None: @@ -150,7 +154,8 @@ def policy_is_satisfied( if len(matching_policies) == 0: # the base policy (generic linux) should always match - raise RuntimeError("Internal error") + msg = "Internal error" + raise RuntimeError(msg) return max(matching_policies) @@ -246,22 +251,24 @@ def _validate_pep600_compliance(policies) -> None: continue if not lib_whitelist.issubset(set(policy["lib_whitelist"])): diff = lib_whitelist - set(policy["lib_whitelist"]) - raise ValueError( + msg = ( 'Invalid "policy.json" file. Missing whitelist libraries in ' f'"{policy["name"]}" compared to previous policies: {diff}' ) + raise ValueError(msg) lib_whitelist.update(policy["lib_whitelist"]) - for arch in policy["symbol_versions"].keys(): + for arch in policy["symbol_versions"]: symbol_versions_arch = symbol_versions.get(arch, defaultdict(set)) - for prefix in policy["symbol_versions"][arch].keys(): + for prefix in policy["symbol_versions"][arch]: policy_symbol_versions = set(policy["symbol_versions"][arch][prefix]) if not symbol_versions_arch[prefix].issubset(policy_symbol_versions): diff = symbol_versions_arch[prefix] - policy_symbol_versions - raise ValueError( + msg = ( 'Invalid "policy.json" file. Symbol versions missing ' f'in "{policy["name"]}_{arch}" for "{prefix}" ' f"compared to previous policies: {diff}" ) + raise ValueError(msg) symbol_versions_arch[prefix].update( policy["symbol_versions"][arch][prefix] ) @@ -285,7 +292,7 @@ def _fixup_musl_libc_soname(libc: Libc, arch: str, whitelist): for soname in whitelist: if soname in soname_map: new_soname = soname_map[soname][arch] - logger.debug(f"Replacing whitelisted '{soname}' by '{new_soname}'") + logger.debug("Replacing whitelisted '%s' by '%s'", soname, new_soname) new_whitelist.append(new_soname) else: new_whitelist.append(soname) @@ -316,8 +323,7 @@ def get_replace_platforms(name: str) -> list[str]: def _load_policy_schema(): with open(join(dirname(abspath(__file__)), "policy-schema.json")) as f_: - schema = json.load(f_) - return schema + return json.load(f_) __all__ = [ diff --git a/src/auditwheel/repair.py b/src/auditwheel/repair.py index 2a162cc8..ad6802de 100644 --- a/src/auditwheel/repair.py +++ b/src/auditwheel/repair.py @@ -61,7 +61,8 @@ def repair_wheel( match = WHEEL_INFO_RE(wheel_fname) if not match: - raise ValueError("Failed to parse wheel file name: %s", wheel_fname) + msg = f"Failed to parse wheel file name: {wheel_fname}" + raise ValueError(msg) dest_dir = match.group("name") + lib_sdir @@ -74,13 +75,11 @@ def repair_wheel( assert not any(fnmatch(soname, e) for e in exclude) if src_path is None: - raise ValueError( - ( - "Cannot repair wheel, because required " - 'library "%s" could not be located' - ) - % soname + msg = ( + "Cannot repair wheel, because required " + f'library "{soname}" could not be located' ) + raise ValueError(msg) if not exists(dest_dir): os.mkdir(dest_dir) @@ -91,18 +90,19 @@ def repair_wheel( patcher.replace_needed(fn, *replacements) if len(ext_libs) > 0: + new_fn = fn if _path_is_script(fn): - fn = _replace_elf_script_with_shim(match.group("name"), fn) + new_fn = _replace_elf_script_with_shim(match.group("name"), fn) - new_rpath = os.path.relpath(dest_dir, os.path.dirname(fn)) + new_rpath = os.path.relpath(dest_dir, os.path.dirname(new_fn)) new_rpath = os.path.join("$ORIGIN", new_rpath) - append_rpath_within_wheel(fn, new_rpath, ctx.name, patcher) + append_rpath_within_wheel(new_fn, new_rpath, ctx.name, patcher) # we grafted in a bunch of libraries and modified their sonames, but # they may have internal dependencies (DT_NEEDED) on one another, so # we need to update those records so each now knows about the new # name of the other. - for old_soname, (new_soname, path) in soname_map.items(): + for _, path in soname_map.values(): needed = elf_read_dt_needed(path) replacements = [] for n in needed: @@ -146,7 +146,7 @@ def copylib(src_path: str, dest_dir: str, patcher: ElfPatcher) -> tuple[str, str src_name = os.path.basename(src_path) base, ext = src_name.split(".", 1) - if not base.endswith("-%s" % shorthash): + if not base.endswith(f"-{shorthash}"): new_soname = f"{base}-{shorthash}.{ext}" else: new_soname = src_name @@ -204,26 +204,20 @@ def _is_valid_rpath(rpath: str, lib_dir: str, wheel_base_dir: str) -> bool: full_rpath_entry = _resolve_rpath_tokens(rpath, lib_dir) if not isabs(full_rpath_entry): logger.debug( - f"rpath entry {rpath} could not be resolved to an " - "absolute path -- discarding it." + "rpath entry %s could not be resolved to an absolute path -- discarding it.", + rpath, ) return False - elif not is_subdir(full_rpath_entry, wheel_base_dir): - logger.debug( - f"rpath entry {rpath} points outside the wheel -- " "discarding it." - ) + if not is_subdir(full_rpath_entry, wheel_base_dir): + logger.debug("rpath entry %s points outside the wheel -- discarding it.", rpath) return False - else: - logger.debug(f"Preserved rpath entry {rpath}") - return True + logger.debug("Preserved rpath entry %s", rpath) + return True def _resolve_rpath_tokens(rpath: str, lib_base_dir: str) -> str: # See https://www.man7.org/linux/man-pages/man8/ld.so.8.html#DESCRIPTION - if platform.architecture()[0] == "64bit": - system_lib_dir = "lib64" - else: - system_lib_dir = "lib" + system_lib_dir = "lib64" if platform.architecture()[0] == "64bit" else "lib" system_processor_type = platform.machine() token_replacements = { "ORIGIN": lib_base_dir, @@ -274,7 +268,7 @@ def _replace_elf_script_with_shim(package_name: str, orig_path: str) -> str: def _script_shim(binary_path: str) -> str: - return """\ + return f"""\ #!python import os import sys @@ -283,9 +277,7 @@ def _script_shim(binary_path: str) -> str: if __name__ == "__main__": os.execv( - os.path.join(sysconfig.get_path("platlib"), {binary_path!r}), + os.path.join(sysconfig.get_path("platlib"), {Path(binary_path).as_posix()!r}), sys.argv, ) -""".format( - binary_path=Path(binary_path).as_posix(), - ) +""" diff --git a/src/auditwheel/tmpdirs.py b/src/auditwheel/tmpdirs.py index 4fd233d5..9f9ab6cb 100644 --- a/src/auditwheel/tmpdirs.py +++ b/src/auditwheel/tmpdirs.py @@ -1,5 +1,4 @@ -""" Contexts for *with* statement providing temporary directories -""" +"""Contexts for *with* statement providing temporary directories""" from __future__ import annotations diff --git a/src/auditwheel/tools.py b/src/auditwheel/tools.py index 29c8ef50..73ab7e15 100644 --- a/src/auditwheel/tools.py +++ b/src/auditwheel/tools.py @@ -66,10 +66,13 @@ def walk(topdir: str) -> Generator[tuple[str, list[str], list[str]]]: # sort list of filenames for iteration in reproducible order filenames.sort() # list any dist-info/RECORD file last - if dirpath.endswith(".dist-info") and os.path.dirname(dirpath) == topdir: - if "RECORD" in filenames: - filenames.remove("RECORD") - filenames.append("RECORD") + if ( + dirpath.endswith(".dist-info") + and os.path.dirname(dirpath) == topdir + and "RECORD" in filenames + ): + filenames.remove("RECORD") + filenames.append("RECORD") yield dirpath, dirnames, filenames @@ -120,7 +123,7 @@ def dir2zip(in_dir: str, zip_fname: str, date_time: datetime | None = None) -> N date_time_args = date_time.timetuple()[:6] compression = zipfile.ZIP_DEFLATED with zipfile.ZipFile(zip_fname, "w", compression=compression) as z: - for root, dirs, files in walk(in_dir): + for root, _, files in walk(in_dir): if root != in_dir: dname = root out_dname = os.path.relpath(dname, in_dir) + "/" @@ -170,4 +173,7 @@ def __init__(self, env, required=True, default=None, **kwargs): super().__init__(default=default, required=required, **kwargs) def __call__(self, parser, namespace, values, option_string=None): + # use self assignment to silence ARG002 + parser = parser # noqa: PLW0127 + option_string = option_string # noqa: PLW0127 setattr(namespace, self.dest, values) diff --git a/src/auditwheel/wheel_abi.py b/src/auditwheel/wheel_abi.py index 16ae9d7e..2e953655 100644 --- a/src/auditwheel/wheel_abi.py +++ b/src/auditwheel/wheel_abi.py @@ -22,7 +22,7 @@ from .policy import WheelPolicies log = logging.getLogger(__name__) -WheelAbIInfo = namedtuple( +WheelAbIInfo = namedtuple( # noqa: PYI024 "WheelAbIInfo", [ "overall_tag", @@ -114,16 +114,14 @@ def get_wheel_elfdata( # If at least one shared library exists in purelib, raise an error if shared_libraries_in_purelib: - raise RuntimeError( - ( - "Invalid binary wheel, found the following shared " - "library/libraries in purelib folder:\n" - "\t%s\n" - "The wheel has to be platlib compliant in order to be " - "repaired by auditwheel." - ) - % "\n\t".join(shared_libraries_in_purelib) + libraries = "\n\t".join(shared_libraries_in_purelib) + msg = ( + "Invalid binary wheel, found the following shared library/libraries " + f"in purelib folder:\n\t{libraries}\n" + "The wheel has to be platlib compliant in order to be repaired by " + "auditwheel." ) + raise RuntimeError(msg) # Get a list of all external libraries needed by ELFs in the wheel. needed_libs = { @@ -132,18 +130,18 @@ def get_wheel_elfdata( for lib in elf["needed"] } - for fn in nonpy_elftree.keys(): + for fn, elf_tree in nonpy_elftree.items(): # If a non-pyextension ELF file is not needed by something else # inside the wheel, then it was not checked by the logic above and # we should walk its elftree. if basename(fn) not in needed_libs: - full_elftree[fn] = nonpy_elftree[fn] + full_elftree[fn] = elf_tree # Even if a non-pyextension ELF file is not needed, we # should include it as an external reference, because # it might require additional external libraries. full_external_refs[fn] = wheel_policy.lddtree_external_references( - nonpy_elftree[fn], ctx.path + elf_tree, ctx.path ) log.debug("full_elftree:\n%s", json.dumps(full_elftree, indent=4)) @@ -175,7 +173,7 @@ def get_external_libs(external_refs) -> dict[str, str]: continue # go through all libs, retrieving their soname and realpath for libname, realpath in policy["libs"].items(): - if realpath and realpath not in result.keys(): + if realpath and realpath not in result: result[realpath] = libname return result @@ -217,7 +215,7 @@ def get_symbol_policies( if policy["priority"] == 0: continue policy_symbols = deepcopy(versioned_symbols) - for soname in policy["libs"].keys(): + for soname in policy["libs"]: if soname not in external_versioned_symbols: continue ext_symbols = external_versioned_symbols[soname] @@ -245,7 +243,7 @@ def analyze_wheel_abi( uses_PyFPE_jbuf, ) = get_wheel_elfdata(wheel_policy, wheel_fn, exclude) - for fn in elftree_by_fn.keys(): + for fn in elftree_by_fn: update(external_refs, external_refs_by_fn[fn]) log.debug("external reference info") @@ -319,5 +317,6 @@ def update(d, u): elif isinstance(v, (str, int, float, type(None))): d[k] = u[k] else: - raise RuntimeError("!", d, k) + msg = f"can't update {d} {k}" + raise RuntimeError(msg) return d diff --git a/src/auditwheel/wheeltools.py b/src/auditwheel/wheeltools.py index 70180b89..aac57c6f 100644 --- a/src/auditwheel/wheeltools.py +++ b/src/auditwheel/wheeltools.py @@ -1,4 +1,4 @@ -""" General tools for working with wheels +"""General tools for working with wheels Tools that aren't specific to delocation """ @@ -14,11 +14,9 @@ from collections.abc import Generator, Iterable from datetime import datetime, timezone from itertools import product -from os.path import abspath, basename, dirname, exists +from os.path import abspath, basename, dirname, exists, relpath, splitext from os.path import join as pjoin -from os.path import relpath from os.path import sep as psep -from os.path import splitext from types import TracebackType from packaging.utils import parse_wheel_filename @@ -45,7 +43,8 @@ def _dist_info_dir(bdist_dir: str) -> str: info_dirs = glob.glob(pjoin(bdist_dir, "*.dist-info")) if len(info_dirs) != 1: - raise WheelToolsError("Should be exactly one `*.dist_info` directory") + msg = "Should be exactly one `*.dist_info` directory" + raise WheelToolsError(msg) return info_dirs[0] @@ -70,9 +69,9 @@ def rewrite_record(bdist_dir: str) -> None: os.unlink(sig_path) def files() -> Generator[str]: - for dir, _, files in walk(bdist_dir): + for dir_, _, files in walk(bdist_dir): for file in files: - yield pjoin(dir, file) + yield pjoin(dir_, file) def skip(path: str) -> bool: """Wheel hashes every possible file.""" @@ -175,10 +174,12 @@ def __enter__(self): def iter_files(self) -> Generator[str]: if self.path is None: - raise ValueError("This function should be called from context manager") + msg = "This function should be called from context manager" + raise ValueError(msg) record_names = glob.glob(os.path.join(self.path, "*.dist-info/RECORD")) if len(record_names) != 1: - raise ValueError("Should be exactly one `*.dist_info` directory") + msg = "Should be exactly one `*.dist_info` directory" + raise ValueError(msg) with open(record_names[0]) as f: record = f.read() @@ -210,9 +211,8 @@ def add_platforms( definitely_not_purelib = False if wheel_ctx.path is None: - raise ValueError( - "This function should be called from wheel_ctx context manager" - ) + msg = "This function should be called from wheel_ctx context manager" + raise ValueError(msg) info_fname = pjoin(_dist_info_dir(wheel_ctx.path), "WHEEL") info = read_pkg_info(info_fname) diff --git a/tests/integration/nonpy_rpath/setup.py b/tests/integration/nonpy_rpath/setup.py index ce2c57f6..5503aa02 100644 --- a/tests/integration/nonpy_rpath/setup.py +++ b/tests/integration/nonpy_rpath/setup.py @@ -88,7 +88,7 @@ def link_args(soname=None): pkg_name + "." + crypt_name, language="c++", extra_compile_args=["-lcrypt"], - extra_link_args=link_args(crypt_soname) + ["-lcrypt"], + extra_link_args=[*link_args(crypt_soname), "-lcrypt"], sources=["extensions/testcrypt.cpp"], ) diff --git a/tests/integration/test_bundled_wheels.py b/tests/integration/test_bundled_wheels.py index a63305a3..13adb7bd 100644 --- a/tests/integration/test_bundled_wheels.py +++ b/tests/integration/test_bundled_wheels.py @@ -21,7 +21,7 @@ @pytest.mark.parametrize( - "file, external_libs, exclude", + ("file", "external_libs", "exclude"), [ ("cffi-1.5.0-cp27-none-linux_x86_64.whl", {"libffi.so.5"}, frozenset()), ("cffi-1.5.0-cp27-none-linux_x86_64.whl", set(), frozenset(["libffi.so.5"])), diff --git a/tests/integration/test_manylinux.py b/tests/integration/test_manylinux.py index c8d1fbdc..05b75023 100644 --- a/tests/integration/test_manylinux.py +++ b/tests/integration/test_manylinux.py @@ -100,14 +100,19 @@ def find_src_folder(): contents = os.listdir(candidate) if "setup.py" in contents and "src" in contents: return candidate + return None -def docker_start(image, volumes={}, env_variables={}): +def docker_start(image, volumes=None, env_variables=None): """Start a long waiting idle program in container Return the container object to be used for 'docker exec' commands. """ # Make sure to use the latest public version of the docker image + if env_variables is None: + env_variables = {} + if volumes is None: + volumes = {} client = docker.from_env() dvolumes = {host: {"bind": ctr, "mode": "rw"} for (ctr, host) in volumes.items()} @@ -125,7 +130,9 @@ def docker_start(image, volumes={}, env_variables={}): @contextmanager -def docker_container_ctx(image, io_dir=None, env_variables={}): +def docker_container_ctx(image, io_dir=None, env_variables=None): + if env_variables is None: + env_variables = {} src_folder = find_src_folder() if src_folder is None: pytest.skip("Can only be run from the source folder") @@ -157,7 +164,7 @@ def docker_exec(container, cmd, expected_retcode=0): @contextmanager -def tmp_docker_image(base, commands, setup_env={}): +def tmp_docker_image(base, commands, setup_env=None): """Make a temporary docker image for tests Pulls the *base* image, runs *commands* inside it with *setup_env*, and @@ -167,6 +174,8 @@ def tmp_docker_image(base, commands, setup_env={}): Making temporary images like this avoids each test having to re-run the same container setup steps. """ + if setup_env is None: + setup_env = {} with docker_container_ctx(base, env_variables=setup_env) as con: for cmd in commands: docker_exec(con, cmd) @@ -242,18 +251,18 @@ def build_numpy(container, policy, output_dir): class Anylinux: - @pytest.fixture() + @pytest.fixture def io_folder(self, tmp_path): d = tmp_path / "io" d.mkdir(exist_ok=True) return str(d) - @pytest.fixture() + @pytest.fixture def docker_python(self, docker_python_img, io_folder): with docker_container_ctx(docker_python_img, io_folder) as container: yield container - @pytest.fixture() + @pytest.fixture def any_manylinux_container(self, any_manylinux_img, io_folder): policy, manylinux_img = any_manylinux_img env = {"PATH": PATH[policy]} @@ -263,7 +272,7 @@ def any_manylinux_container(self, any_manylinux_img, io_folder): with docker_container_ctx(manylinux_img, io_folder, env) as container: platform_tag = ".".join( - [f"{p}_{PLATFORM}" for p in [policy] + POLICY_ALIASES.get(policy, [])] + [f"{p}_{PLATFORM}" for p in [policy, *POLICY_ALIASES.get(policy, [])]] ) yield f"{policy}_{PLATFORM}", platform_tag, container @@ -824,7 +833,7 @@ def any_manylinux_img(self, request): "manylinux_2_5": {"38", "39"}, "manylinux_2_12": {"38", "39", "310"}, } - check_set = support_check_map.get(policy, None) + check_set = support_check_map.get(policy) if check_set and PYTHON_ABI_MAJ_MIN not in check_set: pytest.skip(f"{policy} images do not support cp{PYTHON_ABI_MAJ_MIN}") @@ -886,7 +895,7 @@ def test_build_wheel_with_image_dependencies( policy_priority = wheel_policy.get_priority_by_name(policy) older_policies = [ f"{p}_{PLATFORM}" - for p in MANYLINUX_IMAGES.keys() + for p in MANYLINUX_IMAGES if policy_priority < wheel_policy.get_priority_by_name(f"{p}_{PLATFORM}") ] for target_policy in older_policies: @@ -917,10 +926,7 @@ def test_build_wheel_with_image_dependencies( # check the original wheel with a dependency was not compliant # and check the one without a dependency was already compliant - if with_dependency == "1": - expected = f"linux_{PLATFORM}" - else: - expected = policy + expected = f"linux_{PLATFORM}" if with_dependency == "1" else policy assert_show_output(manylinux_ctr, orig_wheel, expected, True) docker_exec(docker_python, "pip install /io/" + repaired_wheel) @@ -1018,7 +1024,7 @@ def test_build_wheel_compat( ], ) - def test_zlib_blacklist(self, any_manylinux_container, docker_python, io_folder): + def test_zlib_blacklist(self, any_manylinux_container, io_folder): policy, tag, manylinux_ctr = any_manylinux_container if policy.startswith(("manylinux_2_17_", "manylinux_2_28_", "manylinux_2_34_")): pytest.skip(f"{policy} image has no blacklist symbols in libz.so.1") diff --git a/tests/integration/test_nonplatform_wheel.py b/tests/integration/test_nonplatform_wheel.py index ff1ac144..614643ac 100644 --- a/tests/integration/test_nonplatform_wheel.py +++ b/tests/integration/test_nonplatform_wheel.py @@ -15,6 +15,7 @@ def test_non_platform_wheel_repair(mode): ["auditwheel", mode, str(wheel)], stderr=subprocess.PIPE, text=True, + check=False, ) assert proc.returncode == 1 assert "This does not look like a platform wheel" in proc.stderr diff --git a/tests/unit/test_condatools.py b/tests/unit/test_condatools.py index 7f9c76c4..ef802fa6 100644 --- a/tests/unit/test_condatools.py +++ b/tests/unit/test_condatools.py @@ -6,14 +6,14 @@ @patch("auditwheel.condatools.tarbz2todir") -def test_in_condapkg(tarbz2todir_mock): +def test_in_condapkg(_): # noqa: PT019 with InCondaPkg("/fakepath"): assert True @patch("auditwheel.condatools.tarbz2todir") @patch("auditwheel.condatools.open") -def test_in_condapkg_context(open_mock, tarbz2todir_mock): +def test_in_condapkg_context(open_mock, _): # noqa: PT019 with InCondaPkgCtx("/fakepath") as conda_pkg: file_mock = Mock() file_mock.readlines.return_value = ["file1\n", "file2\n", "\n"] @@ -22,4 +22,5 @@ def test_in_condapkg_context(open_mock, tarbz2todir_mock): # might be a subtle bug in the implementation. files = conda_pkg.iter_files() assert len(files) == 3 - assert "file1" and "file2" in files + assert "file1" in files + assert "file2" in files diff --git a/tests/unit/test_elfpatcher.py b/tests/unit/test_elfpatcher.py index 5a5e3dd5..946f0406 100644 --- a/tests/unit/test_elfpatcher.py +++ b/tests/unit/test_elfpatcher.py @@ -11,27 +11,33 @@ @patch("auditwheel.patcher.which") def test_patchelf_unavailable(which): which.return_value = False - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="Cannot find required utility"): Patchelf() +@patch("auditwheel.patcher.which") @patch("auditwheel.patcher.check_output") -def test_patchelf_check_output_fail(check_output): +def test_patchelf_check_output_fail(check_output, which): + which.return_value = True check_output.side_effect = CalledProcessError(1, "patchelf --version") with pytest.raises(ValueError, match="Could not call"): Patchelf() +@patch("auditwheel.patcher.which") @patch("auditwheel.patcher.check_output") @pytest.mark.parametrize("version", ["0.14", "0.14.1", "0.15"]) -def test_patchelf_version_check(check_output, version): +def test_patchelf_version_check(check_output, which, version): + which.return_value = True check_output.return_value.decode.return_value = f"patchelf {version}" Patchelf() +@patch("auditwheel.patcher.which") @patch("auditwheel.patcher.check_output") @pytest.mark.parametrize("version", ["0.13.99", "0.13", "0.9", "0.1"]) -def test_patchelf_version_check_fail(check_output, version): +def test_patchelf_version_check_fail(check_output, which, version): + which.return_value = True check_output.return_value.decode.return_value = f"patchelf {version}" with pytest.raises(ValueError, match=f"patchelf {version} found"): Patchelf() @@ -43,7 +49,7 @@ def test_patchelf_version_check_fail(check_output, version): class TestPatchElf: """ "Validate that patchelf is invoked with the correct arguments.""" - def test_replace_needed_one(self, check_call, _0, _1): + def test_replace_needed_one(self, check_call, _0, _1): # noqa: PT019 patcher = Patchelf() filename = "test.so" soname_old = "TEST_OLD" @@ -53,7 +59,7 @@ def test_replace_needed_one(self, check_call, _0, _1): ["patchelf", "--replace-needed", soname_old, soname_new, filename] ) - def test_replace_needed_multple(self, check_call, _0, _1): + def test_replace_needed_multple(self, check_call, _0, _1): # noqa: PT019 patcher = Patchelf() filename = "test.so" replacements = [ @@ -72,7 +78,7 @@ def test_replace_needed_multple(self, check_call, _0, _1): ] ) - def test_set_soname(self, check_call, _0, _1): + def test_set_soname(self, check_call, _0, _1): # noqa: PT019 patcher = Patchelf() filename = "test.so" soname_new = "TEST_NEW" @@ -81,7 +87,7 @@ def test_set_soname(self, check_call, _0, _1): ["patchelf", "--set-soname", soname_new, filename] ) - def test_set_rpath(self, check_call, _0, _1): + def test_set_rpath(self, check_call, _0, _1): # noqa: PT019 patcher = Patchelf() patcher.set_rpath("test.so", "$ORIGIN/.lib") check_call_expected_args = [ @@ -93,7 +99,7 @@ def test_set_rpath(self, check_call, _0, _1): assert check_call.call_args_list == check_call_expected_args - def test_get_rpath(self, _0, check_output, _1): + def test_get_rpath(self, _0, check_output, _1): # noqa: PT019 patcher = Patchelf() check_output.return_value = b"existing_rpath" result = patcher.get_rpath("test.so") diff --git a/tests/unit/test_elfutils.py b/tests/unit/test_elfutils.py index ec7752b8..75a95d6b 100644 --- a/tests/unit/test_elfutils.py +++ b/tests/unit/test_elfutils.py @@ -35,7 +35,7 @@ def test_missing_section(self, elffile_mock, open_mock): elffile_mock.return_value.get_section_by_name.return_value = None # THEN - with pytest.raises(ValueError): + with pytest.raises(ValueError, match=r"^Could not find soname.*"): # WHEN elf_read_dt_needed("/fake.so") @@ -62,15 +62,15 @@ def test_needed_libs(self, elffile_mock, open_mock): @patch("auditwheel.elfutils.open") @patch("auditwheel.elfutils.ELFFile") class TestElfFileFilter: - def test_filter(self, elffile_mock, open_mock): + def test_filter(self, elffile_mock, open_mock): # noqa: ARG002 result = elf_file_filter(["file1.so", "file2.so"]) assert len(list(result)) == 2 - def test_some_py_files(self, elffile_mock, open_mock): + def test_some_py_files(self, elffile_mock, open_mock): # noqa: ARG002 result = elf_file_filter(["file1.py", "file2.so", "file3.py"]) assert len(list(result)) == 1 - def test_not_elf(self, elffile_mock, open_mock): + def test_not_elf(self, elffile_mock, open_mock): # noqa: ARG002 # GIVEN elffile_mock.side_effect = ELFError @@ -137,7 +137,7 @@ def test_elf_find_ucs2_symbols(self): asunicode = MockSymbol( "PyUnicodeUCS2_AsUnicode", st_shndx="SHN_UNDEF", - st_info=dict(type="STT_FUNC"), + st_info={"type": "STT_FUNC"}, ) symbols = (asunicode, Mock()) symbols[1].name = "foobar" @@ -168,7 +168,7 @@ def test_elf_references_pyfpe_jbuf(self): elf = Mock() symbols = ( MockSymbol( - "PyFPE_jbuf", st_shndx="SHN_UNDEF", st_info=dict(type="STT_FUNC") + "PyFPE_jbuf", st_shndx="SHN_UNDEF", st_info={"type": "STT_FUNC"} ), ) @@ -182,7 +182,7 @@ def test_elf_references_pyfpe_jbuf_false(self): elf = Mock() symbols = ( MockSymbol( - "SomeSymbol", st_shndx="SHN_UNDEF", st_info=dict(type="STT_FUNC") + "SomeSymbol", st_shndx="SHN_UNDEF", st_info={"type": "STT_FUNC"} ), ) diff --git a/tests/unit/test_policy.py b/tests/unit/test_policy.py index d05418f3..427d2d80 100644 --- a/tests/unit/test_policy.py +++ b/tests/unit/test_policy.py @@ -26,6 +26,7 @@ def ids(x): return "NoError" if hasattr(x, "expected_exception"): return x.expected_exception + return None def raises(exception, match=None, escape=True): @@ -35,7 +36,7 @@ def raises(exception, match=None, escape=True): @pytest.mark.parametrize( - "reported_arch,expected_arch", + ("reported_arch", "expected_arch"), [ ("armv6l", "armv6l"), ("armv7l", "armv7l"), @@ -52,7 +53,7 @@ def test_32bits_arch_name(reported_arch, expected_arch, monkeypatch): @pytest.mark.parametrize( - "reported_arch,expected_arch", + ("reported_arch", "expected_arch"), [ ("armv8l", "aarch64"), ("aarch64", "aarch64"), @@ -68,7 +69,7 @@ def test_64bits_arch_name(reported_arch, expected_arch, monkeypatch): @pytest.mark.parametrize( - "maxsize, sizeof_voidp, expected", + ("maxsize", "sizeof_voidp", "expected"), [ # 64-bit (9223372036854775807, 8, "x86_64"), @@ -91,7 +92,7 @@ def _calcsize(fmt): @pytest.mark.parametrize( - "name,expected", + ("name", "expected"), [ ("linux_aarch64", []), ("manylinux1_ppc64le", ["linux_ppc64le"]), @@ -277,7 +278,7 @@ def test_filter_libs(self): @pytest.mark.parametrize( - "libc,musl_policy,arch,exception", + ("libc", "musl_policy", "arch", "exception"), [ # valid (None, None, None, does_not_raise()), diff --git a/tests/unit/test_repair.py b/tests/unit/test_repair.py index 09e26158..f86dcce8 100644 --- a/tests/unit/test_repair.py +++ b/tests/unit/test_repair.py @@ -11,7 +11,7 @@ @patch("auditwheel.patcher.check_output") @patch("auditwheel.patcher.check_call") class TestRepair: - def test_append_rpath(self, check_call, check_output, _): + def test_append_rpath(self, check_call, check_output, _): # noqa: PT019 patcher = Patchelf() # When a library has an existing RPATH entry within wheel_dir existing_rpath = b"$ORIGIN/.existinglibdir" @@ -40,7 +40,7 @@ def test_append_rpath(self, check_call, check_output, _): assert check_output.call_args_list == check_output_expected_args assert check_call.call_args_list == check_call_expected_args - def test_append_rpath_reject_outside_wheel(self, check_call, check_output, _): + def test_append_rpath_reject_outside_wheel(self, check_call, check_output, _): # noqa: PT019 patcher = Patchelf() # When a library has an existing RPATH entry outside wheel_dir existing_rpath = b"/outside/wheel/dir" @@ -69,7 +69,7 @@ def test_append_rpath_reject_outside_wheel(self, check_call, check_output, _): assert check_output.call_args_list == check_output_expected_args assert check_call.call_args_list == check_call_expected_args - def test_append_rpath_ignore_duplicates(self, check_call, check_output, _): + def test_append_rpath_ignore_duplicates(self, check_call, check_output, _): # noqa: PT019 patcher = Patchelf() # When a library has an existing RPATH entry and we try and append it again existing_rpath = b"$ORIGIN" @@ -92,7 +92,7 @@ def test_append_rpath_ignore_duplicates(self, check_call, check_output, _): assert check_output.call_args_list == check_output_expected_args assert check_call.call_args_list == check_call_expected_args - def test_append_rpath_ignore_relative(self, check_call, check_output, _): + def test_append_rpath_ignore_relative(self, check_call, check_output, _): # noqa: PT019 patcher = Patchelf() # When a library has an existing RPATH entry but it cannot be resolved # to an absolute path, it is eliminated diff --git a/tests/unit/test_tools.py b/tests/unit/test_tools.py index 155861f5..a5c7976d 100644 --- a/tests/unit/test_tools.py +++ b/tests/unit/test_tools.py @@ -36,14 +36,14 @@ def test_environment_action(monkeypatch, environ, passed, expected): default="manylinux1", ) args = p.parse_args(argv) - assert args.PLAT == expected + assert expected == args.PLAT def test_environment_action_invalid_env(monkeypatch): choices = ["linux", "manylinux1", "manylinux2010"] monkeypatch.setenv("AUDITWHEEL_PLAT", "foo") + p = argparse.ArgumentParser() with pytest.raises(argparse.ArgumentError): - p = argparse.ArgumentParser() p.add_argument( "--plat", action=EnvironmentDefault, diff --git a/tests/unit/test_wheel_abi.py b/tests/unit/test_wheel_abi.py index c8d0e253..6225aac8 100644 --- a/tests/unit/test_wheel_abi.py +++ b/tests/unit/test_wheel_abi.py @@ -11,7 +11,7 @@ class TestGetWheelElfdata: @pytest.mark.parametrize( - "filenames, message", + ("filenames", "message"), [ ( # A single invalid file @@ -32,9 +32,9 @@ class TestGetWheelElfdata: def test_finds_shared_library_in_purelib(self, filenames, message, monkeypatch): entered_context = pretend.stub(iter_files=lambda: filenames) context = pretend.stub( - __enter__=lambda: entered_context, __exit__=lambda *a: None + __enter__=lambda: entered_context, __exit__=lambda *_: None ) - InGenericPkgCtx = pretend.stub(__call__=lambda a: context) + InGenericPkgCtx = pretend.stub(__call__=lambda _: context) monkeypatch.setattr(wheel_abi, "InGenericPkgCtx", InGenericPkgCtx) monkeypatch.setattr(