check for dict passed as children for component (#4656)
This commit is contained in:
parent
268effe62e
commit
9c019a65d5
@ -740,22 +740,21 @@ class Component(BaseComponent, ABC):
|
||||
# Import here to avoid circular imports.
|
||||
from reflex.components.base.bare import Bare
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.utils.exceptions import ComponentTypeError
|
||||
from reflex.utils.exceptions import ChildrenTypeError
|
||||
|
||||
# Filter out None props
|
||||
props = {key: value for key, value in props.items() if value is not None}
|
||||
|
||||
def validate_children(children):
|
||||
for child in children:
|
||||
if isinstance(child, tuple):
|
||||
if isinstance(child, (tuple, list)):
|
||||
validate_children(child)
|
||||
|
||||
# Make sure the child is a valid type.
|
||||
if not types._isinstance(child, ComponentChild):
|
||||
raise ComponentTypeError(
|
||||
"Children of Reflex components must be other components, "
|
||||
"state vars, or primitive Python types. "
|
||||
f"Got child {child} of type {type(child)}.",
|
||||
)
|
||||
if isinstance(child, dict) or not types._isinstance(
|
||||
child, ComponentChild
|
||||
):
|
||||
raise ChildrenTypeError(component=cls.__name__, child=child)
|
||||
|
||||
# Validate all the children.
|
||||
validate_children(children)
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Custom Exceptions."""
|
||||
|
||||
from typing import NoReturn
|
||||
from typing import Any, NoReturn
|
||||
|
||||
|
||||
class ReflexError(Exception):
|
||||
@ -31,6 +31,22 @@ class ComponentTypeError(ReflexError, TypeError):
|
||||
"""Custom TypeError for component related errors."""
|
||||
|
||||
|
||||
class ChildrenTypeError(ComponentTypeError):
|
||||
"""Raised when the children prop of a component is not a valid type."""
|
||||
|
||||
def __init__(self, component: str, child: Any):
|
||||
"""Initialize the exception.
|
||||
|
||||
Args:
|
||||
component: The name of the component.
|
||||
child: The child that caused the error.
|
||||
"""
|
||||
super().__init__(
|
||||
f"Component {component} received child {child} of type {type(child)}. "
|
||||
"Accepted types are other components, state vars, or primitive Python types (dict excluded)."
|
||||
)
|
||||
|
||||
|
||||
class EventHandlerTypeError(ReflexError, TypeError):
|
||||
"""Custom TypeError for event handler related errors."""
|
||||
|
||||
|
@ -27,7 +27,7 @@ from reflex.event import (
|
||||
from reflex.state import BaseState
|
||||
from reflex.style import Style
|
||||
from reflex.utils import imports
|
||||
from reflex.utils.exceptions import EventFnArgMismatch
|
||||
from reflex.utils.exceptions import ChildrenTypeError, EventFnArgMismatch
|
||||
from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
@ -645,14 +645,17 @@ def test_create_filters_none_props(test_component):
|
||||
assert str(component.style["text-align"]) == '"center"'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("children", [((None,),), ("foo", ("bar", (None,)))])
|
||||
@pytest.mark.parametrize(
|
||||
"children",
|
||||
[
|
||||
((None,),),
|
||||
("foo", ("bar", (None,))),
|
||||
({"foo": "bar"},),
|
||||
],
|
||||
)
|
||||
def test_component_create_unallowed_types(children, test_component):
|
||||
with pytest.raises(TypeError) as err:
|
||||
with pytest.raises(ChildrenTypeError):
|
||||
test_component.create(*children)
|
||||
assert (
|
||||
err.value.args[0]
|
||||
== "Children of Reflex components must be other components, state vars, or primitive Python types. Got child None of type <class 'NoneType'>."
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
Loading…
Reference in New Issue
Block a user