Explorar o código

Clean up cond vars (#536)

Nikhil Rao %!s(int64=2) %!d(string=hai) anos
pai
achega
47eebe0ea5

+ 1 - 1
pynecone/__init__.py

@@ -10,7 +10,7 @@ from .components.component import custom_component as component
 from .components.graphing.victory import data
 from .config import Config
 from .constants import Env, Transports
-from .event import EventChain, console_log, redirect, window_alert
+from .event import EVENT_ARG, EventChain, console_log, redirect, window_alert
 from .middleware import Middleware
 from .model import Model, session
 from .route import route

+ 21 - 6
pynecone/components/__init__.py

@@ -106,11 +106,12 @@ def cond(condition: Any, c1: Any, c2: Any = None):
 
     Returns:
         The conditional component.
+
+    Raises:
+        ValueError: If the arguments are invalid.
     """
     # Import here to avoid circular imports.
-    from pynecone.var import Var
-
-    from .tags.tag import PropCond
+    from pynecone.var import BaseVar, Var
 
     # Convert the condition to a Var.
     cond_var = Var.create(condition)
@@ -123,6 +124,20 @@ def cond(condition: Any, c1: Any, c2: Any = None):
         ), "Both arguments must be components."
         return Cond.create(cond_var, c1, c2)
 
-    # Otherwise, create a PropCond.
-    assert not isinstance(c2, Component), "Both arguments must be props."
-    return PropCond.create(cond_var, c1, c2)
+    # Otherwise, create a conditionl Var.
+    # Check that the second argument is valid.
+    if isinstance(c2, Component):
+        raise ValueError("Both arguments must be props.")
+    if c2 is None:
+        raise ValueError("For conditional vars, the second argument must be set.")
+
+    # Create the conditional var.
+    return BaseVar(
+        name=utils.format_cond(
+            cond=cond_var.full_name,
+            true_value=c1,
+            false_value=c2,
+            is_prop=True,
+        ),
+        type_=c1.type_ if isinstance(c1, BaseVar) else type(c1),
+    )

+ 0 - 1
pynecone/components/forms/input.py

@@ -60,7 +60,6 @@ class Input(ChakraComponent):
             "on_focus": EVENT_ARG.target.value,
             "on_blur": EVENT_ARG.target.value,
             "on_key_down": EVENT_ARG.key,
-            "on_key_press": EVENT_ARG.key,
             "on_key_up": EVENT_ARG.key,
         }
 

+ 3 - 0
pynecone/components/forms/slider.py

@@ -16,6 +16,9 @@ class Slider(ChakraComponent):
     # State var to bind the the input.
     value: Var[int]
 
+    # The color scheme.
+    color_scheme: Var[str]
+
     # The placeholder text.
     default_value: Var[int]
 

+ 0 - 1
pynecone/components/forms/textarea.py

@@ -54,6 +54,5 @@ class TextArea(ChakraComponent):
             "on_focus": EVENT_ARG.target.value,
             "on_blur": EVENT_ARG.target.value,
             "on_key_down": EVENT_ARG.key,
-            "on_key_press": EVENT_ARG.key,
             "on_key_up": EVENT_ARG.key,
         }

+ 2 - 57
pynecone/components/tags/tag.py

@@ -47,7 +47,7 @@ class Tag(Base):
 
     @staticmethod
     def format_prop(
-        prop: Union[Var, EventChain, ComponentStyle, PropCond, str],
+        prop: Union[Var, EventChain, ComponentStyle, str],
     ) -> Union[int, float, str]:
         """Format a prop.
 
@@ -71,10 +71,6 @@ class Tag(Base):
             events = ",".join([utils.format_event(event) for event in prop.events])
             prop = f"({local_args}) => Event([{events}])"
 
-        # Handle conditional props.
-        elif isinstance(prop, PropCond):
-            return str(prop)
-
         # Handle other types.
         elif isinstance(prop, str):
             if utils.is_wrapped(prop, "{"):
@@ -89,7 +85,7 @@ class Tag(Base):
             if isinstance(prop, dict):
                 # Convert any var keys to strings.
                 prop = {
-                    key: str(val) if isinstance(val, (Var, PropCond)) else val
+                    key: str(val) if isinstance(val, Var) else val
                     for key, val in prop.items()
                 }
 
@@ -188,54 +184,3 @@ class Tag(Base):
             Whether the prop is valid.
         """
         return prop is not None and not (isinstance(prop, dict) and len(prop) == 0)
-
-
-class PropCond(Base):
-    """A conditional prop."""
-
-    # The condition to determine which prop to render.
-    cond: Var[Any]
-
-    # The prop to render if the condition is true.
-    prop1: Any
-
-    # The prop to render if the condition is false.
-    prop2: Any
-
-    @classmethod
-    def create(cls, cond: Var, prop1: Any, prop2: Any):
-        """Create a conditional Prop.
-
-        Args:
-            cond: The cond to determine which prop to render.
-            prop1: The prop value to render if the cond is true.
-            prop2: The prop value to render if the cond is false.
-
-        Returns:
-            The conditional Prop.
-
-        Raises:
-            ValueError: If the condition or prop values are not set.
-        """
-        if cond is None:
-            raise ValueError("The condition must be set.")
-        if prop1 is None or prop2 is None:
-            raise ValueError("Both prop values must be set.")
-        return cls(
-            cond=cond,
-            prop1=prop1,
-            prop2=prop2,
-        )
-
-    def __str__(self) -> str:
-        """Render the prop as a React string.
-
-        Returns:
-            The React code to render the prop.
-        """
-        return utils.format_cond(
-            cond=self.cond.full_name,
-            true_value=self.prop1,
-            false_value=self.prop2,
-            is_prop=True,
-        )

+ 5 - 5
pynecone/route.py

@@ -24,11 +24,11 @@ def route(
     Note: the decorated functions still need to be imported.
 
     Args:
-        route: The route to reach the page. Defaults to None.
-        title: The title of the page. Defaults to None.
-        image: The favicon of the page. Defaults to None.
-        description: The description of the page. Defaults to None.
-        on_load: The event handler called when the page load. Defaults to None.
+        route: The route to reach the page.
+        title: The title of the page.
+        image: The favicon of the page.
+        description: The description of the page
+        on_load: The event handler called when the page load.
 
     Returns:
         The decorated function.

+ 7 - 7
pynecone/utils.py

@@ -1060,14 +1060,14 @@ def format_cond(
     Returns:
         The formatted conditional expression.
     """
+    # Import here to avoid circular imports.
+    from pynecone.var import Var
+
     if is_prop:
-        if isinstance(true_value, str):
-            true_value = wrap(true_value, "'")
-        if isinstance(false_value, str):
-            false_value = wrap(false_value, "'")
-        expr = f"{cond} ? {true_value} : {false_value}".replace("{", "").replace(
-            "}", ""
-        )
+        prop1 = Var.create(true_value, is_string=type(true_value) == str)
+        prop2 = Var.create(false_value, is_string=type(false_value) == str)
+        assert prop1 is not None and prop2 is not None, "Invalid prop values"
+        expr = f"{cond} ? {prop1} : {prop2}".replace("{", "").replace("}", "")
     else:
         expr = f"{cond} ? {true_value} : {false_value}"
 

+ 4 - 4
pynecone/var.py

@@ -876,7 +876,7 @@ class PCDict(dict):
         self._reassign_field()
 
     def setdefault(self, *args, **kwargs):
-        """set default.
+        """Return value of key if or set default.
 
         Args:
             args: The args passed.
@@ -901,7 +901,7 @@ class PCDict(dict):
         self._reassign_field()
 
     def update(self, *args, **kwargs):
-        """update dict.
+        """Update the dict with another dict.
 
         Args:
             args: The args passed.
@@ -911,7 +911,7 @@ class PCDict(dict):
         self._reassign_field()
 
     def __setitem__(self, *args, **kwargs):
-        """set item.
+        """Set an item in the dict.
 
         Args:
             args: The args passed.
@@ -921,7 +921,7 @@ class PCDict(dict):
         self._reassign_field() if hasattr(self, "_reassign_field") else None
 
     def __delitem__(self, *args, **kwargs):
-        """delete item.
+        """Delete an item in the dict.
 
         Args:
             args: The args passed.

+ 6 - 5
tests/components/layout/test_cond.py

@@ -1,3 +1,4 @@
+import json
 from typing import Any
 
 import pytest
@@ -6,8 +7,8 @@ import pynecone as pc
 from pynecone.components import cond
 from pynecone.components.layout.cond import Cond
 from pynecone.components.layout.fragment import Fragment
-from pynecone.components.tags.tag import PropCond
 from pynecone.components.typography.text import Text
+from pynecone.var import Var
 
 
 @pytest.fixture
@@ -68,10 +69,10 @@ def test_prop_cond(c1: Any, c2: Any):
         c2,
     )
 
-    assert isinstance(prop_cond, PropCond)
-    assert prop_cond.prop1 == c1
-    assert prop_cond.prop2 == c2
-    assert prop_cond.cond == True  # noqa
+    assert isinstance(prop_cond, Var)
+    c1 = json.dumps(c1).replace('"', "`")
+    c2 = json.dumps(c2).replace('"', "`")
+    assert str(prop_cond) == f"{{true ? {c1} : {c2}}}"
 
 
 def test_cond_no_else():

+ 0 - 9
tests/components/test_tag.py

@@ -3,7 +3,6 @@ from typing import Dict
 import pytest
 
 from pynecone.components.tags import CondTag, Tag
-from pynecone.components.tags.tag import PropCond
 from pynecone.event import EventChain, EventHandler, EventSpec
 from pynecone.var import BaseVar, Var
 
@@ -40,14 +39,6 @@ def mock_event(arg):
             ),
             '{(e) => Event([E("mock_event", {arg:e.target.value})])}',
         ),
-        (
-            PropCond.create(
-                cond=BaseVar(name="random_var", type_=str),
-                prop1="true_value",
-                prop2="false_value",
-            ),
-            "{random_var ? 'true_value' : 'false_value'}",
-        ),
     ],
 )
 def test_format_value(prop: Var, formatted: str):

+ 2 - 2
tests/conftest.py

@@ -19,7 +19,7 @@ def windows_platform() -> Generator:
 
 @pytest.fixture
 def list_mutation_state():
-    """A fixture to create a state with list mutation features.
+    """Create a state with list mutation features.
 
     Returns:
         A state with list mutation features.
@@ -82,7 +82,7 @@ def list_mutation_state():
 
 @pytest.fixture
 def dict_mutation_state():
-    """A fixture to create a state with dict mutation features.
+    """Create a state with dict mutation features.
 
     Returns:
         A state with dict mutation features.

+ 0 - 34
tests/test_propcond.py

@@ -1,34 +0,0 @@
-from typing import Any
-
-import pytest
-
-from pynecone.components.tags.tag import PropCond
-from pynecone.utils import wrap
-from pynecone.var import BaseVar
-
-
-@pytest.mark.parametrize(
-    "prop1,prop2",
-    [
-        (1, 3),
-        (1, "text"),
-        ("text1", "text2"),
-    ],
-)
-def test_validate_propcond(prop1: Any, prop2: Any):
-    """Test the creation of conditional props.
-
-    Args:
-        prop1: truth condition value
-        prop2: false condition value
-    """
-    prop_cond = PropCond.create(
-        cond=BaseVar(name="cond_state.value", type_=str), prop1=prop1, prop2=prop2
-    )
-
-    expected_prop1 = wrap(prop1, "'") if isinstance(prop1, str) else prop1
-    expected_prop2 = wrap(prop2, "'") if isinstance(prop2, str) else prop2
-
-    assert str(prop_cond) == (
-        "{cond_state.value ? " f"{expected_prop1} : " f"{expected_prop2}" "}"
-    )