reflex 0.6.8a1__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

Files changed (248) hide show
  1. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +1 -1
  2. reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
  3. reflex/.templates/jinja/web/pages/utils.js.jinja2 +3 -3
  4. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
  5. reflex/.templates/web/utils/state.js +65 -36
  6. reflex/__init__.py +4 -17
  7. reflex/__init__.pyi +1 -2
  8. reflex/app.py +286 -135
  9. reflex/app_mixins/lifespan.py +9 -9
  10. reflex/app_mixins/middleware.py +6 -6
  11. reflex/app_module_for_backend.py +3 -7
  12. reflex/base.py +7 -7
  13. reflex/compiler/compiler.py +8 -0
  14. reflex/compiler/utils.py +57 -18
  15. reflex/components/base/app_wrap.pyi +16 -16
  16. reflex/components/base/bare.py +1 -1
  17. reflex/components/base/body.pyi +16 -16
  18. reflex/components/base/document.pyi +76 -76
  19. reflex/components/base/error_boundary.py +2 -1
  20. reflex/components/base/error_boundary.pyi +19 -22
  21. reflex/components/base/fragment.pyi +16 -16
  22. reflex/components/base/head.pyi +31 -31
  23. reflex/components/base/link.pyi +31 -31
  24. reflex/components/base/meta.py +2 -2
  25. reflex/components/base/meta.pyi +61 -61
  26. reflex/components/base/script.pyi +19 -19
  27. reflex/components/base/strict_mode.py +10 -0
  28. reflex/components/base/strict_mode.pyi +57 -0
  29. reflex/components/component.py +38 -77
  30. reflex/components/core/banner.py +159 -4
  31. reflex/components/core/banner.pyi +162 -76
  32. reflex/components/core/breakpoints.py +3 -1
  33. reflex/components/core/client_side_routing.py +1 -1
  34. reflex/components/core/client_side_routing.pyi +32 -32
  35. reflex/components/core/clipboard.pyi +17 -20
  36. reflex/components/core/cond.py +9 -10
  37. reflex/components/core/debounce.py +1 -1
  38. reflex/components/core/debounce.pyi +17 -17
  39. reflex/components/core/foreach.py +28 -3
  40. reflex/components/core/html.py +1 -1
  41. reflex/components/core/html.pyi +16 -16
  42. reflex/components/core/match.py +5 -5
  43. reflex/components/core/sticky.py +134 -0
  44. reflex/components/core/sticky.pyi +449 -0
  45. reflex/components/core/upload.py +2 -2
  46. reflex/components/core/upload.pyi +80 -88
  47. reflex/components/datadisplay/code.py +5 -14
  48. reflex/components/datadisplay/code.pyi +31 -31
  49. reflex/components/datadisplay/dataeditor.py +7 -4
  50. reflex/components/datadisplay/dataeditor.pyi +40 -54
  51. reflex/components/datadisplay/logo.py +13 -8
  52. reflex/components/datadisplay/shiki_code_block.py +14 -9
  53. reflex/components/datadisplay/shiki_code_block.pyi +46 -46
  54. reflex/components/dynamic.py +22 -3
  55. reflex/components/el/constants/reflex.py +1 -1
  56. reflex/components/el/element.py +1 -1
  57. reflex/components/el/element.pyi +16 -16
  58. reflex/components/el/elements/base.pyi +16 -16
  59. reflex/components/el/elements/forms.py +4 -4
  60. reflex/components/el/elements/forms.pyi +224 -258
  61. reflex/components/el/elements/inline.pyi +421 -421
  62. reflex/components/el/elements/media.pyi +376 -376
  63. reflex/components/el/elements/metadata.pyi +91 -91
  64. reflex/components/el/elements/other.pyi +106 -106
  65. reflex/components/el/elements/scripts.pyi +46 -46
  66. reflex/components/el/elements/sectioning.pyi +226 -226
  67. reflex/components/el/elements/tables.pyi +151 -151
  68. reflex/components/el/elements/typography.pyi +226 -226
  69. reflex/components/gridjs/datatable.pyi +31 -31
  70. reflex/components/lucide/icon.py +46 -8
  71. reflex/components/lucide/icon.pyi +85 -31
  72. reflex/components/markdown/markdown.py +10 -8
  73. reflex/components/markdown/markdown.pyi +16 -16
  74. reflex/components/moment/moment.py +2 -2
  75. reflex/components/moment/moment.pyi +17 -19
  76. reflex/components/next/base.pyi +16 -16
  77. reflex/components/next/image.py +16 -4
  78. reflex/components/next/image.pyi +22 -20
  79. reflex/components/next/link.py +1 -1
  80. reflex/components/next/link.pyi +16 -16
  81. reflex/components/next/video.pyi +16 -16
  82. reflex/components/plotly/__init__.py +29 -2
  83. reflex/components/plotly/plotly.py +240 -5
  84. reflex/components/plotly/plotly.pyi +799 -44
  85. reflex/components/props.py +3 -3
  86. reflex/components/radix/__init__.pyi +1 -1
  87. reflex/components/radix/primitives/accordion.py +9 -5
  88. reflex/components/radix/primitives/accordion.pyi +110 -108
  89. reflex/components/radix/primitives/base.pyi +31 -31
  90. reflex/components/radix/primitives/drawer.py +5 -2
  91. reflex/components/radix/primitives/drawer.pyi +179 -187
  92. reflex/components/radix/primitives/form.pyi +160 -172
  93. reflex/components/radix/primitives/progress.py +1 -1
  94. reflex/components/radix/primitives/progress.pyi +76 -76
  95. reflex/components/radix/primitives/slider.py +1 -1
  96. reflex/components/radix/primitives/slider.pyi +78 -82
  97. reflex/components/radix/themes/base.pyi +121 -121
  98. reflex/components/radix/themes/color_mode.py +11 -9
  99. reflex/components/radix/themes/color_mode.pyi +47 -49
  100. reflex/components/radix/themes/components/alert_dialog.py +3 -0
  101. reflex/components/radix/themes/components/alert_dialog.pyi +110 -112
  102. reflex/components/radix/themes/components/aspect_ratio.pyi +16 -16
  103. reflex/components/radix/themes/components/avatar.pyi +16 -16
  104. reflex/components/radix/themes/components/badge.pyi +16 -16
  105. reflex/components/radix/themes/components/button.pyi +16 -16
  106. reflex/components/radix/themes/components/callout.pyi +76 -76
  107. reflex/components/radix/themes/components/card.py +1 -1
  108. reflex/components/radix/themes/components/card.pyi +17 -17
  109. reflex/components/radix/themes/components/checkbox.pyi +49 -55
  110. reflex/components/radix/themes/components/checkbox_cards.pyi +31 -31
  111. reflex/components/radix/themes/components/checkbox_group.pyi +31 -31
  112. reflex/components/radix/themes/components/context_menu.py +5 -0
  113. reflex/components/radix/themes/components/context_menu.pyi +149 -155
  114. reflex/components/radix/themes/components/data_list.pyi +61 -61
  115. reflex/components/radix/themes/components/dialog.py +3 -0
  116. reflex/components/radix/themes/components/dialog.pyi +113 -117
  117. reflex/components/radix/themes/components/dropdown_menu.py +5 -0
  118. reflex/components/radix/themes/components/dropdown_menu.pyi +133 -137
  119. reflex/components/radix/themes/components/hover_card.py +3 -0
  120. reflex/components/radix/themes/components/hover_card.pyi +63 -67
  121. reflex/components/radix/themes/components/icon_button.py +2 -2
  122. reflex/components/radix/themes/components/icon_button.pyi +17 -16
  123. reflex/components/radix/themes/components/inset.pyi +16 -16
  124. reflex/components/radix/themes/components/popover.py +3 -0
  125. reflex/components/radix/themes/components/popover.pyi +68 -70
  126. reflex/components/radix/themes/components/progress.pyi +16 -16
  127. reflex/components/radix/themes/components/radio.pyi +16 -16
  128. reflex/components/radix/themes/components/radio_cards.py +2 -0
  129. reflex/components/radix/themes/components/radio_cards.pyi +32 -34
  130. reflex/components/radix/themes/components/radio_group.py +1 -1
  131. reflex/components/radix/themes/components/radio_group.pyi +62 -64
  132. reflex/components/radix/themes/components/scroll_area.pyi +16 -16
  133. reflex/components/radix/themes/components/segmented_control.pyi +32 -35
  134. reflex/components/radix/themes/components/select.py +4 -0
  135. reflex/components/radix/themes/components/select.pyi +145 -157
  136. reflex/components/radix/themes/components/separator.pyi +16 -16
  137. reflex/components/radix/themes/components/skeleton.py +3 -0
  138. reflex/components/radix/themes/components/skeleton.pyi +16 -16
  139. reflex/components/radix/themes/components/slider.pyi +22 -28
  140. reflex/components/radix/themes/components/spinner.pyi +16 -16
  141. reflex/components/radix/themes/components/switch.pyi +17 -19
  142. reflex/components/radix/themes/components/table.pyi +106 -106
  143. reflex/components/radix/themes/components/tabs.py +3 -0
  144. reflex/components/radix/themes/components/tabs.pyi +78 -82
  145. reflex/components/radix/themes/components/text_area.py +12 -0
  146. reflex/components/radix/themes/components/text_area.pyi +21 -33
  147. reflex/components/radix/themes/components/text_field.py +1 -1
  148. reflex/components/radix/themes/components/text_field.pyi +52 -80
  149. reflex/components/radix/themes/components/tooltip.py +6 -1
  150. reflex/components/radix/themes/components/tooltip.pyi +20 -21
  151. reflex/components/radix/themes/layout/__init__.pyi +1 -1
  152. reflex/components/radix/themes/layout/base.pyi +16 -16
  153. reflex/components/radix/themes/layout/box.pyi +16 -16
  154. reflex/components/radix/themes/layout/center.pyi +16 -16
  155. reflex/components/radix/themes/layout/container.pyi +16 -16
  156. reflex/components/radix/themes/layout/flex.pyi +16 -16
  157. reflex/components/radix/themes/layout/grid.pyi +16 -16
  158. reflex/components/radix/themes/layout/list.py +2 -2
  159. reflex/components/radix/themes/layout/list.pyi +76 -76
  160. reflex/components/radix/themes/layout/section.pyi +16 -16
  161. reflex/components/radix/themes/layout/spacer.pyi +16 -16
  162. reflex/components/radix/themes/layout/stack.py +2 -2
  163. reflex/components/radix/themes/layout/stack.pyi +46 -46
  164. reflex/components/radix/themes/typography/blockquote.pyi +16 -16
  165. reflex/components/radix/themes/typography/code.pyi +16 -16
  166. reflex/components/radix/themes/typography/heading.pyi +16 -16
  167. reflex/components/radix/themes/typography/link.py +1 -1
  168. reflex/components/radix/themes/typography/link.pyi +16 -16
  169. reflex/components/radix/themes/typography/text.py +2 -2
  170. reflex/components/radix/themes/typography/text.pyi +106 -106
  171. reflex/components/react_player/audio.pyi +33 -39
  172. reflex/components/react_player/react_player.py +1 -1
  173. reflex/components/react_player/react_player.pyi +32 -38
  174. reflex/components/react_player/video.pyi +33 -39
  175. reflex/components/recharts/__init__.py +2 -0
  176. reflex/components/recharts/__init__.pyi +2 -0
  177. reflex/components/recharts/cartesian.pyi +282 -282
  178. reflex/components/recharts/charts.py +15 -15
  179. reflex/components/recharts/charts.pyi +164 -164
  180. reflex/components/recharts/general.py +19 -4
  181. reflex/components/recharts/general.pyi +132 -81
  182. reflex/components/recharts/polar.py +2 -2
  183. reflex/components/recharts/polar.pyi +55 -55
  184. reflex/components/recharts/recharts.py +4 -4
  185. reflex/components/recharts/recharts.pyi +31 -31
  186. reflex/components/sonner/toast.py +15 -13
  187. reflex/components/sonner/toast.pyi +22 -22
  188. reflex/components/suneditor/editor.py +6 -4
  189. reflex/components/suneditor/editor.pyi +26 -40
  190. reflex/components/tags/iter_tag.py +3 -3
  191. reflex/components/tags/tag.py +25 -3
  192. reflex/config.py +48 -20
  193. reflex/constants/__init__.py +1 -0
  194. reflex/constants/base.py +4 -1
  195. reflex/constants/compiler.py +5 -2
  196. reflex/constants/config.py +8 -1
  197. reflex/constants/installer.py +9 -9
  198. reflex/constants/style.py +1 -1
  199. reflex/custom_components/custom_components.py +18 -10
  200. reflex/event.py +228 -233
  201. reflex/experimental/__init__.py +19 -11
  202. reflex/experimental/client_state.py +53 -28
  203. reflex/experimental/hooks.py +5 -5
  204. reflex/experimental/layout.py +8 -5
  205. reflex/experimental/layout.pyi +79 -83
  206. reflex/experimental/misc.py +3 -3
  207. reflex/istate/wrappers.py +1 -1
  208. reflex/middleware/hydrate_middleware.py +2 -2
  209. reflex/model.py +11 -6
  210. reflex/page.py +5 -5
  211. reflex/reflex.py +104 -26
  212. reflex/route.py +1 -1
  213. reflex/state.py +358 -401
  214. reflex/style.py +27 -3
  215. reflex/testing.py +34 -39
  216. reflex/utils/build.py +6 -2
  217. reflex/utils/codespaces.py +1 -4
  218. reflex/utils/compat.py +6 -5
  219. reflex/utils/console.py +71 -21
  220. reflex/utils/exceptions.py +89 -26
  221. reflex/utils/exec.py +69 -74
  222. reflex/utils/export.py +6 -1
  223. reflex/utils/format.py +8 -40
  224. reflex/utils/imports.py +5 -2
  225. reflex/utils/lazy_loader.py +7 -1
  226. reflex/utils/path_ops.py +74 -14
  227. reflex/utils/prerequisites.py +345 -68
  228. reflex/utils/processes.py +45 -32
  229. reflex/utils/pyi_generator.py +39 -33
  230. reflex/utils/registry.py +4 -4
  231. reflex/utils/serializers.py +1 -1
  232. reflex/utils/telemetry.py +5 -4
  233. reflex/utils/types.py +42 -18
  234. reflex/vars/base.py +695 -330
  235. reflex/vars/datetime.py +6 -7
  236. reflex/vars/dep_tracking.py +344 -0
  237. reflex/vars/function.py +11 -5
  238. reflex/vars/number.py +31 -43
  239. reflex/vars/object.py +74 -64
  240. reflex/vars/sequence.py +79 -67
  241. {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/METADATA +7 -10
  242. reflex-0.7.0.dist-info/RECORD +401 -0
  243. {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/WHEEL +1 -1
  244. reflex/experimental/assets.py +0 -37
  245. reflex/proxy.py +0 -119
  246. reflex-0.6.8a1.dist-info/RECORD +0 -398
  247. {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/LICENSE +0 -0
  248. {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/entry_points.txt +0 -0
reflex/event.py CHANGED
@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
 
5
5
  import dataclasses
6
6
  import inspect
7
- import sys
8
7
  import types
9
8
  import urllib.parse
10
9
  from base64 import b64encode
@@ -25,22 +24,27 @@ from typing import (
25
24
  overload,
26
25
  )
27
26
 
28
- import typing_extensions
29
27
  from typing_extensions import (
30
- Concatenate,
31
- ParamSpec,
32
28
  Protocol,
29
+ Self,
33
30
  TypeAliasType,
34
31
  TypedDict,
35
32
  TypeVar,
33
+ TypeVarTuple,
34
+ Unpack,
36
35
  get_args,
37
36
  get_origin,
38
37
  )
39
38
 
40
39
  from reflex import constants
40
+ from reflex.constants.compiler import CompileVars, Hooks, Imports
41
41
  from reflex.constants.state import FRONTEND_EVENT_STATE
42
42
  from reflex.utils import console, format
43
- from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgTypeMismatch
43
+ from reflex.utils.exceptions import (
44
+ EventFnArgMismatchError,
45
+ EventHandlerArgTypeMismatchError,
46
+ MissingAnnotationError,
47
+ )
44
48
  from reflex.utils.types import ArgsSpec, GenericType, typehint_issubclass
45
49
  from reflex.vars import VarData
46
50
  from reflex.vars.base import LiteralVar, Var
@@ -91,33 +95,9 @@ class Event:
91
95
  return f"{self.token}_{substate}"
92
96
 
93
97
 
94
- BACKGROUND_TASK_MARKER = "_reflex_background_task"
95
-
96
-
97
- def background(fn, *, __internal_reflex_call: bool = False):
98
- """Decorator to mark event handler as running in the background.
99
-
100
- Args:
101
- fn: The function to decorate.
102
-
103
- Returns:
104
- The same function, but with a marker set.
105
-
98
+ _EVENT_FIELDS: set[str] = {f.name for f in dataclasses.fields(Event)}
106
99
 
107
- Raises:
108
- TypeError: If the function is not a coroutine function or async generator.
109
- """
110
- if not __internal_reflex_call:
111
- console.deprecate(
112
- "background-decorator",
113
- "Use `rx.event(background=True)` instead.",
114
- "0.6.5",
115
- "0.7.0",
116
- )
117
- if not inspect.iscoroutinefunction(fn) and not inspect.isasyncgenfunction(fn):
118
- raise TypeError("Background task must be async function or generator.")
119
- setattr(fn, BACKGROUND_TASK_MARKER, True)
120
- return fn
100
+ BACKGROUND_TASK_MARKER = "_reflex_background_task"
121
101
 
122
102
 
123
103
  @dataclasses.dataclass(
@@ -131,7 +111,7 @@ class EventActionsMixin:
131
111
  event_actions: Dict[str, Union[bool, int]] = dataclasses.field(default_factory=dict)
132
112
 
133
113
  @property
134
- def stop_propagation(self):
114
+ def stop_propagation(self) -> Self:
135
115
  """Stop the event from bubbling up the DOM tree.
136
116
 
137
117
  Returns:
@@ -143,7 +123,7 @@ class EventActionsMixin:
143
123
  )
144
124
 
145
125
  @property
146
- def prevent_default(self):
126
+ def prevent_default(self) -> Self:
147
127
  """Prevent the default behavior of the event.
148
128
 
149
129
  Returns:
@@ -154,7 +134,7 @@ class EventActionsMixin:
154
134
  event_actions={"preventDefault": True, **self.event_actions},
155
135
  )
156
136
 
157
- def throttle(self, limit_ms: int):
137
+ def throttle(self, limit_ms: int) -> Self:
158
138
  """Throttle the event handler.
159
139
 
160
140
  Args:
@@ -168,7 +148,7 @@ class EventActionsMixin:
168
148
  event_actions={"throttle": limit_ms, **self.event_actions},
169
149
  )
170
150
 
171
- def debounce(self, delay_ms: int):
151
+ def debounce(self, delay_ms: int) -> Self:
172
152
  """Debounce the event handler.
173
153
 
174
154
  Args:
@@ -183,7 +163,7 @@ class EventActionsMixin:
183
163
  )
184
164
 
185
165
  @property
186
- def temporal(self):
166
+ def temporal(self) -> Self:
187
167
  """Do not queue the event if the backend is down.
188
168
 
189
169
  Returns:
@@ -264,7 +244,7 @@ class EventHandler(EventActionsMixin):
264
244
  raise EventHandlerTypeError(
265
245
  f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
266
246
  ) from e
267
- payload = tuple(zip(fn_args, values))
247
+ payload = tuple(zip(fn_args, values, strict=False))
268
248
 
269
249
  # Return the event spec.
270
250
  return EventSpec(
@@ -284,7 +264,7 @@ class EventSpec(EventActionsMixin):
284
264
  """
285
265
 
286
266
  # The event handler.
287
- handler: EventHandler = dataclasses.field(default=None) # type: ignore
267
+ handler: EventHandler = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
288
268
 
289
269
  # The handler on the client to process event.
290
270
  client_handler_name: str = dataclasses.field(default="")
@@ -353,12 +333,12 @@ class EventSpec(EventActionsMixin):
353
333
  arg = None
354
334
  try:
355
335
  for arg in args:
356
- values.append(LiteralVar.create(value=arg)) # noqa: PERF401
336
+ values.append(LiteralVar.create(value=arg)) # noqa: PERF401, RUF100
357
337
  except TypeError as e:
358
338
  raise EventHandlerTypeError(
359
339
  f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
360
340
  ) from e
361
- new_payload = tuple(zip(fn_args, values))
341
+ new_payload = tuple(zip(fn_args, values, strict=False))
362
342
  return self.with_args(self.args + new_payload)
363
343
 
364
344
 
@@ -437,6 +417,7 @@ class EventChain(EventActionsMixin):
437
417
  value: EventType,
438
418
  args_spec: ArgsSpec | Sequence[ArgsSpec],
439
419
  key: Optional[str] = None,
420
+ **event_chain_kwargs,
440
421
  ) -> Union[EventChain, Var]:
441
422
  """Create an event chain from a variety of input types.
442
423
 
@@ -444,6 +425,7 @@ class EventChain(EventActionsMixin):
444
425
  value: The value to create the event chain from.
445
426
  args_spec: The args_spec of the event trigger being bound.
446
427
  key: The key of the event trigger being bound.
428
+ **event_chain_kwargs: Additional kwargs to pass to the EventChain constructor.
447
429
 
448
430
  Returns:
449
431
  The event chain.
@@ -462,6 +444,7 @@ class EventChain(EventActionsMixin):
462
444
  value=value.guess_type(),
463
445
  args_spec=args_spec,
464
446
  key=key,
447
+ **event_chain_kwargs,
465
448
  )
466
449
  else:
467
450
  raise ValueError(
@@ -501,7 +484,9 @@ class EventChain(EventActionsMixin):
501
484
  result = call_event_fn(value, args_spec, key=key)
502
485
  if isinstance(result, Var):
503
486
  # Recursively call this function if the lambda returned an EventChain Var.
504
- return cls.create(value=result, args_spec=args_spec, key=key)
487
+ return cls.create(
488
+ value=result, args_spec=args_spec, key=key, **event_chain_kwargs
489
+ )
505
490
  events = [*result]
506
491
 
507
492
  # Otherwise, raise an error.
@@ -518,7 +503,7 @@ class EventChain(EventActionsMixin):
518
503
  return cls(
519
504
  events=events,
520
505
  args_spec=args_spec,
521
- event_actions={},
506
+ **event_chain_kwargs,
522
507
  )
523
508
 
524
509
 
@@ -550,13 +535,13 @@ class JavasciptKeyboardEvent:
550
535
  """Interface for a Javascript KeyboardEvent https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent."""
551
536
 
552
537
  key: str = ""
553
- altKey: bool = False
554
- ctrlKey: bool = False
555
- metaKey: bool = False
556
- shiftKey: bool = False
538
+ altKey: bool = False # noqa: N815
539
+ ctrlKey: bool = False # noqa: N815
540
+ metaKey: bool = False # noqa: N815
541
+ shiftKey: bool = False # noqa: N815
557
542
 
558
543
 
559
- def input_event(e: Var[JavascriptInputEvent]) -> Tuple[Var[str]]:
544
+ def input_event(e: ObjectVar[JavascriptInputEvent]) -> Tuple[Var[str]]:
560
545
  """Get the value from an input event.
561
546
 
562
547
  Args:
@@ -577,7 +562,9 @@ class KeyInputInfo(TypedDict):
577
562
  shift_key: bool
578
563
 
579
564
 
580
- def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str], Var[KeyInputInfo]]:
565
+ def key_event(
566
+ e: ObjectVar[JavasciptKeyboardEvent],
567
+ ) -> Tuple[Var[str], Var[KeyInputInfo]]:
581
568
  """Get the key from a keyboard event.
582
569
 
583
570
  Args:
@@ -587,7 +574,7 @@ def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str], Var[KeyInputInf
587
574
  The key from the keyboard event.
588
575
  """
589
576
  return (
590
- e.key,
577
+ e.key.to(str),
591
578
  Var.create(
592
579
  {
593
580
  "alt_key": e.altKey,
@@ -595,7 +582,7 @@ def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str], Var[KeyInputInf
595
582
  "meta_key": e.metaKey,
596
583
  "shift_key": e.shiftKey,
597
584
  },
598
- ),
585
+ ).to(KeyInputInfo),
599
586
  )
600
587
 
601
588
 
@@ -605,7 +592,7 @@ def no_args_event_spec() -> Tuple[()]:
605
592
  Returns:
606
593
  An empty tuple.
607
594
  """
608
- return () # type: ignore
595
+ return ()
609
596
 
610
597
 
611
598
  # These chains can be used for their side effects when no other events are desired.
@@ -633,9 +620,9 @@ class IdentityEventReturn(Generic[T], Protocol):
633
620
 
634
621
 
635
622
  @overload
636
- def passthrough_event_spec(
623
+ def passthrough_event_spec( # pyright: ignore [reportOverlappingOverload]
637
624
  event_type: Type[T], /
638
- ) -> Callable[[Var[T]], Tuple[Var[T]]]: ... # type: ignore
625
+ ) -> Callable[[Var[T]], Tuple[Var[T]]]: ...
639
626
 
640
627
 
641
628
  @overload
@@ -648,7 +635,7 @@ def passthrough_event_spec(
648
635
  def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: ...
649
636
 
650
637
 
651
- def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: # type: ignore
638
+ def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: # pyright: ignore [reportInconsistentOverload]
652
639
  """A helper function that returns the input event as output.
653
640
 
654
641
  Args:
@@ -662,9 +649,9 @@ def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: #
662
649
  return values
663
650
 
664
651
  inner_type = tuple(Var[event_type] for event_type in event_types)
665
- return_annotation = Tuple[inner_type] # type: ignore
652
+ return_annotation = Tuple[inner_type]
666
653
 
667
- inner.__signature__ = inspect.signature(inner).replace( # type: ignore
654
+ inner.__signature__ = inspect.signature(inner).replace( # pyright: ignore [reportFunctionMemberAccess]
668
655
  parameters=[
669
656
  inspect.Parameter(
670
657
  f"ev_{i}",
@@ -746,7 +733,7 @@ class FileUpload:
746
733
  # Call the lambda to get the event chain.
747
734
  events = call_event_fn(
748
735
  on_upload_progress, self.on_upload_progress_args_spec
749
- ) # type: ignore
736
+ )
750
737
  else:
751
738
  raise ValueError(f"{on_upload_progress} is not a valid event handler.")
752
739
  if isinstance(events, Var):
@@ -793,7 +780,7 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
793
780
  return None
794
781
 
795
782
  fn.__qualname__ = name
796
- fn.__signature__ = sig
783
+ fn.__signature__ = sig # pyright: ignore [reportFunctionMemberAccess]
797
784
  return EventSpec(
798
785
  handler=EventHandler(fn=fn, state_full_name=FRONTEND_EVENT_STATE),
799
786
  args=tuple(
@@ -806,29 +793,10 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
806
793
  )
807
794
 
808
795
 
809
- @overload
810
- def redirect(
811
- path: str | Var[str],
812
- is_external: Optional[bool] = None,
813
- replace: bool = False,
814
- ) -> EventSpec: ...
815
-
816
-
817
- @overload
818
- @typing_extensions.deprecated("`external` is deprecated use `is_external` instead")
819
- def redirect(
820
- path: str | Var[str],
821
- is_external: Optional[bool] = None,
822
- replace: bool = False,
823
- external: Optional[bool] = None,
824
- ) -> EventSpec: ...
825
-
826
-
827
796
  def redirect(
828
797
  path: str | Var[str],
829
- is_external: Optional[bool] = None,
798
+ is_external: bool = False,
830
799
  replace: bool = False,
831
- external: Optional[bool] = None,
832
800
  ) -> EventSpec:
833
801
  """Redirect to a new path.
834
802
 
@@ -836,26 +804,10 @@ def redirect(
836
804
  path: The path to redirect to.
837
805
  is_external: Whether to open in new tab or not.
838
806
  replace: If True, the current page will not create a new history entry.
839
- external(Deprecated): Whether to open in new tab or not.
840
807
 
841
808
  Returns:
842
809
  An event to redirect to the path.
843
810
  """
844
- if external is not None:
845
- console.deprecate(
846
- "The `external` prop in `rx.redirect`",
847
- "use `is_external` instead.",
848
- "0.6.6",
849
- "0.7.0",
850
- )
851
-
852
- # is_external should take precedence over external.
853
- is_external = (
854
- (False if external is None else external)
855
- if is_external is None
856
- else is_external
857
- )
858
-
859
811
  return server_side(
860
812
  "_redirect",
861
813
  get_fn_signature(redirect),
@@ -1101,13 +1053,13 @@ def download(
1101
1053
 
1102
1054
  is_data_url = (data.js_type() == "string") & (
1103
1055
  data.to(str).startswith("data:")
1104
- ) # type: ignore
1056
+ )
1105
1057
 
1106
1058
  # If it's a data: URI, use it as is, otherwise convert the Var to JSON in a data: URI.
1107
- url = cond( # type: ignore
1059
+ url = cond(
1108
1060
  is_data_url,
1109
1061
  data.to(str),
1110
- "data:text/plain," + data.to_string(), # type: ignore
1062
+ "data:text/plain," + data.to_string(),
1111
1063
  )
1112
1064
  elif isinstance(data, bytes):
1113
1065
  # Caller provided bytes, so base64 encode it as a data: URI.
@@ -1126,7 +1078,8 @@ def download(
1126
1078
  )
1127
1079
 
1128
1080
 
1129
- def _callback_arg_spec(eval_result):
1081
+ # This function seems unused. Check if we still need it. If not, remove in 0.7.0
1082
+ def _callback_arg_spec(eval_result: Any):
1130
1083
  """ArgSpec for call_script callback function.
1131
1084
 
1132
1085
  Args:
@@ -1140,7 +1093,7 @@ def _callback_arg_spec(eval_result):
1140
1093
 
1141
1094
  def call_script(
1142
1095
  javascript_code: str | Var[str],
1143
- callback: EventType | None = None,
1096
+ callback: EventType[Any] | None = None,
1144
1097
  ) -> EventSpec:
1145
1098
  """Create an event handler that executes arbitrary javascript code.
1146
1099
 
@@ -1179,7 +1132,7 @@ def call_script(
1179
1132
 
1180
1133
  def call_function(
1181
1134
  javascript_code: str | Var,
1182
- callback: EventType | None = None,
1135
+ callback: EventType[Any] | None = None,
1183
1136
  ) -> EventSpec:
1184
1137
  """Create an event handler that executes arbitrary javascript code.
1185
1138
 
@@ -1213,7 +1166,7 @@ def call_function(
1213
1166
 
1214
1167
  def run_script(
1215
1168
  javascript_code: str | Var,
1216
- callback: EventType | None = None,
1169
+ callback: EventType[Any] | None = None,
1217
1170
  ) -> EventSpec:
1218
1171
  """Create an event handler that executes arbitrary javascript code.
1219
1172
 
@@ -1231,7 +1184,7 @@ def run_script(
1231
1184
  return call_function(ArgsFunctionOperation.create((), javascript_code), callback)
1232
1185
 
1233
1186
 
1234
- def get_event(state, event):
1187
+ def get_event(state: BaseState, event: str):
1235
1188
  """Get the event from the given state.
1236
1189
 
1237
1190
  Args:
@@ -1244,7 +1197,7 @@ def get_event(state, event):
1244
1197
  return f"{state.get_name()}.{event}"
1245
1198
 
1246
1199
 
1247
- def get_hydrate_event(state) -> str:
1200
+ def get_hydrate_event(state: BaseState) -> str:
1248
1201
  """Get the name of the hydrate event for the state.
1249
1202
 
1250
1203
  Args:
@@ -1272,13 +1225,16 @@ def call_event_handler(
1272
1225
  event_spec: The lambda that define the argument(s) to pass to the event handler.
1273
1226
  key: The key to pass to the event handler.
1274
1227
 
1228
+ Raises:
1229
+ EventHandlerArgTypeMismatchError: If the event handler arguments do not match the event spec. #noqa: DAR402
1230
+ TypeError: If the event handler arguments are invalid.
1231
+
1275
1232
  Returns:
1276
1233
  The event spec from calling the event handler.
1277
1234
 
1278
- # noqa: DAR401 failure
1279
-
1235
+ #noqa: DAR401
1280
1236
  """
1281
- event_spec_args = parse_args_spec(event_spec) # type: ignore
1237
+ event_spec_args = parse_args_spec(event_spec)
1282
1238
 
1283
1239
  if isinstance(event_callback, EventSpec):
1284
1240
  check_fn_match_arg_spec(
@@ -1313,10 +1269,15 @@ def call_event_handler(
1313
1269
  ),
1314
1270
  )
1315
1271
  )
1272
+ type_match_found: dict[str, bool] = {}
1273
+ delayed_exceptions: list[EventHandlerArgTypeMismatchError] = []
1316
1274
 
1317
- if event_spec_return_types:
1318
- failures = []
1275
+ try:
1276
+ type_hints_of_provided_callback = get_type_hints(event_callback.fn)
1277
+ except NameError:
1278
+ type_hints_of_provided_callback = {}
1319
1279
 
1280
+ if event_spec_return_types:
1320
1281
  event_callback_spec = inspect.getfullargspec(event_callback.fn)
1321
1282
 
1322
1283
  for event_spec_index, event_spec_return_type in enumerate(
@@ -1328,43 +1289,35 @@ def call_event_handler(
1328
1289
  arg if get_origin(arg) is not Var else get_args(arg)[0] for arg in args
1329
1290
  ]
1330
1291
 
1331
- try:
1332
- type_hints_of_provided_callback = get_type_hints(event_callback.fn)
1333
- except NameError:
1334
- type_hints_of_provided_callback = {}
1335
-
1336
- failed_type_check = False
1337
-
1338
1292
  # check that args of event handler are matching the spec if type hints are provided
1339
1293
  for i, arg in enumerate(event_callback_spec.args[1:]):
1340
1294
  if arg not in type_hints_of_provided_callback:
1341
1295
  continue
1342
1296
 
1297
+ type_match_found.setdefault(arg, False)
1298
+
1343
1299
  try:
1344
1300
  compare_result = typehint_issubclass(
1345
1301
  args_types_without_vars[i], type_hints_of_provided_callback[arg]
1346
1302
  )
1347
- except TypeError:
1348
- # TODO: In 0.7.0, remove this block and raise the exception
1349
- # raise TypeError(
1350
- # 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}." # noqa: ERA001
1351
- # ) from e
1352
- console.warn(
1303
+ except TypeError as te:
1304
+ raise TypeError(
1353
1305
  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}."
1354
- )
1355
- compare_result = False
1306
+ ) from te
1356
1307
 
1357
1308
  if compare_result:
1309
+ type_match_found[arg] = True
1358
1310
  continue
1359
1311
  else:
1360
- failure = EventHandlerArgTypeMismatch(
1361
- 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."
1312
+ type_match_found[arg] = False
1313
+ delayed_exceptions.append(
1314
+ EventHandlerArgTypeMismatchError(
1315
+ 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."
1316
+ )
1362
1317
  )
1363
- failures.append(failure)
1364
- failed_type_check = True
1365
- break
1366
1318
 
1367
- if not failed_type_check:
1319
+ if all(type_match_found.values()):
1320
+ delayed_exceptions.clear()
1368
1321
  if event_spec_index:
1369
1322
  args = get_args(event_spec_return_types[0])
1370
1323
 
@@ -1386,17 +1339,12 @@ def call_event_handler(
1386
1339
  f"Event handler {key} expects ({expect_string}) -> () but got ({given_string}) -> () as annotated in {event_callback.fn.__qualname__} instead. "
1387
1340
  f"This may lead to unexpected behavior but is intentionally ignored for {key}."
1388
1341
  )
1389
- return event_callback(*event_spec_args)
1390
-
1391
- if failures:
1392
- console.deprecate(
1393
- "Mismatched event handler argument types",
1394
- "\n".join([str(f) for f in failures]),
1395
- "0.6.5",
1396
- "0.7.0",
1397
- )
1342
+ break
1398
1343
 
1399
- return event_callback(*event_spec_args) # type: ignore
1344
+ if delayed_exceptions:
1345
+ raise delayed_exceptions[0]
1346
+
1347
+ return event_callback(*event_spec_args)
1400
1348
 
1401
1349
 
1402
1350
  def unwrap_var_annotation(annotation: GenericType):
@@ -1408,31 +1356,31 @@ def unwrap_var_annotation(annotation: GenericType):
1408
1356
  Returns:
1409
1357
  The unwrapped annotation.
1410
1358
  """
1411
- if get_origin(annotation) is Var and (args := get_args(annotation)):
1359
+ if get_origin(annotation) in (Var, ObjectVar) and (args := get_args(annotation)):
1412
1360
  return args[0]
1413
1361
  return annotation
1414
1362
 
1415
1363
 
1416
- def resolve_annotation(annotations: dict[str, Any], arg_name: str):
1364
+ def resolve_annotation(annotations: dict[str, Any], arg_name: str, spec: ArgsSpec):
1417
1365
  """Resolve the annotation for the given argument name.
1418
1366
 
1419
1367
  Args:
1420
1368
  annotations: The annotations.
1421
1369
  arg_name: The argument name.
1370
+ spec: The specs which the annotations come from.
1371
+
1372
+ Raises:
1373
+ MissingAnnotationError: If the annotation is missing for non-lambda methods.
1422
1374
 
1423
1375
  Returns:
1424
1376
  The resolved annotation.
1425
1377
  """
1426
1378
  annotation = annotations.get(arg_name)
1427
1379
  if annotation is None:
1428
- console.deprecate(
1429
- feature_name="Unannotated event handler arguments",
1430
- reason="Provide type annotations for event handler arguments.",
1431
- deprecation_version="0.6.3",
1432
- removal_version="0.7.0",
1433
- )
1434
- # Allow arbitrary attribute access two levels deep until removed.
1435
- return Dict[str, dict]
1380
+ if not isinstance(spec, types.LambdaType):
1381
+ raise MissingAnnotationError(var_name=arg_name)
1382
+ else:
1383
+ return dict[str, dict]
1436
1384
  return annotation
1437
1385
 
1438
1386
 
@@ -1454,7 +1402,13 @@ def parse_args_spec(arg_spec: ArgsSpec | Sequence[ArgsSpec]):
1454
1402
  arg_spec(
1455
1403
  *[
1456
1404
  Var(f"_{l_arg}").to(
1457
- unwrap_var_annotation(resolve_annotation(annotations, l_arg))
1405
+ unwrap_var_annotation(
1406
+ resolve_annotation(
1407
+ annotations,
1408
+ l_arg,
1409
+ spec=arg_spec,
1410
+ )
1411
+ )
1458
1412
  )
1459
1413
  for l_arg in spec.args
1460
1414
  ]
@@ -1470,7 +1424,7 @@ def check_fn_match_arg_spec(
1470
1424
  func_name: str | None = None,
1471
1425
  ):
1472
1426
  """Ensures that the function signature matches the passed argument specification
1473
- or raises an EventFnArgMismatch if they do not.
1427
+ or raises an EventFnArgMismatchError if they do not.
1474
1428
 
1475
1429
  Args:
1476
1430
  user_func: The function to be validated.
@@ -1480,7 +1434,7 @@ def check_fn_match_arg_spec(
1480
1434
  func_name: The name of the function to be validated.
1481
1435
 
1482
1436
  Raises:
1483
- EventFnArgMismatch: Raised if the number of mandatory arguments do not match
1437
+ EventFnArgMismatchError: Raised if the number of mandatory arguments do not match
1484
1438
  """
1485
1439
  user_args = inspect.getfullargspec(user_func).args
1486
1440
  # Drop the first argument if it's a bound method
@@ -1496,7 +1450,7 @@ def check_fn_match_arg_spec(
1496
1450
  number_of_event_args = len(parsed_event_args)
1497
1451
 
1498
1452
  if number_of_user_args - number_of_user_default_args > number_of_event_args:
1499
- raise EventFnArgMismatch(
1453
+ raise EventFnArgMismatchError(
1500
1454
  f"Event {key} only provides {number_of_event_args} arguments, but "
1501
1455
  f"{func_name or user_func} requires at least {number_of_user_args - number_of_user_default_args} "
1502
1456
  "arguments to be passed to the event handler.\n"
@@ -1584,7 +1538,7 @@ def get_handler_args(
1584
1538
 
1585
1539
 
1586
1540
  def fix_events(
1587
- events: list[EventHandler | EventSpec] | None,
1541
+ events: list[EventSpec | EventHandler] | None,
1588
1542
  token: str,
1589
1543
  router_data: dict[str, Any] | None = None,
1590
1544
  ) -> list[Event]:
@@ -1624,7 +1578,7 @@ def fix_events(
1624
1578
  if not isinstance(e, EventSpec):
1625
1579
  raise ValueError(f"Unexpected event type, {type(e)}.")
1626
1580
  name = format.format_event_handler(e.handler)
1627
- payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore
1581
+ payload = {k._js_expr: v._decode() for k, v in e.args}
1628
1582
 
1629
1583
  # Filter router_data to reduce payload size
1630
1584
  event_router_data = {
@@ -1668,12 +1622,12 @@ class EventVar(ObjectVar, python_types=EventSpec):
1668
1622
  @dataclasses.dataclass(
1669
1623
  eq=False,
1670
1624
  frozen=True,
1671
- **{"slots": True} if sys.version_info >= (3, 10) else {},
1625
+ slots=True,
1672
1626
  )
1673
1627
  class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
1674
1628
  """A literal event var."""
1675
1629
 
1676
- _var_value: EventSpec = dataclasses.field(default=None) # type: ignore
1630
+ _var_value: EventSpec = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
1677
1631
 
1678
1632
  def __hash__(self) -> int:
1679
1633
  """Get the hash of the var.
@@ -1729,7 +1683,7 @@ class EventChainVar(BuilderFunctionVar, python_types=EventChain):
1729
1683
  @dataclasses.dataclass(
1730
1684
  eq=False,
1731
1685
  frozen=True,
1732
- **{"slots": True} if sys.version_info >= (3, 10) else {},
1686
+ slots=True,
1733
1687
  )
1734
1688
  # Note: LiteralVar is second in the inheritance list allowing it act like a
1735
1689
  # CachedVarOperation (ArgsFunctionOperation) and get the _js_expr from the
@@ -1737,7 +1691,7 @@ class EventChainVar(BuilderFunctionVar, python_types=EventChain):
1737
1691
  class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainVar):
1738
1692
  """A literal event chain var."""
1739
1693
 
1740
- _var_value: EventChain = dataclasses.field(default=None) # type: ignore
1694
+ _var_value: EventChain = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
1741
1695
 
1742
1696
  def __hash__(self) -> int:
1743
1697
  """Get the hash of the var.
@@ -1761,13 +1715,16 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
1761
1715
 
1762
1716
  Returns:
1763
1717
  The created LiteralEventChainVar instance.
1718
+
1719
+ Raises:
1720
+ ValueError: If the invocation is not a FunctionVar.
1764
1721
  """
1765
1722
  arg_spec = (
1766
1723
  value.args_spec[0]
1767
1724
  if isinstance(value.args_spec, Sequence)
1768
1725
  else value.args_spec
1769
1726
  )
1770
- sig = inspect.signature(arg_spec) # type: ignore
1727
+ sig = inspect.signature(arg_spec) # pyright: ignore [reportArgumentType]
1771
1728
  if sig.parameters:
1772
1729
  arg_def = tuple((f"_{p}" for p in sig.parameters))
1773
1730
  arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
@@ -1778,10 +1735,21 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
1778
1735
  arg_def_expr = Var(_js_expr="args")
1779
1736
 
1780
1737
  if value.invocation is None:
1781
- invocation = FunctionStringVar.create("addEvents")
1738
+ invocation = FunctionStringVar.create(
1739
+ CompileVars.ADD_EVENTS,
1740
+ _var_data=VarData(
1741
+ imports=Imports.EVENTS,
1742
+ hooks={Hooks.EVENTS: None},
1743
+ ),
1744
+ )
1782
1745
  else:
1783
1746
  invocation = value.invocation
1784
1747
 
1748
+ if invocation is not None and not isinstance(invocation, FunctionVar):
1749
+ raise ValueError(
1750
+ f"EventChain invocation must be a FunctionVar, got {invocation!s} of type {invocation._var_type!s}."
1751
+ )
1752
+
1785
1753
  return cls(
1786
1754
  _js_expr="",
1787
1755
  _var_type=EventChain,
@@ -1796,8 +1764,8 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
1796
1764
  )
1797
1765
 
1798
1766
 
1799
- P = ParamSpec("P")
1800
- Q = ParamSpec("Q")
1767
+ P = TypeVarTuple("P")
1768
+ Q = TypeVarTuple("Q")
1801
1769
  T = TypeVar("T")
1802
1770
  V = TypeVar("V")
1803
1771
  V2 = TypeVar("V2")
@@ -1805,13 +1773,11 @@ V3 = TypeVar("V3")
1805
1773
  V4 = TypeVar("V4")
1806
1774
  V5 = TypeVar("V5")
1807
1775
 
1808
- background_event_decorator = background
1809
-
1810
1776
 
1811
- class EventCallback(Generic[P, T]):
1777
+ class EventCallback(Generic[Unpack[P]], EventActionsMixin):
1812
1778
  """A descriptor that wraps a function to be used as an event."""
1813
1779
 
1814
- def __init__(self, func: Callable[Concatenate[Any, P], T]):
1780
+ def __init__(self, func: Callable[[Any, Unpack[P]], Any]):
1815
1781
  """Initialize the descriptor with the function to be wrapped.
1816
1782
 
1817
1783
  Args:
@@ -1819,59 +1785,41 @@ class EventCallback(Generic[P, T]):
1819
1785
  """
1820
1786
  self.func = func
1821
1787
 
1822
- @property
1823
- def prevent_default(self):
1824
- """Prevent default behavior.
1825
-
1826
- Returns:
1827
- The event callback with prevent default behavior.
1828
- """
1829
- return self
1830
-
1831
- @property
1832
- def stop_propagation(self):
1833
- """Stop event propagation.
1834
-
1835
- Returns:
1836
- The event callback with stop propagation behavior.
1837
- """
1838
- return self
1839
-
1840
1788
  @overload
1841
1789
  def __call__(
1842
- self: EventCallback[Q, T],
1843
- ) -> EventCallback[Q, T]: ...
1790
+ self: EventCallback[Unpack[Q]],
1791
+ ) -> EventCallback[Unpack[Q]]: ...
1844
1792
 
1845
1793
  @overload
1846
1794
  def __call__(
1847
- self: EventCallback[Concatenate[V, Q], T], value: V | Var[V]
1848
- ) -> EventCallback[Q, T]: ...
1795
+ self: EventCallback[V, Unpack[Q]], value: V | Var[V]
1796
+ ) -> EventCallback[Unpack[Q]]: ...
1849
1797
 
1850
1798
  @overload
1851
1799
  def __call__(
1852
- self: EventCallback[Concatenate[V, V2, Q], T],
1800
+ self: EventCallback[V, V2, Unpack[Q]],
1853
1801
  value: V | Var[V],
1854
1802
  value2: V2 | Var[V2],
1855
- ) -> EventCallback[Q, T]: ...
1803
+ ) -> EventCallback[Unpack[Q]]: ...
1856
1804
 
1857
1805
  @overload
1858
1806
  def __call__(
1859
- self: EventCallback[Concatenate[V, V2, V3, Q], T],
1807
+ self: EventCallback[V, V2, V3, Unpack[Q]],
1860
1808
  value: V | Var[V],
1861
1809
  value2: V2 | Var[V2],
1862
1810
  value3: V3 | Var[V3],
1863
- ) -> EventCallback[Q, T]: ...
1811
+ ) -> EventCallback[Unpack[Q]]: ...
1864
1812
 
1865
1813
  @overload
1866
1814
  def __call__(
1867
- self: EventCallback[Concatenate[V, V2, V3, V4, Q], T],
1815
+ self: EventCallback[V, V2, V3, V4, Unpack[Q]],
1868
1816
  value: V | Var[V],
1869
1817
  value2: V2 | Var[V2],
1870
1818
  value3: V3 | Var[V3],
1871
1819
  value4: V4 | Var[V4],
1872
- ) -> EventCallback[Q, T]: ...
1820
+ ) -> EventCallback[Unpack[Q]]: ...
1873
1821
 
1874
- def __call__(self, *values) -> EventCallback: # type: ignore
1822
+ def __call__(self, *values) -> EventCallback: # pyright: ignore [reportInconsistentOverload]
1875
1823
  """Call the function with the values.
1876
1824
 
1877
1825
  Args:
@@ -1880,17 +1828,17 @@ class EventCallback(Generic[P, T]):
1880
1828
  Returns:
1881
1829
  The function with the values.
1882
1830
  """
1883
- return self.func(*values) # type: ignore
1831
+ return self.func(*values) # pyright: ignore [reportArgumentType]
1884
1832
 
1885
1833
  @overload
1886
1834
  def __get__(
1887
- self: EventCallback[P, T], instance: None, owner
1888
- ) -> EventCallback[P, T]: ...
1835
+ self: EventCallback[Unpack[P]], instance: None, owner: Any
1836
+ ) -> EventCallback[Unpack[P]]: ...
1889
1837
 
1890
1838
  @overload
1891
- def __get__(self, instance, owner) -> Callable[P, T]: ...
1839
+ def __get__(self, instance: Any, owner: Any) -> Callable[[Unpack[P]]]: ...
1892
1840
 
1893
- def __get__(self, instance, owner) -> Callable: # type: ignore
1841
+ def __get__(self, instance: Any, owner: Any) -> Callable:
1894
1842
  """Get the function with the instance bound to it.
1895
1843
 
1896
1844
  Args:
@@ -1901,38 +1849,74 @@ class EventCallback(Generic[P, T]):
1901
1849
  The function with the instance bound to it
1902
1850
  """
1903
1851
  if instance is None:
1904
- return self.func # type: ignore
1852
+ return self.func
1905
1853
 
1906
- return partial(self.func, instance) # type: ignore
1854
+ return partial(self.func, instance)
1907
1855
 
1908
1856
 
1909
- G = ParamSpec("G")
1857
+ class LambdaEventCallback(Protocol[Unpack[P]]):
1858
+ """A protocol for a lambda event callback."""
1910
1859
 
1911
- if TYPE_CHECKING:
1912
- from reflex.state import BaseState
1860
+ @overload
1861
+ def __call__(self: LambdaEventCallback[()]) -> Any: ...
1913
1862
 
1914
- BASE_STATE = TypeVar("BASE_STATE", bound=BaseState)
1915
- else:
1916
- BASE_STATE = TypeVar("BASE_STATE")
1863
+ @overload
1864
+ def __call__(self: LambdaEventCallback[V], value: Var[V], /) -> Any: ...
1865
+
1866
+ @overload
1867
+ def __call__(
1868
+ self: LambdaEventCallback[V, V2], value: Var[V], value2: Var[V2], /
1869
+ ) -> Any: ...
1870
+
1871
+ @overload
1872
+ def __call__(
1873
+ self: LambdaEventCallback[V, V2, V3],
1874
+ value: Var[V],
1875
+ value2: Var[V2],
1876
+ value3: Var[V3],
1877
+ /,
1878
+ ) -> Any: ...
1879
+
1880
+ def __call__(self, *args: Var) -> Any:
1881
+ """Call the lambda with the args.
1882
+
1883
+ Args:
1884
+ *args: The args to call the lambda with.
1885
+ """
1886
+
1887
+
1888
+ ARGS = TypeVarTuple("ARGS")
1917
1889
 
1918
- StateCallable = TypeAliasType(
1919
- "StateCallable",
1920
- Callable[Concatenate[BASE_STATE, G], Any],
1921
- type_params=(G, BASE_STATE),
1890
+
1891
+ LAMBDA_OR_STATE = TypeAliasType(
1892
+ "LAMBDA_OR_STATE",
1893
+ LambdaEventCallback[Unpack[ARGS]] | EventCallback[Unpack[ARGS]],
1894
+ type_params=(ARGS,),
1922
1895
  )
1923
1896
 
1924
- IndividualEventType = Union[
1925
- EventSpec,
1926
- EventHandler,
1927
- Callable[G, Any],
1928
- StateCallable[G, BASE_STATE],
1929
- EventCallback[G, Any],
1930
- Var[Any],
1931
- ]
1897
+ ItemOrList = V | List[V]
1932
1898
 
1933
- ItemOrList = Union[V, List[V]]
1899
+ BASIC_EVENT_TYPES = TypeAliasType(
1900
+ "BASIC_EVENT_TYPES", EventSpec | EventHandler | Var[Any], type_params=()
1901
+ )
1934
1902
 
1935
- EventType = ItemOrList[IndividualEventType[G, BASE_STATE]]
1903
+ IndividualEventType = TypeAliasType(
1904
+ "IndividualEventType",
1905
+ LAMBDA_OR_STATE[Unpack[ARGS]] | BASIC_EVENT_TYPES,
1906
+ type_params=(ARGS,),
1907
+ )
1908
+
1909
+ EventType = TypeAliasType(
1910
+ "EventType", ItemOrList[IndividualEventType[Unpack[ARGS]]], type_params=(ARGS,)
1911
+ )
1912
+
1913
+
1914
+ if TYPE_CHECKING:
1915
+ from reflex.state import BaseState
1916
+
1917
+ BASE_STATE = TypeVar("BASE_STATE", bound=BaseState)
1918
+ else:
1919
+ BASE_STATE = TypeVar("BASE_STATE")
1936
1920
 
1937
1921
 
1938
1922
  class EventNamespace(types.SimpleNamespace):
@@ -1954,24 +1938,26 @@ class EventNamespace(types.SimpleNamespace):
1954
1938
  @staticmethod
1955
1939
  def __call__(
1956
1940
  func: None = None, *, background: bool | None = None
1957
- ) -> Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]]: ...
1941
+ ) -> Callable[
1942
+ [Callable[[BASE_STATE, Unpack[P]], Any]], EventCallback[Unpack[P]] # pyright: ignore [reportInvalidTypeVarUse]
1943
+ ]: ...
1958
1944
 
1959
1945
  @overload
1960
1946
  @staticmethod
1961
1947
  def __call__(
1962
- func: Callable[Concatenate[BASE_STATE, P], T],
1948
+ func: Callable[[BASE_STATE, Unpack[P]], Any],
1963
1949
  *,
1964
1950
  background: bool | None = None,
1965
- ) -> EventCallback[P, T]: ...
1951
+ ) -> EventCallback[Unpack[P]]: ...
1966
1952
 
1967
1953
  @staticmethod
1968
1954
  def __call__(
1969
- func: Callable[Concatenate[BASE_STATE, P], T] | None = None,
1955
+ func: Callable[[BASE_STATE, Unpack[P]], Any] | None = None,
1970
1956
  *,
1971
1957
  background: bool | None = None,
1972
1958
  ) -> Union[
1973
- EventCallback[P, T],
1974
- Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]],
1959
+ EventCallback[Unpack[P]],
1960
+ Callable[[Callable[[BASE_STATE, Unpack[P]], Any]], EventCallback[Unpack[P]]],
1975
1961
  ]:
1976
1962
  """Wrap a function to be used as an event.
1977
1963
 
@@ -1979,16 +1965,25 @@ class EventNamespace(types.SimpleNamespace):
1979
1965
  func: The function to wrap.
1980
1966
  background: Whether the event should be run in the background. Defaults to False.
1981
1967
 
1968
+ Raises:
1969
+ TypeError: If background is True and the function is not a coroutine or async generator. # noqa: DAR402
1970
+
1982
1971
  Returns:
1983
1972
  The wrapped function.
1984
1973
  """
1985
1974
 
1986
1975
  def wrapper(
1987
- func: Callable[Concatenate[BASE_STATE, P], T],
1988
- ) -> EventCallback[P, T]:
1976
+ func: Callable[[BASE_STATE, Unpack[P]], T],
1977
+ ) -> EventCallback[Unpack[P]]:
1989
1978
  if background is True:
1990
- return background_event_decorator(func, __internal_reflex_call=True) # type: ignore
1991
- return func # type: ignore
1979
+ if not inspect.iscoroutinefunction(
1980
+ func
1981
+ ) and not inspect.isasyncgenfunction(func):
1982
+ raise TypeError(
1983
+ "Background task must be async function or generator."
1984
+ )
1985
+ setattr(func, BACKGROUND_TASK_MARKER, True)
1986
+ return func # pyright: ignore [reportReturnType]
1992
1987
 
1993
1988
  if func is not None:
1994
1989
  return wrapper(func)