Repository navigation
Do not import reflex.model while transforming an event payload - #7802
Conversation
_transform_event_arg ran `from reflex.model import Model` for every dict payload with a class annotation (dict, dataclass, TypedDict, Pydantic model). The first such event therefore imported reflex.model, and with the db extra SQLAlchemy/SQLModel/alembic (0.22-0.56 s, ~143 modules), inside the event task, and the dev event-loop blocking monitor (#7672) reported the user's trivial handler as blocking the loop. A class can only subclass rx.Model after reflex.model has run, so look the module up in sys.modules instead of importing it, as telemetry_accounting._get_db_model_count already does. Apps that never use rx.Model never load SQLAlchemy, at startup or per event, and apps that do already loaded it when their models were defined. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi
[Medium impact] The PR appears safe to merge. SummaryRemoves the import of
Reviews (1) · Last reviewed commit: "Do not import reflex.model while transfo..." · Reviewed by Greptile |
…ing) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi
Merging this PR will degrade performance by 4.56%2 warnings
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing |
|
The failing Generated by Claude Code |
_transform_event_arg ran `from reflex.model import Model` for every dict payload with a class annotation (dict, dataclass, TypedDict, Pydantic model). The first such event therefore imported reflex.model, and with the db extra SQLAlchemy/SQLModel/alembic (0.22-0.56 s, ~143 modules), inside the event task, and the dev event-loop blocking monitor (#7672) reported the user's trivial handler as blocking the loop. A class can only subclass rx.Model after reflex.model has run, so look the module up in sys.modules instead of importing it, as telemetry_accounting._get_db_model_count already does. Apps that never use rx.Model never load SQLAlchemy, at startup or per event, and apps that do already loaded it when their models were defined. Claude-Session: https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi Co-authored-by: Claude <noreply@anthropic.com> (cherry picked from commit 68b522c)
…the train Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi
Fixes FINDING-045 from the reflex 0.11.0a1 pre-release testing (artifacts on branch
claude/vibrant-pasteur-3921g3,prerelease-testing/runs/2026-11-11-v0.11.0a1/compile_memo/andenterprise/).All Submissions:
Type of change
Changes To Core Features:
Defect
The first event whose handler takes a
dict, dataclass,TypedDictor Pydantic model argument (e.g.on_upload_progress=State.on_progresswithdef on_progress(self, prog: dict)) ranfrom reflex.model import Modelinside_transform_event_arg. With thedbextra installed that imports SQLAlchemy / SQLModel / alembic (0.22–0.56 s, ~143 modules) inside the event task, and the dev event-loop blocking monitor (#7672) reported the user's trivial handler as blocking the loop, with a stack through SQLAlchemy's import. Seen on an upload page and on the reflex-enterprise flow demo.Fix
A class can only subclass
rx.Modeloncereflex.modelhas run, so the payload transform now looks the module up insys.modulesinstead of importing it (the patterntelemetry_accounting._get_db_model_countalready uses). Apps that never userx.Modelnever load SQLAlchemy, at startup or per event; apps that do loaded it when they defined their models. Per-event cost unchanged (~120 ns).Every lazy import reachable from the event path was checked, statically and with an import audit hook on a dev server: this was the only one that ran inside an event (the next largest, plotly's
to_jsonon the first Figure, costs 1–16 ms). Warmingreflex.modelat worker startup was considered and rejected: +0.22–0.32 s on every worker start and dev reload for every app with the db extra, used or not (reflex-enterprise depends onreflex[db]), and warming it in a thread can still block the first event on the import lock.Test plan
tests/units/reflex_base/event/processor/test_base_state_processor.py:test_transform_event_arg_dict_does_not_import_the_model_module[dict|_TagsDict|_TagsRecord]— withsys.modules["reflex.model"] = None; before:ModuleNotFoundError: import of reflex.model halted; None in sys.modules×3.test_dict_arg_handler_first_event_does_not_block_on_the_model_import— realBaseStateEventProcessorin dev with a 0.05 s threshold and a fakereflex.modelwhose import sleeps 0.3 s; before: the fake import ran and the monitor logged the finding's warning; after: no import, no warning, the dict reaches the handler.rx.Modelpath test still passes. The processor directory: 478 passed; the touched module: 375 passed.ruff,pyright: clean.on_progresswith 147 imports inside the event; this branch: 0 warnings, 0 imports inside events for dict / dataclass / TypedDict / Pydantic / background / upload handlers, with and without the db extra; anrx.Modelargument still drops extra keys.Notes
/_healthlazily importsreflex.modelon the loop whendb_urlis set (not an event); left as is.News fragment:
packages/reflex-base/news/+dict-arg-no-model-import.bugfix.md.Generated by Claude Code