From 6c1b3be873725cb1a95feac5b72eb8d3cea82d10 Mon Sep 17 00:00:00 2001 From: Matthias Dellweg Date: Tue, 6 Jan 2026 15:00:35 +0100 Subject: [PATCH] Switch to using ruff --- .ci/gen_certs.py | 8 +- .ci/scripts/calc_constraints.py | 119 +++++++++++++++++++++++++ .ci/scripts/check_cli_dependencies.py | 9 +- .ci/scripts/check_click_for_mypy.py | 6 ++ .ci/scripts/collect_changes.py | 9 +- .ci/scripts/pr_labels.py | 8 +- .ci/scripts/validate_commit_message.py | 9 +- .github/workflows/test.yml | 1 + Makefile | 22 ++--- lint_requirements.txt | 5 +- pyproject.toml | 24 ++--- 11 files changed, 184 insertions(+), 36 deletions(-) create mode 100755 .ci/scripts/calc_constraints.py diff --git a/.ci/gen_certs.py b/.ci/gen_certs.py index 289cd95..d55b0b9 100644 --- a/.ci/gen_certs.py +++ b/.ci/gen_certs.py @@ -1,3 +1,10 @@ +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "trustme>=1.2.1,<1.3.0", +# ] +# /// + import argparse import os import sys @@ -6,7 +13,6 @@ def main() -> None: - parser = argparse.ArgumentParser(prog="gen_certs") parser.add_argument( "-d", diff --git a/.ci/scripts/calc_constraints.py b/.ci/scripts/calc_constraints.py new file mode 100755 index 0000000..ca8e11e --- /dev/null +++ b/.ci/scripts/calc_constraints.py @@ -0,0 +1,119 @@ +#!/bin/python3 +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "packaging>=25.0,<25.1", +# "tomli>=2.3.0,<2.4.0;python_version<'3.11'", +# ] +# /// + +import argparse +import fileinput +import sys + +from packaging.requirements import Requirement +from packaging.version import Version + +try: + import tomllib +except ImportError: + import tomli as tomllib + + +def split_comment(line): + split_line = line.split("#", maxsplit=1) + try: + comment = " # " + split_line[1].strip() + except IndexError: + comment = "" + return split_line[0].strip(), comment + + +def to_upper_bound(req): + try: + requirement = Requirement(req) + except ValueError: + return f"# UNPARSABLE: {req}" + else: + for spec in requirement.specifier: + if spec.operator == "~=": + return f"# NO BETTER CONSTRAINT: {req}" + if spec.operator == "<=": + operator = "==" + max_version = spec.version + return f"{requirement.name}{operator}{max_version}" + if spec.operator == "<": + operator = "~=" + version = Version(spec.version) + if version.micro != 0: + max_version = f"{version.major}.{version.minor}.{version.micro - 1}" + elif version.minor != 0: + max_version = f"{version.major}.{version.minor - 1}" + elif version.major != 0: + max_version = f"{version.major - 1}.0" + else: + return f"# NO BETTER CONSTRAINT: {req}" + return f"{requirement.name}{operator}{max_version}" + return f"# NO UPPER BOUND: {req}" + + +def to_lower_bound(req): + try: + requirement = Requirement(req) + except ValueError: + return f"# UNPARSABLE: {req}" + else: + for spec in requirement.specifier: + if spec.operator == ">=": + if requirement.name == "pulpcore": + # Currently an exception to allow for pulpcore bugfix releases. + # TODO Semver libraries should be allowed too. + operator = "~=" + else: + operator = "==" + min_version = spec.version + return f"{requirement.name}{operator}{min_version}" + return f"# NO LOWER BOUND: {req}" + + +def main(): + """Calculate constraints for the lower bound of dependencies where possible.""" + parser = argparse.ArgumentParser( + prog=sys.argv[0], + description="Calculate constraints for the lower or upper bound of dependencies where " + "possible.", + ) + parser.add_argument("-u", "--upper", action="store_true") + parser.add_argument("filename", nargs="*") + args = parser.parse_args() + + modifier = to_upper_bound if args.upper else to_lower_bound + + req_files = [filename for filename in args.filename if not filename.endswith("pyproject.toml")] + pyp_files = [filename for filename in args.filename if filename.endswith("pyproject.toml")] + if req_files: + with fileinput.input(files=req_files) as req_file: + for line in req_file: + if line.strip().startswith("#"): + # Shortcut comment only lines + print(line.strip()) + else: + req, comment = split_comment(line) + new_req = modifier(req) + print(new_req + comment) + for filename in pyp_files: + with open(filename, "rb") as fp: + pyproject = tomllib.load(fp) + for req in pyproject["project"]["dependencies"]: + new_req = modifier(req) + print(new_req) + optional_dependencies = pyproject["project"].get("optional-dependencies") + if optional_dependencies: + for opt in optional_dependencies.values(): + for req in opt: + new_req = modifier(req) + print(new_req) + + +if __name__ == "__main__": + main() diff --git a/.ci/scripts/check_cli_dependencies.py b/.ci/scripts/check_cli_dependencies.py index c2cc8c9..46da068 100755 --- a/.ci/scripts/check_cli_dependencies.py +++ b/.ci/scripts/check_cli_dependencies.py @@ -1,8 +1,15 @@ #!/bin/env python3 -import tomllib +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "packaging>=25.0,<25.1", +# ] +# /// + import typing as t from pathlib import Path +import tomllib from packaging.requirements import Requirement GLUE_DIR = "pulp-glue-gem" diff --git a/.ci/scripts/check_click_for_mypy.py b/.ci/scripts/check_click_for_mypy.py index 408a7c6..33ecf4c 100755 --- a/.ci/scripts/check_click_for_mypy.py +++ b/.ci/scripts/check_click_for_mypy.py @@ -1,4 +1,10 @@ #!/bin/env python3 +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "packaging>=25.0,<25.1", +# ] +# /// from importlib import metadata diff --git a/.ci/scripts/collect_changes.py b/.ci/scripts/collect_changes.py index e6cb0da..499265c 100755 --- a/.ci/scripts/collect_changes.py +++ b/.ci/scripts/collect_changes.py @@ -1,10 +1,17 @@ #!/bin/env python3 +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "gitpython>=3.1.46,<3.2.0", +# "packaging>=25.0,<25.1", +# ] +# /// import itertools import os import re -import tomllib +import tomllib from git import GitCommandError, Repo from packaging.version import parse as parse_version diff --git a/.ci/scripts/pr_labels.py b/.ci/scripts/pr_labels.py index 9d637b6..49eb4ad 100755 --- a/.ci/scripts/pr_labels.py +++ b/.ci/scripts/pr_labels.py @@ -1,12 +1,18 @@ #!/bin/env python3 +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "gitpython>=3.1.46,<3.2.0", +# ] +# /// # This script is running with elevated privileges from the main branch against pull requests. import re import sys -import tomllib from pathlib import Path +import tomllib from git import Repo diff --git a/.ci/scripts/validate_commit_message.py b/.ci/scripts/validate_commit_message.py index 7a7f370..0a6c068 100644 --- a/.ci/scripts/validate_commit_message.py +++ b/.ci/scripts/validate_commit_message.py @@ -1,10 +1,17 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "gitpython>=3.1.46,<3.2.0", +# ] +# /// + import os import re import subprocess import sys -import tomllib from pathlib import Path +import tomllib from github import Github with open("pyproject.toml", "rb") as fp: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 922f7f2..7c9e7e5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,6 +19,7 @@ jobs: include: - image_tag: "nightly" pulp_api_root: "/relocated/djnd/" + upper_bounds: true python: "3.11" - image_tag: "latest" lower_bounds: true diff --git a/Makefile b/Makefile index 6fdf059..6236771 100644 --- a/Makefile +++ b/Makefile @@ -2,29 +2,28 @@ GLUE_PLUGINS=$(notdir $(wildcard pulp-glue-gem/pulp_glue/*)) CLI_PLUGINS=$(notdir $(wildcard pulpcore/cli/*)) +.PHONY: info info: @echo Pulp glue @echo plugins: $(GLUE_PLUGINS) @echo Pulp CLI @echo plugins: $(CLI_PLUGINS) +.PHONY: build build: cd pulp-glue-gem; pyproject-build -n pyproject-build -n -black: format - +.PHONY: format format: - isort . - cd pulp-glue-gem; isort . - black . + ruff format + ruff check --fix +.PHONY: lint lint: find tests .ci -name '*.sh' -print0 | xargs -0 shellcheck -x - isort -c --diff . - cd pulp-glue-gem; isort -c --diff . - black --diff --check . - flake8 + ruff format --check --diff + ruff check --diff .ci/scripts/check_cli_dependencies.py .ci/scripts/check_click_for_mypy.py MYPYPATH=pulp-glue-gem mypy @@ -35,15 +34,18 @@ tests/cli.toml: cp $@.example $@ @echo "In order to configure the tests to talk to your test server, you might need to edit $@ ." +.PHONY: test test: | tests/cli.toml python3 -m pytest -v tests pulp-glue-gem/tests +.PHONY: livetest livetest: | tests/cli.toml python3 -m pytest -v tests pulp-glue-gem/tests -m live +.PHONY: unittest unittest: python3 -m pytest -v tests pulp-glue-gem/tests -m "not live" +.PHONY: unittest_glue unittest_glue: python3 -m pytest -v pulp-glue-gem/tests -m "not live" -.PHONY: build info black lint test diff --git a/lint_requirements.txt b/lint_requirements.txt index adf5ff8..c17cc78 100644 --- a/lint_requirements.txt +++ b/lint_requirements.txt @@ -1,8 +1,5 @@ # Lint requirements -black==25.12.0 -flake8==7.3.0 -flake8-pyproject==1.2.4 -isort==7.0.0 +ruff==0.14.10 mypy==1.19.1 shellcheck-py==0.11.0.1 diff --git a/pyproject.toml b/pyproject.toml index 3a04c8b..c9ee3c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,16 +108,6 @@ name = "Misc" showcontent = true -[tool.black] -# This section is managed by the cookiecutter templates. -line-length = 100 - -[tool.isort] -# This section is managed by the cookiecutter templates. -profile = "black" -line_length = 100 -extend_skip = ["pulp-glue-gem"] - [tool.pytest.ini_options] markers = [ "script: tests provided as shell scripts", @@ -194,12 +184,12 @@ search = "\"pulp-glue-gem=={current_version}\"" replace = "\"pulp-glue-gem=={new_version}\"" -[tool.flake8] +[tool.ruff] +# This section is managed by the cookiecutter templates. +line-length = 100 +extend-exclude = ["cookiecutter"] + +[tool.ruff.lint] # This section is managed by the cookiecutter templates. -exclude = ["./docs/*"] -ignore = ["W503", "Q000", "Q003", "D100", "D104", "D106", "D200", "D202", "D205", "D400", "D401", "D402"] -# E203: whitespace before ':'; https://github.com/psf/black/issues/279 -# E401: multiple imports on one line -extend-ignore = ["E203", "E401"] -max-line-length = 100 +extend-select = ["I"]