diff --git a/reflex/state.py b/reflex/state.py index 100a48c8f4..010af0bd1d 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1008,6 +1008,21 @@ def _clean(self): self.dirty_vars = set() self.dirty_substates = set() + def get_value(self, key: str) -> Any: + """Get the value of a field (without proxying). + + The returned value will NOT track dirty state updates. + + Args: + key: The key of the field. + + Returns: + The value of the field. + """ + if isinstance(key, MutableProxy): + return super().get_value(key.__wrapped__) + return super().get_value(key) + def dict(self, include_computed: bool = True, **kwargs) -> dict[str, Any]: """Convert the object to a dictionary. diff --git a/tests/test_state.py b/tests/test_state.py index 74ec8e1eb6..b96b263ce3 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -29,6 +29,7 @@ StateUpdate, ) from reflex.utils import prerequisites +from reflex.utils.format import json_dumps from reflex.vars import BaseVar, ComputedVar from .states import GenState @@ -2091,6 +2092,24 @@ def test_duplicate_substate_class(duplicate_substate): duplicate_substate() +class Foo(Base): + """A class containing a list of str.""" + + tags: List[str] = ["123", "456"] + + +def test_json_dumps_with_mutables(): + """Test that json.dumps works with Base vars inside mutable types.""" + + class MutableContainsBase(State): + items: List[Foo] = [Foo()] + + dict_val = MutableContainsBase().dict() + assert isinstance(dict_val["items"][0], dict) + val = json_dumps(dict_val) + assert val == '{"is_hydrated": false, "items": [{"tags": ["123", "456"]}]}' + + def test_reset_with_mutables(): """Calling reset should always reset fields to a copy of the defaults.""" default = [[0, 0], [0, 1], [1, 1]]