Skip to content

Commit 7030755

Browse files
committed
optimize mutable proxy
1 parent 1d9fee6 commit 7030755

File tree

2 files changed

+31
-29
lines changed

2 files changed

+31
-29
lines changed

reflex/istate/proxy.py

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -378,17 +378,6 @@ class MutableProxy(wrapt.ObjectProxy):
378378
pydantic.BaseModel.__dict__
379379
)
380380

381-
# These types will be wrapped in MutableProxy
382-
__mutable_types__ = (
383-
list,
384-
dict,
385-
set,
386-
Base,
387-
DeclarativeBase,
388-
BaseModelV2,
389-
BaseModelV1,
390-
)
391-
392381
# Dynamically generated classes for tracking dataclass mutations.
393382
__dataclass_proxies__: dict[type, type] = {}
394383

@@ -469,20 +458,6 @@ def _mark_dirty(
469458
return wrapped(*args, **(kwargs or {}))
470459
return None
471460

472-
@classmethod
473-
def _is_mutable_type(cls, value: Any) -> bool:
474-
"""Check if a value is of a mutable type and should be wrapped.
475-
476-
Args:
477-
value: The value to check.
478-
479-
Returns:
480-
Whether the value is of a mutable type.
481-
"""
482-
return isinstance(value, cls.__mutable_types__) or (
483-
dataclasses.is_dataclass(value) and not isinstance(value, Var)
484-
)
485-
486461
@staticmethod
487462
def _is_called_from_dataclasses_internal() -> bool:
488463
"""Check if the current function is called from dataclasses helper.
@@ -514,7 +489,7 @@ def _wrap_recursive(self, value: Any) -> Any:
514489
if self._is_called_from_dataclasses_internal():
515490
return value
516491
# Recursively wrap mutable types, but do not re-wrap MutableProxy instances.
517-
if self._is_mutable_type(value) and not isinstance(value, MutableProxy):
492+
if is_mutable_type(value) and not isinstance(value, MutableProxy):
518493
base_cls = globals()[self.__base_proxy__]
519494
return base_cls(
520495
wrapped=value,
@@ -575,7 +550,7 @@ def __getattr__(self, __name: str) -> Any:
575550
self._wrap_recursive_decorator,
576551
)
577552

578-
if self._is_mutable_type(value) and __name not in (
553+
if is_mutable_type(value) and __name not in (
579554
"__wrapped__",
580555
"_self_state",
581556
"__dict__",
@@ -764,3 +739,30 @@ def _mark_dirty(
764739
return super()._mark_dirty(
765740
wrapped=wrapped, instance=instance, args=args, kwargs=kwargs
766741
)
742+
743+
744+
# These types will be wrapped in MutableProxy
745+
MUTABLE_TYPES = (
746+
list,
747+
dict,
748+
set,
749+
Base,
750+
DeclarativeBase,
751+
BaseModelV2,
752+
BaseModelV1,
753+
)
754+
755+
756+
@functools.lru_cache(maxsize=1024)
757+
def is_mutable_type(type_: type) -> bool:
758+
"""Check if a type is mutable and should be wrapped.
759+
760+
Args:
761+
type_: The type to check.
762+
763+
Returns:
764+
Whether the type is mutable and should be wrapped.
765+
"""
766+
return issubclass(type_, MUTABLE_TYPES) or (
767+
dataclasses.is_dataclass(type_) and not issubclass(type_, Var)
768+
)

reflex/state.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from reflex.istate import HANDLED_PICKLE_ERRORS, debug_failed_pickles
4242
from reflex.istate.data import RouterData
4343
from reflex.istate.proxy import ImmutableMutableProxy as ImmutableMutableProxy
44-
from reflex.istate.proxy import MutableProxy, StateProxy
44+
from reflex.istate.proxy import MutableProxy, StateProxy, is_mutable_type
4545
from reflex.istate.storage import ClientStorageBase
4646
from reflex.model import Model
4747
from reflex.utils import console, format, prerequisites, types
@@ -1359,7 +1359,7 @@ def __getattribute__(self, name: str) -> Any:
13591359
if parent_state is not None:
13601360
return getattr(parent_state, name)
13611361

1362-
if MutableProxy._is_mutable_type(value) and (
1362+
if is_mutable_type(value) and (
13631363
name in super().__getattribute__("base_vars") or name in backend_vars
13641364
):
13651365
# track changes in mutable containers (list, dict, set, etc)

0 commit comments

Comments
 (0)