Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement a global var cache #4691

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 81 additions & 5 deletions reflex/vars/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import re
import string
import sys
import uuid
import warnings
from types import CodeType, FunctionType
from typing import (
Expand Down Expand Up @@ -1563,17 +1564,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: Callable):
"""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: Any, name: str):
"""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: Any):
"""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: Any, owner: Type | None = 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:
Expand Down