[ENG-3476] Setting State Vars that are not defined should raise an error (#4007)
This commit is contained in:
parent
12d73e4167
commit
4b3d056212
@ -74,6 +74,7 @@ from reflex.utils.exceptions import (
|
||||
EventHandlerShadowsBuiltInStateMethod,
|
||||
ImmutableStateError,
|
||||
LockExpiredError,
|
||||
SetUndefinedStateVarError,
|
||||
)
|
||||
from reflex.utils.exec import is_testing_env
|
||||
from reflex.utils.serializers import serializer
|
||||
@ -1260,6 +1261,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
Args:
|
||||
name: The name of the attribute.
|
||||
value: The value of the attribute.
|
||||
|
||||
Raises:
|
||||
SetUndefinedStateVarError: If a value of a var is set without first defining it.
|
||||
"""
|
||||
if isinstance(value, MutableProxy):
|
||||
# unwrap proxy objects when assigning back to the state
|
||||
@ -1277,6 +1281,17 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||
self._mark_dirty()
|
||||
return
|
||||
|
||||
if (
|
||||
name not in self.vars
|
||||
and name not in self.get_skip_vars()
|
||||
and not name.startswith("__")
|
||||
and not name.startswith(f"_{type(self).__name__}__")
|
||||
):
|
||||
raise SetUndefinedStateVarError(
|
||||
f"The state variable '{name}' has not been defined in '{type(self).__name__}'. "
|
||||
f"All state variables must be declared before they can be set."
|
||||
)
|
||||
|
||||
# Set the attribute.
|
||||
super().__setattr__(name, value)
|
||||
|
||||
|
@ -115,3 +115,7 @@ class PrimitiveUnserializableToJSON(ReflexError, ValueError):
|
||||
|
||||
class InvalidLifespanTaskType(ReflexError, TypeError):
|
||||
"""Raised when an invalid task type is registered as a lifespan task."""
|
||||
|
||||
|
||||
class SetUndefinedStateVarError(ReflexError, AttributeError):
|
||||
"""Raised when setting the value of a var without first declaring it."""
|
||||
|
@ -41,6 +41,7 @@ from reflex.state import (
|
||||
)
|
||||
from reflex.testing import chdir
|
||||
from reflex.utils import format, prerequisites, types
|
||||
from reflex.utils.exceptions import SetUndefinedStateVarError
|
||||
from reflex.utils.format import json_dumps
|
||||
from reflex.vars.base import ComputedVar, Var
|
||||
from tests.units.states.mutation import MutableSQLAModel, MutableTestState
|
||||
@ -3262,3 +3263,45 @@ def test_child_mixin_state() -> None:
|
||||
|
||||
assert "computed" in ChildUsesMixinState.inherited_vars
|
||||
assert "computed" not in ChildUsesMixinState.computed_vars
|
||||
|
||||
|
||||
def test_assignment_to_undeclared_vars():
|
||||
"""Test that an attribute error is thrown when undeclared vars are set."""
|
||||
|
||||
class State(BaseState):
|
||||
val: str
|
||||
_val: str
|
||||
__val: str # type: ignore
|
||||
|
||||
def handle_supported_regular_vars(self):
|
||||
self.val = "no underscore"
|
||||
self._val = "single leading underscore"
|
||||
self.__val = "double leading undercore"
|
||||
|
||||
def handle_regular_var(self):
|
||||
self.num = 5
|
||||
|
||||
def handle_backend_var(self):
|
||||
self._num = 5
|
||||
|
||||
def handle_non_var(self):
|
||||
self.__num = 5
|
||||
|
||||
class Substate(State):
|
||||
def handle_var(self):
|
||||
self.value = 20
|
||||
|
||||
state = State() # type: ignore
|
||||
sub_state = Substate() # type: ignore
|
||||
|
||||
with pytest.raises(SetUndefinedStateVarError):
|
||||
state.handle_regular_var()
|
||||
|
||||
with pytest.raises(SetUndefinedStateVarError):
|
||||
sub_state.handle_var()
|
||||
|
||||
with pytest.raises(SetUndefinedStateVarError):
|
||||
state.handle_backend_var()
|
||||
|
||||
state.handle_supported_regular_vars()
|
||||
state.handle_non_var()
|
||||
|
Loading…
Reference in New Issue
Block a user