From d56ee97cc73c2eaa0c1992f1ff29702795a72746 Mon Sep 17 00:00:00 2001 From: Elias Mueller Date: Wed, 1 Jul 2026 22:09:11 +0200 Subject: [PATCH 1/4] build: replace make and tox with just --- .github/workflows/tests.yaml | 28 +++--- .gitignore | 1 - Justfile | 87 ++++++++++++++++++ README.md | 11 ++- makefile | 27 ------ pyproject.toml | 147 +---------------------------- uv.lock | 174 ----------------------------------- 7 files changed, 115 insertions(+), 360 deletions(-) create mode 100644 Justfile delete mode 100644 makefile diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index a8e2e5a..2515989 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -25,14 +25,14 @@ jobs: python-version: "3.14" - name: "Setup uv" uses: astral-sh/setup-uv@v8.2.0 + - name: "Setup just" + uses: extractions/setup-just@v4 - name: "Check uv.lock" - run: uv lock --check + run: just lock-check - name: "Lint TOMLs" - uses: docker://docker.io/tamasfe/taplo:0.10.0 - with: - args: fmt --check --diff + run: just lint-toml - name: "Lint YAMLs" - run: uv run tox -e lint-yaml + run: just lint-yaml lint: name: "Linting" @@ -46,10 +46,10 @@ jobs: python-version: "3.14" - name: "Setup uv" uses: astral-sh/setup-uv@v8.2.0 + - name: "Setup just" + uses: extractions/setup-just@v4 - name: "Lint formatting" - run: uv run tox -e lint-py -# - name: "Type checking" TODO(trin94): revisit linter config and re-enable -# run: uv run tox -e lint-mypy + run: just lint types: name: "Type checking (public API)" @@ -63,8 +63,12 @@ jobs: python-version: "3.14" - name: "Setup uv" uses: astral-sh/setup-uv@v8.2.0 + - name: "Setup just" + uses: extractions/setup-just@v4 - name: "Type checking (public API)" - run: uv run tox -e lint-types + run: just public-typing +# - name: "Type checking (full)" TODO: re-enable once green +# run: just typing tests: name: "Run unit tests" @@ -82,7 +86,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: "Setup uv" uses: astral-sh/setup-uv@v8.2.0 + - name: "Setup just" + uses: extractions/setup-just@v4 - name: "Run tests" - run: >- - uv run tox -e ${{ matrix.python-version }} - --skip-missing-interpreters false + run: just test ${{ matrix.python-version }} diff --git a/.gitignore b/.gitignore index be475c7..077efa8 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,6 @@ pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports -.tox/ .coverage .cache coverage.xml diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..de8206b --- /dev/null +++ b/Justfile @@ -0,0 +1,87 @@ +set shell := ["bash", "-euc"] + +python_oldest := "3.10" # Oldest supported version +python_latest := "3.14" # Newest supported version +python := "3.14" # Default version for dev loop +python_versions := "3.10 3.11 3.12 3.13 3.14" + +taplo := "uvx taplo@0.9.3" + +@_default: + just --list --unsorted + +fmt: + uv run --only-group ruff ruff format . + uv run --only-group ruff ruff check --fix --show-fixes . + {{ taplo }} format + just --fmt + +# Dev loop +dev: fmt lint test + +# Full check +check: lock-check lint lint-toml lint-yaml public-typing typing test-all + +# Install locked dependencies +[group('project')] +init: + uv sync + +[group('project')] +dist: + uv build + +[group('project')] +publish: + uv publish + +[group('project')] +clean: + rm -rf dist .mypy_cache .pytest_cache .ruff_cache .uv-cache + +[group('test')] +test version=python *args: + uv run --python {{ version }} --no-default-groups --group tests pytest {{ args }} + +# Test all supported Python versions +[group('test')] +test-all: + for v in {{ python_versions }}; do just test "$v"; done + +[group('test')] +coverage version=python: + uv run --python {{ version }} --no-default-groups --group tests \ + pytest --cov=. --cov-branch --cov-report=term-missing:skip-covered + +# Type check our code +[group('typing')] +typing version=python_oldest: + # --python-version is a mypy target flag, not a host interpreter + uv run --no-default-groups --group mypy mypy --python-version {{ version }} . + +# Type check as if we're a consumer of the library +[group('typing')] +public-typing version=python_oldest: + uv run --no-default-groups --group mypy mypy --python-version {{ version }} typing_checks + +[group('typing')] +public-typing-all: + for v in {{ python_oldest }} {{ python_latest }}; do just public-typing "$v"; done + +[group('lint')] +lint: + uv run --only-group ruff ruff format --diff . + uv run --only-group ruff ruff check . + +[group('lint')] +lint-toml: + {{ taplo }} lint + {{ taplo }} format --check --diff + +[group('lint')] +lint-yaml: + uv run --only-group yamllint yamllint --strict . + +[group('lint')] +lock-check: + uv lock --check diff --git a/README.md b/README.md index 70d77af..f95d9df 100644 --- a/README.md +++ b/README.md @@ -320,7 +320,16 @@ def foo(user): Apache License 2.0 ## Development -We use [uv](https://docs.astral.sh/uv/getting-started/installation/) and `make` for development. Install both, then run `make init` to get started. +We use [uv](https://docs.astral.sh/uv/getting-started/installation/) and +[just](https://github.com/casey/just#installation) for development. Install both, +then run `just init` to set up the environment. + +Useful recipes: + +* `just` lists all recipes +* `just dev` formats, lints, and tests on the default interpreter (the fast loop) +* `just test 3.12` runs the tests against a specific Python version +* `just check` runs the full gate before pushing ## Contributors * Ivan Korobkov [@ivankorobkov](https://github.com/ivankorobkov) diff --git a/makefile b/makefile deleted file mode 100644 index 7320188..0000000 --- a/makefile +++ /dev/null @@ -1,27 +0,0 @@ -SHELL := bash -.DELETE_ON_ERROR: -.SHELLFLAGS := -ceu -MAKEFLAGS += --no-builtin-rules \ - --warn-undefined-variables - -.PHONY: init dist upload clean pytest - -init: - uv sync - -dist: - uv build - -upload: - uv publish - -clean: - rm -rf ./dist/* - rm -rf ./.mypy_cache - rm -rf ./.pytest_cache - rm -rf ./.ruff_cache - rm -rf ./.tox - rm -rf ./.uv-cache - -pytest: - uv run pytest tests diff --git a/pyproject.toml b/pyproject.toml index 732ac02..53c6021 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,14 +33,12 @@ issues = "https://github.com/ivankorobkov/python-inject/issues" [dependency-groups] dev = [ "typing-extensions>=4.15.0", - { include-group = "tox" }, { include-group = "ruff" }, { include-group = "mypy" }, { include-group = "yamllint" }, { include-group = "tests" }, ] -tox = ["tox>=4.56.1", "tox-uv>=1.35.2"] ruff = ["ruff>=0.15.20"] mypy = ["mypy>=2.1.0"] yamllint = ["yamllint>=1.38.0"] @@ -88,7 +86,7 @@ disallow_untyped_decorators = true disallow_untyped_defs = true ignore_missing_imports = true no_implicit_optional = true -python_version = "3.11" +python_version = "3.10" warn_redundant_casts = true warn_return_any = true warn_unused_configs = true @@ -202,7 +200,7 @@ branch = true [tool.coverage.report] include_namespace_packages = true # Regexes for lines to exclude from consideration -omit = ["*/.venv/*", "*/.tox/*", "*/.uv-cache/*"] +omit = ["*/.venv/*", "*/.uv-cache/*"] exclude_also = [ # Don't complain if tests don't hit defensive assertion code: "raise NotImplementedError", @@ -215,144 +213,3 @@ exclude_also = [ "if TYPE_CHECKING:", ] - - -# Tox config -[tool.tox] -skip_missing_interpreters = true - -env_list = [ - "py310", - "py311", - "py312", - "py313", - "py314", - "fmt-py", - "fmt-toml", - "lint-py", - "lint-types", - #"lint-mypy", # TODO(pyctrl): make it green & uncomment - "lint-toml", - "lint-yaml", - "coverage", -] - -[tool.tox.labels] -fmt = [ - "fmt-py", - "fmt-toml", -] -lint = [ - "lint-py", - "lint-types", - #"lint-mypy", # TODO(pyctrl): make it green & uncomment - "lint-toml", - "lint-yaml", -] - -# default env -[tool.tox.env_run_base] -runner = "uv-venv-lock-runner" -description = "Run unit tests with coverage report ({env_name})" -use_develop = true -dependency_groups = ["tests"] -commands = [["pytest", { replace = "posargs", extend = true }]] - -# tox envs -[tool.tox.env.lint-py] -description = "Lint python files" -dependency_groups = ["ruff"] -commands = [ - [ - "ruff", - "format", - "--diff", - { replace = "posargs", default = [ - "{tox_root}", - ], extend = true }, - ], - [ - "ruff", - "check", - { replace = "posargs", default = [ - "{tox_root}", - ], extend = true }, - ], -] - -[tool.tox.env.lint-types] -description = "Type-check the public-API typing guards" -dependency_groups = ["mypy"] -commands = [ - [ - "mypy", - { replace = "posargs", default = [ - "typing_checks", - ], extend = true }, - ], -] - -[tool.tox.env.lint-mypy] -description = "Type checking" -dependency_groups = ["mypy"] -commands = [["mypy", { replace = "posargs", default = ["{tox_root}"], extend = true }]] - -[tool.tox.env.lint-toml] -description = "Lint TOML files" -allowlist_externals = ["taplo"] -skip_install = true -commands = [ - ["taplo", "lint", { replace = "posargs", extend = true }], - ["taplo", "format", "--check", "--diff", { replace = "posargs", extend = true }], -] - -[tool.tox.env.lint-yaml] -description = "Lint YAML files" -dependency_groups = ["yamllint"] -commands = [ - [ - "yamllint", - "--strict", - { replace = "posargs", default = [ - "{tox_root}", - ], extend = true }, - ], -] - -[tool.tox.env.fmt-py] -description = "Format python files" -dependency_groups = ["ruff"] -commands = [ - [ - "ruff", - "format", - { replace = "posargs", default = ["{tox_root}"], extend = true }, - ], - [ - "ruff", - "check", - "--fix", - "--show-fixes", - { replace = "posargs", default = ["{tox_root}"], extend = true }, - ], -] - -[tool.tox.env.fmt-toml] -description = "Format TOML files" -allowlist_externals = ["taplo"] -skip_install = true -commands = [["taplo", "format", { replace = "posargs", extend = true }]] - -[tool.tox.env.coverage] -description = "run coverage" -use_develop = true -dependency_groups = ["tests"] -commands = [ - [ - "pytest", - "--cov=.", - "--cov-branch", - "--cov-report=term-missing:skip-covered", - { replace = "posargs", default = ["--cov-report=xml:coverage.xml"], extend = true }, - ], -] diff --git a/uv.lock b/uv.lock index 99a86ad..38a7e3a 100644 --- a/uv.lock +++ b/uv.lock @@ -46,15 +46,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/45/19/cc8bd127d28a43da249aa955cfd164cf8fd534e79e42cea96c4854d72fd0/ast_serialize-0.5.0-cp39-abi3-win_arm64.whl", hash = "sha256:92a31c9c20d25a076edaeec76b128a3535d74a24f340b9a8a7e96c9b86dc9642", size = 1081181, upload-time = "2026-05-17T17:48:28.122Z" }, ] -[[package]] -name = "cachetools" -version = "7.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/8b/0d3945a13955303b81272f759a0331e54c5c793da455e6f5706b89d2639c/cachetools-7.1.4.tar.gz", hash = "sha256:437f55a4e0c1b01a4f3077cc470e6991d47430970e36fbcb77e2be0df4fc1cd6", size = 40085, upload-time = "2026-05-21T22:40:43.376Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/7b/1fc1c09cc0756cf25861a3be10565915953876da48bb228fb9a672b20a42/cachetools-7.1.4-py3-none-any.whl", hash = "sha256:323dc4127934744db5b54eb4924482d7edafbf9554e820d1531c2e08c0e4ef54", size = 16761, upload-time = "2026-05-21T22:40:41.845Z" }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -167,15 +158,6 @@ toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] -[[package]] -name = "distlib" -version = "0.4.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, -] - [[package]] name = "exceptiongroup" version = "1.3.1" @@ -188,15 +170,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] -[[package]] -name = "filelock" -version = "3.29.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/dc/be6cbe99670cd6e4ad387123647cb08e0c32975e223f82551e914c5568a6/filelock-3.29.4.tar.gz", hash = "sha256:10cdb3656fc44541cdf30652a93fb10ec6b05325620eb316bd26893e4201538a", size = 63028, upload-time = "2026-06-13T16:12:00.744Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/37/a065dc3bd6e49423a6532c642ca7378d3f467b1ef44c2800c937af7f9739/filelock-3.29.4-py3-none-any.whl", hash = "sha256:dac1648087d5115554850d113e7dd8c83ab2d38e3435dde2d4f163847e57b767", size = 42757, upload-time = "2026-06-13T16:11:59.582Z" }, -] - [[package]] name = "iniconfig" version = "2.3.0" @@ -216,8 +189,6 @@ dev = [ { name = "pytest" }, { name = "pytest-cov" }, { name = "ruff" }, - { name = "tox" }, - { name = "tox-uv" }, { name = "typing-extensions" }, { name = "yamllint" }, ] @@ -231,10 +202,6 @@ tests = [ { name = "pytest" }, { name = "pytest-cov" }, ] -tox = [ - { name = "tox" }, - { name = "tox-uv" }, -] yamllint = [ { name = "yamllint" }, ] @@ -247,8 +214,6 @@ dev = [ { name = "pytest", specifier = ">=9.1.1" }, { name = "pytest-cov", specifier = ">=7.1.0" }, { name = "ruff", specifier = ">=0.15.20" }, - { name = "tox", specifier = ">=4.56.1" }, - { name = "tox-uv", specifier = ">=1.35.2" }, { name = "typing-extensions", specifier = ">=4.15.0" }, { name = "yamllint", specifier = ">=1.38.0" }, ] @@ -258,10 +223,6 @@ tests = [ { name = "pytest", specifier = ">=9.1.1" }, { name = "pytest-cov", specifier = ">=7.1.0" }, ] -tox = [ - { name = "tox", specifier = ">=4.56.1" }, - { name = "tox-uv", specifier = ">=1.35.2" }, -] yamllint = [{ name = "yamllint", specifier = ">=1.38.0" }] [[package]] @@ -435,15 +396,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] -[[package]] -name = "platformdirs" -version = "4.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" }, -] - [[package]] name = "pluggy" version = "1.6.0" @@ -462,19 +414,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] -[[package]] -name = "pyproject-api" -version = "1.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/62/62/0fe346fe380b1aafaf819c8cb195d3241bb4f355f908e6339814131a830b/pyproject_api-1.10.1.tar.gz", hash = "sha256:c2b2726bd7aa9217b6c50b621fef5b2ae5def4d55b779c9e0694c15e0a8517ba", size = 23477, upload-time = "2026-05-28T14:22:14.049Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/d7/29e1e5e882f79133631f7bcace42d23db493f616463c157a1ab614bf69dd/pyproject_api-1.10.1-py3-none-any.whl", hash = "sha256:fa9e6f66c35b5017e909825d8f2b5d5482ea699d7be809d21c03bd1f7317f36a", size = 12992, upload-time = "2026-05-28T14:22:12.711Z" }, -] - [[package]] name = "pytest" version = "9.1.1" @@ -507,19 +446,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, ] -[[package]] -name = "python-discovery" -version = "1.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "filelock" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/1a/cbbaf13b730abb0a16b964d984e19f2fe520c21a4dc664051359a3f5a9e7/python_discovery-1.4.2.tar.gz", hash = "sha256:8f3746c4b4968d22afbb97d36e1a0e5b66e6c0f297290f2e95f05b9b8bf18690", size = 70277, upload-time = "2026-06-11T16:10:42.383Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/82/a70006589557f267f15bd384c0642ad49f0d97b690c3a05b166b9dcbad3b/python_discovery-1.4.2-py3-none-any.whl", hash = "sha256:475803f53b7b2ed6e490e27373f9d8340f7d2eebf9acdaf645d7d714c97bb500", size = 33886, upload-time = "2026-06-11T16:10:41.192Z" }, -] - [[package]] name = "pyyaml" version = "6.0.3" @@ -663,64 +589,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, ] -[[package]] -name = "tomli-w" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, -] - -[[package]] -name = "tox" -version = "4.56.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachetools" }, - { name = "colorama" }, - { name = "filelock" }, - { name = "packaging" }, - { name = "platformdirs" }, - { name = "pluggy" }, - { name = "pyproject-api" }, - { name = "python-discovery" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "tomli-w" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, - { name = "virtualenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6a/d20d405fc6661902ff803a9fa048d8aae27597c3b5dc750369ded82d08f7/tox-4.56.1.tar.gz", hash = "sha256:db1c2610802553189cf40de251661d066a635ee0ed9bf2a60093b5f1a7f36ef8", size = 283155, upload-time = "2026-06-25T06:18:36.802Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/97/560a5dfde154619d9643b1e208119dddc29bbb35a38a4ce4d095c16cf8f0/tox-4.56.1-py3-none-any.whl", hash = "sha256:4d06b925c4dd67872099b39c5a46fba79a2169c5f6e32060f95a8b1181f0ef55", size = 216469, upload-time = "2026-06-25T06:18:35.229Z" }, -] - -[[package]] -name = "tox-uv" -version = "1.35.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tox-uv-bare" }, - { name = "uv" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/dc/6e9994c799bdbb309f829dd6b8d98764dd0757302f3433c380438a3a127b/tox_uv-1.35.2-py3-none-any.whl", hash = "sha256:2d99b0e3c782ba49e7cbe521c8d344758595961b17a3633738d67096641c1bde", size = 6565, upload-time = "2026-05-05T01:34:16.07Z" }, -] - -[[package]] -name = "tox-uv-bare" -version = "1.35.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "tox" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/cb/168dc1ccf24e4065a9a0a33df55709ed2b5eb73bd2b13ddd53187e5dffb8/tox_uv_bare-1.35.2.tar.gz", hash = "sha256:49e28a804c97f23ea17e25859960c0fa78f35bccb7e14344cfd840e89a9aade9", size = 32333, upload-time = "2026-05-05T01:34:18.916Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/53/4a33dc81da39db7b31e5622333df361e8fe055b7ec636bd5fea762c9182d/tox_uv_bare-1.35.2-py3-none-any.whl", hash = "sha256:c0d590a41d1054a1ad0874e9e5943ff52402786e3d4599d8f8d37a65b566ef53", size = 22307, upload-time = "2026-05-05T01:34:17.681Z" }, -] - [[package]] name = "typing-extensions" version = "4.15.0" @@ -730,48 +598,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] -[[package]] -name = "uv" -version = "0.11.25" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4b/8e/2777bf40df3c634f2a522baaa2995d2bd5901461fc5d8730c04c39fa6c75/uv-0.11.25.tar.gz", hash = "sha256:458e731778e7b5cc870710397859c23e766703e7bc0695f23b3eb15080745ba6", size = 4329198, upload-time = "2026-06-27T00:49:00.519Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/a7/dc836daca0db76178cfe4e40ee95fa2c5f96a3d7b3cda0bdde5291aef8b8/uv-0.11.25-py3-none-linux_armv6l.whl", hash = "sha256:d6f965a79fc7539a12139ce981caa0cbf7d9d3bd4ea3daadaf174ab4d7fb6e42", size = 25153689, upload-time = "2026-06-27T00:48:10.708Z" }, - { url = "https://files.pythonhosted.org/packages/9c/97/d60eabb616db232ed0e682c55d858d0980175a92336429c4e0ee82a160e6/uv-0.11.25-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:610650cbaa0a9b18015da39d2c28d736d287a5a124e49296d8fdef5e4022e980", size = 24149272, upload-time = "2026-06-27T00:48:13.917Z" }, - { url = "https://files.pythonhosted.org/packages/ab/fd/9f72373e340c6abcd3eb9257d69b442434b65e90e1f7f53f333abdac11b2/uv-0.11.25-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f7a78fc8d0c5e764e9fa39c99066db47a0bc465b023feed90812e3c0a6b5eb0d", size = 22885453, upload-time = "2026-06-27T00:48:16.641Z" }, - { url = "https://files.pythonhosted.org/packages/ee/c1/7cbb3f6b4a021ce7c1c453d1412d3b4b68d7d7585d15d91a57e9ab0a317e/uv-0.11.25-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:e3480640983e0b8e509eeb67882837e620bdd820f8776948a5f13ebbb4481d04", size = 24935172, upload-time = "2026-06-27T00:48:19.495Z" }, - { url = "https://files.pythonhosted.org/packages/df/d4/862a534ab4aae28ad2c9145ea5af3021eefe225e4e1c983278bb34b53b9e/uv-0.11.25-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:b180b12237b4e04692491fc6796584a9a8bdf4c7332bd2a769caf096b97885d0", size = 24665125, upload-time = "2026-06-27T00:48:22.408Z" }, - { url = "https://files.pythonhosted.org/packages/91/2a/70ef2f2a212d89d23f90e1c8017c080fae93bec21cd9f14795498a6e6f89/uv-0.11.25-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69d14ffd0a4b050f8a70f64aacb09b8dfdfb1cb30a6351fb17b48f273f95c58c", size = 24653836, upload-time = "2026-06-27T00:48:24.858Z" }, - { url = "https://files.pythonhosted.org/packages/44/2b/a7beea057778f092daa5aeda7aeb3f8bfa78f4a0622245adb449fdbb3d20/uv-0.11.25-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61ef11d9967a38109e6e8e3d20d1f743fa08033c32bce274d6ccd9a9abb5d305", size = 26069304, upload-time = "2026-06-27T00:48:28.05Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e8/bb8ab595a27035b565cedd5d601ae2b85cf6aba6f68cd6a97eae88dd7250/uv-0.11.25-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3febca65ec5bc336ddaf7e4f724704f2c894c16839723df14865ee00b4acf38d", size = 26992784, upload-time = "2026-06-27T00:48:30.584Z" }, - { url = "https://files.pythonhosted.org/packages/17/90/bbfa0653e992877e5ea78ab3186fb6a5a122ebef5913b6809ef6d06fcf9b/uv-0.11.25-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:850ba0018ff170c3a9baaf9b5fe8b23393b6b77ee4ea6b2e2315fdb8d7c388f7", size = 26151002, upload-time = "2026-06-27T00:48:33.739Z" }, - { url = "https://files.pythonhosted.org/packages/91/01/f5a01fd777ce501cc59eb71775f3bbacac258a65a64939f07804c2279c98/uv-0.11.25-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2bc05e17ae3e1f232abf93e7dcfb3b68702dfcde34a00c29cbce7e07d1ecbfb", size = 26334122, upload-time = "2026-06-27T00:48:36.247Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c4/f8b3b6b1bb48a452d98c02909e229f7ae317300618d6dc334c883742339e/uv-0.11.25-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:57fbd47e924242fd347d0c209d95711d8ea61db8d8780962d0f30ccde2c854a3", size = 25055505, upload-time = "2026-06-27T00:48:39.418Z" }, - { url = "https://files.pythonhosted.org/packages/c6/7d/aece221faba22804d8b4f913903358dc2d45193babf2a44a49f79eadd25b/uv-0.11.25-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:f42de9e7d63a28a4fe76a522077813656de38b5acda20b4db63857d260c1ff13", size = 25660097, upload-time = "2026-06-27T00:48:42.398Z" }, - { url = "https://files.pythonhosted.org/packages/d3/7d/b835ed56eab281054efbfbcbbe1249621908c6e4c721a878904cbed2f418/uv-0.11.25-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2c1cfe97dce56c997dfa3214bdb8955b7b34cceea7505520185e22ad99c0eb6b", size = 25759374, upload-time = "2026-06-27T00:48:45.069Z" }, - { url = "https://files.pythonhosted.org/packages/c2/fd/28c990fd18330aa01383bae738be113f4ac5d9d414f92790947326c6781c/uv-0.11.25-py3-none-musllinux_1_1_i686.whl", hash = "sha256:fbff70ae9fa4da9fb6823ae4fdaf77a65c9520e13b6d1d0241ba56e4b121b7aa", size = 25329343, upload-time = "2026-06-27T00:48:47.718Z" }, - { url = "https://files.pythonhosted.org/packages/70/48/16ff9dbe5f308cb547e227971cbcaf3c905797da12a4116b620e2acc09cb/uv-0.11.25-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:41b37e724f41eb4c3794bbdd82ddeebb4b5850d4ada8cccb2906ef9e5aa0f83b", size = 26477125, upload-time = "2026-06-27T00:48:50.251Z" }, - { url = "https://files.pythonhosted.org/packages/f6/8b/4146a55d3ee6b2b67c3dece3ef6be220c443abafc2dc56baa2f74d6b36a8/uv-0.11.25-py3-none-win32.whl", hash = "sha256:86d4759fec9b46f61944d6e9ef1f5eaa2c5fbe2db5ddb59492d9174b08fcf39c", size = 23896598, upload-time = "2026-06-27T00:48:53.01Z" }, - { url = "https://files.pythonhosted.org/packages/64/66/784f9fb457b640dbb96cdd175f4902235b42ffe740dbaee9ea5fc649d8b2/uv-0.11.25-py3-none-win_amd64.whl", hash = "sha256:560b0fbaa6356af533923a349658c21d4f410d16e835787d8a05da451d4ee859", size = 26862205, upload-time = "2026-06-27T00:48:55.667Z" }, - { url = "https://files.pythonhosted.org/packages/85/cb/d7bb121261db0b829f38b1e86b80d8103afd050b8a5c5c9fe4a988d2f1fc/uv-0.11.25-py3-none-win_arm64.whl", hash = "sha256:79f166cd1b84f855e9d2768221d59b403869648289fd884d58ad4299edfb4d9e", size = 25153588, upload-time = "2026-06-27T00:48:58.495Z" }, -] - -[[package]] -name = "virtualenv" -version = "21.5.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib" }, - { name = "filelock" }, - { name = "platformdirs" }, - { name = "python-discovery" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/a5/81f987504738e6defeed61ec1c47e2aefab3c35d8eeb87e1b3f38cf28254/virtualenv-21.5.1.tar.gz", hash = "sha256:dca3bf98275a59c652b69d68e73433e597d977c2da9198882479d1a7188009c8", size = 4578798, upload-time = "2026-06-16T16:23:58.603Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/02/3623e6169bed617ed1e2d372f7c69f92ec28d54c4dfc997055c8578ec148/virtualenv-21.5.1-py3-none-any.whl", hash = "sha256:55aa670b67bbfb991b03fda39bd3276d92c419d702376e98c5df1c9989a26783", size = 4558820, upload-time = "2026-06-16T16:23:56.963Z" }, -] - [[package]] name = "yamllint" version = "1.38.0" From 569796a4875a2ed677c7863431d3bfe2195b684e Mon Sep 17 00:00:00 2001 From: Elias Mueller Date: Wed, 1 Jul 2026 22:34:22 +0200 Subject: [PATCH 2/4] fix: resolve ruff violations RUF067 fires on every top-level statement because the whole public API intentionally lives in inject/__init__.py, so it is turned off project-wide rather than per file. ISC004 caught a real bug: a stray trailing comma made the runtime binding error message a one-element tuple instead of a string, so the raised exception showed the tuple instead of the text. Dropping the comma restores the intended message. D420 reorders the get_injector_or_die docstring so Returns comes before Raises. RUF075 wraps the yields in the test context-manager fixtures in try/finally so their cleanup still runs when the caller raises. The now-unused `# noqa: RUF029` on the async fixtures is dropped too; that removal is a ruff auto-fix. --- pyproject.toml | 11 ++++++----- src/inject/__init__.py | 8 ++++---- tests/test_context_manager.py | 34 ++++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 53c6021..e41361b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -116,11 +116,12 @@ extend-exclude = [".git", ".venv", "docs"] preview = true extend-select = ["ALL"] extend-ignore = [ - "D10", # missing documentation - "D203", # 1 of conflicting code-styles - "D212", # 1 of conflicting code-styles - "C408", # allow `dict()` instead of literal - "TD003", # don't require issue link + "D10", # missing documentation + "D203", # 1 of conflicting code-styles + "D212", # 1 of conflicting code-styles + "C408", # allow `dict()` instead of literal + "TD003", # don't require issue link + "RUF067", # __init__ modules intentionally contain code # Completely disable "FIX", "CPY", diff --git a/src/inject/__init__.py b/src/inject/__init__.py index 4df24f9..7a75423 100644 --- a/src/inject/__init__.py +++ b/src/inject/__init__.py @@ -282,7 +282,7 @@ def get_instance(self, cls: Binding) -> Injectable: if not callable(cls): msg = ( "Cannot create a runtime binding, the key is not callable," - f" key={cls}", + f" key={cls}" ) raise InjectorException(msg) @@ -717,12 +717,12 @@ def get_injector_or_die() -> Injector: """ Return the current injector or raise an InjectorException. - Raises: - InjectorException: If injector is not configured. - Returns: Configured injector. + Raises: + InjectorException: If injector is not configured. + """ injector = _INJECTOR if not injector: diff --git a/tests/test_context_manager.py b/tests/test_context_manager.py index 9b19bc8..a0ce041 100644 --- a/tests/test_context_manager.py +++ b/tests/test_context_manager.py @@ -24,36 +24,46 @@ class MockFoo(Destroyable): ... @contextlib.contextmanager def get_file_sync(): obj = MockFile() - yield obj - obj.destroy() + try: + yield obj + finally: + obj.destroy() @contextlib.contextmanager def get_conn_sync(): obj = MockConnection() - yield obj - obj.destroy() + try: + yield obj + finally: + obj.destroy() @contextlib.contextmanager def get_foo_sync(): obj = MockFoo() - yield obj - obj.destroy() + try: + yield obj + finally: + obj.destroy() @contextlib.asynccontextmanager -async def get_file_async(): # noqa: RUF029 +async def get_file_async(): obj = MockFile() - yield obj - obj.destroy() + try: + yield obj + finally: + obj.destroy() @contextlib.asynccontextmanager -async def get_conn_async(): # noqa: RUF029 +async def get_conn_async(): obj = MockConnection() - yield obj - obj.destroy() + try: + yield obj + finally: + obj.destroy() class TestContextManagerFunctional(BaseTestInject): From f9b55812338253c0bc648cabcf92c3568d7d3eb8 Mon Sep 17 00:00:00 2001 From: Elias Mueller Date: Wed, 1 Jul 2026 22:36:11 +0200 Subject: [PATCH 3/4] ci: use ubuntu-latest for all runners --- .github/workflows/tests.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 2515989..202aa1c 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -36,7 +36,7 @@ jobs: lint: name: "Linting" - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest steps: - name: "Checkout" uses: actions/checkout@v7 @@ -53,7 +53,7 @@ jobs: types: name: "Type checking (public API)" - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest steps: - name: "Checkout" uses: actions/checkout@v7 @@ -72,7 +72,7 @@ jobs: tests: name: "Run unit tests" - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: From bf36feeb9763fb958449ec1395c1c17b02e28c71 Mon Sep 17 00:00:00 2001 From: Elias Mueller Date: Wed, 1 Jul 2026 22:39:20 +0200 Subject: [PATCH 4/4] ci: re-enable full mypy --- .github/workflows/tests.yaml | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 202aa1c..27c8f87 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -51,7 +51,24 @@ jobs: - name: "Lint formatting" run: just lint - types: + typing: + name: "Type checking (library code)" + runs-on: ubuntu-latest + steps: + - name: "Checkout" + uses: actions/checkout@v7 + - name: "Setup Python" + uses: actions/setup-python@v6 + with: + python-version: "3.14" + - name: "Setup uv" + uses: astral-sh/setup-uv@v8.2.0 + - name: "Setup just" + uses: extractions/setup-just@v4 + - name: "Type checking (library code)" + run: just typing + + public-typing: name: "Type checking (public API)" runs-on: ubuntu-latest steps: @@ -66,9 +83,7 @@ jobs: - name: "Setup just" uses: extractions/setup-just@v4 - name: "Type checking (public API)" - run: just public-typing -# - name: "Type checking (full)" TODO: re-enable once green -# run: just typing + run: just public-typing-all tests: name: "Run unit tests"