Allow fstrings as component children (#890)
This commit is contained in:
parent
e03e5f8033
commit
f0346506d7
@ -263,6 +263,7 @@ class App(Base):
|
||||
# Generate the component if it is a callable.
|
||||
try:
|
||||
component = component if isinstance(component, Component) else component()
|
||||
component.set_state(self.state)
|
||||
except TypeError as e:
|
||||
message = str(e)
|
||||
if "BaseVar" in message or "ComputedVar" in message:
|
||||
|
@ -27,4 +27,8 @@ class Bare(Component):
|
||||
return cls(contents=str(contents)) # type: ignore
|
||||
|
||||
def _render(self) -> Tag:
|
||||
return Tagless(contents=str(self.contents))
|
||||
contents = str(self.contents)
|
||||
if self.state is not None:
|
||||
check = f"{{{self.state.get_name()}"
|
||||
contents = str(self.contents).replace(check, f"${check}")
|
||||
return Tagless(contents=contents)
|
||||
|
@ -24,6 +24,9 @@ from pynecone.style import Style
|
||||
from pynecone.utils import format, imports, path_ops, types
|
||||
from pynecone.var import BaseVar, Var
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from pynecone.state import State
|
||||
|
||||
|
||||
class Component(Base, ABC):
|
||||
"""The base class for all Pynecone components."""
|
||||
@ -34,6 +37,9 @@ class Component(Base, ABC):
|
||||
# The style of the component.
|
||||
style: Style = Style()
|
||||
|
||||
# The app state the component is connected to.
|
||||
state: Optional[Type[State]] = None
|
||||
|
||||
# A mapping from event triggers to event chains.
|
||||
event_triggers: Dict[str, Union[EventChain, Var]] = {}
|
||||
|
||||
@ -393,6 +399,19 @@ class Component(Base, ABC):
|
||||
child.add_style(style)
|
||||
return self
|
||||
|
||||
def set_state(self, state: Type[State]):
|
||||
"""Set the state of the component and its children.
|
||||
|
||||
Args:
|
||||
state: The state to set.
|
||||
"""
|
||||
# Set the state of the component.
|
||||
self.state = state
|
||||
|
||||
# Set the state of the children.
|
||||
for child in self.children:
|
||||
child.set_state(state)
|
||||
|
||||
def render(self) -> str:
|
||||
"""Render the component.
|
||||
|
||||
|
0
tests/components/base/__init__.py
Normal file
0
tests/components/base/__init__.py
Normal file
25
tests/components/base/test_bare.py
Normal file
25
tests/components/base/test_bare.py
Normal file
@ -0,0 +1,25 @@
|
||||
import pytest
|
||||
|
||||
from pynecone.components.base.bare import Bare
|
||||
from pynecone.state import DefaultState
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"contents,expected",
|
||||
[
|
||||
("hello", "hello"),
|
||||
("{}", "{}"),
|
||||
("{default_state.name}", "${default_state.name}"),
|
||||
("{state.name}", "{state.name}"),
|
||||
],
|
||||
)
|
||||
def test_fstrings(contents, expected):
|
||||
"""Test that fstrings are rendered correctly.
|
||||
|
||||
Args:
|
||||
contents: The contents of the component.
|
||||
expected: The expected output.
|
||||
"""
|
||||
comp = Bare.create(contents)
|
||||
comp.set_state(DefaultState)
|
||||
assert str(comp) == expected
|
@ -6,7 +6,7 @@ import pynecone as pc
|
||||
from pynecone.components.component import Component, CustomComponent, custom_component
|
||||
from pynecone.components.layout.box import Box
|
||||
from pynecone.event import EVENT_ARG, EVENT_TRIGGERS, EventHandler
|
||||
from pynecone.state import State
|
||||
from pynecone.state import DefaultState, State
|
||||
from pynecone.style import Style
|
||||
from pynecone.utils import imports
|
||||
from pynecone.var import Var
|
||||
@ -434,3 +434,27 @@ def test_get_hooks_nested2(component3, component4):
|
||||
).get_hooks()
|
||||
== exp_hooks
|
||||
)
|
||||
|
||||
|
||||
def test_set_state(component1, component2, component3):
|
||||
"""Test that setting the state of a component works.
|
||||
|
||||
Args:
|
||||
component1: test component.
|
||||
component2: another component.
|
||||
component3: component with hooks defined.
|
||||
"""
|
||||
c2 = component2.create()
|
||||
c3 = component3.create()
|
||||
c1 = component1.create(c2, c3)
|
||||
|
||||
# State should be None by default.
|
||||
assert c1.state is None
|
||||
assert c2.state is None
|
||||
assert c3.state is None
|
||||
|
||||
# Setting the parent state should set the child state.
|
||||
c1.set_state(DefaultState)
|
||||
assert c1.state == DefaultState
|
||||
assert c2.state == DefaultState
|
||||
assert c3.state == DefaultState
|
||||
|
Loading…
Reference in New Issue
Block a user