Call special events from event triggers (#601)

This commit is contained in:
Nikhil Rao 2023-02-24 15:17:03 -08:00 committed by GitHub
parent f76acb2d9c
commit 6c8ce67b8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 32 deletions

View File

@ -159,7 +159,9 @@ class Component(Base, ABC):
def _create_event_chain(
self,
event_trigger: str,
value: Union[Var, EventHandler, List[EventHandler], Callable],
value: Union[
Var, EventHandler, EventSpec, List[Union[EventHandler, EventSpec]], Callable
],
) -> Union[EventChain, Var]:
"""Create an event chain from a variety of input types.
@ -186,7 +188,7 @@ class Component(Base, ABC):
arg = controlled_triggers.get(event_trigger, EVENT_ARG)
# If the input is a single event handler, wrap it in a list.
if isinstance(value, EventHandler):
if isinstance(value, (EventHandler, EventSpec)):
value = [value]
# If the input is a list of event handlers, create an event chain.
@ -205,6 +207,9 @@ class Component(Base, ABC):
# Add the event to the chain.
events.append(event)
elif isinstance(v, EventSpec):
# Add the event to the chain.
events.append(v)
elif isinstance(v, Callable):
# Call the lambda to get the event chain.
events.extend(utils.call_event_fn(v, arg))

View File

@ -123,7 +123,7 @@ EVENT_ARG = BaseVar(name="_e", type_=FrontendEvent, is_local=True)
# Special server-side events.
def redirect(path: str) -> Event:
def redirect(path: str) -> EventSpec:
"""Redirect to a new path.
Args:
@ -132,14 +132,18 @@ def redirect(path: str) -> Event:
Returns:
An event to redirect to the path.
"""
return Event(
token="",
name="_redirect",
payload={"path": path},
def fn():
return None
fn.__qualname__ = "_redirect"
return EventSpec(
handler=EventHandler(fn=fn),
args=(("path", path),),
)
def console_log(message: str) -> Event:
def console_log(message: str) -> EventSpec:
"""Do a console.log on the browser.
Args:
@ -148,14 +152,18 @@ def console_log(message: str) -> Event:
Returns:
An event to log the message.
"""
return Event(
token="",
name="_console",
payload={"message": message},
def fn():
return None
fn.__qualname__ = "_console"
return EventSpec(
handler=EventHandler(fn=fn),
args=(("message", message),),
)
def window_alert(message: str) -> Event:
def window_alert(message: str) -> EventSpec:
"""Create a window alert on the browser.
Args:
@ -164,10 +172,14 @@ def window_alert(message: str) -> Event:
Returns:
An event to alert the message.
"""
return Event(
token="",
name="_alert",
payload={"message": message},
def fn():
return None
fn.__qualname__ = "_alert"
return EventSpec(
handler=EventHandler(fn=fn),
args=(("message", message),),
)

View File

@ -545,9 +545,10 @@ class State(Base, ABC):
except Exception:
error = traceback.format_exc()
print(error)
return StateUpdate(
events=[window_alert("An error occurred. See logs for details.")]
events = utils.fix_events(
[window_alert("An error occurred. See logs for details.")], event.token
)
return StateUpdate(events=events)
# Fix the returned events.
events = utils.fix_events(events, event.token)

View File

@ -1421,7 +1421,9 @@ def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[str, str],
return event_spec.args if len(args) > 2 else ((args[1], arg.name),)
def fix_events(events: Optional[List[Event]], token: str) -> List[Event]:
def fix_events(
events: Optional[List[Union[EventHandler, EventSpec]]], token: str
) -> List[Event]:
"""Fix a list of events returned by an event handler.
Args:
@ -1444,13 +1446,7 @@ def fix_events(events: Optional[List[Event]], token: str) -> List[Event]:
# Fix the events created by the handler.
out = []
for e in events:
# If it is already an event, don't modify it.
if isinstance(e, Event):
name = e.name
payload = e.payload
# Otherwise, create an event from the event spec.
else:
if isinstance(e, EventHandler):
e = e()
assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}."

View File

@ -1,4 +1,5 @@
from pynecone.event import Event, EventHandler
from pynecone import event
from pynecone.event import Event, EventHandler, EventSpec
from pynecone.var import Var
@ -46,3 +47,27 @@ def test_call_event_handler():
assert event_spec.handler == handler
assert event_spec.local_args == ()
assert event_spec.args == (("arg1", "first"), ("arg2", "second"))
def test_event_redirect():
"""Test the event redirect function."""
spec = event.redirect("/path")
assert isinstance(spec, EventSpec)
assert spec.handler.fn.__qualname__ == "_redirect"
assert spec.args == (("path", "/path"),)
def test_event_console_log():
"""Test the event console log function."""
spec = event.console_log("message")
assert isinstance(spec, EventSpec)
assert spec.handler.fn.__qualname__ == "_console"
assert spec.args == (("message", "message"),)
def test_event_window_alert():
"""Test the event window alert function."""
spec = event.window_alert("message")
assert isinstance(spec, EventSpec)
assert spec.handler.fn.__qualname__ == "_alert"
assert spec.args == (("message", "message"),)