support dataclasses.asdict on MutableProxy instances
This commit is contained in:
parent
72d0e5f230
commit
d2eb751ab5
@ -3783,6 +3783,24 @@ class MutableProxy(wrapt.ObjectProxy):
|
||||
dataclasses.is_dataclass(value) and not isinstance(value, Var)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _is_called_from_dataclasses_internal() -> bool:
|
||||
"""Check if the current function is called from dataclasses helper.
|
||||
|
||||
Returns:
|
||||
Whether the current function is called from dataclasses internal code.
|
||||
"""
|
||||
# Walk up the stack a bit to see if we are called from dataclasses
|
||||
# internal code, for example `asdict` or `astuple`.
|
||||
frame = inspect.currentframe()
|
||||
for _ in range(5):
|
||||
# Why not `inspect.stack()` -- this is much faster!
|
||||
if not (frame := frame and frame.f_back):
|
||||
break
|
||||
if inspect.getfile(frame) == dataclasses.__file__:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _wrap_recursive(self, value: Any) -> Any:
|
||||
"""Wrap a value recursively if it is mutable.
|
||||
|
||||
@ -3792,6 +3810,9 @@ class MutableProxy(wrapt.ObjectProxy):
|
||||
Returns:
|
||||
The wrapped value.
|
||||
"""
|
||||
# When called from dataclasses internal code, return the unwrapped value
|
||||
if self._is_called_from_dataclasses_internal():
|
||||
return value
|
||||
# Recursively wrap mutable types, but do not re-wrap MutableProxy instances.
|
||||
if self._is_mutable_type(value) and not isinstance(value, MutableProxy):
|
||||
base_cls = globals()[self.__base_proxy__]
|
||||
|
@ -3624,6 +3624,18 @@ def test_mutable_models():
|
||||
state.dc.foo = "baz"
|
||||
assert state.dirty_vars == {"dc"}
|
||||
state.dirty_vars.clear()
|
||||
assert state.dirty_vars == set()
|
||||
state.dc.ls.append({"hi": "reflex"})
|
||||
assert state.dirty_vars == {"dc"}
|
||||
state.dirty_vars.clear()
|
||||
assert state.dirty_vars == set()
|
||||
assert dataclasses.asdict(state.dc) == {"foo": "baz", "ls": [{"hi": "reflex"}]}
|
||||
assert dataclasses.astuple(state.dc) == ("baz", [{"hi": "reflex"}])
|
||||
# creating a new instance shouldn't mark the state dirty
|
||||
assert dataclasses.replace(state.dc, foo="quuc") == ModelDC(
|
||||
foo="quuc", ls=[{"hi": "reflex"}]
|
||||
)
|
||||
assert state.dirty_vars == set()
|
||||
|
||||
|
||||
def test_get_value():
|
||||
|
Loading…
Reference in New Issue
Block a user