Skip to content

Commit 3d22562

Browse files
authored
optimize mutable proxy (#5815)
* optimize mutable proxy * type
1 parent a3c14e7 commit 3d22562

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
@@ -376,17 +376,6 @@ class MutableProxy(wrapt.ObjectProxy):
376376
pydantic.BaseModel.__dict__
377377
)
378378

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

@@ -467,20 +456,6 @@ def _mark_dirty(
467456
return wrapped(*args, **(kwargs or {}))
468457
return None
469458

470-
@classmethod
471-
def _is_mutable_type(cls, value: Any) -> bool:
472-
"""Check if a value is of a mutable type and should be wrapped.
473-
474-
Args:
475-
value: The value to check.
476-
477-
Returns:
478-
Whether the value is of a mutable type.
479-
"""
480-
return isinstance(value, cls.__mutable_types__) or (
481-
dataclasses.is_dataclass(value) and not isinstance(value, Var)
482-
)
483-
484459
@staticmethod
485460
def _is_called_from_dataclasses_internal() -> bool:
486461
"""Check if the current function is called from dataclasses helper.
@@ -512,7 +487,7 @@ def _wrap_recursive(self, value: Any) -> Any:
512487
if self._is_called_from_dataclasses_internal():
513488
return value
514489
# Recursively wrap mutable types, but do not re-wrap MutableProxy instances.
515-
if self._is_mutable_type(value) and not isinstance(value, MutableProxy):
490+
if is_mutable_type(type(value)) and not isinstance(value, MutableProxy):
516491
base_cls = globals()[self.__base_proxy__]
517492
return base_cls(
518493
wrapped=value,
@@ -573,7 +548,7 @@ def __getattr__(self, __name: str) -> Any:
573548
self._wrap_recursive_decorator,
574549
)
575550

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

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(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)