Latest Results
fix(types): qualify annotations shadowed by same-class members (#6846)
* fix(types): qualify annotations shadowed by same-class members
A class member whose name matches a builtin also shadows that builtin for
annotations elsewhere in the same class body, because type checkers resolve
annotations against the class namespace.
The worst case is `Var.bool()`, which shadows `bool` for the `value: bool`
parameter of the second `Var.create` overload. A checker that resolves the
annotation to the method degrades that parameter to an unknown type, so the
overload matches every argument and `Var.create(anything)` is inferred as
`LiteralBooleanVar`. `Var.to`, `Var.guess_type` and `Var.to_string` are
affected the same way, as are `BaseState.dict`, `BaseComponent.set`,
`PropsBase.dict` and `ToastProps.dict`.
Qualify the 16 affected annotations as `builtins.<name>`. Public method names
are unchanged, so this is not a breaking change.
`_get_type_hint` needed a matching guard: its fallback qualifies a type by
whichever module component of `__module__` it finds in the module globals, so
importing `builtins` for the above made it emit `builtins.str` into generated
stubs, which do not import `builtins`. Builtins are always in scope and now
stay unqualified there.
* test: use repo-relative paths as parametrize ids
Basenames collide across reflex/ and packages/, so a failing check could not
be traced to a file from the node id alone.
* docs: add news fragments for the affected packages
* test: add a type-checking suite driven by assert_type
Inferred types are part of the public contract, but nothing verified them.
`tests/type_checking/` holds Reflex code whose `typing.assert_type` calls each
checker verifies statically; `tests/units/test_type_checking.py` runs every
checker over the directory and requires a clean result.
The assertions are checker-agnostic, so the same file gates pyright and ty
today and anything added later. A checker that is not installed is skipped.
`vars.py` covers the `Var.create`, `Var.to` and `guess_type` overload sets.
Reverting the shadowing fix in this branch turns six of them red, naming the
wrong inferred type in each case.
Adds ty to the dev group so its half actually runs rather than skipping.
* test: drop the AST shadowing lint in favour of the type-checking suite
The assert_type examples cover the same regression by its observable effect
rather than by one syntactic cause.
* test: run the checkers from pre-commit instead of pytest
The pytest wrapper was shelling out to the same checkers CI already runs, and
pyright's existing hook covers `reflex` and `tests`, so it was duplicating that
half outright. Worse, it skipped when a checker was not installed, so a CI
misconfiguration would have read as green.
ty gets its own hook scoped to the example directory. A missing checker now
fails the hook rather than silently passing.
* test: always run the ty hook, and check the examples at the supported floor
The hook was scoped to `tests/type_checking/`, so it only fired when the
examples themselves changed. What they catch is a source edit elsewhere
altering an inferred type, which is exactly the commit the hook would have
skipped.
`typing.assert_type` is 3.11+, so the examples could not be checked at the
3.10 floor reflex supports. `typing_extensions.assert_type` works on every
supported version; verified clean under both checkers at 3.10 and 3.14.
* docs: stop claiming the floor is enforced
The examples are written to hold at 3.10 and verified there by hand, but the
ty hook pins 3.14 and pyright follows the interpreter, so nothing gates it.
Say so rather than implying a guarantee that is not wired up.
* build: raise the reflex-base floor to 0.9.8
`reflex/` uses `AddPageProtocol`, `RegisterRouteContext`, `get_plugin`,
`Env.PREVIEW`, `Plugin.register_route`, `EnvironmentVariables.VITE_MINIFY` and
`REFLEX_NO_AUTOPREFIXER`, none of which exist in reflex-base 0.9.7, so
resolving the declared floor from PyPI fails to type-check.
Pre-existing on main rather than introduced here: main's HEAD is the 0.9.8
release commit and min_deps has not run on it, so this branch is the first to
exercise the check against it. Confirmed by running the script on a pristine
origin/main worktree, which fails identically.
All 17 workspace packages pass afterwards. Latest Branches
-3%
benedikt-bartscher:try-orjson 0%
benedikt-bartscher:pin-lscpu-locale 0%
khaleel/fix-builtin-shadowed-annotations © 2026 CodSpeed Technology