Clean up cond vars (#536)
This commit is contained in:
parent
adf5b7fb1b
commit
47eebe0ea5
@ -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
|
||||
|
@ -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),
|
||||
)
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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.
|
||||
|
@ -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}"
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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():
|
||||
|
@ -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):
|
||||
|
@ -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.
|
||||
|
@ -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}" "}"
|
||||
)
|
Loading…
Reference in New Issue
Block a user