Skip to content

Commit 9c019a6

Browse files
authored
check for dict passed as children for component (#4656)
1 parent 268effe commit 9c019a6

File tree

3 files changed

+34
-16
lines changed

3 files changed

+34
-16
lines changed

reflex/components/component.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -740,22 +740,21 @@ def create(cls, *children, **props) -> Component:
740740
# Import here to avoid circular imports.
741741
from reflex.components.base.bare import Bare
742742
from reflex.components.base.fragment import Fragment
743-
from reflex.utils.exceptions import ComponentTypeError
743+
from reflex.utils.exceptions import ChildrenTypeError
744744

745745
# Filter out None props
746746
props = {key: value for key, value in props.items() if value is not None}
747747

748748
def validate_children(children):
749749
for child in children:
750-
if isinstance(child, tuple):
750+
if isinstance(child, (tuple, list)):
751751
validate_children(child)
752+
752753
# Make sure the child is a valid type.
753-
if not types._isinstance(child, ComponentChild):
754-
raise ComponentTypeError(
755-
"Children of Reflex components must be other components, "
756-
"state vars, or primitive Python types. "
757-
f"Got child {child} of type {type(child)}.",
758-
)
754+
if isinstance(child, dict) or not types._isinstance(
755+
child, ComponentChild
756+
):
757+
raise ChildrenTypeError(component=cls.__name__, child=child)
759758

760759
# Validate all the children.
761760
validate_children(children)

reflex/utils/exceptions.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Custom Exceptions."""
22

3-
from typing import NoReturn
3+
from typing import Any, NoReturn
44

55

66
class ReflexError(Exception):
@@ -31,6 +31,22 @@ class ComponentTypeError(ReflexError, TypeError):
3131
"""Custom TypeError for component related errors."""
3232

3333

34+
class ChildrenTypeError(ComponentTypeError):
35+
"""Raised when the children prop of a component is not a valid type."""
36+
37+
def __init__(self, component: str, child: Any):
38+
"""Initialize the exception.
39+
40+
Args:
41+
component: The name of the component.
42+
child: The child that caused the error.
43+
"""
44+
super().__init__(
45+
f"Component {component} received child {child} of type {type(child)}. "
46+
"Accepted types are other components, state vars, or primitive Python types (dict excluded)."
47+
)
48+
49+
3450
class EventHandlerTypeError(ReflexError, TypeError):
3551
"""Custom TypeError for event handler related errors."""
3652

tests/units/components/test_component.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from reflex.state import BaseState
2828
from reflex.style import Style
2929
from reflex.utils import imports
30-
from reflex.utils.exceptions import EventFnArgMismatch
30+
from reflex.utils.exceptions import ChildrenTypeError, EventFnArgMismatch
3131
from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports
3232
from reflex.vars import VarData
3333
from reflex.vars.base import LiteralVar, Var
@@ -645,14 +645,17 @@ def test_create_filters_none_props(test_component):
645645
assert str(component.style["text-align"]) == '"center"'
646646

647647

648-
@pytest.mark.parametrize("children", [((None,),), ("foo", ("bar", (None,)))])
648+
@pytest.mark.parametrize(
649+
"children",
650+
[
651+
((None,),),
652+
("foo", ("bar", (None,))),
653+
({"foo": "bar"},),
654+
],
655+
)
649656
def test_component_create_unallowed_types(children, test_component):
650-
with pytest.raises(TypeError) as err:
657+
with pytest.raises(ChildrenTypeError):
651658
test_component.create(*children)
652-
assert (
653-
err.value.args[0]
654-
== "Children of Reflex components must be other components, state vars, or primitive Python types. Got child None of type <class 'NoneType'>."
655-
)
656659

657660

658661
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)