Support hybrid_property on ObjectVar for nested dataclasses#6619
Support hybrid_property on ObjectVar for nested dataclasses#6619masenf wants to merge 4 commits into
Conversation
`rx._x.hybrid_property` previously only resolved as a frontend var when accessed directly on a `State` class. Accessing it through an object var (e.g. `State.info.a_b` where `info` is a dataclass, pydantic model or SQLAlchemy model) raised `VarAttributeError`. `ObjectVar.__getattr__` now detects a `HybridProperty` defined on the underlying type and evaluates its frontend logic with the object var substituted as `self`, so it renders with the same Var-access semantics as accessing the hybrid property directly on the state. This works uniformly across bare classes, pydantic models, SQLAlchemy models and dataclasses, since they are all treated as object vars. `HybridProperty` moved to `reflex_base.vars.hybrid_property` (so the var system can reference it without an inverted dependency) and is still re-exported from `reflex.experimental.hybrid_property`. Fixes #6617 https://claude.ai/code/session_01DKFiYGnWRQG8wMNKFW7obm
Import `hybrid_property` directly from `reflex_base.vars.hybrid_property` in `reflex.experimental.__init__` instead of going through a one-line re-export module. `from reflex.experimental import hybrid_property` and `rx._x.hybrid_property` are unchanged. https://claude.ai/code/session_01DKFiYGnWRQG8wMNKFW7obm
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR extends
Confidence Score: 5/5Safe to merge. The change is additive: ObjectVar attribute lookups gain a new hybrid-property fast-path that is well-guarded and falls through cleanly to existing logic when not applicable. The mechanics are sound: the get/_get_var refactoring is consistent, the ObjectVar hook is minimal and guarded, and all four object-var variants plus state-level access are covered by unit and integration tests. No existing behaviour is removed or silently changed for state classes. No files require special attention. Important Files Changed
Reviews (2): Last reviewed commit: "perf: detect hybrid properties via getat..." | Re-trigger Greptile |
…non-states HybridProperty.__get__ produced a frontend var for any class-level access, which only makes sense on a state (whose class attributes are vars). On a plain class accessed directly — e.g. `Info.a_b` on a dataclass, not through an object var — it ran the getter with the class as `self`, raising AttributeError (no field default) or returning a value built from class defaults. It now returns the descriptor itself, like a normal property. Var access through an object var (`State.info.a_b`) is unaffected: it is resolved by ObjectVar.__getattr__ via _get_var, not __get__. https://claude.ai/code/session_01DKFiYGnWRQG8wMNKFW7obm
ObjectVar.__getattr__ ran inspect.getattr_static on every attribute access to detect a HybridProperty on the underlying type — a pure-Python MRO walk on a hot path, ~15x slower than getattr for ordinary field access. Now that HybridProperty.__get__ returns the descriptor itself for non-state class access, a plain getattr surfaces it directly, so the static lookup is no longer needed. https://claude.ai/code/session_01DKFiYGnWRQG8wMNKFW7obm
|
@greptile |
|
This is great, thanks @masenf ! |
Type of change
Description
This PR extends
hybrid_propertysupport to work seamlessly withObjectVarattribute access on nested dataclasses, Pydantic models, and SQLAlchemy models—not justStateclasses.Key changes:
Moved
HybridPropertytoreflex_base: Relocatedhybrid_property.pyfromreflex/experimental/toreflex_base/vars/to make it available at the var level where it's needed forObjectVarresolution.ObjectVardescriptor resolution: ModifiedObjectVar.__getattr__to detect and resolveHybridPropertydescriptors on the underlying type. When a hybrid property is accessed (e.g.,State.info.a_b), the property's frontend logic is evaluated with the object var substituted asself, enabling consistent var-level semantics.HybridProperty._get_varextraction: Refactored the var-resolution logic into a dedicated_get_varmethod that accepts either a class or anObjectVaras the owner, allowing the property to work uniformly across both direct class access and nested object var access.Comprehensive test coverage: Added unit tests verifying hybrid property resolution on bare classes, Pydantic models, SQLAlchemy models, and dataclasses. Included integration tests demonstrating re-rendering when nested dataclass fields are updated.
Example usage:
Closes #6617
Testing
tests/units/vars/test_object.pycovering hybrid property resolution on all object typestests/integration/test_hybrid_properties.pyverifying frontend rendering and re-rendering on state updateshttps://claude.ai/code/session_01DKFiYGnWRQG8wMNKFW7obm