28
28
from typing_extensions import ParamSpec , Protocol , get_args , get_origin
29
29
30
30
from reflex import constants
31
+ from reflex .constants .state import FRONTEND_EVENT_STATE
31
32
from reflex .utils import console , format
32
33
from reflex .utils .exceptions import (
33
34
EventFnArgMismatch ,
34
- EventHandlerArgMismatch ,
35
35
EventHandlerArgTypeMismatch ,
36
36
)
37
37
from reflex .utils .types import ArgsSpec , GenericType , typehint_issubclass
@@ -662,7 +662,7 @@ def fn():
662
662
fn .__qualname__ = name
663
663
fn .__signature__ = sig
664
664
return EventSpec (
665
- handler = EventHandler (fn = fn ),
665
+ handler = EventHandler (fn = fn , state_full_name = FRONTEND_EVENT_STATE ),
666
666
args = tuple (
667
667
(
668
668
Var (_js_expr = k ),
@@ -1092,8 +1092,8 @@ def get_hydrate_event(state) -> str:
1092
1092
1093
1093
1094
1094
def call_event_handler (
1095
- event_handler : EventHandler | EventSpec ,
1096
- arg_spec : ArgsSpec | Sequence [ArgsSpec ],
1095
+ event_callback : EventHandler | EventSpec ,
1096
+ event_spec : ArgsSpec | Sequence [ArgsSpec ],
1097
1097
key : Optional [str ] = None ,
1098
1098
) -> EventSpec :
1099
1099
"""Call an event handler to get the event spec.
@@ -1103,53 +1103,57 @@ def call_event_handler(
1103
1103
Otherwise, the event handler will be called with no args.
1104
1104
1105
1105
Args:
1106
- event_handler : The event handler.
1107
- arg_spec : The lambda that define the argument(s) to pass to the event handler.
1106
+ event_callback : The event handler.
1107
+ event_spec : The lambda that define the argument(s) to pass to the event handler.
1108
1108
key: The key to pass to the event handler.
1109
1109
1110
- Raises:
1111
- EventHandlerArgMismatch: if number of arguments expected by event_handler doesn't match the spec.
1112
-
1113
1110
Returns:
1114
1111
The event spec from calling the event handler.
1115
1112
1116
1113
# noqa: DAR401 failure
1117
1114
1118
1115
"""
1119
- parsed_args = parse_args_spec (arg_spec ) # type: ignore
1120
-
1121
- if isinstance (event_handler , EventSpec ):
1122
- # Handle partial application of EventSpec args
1123
- return event_handler .add_args (* parsed_args )
1124
-
1125
- provided_callback_fullspec = inspect .getfullargspec (event_handler .fn )
1126
-
1127
- provided_callback_n_args = (
1128
- len (provided_callback_fullspec .args ) - 1
1129
- ) # subtract 1 for bound self arg
1130
-
1131
- if provided_callback_n_args != len (parsed_args ):
1132
- raise EventHandlerArgMismatch (
1133
- "The number of arguments accepted by "
1134
- f"{ event_handler .fn .__qualname__ } ({ provided_callback_n_args } ) "
1135
- "does not match the arguments passed by the event trigger: "
1136
- f"{ [str (v ) for v in parsed_args ]} \n "
1137
- "See https://reflex.dev/docs/events/event-arguments/"
1116
+ event_spec_args = parse_args_spec (event_spec ) # type: ignore
1117
+
1118
+ if isinstance (event_callback , EventSpec ):
1119
+ check_fn_match_arg_spec (
1120
+ event_callback .handler .fn ,
1121
+ event_spec ,
1122
+ key ,
1123
+ bool (event_callback .handler .state_full_name ) + len (event_callback .args ),
1124
+ event_callback .handler .fn .__qualname__ ,
1138
1125
)
1126
+ # Handle partial application of EventSpec args
1127
+ return event_callback .add_args (* event_spec_args )
1128
+
1129
+ check_fn_match_arg_spec (
1130
+ event_callback .fn ,
1131
+ event_spec ,
1132
+ key ,
1133
+ bool (event_callback .state_full_name ),
1134
+ event_callback .fn .__qualname__ ,
1135
+ )
1139
1136
1140
- all_arg_spec = [arg_spec ] if not isinstance (arg_spec , Sequence ) else arg_spec
1137
+ all_acceptable_specs = (
1138
+ [event_spec ] if not isinstance (event_spec , Sequence ) else event_spec
1139
+ )
1141
1140
1142
1141
event_spec_return_types = list (
1143
1142
filter (
1144
1143
lambda event_spec_return_type : event_spec_return_type is not None
1145
1144
and get_origin (event_spec_return_type ) is tuple ,
1146
- (get_type_hints (arg_spec ).get ("return" , None ) for arg_spec in all_arg_spec ),
1145
+ (
1146
+ get_type_hints (arg_spec ).get ("return" , None )
1147
+ for arg_spec in all_acceptable_specs
1148
+ ),
1147
1149
)
1148
1150
)
1149
1151
1150
1152
if event_spec_return_types :
1151
1153
failures = []
1152
1154
1155
+ event_callback_spec = inspect .getfullargspec (event_callback .fn )
1156
+
1153
1157
for event_spec_index , event_spec_return_type in enumerate (
1154
1158
event_spec_return_types
1155
1159
):
@@ -1160,14 +1164,14 @@ def call_event_handler(
1160
1164
]
1161
1165
1162
1166
try :
1163
- type_hints_of_provided_callback = get_type_hints (event_handler .fn )
1167
+ type_hints_of_provided_callback = get_type_hints (event_callback .fn )
1164
1168
except NameError :
1165
1169
type_hints_of_provided_callback = {}
1166
1170
1167
1171
failed_type_check = False
1168
1172
1169
1173
# check that args of event handler are matching the spec if type hints are provided
1170
- for i , arg in enumerate (provided_callback_fullspec .args [1 :]):
1174
+ for i , arg in enumerate (event_callback_spec .args [1 :]):
1171
1175
if arg not in type_hints_of_provided_callback :
1172
1176
continue
1173
1177
@@ -1181,15 +1185,15 @@ def call_event_handler(
1181
1185
# f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_handler.fn.__qualname__} provided for {key}."
1182
1186
# ) from e
1183
1187
console .warn (
1184
- f"Could not compare types { args_types_without_vars [i ]} and { type_hints_of_provided_callback [arg ]} for argument { arg } of { event_handler .fn .__qualname__ } provided for { key } ."
1188
+ f"Could not compare types { args_types_without_vars [i ]} and { type_hints_of_provided_callback [arg ]} for argument { arg } of { event_callback .fn .__qualname__ } provided for { key } ."
1185
1189
)
1186
1190
compare_result = False
1187
1191
1188
1192
if compare_result :
1189
1193
continue
1190
1194
else :
1191
1195
failure = EventHandlerArgTypeMismatch (
1192
- f"Event handler { key } expects { args_types_without_vars [i ]} for argument { arg } but got { type_hints_of_provided_callback [arg ]} as annotated in { event_handler .fn .__qualname__ } instead."
1196
+ f"Event handler { key } expects { args_types_without_vars [i ]} for argument { arg } but got { type_hints_of_provided_callback [arg ]} as annotated in { event_callback .fn .__qualname__ } instead."
1193
1197
)
1194
1198
failures .append (failure )
1195
1199
failed_type_check = True
@@ -1210,14 +1214,14 @@ def call_event_handler(
1210
1214
1211
1215
given_string = ", " .join (
1212
1216
repr (type_hints_of_provided_callback .get (arg , Any ))
1213
- for arg in provided_callback_fullspec .args [1 :]
1217
+ for arg in event_callback_spec .args [1 :]
1214
1218
).replace ("[" , "\\ [" )
1215
1219
1216
1220
console .warn (
1217
- f"Event handler { key } expects ({ expect_string } ) -> () but got ({ given_string } ) -> () as annotated in { event_handler .fn .__qualname__ } instead. "
1221
+ f"Event handler { key } expects ({ expect_string } ) -> () but got ({ given_string } ) -> () as annotated in { event_callback .fn .__qualname__ } instead. "
1218
1222
f"This may lead to unexpected behavior but is intentionally ignored for { key } ."
1219
1223
)
1220
- return event_handler ( * parsed_args )
1224
+ return event_callback ( * event_spec_args )
1221
1225
1222
1226
if failures :
1223
1227
console .deprecate (
@@ -1227,7 +1231,7 @@ def call_event_handler(
1227
1231
"0.7.0" ,
1228
1232
)
1229
1233
1230
- return event_handler ( * parsed_args ) # type: ignore
1234
+ return event_callback ( * event_spec_args ) # type: ignore
1231
1235
1232
1236
1233
1237
def unwrap_var_annotation (annotation : GenericType ):
@@ -1294,45 +1298,46 @@ def parse_args_spec(arg_spec: ArgsSpec | Sequence[ArgsSpec]):
1294
1298
1295
1299
1296
1300
def check_fn_match_arg_spec (
1297
- fn : Callable ,
1298
- arg_spec : ArgsSpec ,
1299
- key : Optional [str ] = None ,
1300
- ) -> List [Var ]:
1301
+ user_func : Callable ,
1302
+ arg_spec : ArgsSpec | Sequence [ArgsSpec ],
1303
+ key : str | None = None ,
1304
+ number_of_bound_args : int = 0 ,
1305
+ func_name : str | None = None ,
1306
+ ):
1301
1307
"""Ensures that the function signature matches the passed argument specification
1302
1308
or raises an EventFnArgMismatch if they do not.
1303
1309
1304
1310
Args:
1305
- fn : The function to be validated.
1311
+ user_func : The function to be validated.
1306
1312
arg_spec: The argument specification for the event trigger.
1307
- key: The key to pass to the event handler.
1308
-
1309
- Returns:
1310
- The parsed arguments from the argument specification.
1313
+ key: The key of the event trigger.
1314
+ number_of_bound_args: The number of bound arguments to the function.
1315
+ func_name: The name of the function to be validated.
1311
1316
1312
1317
Raises:
1313
1318
EventFnArgMismatch: Raised if the number of mandatory arguments do not match
1314
1319
"""
1315
- fn_args = inspect .getfullargspec (fn ).args
1316
- fn_defaults_args = inspect .getfullargspec (fn ).defaults
1317
- n_fn_args = len (fn_args )
1318
- n_fn_defaults_args = len (fn_defaults_args ) if fn_defaults_args else 0
1319
- if isinstance (fn , types .MethodType ):
1320
- n_fn_args -= 1 # subtract 1 for bound self arg
1321
- parsed_args = parse_args_spec (arg_spec )
1322
- if not (n_fn_args - n_fn_defaults_args <= len (parsed_args ) <= n_fn_args ):
1320
+ user_args = inspect .getfullargspec (user_func ).args
1321
+ user_default_args = inspect .getfullargspec (user_func ).defaults
1322
+ number_of_user_args = len (user_args ) - number_of_bound_args
1323
+ number_of_user_default_args = len (user_default_args ) if user_default_args else 0
1324
+
1325
+ parsed_event_args = parse_args_spec (arg_spec )
1326
+
1327
+ number_of_event_args = len (parsed_event_args )
1328
+
1329
+ if number_of_user_args - number_of_user_default_args > number_of_event_args :
1323
1330
raise EventFnArgMismatch (
1324
- "The number of mandatory arguments accepted by "
1325
- f"{ fn } ({ n_fn_args - n_fn_defaults_args } ) "
1326
- "does not match the arguments passed by the event trigger: "
1327
- f"{ [str (v ) for v in parsed_args ]} \n "
1331
+ f"Event { key } only provides { number_of_event_args } arguments, but "
1332
+ f"{ func_name or user_func } requires at least { number_of_user_args - number_of_user_default_args } "
1333
+ "arguments to be passed to the event handler.\n "
1328
1334
"See https://reflex.dev/docs/events/event-arguments/"
1329
1335
)
1330
- return parsed_args
1331
1336
1332
1337
1333
1338
def call_event_fn (
1334
1339
fn : Callable ,
1335
- arg_spec : ArgsSpec ,
1340
+ arg_spec : ArgsSpec | Sequence [ ArgsSpec ] ,
1336
1341
key : Optional [str ] = None ,
1337
1342
) -> list [EventSpec ] | Var :
1338
1343
"""Call a function to a list of event specs.
@@ -1356,10 +1361,14 @@ def call_event_fn(
1356
1361
from reflex .utils .exceptions import EventHandlerValueError
1357
1362
1358
1363
# Check that fn signature matches arg_spec
1359
- parsed_args = check_fn_match_arg_spec (fn , arg_spec , key = key )
1364
+ check_fn_match_arg_spec (fn , arg_spec , key = key )
1365
+
1366
+ parsed_args = parse_args_spec (arg_spec )
1367
+
1368
+ number_of_fn_args = len (inspect .getfullargspec (fn ).args )
1360
1369
1361
1370
# Call the function with the parsed args.
1362
- out = fn (* parsed_args )
1371
+ out = fn (* [ * parsed_args ][: number_of_fn_args ] )
1363
1372
1364
1373
# If the function returns a Var, assume it's an EventChain and render it directly.
1365
1374
if isinstance (out , Var ):
@@ -1478,7 +1487,7 @@ def get_fn_signature(fn: Callable) -> inspect.Signature:
1478
1487
"""
1479
1488
signature = inspect .signature (fn )
1480
1489
new_param = inspect .Parameter (
1481
- "state" , inspect .Parameter .POSITIONAL_OR_KEYWORD , annotation = Any
1490
+ FRONTEND_EVENT_STATE , inspect .Parameter .POSITIONAL_OR_KEYWORD , annotation = Any
1482
1491
)
1483
1492
return signature .replace (parameters = (new_param , * signature .parameters .values ()))
1484
1493
0 commit comments