Pin ruff target-version to py310, and drop the future imports it made redundant - #2182
Open
David Harris (davidharrishmc) wants to merge 2 commits into
Open
Pin ruff target-version to py310, and drop the future imports it made redundant#2182David Harris (davidharrishmc) wants to merge 2 commits into
David Harris (davidharrishmc) wants to merge 2 commits into
Conversation
[tool.ruff] sets line-length but never target-version, and the root pyproject.toml has no [project] table, so there is no requires-python for ruff to infer the target from. Ruff therefore falls back to searching outside the repository and picks up whatever the nearest ancestor Python project declares. That makes lint results depend on where the repository happens to be checked out. In a standalone checkout, as in CI, nothing is found and ruff's default applies, which lints clean. But checked out inside another Python project that declares an older floor -- for example under a tool that sets requires-python = ">=3.9" -- ruff resolves py39 and reports 16 errors CI never sees, all of them FA102 "missing `from __future__ import annotations`, but uses PEP 604 union" on files that are correct for this project's actual floor. py310 is the floor this project already commits to everywhere else: [tool.pyright] sets pythonVersion = "3.10", all three workspace members declare requires-python = ">=3.10", AGENTS.md asks contributors to keep the Python 3.10-compatible, and CI pins .python-version to 3.10 for the oldest-supported version job. Ruff was the one tool left to infer it. This does not change CI results today; it makes them reproducible outside CI and independent of ruff's default changing in a future release. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjJfW5f7acPCsErzWbCv7m Signed-off-by: David Harris <David_Harris@hmc.edu>
With target-version pinned to py310, PEP 604 unions (X | Y) and PEP 585 builtin generics (list[int]) are valid natively in annotations, so the future import is redundant in most modules. Removed from 40 files. Three files genuinely still need it and keep it: - generators/testgen/src/testgen/data/registers.py annotates four methods with classes that are not yet defined at that point in the module (RegisterFile, IntegerRegisterFile, FloatRegisterFile, VectorRegisterFile). Without lazy annotations these are NameErrors at import. - framework/src/act/parse_udb_config.py imports act.config.Config inside an if TYPE_CHECKING block. Eager annotations would require that import to move to runtime, which is a heavier change than keeping the future import. - framework/src/act/build_cache.py annotates _new_hash() -> hashlib._Hash. That name exists only in typeshed, not at runtime, so evaluating the annotation raises AttributeError on any Python before 3.14. The last one is worth noting for future cleanups: Python 3.14 implements PEP 649, so annotations are lazy by default there and this class of breakage is invisible on a 3.14 interpreter. It must be checked against the 3.10 floor. Verified on Python 3.10 (the oldest supported version, matching the CI job): ruff and pyright clean, ruff format reports no change on any touched file, every touched module imports, make tests leaves the checked-in trees with zero diff, and FAST=True EXTENSIONS=I make -- the exact CI step -- completes a real build of 204 ELFs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjJfW5f7acPCsErzWbCv7m Signed-off-by: David Harris <David_Harris@hmc.edu>
David Harris (davidharrishmc)
force-pushed
the
ruff-target-version
branch
from
August 24, 2026 15:51
483a4b8 to
f51c8c4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits: a config fix, and the cleanup it enables.
1. Pin
target-version = "py310"[tool.ruff]setsline-lengthbut nevertarget-version, and the rootpyproject.tomlhas no[project]table, so there is norequires-pythonfor ruff to infer the target from either. Ruff falls back to searching outside the repository and picks up whatever the nearest ancestor Python project declares.The result is that lint results depend on where the repository is checked out.
In a standalone checkout, as in CI, nothing is found, ruff's default applies, and the tree lints clean. But checked out inside another Python project that declares an older floor — which is how this repo is consumed when vendored as a submodule, e.g. under a parent that sets
requires-python = ">=3.9"— ruff resolvespy39and reports 16 errors CI never sees, all of themFA102(missing from __future__ import annotations, but uses PEP 604 union) on files that are correct for this project's actual floor.Reproduced by forcing the version on an otherwise unmodified tree:
ruff check .(standalone, default)ruff check --target-version py39 .ruff check --target-version py310 .py310is the floor this project already commits to everywhere else:[tool.pyright]setspythonVersion = "3.10", all three workspace members declarerequires-python = ">=3.10",AGENTS.mdasks contributors to keep the Python 3.10-compatible, and CI rewrites.python-versionto3.10for the oldest-supported-version job. Ruff was the one tool left inferring it. Note the asymmetry this removes — pyright was already immune, because its version is pinned in the same file.This does not change CI results today. It makes them reproducible outside CI, and stable if ruff changes its default in a future release.
2. Drop
from __future__ import annotationswhere it is now redundantWith the target pinned to py310, PEP 604 unions (
X | Y) and PEP 585 builtin generics (list[int]) are natively valid in annotations. Removed from 40 files.Three files genuinely still need it and keep it:
generators/testgen/src/testgen/data/registers.pyRegisterFile,IntegerRegisterFile,FloatRegisterFile,VectorRegisterFile) —NameErrorat import without lazy annotationsframework/src/act/parse_udb_config.pyact.config.Configunderif TYPE_CHECKING:; eager annotations would force it to a runtime importframework/src/act/build_cache.py_new_hash() -> hashlib._Hash— that name exists only in typeshed, not at runtimeA note for future cleanups of this kind
The
build_cache.pycase is worth calling out. Python 3.14 implements PEP 649, so annotations are lazily evaluated by default there and this entire class of breakage is invisible on a 3.14 interpreter — the full ACT build passes. On the 3.10 floor it fails at import withAttributeError: module 'hashlib' has no attribute '_Hash'. Anyone repeating this cleanup should verify against 3.10, not against a modern local interpreter. This PR's first CI run caught exactly that, on thePython 3.10 (uv)job.Verification
All re-run on Python 3.10, matching the oldest-supported-version CI job:
ruff checkandpyrightclean;ruff format --checkreports no change on any touched file. (One unrelated file is format-dirty onact4already, before and after this change.)TYPE_CHECKINGis true and trusts typeshed.make testsleaves the checked-in generated trees with zero diff.FAST=True EXTENSIONS=I make— the exact CI step that failed — completes a real build of 204 ELFs.🤖 Generated with Claude Code