Skip to content

Commit

Permalink
Clean up cond vars (#536)
Browse files Browse the repository at this point in the history
  • Loading branch information
picklelo authored Feb 13, 2023
1 parent adf5b7f commit 47eebe0
Show file tree
Hide file tree
Showing 13 changed files with 51 additions and 132 deletions.
2 changes: 1 addition & 1 deletion pynecone/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
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
Expand Down
27 changes: 21 additions & 6 deletions pynecone/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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),
)
1 change: 0 additions & 1 deletion pynecone/components/forms/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ def get_controlled_triggers(cls) -> Dict[str, Var]:
"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,
}

Expand Down
3 changes: 3 additions & 0 deletions pynecone/components/forms/slider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
1 change: 0 additions & 1 deletion pynecone/components/forms/textarea.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,5 @@ def get_controlled_triggers(cls) -> Dict[str, Var]:
"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,
}
59 changes: 2 additions & 57 deletions pynecone/components/tags/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__(self, *args, **kwargs):

@staticmethod
def format_prop(
prop: Union[Var, EventChain, ComponentStyle, PropCond, str],
prop: Union[Var, EventChain, ComponentStyle, str],
) -> Union[int, float, str]:
"""Format a prop.
Expand All @@ -71,10 +71,6 @@ def format_prop(
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, "{"):
Expand All @@ -89,7 +85,7 @@ def format_prop(
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()
}

Expand Down Expand Up @@ -188,54 +184,3 @@ def is_valid_prop(prop: Optional[Var]) -> bool:
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,
)
10 changes: 5 additions & 5 deletions pynecone/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 7 additions & 7 deletions pynecone/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

Expand Down
8 changes: 4 additions & 4 deletions pynecone/var.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ def clear(self):
self._reassign_field()

def setdefault(self, *args, **kwargs):
"""set default.
"""Return value of key if or set default.
Args:
args: The args passed.
Expand All @@ -901,7 +901,7 @@ def pop(self, k, d=None):
self._reassign_field()

def update(self, *args, **kwargs):
"""update dict.
"""Update the dict with another dict.
Args:
args: The args passed.
Expand All @@ -911,7 +911,7 @@ def update(self, *args, **kwargs):
self._reassign_field()

def __setitem__(self, *args, **kwargs):
"""set item.
"""Set an item in the dict.
Args:
args: The args passed.
Expand All @@ -921,7 +921,7 @@ def __setitem__(self, *args, **kwargs):
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.
Expand Down
11 changes: 6 additions & 5 deletions tests/components/layout/test_cond.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from typing import Any

import pytest
Expand All @@ -6,8 +7,8 @@
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
Expand Down Expand Up @@ -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():
Expand Down
9 changes: 0 additions & 9 deletions tests/components/test_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
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

Expand Down Expand Up @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -82,7 +82,7 @@ def add_jimmy_to_second_group(self):

@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.
Expand Down
34 changes: 0 additions & 34 deletions tests/test_propcond.py

This file was deleted.

0 comments on commit 47eebe0

Please sign in to comment.