Ver Fonte

pc table validation (#1075)

Elijah Ahianyo há 2 anos atrás
pai
commit
368b79f160

+ 28 - 1
pynecone/components/component.py

@@ -64,6 +64,9 @@ class Component(Base, ABC):
     # Whether the component should take the focus once the page is loaded
     autofocus: bool = False
 
+    # components that cannot be children
+    invalid_children: List[str] = []
+
     @classmethod
     def __init_subclass__(cls, **kwargs):
         """Set default properties.
@@ -411,7 +414,8 @@ class Component(Base, ABC):
             The dictionary for template of component.
         """
         tag = self._render()
-        return dict(
+
+        rendered_dict = dict(
             tag.add_props(
                 **self.event_triggers,
                 key=self.key,
@@ -425,6 +429,29 @@ class Component(Base, ABC):
             ),
             autofocus=self.autofocus,
         )
+        self._validate_component_children(
+            rendered_dict["name"], rendered_dict["children"]
+        )
+        return rendered_dict
+
+    def _validate_component_children(self, comp_name: str, children: List[Dict]):
+        """Validate the children components.
+
+        Args:
+            comp_name: name of the component.
+            children: list of children components.
+
+        Raises:
+            ValueError: when an unsupported component is matched.
+        """
+        if not self.invalid_children:
+            return
+        for child in children:
+            name = child["name"]
+            if name in self.invalid_children:
+                raise ValueError(
+                    f"The component `{comp_name.lower()}` cannot have `{name.lower()}` as a child component"
+                )
 
     def _get_custom_code(self) -> Optional[str]:
         """Get custom code for the component.

+ 19 - 0
pynecone/components/datadisplay/table.py

@@ -1,4 +1,5 @@
 """Table components."""
+from typing import List
 
 from pynecone.components.component import Component
 from pynecone.components.layout.foreach import Foreach
@@ -62,6 +63,9 @@ class Thead(ChakraComponent):
 
     tag = "Thead"
 
+    # invalid children components
+    invalid_children: List[str] = ["Tbody", "Thead", "Tfoot"]
+
     @classmethod
     def create(cls, *children, headers=None, **props) -> Component:
         """Create a table header component.
@@ -84,6 +88,9 @@ class Tbody(ChakraComponent):
 
     tag = "Tbody"
 
+    # invalid children components
+    invalid_children: List[str] = ["Tbody", "Thead", "Tfoot", "Td", "Th"]
+
     @classmethod
     def create(cls, *children, rows=None, **props) -> Component:
         """Create a table body component.
@@ -106,6 +113,9 @@ class Tfoot(ChakraComponent):
 
     tag = "Tfoot"
 
+    # invalid children components
+    invalid_children: List[str] = ["Tbody", "Thead", "Td", "Th", "Tfoot"]
+
     @classmethod
     def create(cls, *children, footers=None, **props) -> Component:
         """Create a table footer component.
@@ -128,6 +138,9 @@ class Tr(ChakraComponent):
 
     tag = "Tr"
 
+    # invalid children components
+    invalid_children: List[str] = ["Tbody", "Thead", "Tfoot", "Tr"]
+
     @classmethod
     def create(cls, *children, cell_type: str = "", cells=None, **props) -> Component:
         """Create a table row component.
@@ -156,6 +169,9 @@ class Th(ChakraComponent):
 
     tag = "Th"
 
+    # invalid children components
+    invalid_children: List[str] = ["Tbody", "Thead", "Tr", "Td", "Th"]
+
     # Aligns the cell content to the right.
     is_numeric: Var[bool]
 
@@ -165,6 +181,9 @@ class Td(ChakraComponent):
 
     tag = "Td"
 
+    # invalid children components
+    invalid_children: List[str] = ["Tbody", "Thead"]
+
     # Aligns the cell content to the right.
     is_numeric: Var[bool]
 

+ 31 - 0
tests/components/test_component.py

@@ -112,6 +112,22 @@ def component4() -> Type[Component]:
     return TestComponent4
 
 
+@pytest.fixture
+def component5() -> Type[Component]:
+    """A test component.
+
+    Returns:
+        A test component.
+    """
+
+    class TestComponent5(Component):
+        tag = "Tag"
+
+        invalid_children: List[str] = ["Text"]
+
+    return TestComponent5
+
+
 @pytest.fixture
 def on_click1() -> EventHandler:
     """A sample on click function.
@@ -433,3 +449,18 @@ def test_get_hooks_nested2(component3, component4):
         ).get_hooks()
         == exp_hooks
     )
+
+
+def test_unsupported_child_components(component5):
+    """Test that a value error is raised when an unsupported component is provided as a child.
+
+    Args:
+        component5: the test component
+    """
+    with pytest.raises(ValueError) as err:
+        comp = component5.create(pc.text("testing component"))
+        comp.render()
+    assert (
+        err.value.args[0]
+        == f"The component `tag` cannot have `text` as a child component"
+    )