Repository navigation
Address the #7215 review follow-ups in BaseStateMeta - #7626
Conversation
Give the metaclass a typed `_reflex_state_root` default of None and read it directly from the state bases in `__new__`, instead of looking it up by name with getattr over every base. `_is_tree_state` now treats both None and the class itself as "not a tree state", so states outside any root's hierarchy stay out of the tree as before. `_validate_state_name` accepts None, since a state outside any hierarchy reserves no names. Split test_reserved_mixin_var into one test per mixin kind, so each asserts where the rejection happens; the state-mixin case used to stop at its first statement. Document the BaseStateMeta contract: `type(rx.State) is BaseStateMeta`, the `state_root=` and `mixin=` class keywords, and the reserved `_reflex_state_root` name. Closes reflex-dev#7264 Co-authored-by: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 2 files
Reply to a comment to ask cubic a question or push back. It learns from your replies.
View guided diff | Re-trigger cubic
[Medium impact] The PR appears safe to merge; no actionable issues remain. SummaryDocuments the
Reviews (4) · Last reviewed commit: "Merge branch 'main' into fix/7264-state-..." · Reviewed by Greptile |
Tuple membership falls back to ==, which a custom BaseStateMeta subclass can override, so check `is not None` and `is not cls` explicitly, as the getattr version did. Co-authored-by: Claude <noreply@anthropic.com>
masenf
left a comment
There was a problem hiding this comment.
thanks for the cleanup work 👏
Merging this PR will not alter performance1 warning
Comparing |
Summary
Closes #7264.
This handles the three follow-ups from the #7215 review that the issue lists: a dead statement in
test_reserved_mixin_var, thegetattrlookup of_reflex_state_rootinBaseStateMeta.__new__, and the missing contract docs onBaseStateMeta.What changed
test_reserved_mixin_varinto two tests. The plain-mixin case now creates the mixin outsidepytest.raises, so it shows the rejection happens when a state inherits it. The newtest_reserved_state_mixin_varasserts the rejection at the state mixin's own declaration, with no second statement left to skip.BaseStateMetanow has_reflex_state_root: BaseStateMeta | None = None, and__new__reads it directly from theEvenMoreBasicBaseStatebases instead of callinggetattron every base._is_tree_state: this also usedgetattr, withclsas the fallback. With the newNonedefault, root-less states would have counted as tree states, so it now checksis not Noneandis not cls(identity, as before). The existing suite still passed with the broken version, so I addedtest_only_states_below_a_root_are_tree_states._validate_state_name: now acceptsNoneand returns early, since a state outside any hierarchy reserves no names. Without this, pyright flags the threecls._reflex_state_rootcalls inreflex/state.py. Covered bytest_no_root_reserves_no_names.BaseStateMetanow documents thattype(rx.State) is BaseStateMetais supported, thestate_root=andmixin=keywords, and the reserved_reflex_state_rootname.Notes for reviewers
Nonebranch in_validate_state_nameonly exists for the type checker. At runtime those three callers always have a root. If you'd rather narrow the type at the call sites instead, I can change it.skip-changeloglabel?Verification
uv run pytest tests/units --cov --no-cov-on-fail --cov-report=: 13,083 passed, 81.99% coverage. Two granian reload tests intests/units/utils/test_exec.pytime out on my WSL machine (they fail onmaintoo) and pass in CI.uv run ruff check .,uv run ruff format --check .anduv run pyright reflex tests: all clean.The code changes were made with help from Claude. I reviewed the diff and confirmed the checks above pass on my machine.