Bläddra i källkod

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 månader sedan
förälder
incheckning
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.constants import Dirs
 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.utils.imports import ImportDict, ImportVar
 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)
 
     # 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 .object import LiteralObjectVar as LiteralObjectVar
 from .object import ObjectVar as ObjectVar
-from .sequence import ArrayJoinOperation as ArrayJoinOperation
 from .sequence import ArrayVar as ArrayVar
 from .sequence import ConcatVarOperation as ConcatVarOperation
 from .sequence import LiteralArrayVar as LiteralArrayVar

+ 264 - 151
reflex/ivars/base.py

@@ -20,6 +20,7 @@ from typing import (
     Generic,
     List,
     Literal,
+    NoReturn,
     Optional,
     Sequence,
     Set,
@@ -384,10 +385,18 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
             return self.to(BooleanVar, output)
 
         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)
 
         if issubclass(output, BooleanVar):
@@ -440,7 +449,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Raises:
             TypeError: If the type is not supported for guessing.
         """
-        from .number import NumberVar
+        from .number import BooleanVar, NumberVar
         from .object import ObjectVar
         from .sequence import ArrayVar, StringVar
 
@@ -454,11 +463,16 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         fixed_type = get_origin(var_type) or var_type
 
         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
 
         if not inspect.isclass(fixed_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)):
             return self.to(NumberVar, self._var_type)
         if issubclass(fixed_type, dict):
@@ -570,9 +584,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """Check if the current object is not equal to the given object.
@@ -583,9 +597,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """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:
             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:
         """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:
             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:
         """Compare the current instance with another variable using the less than (<) operator.
@@ -622,9 +636,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """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:
             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:
         """Convert the var to a boolean.
@@ -645,9 +659,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """Perform a logical AND operation on the current instance and another variable.
@@ -658,7 +672,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """Perform a logical AND operation on the current instance and another variable.
@@ -669,7 +683,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """Perform a logical OR operation on the current instance and another variable.
@@ -680,7 +694,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """Perform a logical OR operation on the current instance and another variable.
@@ -691,7 +705,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """Perform a logical NOT operation on the current instance.
@@ -699,9 +713,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
         Returns:
             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:
         """Convert the var to a string.
@@ -926,52 +938,92 @@ class LiteralVar(ImmutableVar):
 
 
 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.
 
     Example:
     ```python
-    @var_operation(output=NumberVar)
+    @var_operation
     def add(a: NumberVar, b: NumberVar):
-        return f"({a} + {b})"
+        return custom_var_operation(f"{a} + {b}")
     ```
 
     Args:
-        output: The output type of the operation.
+        func: The function to decorate.
 
     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:
@@ -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(
@@ -1797,3 +1799,114 @@ def immutable_computed_var(
         )
 
     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,
+        )

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 332 - 493
reflex/ivars/number.py


+ 75 - 237
reflex/ivars/object.py

@@ -30,6 +30,8 @@ from .base import (
     LiteralVar,
     cached_property_no_lock,
     figure_out_type,
+    var_operation,
+    var_operation_return,
 )
 from .number import BooleanVar, NumberVar
 from .sequence import ArrayVar, StringVar
@@ -56,7 +58,9 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         return str
 
     @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
     def _value_type(self) -> Type: ...
@@ -79,7 +83,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
             The keys of the object.
         """
-        return ObjectKeysOperation.create(self)
+        return object_keys_operation(self)
 
     @overload
     def values(
@@ -95,7 +99,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
             The values of the object.
         """
-        return ObjectValuesOperation.create(self)
+        return object_values_operation(self)
 
     @overload
     def entries(
@@ -111,9 +115,9 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
             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.
 
         Args:
@@ -122,7 +126,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
             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
     @overload
@@ -270,7 +274,7 @@ class ObjectVar(ImmutableVar[OBJECT_TYPE]):
         Returns:
             The result of the check.
         """
-        return ObjectHasOwnProperty.create(self, key)
+        return object_has_own_property_operation(self, key)
 
 
 @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(
@@ -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,
+    )

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 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)),
-            '(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
-            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(

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

@@ -23,7 +23,7 @@ def cond_state(request):
 def test_f_string_cond_interpolation():
     # make sure backticks inside interpolation don't get escaped
     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(
@@ -97,7 +97,7 @@ def test_prop_cond(c1: Any, c2: Any):
         c1 = json.dumps(c1)
     if not isinstance(c2, Var):
         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():
@@ -141,8 +141,7 @@ def test_cond_computed_var():
 
     state_name = format_state_name(CondStateComputed.get_full_name())
     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]

+ 7 - 6
tests/test_var.py

@@ -12,6 +12,7 @@ from reflex.ivars.base import (
     ImmutableVar,
     LiteralVar,
     var_operation,
+    var_operation_return,
 )
 from reflex.ivars.function import ArgsFunctionOperation, FunctionStringVar
 from reflex.ivars.number import (
@@ -925,9 +926,9 @@ def test_function_var():
 
 
 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(a=4, b=-9)) == "(4 + -9)"
@@ -967,14 +968,14 @@ def test_all_number_operations():
 
     assert (
         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(LiteralBooleanVar.create(False) < 5) == "((false ? 1 : 0) < 5)"
+    assert str(LiteralBooleanVar.create(False) < 5) == "(Number(false) < 5)"
     assert (
         str(LiteralBooleanVar.create(False) < LiteralBooleanVar.create(True))
-        == "((false ? 1 : 0) < (true ? 1 : 0))"
+        == "(Number(false) < Number(true))"
     )
 
 

Vissa filer visades inte eftersom för många filer har ändrats