Kaynağa Gözat

add var_operation and move some operations to the new style (#3841)

* add var_operations and move some operations to the new style

* change bound style

* can't assume int anymore

* slice is not hashable (how did this work bef)

* convert to int explicitly

* move the rest of the operations to new style

* fix bool guess type

* forgot to precommit dangit

* add type ignore to bool for now
Khaleel Al-Adhami 8 ay önce
ebeveyn
işleme
c07a983f05

+ 7 - 6
reflex/components/core/cond.py

@@ -9,7 +9,7 @@ from reflex.components.component import BaseComponent, Component, MemoizationLea
 from reflex.components.tags import CondTag, Tag
 from reflex.components.tags import CondTag, Tag
 from reflex.constants import Dirs
 from reflex.constants import Dirs
 from reflex.ivars.base import ImmutableVar, LiteralVar
 from reflex.ivars.base import ImmutableVar, LiteralVar
-from reflex.ivars.number import TernaryOperator
+from reflex.ivars.number import ternary_operation
 from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode
 from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode
 from reflex.utils.imports import ImportDict, ImportVar
 from reflex.utils.imports import ImportDict, ImportVar
 from reflex.vars import Var, VarData
 from reflex.vars import Var, VarData
@@ -163,11 +163,12 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | ImmutableVar:
     c2 = create_var(c2)
     c2 = create_var(c2)
 
 
     # Create the conditional var.
     # Create the conditional var.
-    return TernaryOperator.create(
-        condition=cond_var.to(bool),  # type: ignore
-        if_true=c1,
-        if_false=c2,
-        _var_data=VarData(imports=_IS_TRUE_IMPORT),
+    return ternary_operation(
+        cond_var.bool()._replace(  # type: ignore
+            merge_var_data=VarData(imports=_IS_TRUE_IMPORT),
+        ),  # type: ignore
+        c1,
+        c2,
     )
     )
 
 
 
 

+ 0 - 1
reflex/ivars/__init__.py

@@ -12,7 +12,6 @@ from .number import LiteralNumberVar as LiteralNumberVar
 from .number import NumberVar as NumberVar
 from .number import NumberVar as NumberVar
 from .object import LiteralObjectVar as LiteralObjectVar
 from .object import LiteralObjectVar as LiteralObjectVar
 from .object import ObjectVar as ObjectVar
 from .object import ObjectVar as ObjectVar
-from .sequence import ArrayJoinOperation as ArrayJoinOperation
 from .sequence import ArrayVar as ArrayVar
 from .sequence import ArrayVar as ArrayVar
 from .sequence import ConcatVarOperation as ConcatVarOperation
 from .sequence import ConcatVarOperation as ConcatVarOperation
 from .sequence import LiteralArrayVar as LiteralArrayVar
 from .sequence import LiteralArrayVar as LiteralArrayVar

+ 264 - 151
reflex/ivars/base.py

@@ -20,6 +20,7 @@ from typing import (
     Generic,
     Generic,
     List,
     List,
     Literal,
     Literal,
+    NoReturn,
     Optional,
     Optional,
     Sequence,
     Sequence,
     Set,
     Set,
@@ -384,10 +385,18 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
             return self.to(BooleanVar, output)
             return self.to(BooleanVar, output)
 
 
         if issubclass(output, NumberVar):
         if issubclass(output, NumberVar):
-            if fixed_type is not None and not issubclass(fixed_type, (int, float)):
-                raise TypeError(
-                    f"Unsupported type {var_type} for NumberVar. Must be int or float."
-                )
+            if fixed_type is not None:
+                if fixed_type is Union:
+                    inner_types = get_args(base_type)
+                    if not all(issubclass(t, (int, float)) for t in inner_types):
+                        raise TypeError(
+                            f"Unsupported type {var_type} for NumberVar. Must be int or float."
+                        )
+
+                elif not issubclass(fixed_type, (int, float)):
+                    raise TypeError(
+                        f"Unsupported type {var_type} for NumberVar. Must be int or float."
+                    )
             return ToNumberVarOperation.create(self, var_type or float)
             return ToNumberVarOperation.create(self, var_type or float)
 
 
         if issubclass(output, BooleanVar):
         if issubclass(output, BooleanVar):
@@ -440,7 +449,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Raises:
         Raises:
             TypeError: If the type is not supported for guessing.
             TypeError: If the type is not supported for guessing.
         """
         """
-        from .number import NumberVar
+        from .number import BooleanVar, NumberVar
         from .object import ObjectVar
         from .object import ObjectVar
         from .sequence import ArrayVar, StringVar
         from .sequence import ArrayVar, StringVar
 
 
@@ -454,11 +463,16 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         fixed_type = get_origin(var_type) or var_type
         fixed_type = get_origin(var_type) or var_type
 
 
         if fixed_type is Union:
         if fixed_type is Union:
+            inner_types = get_args(var_type)
+            if int in inner_types and float in inner_types:
+                return self.to(NumberVar, self._var_type)
             return self
             return self
 
 
         if not inspect.isclass(fixed_type):
         if not inspect.isclass(fixed_type):
             raise TypeError(f"Unsupported type {var_type} for guess_type.")
             raise TypeError(f"Unsupported type {var_type} for guess_type.")
 
 
+        if issubclass(fixed_type, bool):
+            return self.to(BooleanVar, self._var_type)
         if issubclass(fixed_type, (int, float)):
         if issubclass(fixed_type, (int, float)):
             return self.to(NumberVar, self._var_type)
             return self.to(NumberVar, self._var_type)
         if issubclass(fixed_type, dict):
         if issubclass(fixed_type, dict):
@@ -570,9 +584,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             BooleanVar: A BooleanVar object representing the result of the equality check.
             BooleanVar: A BooleanVar object representing the result of the equality check.
         """
         """
-        from .number import EqualOperation
+        from .number import equal_operation
 
 
-        return EqualOperation.create(self, other)
+        return equal_operation(self, other)
 
 
     def __ne__(self, other: Var | Any) -> BooleanVar:
     def __ne__(self, other: Var | Any) -> BooleanVar:
         """Check if the current object is not equal to the given object.
         """Check if the current object is not equal to the given object.
@@ -583,9 +597,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             BooleanVar: A BooleanVar object representing the result of the comparison.
             BooleanVar: A BooleanVar object representing the result of the comparison.
         """
         """
-        from .number import EqualOperation
+        from .number import equal_operation
 
 
-        return ~EqualOperation.create(self, other)
+        return ~equal_operation(self, other)
 
 
     def __gt__(self, other: Var | Any) -> BooleanVar:
     def __gt__(self, other: Var | Any) -> BooleanVar:
         """Compare the current instance with another variable and return a BooleanVar representing the result of the greater than operation.
         """Compare the current instance with another variable and return a BooleanVar representing the result of the greater than operation.
@@ -596,9 +610,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             BooleanVar: A BooleanVar representing the result of the greater than operation.
             BooleanVar: A BooleanVar representing the result of the greater than operation.
         """
         """
-        from .number import GreaterThanOperation
+        from .number import greater_than_operation
 
 
-        return GreaterThanOperation.create(self, other)
+        return greater_than_operation(self, other)
 
 
     def __ge__(self, other: Var | Any) -> BooleanVar:
     def __ge__(self, other: Var | Any) -> BooleanVar:
         """Check if the value of this variable is greater than or equal to the value of another variable or object.
         """Check if the value of this variable is greater than or equal to the value of another variable or object.
@@ -609,9 +623,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             BooleanVar: A BooleanVar object representing the result of the comparison.
             BooleanVar: A BooleanVar object representing the result of the comparison.
         """
         """
-        from .number import GreaterThanOrEqualOperation
+        from .number import greater_than_or_equal_operation
 
 
-        return GreaterThanOrEqualOperation.create(self, other)
+        return greater_than_or_equal_operation(self, other)
 
 
     def __lt__(self, other: Var | Any) -> BooleanVar:
     def __lt__(self, other: Var | Any) -> BooleanVar:
         """Compare the current instance with another variable using the less than (<) operator.
         """Compare the current instance with another variable using the less than (<) operator.
@@ -622,9 +636,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             A `BooleanVar` object representing the result of the comparison.
             A `BooleanVar` object representing the result of the comparison.
         """
         """
-        from .number import LessThanOperation
+        from .number import less_than_operation
 
 
-        return LessThanOperation.create(self, other)
+        return less_than_operation(self, other)
 
 
     def __le__(self, other: Var | Any) -> BooleanVar:
     def __le__(self, other: Var | Any) -> BooleanVar:
         """Compare if the current instance is less than or equal to the given value.
         """Compare if the current instance is less than or equal to the given value.
@@ -635,9 +649,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             A BooleanVar object representing the result of the comparison.
             A BooleanVar object representing the result of the comparison.
         """
         """
-        from .number import LessThanOrEqualOperation
+        from .number import less_than_or_equal_operation
 
 
-        return LessThanOrEqualOperation.create(self, other)
+        return less_than_or_equal_operation(self, other)
 
 
     def bool(self) -> BooleanVar:
     def bool(self) -> BooleanVar:
         """Convert the var to a boolean.
         """Convert the var to a boolean.
@@ -645,9 +659,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             The boolean var.
             The boolean var.
         """
         """
-        from .number import ToBooleanVarOperation
+        from .number import boolify
 
 
-        return ToBooleanVarOperation.create(self)
+        return boolify(self)
 
 
     def __and__(self, other: Var | Any) -> ImmutableVar:
     def __and__(self, other: Var | Any) -> ImmutableVar:
         """Perform a logical AND operation on the current instance and another variable.
         """Perform a logical AND operation on the current instance and another variable.
@@ -658,7 +672,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             A `BooleanVar` object representing the result of the logical AND operation.
             A `BooleanVar` object representing the result of the logical AND operation.
         """
         """
-        return AndOperation.create(self, other)
+        return and_operation(self, other)
 
 
     def __rand__(self, other: Var | Any) -> ImmutableVar:
     def __rand__(self, other: Var | Any) -> ImmutableVar:
         """Perform a logical AND operation on the current instance and another variable.
         """Perform a logical AND operation on the current instance and another variable.
@@ -669,7 +683,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             A `BooleanVar` object representing the result of the logical AND operation.
             A `BooleanVar` object representing the result of the logical AND operation.
         """
         """
-        return AndOperation.create(other, self)
+        return and_operation(other, self)
 
 
     def __or__(self, other: Var | Any) -> ImmutableVar:
     def __or__(self, other: Var | Any) -> ImmutableVar:
         """Perform a logical OR operation on the current instance and another variable.
         """Perform a logical OR operation on the current instance and another variable.
@@ -680,7 +694,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             A `BooleanVar` object representing the result of the logical OR operation.
             A `BooleanVar` object representing the result of the logical OR operation.
         """
         """
-        return OrOperation.create(self, other)
+        return or_operation(self, other)
 
 
     def __ror__(self, other: Var | Any) -> ImmutableVar:
     def __ror__(self, other: Var | Any) -> ImmutableVar:
         """Perform a logical OR operation on the current instance and another variable.
         """Perform a logical OR operation on the current instance and another variable.
@@ -691,7 +705,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             A `BooleanVar` object representing the result of the logical OR operation.
             A `BooleanVar` object representing the result of the logical OR operation.
         """
         """
-        return OrOperation.create(other, self)
+        return or_operation(other, self)
 
 
     def __invert__(self) -> BooleanVar:
     def __invert__(self) -> BooleanVar:
         """Perform a logical NOT operation on the current instance.
         """Perform a logical NOT operation on the current instance.
@@ -699,9 +713,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
         Returns:
             A `BooleanVar` object representing the result of the logical NOT operation.
             A `BooleanVar` object representing the result of the logical NOT operation.
         """
         """
-        from .number import BooleanNotOperation
-
-        return BooleanNotOperation.create(self.bool())
+        return ~self.bool()
 
 
     def to_string(self) -> ImmutableVar:
     def to_string(self) -> ImmutableVar:
         """Convert the var to a string.
         """Convert the var to a string.
@@ -926,52 +938,92 @@ class LiteralVar(ImmutableVar):
 
 
 
 
 P = ParamSpec("P")
 P = ParamSpec("P")
-T = TypeVar("T", bound=ImmutableVar)
+T = TypeVar("T")
+
+
+# NoReturn is used to match CustomVarOperationReturn with no type hint.
+@overload
+def var_operation(
+    func: Callable[P, CustomVarOperationReturn[NoReturn]],
+) -> Callable[P, ImmutableVar]: ...
+
+
+@overload
+def var_operation(
+    func: Callable[P, CustomVarOperationReturn[bool]],
+) -> Callable[P, BooleanVar]: ...
+
+
+NUMBER_T = TypeVar("NUMBER_T", int, float, Union[int, float])
+
+
+@overload
+def var_operation(
+    func: Callable[P, CustomVarOperationReturn[NUMBER_T]],
+) -> Callable[P, NumberVar[NUMBER_T]]: ...
+
+
+@overload
+def var_operation(
+    func: Callable[P, CustomVarOperationReturn[str]],
+) -> Callable[P, StringVar]: ...
+
+
+LIST_T = TypeVar("LIST_T", bound=Union[List[Any], Tuple, Set])
 
 
 
 
-def var_operation(*, output: Type[T]) -> Callable[[Callable[P, str]], Callable[P, T]]:
+@overload
+def var_operation(
+    func: Callable[P, CustomVarOperationReturn[LIST_T]],
+) -> Callable[P, ArrayVar[LIST_T]]: ...
+
+
+OBJECT_TYPE = TypeVar("OBJECT_TYPE", bound=Dict)
+
+
+@overload
+def var_operation(
+    func: Callable[P, CustomVarOperationReturn[OBJECT_TYPE]],
+) -> Callable[P, ObjectVar[OBJECT_TYPE]]: ...
+
+
+def var_operation(
+    func: Callable[P, CustomVarOperationReturn[T]],
+) -> Callable[P, ImmutableVar[T]]:
     """Decorator for creating a var operation.
     """Decorator for creating a var operation.
 
 
     Example:
     Example:
     ```python
     ```python
-    @var_operation(output=NumberVar)
+    @var_operation
     def add(a: NumberVar, b: NumberVar):
     def add(a: NumberVar, b: NumberVar):
-        return f"({a} + {b})"
+        return custom_var_operation(f"{a} + {b}")
     ```
     ```
 
 
     Args:
     Args:
-        output: The output type of the operation.
+        func: The function to decorate.
 
 
     Returns:
     Returns:
-        The decorator.
+        The decorated function.
     """
     """
 
 
-    def decorator(func: Callable[P, str], output=output):
-        @functools.wraps(func)
-        def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
-            args_vars = [
-                LiteralVar.create(arg) if not isinstance(arg, Var) else arg
-                for arg in args
-            ]
-            kwargs_vars = {
-                key: LiteralVar.create(value) if not isinstance(value, Var) else value
-                for key, value in kwargs.items()
-            }
-            return output(
-                _var_name=func(*args_vars, **kwargs_vars),  # type: ignore
-                _var_data=VarData.merge(
-                    *[arg._get_all_var_data() for arg in args if isinstance(arg, Var)],
-                    *[
-                        arg._get_all_var_data()
-                        for arg in kwargs.values()
-                        if isinstance(arg, Var)
-                    ],
-                ),
-            )
-
-        return wrapper
+    @functools.wraps(func)
+    def wrapper(*args: P.args, **kwargs: P.kwargs) -> ImmutableVar[T]:
+        func_args = list(inspect.signature(func).parameters)
+        args_vars = {
+            func_args[i]: (LiteralVar.create(arg) if not isinstance(arg, Var) else arg)
+            for i, arg in enumerate(args)
+        }
+        kwargs_vars = {
+            key: LiteralVar.create(value) if not isinstance(value, Var) else value
+            for key, value in kwargs.items()
+        }
+
+        return CustomVarOperation.create(
+            args=tuple(list(args_vars.items()) + list(kwargs_vars.items())),
+            return_var=func(*args_vars.values(), **kwargs_vars),  # type: ignore
+        ).guess_type()
 
 
-    return decorator
+    return wrapper
 
 
 
 
 def unionize(*args: Type) -> Type:
 def unionize(*args: Type) -> Type:
@@ -1100,114 +1152,64 @@ class CachedVarOperation:
         )
         )
 
 
 
 
-@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))
+def and_operation(a: Var | Any, b: Var | Any) -> ImmutableVar:
+    """Perform a logical AND operation on two variables.
 
 
-    @cached_property_no_lock
-    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.
+    Args:
+        a: The first variable.
+        b: The second variable.
 
 
-        Returns:
-            int: The hash value of the object.
-        """
-        return hash((self.__class__.__name__, self._var1, self._var2))
+    Returns:
+        The result of the logical AND operation.
+    """
+    return _and_operation(a, b)  # type: ignore
 
 
-    @classmethod
-    def create(
-        cls, var1: Var | Any, var2: Var | Any, _var_data: VarData | None = None
-    ) -> AndOperation:
-        """Create an AndOperation.
 
 
-        Args:
-            var1: The first var.
-            var2: The second var.
-            _var_data: Additional hooks and imports associated with the Var.
+@var_operation
+def _and_operation(a: ImmutableVar, b: ImmutableVar):
+    """Perform a logical AND operation on two variables.
 
 
-        Returns:
-            The AndOperation.
-        """
-        var1, var2 = map(LiteralVar.create, (var1, var2))
-        return AndOperation(
-            _var_name="",
-            _var_type=unionize(var1._var_type, var2._var_type),
-            _var_data=ImmutableVarData.merge(_var_data),
-            _var1=var1,
-            _var2=var2,
-        )
+    Args:
+        a: The first variable.
+        b: The second variable.
 
 
+    Returns:
+        The result of the logical AND operation.
+    """
+    return var_operation_return(
+        js_expression=f"({a} && {b})",
+        var_type=unionize(a._var_type, b._var_type),
+    )
 
 
-@dataclasses.dataclass(
-    eq=False,
-    frozen=True,
-    **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class OrOperation(CachedVarOperation, ImmutableVar):
-    """Class for the logical OR operation."""
 
 
-    # The first var.
-    _var1: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
+def or_operation(a: Var | Any, b: Var | Any) -> ImmutableVar:
+    """Perform a logical OR operation on two variables.
 
 
-    # The second var.
-    _var2: Var = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
+    Args:
+        a: The first variable.
+        b: The second variable.
 
 
-    @cached_property_no_lock
-    def _cached_var_name(self) -> str:
-        """Get the cached var name.
+    Returns:
+        The result of the logical OR operation.
+    """
+    return _or_operation(a, b)  # type: ignore
 
 
-        Returns:
-            The cached var name.
-        """
-        return f"({str(self._var1)} || {str(self._var2)})"
 
 
-    def __hash__(self) -> int:
-        """Calculates the hash value for the object.
+@var_operation
+def _or_operation(a: ImmutableVar, b: ImmutableVar):
+    """Perform a logical OR operation on two variables.
 
 
-        Returns:
-            int: The hash value of the object.
-        """
-        return hash((self.__class__.__name__, self._var1, self._var2))
-
-    @classmethod
-    def create(
-        cls, var1: Var | Any, var2: Var | Any, _var_data: VarData | None = None
-    ) -> OrOperation:
-        """Create an OrOperation.
-
-        Args:
-            var1: The first var.
-            var2: The second var.
-            _var_data: Additional hooks and imports associated with the Var.
+    Args:
+        a: The first variable.
+        b: The second variable.
 
 
-        Returns:
-            The OrOperation.
-        """
-        var1, var2 = map(LiteralVar.create, (var1, var2))
-        return OrOperation(
-            _var_name="",
-            _var_type=unionize(var1._var_type, var2._var_type),
-            _var_data=ImmutableVarData.merge(_var_data),
-            _var1=var1,
-            _var2=var2,
-        )
+    Returns:
+        The result of the logical OR operation.
+    """
+    return var_operation_return(
+        js_expression=f"({a} || {b})",
+        var_type=unionize(a._var_type, b._var_type),
+    )
 
 
 
 
 @dataclasses.dataclass(
 @dataclasses.dataclass(
@@ -1797,3 +1799,114 @@ def immutable_computed_var(
         )
         )
 
 
     return wrapper
     return wrapper
+
+
+RETURN = TypeVar("RETURN")
+
+
+class CustomVarOperationReturn(ImmutableVar[RETURN]):
+    """Base class for custom var operations."""
+
+    @classmethod
+    def create(
+        cls,
+        js_expression: str,
+        _var_type: Type[RETURN] | None = None,
+        _var_data: VarData | None = None,
+    ) -> CustomVarOperationReturn[RETURN]:
+        """Create a CustomVarOperation.
+
+        Args:
+            js_expression: The JavaScript expression to evaluate.
+            _var_type: The type of the var.
+            _var_data: Additional hooks and imports associated with the Var.
+
+        Returns:
+            The CustomVarOperation.
+        """
+        return CustomVarOperationReturn(
+            _var_name=js_expression,
+            _var_type=_var_type or Any,
+            _var_data=ImmutableVarData.merge(_var_data),
+        )
+
+
+def var_operation_return(
+    js_expression: str,
+    var_type: Type[RETURN] | None = None,
+) -> CustomVarOperationReturn[RETURN]:
+    """Shortcut for creating a CustomVarOperationReturn.
+
+    Args:
+        js_expression: The JavaScript expression to evaluate.
+        var_type: The type of the var.
+
+    Returns:
+        The CustomVarOperationReturn.
+    """
+    return CustomVarOperationReturn.create(js_expression, var_type)
+
+
+@dataclasses.dataclass(
+    eq=False,
+    frozen=True,
+    **{"slots": True} if sys.version_info >= (3, 10) else {},
+)
+class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
+    """Base class for custom var operations."""
+
+    _args: Tuple[Tuple[str, Var], ...] = dataclasses.field(default_factory=tuple)
+
+    _return: CustomVarOperationReturn[T] = dataclasses.field(
+        default_factory=lambda: CustomVarOperationReturn.create("")
+    )
+
+    @cached_property_no_lock
+    def _cached_var_name(self) -> str:
+        """Get the cached var name.
+
+        Returns:
+            The cached var name.
+        """
+        return str(self._return)
+
+    @cached_property_no_lock
+    def _cached_get_all_var_data(self) -> ImmutableVarData | None:
+        """Get the cached VarData.
+
+        Returns:
+            The cached VarData.
+        """
+        return ImmutableVarData.merge(
+            *map(
+                lambda arg: arg[1]._get_all_var_data(),
+                self._args,
+            ),
+            self._return._get_all_var_data(),
+            self._var_data,
+        )
+
+    @classmethod
+    def create(
+        cls,
+        args: Tuple[Tuple[str, Var], ...],
+        return_var: CustomVarOperationReturn[T],
+        _var_data: VarData | None = None,
+    ) -> CustomVarOperation[T]:
+        """Create a CustomVarOperation.
+
+        Args:
+            args: The arguments to the operation.
+            return_var: The return var.
+            _var_data: Additional hooks and imports associated with the Var.
+
+        Returns:
+            The CustomVarOperation.
+        """
+        return CustomVarOperation(
+            _var_name="",
+            _var_type=return_var._var_type,
+            _var_data=ImmutableVarData.merge(_var_data),
+            _args=args,
+            _return=return_var,
+        )

Dosya farkı çok büyük olduğundan ihmal edildi
+ 332 - 493
reflex/ivars/number.py


+ 75 - 237
reflex/ivars/object.py

@@ -30,6 +30,8 @@ from .base import (
     LiteralVar,
     LiteralVar,
     cached_property_no_lock,
     cached_property_no_lock,
     figure_out_type,
     figure_out_type,
+    var_operation,
+    var_operation_return,
 )
 )
 from .number import BooleanVar, NumberVar
 from .number import BooleanVar, NumberVar
 from .sequence import ArrayVar, StringVar
 from .sequence import ArrayVar, StringVar
@@ -56,7 +58,9 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         return str
         return str
 
 
     @overload
     @overload
-    def _value_type(self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]]) -> VALUE_TYPE: ...
+    def _value_type(
+        self: ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]],
+    ) -> Type[VALUE_TYPE]: ...
 
 
     @overload
     @overload
     def _value_type(self) -> Type: ...
     def _value_type(self) -> Type: ...
@@ -79,7 +83,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
         Returns:
             The keys of the object.
             The keys of the object.
         """
         """
-        return ObjectKeysOperation.create(self)
+        return object_keys_operation(self)
 
 
     @overload
     @overload
     def values(
     def values(
@@ -95,7 +99,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
         Returns:
             The values of the object.
             The values of the object.
         """
         """
-        return ObjectValuesOperation.create(self)
+        return object_values_operation(self)
 
 
     @overload
     @overload
     def entries(
     def entries(
@@ -111,9 +115,9 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
         Returns:
             The entries of the object.
             The entries of the object.
         """
         """
-        return ObjectEntriesOperation.create(self)
+        return object_entries_operation(self)
 
 
-    def merge(self, other: ObjectVar) -> ObjectMergeOperation:
+    def merge(self, other: ObjectVar):
         """Merge two objects.
         """Merge two objects.
 
 
         Args:
         Args:
@@ -122,7 +126,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
         Returns:
             The merged object.
             The merged object.
         """
         """
-        return ObjectMergeOperation.create(self, other)
+        return object_merge_operation(self, other)
 
 
     # NoReturn is used here to catch when key value is Any
     # NoReturn is used here to catch when key value is Any
     @overload
     @overload
@@ -270,7 +274,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
         Returns:
             The result of the check.
             The result of the check.
         """
         """
-        return ObjectHasOwnProperty.create(self, key)
+        return object_has_own_property_operation(self, key)
 
 
 
 
 @dataclasses.dataclass(
 @dataclasses.dataclass(
@@ -387,207 +391,72 @@ class LiteralObjectVar(CachedVarOperation, ObjectVar[OBJECT_TYPE], LiteralVar):
         )
         )
 
 
 
 
-@dataclasses.dataclass(
-    eq=False,
-    frozen=True,
-    **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ObjectToArrayOperation(CachedVarOperation, ArrayVar):
-    """Base class for object to array operations."""
-
-    _value: ObjectVar = dataclasses.field(
-        default_factory=lambda: LiteralObjectVar.create({})
-    )
-
-    @cached_property_no_lock
-    def _cached_var_name(self) -> str:
-        """The name of the operation.
-
-        Raises:
-            NotImplementedError: Must implement _cached_var_name.
-        """
-        raise NotImplementedError(
-            "ObjectToArrayOperation must implement _cached_var_name"
-        )
-
-    @classmethod
-    def create(
-        cls,
-        value: ObjectVar,
-        _var_type: GenericType | None = None,
-        _var_data: VarData | None = None,
-    ) -> ObjectToArrayOperation:
-        """Create the object to array operation.
-
-        Args:
-            value: The value of the operation.
-            _var_data: Additional hooks and imports associated with the operation.
-
-        Returns:
-            The object to array operation.
-        """
-        return cls(
-            _var_name="",
-            _var_type=list if _var_type is None else _var_type,
-            _var_data=ImmutableVarData.merge(_var_data),
-            _value=value,
-        )
-
-
-class ObjectKeysOperation(ObjectToArrayOperation):
-    """Operation to get the keys of an object."""
-
-    @cached_property_no_lock
-    def _cached_var_name(self) -> str:
-        """The name of the operation.
-
-        Returns:
-            The name of the operation.
-        """
-        return f"Object.keys({str(self._value)})"
-
-    @classmethod
-    def create(
-        cls,
-        value: ObjectVar,
-        _var_data: VarData | None = None,
-    ) -> ObjectKeysOperation:
-        """Create the object keys operation.
-
-        Args:
-            value: The value of the operation.
-            _var_data: Additional hooks and imports associated with the operation.
-
-        Returns:
-            The object keys operation.
-        """
-        return cls(
-            _var_name="",
-            _var_type=List[str],
-            _var_data=ImmutableVarData.merge(_var_data),
-            _value=value,
-        )
-
-
-class ObjectValuesOperation(ObjectToArrayOperation):
-    """Operation to get the values of an object."""
-
-    @cached_property_no_lock
-    def _cached_var_name(self) -> str:
-        """The name of the operation.
-
-        Returns:
-            The name of the operation.
-        """
-        return f"Object.values({str(self._value)})"
-
-    @classmethod
-    def create(
-        cls,
-        value: ObjectVar,
-        _var_data: VarData | None = None,
-    ) -> ObjectValuesOperation:
-        """Create the object values operation.
+@var_operation
+def object_keys_operation(value: ObjectVar):
+    """Get the keys of an object.
 
 
-        Args:
-            value: The value of the operation.
-            _var_data: Additional hooks and imports associated with the operation.
-
-        Returns:
-            The object values operation.
-        """
-        return cls(
-            _var_name="",
-            _var_type=List[value._value_type()],
-            _var_data=ImmutableVarData.merge(_var_data),
-            _value=value,
-        )
+    Args:
+        value: The object to get the keys from.
 
 
+    Returns:
+        The keys of the object.
+    """
+    return var_operation_return(
+        js_expression=f"Object.keys({value})",
+        var_type=List[str],
+    )
 
 
-class ObjectEntriesOperation(ObjectToArrayOperation):
-    """Operation to get the entries of an object."""
-
-    @cached_property_no_lock
-    def _cached_var_name(self) -> str:
-        """The name of the operation.
 
 
-        Returns:
-            The name of the operation.
-        """
-        return f"Object.entries({str(self._value)})"
+@var_operation
+def object_values_operation(value: ObjectVar):
+    """Get the values of an object.
 
 
-    @classmethod
-    def create(
-        cls,
-        value: ObjectVar,
-        _var_data: VarData | None = None,
-    ) -> ObjectEntriesOperation:
-        """Create the object entries operation.
+    Args:
+        value: The object to get the values from.
 
 
-        Args:
-            value: The value of the operation.
-            _var_data: Additional hooks and imports associated with the operation.
+    Returns:
+        The values of the object.
+    """
+    return var_operation_return(
+        js_expression=f"Object.values({value})",
+        var_type=List[value._value_type()],
+    )
 
 
-        Returns:
-            The object entries operation.
-        """
-        return cls(
-            _var_name="",
-            _var_type=List[Tuple[str, value._value_type()]],
-            _var_data=ImmutableVarData.merge(_var_data),
-            _value=value,
-        )
 
 
+@var_operation
+def object_entries_operation(value: ObjectVar):
+    """Get the entries of an object.
 
 
-@dataclasses.dataclass(
-    eq=False,
-    frozen=True,
-    **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ObjectMergeOperation(CachedVarOperation, ObjectVar):
-    """Operation to merge two objects."""
+    Args:
+        value: The object to get the entries from.
 
 
-    _lhs: ObjectVar = dataclasses.field(
-        default_factory=lambda: LiteralObjectVar.create({})
-    )
-    _rhs: ObjectVar = dataclasses.field(
-        default_factory=lambda: LiteralObjectVar.create({})
+    Returns:
+        The entries of the object.
+    """
+    return var_operation_return(
+        js_expression=f"Object.entries({value})",
+        var_type=List[Tuple[str, value._value_type()]],
     )
     )
 
 
-    @cached_property_no_lock
-    def _cached_var_name(self) -> str:
-        """The name of the operation.
 
 
-        Returns:
-            The name of the operation.
-        """
-        return f"({{...{str(self._lhs)}, ...{str(self._rhs)}}})"
-
-    @classmethod
-    def create(
-        cls,
-        lhs: ObjectVar,
-        rhs: ObjectVar,
-        _var_data: VarData | None = None,
-    ) -> ObjectMergeOperation:
-        """Create the object merge operation.
+@var_operation
+def object_merge_operation(lhs: ObjectVar, rhs: ObjectVar):
+    """Merge two objects.
 
 
-        Args:
-            lhs: The left object to merge.
-            rhs: The right object to merge.
-            _var_data: Additional hooks and imports associated with the operation.
+    Args:
+        lhs: The first object to merge.
+        rhs: The second object to merge.
 
 
-        Returns:
-            The object merge operation.
-        """
-        # TODO: Figure out how to merge the types
-        return cls(
-            _var_name="",
-            _var_type=lhs._var_type,
-            _var_data=ImmutableVarData.merge(_var_data),
-            _lhs=lhs,
-            _rhs=rhs,
-        )
+    Returns:
+        The merged object.
+    """
+    return var_operation_return(
+        js_expression=f"({{...{lhs}, ...{rhs}}})",
+        var_type=Dict[
+            Union[lhs._key_type(), rhs._key_type()],
+            Union[lhs._value_type(), rhs._value_type()],
+        ],
+    )
 
 
 
 
 @dataclasses.dataclass(
 @dataclasses.dataclass(
@@ -688,49 +557,18 @@ class ToObjectOperation(CachedVarOperation, ObjectVar):
         )
         )
 
 
 
 
-@dataclasses.dataclass(
-    eq=False,
-    frozen=True,
-    **{"slots": True} if sys.version_info >= (3, 10) else {},
-)
-class ObjectHasOwnProperty(CachedVarOperation, BooleanVar):
-    """Operation to check if an object has a property."""
-
-    _object: ObjectVar = dataclasses.field(
-        default_factory=lambda: LiteralObjectVar.create({})
-    )
-    _key: Var | Any = dataclasses.field(default_factory=lambda: LiteralVar.create(None))
-
-    @cached_property_no_lock
-    def _cached_var_name(self) -> str:
-        """The name of the operation.
-
-        Returns:
-            The name of the operation.
-        """
-        return f"{str(self._object)}.hasOwnProperty({str(self._key)})"
-
-    @classmethod
-    def create(
-        cls,
-        object: ObjectVar,
-        key: Var | Any,
-        _var_data: VarData | None = None,
-    ) -> ObjectHasOwnProperty:
-        """Create the object has own property operation.
+@var_operation
+def object_has_own_property_operation(object: ObjectVar, key: Var):
+    """Check if an object has a key.
 
 
-        Args:
-            object: The object to check.
-            key: The key to check.
-            _var_data: Additional hooks and imports associated with the operation.
+    Args:
+        object: The object to check.
+        key: The key to check.
 
 
-        Returns:
-            The object has own property operation.
-        """
-        return cls(
-            _var_name="",
-            _var_type=bool,
-            _var_data=ImmutableVarData.merge(_var_data),
-            _object=object,
-            _key=key if isinstance(key, Var) else LiteralVar.create(key),
-        )
+    Returns:
+        The result of the check.
+    """
+    return var_operation_return(
+        js_expression=f"{object}.hasOwnProperty({key})",
+        var_type=bool,
+    )

Dosya farkı çok büyük olduğundan ihmal edildi
+ 198 - 632
reflex/ivars/sequence.py


+ 2 - 2
tests/components/core/test_colors.py

@@ -67,11 +67,11 @@ def test_color(color, expected):
     [
     [
         (
         (
             rx.cond(True, rx.color("mint"), rx.color("tomato", 5)),
             rx.cond(True, rx.color("mint"), rx.color("tomato", 5)),
-            '(Boolean(true) ? "var(--mint-7)" : "var(--tomato-5)")',
+            '(true ? "var(--mint-7)" : "var(--tomato-5)")',
         ),
         ),
         (
         (
             rx.cond(True, rx.color(ColorState.color), rx.color(ColorState.color, 5)),  # type: ignore
             rx.cond(True, rx.color(ColorState.color), rx.color(ColorState.color, 5)),  # type: ignore
-            f'(Boolean(true) ? ("var(--"+{str(color_state_name)}.color+"-7)") : ("var(--"+{str(color_state_name)}.color+"-5)"))',
+            f'(true ? ("var(--"+{str(color_state_name)}.color+"-7)") : ("var(--"+{str(color_state_name)}.color+"-5)"))',
         ),
         ),
         (
         (
             rx.match(
             rx.match(

+ 3 - 4
tests/components/core/test_cond.py

@@ -23,7 +23,7 @@ def cond_state(request):
 def test_f_string_cond_interpolation():
 def test_f_string_cond_interpolation():
     # make sure backticks inside interpolation don't get escaped
     # make sure backticks inside interpolation don't get escaped
     var = LiteralVar.create(f"x {cond(True, 'a', 'b')}")
     var = LiteralVar.create(f"x {cond(True, 'a', 'b')}")
-    assert str(var) == '("x "+(Boolean(true) ? "a" : "b"))'
+    assert str(var) == '("x "+(true ? "a" : "b"))'
 
 
 
 
 @pytest.mark.parametrize(
 @pytest.mark.parametrize(
@@ -97,7 +97,7 @@ def test_prop_cond(c1: Any, c2: Any):
         c1 = json.dumps(c1)
         c1 = json.dumps(c1)
     if not isinstance(c2, Var):
     if not isinstance(c2, Var):
         c2 = json.dumps(c2)
         c2 = json.dumps(c2)
-    assert str(prop_cond) == f"(Boolean(true) ? {c1} : {c2})"
+    assert str(prop_cond) == f"(true ? {c1} : {c2})"
 
 
 
 
 def test_cond_no_mix():
 def test_cond_no_mix():
@@ -141,8 +141,7 @@ def test_cond_computed_var():
 
 
     state_name = format_state_name(CondStateComputed.get_full_name())
     state_name = format_state_name(CondStateComputed.get_full_name())
     assert (
     assert (
-        str(comp)
-        == f"(Boolean(true) ? {state_name}.computed_int : {state_name}.computed_str)"
+        str(comp) == f"(true ? {state_name}.computed_int : {state_name}.computed_str)"
     )
     )
 
 
     assert comp._var_type == Union[int, str]
     assert comp._var_type == Union[int, str]

+ 7 - 6
tests/test_var.py

@@ -12,6 +12,7 @@ from reflex.ivars.base import (
     ImmutableVar,
     ImmutableVar,
     LiteralVar,
     LiteralVar,
     var_operation,
     var_operation,
+    var_operation_return,
 )
 )
 from reflex.ivars.function import ArgsFunctionOperation, FunctionStringVar
 from reflex.ivars.function import ArgsFunctionOperation, FunctionStringVar
 from reflex.ivars.number import (
 from reflex.ivars.number import (
@@ -925,9 +926,9 @@ def test_function_var():
 
 
 
 
 def test_var_operation():
 def test_var_operation():
-    @var_operation(output=NumberVar)
-    def add(a: Union[NumberVar, int], b: Union[NumberVar, int]) -> str:
-        return f"({a} + {b})"
+    @var_operation
+    def add(a: Union[NumberVar, int], b: Union[NumberVar, int]):
+        return var_operation_return(js_expression=f"({a} + {b})", var_type=int)
 
 
     assert str(add(1, 2)) == "(1 + 2)"
     assert str(add(1, 2)) == "(1 + 2)"
     assert str(add(a=4, b=-9)) == "(4 + -9)"
     assert str(add(a=4, b=-9)) == "(4 + -9)"
@@ -967,14 +968,14 @@ def test_all_number_operations():
 
 
     assert (
     assert (
         str(even_more_complicated_number)
         str(even_more_complicated_number)
-        == "!(Boolean((Math.abs(Math.floor(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2))) || (2 && Math.round(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2))))))"
+        == "!(((Math.abs(Math.floor(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2))) || (2 && Math.round(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2)))) !== 0))"
     )
     )
 
 
     assert str(LiteralNumberVar.create(5) > False) == "(5 > 0)"
     assert str(LiteralNumberVar.create(5) > False) == "(5 > 0)"
-    assert str(LiteralBooleanVar.create(False) < 5) == "((false ? 1 : 0) < 5)"
+    assert str(LiteralBooleanVar.create(False) < 5) == "(Number(false) < 5)"
     assert (
     assert (
         str(LiteralBooleanVar.create(False) < LiteralBooleanVar.create(True))
         str(LiteralBooleanVar.create(False) < LiteralBooleanVar.create(True))
-        == "((false ? 1 : 0) < (true ? 1 : 0))"
+        == "(Number(false) < Number(true))"
     )
     )
 
 
 
 

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor