From b2a27cb8c1457bd153717f13fc700a29f20a5177 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 22 Jan 2025 16:17:08 -0800 Subject: [PATCH] fix list of component is a component --- reflex/components/core/cond.py | 7 ++++++- reflex/utils/types.py | 16 ++++++++++++++++ reflex/vars/sequence.py | 15 ++++++++++++--- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/reflex/components/core/cond.py b/reflex/components/core/cond.py index 7ba5f2fc0..0ab543248 100644 --- a/reflex/components/core/cond.py +++ b/reflex/components/core/cond.py @@ -7,6 +7,7 @@ from typing import Any, overload from reflex.components.base.fragment import Fragment from reflex.components.component import BaseComponent, Component from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode +from reflex.utils import types from reflex.utils.types import safe_issubclass from reflex.vars.base import LiteralVar, ReflexCallable, Var from reflex.vars.function import ArgsFunctionOperation @@ -40,7 +41,11 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var: # If the first component is a component, create a Fragment if the second component is not set. if isinstance(c1, BaseComponent) or ( - isinstance(c1, Var) and safe_issubclass(c1._var_type, BaseComponent) + isinstance(c1, Var) + and ( + safe_issubclass(c1._var_type, BaseComponent) + or types.safe_typehint_issubclass(c1._var_type, list[BaseComponent]) + ) ): c2 = c2 if c2 is not None else Fragment.create() diff --git a/reflex/utils/types.py b/reflex/utils/types.py index 6be54aff5..3f10fa757 100644 --- a/reflex/utils/types.py +++ b/reflex/utils/types.py @@ -976,3 +976,19 @@ def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> boo for provided_arg, accepted_arg in zip(provided_args, accepted_args) if accepted_arg is not Any and not isinstance(accepted_arg, TypeVar) ) + + +def safe_typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> bool: + """Check if a type hint is a subclass of another type hint. + + Args: + possible_subclass: The type hint to check. + possible_superclass: The type hint to check against. + + Returns: + Whether the type hint is a subclass of the other type hint. + """ + try: + return typehint_issubclass(possible_subclass, possible_superclass) + except Exception: + return False diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py index 1f56216a5..d9d097e86 100644 --- a/reflex/vars/sequence.py +++ b/reflex/vars/sequence.py @@ -996,13 +996,22 @@ class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)): if not callable(fn): raise_unsupported_operand_types("foreach", (type(self), type(fn))) + # get the number of arguments of the function - num_args = len(inspect.signature(fn).parameters) - if num_args > 2: + required_num_args = len( + [ + p + for p in inspect.signature(fn).parameters.values() + if p.default != p.empty + ] + ) + if required_num_args > 2: raise VarTypeError( "The function passed to foreach should take at most two arguments." ) + num_args = len(inspect.signature(fn).parameters) + if ( hasattr(fn, "__qualname__") and fn.__qualname__ == ComponentState.create.__qualname__ @@ -1039,7 +1048,7 @@ class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)): ).guess_type(), ) - if num_args == 1: + if required_num_args < 2: fn_result = fn(first_arg) # pyright: ignore [reportCallIssue] return_value = Var.create(fn_result)