Repository navigation
Conversation
A browser storage var is classified at compile time from its default value or its annotation. A default_factory only reveals what it produces when called, so a str-annotated var whose factory returns a LocalStorage was never compiled as storage and silently held a storage instance as an ordinary str (#7498), while a storage-annotated var's factory was called during compile_client_storage just to read its options. compile_client_storage now raises VarTypeError in both cases: a storage annotated field with a factory (declared, or set later through set_default), and a str/Any-compatible field whose factory returns a storage value. The factory of a str-compatible field is called once at compile for the check; factories for other types are never called. The special case reading options from a factory's product is removed, and the tests that exercised factory-declared storage go with it. Closes #7498 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014uPh1ADyPWucA2MM6zpW9T
_accepts_str used issubclass(str, type_) directly, which raises for a TypedDict annotation (and other types that refuse class checks), so compiling an app with a TypedDict factory field failed. Use safe_issubclass, which treats such types as not accepting a str. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014uPh1ADyPWucA2MM6zpW9T
[Critical impact] The PR appears safe to merge; both previous findings are fixed and no new actionable issues remain. SummaryThe PR rejects browser storage declared through a
Reviews (2) · Last reviewed commit: "Leave backend factories alone; catch sto..." · Reviewed by Greptile |
The factory check only concerns frontend vars, since a backend var is never browser storage, and a backend factory may depend on runtime-only state such as an environment variable. A union annotation now counts as holding a str when any member is a str or a str subclass, so a storage type inside an Optional is checked too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014uPh1ADyPWucA2MM6zpW9T
Merging this PR will degrade performance by 4.7%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | test_state_access[write_own] |
126.1 ms | 132.3 ms | -4.7% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing claude/reject-factory-storage-defaults-1uthtm (248a484) with main (5ae5dcd)
|
CodSpeed Performance Analysis is red on this head, flagging Generated by Claude Code |
Requested by Masen · project thread
All Submissions:
Type of change
Changes To Core Features:
What
Before: a
str-annotated var whosedefault_factoryreturned aLocalStoragewas never detected as browser storage. It compiled as an ordinary var and each session silently held a storage instance as a plainstr. A storage-annotated var with a factory was accepted, andcompile_client_storagecalled the factory to read the storage name and options.After: both declarations fail at compile time with a
VarTypeErrornaming the var and showing the supported form (theme: str = rx.LocalStorage("", name='theme')). Browser storage must be declared with a storage value as the default or with a storage type annotation. The docs say so in Browser Storage and in Changing Defaults.This rejects rather than warns: a factory-produced storage value cannot be classified when the app compiles, so there is no working fallback to warn about, and nothing in the codebase deprecates a declaration that never worked.
How
_compile_client_storage_fieldraises when a storage-annotated field has nodefault(a declared factory, or one set later withset_default(default_factory=...)), and when a field whose annotation accepts astr(str,str | None,Any,object) has a factory that returns aClientStorageBase. That second check calls the factory once at compile forstr-compatible factory fields only; factories for other types are never called. The special case that read storage options from a factory's product is removed, along with the unit and Playwright tests that exercised factory-declared storage.Test plan
tests/units/compiler/test_compiler_utils.py: rejection for each storage type via annotation, viaset_default(default_factory=...), and forstr/str | Nonefactories returning storage; a plainstrfactory and alistfactory compile as ordinary vars with thestrfactory called once.uv run pytest tests/units/compiler tests/units/test_state.py tests/units/utils/test_telemetry_accounting.py: 638 passed.uv run pytest tests/integration/tests_playwright/test_hydration_storage.py: 32 passed.ruff check,ruff format --check,pyright reflex tests: clean.Closes #7498
🤖 Generated with Claude Code
https://claude.ai/code/session_014uPh1ADyPWucA2MM6zpW9T
Generated by Claude Code