Make argument optional for event handlers (#950)
This commit is contained in:
parent
b4e534cc97
commit
893c0b132e
@ -220,7 +220,9 @@ class Component(Base, ABC):
|
||||
event = call_event_handler(v, arg)
|
||||
|
||||
# Check that the event handler takes no args if it's uncontrolled.
|
||||
if not is_controlled_event and len(event.args) > 0:
|
||||
if not is_controlled_event and (
|
||||
event.args is not None and len(event.args) > 0
|
||||
):
|
||||
raise ValueError(
|
||||
f"Event handler: {v.fn} for uncontrolled event {event_trigger} should not take any args."
|
||||
)
|
||||
|
@ -90,7 +90,7 @@ class EventSpec(Base):
|
||||
local_args: Tuple[Var, ...] = ()
|
||||
|
||||
# The arguments to pass to the function.
|
||||
args: Tuple[Tuple[Var, Var], ...] = ()
|
||||
args: Optional[Tuple[Tuple[Var, Var], ...]] = ()
|
||||
|
||||
# Whether to upload files.
|
||||
upload: bool = False
|
||||
@ -318,7 +318,9 @@ def call_event_fn(fn: Callable, arg: Var) -> List[EventSpec]:
|
||||
return events
|
||||
|
||||
|
||||
def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[Var, Var], ...]:
|
||||
def get_handler_args(
|
||||
event_spec: EventSpec, arg: Var
|
||||
) -> Optional[Tuple[Tuple[Var, Var], ...]]:
|
||||
"""Get the handler args for the given event spec.
|
||||
|
||||
Args:
|
||||
@ -327,16 +329,14 @@ def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[Var, Var],
|
||||
|
||||
Returns:
|
||||
The handler args.
|
||||
|
||||
Raises:
|
||||
ValueError: If the event handler has an invalid signature.
|
||||
"""
|
||||
args = inspect.getfullargspec(event_spec.handler.fn).args
|
||||
if len(args) < 2:
|
||||
raise ValueError(
|
||||
f"Event handler has an invalid signature, needed a method with a parameter, got {event_spec.handler}."
|
||||
)
|
||||
return event_spec.args if len(args) > 2 else ((Var.create_safe(args[1]), arg),)
|
||||
|
||||
return (
|
||||
event_spec.args
|
||||
if len(args) > 2
|
||||
else (((Var.create_safe(args[1]), arg),) if len(args) == 2 else None)
|
||||
)
|
||||
|
||||
|
||||
def fix_events(
|
||||
@ -369,7 +369,7 @@ def fix_events(
|
||||
e = e()
|
||||
assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}."
|
||||
name = format.format_event_handler(e.handler)
|
||||
payload = {k.name: v.name for k, v in e.args}
|
||||
payload = {k.name: v.name for k, v in e.args} if e.args else {}
|
||||
|
||||
# Create an event and append it to the list.
|
||||
out.append(
|
||||
|
@ -286,11 +286,17 @@ def format_event(event_spec: EventSpec) -> str:
|
||||
Returns:
|
||||
The compiled event.
|
||||
"""
|
||||
args = ",".join(
|
||||
[
|
||||
":".join((name.name, json.dumps(val.name) if val.is_string else val.name))
|
||||
for name, val in event_spec.args
|
||||
]
|
||||
args = (
|
||||
",".join(
|
||||
[
|
||||
":".join(
|
||||
(name.name, json.dumps(val.name) if val.is_string else val.name)
|
||||
)
|
||||
for name, val in event_spec.args
|
||||
]
|
||||
)
|
||||
if event_spec.args is not None
|
||||
else ""
|
||||
)
|
||||
return f"E(\"{format_event_handler(event_spec.handler)}\", {wrap(args, '{')})"
|
||||
|
||||
@ -323,7 +329,7 @@ def format_full_control_event(event_chain: EventChain) -> str:
|
||||
from pynecone.compiler import templates
|
||||
|
||||
event_spec = event_chain.events[0]
|
||||
arg = event_spec.args[0][1]
|
||||
arg = event_spec.args[0][1] if event_spec.args else None
|
||||
state_name = event_chain.state_name
|
||||
chain = ",".join([format_event(event) for event in event_chain.events])
|
||||
event = templates.FULL_CONTROL(state_name=state_name, arg=arg, chain=chain)
|
||||
|
@ -391,13 +391,10 @@ def test_invalid_event_handler_args(component2, test_state):
|
||||
# Controlled event handlers should take args.
|
||||
# This is okay.
|
||||
component2.create(on_open=test_state.do_something_arg)
|
||||
# This is not okay.
|
||||
with pytest.raises(ValueError):
|
||||
component2.create(on_open=test_state.do_something)
|
||||
with pytest.raises(ValueError):
|
||||
component2.create(
|
||||
on_open=[test_state.do_something_arg, test_state.do_something]
|
||||
)
|
||||
|
||||
# do_something is allowed and will simply run while ignoring the arg
|
||||
component2.create(on_open=test_state.do_something)
|
||||
component2.create(on_open=[test_state.do_something_arg, test_state.do_something])
|
||||
|
||||
|
||||
def test_get_hooks_nested(component1, component2, component3):
|
||||
|
Loading…
Reference in New Issue
Block a user