diff --git a/reflex/__init__.py b/reflex/__init__.py index d029486a2..94ba31bd7 100644 --- a/reflex/__init__.py +++ b/reflex/__init__.py @@ -325,7 +325,6 @@ _MAPPING: dict = { "utils.imports": ["ImportVar"], "utils.serializers": ["serializer"], "vars": ["Var"], - "ivars.base": ["cached_var"], } _SUBMODULES: set[str] = { diff --git a/reflex/__init__.pyi b/reflex/__init__.pyi index 5d3fea2bb..ceecd1a6a 100644 --- a/reflex/__init__.pyi +++ b/reflex/__init__.pyi @@ -175,7 +175,6 @@ from .event import stop_propagation as stop_propagation from .event import upload_files as upload_files from .event import window_alert as window_alert from .experimental import _x as _x -from .ivars.base import cached_var as cached_var from .middleware import Middleware as Middleware from .middleware import middleware as middleware from .model import Model as Model diff --git a/reflex/app.py b/reflex/app.py index ca438fd2d..e1a0a8568 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -442,11 +442,7 @@ class App(MiddlewareMixin, LifespanMixin, Base): raise except TypeError as e: message = str(e) - if ( - "BaseVar" in message - or "ComputedVar" in message - or "ImmutableComputedVar" in message - ): + if "Var" in message: raise VarOperationTypeError( "You may be trying to use an invalid Python function on a state var. " "When referencing a var inside your render code, only limited var operations are supported. " diff --git a/reflex/components/chakra/media/image.py b/reflex/components/chakra/media/image.py index 6a4f59711..f10ba5eb4 100644 --- a/reflex/components/chakra/media/image.py +++ b/reflex/components/chakra/media/image.py @@ -7,7 +7,6 @@ from typing import Any, Optional from reflex.components.chakra import ChakraComponent, LiteralImageLoading from reflex.components.component import Component from reflex.event import EventHandler -from reflex.ivars.base import LiteralVar from reflex.vars import Var @@ -69,7 +68,4 @@ class Image(ChakraComponent): Returns: The Image component. """ - src = props.get("src", None) - if src is not None and not isinstance(src, (Var)): - props["src"] = LiteralVar.create(value=src) return super().create(*children, **props) diff --git a/reflex/components/chakra/navigation/breadcrumb.pyi b/reflex/components/chakra/navigation/breadcrumb.pyi index 914b00719..c46a6ccba 100644 --- a/reflex/components/chakra/navigation/breadcrumb.pyi +++ b/reflex/components/chakra/navigation/breadcrumb.pyi @@ -7,6 +7,7 @@ from typing import Any, Callable, Dict, Optional, Union, overload from reflex.components.chakra import ChakraComponent from reflex.components.chakra.navigation.link import Link +from reflex.components.component import Component from reflex.event import EventHandler, EventSpec from reflex.style import Style from reflex.vars import Var @@ -239,7 +240,7 @@ class BreadcrumbLink(Link): rel: Optional[Union[Var[str], str]] = None, href: Optional[Union[Var[str], str]] = None, text: Optional[Union[Var[str], str]] = None, - as_: Optional[Union[Var[str], str]] = None, + as_: Optional[Union[Var[Component], Component]] = None, is_external: Optional[Union[Var[bool], bool]] = None, style: Optional[Style] = None, key: Optional[Any] = None, diff --git a/reflex/components/chakra/navigation/link.py b/reflex/components/chakra/navigation/link.py index 8fa67417f..67f2711ac 100644 --- a/reflex/components/chakra/navigation/link.py +++ b/reflex/components/chakra/navigation/link.py @@ -25,7 +25,7 @@ class Link(ChakraComponent): text: Var[str] # What the link renders to. - as_: Var[str] = ImmutableVar.create_safe("NextLink").to(str) + as_: Var[Component] = ImmutableVar(_var_name="NextLink", _var_type=Component) # If true, the link will open in new tab. is_external: Var[bool] diff --git a/reflex/components/chakra/navigation/link.pyi b/reflex/components/chakra/navigation/link.pyi index 6a33cd3ba..df092377b 100644 --- a/reflex/components/chakra/navigation/link.pyi +++ b/reflex/components/chakra/navigation/link.pyi @@ -6,6 +6,7 @@ from typing import Any, Callable, Dict, Optional, Union, overload from reflex.components.chakra import ChakraComponent +from reflex.components.component import Component from reflex.components.next.link import NextLink from reflex.event import EventHandler, EventSpec from reflex.style import Style @@ -24,7 +25,7 @@ class Link(ChakraComponent): rel: Optional[Union[Var[str], str]] = None, href: Optional[Union[Var[str], str]] = None, text: Optional[Union[Var[str], str]] = None, - as_: Optional[Union[Var[str], str]] = None, + as_: Optional[Union[Var[Component], Component]] = None, is_external: Optional[Union[Var[bool], bool]] = None, style: Optional[Style] = None, key: Optional[Any] = None, diff --git a/reflex/components/core/banner.py b/reflex/components/core/banner.py index 7e899079b..4c4f587ee 100644 --- a/reflex/components/core/banner.py +++ b/reflex/components/core/banner.py @@ -22,7 +22,7 @@ from reflex.ivars.base import ImmutableVar, LiteralVar from reflex.ivars.function import FunctionStringVar from reflex.ivars.number import BooleanVar from reflex.ivars.sequence import LiteralArrayVar -from reflex.utils.imports import ImportDict, ImportVar +from reflex.utils.imports import ImportVar from reflex.vars import ImmutableVarData, Var, VarData connect_error_var_data: VarData = VarData( # type: ignore @@ -56,20 +56,9 @@ has_too_many_connection_errors: Var = ImmutableVar.create_safe( ).to(BooleanVar) -class WebsocketTargetURL: +class WebsocketTargetURL(ImmutableVar): """A component that renders the websocket target URL.""" - def add_imports(self) -> ImportDict: - """Add imports for the websocket target URL component. - - Returns: - The import dict. - """ - return { - f"/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")], - "/env.json": [ImportVar(tag="env", is_default=True)], - } - @classmethod def create(cls) -> ImmutableVar: """Create a websocket target URL component. @@ -85,6 +74,7 @@ class WebsocketTargetURL: f"/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")], }, ), + _var_type=WebsocketTargetURL, ) diff --git a/reflex/components/core/banner.pyi b/reflex/components/core/banner.pyi index 4c7de2fbe..6327afe0b 100644 --- a/reflex/components/core/banner.pyi +++ b/reflex/components/core/banner.pyi @@ -12,7 +12,7 @@ from reflex.components.sonner.toast import Toaster, ToastProps from reflex.event import EventHandler, EventSpec from reflex.ivars.base import ImmutableVar from reflex.style import Style -from reflex.utils.imports import ImportDict, ImportVar +from reflex.utils.imports import ImportVar from reflex.vars import Var, VarData connect_error_var_data: VarData @@ -22,8 +22,7 @@ connection_errors_count: Var has_connection_errors: Var has_too_many_connection_errors: Var -class WebsocketTargetURL: - def add_imports(self) -> ImportDict: ... +class WebsocketTargetURL(ImmutableVar): @classmethod def create(cls) -> ImmutableVar: ... # type: ignore diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py index 878e5ac12..375d563c8 100644 --- a/reflex/components/datadisplay/code.py +++ b/reflex/components/datadisplay/code.py @@ -2,9 +2,10 @@ from __future__ import annotations -import re from typing import Dict, Literal, Optional, Union +from typing_extensions import get_args + from reflex.components.component import Component from reflex.components.core.cond import color_mode_cond from reflex.components.lucide.icon import Icon @@ -350,6 +351,20 @@ LiteralCodeLanguage = Literal[ ] +def replace_quotes_with_camel_case(value: str) -> str: + """Replaces quotes in the given string with camel case format. + + Args: + value (str): The string to be processed. + + Returns: + str: The processed string with quotes replaced by camel case. + """ + for theme in get_args(LiteralCodeBlockTheme): + value = value.replace(f'"{theme}"', format.to_camel_case(theme)) + return value + + class CodeBlock(Component): """A code block.""" @@ -393,20 +408,13 @@ class CodeBlock(Component): themeString = str(self.theme) - themes = re.findall(r'"(.*?)"', themeString) - if not themes: - themes = [themeString] + selected_themes = [] - if "oneLight" in themeString: - themes.append("light") - if "oneDark" in themeString: - themes.append("dark") - if "one-light" in themeString: - themes.append("light") - if "one-dark" in themeString: - themes.append("dark") + for possibleTheme in get_args(LiteralCodeBlockTheme): + if possibleTheme in themeString: + selected_themes.append(possibleTheme) - themes = sorted(set(themes)) + selected_themes = sorted(set(selected_themes)) imports_.update( { @@ -417,7 +425,7 @@ class CodeBlock(Component): install=False, ) ] - for theme in themes + for theme in selected_themes } ) @@ -523,12 +531,14 @@ class CodeBlock(Component): def _render(self): out = super()._render() - predicate, qmark, value = self.theme._var_name.partition("?") - out.add_props( - style=ImmutableVar.create( - format.to_camel_case(f"{predicate}{qmark}{value.replace('`', '')}"), - ) - ).remove_props("theme", "code").add_props(children=self.code) + + theme = self.theme._replace( + _var_name=replace_quotes_with_camel_case(str(self.theme)) + ) + + out.add_props(style=theme).remove_props("theme", "code").add_props( + children=self.code + ) return out diff --git a/reflex/components/datadisplay/code.pyi b/reflex/components/datadisplay/code.pyi index 9db5b2344..015cc0708 100644 --- a/reflex/components/datadisplay/code.pyi +++ b/reflex/components/datadisplay/code.pyi @@ -341,6 +341,8 @@ LiteralCodeLanguage = Literal[ "zig", ] +def replace_quotes_with_camel_case(value: str) -> str: ... + class CodeBlock(Component): def add_imports(self) -> ImportDict: ... @overload diff --git a/reflex/components/next/image.py b/reflex/components/next/image.py index ed9e534fb..817bf590a 100644 --- a/reflex/components/next/image.py +++ b/reflex/components/next/image.py @@ -3,7 +3,6 @@ from typing import Any, Literal, Optional, Union from reflex.event import EventHandler -from reflex.ivars.base import LiteralVar from reflex.utils import types from reflex.vars import Var @@ -103,8 +102,4 @@ class Image(NextComponent): # mysteriously, following `sizes` prop is needed to avoid blury images. props["sizes"] = "100vw" - src = props.get("src", None) - if src is not None and not isinstance(src, (Var)): - props["src"] = LiteralVar.create(src) - return super().create(*children, **props) diff --git a/reflex/ivars/base.py b/reflex/ivars/base.py index 004b3464d..88a73f8a8 100644 --- a/reflex/ivars/base.py +++ b/reflex/ivars/base.py @@ -174,14 +174,13 @@ class ImmutableVar(Var, Generic[VAR_TYPE]): "The _var_full_name_needs_state_prefix argument is not supported for ImmutableVar." ) - field_values = dict( - _var_name=kwargs.pop("_var_name", self._var_name), - _var_type=kwargs.pop("_var_type", self._var_type), + return dataclasses.replace( + self, _var_data=ImmutableVarData.merge( kwargs.get("_var_data", self._var_data), merge_var_data ), + **kwargs, ) - return dataclasses.replace(self, **field_values) @classmethod def create( @@ -366,6 +365,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]): fixed_output_type = get_origin(output) or output + # If the first argument is a python type, we map it to the corresponding Var type. if fixed_output_type is dict: return self.to(ObjectVar, output) if fixed_output_type in (list, tuple, set): @@ -409,16 +409,21 @@ class ImmutableVar(Var, Generic[VAR_TYPE]): # ) return ToFunctionOperation.create(self, var_type or Callable) - if not issubclass(output, Var) and var_type is None: + # If we can't determine the first argument, we just replace the _var_type. + if not issubclass(output, Var) or var_type is None: return dataclasses.replace( self, _var_type=output, ) - return dataclasses.replace( - self, - _var_type=var_type, - ) + # We couldn't determine the output type to be any other Var type, so we replace the _var_type. + if var_type is not None: + return dataclasses.replace( + self, + _var_type=var_type, + ) + + return self def guess_type(self) -> ImmutableVar: """Guesses the type of the variable based on its `_var_type` attribute. @@ -1005,33 +1010,13 @@ def figure_out_type(value: Any) -> types.GenericType: return type(value) -@dataclasses.dataclass( - eq=False, - frozen=True, - **{"slots": True} if sys.version_info >= (3, 10) else {}, -) -class AndOperation(ImmutableVar): - """Class for the logical AND operation.""" - - # The first var. - _var1: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None)) - - # The second var. - _var2: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None)) +class CachedVarOperation: + """Base class for cached var operations to lower boilerplate code.""" def __post_init__(self): - """Post-initialize the AndOperation.""" + """Post-initialize the CachedVarOperation.""" object.__delattr__(self, "_var_name") - @functools.cached_property - def _cached_var_name(self) -> str: - """Get the cached var name. - - Returns: - The cached var name. - """ - return f"({str(self._var1)} && {str(self._var2)})" - def __getattr__(self, name: str) -> Any: """Get an attribute of the var. @@ -1043,19 +1028,13 @@ class AndOperation(ImmutableVar): """ if name == "_var_name": return self._cached_var_name - return getattr(super(type(self), self), name) - @functools.cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get the cached VarData. + parent_classes = inspect.getmro(self.__class__) - Returns: - The cached VarData. - """ - return ImmutableVarData.merge( - self._var1._get_all_var_data(), - self._var2._get_all_var_data(), - self._var_data, + print(repr(self), parent_classes, name) + + return parent_classes[parent_classes.index(CachedVarOperation) + 1].__getattr__( # type: ignore + self, name ) def _get_all_var_data(self) -> ImmutableVarData | None: @@ -1066,6 +1045,67 @@ class AndOperation(ImmutableVar): """ return self._cached_get_all_var_data + @functools.cached_property + def _cached_get_all_var_data(self) -> ImmutableVarData | None: + """Get the cached VarData. + + Returns: + The cached VarData. + """ + return ImmutableVarData.merge( + *map( + lambda value: ( + value._get_all_var_data() if isinstance(value, Var) else None + ), + map( + lambda field: getattr(self, field.name), + dataclasses.fields(self), # type: ignore + ), + ), + self._var_data, + ) + + def __hash__(self) -> int: + """Calculate the hash of the object. + + Returns: + The hash of the object. + """ + return hash( + ( + self.__class__.__name__, + *[ + getattr(self, field.name) + for field in dataclasses.fields(self) # type: ignore + if field.name not in ["_var_name", "_var_data", "_var_type"] + ], + ) + ) + + +@dataclasses.dataclass( + eq=False, + frozen=True, + **{"slots": True} if sys.version_info >= (3, 10) else {}, +) +class AndOperation(CachedVarOperation, ImmutableVar): + """Class for the logical AND operation.""" + + # The first var. + _var1: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None)) + + # The second var. + _var2: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None)) + + @functools.cached_property + def _cached_var_name(self) -> str: + """Get the cached var name. + + Returns: + The cached var name. + """ + return f"({str(self._var1)} && {str(self._var2)})" + def __hash__(self) -> int: """Calculates the hash value of the object. @@ -1103,7 +1143,7 @@ class AndOperation(ImmutableVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class OrOperation(ImmutableVar): +class OrOperation(CachedVarOperation, ImmutableVar): """Class for the logical OR operation.""" # The first var. @@ -1112,10 +1152,6 @@ class OrOperation(ImmutableVar): # The second var. _var2: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None)) - def __post_init__(self): - """Post-initialize the OrOperation.""" - object.__delattr__(self, "_var_name") - @functools.cached_property def _cached_var_name(self) -> str: """Get the cached var name. @@ -1125,40 +1161,6 @@ class OrOperation(ImmutableVar): """ return f"({str(self._var1)} || {str(self._var2)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute. - """ - if name == "_var_name": - return self._cached_var_name - return getattr(super(type(self), self), name) - - @functools.cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get the cached VarData. - - Returns: - The cached VarData. - """ - return ImmutableVarData.merge( - self._var1._get_all_var_data(), - self._var2._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - def __hash__(self) -> int: """Calculates the hash value for the object. @@ -1378,12 +1380,6 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]): backend=kwargs.pop("backend", self._backend), _var_name=kwargs.pop("_var_name", self._var_name), _var_type=kwargs.pop("_var_type", self._var_type), - _var_is_local=kwargs.pop("_var_is_local", self._var_is_local), - _var_is_string=kwargs.pop("_var_is_string", self._var_is_string), - _var_full_name_needs_state_prefix=kwargs.pop( - "_var_full_name_needs_state_prefix", - self._var_full_name_needs_state_prefix, - ), _var_data=kwargs.pop( "_var_data", VarData.merge(self._var_data, merge_var_data) ), @@ -1676,7 +1672,6 @@ def immutable_computed_var( auto_deps: bool = True, interval: Optional[Union[datetime.timedelta, int]] = None, backend: bool | None = None, - _deprecated_cached_var: bool = False, **kwargs, ) -> Callable[ [Callable[[BASE_STATE], RETURN_TYPE]], ImmutableComputedVar[RETURN_TYPE] @@ -1692,7 +1687,6 @@ def immutable_computed_var( auto_deps: bool = True, interval: Optional[Union[datetime.timedelta, int]] = None, backend: bool | None = None, - _deprecated_cached_var: bool = False, **kwargs, ) -> ImmutableComputedVar[RETURN_TYPE]: ... @@ -1705,7 +1699,6 @@ def immutable_computed_var( auto_deps: bool = True, interval: Optional[Union[datetime.timedelta, int]] = None, backend: bool | None = None, - _deprecated_cached_var: bool = False, **kwargs, ) -> ( ImmutableComputedVar | Callable[[Callable[[BASE_STATE], Any]], ImmutableComputedVar] @@ -1720,7 +1713,6 @@ def immutable_computed_var( auto_deps: Whether var dependencies should be auto-determined. interval: Interval at which the computed var should be updated. backend: Whether the computed var is a backend var. - _deprecated_cached_var: Indicate usage of deprecated cached_var partial function. **kwargs: additional attributes to set on the instance Returns: @@ -1730,14 +1722,6 @@ def immutable_computed_var( ValueError: If caching is disabled and an update interval is set. VarDependencyError: If user supplies dependencies without caching. """ - if _deprecated_cached_var: - console.deprecate( - feature_name="cached_var", - reason=("Use @rx.var(cache=True) instead of @rx.cached_var."), - deprecation_version="0.5.6", - removal_version="0.6.0", - ) - if cache is False and interval is not None: raise ValueError("Cannot set update interval without caching.") @@ -1760,9 +1744,3 @@ def immutable_computed_var( ) return wrapper - - -# Partial function of computed_var with cache=True -cached_var = functools.partial( - immutable_computed_var, cache=True, _deprecated_cached_var=True -) diff --git a/reflex/ivars/function.py b/reflex/ivars/function.py index b16902b7c..e4a486694 100644 --- a/reflex/ivars/function.py +++ b/reflex/ivars/function.py @@ -10,7 +10,7 @@ from typing import Any, Callable, Optional, Tuple, Type, Union from reflex.utils.types import GenericType from reflex.vars import ImmutableVarData, Var, VarData -from .base import ImmutableVar, LiteralVar +from .base import CachedVarOperation, ImmutableVar, LiteralVar class FunctionVar(ImmutableVar[Callable]): @@ -73,25 +73,12 @@ class FunctionStringVar(FunctionVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class VarOperationCall(ImmutableVar): +class VarOperationCall(CachedVarOperation, ImmutableVar): """Base class for immutable vars that are the result of a function call.""" _func: Optional[FunctionVar] = dataclasses.field(default=None) _args: Tuple[Union[Var, Any], ...] = dataclasses.field(default_factory=tuple) - def __getattr__(self, name): - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the var. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -101,39 +88,6 @@ class VarOperationCall(ImmutableVar): """ return f"({str(self._func)}({', '.join([str(LiteralVar.create(arg)) for arg in self._args])}))" - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._func._get_all_var_data() if self._func is not None else None, - *[var._get_all_var_data() for var in self._args], - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - - def __hash__(self): - """Hash the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._func, self._args)) - @classmethod def create( cls, @@ -166,25 +120,12 @@ class VarOperationCall(ImmutableVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArgsFunctionOperation(FunctionVar): +class ArgsFunctionOperation(CachedVarOperation, FunctionVar): """Base class for immutable function defined via arguments and return expression.""" _args_names: Tuple[str, ...] = dataclasses.field(default_factory=tuple) _return_expr: Union[Var, Any] = dataclasses.field(default=None) - def __getattr__(self, name): - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the var. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -194,38 +135,6 @@ class ArgsFunctionOperation(FunctionVar): """ return f"(({', '.join(self._args_names)}) => ({str(LiteralVar.create(self._return_expr))}))" - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._return_expr._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - - def __hash__(self): - """Hash the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._args_names, self._return_expr)) - @classmethod def create( cls, @@ -258,30 +167,13 @@ class ArgsFunctionOperation(FunctionVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ToFunctionOperation(FunctionVar): +class ToFunctionOperation(CachedVarOperation, FunctionVar): """Base class of converting a var to a function.""" _original_var: Var = dataclasses.field( default_factory=lambda: LiteralVar.create(None) ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - - def __getattr__(self, name): - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the var. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -291,34 +183,6 @@ class ToFunctionOperation(FunctionVar): """ return str(self._original_var) - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._original_var._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __hash__(self): - """Hash the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._original_var)) - @classmethod def create( cls, diff --git a/reflex/ivars/number.py b/reflex/ivars/number.py index d8f85c77f..4916e0261 100644 --- a/reflex/ivars/number.py +++ b/reflex/ivars/number.py @@ -11,6 +11,7 @@ from typing import Any, Union from reflex.vars import ImmutableVarData, Var, VarData from .base import ( + CachedVarOperation, ImmutableVar, LiteralVar, unionize, @@ -330,7 +331,7 @@ class NumberVar(ImmutableVar[Union[int, float]]): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class BinaryNumberOperation(NumberVar): +class BinaryNumberOperation(CachedVarOperation, NumberVar): """Base class for immutable number vars that are the result of a binary operation.""" _lhs: NumberVar = dataclasses.field( @@ -340,10 +341,6 @@ class BinaryNumberOperation(NumberVar): default_factory=lambda: LiteralNumberVar.create(0) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -355,49 +352,6 @@ class BinaryNumberOperation(NumberVar): "BinaryNumberOperation must implement _cached_var_name" ) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(BinaryNumberOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - first_value = ( - self._lhs if isinstance(self._lhs, Var) else LiteralNumberVar(self._lhs) - ) - second_value = ( - self._rhs if isinstance(self._rhs, Var) else LiteralNumberVar(self._rhs) - ) - return ImmutableVarData.merge( - first_value._get_all_var_data(), - second_value._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._lhs, self._rhs)) - @classmethod def create( cls, lhs: number_types, rhs: number_types, _var_data: VarData | None = None @@ -430,17 +384,13 @@ class BinaryNumberOperation(NumberVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class UnaryNumberOperation(NumberVar): +class UnaryNumberOperation(CachedVarOperation, NumberVar): """Base class for immutable number vars that are the result of a unary operation.""" _value: NumberVar = dataclasses.field( default_factory=lambda: LiteralNumberVar.create(0) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -452,44 +402,6 @@ class UnaryNumberOperation(NumberVar): "UnaryNumberOperation must implement _cached_var_name" ) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(UnaryNumberOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - value = ( - self._value - if isinstance(self._value, Var) - else LiteralNumberVar(self._value) - ) - return ImmutableVarData.merge(value._get_all_var_data(), self._var_data) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._value)) - @classmethod def create(cls, value: NumberVar, _var_data: VarData | None = None): """Create the unary number operation var. @@ -787,17 +699,13 @@ class BooleanVar(ImmutableVar[bool]): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class BooleanToIntOperation(NumberVar): +class BooleanToIntOperation(CachedVarOperation, NumberVar): """Base class for immutable number vars that are the result of a boolean to int operation.""" _value: BooleanVar = dataclasses.field( default_factory=lambda: LiteralBooleanVar.create(False) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -807,42 +715,6 @@ class BooleanToIntOperation(NumberVar): """ return f"({str(self._value)} ? 1 : 0)" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(BooleanToIntOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._value._get_all_var_data() if isinstance(self._value, Var) else None, - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._value)) - @classmethod def create(cls, value: BooleanVar, _var_data: VarData | None = None): """Create the boolean to int operation var. @@ -867,7 +739,7 @@ class BooleanToIntOperation(NumberVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ComparisonOperation(BooleanVar): +class ComparisonOperation(CachedVarOperation, BooleanVar): """Base class for immutable boolean vars that are the result of a comparison operation.""" _lhs: Var = dataclasses.field( @@ -877,10 +749,6 @@ class ComparisonOperation(BooleanVar): default_factory=lambda: LiteralBooleanVar.create(False) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -890,41 +758,6 @@ class ComparisonOperation(BooleanVar): """ raise NotImplementedError("ComparisonOperation must implement _cached_var_name") - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ComparisonOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._lhs._get_all_var_data(), self._rhs._get_all_var_data() - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._lhs, self._rhs)) - @classmethod def create(cls, lhs: Var | Any, rhs: Var | Any, _var_data: VarData | None = None): """Create the comparison operation var. @@ -1022,7 +855,7 @@ class NotEqualOperation(ComparisonOperation): Returns: The name of the var. """ - return f"({str(self._lhs)} != {str(self._rhs)})" + return f"({str(self._lhs)} !== {str(self._rhs)})" @dataclasses.dataclass( @@ -1030,7 +863,7 @@ class NotEqualOperation(ComparisonOperation): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class LogicalOperation(BooleanVar): +class LogicalOperation(CachedVarOperation, BooleanVar): """Base class for immutable boolean vars that are the result of a logical operation.""" _lhs: BooleanVar = dataclasses.field( @@ -1040,10 +873,6 @@ class LogicalOperation(BooleanVar): default_factory=lambda: LiteralBooleanVar.create(False) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1053,41 +882,6 @@ class LogicalOperation(BooleanVar): """ raise NotImplementedError("LogicalOperation must implement _cached_var_name") - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(LogicalOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._lhs._get_all_var_data(), self._rhs._get_all_var_data() - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._lhs, self._rhs)) - @classmethod def create( cls, lhs: boolean_types, rhs: boolean_types, _var_data: VarData | None = None @@ -1122,17 +916,13 @@ class LogicalOperation(BooleanVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class BooleanNotOperation(BooleanVar): +class BooleanNotOperation(CachedVarOperation, BooleanVar): """Base class for immutable boolean vars that are the result of a logical NOT operation.""" _value: BooleanVar = dataclasses.field( default_factory=lambda: LiteralBooleanVar.create(False) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1142,39 +932,6 @@ class BooleanNotOperation(BooleanVar): """ return f"!({str(self._value)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(BooleanNotOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge(self._value._get_all_var_data()) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._value)) - @classmethod def create(cls, value: boolean_types, _var_data: VarData | None = None): """Create the logical NOT operation var. @@ -1205,14 +962,6 @@ class LiteralBooleanVar(LiteralVar, BooleanVar): _var_value: bool = dataclasses.field(default=False) - def __hash__(self) -> int: - """Hash the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._var_value)) - def json(self) -> str: """Get the JSON representation of the var. @@ -1221,6 +970,14 @@ class LiteralBooleanVar(LiteralVar, BooleanVar): """ return "true" if self._var_value else "false" + def __hash__(self) -> int: + """Calculate the hash value of the object. + + Returns: + int: The hash value of the object. + """ + return hash((self.__class__.__name__, self._var_value)) + @classmethod def create(cls, value: bool, _var_data: VarData | None = None): """Create the boolean var. @@ -1250,14 +1007,6 @@ class LiteralNumberVar(LiteralVar, NumberVar): _var_value: float | int = dataclasses.field(default=0) - def __hash__(self) -> int: - """Hash the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._var_value)) - def json(self) -> str: """Get the JSON representation of the var. @@ -1266,6 +1015,14 @@ class LiteralNumberVar(LiteralVar, NumberVar): """ return json.dumps(self._var_value) + def __hash__(self) -> int: + """Calculate the hash value of the object. + + Returns: + int: The hash value of the object. + """ + return hash((self.__class__.__name__, self._var_value)) + @classmethod def create(cls, value: float | int, _var_data: VarData | None = None): """Create the number var. @@ -1294,17 +1051,13 @@ boolean_types = Union[BooleanVar, bool] frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ToNumberVarOperation(NumberVar): +class ToNumberVarOperation(CachedVarOperation, NumberVar): """Base class for immutable number vars that are the result of a number operation.""" _original_value: Var = dataclasses.field( default_factory=lambda: LiteralNumberVar.create(0) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1314,41 +1067,6 @@ class ToNumberVarOperation(NumberVar): """ return str(self._original_value) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ToNumberVarOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._original_value._get_all_var_data(), self._var_data - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._original_value)) - @classmethod def create( cls, @@ -1379,7 +1097,7 @@ class ToNumberVarOperation(NumberVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ToBooleanVarOperation(BooleanVar): +class ToBooleanVarOperation(CachedVarOperation, BooleanVar): """Base class for immutable boolean vars that are the result of a boolean operation.""" _original_value: Var = dataclasses.field( @@ -1395,45 +1113,6 @@ class ToBooleanVarOperation(BooleanVar): """ return f"Boolean({str(self._original_value)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ToBooleanVarOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._original_value._get_all_var_data(), self._var_data - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._original_value)) - - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @classmethod def create( cls, @@ -1462,7 +1141,7 @@ class ToBooleanVarOperation(BooleanVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class TernaryOperator(ImmutableVar): +class TernaryOperator(CachedVarOperation, ImmutableVar): """Base class for immutable vars that are the result of a ternary operation.""" _condition: BooleanVar = dataclasses.field( @@ -1475,10 +1154,6 @@ class TernaryOperator(ImmutableVar): default_factory=lambda: LiteralNumberVar.create(0) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1490,46 +1165,6 @@ class TernaryOperator(ImmutableVar): f"({str(self._condition)} ? {str(self._if_true)} : {str(self._if_false)})" ) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(TernaryOperator, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._condition._get_all_var_data(), - self._if_true._get_all_var_data(), - self._if_false._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash( - (self.__class__.__name__, self._condition, self._if_true, self._if_false) - ) - @classmethod def create( cls, diff --git a/reflex/ivars/object.py b/reflex/ivars/object.py index da414bebe..3c3d3c77f 100644 --- a/reflex/ivars/object.py +++ b/reflex/ivars/object.py @@ -3,6 +3,7 @@ from __future__ import annotations import dataclasses +import functools import sys import typing from functools import cached_property @@ -28,6 +29,7 @@ from reflex.utils.types import GenericType, get_attribute_access_type from reflex.vars import ImmutableVarData, Var, VarData from .base import ( + CachedVarOperation, ImmutableVar, LiteralVar, figure_out_type, @@ -255,7 +257,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]): attribute_type = get_attribute_access_type(var_type, name) if attribute_type is None: raise VarAttributeError( - f"The State var `{self._var_name}` has no attribute '{name}' or may have been annotated " + f"The State var `{str(self)}` has no attribute '{name}' or may have been annotated " f"wrongly." ) return ObjectItemOperation.create(self, name, attribute_type).guess_type() @@ -279,17 +281,13 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class LiteralObjectVar(LiteralVar, ObjectVar[OBJECT_TYPE]): +class LiteralObjectVar(CachedVarOperation, ObjectVar[OBJECT_TYPE], LiteralVar): """Base class for immutable literal object vars.""" _var_value: Dict[Union[Var, Any], Union[Var, Any]] = dataclasses.field( default_factory=dict ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - def _key_type(self) -> Type: """Get the type of the keys of the object. @@ -308,19 +306,6 @@ class LiteralObjectVar(LiteralVar, ObjectVar[OBJECT_TYPE]): args_list = typing.get_args(self._var_type) return args_list[1] if args_list else Any - def __getattr__(self, name): - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the var. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -339,30 +324,6 @@ class LiteralObjectVar(LiteralVar, ObjectVar[OBJECT_TYPE]): + " })" ) - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - *[ - LiteralVar.create(value)._get_all_var_data() - for value in self._var_value.values() - ], - *[LiteralVar.create(key)._get_all_var_data() for key in self._var_value], - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - def json(self) -> str: """Get the JSON representation of the object. @@ -388,6 +349,22 @@ class LiteralObjectVar(LiteralVar, ObjectVar[OBJECT_TYPE]): """ return hash((self.__class__.__name__, self._var_name)) + @functools.cached_property + def _cached_get_all_var_data(self) -> ImmutableVarData | None: + """Get all the var data. + + Returns: + The var data. + """ + return ImmutableVarData.merge( + *[LiteralVar.create(var)._get_all_var_data() for var in self._var_value], + *[ + LiteralVar.create(var)._get_all_var_data() + for var in self._var_value.values() + ], + self._var_data, + ) + @classmethod def create( cls, @@ -418,17 +395,13 @@ class LiteralObjectVar(LiteralVar, ObjectVar[OBJECT_TYPE]): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ObjectToArrayOperation(ArrayVar): +class ObjectToArrayOperation(CachedVarOperation, ArrayVar): """Base class for object to array operations.""" _value: ObjectVar = dataclasses.field( default_factory=lambda: LiteralObjectVar.create({}) ) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the operation. @@ -440,47 +413,6 @@ class ObjectToArrayOperation(ArrayVar): "ObjectToArrayOperation must implement _cached_var_name" ) - def __getattr__(self, name): - """Get an attribute of the operation. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the operation. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the operation. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._value._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the operation. - - Returns: - The hash of the operation. - """ - return hash((self.__class__.__name__, self._value)) - @classmethod def create( cls, @@ -508,9 +440,6 @@ class ObjectToArrayOperation(ArrayVar): class ObjectKeysOperation(ObjectToArrayOperation): """Operation to get the keys of an object.""" - # value, List[value._key_type()], _var_data - # ) - @cached_property def _cached_var_name(self) -> str: """The name of the operation. @@ -553,7 +482,7 @@ class ObjectValuesOperation(ObjectToArrayOperation): Returns: The name of the operation. """ - return f"Object.values({self._value._var_name})" + return f"Object.values({str(self._value)})" @classmethod def create( @@ -588,7 +517,7 @@ class ObjectEntriesOperation(ObjectToArrayOperation): Returns: The name of the operation. """ - return f"Object.entries({self._value._var_name})" + return f"Object.entries({str(self._value)})" @classmethod def create( @@ -618,7 +547,7 @@ class ObjectEntriesOperation(ObjectToArrayOperation): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ObjectMergeOperation(ObjectVar): +class ObjectMergeOperation(CachedVarOperation, ObjectVar): """Operation to merge two objects.""" _lhs: ObjectVar = dataclasses.field( @@ -635,53 +564,7 @@ class ObjectMergeOperation(ObjectVar): Returns: The name of the operation. """ - return f"Object.assign({self._lhs._var_name}, {self._rhs._var_name})" - - def __getattr__(self, name): - """Get an attribute of the operation. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the operation. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the operation. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._lhs._get_all_var_data(), - self._rhs._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the operation. - - Returns: - The hash of the operation. - """ - return hash((self.__class__.__name__, self._lhs, self._rhs)) - - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") + return f"({{...{str(self._lhs)}, ...{str(self._rhs)}}})" @classmethod def create( @@ -715,7 +598,7 @@ class ObjectMergeOperation(ObjectVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ObjectItemOperation(ImmutableVar): +class ObjectItemOperation(CachedVarOperation, ImmutableVar): """Operation to get an item from an object.""" _object: ObjectVar = dataclasses.field( @@ -734,52 +617,6 @@ class ObjectItemOperation(ImmutableVar): return f"{str(self._object)}?.[{str(self._key)}]" return f"{str(self._object)}[{str(self._key)}]" - def __getattr__(self, name): - """Get an attribute of the operation. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the operation. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the operation. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._object._get_all_var_data(), - self._key._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the operation. - - Returns: - The hash of the operation. - """ - return hash((self.__class__.__name__, self._object, self._key)) - - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @classmethod def create( cls, @@ -813,7 +650,7 @@ class ObjectItemOperation(ImmutableVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ToObjectOperation(ObjectVar): +class ToObjectOperation(CachedVarOperation, ObjectVar): """Operation to convert a var to an object.""" _original_var: Var = dataclasses.field( @@ -829,51 +666,6 @@ class ToObjectOperation(ObjectVar): """ return str(self._original_var) - def __getattr__(self, name): - """Get an attribute of the operation. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the operation. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the operation. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._original_var._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the operation. - - Returns: - The hash of the operation. - """ - return hash((self.__class__.__name__, self._original_var)) - - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @classmethod def create( cls, @@ -904,7 +696,7 @@ class ToObjectOperation(ObjectVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ObjectHasOwnProperty(BooleanVar): +class ObjectHasOwnProperty(CachedVarOperation, BooleanVar): """Operation to check if an object has a property.""" _object: ObjectVar = dataclasses.field( @@ -912,10 +704,6 @@ class ObjectHasOwnProperty(BooleanVar): ) _key: Var | Any = dataclasses.field(default_factory=lambda: LiteralVar.create(None)) - def __post_init__(self): - """Post initialization.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the operation. @@ -925,48 +713,6 @@ class ObjectHasOwnProperty(BooleanVar): """ return f"{str(self._object)}.hasOwnProperty({str(self._key)})" - def __getattr__(self, name): - """Get an attribute of the operation. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the operation. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the operation. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._object._get_all_var_data(), - self._key._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the operation. - - Returns: - The hash of the operation. - """ - return hash((self.__class__.__name__, self._object, self._key)) - @classmethod def create( cls, diff --git a/reflex/ivars/sequence.py b/reflex/ivars/sequence.py index 6cec4681b..a3e033644 100644 --- a/reflex/ivars/sequence.py +++ b/reflex/ivars/sequence.py @@ -32,6 +32,7 @@ from reflex.utils.types import GenericType from reflex.vars import ImmutableVarData, Var, VarData, _global_vars from .base import ( + CachedVarOperation, ImmutableVar, LiteralVar, figure_out_type, @@ -203,17 +204,13 @@ class StringVar(ImmutableVar[str]): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class StringToStringOperation(StringVar): +class StringToStringOperation(CachedVarOperation, StringVar): """Base class for immutable string vars that are the result of a string to string operation.""" _value: StringVar = dataclasses.field( default_factory=lambda: LiteralStringVar.create("") ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -225,42 +222,6 @@ class StringToStringOperation(StringVar): "StringToStringOperation must implement _cached_var_name" ) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(StringToStringOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._value._get_all_var_data() if isinstance(self._value, Var) else None, - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._value)) - @classmethod def create( cls, @@ -328,7 +289,7 @@ class StringStripOperation(StringToStringOperation): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class StringContainsOperation(BooleanVar): +class StringContainsOperation(CachedVarOperation, BooleanVar): """Base class for immutable boolean vars that are the result of a string contains operation.""" _haystack: StringVar = dataclasses.field( @@ -338,10 +299,6 @@ class StringContainsOperation(BooleanVar): default_factory=lambda: LiteralStringVar.create("") ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -351,43 +308,6 @@ class StringContainsOperation(BooleanVar): """ return f"{str(self._haystack)}.includes({str(self._needle)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(StringContainsOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._haystack._get_all_var_data(), - self._needle._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._haystack, self._needle)) - @classmethod def create( cls, @@ -425,7 +345,7 @@ class StringContainsOperation(BooleanVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class StringStartsWithOperation(BooleanVar): +class StringStartsWithOperation(CachedVarOperation, BooleanVar): """Base class for immutable boolean vars that are the result of a string starts with operation.""" _full_string: StringVar = dataclasses.field( @@ -435,10 +355,6 @@ class StringStartsWithOperation(BooleanVar): default_factory=lambda: LiteralStringVar.create("") ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -448,43 +364,6 @@ class StringStartsWithOperation(BooleanVar): """ return f"{str(self._full_string)}.startsWith({str(self._prefix)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(StringStartsWithOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._full_string._get_all_var_data(), - self._prefix._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._full_string, self._prefix)) - @classmethod def create( cls, @@ -522,7 +401,7 @@ class StringStartsWithOperation(BooleanVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class StringItemOperation(StringVar): +class StringItemOperation(CachedVarOperation, StringVar): """Base class for immutable string vars that are the result of a string item operation.""" _string: StringVar = dataclasses.field( @@ -541,47 +420,6 @@ class StringItemOperation(StringVar): """ return f"{str(self._string)}.at({str(self._index)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(StringItemOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._string._get_all_var_data(), - self._index._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._string, self._index)) - - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @classmethod def create( cls, @@ -617,7 +455,7 @@ class StringItemOperation(StringVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArrayJoinOperation(StringVar): +class ArrayJoinOperation(CachedVarOperation, StringVar): """Base class for immutable string vars that are the result of an array join operation.""" _array: ArrayVar = dataclasses.field( @@ -627,10 +465,6 @@ class ArrayJoinOperation(StringVar): default_factory=lambda: LiteralStringVar.create("") ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -640,43 +474,6 @@ class ArrayJoinOperation(StringVar): """ return f"{str(self._array)}.join({str(self._sep)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArrayJoinOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._array._get_all_var_data(), - self._sep._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Calculate the hash value of the object. - - Returns: - int: The hash value of the object. - """ - return hash((self.__class__.__name__, self._array, self._sep)) - @classmethod def create( cls, @@ -835,24 +632,11 @@ class LiteralStringVar(LiteralVar, StringVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ConcatVarOperation(StringVar): +class ConcatVarOperation(CachedVarOperation, StringVar): """Representing a concatenation of literal string vars.""" _var_value: Tuple[Var, ...] = dataclasses.field(default_factory=tuple) - def __getattr__(self, name): - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the var. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -885,10 +669,10 @@ class ConcatVarOperation(StringVar): @cached_property def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. + """Get all the VarData associated with the Var. Returns: - The VarData of the components and all of its children. + The VarData associated with the Var. """ return ImmutableVarData.merge( *[ @@ -899,26 +683,6 @@ class ConcatVarOperation(StringVar): self._var_data, ) - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, *self._var_value)) - @classmethod def create( cls, @@ -1160,16 +924,7 @@ class ArrayVar(ImmutableVar[ARRAY_VAR_TYPE]): """ return ArrayRepeatOperation.create(self, other) - def __rmul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]: - """Multiply the sequence by a number or integer. - - Parameters: - other (NumberVar | int): The number or integer to multiply the sequence by. - - Returns: - ArrayVar[ARRAY_VAR_TYPE]: The result of multiplying the sequence by the given number or integer. - """ - return ArrayRepeatOperation.create(self, other) + __rmul__ = __mul__ # type: ignore LIST_ELEMENT = TypeVar("LIST_ELEMENT") @@ -1186,26 +941,13 @@ ARRAY_VAR_OF_LIST_ELEMENT = Union[ frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class LiteralArrayVar(LiteralVar, ArrayVar[ARRAY_VAR_TYPE]): +class LiteralArrayVar(CachedVarOperation, LiteralVar, ArrayVar[ARRAY_VAR_TYPE]): """Base class for immutable literal array vars.""" _var_value: Union[ List[Union[Var, Any]], Set[Union[Var, Any]], Tuple[Union[Var, Any], ...] ] = dataclasses.field(default_factory=list) - def __getattr__(self, name): - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute of the var. - """ - if name == "_var_name": - return self._cached_var_name - return super(type(self), self).__getattr__(name) - @functools.cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1223,24 +965,19 @@ class LiteralArrayVar(LiteralVar, ArrayVar[ARRAY_VAR_TYPE]): @functools.cached_property def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. + """Get all the VarData associated with the Var. Returns: - The VarData of the components and all of its children. + The VarData associated with the Var. """ return ImmutableVarData.merge( - *[LiteralVar.create(var)._get_all_var_data() for var in self._var_value], + *[ + LiteralVar.create(element)._get_all_var_data() + for element in self._var_value + ], self._var_data, ) - def _get_all_var_data(self) -> ImmutableVarData | None: - """Wrapper method for cached property. - - Returns: - The VarData of the components and all of its children. - """ - return self._cached_get_all_var_data - def __hash__(self) -> int: """Get the hash of the var. @@ -1263,10 +1000,6 @@ class LiteralArrayVar(LiteralVar, ArrayVar[ARRAY_VAR_TYPE]): + "]" ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @classmethod def create( cls, @@ -1296,7 +1029,7 @@ class LiteralArrayVar(LiteralVar, ArrayVar[ARRAY_VAR_TYPE]): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class StringSplitOperation(ArrayVar): +class StringSplitOperation(CachedVarOperation, ArrayVar): """Base class for immutable array vars that are the result of a string split operation.""" _string: StringVar = dataclasses.field( @@ -1306,10 +1039,6 @@ class StringSplitOperation(ArrayVar): default_factory=lambda: LiteralStringVar.create("") ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1319,43 +1048,6 @@ class StringSplitOperation(ArrayVar): """ return f"{str(self._string)}.split({str(self._sep)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(StringSplitOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._string._get_all_var_data(), - self._sep._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._string, self._sep)) - @classmethod def create( cls, @@ -1389,17 +1081,13 @@ class StringSplitOperation(ArrayVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArrayToArrayOperation(ArrayVar): +class ArrayToArrayOperation(CachedVarOperation, ArrayVar): """Base class for immutable array vars that are the result of an array to array operation.""" _value: ArrayVar = dataclasses.field( default_factory=lambda: LiteralArrayVar.create([]) ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1411,35 +1099,6 @@ class ArrayToArrayOperation(ArrayVar): "ArrayToArrayOperation must implement _cached_var_name" ) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArrayToArrayOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._value._get_all_var_data() if isinstance(self._value, Var) else None, - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: """Get the hash of the var. Returns: @@ -1475,7 +1134,7 @@ class ArrayToArrayOperation(ArrayVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArraySliceOperation(ArrayVar): +class ArraySliceOperation(CachedVarOperation, ArrayVar): """Base class for immutable string vars that are the result of a string slice operation.""" _array: ArrayVar = dataclasses.field( @@ -1483,10 +1142,6 @@ class ArraySliceOperation(ArrayVar): ) _slice: slice = dataclasses.field(default_factory=lambda: slice(None, None, None)) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1534,51 +1189,6 @@ class ArraySliceOperation(ArrayVar): return f"{str(self.step)} > 0 ? {str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)}).filter((_, i) => i % {str(step)} === 0) : {str(self._array)}.slice({str(actual_start_reverse)}, {str(actual_end_reverse)}).reverse().filter((_, i) => i % {str(-step)} === 0)" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArraySliceOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._array._get_all_var_data(), - *[ - slice_value._get_all_var_data() - for slice_value in ( - self._slice.start, - self._slice.stop, - self._slice.step, - ) - if slice_value is not None and isinstance(slice_value, Var) - ], - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._array, self._slice)) - @classmethod def create( cls, @@ -1623,17 +1233,13 @@ class ArrayReverseOperation(ArrayToArrayOperation): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArrayToNumberOperation(NumberVar): +class ArrayToNumberOperation(CachedVarOperation, NumberVar): """Base class for immutable number vars that are the result of an array to number operation.""" _array: ArrayVar = dataclasses.field( default_factory=lambda: LiteralArrayVar.create([]), ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1645,39 +1251,6 @@ class ArrayToNumberOperation(NumberVar): "StringToNumberOperation must implement _cached_var_name" ) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArrayToNumberOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge(self._array._get_all_var_data(), self._var_data) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._array)) - @classmethod def create( cls, @@ -1733,7 +1306,7 @@ def is_tuple_type(t: GenericType) -> bool: frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArrayItemOperation(ImmutableVar): +class ArrayItemOperation(CachedVarOperation, ImmutableVar): """Base class for immutable array vars that are the result of an array item operation.""" _array: ArrayVar = dataclasses.field( @@ -1743,10 +1316,6 @@ class ArrayItemOperation(ImmutableVar): default_factory=lambda: LiteralNumberVar.create(0) ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1756,43 +1325,6 @@ class ArrayItemOperation(ImmutableVar): """ return f"{str(self._array)}.at({str(self._index)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArrayItemOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._array._get_all_var_data(), - self._index._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._array, self._index)) - @classmethod def create( cls, @@ -1831,7 +1363,7 @@ class ArrayItemOperation(ImmutableVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class RangeOperation(ArrayVar): +class RangeOperation(CachedVarOperation, ArrayVar): """Base class for immutable array vars that are the result of a range operation.""" _start: NumberVar = dataclasses.field( @@ -1844,10 +1376,6 @@ class RangeOperation(ArrayVar): default_factory=lambda: LiteralNumberVar.create(1) ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1858,44 +1386,6 @@ class RangeOperation(ArrayVar): start, end, step = self._start, self._stop, self._step return f"Array.from({{ length: ({str(end)} - {str(start)}) / {str(step)} }}, (_, i) => {str(start)} + i * {str(step)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(RangeOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._start._get_all_var_data(), - self._stop._get_all_var_data(), - self._step._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._start, self._stop, self._step)) - @classmethod def create( cls, @@ -1930,7 +1420,7 @@ class RangeOperation(ArrayVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArrayContainsOperation(BooleanVar): +class ArrayContainsOperation(CachedVarOperation, BooleanVar): """Base class for immutable boolean vars that are the result of an array contains operation.""" _haystack: ArrayVar = dataclasses.field( @@ -1938,10 +1428,6 @@ class ArrayContainsOperation(BooleanVar): ) _needle: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None)) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -1951,43 +1437,6 @@ class ArrayContainsOperation(BooleanVar): """ return f"{str(self._haystack)}.includes({str(self._needle)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArrayContainsOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._haystack._get_all_var_data(), - self._needle._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._haystack, self._needle)) - @classmethod def create( cls, @@ -2019,17 +1468,13 @@ class ArrayContainsOperation(BooleanVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ToStringOperation(StringVar): +class ToStringOperation(CachedVarOperation, StringVar): """Base class for immutable string vars that are the result of a to string operation.""" _original_var: Var = dataclasses.field( default_factory=lambda: LiteralStringVar.create("") ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -2039,41 +1484,6 @@ class ToStringOperation(StringVar): """ return str(self._original_var) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ToStringOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._original_var._get_all_var_data(), self._var_data - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._original_var)) - @classmethod def create( cls, @@ -2102,17 +1512,13 @@ class ToStringOperation(StringVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ToArrayOperation(ArrayVar): +class ToArrayOperation(CachedVarOperation, ArrayVar): """Base class for immutable array vars that are the result of a to array operation.""" _original_var: Var = dataclasses.field( default_factory=lambda: LiteralArrayVar.create([]) ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -2122,41 +1528,6 @@ class ToArrayOperation(ArrayVar): """ return str(self._original_var) - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ToArrayOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._original_var._get_all_var_data(), self._var_data - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._original_var)) - @classmethod def create( cls, @@ -2186,7 +1557,7 @@ class ToArrayOperation(ArrayVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArrayRepeatOperation(ArrayVar): +class ArrayRepeatOperation(CachedVarOperation, ArrayVar): """Base class for immutable array vars that are the result of an array repeat operation.""" _array: ArrayVar = dataclasses.field( @@ -2196,10 +1567,6 @@ class ArrayRepeatOperation(ArrayVar): default_factory=lambda: LiteralNumberVar.create(0) ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -2209,43 +1576,6 @@ class ArrayRepeatOperation(ArrayVar): """ return f"Array.from({{ length: {str(self._count)} }}).flatMap(() => {str(self._array)})" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArrayRepeatOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._array._get_all_var_data(), - self._count._get_all_var_data(), - self._var_data, - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._array, self._count)) - @classmethod def create( cls, @@ -2277,7 +1607,7 @@ class ArrayRepeatOperation(ArrayVar): frozen=True, **{"slots": True} if sys.version_info >= (3, 10) else {}, ) -class ArrayConcatOperation(ArrayVar): +class ArrayConcatOperation(CachedVarOperation, ArrayVar): """Base class for immutable array vars that are the result of an array concat operation.""" _lhs: ArrayVar = dataclasses.field( @@ -2287,10 +1617,6 @@ class ArrayConcatOperation(ArrayVar): default_factory=lambda: LiteralArrayVar.create([]) ) - def __post_init__(self): - """Post-initialize the var.""" - object.__delattr__(self, "_var_name") - @cached_property def _cached_var_name(self) -> str: """The name of the var. @@ -2300,41 +1626,6 @@ class ArrayConcatOperation(ArrayVar): """ return f"[...{str(self._lhs)}, ...{str(self._rhs)}]" - def __getattr__(self, name: str) -> Any: - """Get an attribute of the var. - - Args: - name: The name of the attribute. - - Returns: - The attribute value. - """ - if name == "_var_name": - return self._cached_var_name - getattr(super(ArrayConcatOperation, self), name) - - @cached_property - def _cached_get_all_var_data(self) -> ImmutableVarData | None: - """Get all VarData associated with the Var. - - Returns: - The VarData of the components and all of its children. - """ - return ImmutableVarData.merge( - self._lhs._get_all_var_data(), self._rhs._get_all_var_data(), self._var_data - ) - - def _get_all_var_data(self) -> ImmutableVarData | None: - return self._cached_get_all_var_data - - def __hash__(self) -> int: - """Get the hash of the var. - - Returns: - The hash of the var. - """ - return hash((self.__class__.__name__, self._lhs, self._rhs)) - @classmethod def create( cls, diff --git a/reflex/vars.py b/reflex/vars.py index 8f3732650..a74654d85 100644 --- a/reflex/vars.py +++ b/reflex/vars.py @@ -905,7 +905,6 @@ class Var: Raises: VarTypeError: If the var is not indexable. """ - print(repr(self)) from reflex.utils import format # Indexing is only supported for strings, lists, tuples, dicts, and dataframes. @@ -1058,7 +1057,6 @@ class Var: return self._replace( _var_name=f"{self._var_name}{'?' if is_optional else ''}.{name}", _var_type=type_, - _var_is_string=False, ) if name in REPLACED_NAMES: diff --git a/tests/components/test_component.py b/tests/components/test_component.py index 3732eeb01..9565e3fd1 100644 --- a/tests/components/test_component.py +++ b/tests/components/test_component.py @@ -1073,7 +1073,7 @@ TEST_VAR = LiteralVar.create("test")._replace( ) ) FORMATTED_TEST_VAR = LiteralVar.create(f"foo{TEST_VAR}bar") -STYLE_VAR = TEST_VAR._replace(_var_name="style", _var_is_local=False) +STYLE_VAR = TEST_VAR._replace(_var_name="style") EVENT_CHAIN_VAR = TEST_VAR._replace(_var_type=EventChain) ARG_VAR = Var.create("arg") @@ -1299,8 +1299,8 @@ def test_get_vars(component, exp_vars): comp_vars, sorted(exp_vars, key=lambda v: v._var_name), ): - print(str(comp_var), str(exp_var)) - print(comp_var._get_all_var_data(), exp_var._get_all_var_data()) + # print(str(comp_var), str(exp_var)) + # print(comp_var._get_all_var_data(), exp_var._get_all_var_data()) assert comp_var.equals(exp_var) diff --git a/tests/test_var.py b/tests/test_var.py index 51a96bc11..cca6cbec4 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -1036,7 +1036,7 @@ def test_object_operations(): assert str(object_var["a"]) == '({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })["a"]' assert ( str(object_var.merge(LiteralObjectVar.create({"c": 4, "d": 5}))) - == 'Object.assign(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 }), ({ ["c"] : 4, ["d"] : 5 }))' + == '({...({ ["a"] : 1, ["b"] : 2, ["c"] : 3 }), ...({ ["c"] : 4, ["d"] : 5 })})' )