type check for event handler if spec arg are typed

This commit is contained in:
Lendemor 2024-10-03 16:37:10 +02:00
parent c08720ed1a
commit 0be141fd30
3 changed files with 35 additions and 7 deletions

View File

@ -13,6 +13,10 @@ from ..base import (
) )
def _on_change_spec(value: List[Union[float, int]]):
return [value]
class Slider(RadixThemesComponent): class Slider(RadixThemesComponent):
"""Provides user selection from a range of values.""" """Provides user selection from a range of values."""
@ -64,7 +68,7 @@ class Slider(RadixThemesComponent):
_rename_props = {"onChange": "onValueChange"} _rename_props = {"onChange": "onValueChange"}
# Fired when the value of the slider changes. # Fired when the value of the slider changes.
on_change: EventHandler[lambda e0: [e0]] on_change: EventHandler[_on_change_spec]
# Fired when a thumb is released after being dragged. # Fired when a thumb is released after being dragged.
on_value_commit: EventHandler[lambda e0: [e0]] on_value_commit: EventHandler[lambda e0: [e0]]

View File

@ -22,7 +22,11 @@ from typing_extensions import get_args, get_origin
from reflex import constants from reflex import constants
from reflex.utils import format from reflex.utils import format
from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch from reflex.utils.exceptions import (
EventFnArgMismatch,
EventHandlerArgMismatch,
EventHandlerArgTypeMismatch,
)
from reflex.utils.types import ArgsSpec, GenericType from reflex.utils.types import ArgsSpec, GenericType
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import LiteralVar, Var from reflex.vars.base import LiteralVar, Var
@ -888,6 +892,7 @@ def call_event_handler(
Raises: Raises:
EventHandlerArgMismatch: if number of arguments expected by event_handler doesn't match the spec. EventHandlerArgMismatch: if number of arguments expected by event_handler doesn't match the spec.
EventHandlerArgTypeMismatch: if the annotations of args accepted by event_handler differs from the spec of the event trigger.
Returns: Returns:
The event spec from calling the event handler. The event spec from calling the event handler.
@ -898,11 +903,12 @@ def call_event_handler(
# Handle partial application of EventSpec args # Handle partial application of EventSpec args
return event_handler.add_args(*parsed_args) return event_handler.add_args(*parsed_args)
args = inspect.getfullargspec(event_handler.fn).args fullspec = inspect.getfullargspec(event_handler.fn)
args = fullspec.args
n_args = len(args) - 1 # subtract 1 for bound self arg n_args = len(args) - 1 # subtract 1 for bound self arg
if n_args == len(parsed_args):
return event_handler(*parsed_args) # type: ignore if n_args != len(parsed_args):
else:
raise EventHandlerArgMismatch( raise EventHandlerArgMismatch(
"The number of arguments accepted by " "The number of arguments accepted by "
f"{event_handler.fn.__qualname__} ({n_args}) " f"{event_handler.fn.__qualname__} ({n_args}) "
@ -911,6 +917,20 @@ def call_event_handler(
"See https://reflex.dev/docs/events/event-arguments/" "See https://reflex.dev/docs/events/event-arguments/"
) )
# check that args of event handler are matching the spec if type hints are provided
for arg, arg_type in inspect.getfullargspec(arg_spec).annotations.items():
if arg not in fullspec.annotations:
continue
if arg_type == fullspec.annotations[arg]:
print(f"continue for {arg}: {arg_type} == {fullspec.annotations[arg]}")
continue
else:
raise EventHandlerArgTypeMismatch(
f"Type mismatch for argument {arg} in {event_handler.fn.__qualname__}. Expected {arg_type} but got {fullspec.annotations[arg]}"
)
return event_handler(*parsed_args) # type: ignore
def unwrap_var_annotation(annotation: GenericType): def unwrap_var_annotation(annotation: GenericType):
"""Unwrap a Var annotation or return it as is if it's not Var[X]. """Unwrap a Var annotation or return it as is if it's not Var[X].

View File

@ -82,7 +82,11 @@ class MatchTypeError(ReflexError, TypeError):
class EventHandlerArgMismatch(ReflexError, TypeError): class EventHandlerArgMismatch(ReflexError, TypeError):
"""Raised when the number of args accepted by an EventHandler is differs from that provided by the event trigger.""" """Raised when the number of args accepted by an EventHandler differs from that provided by the event trigger."""
class EventHandlerArgTypeMismatch(ReflexError, TypeError):
"""Raised when the annotations of args accepted by an EventHandler differs from the spec of the event trigger."""
class EventFnArgMismatch(ReflexError, TypeError): class EventFnArgMismatch(ReflexError, TypeError):