From 2f0e29f750d6c92a88ffdd80298ca3fae4838d38 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Fri, 24 Jan 2025 16:39:05 -0800 Subject: [PATCH 1/2] implement a global var cache --- reflex/vars/base.py | 86 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 8fb543c99b8..dbb0ea8cbd0 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -13,6 +13,7 @@ import re import string import sys +import uuid import warnings from types import CodeType, FunctionType from typing import ( @@ -1555,17 +1556,92 @@ def figure_out_type(value: Any) -> types.GenericType: return type(value) -class cached_property_no_lock(functools.cached_property): # noqa: N801 - """A special version of functools.cached_property that does not use a lock.""" +GLOBAL_CACHE = {} + + +class cached_property: # noqa: N801 + """A cached property that caches the result of the function.""" def __init__(self, func): - """Initialize the cached_property_no_lock. + """Initialize the cached_property. Args: func: The function to cache. """ - super().__init__(func) - self.lock = contextlib.nullcontext() + self._func = func + self._attrname = None + + def __set_name__(self, owner, name): + """Set the name of the cached property. + + Args: + owner: The owner of the cached property. + name: The name of the cached property. + + Raises: + TypeError: If the cached property is assigned to two different names. + """ + if self._attrname is None: + self._attrname = name + + original_del = getattr(owner, "__del__", None) + + def delete_property(this): + """Delete the cached property. + + Args: + this: The object to delete the cached property from. + """ + cached_field_name = "_reflex_cache_" + name + try: + unique_id = object.__getattribute__(this, cached_field_name) + except AttributeError: + if original_del is not None: + original_del(this) + return + if unique_id in GLOBAL_CACHE: + del GLOBAL_CACHE[unique_id] + + if original_del is not None: + original_del(this) + + owner.__del__ = delete_property + + elif name != self._attrname: + raise TypeError( + "Cannot assign the same cached_property to two different names " + f"({self._attrname!r} and {name!r})." + ) + + def __get__(self, instance, owner=None): + """Get the cached property. + + Args: + instance: The instance to get the cached property from. + owner: The owner of the cached property. + + Returns: + The cached property. + + Raises: + TypeError: If the class does not have __set_name__. + """ + if self._attrname is None: + raise TypeError( + "Cannot use cached_property on a class without __set_name__." + ) + cached_field_name = "_reflex_cache_" + self._attrname + try: + unique_id = object.__getattribute__(instance, cached_field_name) + except AttributeError: + unique_id = uuid.uuid4().int + object.__setattr__(instance, cached_field_name, unique_id) + if unique_id not in GLOBAL_CACHE: + GLOBAL_CACHE[unique_id] = self._func(instance) + return GLOBAL_CACHE[unique_id] + + +cached_property_no_lock = cached_property class CachedVarOperation: From a3b91d9b4e6270c2d587739da15d288e7153811f Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 29 Jan 2025 10:16:12 -0800 Subject: [PATCH 2/2] fix misisng types --- reflex/vars/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 0dbd6e481bd..0f39c0fdd15 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -1579,7 +1579,7 @@ def __init__(self, func: Callable): self._func = func self._attrname = None - def __set_name__(self, owner, name): + def __set_name__(self, owner: Any, name: str): """Set the name of the cached property. Args: @@ -1594,7 +1594,7 @@ def __set_name__(self, owner, name): original_del = getattr(owner, "__del__", None) - def delete_property(this): + def delete_property(this: Any): """Delete the cached property. Args: @@ -1621,7 +1621,7 @@ def delete_property(this): f"({self._attrname!r} and {name!r})." ) - def __get__(self, instance, owner=None): + def __get__(self, instance: Any, owner: Type | None = None): """Get the cached property. Args: