Skip to content

Address the #7215 review follow-ups in BaseStateMeta - #7626

Merged
masenf merged 5 commits into
reflex-dev:mainfrom
yam333:fix/7264-state-meta-followups
Oct 22, 2026
Merged

masenf merged 5 commits into
reflex-dev:mainfrom
yam333:fix/7264-state-meta-followups

Conversation

@yam333

@yam333 yam333 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

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, the getattr lookup of _reflex_state_root in BaseStateMeta.__new__, and the missing contract docs on BaseStateMeta.

What changed

  • Test: split test_reserved_mixin_var into two tests. The plain-mixin case now creates the mixin outside pytest.raises, so it shows the rejection happens when a state inherits it. The new test_reserved_state_mixin_var asserts the rejection at the state mixin's own declaration, with no second statement left to skip.
  • Typed default: BaseStateMeta now has _reflex_state_root: BaseStateMeta | None = None, and __new__ reads it directly from the EvenMoreBasicBaseState bases instead of calling getattr on every base.
  • _is_tree_state: this also used getattr, with cls as the fallback. With the new None default, root-less states would have counted as tree states, so it now checks is not None and is not cls (identity, as before). The existing suite still passed with the broken version, so I added test_only_states_below_a_root_are_tree_states.
  • _validate_state_name: now accepts None and returns early, since a state outside any hierarchy reserves no names. Without this, pyright flags the three cls._reflex_state_root calls in reflex/state.py. Covered by test_no_root_reserves_no_names.
  • Docstring: BaseStateMeta now documents that type(rx.State) is BaseStateMeta is supported, the state_root= and mixin= keywords, and the reserved _reflex_state_root name.

Notes for reviewers

  • The None branch in _validate_state_name only 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.
  • There's no user-facing change, so I didn't add a news fragment. Could you add the skip-changelog label?

Verification

  • uv run pytest tests/units --cov --no-cov-on-fail --cov-report=: 13,083 passed, 81.99% coverage. Two granian reload tests in tests/units/utils/test_exec.py time out on my WSL machine (they fail on main too) and pass in CI.
  • uv run ruff check ., uv run ruff format --check . and uv 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.

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>
@yam333
yam333 requested a review from a team as a code owner October 21, 2026 16:26

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread packages/reflex-base/src/reflex_base/vars/base.py Outdated
@greptile-apps

greptile-apps Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues remain.

Summary

Documents the BaseStateMeta contract and replaces the root lookup with a typed default.

  • State classes now carry a clear root value for hierarchy checks.

Reviews (4) · Last reviewed commit: "Merge branch 'main' into fix/7264-state-..." · Reviewed by Greptile

Comment thread packages/reflex-base/src/reflex_base/vars/base.py Outdated
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 masenf added the on deck PRs lined up to review / merge next label Oct 21, 2026
masenf
masenf previously approved these changes Oct 22, 2026

@masenf masenf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the cleanup work 👏

@masenf
masenf enabled auto-merge (squash) October 22, 2026 00:38
@codspeed

codspeed Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning

⚠️ 17 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

✅ 148 untouched benchmarks


Comparing yam333:fix/7264-state-meta-followups (136abbc) with main (be0c685)

Open in CodSpeed

@masenf
masenf merged commit b2e009a into reflex-dev:main Oct 22, 2026
169 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

on deck PRs lined up to review / merge next

Projects

None yet

3 participants