diff --git a/reflex/utils/types.py b/reflex/utils/types.py index 6503be8be..d968b9a09 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -860,6 +860,10 @@ def infallible_issubclass(cls: Any, class_or_tuple: Any, /) -> bool: Returns: Whether the class is a subclass of the other class or tuple of classes. """ + if cls is class_or_tuple or ( + isinstance(class_or_tuple, tuple) and cls in class_or_tuple + ): + return True try: return issubclass(cls, class_or_tuple) except TypeError: @@ -876,6 +880,8 @@ def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> boo Returns: Whether the type hint is a subclass of the other type hint. """ + if possible_subclass is possible_superclass: + return True if possible_superclass is Any: return True if possible_subclass is Any: @@ -956,7 +962,7 @@ def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> boo return True # Check if the origin of both types is the same (e.g., list for List[int]) - if not safe_issubclass( + if not infallible_issubclass( provided_type_origin or possible_subclass, accepted_type_origin or possible_superclass, ): @@ -968,5 +974,5 @@ def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> boo return all( typehint_issubclass(provided_arg, accepted_arg) for provided_arg, accepted_arg in zip(provided_args, accepted_args) - if accepted_arg is not Any + if accepted_arg is not Any and not isinstance(accepted_arg, TypeVar) ) diff --git a/reflex/vars/base.py b/reflex/vars/base.py index cd42b34d6..ba54b100d 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -3261,37 +3261,14 @@ def and_operation(a: Var | Any, b: Var | Any) -> Var: Returns: The result of the logical AND operation. """ - return _and_operation(a, b) # type: ignore + from .function import ArgsFunctionOperation + a = Var.create(a) + b = Var.create(b) -@var_operation -def _and_operation(a: Var, b: Var): - """Perform a logical AND operation on two variables. - - Args: - a: The first variable. - b: The second variable. - - Returns: - The result of the logical AND operation. - """ - - def type_computer(*args: Var): - if not args: - return (ReflexCallable[[Any, Any], Any], type_computer) - if len(args) == 1: - return ( - ReflexCallable[[Any], Any], - functools.partial(type_computer, args[0]), - ) - return ( - ReflexCallable[[], unionize(args[0]._var_type, args[1]._var_type)], - None, - ) - - return var_operation_return( - js_expression=f"({a} && {b})", - type_computer=type_computer, + return _or_func_operation( + ArgsFunctionOperation.create((), a, _var_type=ReflexCallable[[], a._var_type]), + ArgsFunctionOperation.create((), b, _var_type=ReflexCallable[[], b._var_type]), ) @@ -3305,11 +3282,65 @@ def or_operation(a: Var | Any, b: Var | Any) -> Var: Returns: The result of the logical OR operation. """ - return _or_operation(a, b) # type: ignore + from .function import ArgsFunctionOperation + + a = Var.create(a) + b = Var.create(b) + + return _or_func_operation( + ArgsFunctionOperation.create((), a, _var_type=ReflexCallable[[], a._var_type]), + ArgsFunctionOperation.create((), b, _var_type=ReflexCallable[[], b._var_type]), + ) + + +T_LOGICAL = TypeVar("T_LOGICAL") +U_LOGICAL = TypeVar("U_LOGICAL") @var_operation -def _or_operation(a: Var, b: Var): +def _and_func_operation( + a: Var[ReflexCallable[[], T_LOGICAL]], b: Var[ReflexCallable[[], U_LOGICAL]] +) -> CustomVarOperationReturn[ReflexCallable[[], Union[T_LOGICAL, U_LOGICAL]]]: + """Perform a logical AND operation on two variables. + + Args: + a: The first variable. + b: The second variable. + + Returns: + The result of the logical AND operation. + """ + + def type_computer(*args: Var): + if not args: + return ( + ReflexCallable[[ReflexCallable[[], Any], ReflexCallable[[], Any]], Any], + type_computer, + ) + if len(args) == 1: + return ( + ReflexCallable[[ReflexCallable[[], Any]], Any], + functools.partial(type_computer, args[0]), + ) + + a_return_type = unwrap_reflex_callalbe(args[0]._var_type)[1] + b_return_type = unwrap_reflex_callalbe(args[1]._var_type)[1] + + return ( + ReflexCallable[[], unionize(a_return_type, b_return_type)], + None, + ) + + return var_operation_return( + js_expression=f"({a}() && {b}())", + type_computer=type_computer, + ) + + +@var_operation +def _or_func_operation( + a: Var[ReflexCallable[[], T_LOGICAL]], b: Var[ReflexCallable[[], U_LOGICAL]] +) -> CustomVarOperationReturn[ReflexCallable[[], Union[T_LOGICAL, U_LOGICAL]]]: """Perform a logical OR operation on two variables. Args: @@ -3322,19 +3353,26 @@ def _or_operation(a: Var, b: Var): def type_computer(*args: Var): if not args: - return (ReflexCallable[[Any, Any], Any], type_computer) + return ( + ReflexCallable[[ReflexCallable[[], Any], ReflexCallable[[], Any]], Any], + type_computer, + ) if len(args) == 1: return ( - ReflexCallable[[Any], Any], + ReflexCallable[[ReflexCallable[[], Any]], Any], functools.partial(type_computer, args[0]), ) + + a_return_type = unwrap_reflex_callalbe(args[0]._var_type)[1] + b_return_type = unwrap_reflex_callalbe(args[1]._var_type)[1] + return ( - ReflexCallable[[], unionize(args[0]._var_type, args[1]._var_type)], + ReflexCallable[[], unionize(a_return_type, b_return_type)], None, ) return var_operation_return( - js_expression=f"({a} || {b})", + js_expression=f"({a}() || {b}())", type_computer=type_computer, ) diff --git a/reflex/vars/function.py b/reflex/vars/function.py index b84b69fe0..f529df008 100644 --- a/reflex/vars/function.py +++ b/reflex/vars/function.py @@ -751,6 +751,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar[CALLABLE_TYPE]): Returns: The function var. """ + return_expr = Var.create(return_expr) return cls( _js_expr="", _var_type=_var_type, @@ -829,6 +830,7 @@ class ArgsFunctionOperationBuilder( Returns: The function var. """ + return_expr = Var.create(return_expr) return cls( _js_expr="", _var_type=_var_type,