Repository navigation
Enable ruff typing-only import rules (TC) - #3902
Merged
Merged
Conversation
anth-volk
added this pull request to stack #3888
October 13, 2026 11:39
anth-volk
force-pushed
the
ruff-typing-imports
branch
from
October 13, 2026 16:56
b71530a to
5d3461e
Compare
anth-volk
removed this pull request from stack #3888
October 13, 2026 19:26
anth-volk
added this pull request to stack #3917
October 13, 2026 19:26
anth-volk
force-pushed
the
ruff-typing-imports
branch
from
October 14, 2026 13:52
5d3461e to
e950a77
Compare
anth-volk
force-pushed
the
ruff-typing-imports
branch
2 times, most recently
from
October 14, 2026 16:59
a59bb82 to
c354d5f
Compare
anth-volk
force-pushed
the
ruff-typing-imports
branch
3 times, most recently
from
October 14, 2026 20:04
e7aff0c to
6b8a90a
Compare
anth-volk
force-pushed
the
ruff-typing-imports
branch
4 times, most recently
from
October 14, 2026 22:29
5035c82 to
cd21647
Compare
anth-volk
force-pushed
the
ruff-typing-imports
branch
from
October 14, 2026 22:56
cd21647 to
e0a9e49
Compare
Select TC and move imports used only in annotations under TYPE_CHECKING. Pydantic, SQLModel and SQLAlchemy evaluate model annotations at runtime, and FastAPI evaluates endpoint annotations, so those imports stay at runtime: pyproject.toml lists the runtime-evaluated base classes (every project model base, since ruff only checks direct bases) and the APIRouter decorators. scripts/rules changes are mirrored in policyengine-sim-api. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
ruff-typing-imports
branch
from
October 15, 2026 00:06
e0a9e49 to
11c3b1f
Compare
anth-volk
marked this pull request as ready for review
October 15, 2026 12:51
Ruff's TC rules keep a class's annotation imports at runtime only when one of its direct bases is listed in runtime-evaluated-base-classes. Pydantic, SQLModel and SQLAlchemy read model annotations at runtime, so a model base missing from that list lets ruff ask for an import its subclasses need to be moved under TYPE_CHECKING; moving it breaks those models the first time they are used. tests/unit/test_runtime_evaluated_annotations.py imports the package (except the two app-assembly modules, which define no classes) and checks that: - every package model class that other models inherit from is listed; - every Pydantic model resolves its annotations (model_rebuild with raise_errors); - every SQLAlchemy mapper configures. Registered as api.quality.runtime-evaluated-models-resolve, with the rationale in a new typing-only-imports skill and a pointer in AGENTS.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
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.
Fixes #3901
Summary
Phase 1 step 1.8, group 2: typing-only imports. Stacked on #3898.
What changed:
selectgainsTC, and its fixes move imports used only in annotations underTYPE_CHECKING(236 findings on today'smaster: 103 standard-library, 90 first-party and 36 third-party imports, plus 7cast()calls whose type is now quoted). This removes import-time work and import cycles, without changing runtime behaviour.What stays at runtime: Pydantic and SQLModel models, SQLAlchemy declarative models and FastAPI endpoints all evaluate annotations at runtime, so their imports must stay.
[tool.ruff.lint.flake8-type-checking]lists:pydantic.BaseModel,sqlmodel.SQLModel,sqlalchemy.orm.DeclarativeBase,V1Base, and the 33 other project model classes that other models inherit from. Ruff checks direct bases only, so each must be listed. A model base missing from the list fails the guard described below.APIRouterroute decorators.Found during testing: the first attempt broke
V1Basemodels, because SQLAlchemy resolvesMapped[...]at class creation. HenceDeclarativeBaseandV1Baseare on the list.Rules tool: the
scripts/ruleschanges here are this repository's own; the copy in the Simulation API no longer has to match.Guard for the runtime list:
tests/unit/test_runtime_evaluated_annotations.py(api.quality.runtime-evaluated-models-resolve) imports the package, apart from the two app-assembly modules, which define no classes. It then checks that:runtime-evaluated-base-classes;model_rebuild(raise_errors=True));Without it, a model base left off the list would let ruff ask for an import its subclasses need to be moved, and the break would surface only when that model was first used. The rationale is in a new skill,
docs/engineering/skills/typing-only-imports.md, with a pointer inAGENTS.md.Testing
pytest tests/unit: 2,342 passed, including the 4 new guard tests. RemovingTimestampedModelfrom the list fails the first. MovingUUIDunderTYPE_CHECKINGinservices/v2/policies/types.pyfails the second, naming the five models that need it.ruff check .passes with 0.15.12 and 0.16.8.🤖 Generated with Claude Code