Преглед изворни кода

Fix infinite recursion when a substate named "state" has a computed var (#2778)

* test_potentially_dirty_substates: when a state named State should be computed

Catch a regression introduced in 0.4.3a1

* _potentially_dirty_substates: qualify substate name

When looking up substate classes, ensure the qualified name is used to avoid
issues with same-named substates.
Masen Furer пре 1 година
родитељ
комит
4f12d2e269
2 измењених фајлова са 27 додато и 3 уклоњено
  1. 2 3
      reflex/state.py
  2. 25 0
      tests/test_state.py

+ 2 - 3
reflex/state.py

@@ -1505,14 +1505,13 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
         """
         # _always_dirty_substates need to be fetched to recalc computed vars.
         fetch_substates = set(
-            cls.get_class_substate(tuple(substate_name.split(".")))
+            cls.get_class_substate((cls.get_name(), *substate_name.split(".")))
             for substate_name in cls._always_dirty_substates
         )
-        # Substates with cached vars also need to be fetched.
         for dependent_substates in cls._substate_var_dependencies.values():
             fetch_substates.update(
                 set(
-                    cls.get_class_substate(tuple(substate_name.split(".")))
+                    cls.get_class_substate((cls.get_name(), *substate_name.split(".")))
                     for substate_name in dependent_substates
                 )
             )

+ 25 - 0
tests/test_state.py

@@ -2719,3 +2719,28 @@ async def test_get_state(mock_app: rx.App, token: str):
             "computed": "",
         },
     }
+
+
+# Save a reference to the rx.State to shadow the name State for testing.
+RxState = State
+
+
+def test_potentially_dirty_substates():
+    """Test that potentially_dirty_substates returns the correct substates.
+
+    Even if the name "State" is shadowed, it should still work correctly.
+    """
+
+    class State(RxState):
+        @ComputedVar
+        def foo(self) -> str:
+            return ""
+
+    class C1(State):
+        @ComputedVar
+        def bar(self) -> str:
+            return ""
+
+    assert RxState._potentially_dirty_substates() == {State}
+    assert State._potentially_dirty_substates() == {C1}
+    assert C1._potentially_dirty_substates() == set()