reflex 0.6.8a2__py3-none-any.whl → 0.7.0a2__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 (246) 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 +249 -116
  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 +35 -6
  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 +160 -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/plotly.py +5 -5
  83. reflex/components/plotly/plotly.pyi +34 -44
  84. reflex/components/props.py +3 -3
  85. reflex/components/radix/__init__.pyi +1 -1
  86. reflex/components/radix/primitives/accordion.py +9 -5
  87. reflex/components/radix/primitives/accordion.pyi +110 -108
  88. reflex/components/radix/primitives/base.pyi +31 -31
  89. reflex/components/radix/primitives/drawer.py +5 -2
  90. reflex/components/radix/primitives/drawer.pyi +179 -187
  91. reflex/components/radix/primitives/form.pyi +160 -172
  92. reflex/components/radix/primitives/progress.py +1 -1
  93. reflex/components/radix/primitives/progress.pyi +76 -76
  94. reflex/components/radix/primitives/slider.py +1 -1
  95. reflex/components/radix/primitives/slider.pyi +78 -82
  96. reflex/components/radix/themes/base.pyi +121 -121
  97. reflex/components/radix/themes/color_mode.py +11 -9
  98. reflex/components/radix/themes/color_mode.pyi +47 -49
  99. reflex/components/radix/themes/components/alert_dialog.py +3 -0
  100. reflex/components/radix/themes/components/alert_dialog.pyi +110 -112
  101. reflex/components/radix/themes/components/aspect_ratio.pyi +16 -16
  102. reflex/components/radix/themes/components/avatar.pyi +16 -16
  103. reflex/components/radix/themes/components/badge.pyi +16 -16
  104. reflex/components/radix/themes/components/button.pyi +16 -16
  105. reflex/components/radix/themes/components/callout.pyi +76 -76
  106. reflex/components/radix/themes/components/card.py +1 -1
  107. reflex/components/radix/themes/components/card.pyi +17 -17
  108. reflex/components/radix/themes/components/checkbox.pyi +49 -55
  109. reflex/components/radix/themes/components/checkbox_cards.pyi +31 -31
  110. reflex/components/radix/themes/components/checkbox_group.pyi +31 -31
  111. reflex/components/radix/themes/components/context_menu.py +5 -0
  112. reflex/components/radix/themes/components/context_menu.pyi +149 -155
  113. reflex/components/radix/themes/components/data_list.pyi +61 -61
  114. reflex/components/radix/themes/components/dialog.py +3 -0
  115. reflex/components/radix/themes/components/dialog.pyi +113 -117
  116. reflex/components/radix/themes/components/dropdown_menu.py +5 -0
  117. reflex/components/radix/themes/components/dropdown_menu.pyi +133 -137
  118. reflex/components/radix/themes/components/hover_card.py +3 -0
  119. reflex/components/radix/themes/components/hover_card.pyi +63 -67
  120. reflex/components/radix/themes/components/icon_button.py +2 -2
  121. reflex/components/radix/themes/components/icon_button.pyi +17 -16
  122. reflex/components/radix/themes/components/inset.pyi +16 -16
  123. reflex/components/radix/themes/components/popover.py +3 -0
  124. reflex/components/radix/themes/components/popover.pyi +68 -70
  125. reflex/components/radix/themes/components/progress.pyi +16 -16
  126. reflex/components/radix/themes/components/radio.pyi +16 -16
  127. reflex/components/radix/themes/components/radio_cards.py +2 -0
  128. reflex/components/radix/themes/components/radio_cards.pyi +32 -34
  129. reflex/components/radix/themes/components/radio_group.py +1 -1
  130. reflex/components/radix/themes/components/radio_group.pyi +62 -64
  131. reflex/components/radix/themes/components/scroll_area.pyi +16 -16
  132. reflex/components/radix/themes/components/segmented_control.pyi +32 -35
  133. reflex/components/radix/themes/components/select.py +4 -0
  134. reflex/components/radix/themes/components/select.pyi +145 -157
  135. reflex/components/radix/themes/components/separator.pyi +16 -16
  136. reflex/components/radix/themes/components/skeleton.py +3 -0
  137. reflex/components/radix/themes/components/skeleton.pyi +16 -16
  138. reflex/components/radix/themes/components/slider.pyi +22 -28
  139. reflex/components/radix/themes/components/spinner.pyi +16 -16
  140. reflex/components/radix/themes/components/switch.pyi +17 -19
  141. reflex/components/radix/themes/components/table.pyi +106 -106
  142. reflex/components/radix/themes/components/tabs.py +3 -0
  143. reflex/components/radix/themes/components/tabs.pyi +78 -82
  144. reflex/components/radix/themes/components/text_area.py +12 -0
  145. reflex/components/radix/themes/components/text_area.pyi +21 -33
  146. reflex/components/radix/themes/components/text_field.py +1 -1
  147. reflex/components/radix/themes/components/text_field.pyi +52 -80
  148. reflex/components/radix/themes/components/tooltip.py +6 -1
  149. reflex/components/radix/themes/components/tooltip.pyi +20 -21
  150. reflex/components/radix/themes/layout/__init__.pyi +1 -1
  151. reflex/components/radix/themes/layout/base.pyi +16 -16
  152. reflex/components/radix/themes/layout/box.pyi +16 -16
  153. reflex/components/radix/themes/layout/center.pyi +16 -16
  154. reflex/components/radix/themes/layout/container.pyi +16 -16
  155. reflex/components/radix/themes/layout/flex.pyi +16 -16
  156. reflex/components/radix/themes/layout/grid.pyi +16 -16
  157. reflex/components/radix/themes/layout/list.py +2 -2
  158. reflex/components/radix/themes/layout/list.pyi +76 -76
  159. reflex/components/radix/themes/layout/section.pyi +16 -16
  160. reflex/components/radix/themes/layout/spacer.pyi +16 -16
  161. reflex/components/radix/themes/layout/stack.py +2 -2
  162. reflex/components/radix/themes/layout/stack.pyi +46 -46
  163. reflex/components/radix/themes/typography/blockquote.pyi +16 -16
  164. reflex/components/radix/themes/typography/code.pyi +16 -16
  165. reflex/components/radix/themes/typography/heading.pyi +16 -16
  166. reflex/components/radix/themes/typography/link.py +1 -1
  167. reflex/components/radix/themes/typography/link.pyi +16 -16
  168. reflex/components/radix/themes/typography/text.py +2 -2
  169. reflex/components/radix/themes/typography/text.pyi +106 -106
  170. reflex/components/react_player/audio.pyi +33 -39
  171. reflex/components/react_player/react_player.py +1 -1
  172. reflex/components/react_player/react_player.pyi +32 -38
  173. reflex/components/react_player/video.pyi +33 -39
  174. reflex/components/recharts/__init__.py +2 -0
  175. reflex/components/recharts/__init__.pyi +2 -0
  176. reflex/components/recharts/cartesian.pyi +282 -282
  177. reflex/components/recharts/charts.py +15 -15
  178. reflex/components/recharts/charts.pyi +164 -164
  179. reflex/components/recharts/general.py +19 -4
  180. reflex/components/recharts/general.pyi +132 -81
  181. reflex/components/recharts/polar.py +2 -2
  182. reflex/components/recharts/polar.pyi +55 -55
  183. reflex/components/recharts/recharts.py +4 -4
  184. reflex/components/recharts/recharts.pyi +31 -31
  185. reflex/components/sonner/toast.py +15 -13
  186. reflex/components/sonner/toast.pyi +22 -22
  187. reflex/components/suneditor/editor.py +6 -4
  188. reflex/components/suneditor/editor.pyi +26 -40
  189. reflex/components/tags/iter_tag.py +3 -3
  190. reflex/components/tags/tag.py +25 -3
  191. reflex/config.py +48 -15
  192. reflex/constants/__init__.py +1 -0
  193. reflex/constants/base.py +4 -1
  194. reflex/constants/compiler.py +5 -2
  195. reflex/constants/config.py +8 -1
  196. reflex/constants/installer.py +9 -9
  197. reflex/constants/style.py +1 -1
  198. reflex/custom_components/custom_components.py +9 -7
  199. reflex/event.py +215 -208
  200. reflex/experimental/__init__.py +19 -11
  201. reflex/experimental/client_state.py +53 -28
  202. reflex/experimental/hooks.py +5 -5
  203. reflex/experimental/layout.py +8 -5
  204. reflex/experimental/layout.pyi +79 -83
  205. reflex/experimental/misc.py +3 -3
  206. reflex/istate/wrappers.py +1 -1
  207. reflex/middleware/hydrate_middleware.py +2 -2
  208. reflex/model.py +11 -6
  209. reflex/page.py +5 -5
  210. reflex/reflex.py +90 -19
  211. reflex/route.py +1 -1
  212. reflex/state.py +358 -401
  213. reflex/style.py +27 -3
  214. reflex/testing.py +29 -23
  215. reflex/utils/build.py +6 -2
  216. reflex/utils/codespaces.py +1 -4
  217. reflex/utils/compat.py +6 -5
  218. reflex/utils/console.py +52 -16
  219. reflex/utils/exceptions.py +89 -26
  220. reflex/utils/exec.py +69 -74
  221. reflex/utils/export.py +6 -1
  222. reflex/utils/format.py +8 -40
  223. reflex/utils/imports.py +2 -2
  224. reflex/utils/lazy_loader.py +7 -1
  225. reflex/utils/path_ops.py +28 -14
  226. reflex/utils/prerequisites.py +326 -67
  227. reflex/utils/processes.py +45 -32
  228. reflex/utils/pyi_generator.py +39 -33
  229. reflex/utils/registry.py +4 -4
  230. reflex/utils/serializers.py +1 -1
  231. reflex/utils/telemetry.py +5 -4
  232. reflex/utils/types.py +42 -18
  233. reflex/vars/base.py +656 -333
  234. reflex/vars/datetime.py +6 -7
  235. reflex/vars/dep_tracking.py +344 -0
  236. reflex/vars/function.py +11 -5
  237. reflex/vars/number.py +31 -43
  238. reflex/vars/object.py +63 -62
  239. reflex/vars/sequence.py +79 -67
  240. {reflex-0.6.8a2.dist-info → reflex-0.7.0a2.dist-info}/METADATA +7 -8
  241. reflex-0.7.0a2.dist-info/RECORD +401 -0
  242. {reflex-0.6.8a2.dist-info → reflex-0.7.0a2.dist-info}/WHEEL +1 -1
  243. reflex/experimental/assets.py +0 -37
  244. reflex-0.6.8a2.dist-info/RECORD +0 -397
  245. {reflex-0.6.8a2.dist-info → reflex-0.7.0a2.dist-info}/LICENSE +0 -0
  246. {reflex-0.6.8a2.dist-info → reflex-0.7.0a2.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,26 @@ 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,
33
29
  TypeAliasType,
34
30
  TypedDict,
35
31
  TypeVar,
32
+ TypeVarTuple,
33
+ Unpack,
36
34
  get_args,
37
35
  get_origin,
38
36
  )
39
37
 
40
38
  from reflex import constants
39
+ from reflex.constants.compiler import CompileVars, Hooks, Imports
41
40
  from reflex.constants.state import FRONTEND_EVENT_STATE
42
41
  from reflex.utils import console, format
43
- from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgTypeMismatch
42
+ from reflex.utils.exceptions import (
43
+ EventFnArgMismatchError,
44
+ EventHandlerArgTypeMismatchError,
45
+ MissingAnnotationError,
46
+ )
44
47
  from reflex.utils.types import ArgsSpec, GenericType, typehint_issubclass
45
48
  from reflex.vars import VarData
46
49
  from reflex.vars.base import LiteralVar, Var
@@ -91,33 +94,9 @@ class Event:
91
94
  return f"{self.token}_{substate}"
92
95
 
93
96
 
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
-
97
+ _EVENT_FIELDS: set[str] = {f.name for f in dataclasses.fields(Event)}
106
98
 
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
99
+ BACKGROUND_TASK_MARKER = "_reflex_background_task"
121
100
 
122
101
 
123
102
  @dataclasses.dataclass(
@@ -264,7 +243,7 @@ class EventHandler(EventActionsMixin):
264
243
  raise EventHandlerTypeError(
265
244
  f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
266
245
  ) from e
267
- payload = tuple(zip(fn_args, values))
246
+ payload = tuple(zip(fn_args, values, strict=False))
268
247
 
269
248
  # Return the event spec.
270
249
  return EventSpec(
@@ -284,7 +263,7 @@ class EventSpec(EventActionsMixin):
284
263
  """
285
264
 
286
265
  # The event handler.
287
- handler: EventHandler = dataclasses.field(default=None) # type: ignore
266
+ handler: EventHandler = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
288
267
 
289
268
  # The handler on the client to process event.
290
269
  client_handler_name: str = dataclasses.field(default="")
@@ -353,12 +332,12 @@ class EventSpec(EventActionsMixin):
353
332
  arg = None
354
333
  try:
355
334
  for arg in args:
356
- values.append(LiteralVar.create(value=arg)) # noqa: PERF401
335
+ values.append(LiteralVar.create(value=arg)) # noqa: PERF401, RUF100
357
336
  except TypeError as e:
358
337
  raise EventHandlerTypeError(
359
338
  f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
360
339
  ) from e
361
- new_payload = tuple(zip(fn_args, values))
340
+ new_payload = tuple(zip(fn_args, values, strict=False))
362
341
  return self.with_args(self.args + new_payload)
363
342
 
364
343
 
@@ -555,13 +534,13 @@ class JavasciptKeyboardEvent:
555
534
  """Interface for a Javascript KeyboardEvent https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent."""
556
535
 
557
536
  key: str = ""
558
- altKey: bool = False
559
- ctrlKey: bool = False
560
- metaKey: bool = False
561
- shiftKey: bool = False
537
+ altKey: bool = False # noqa: N815
538
+ ctrlKey: bool = False # noqa: N815
539
+ metaKey: bool = False # noqa: N815
540
+ shiftKey: bool = False # noqa: N815
562
541
 
563
542
 
564
- def input_event(e: Var[JavascriptInputEvent]) -> Tuple[Var[str]]:
543
+ def input_event(e: ObjectVar[JavascriptInputEvent]) -> Tuple[Var[str]]:
565
544
  """Get the value from an input event.
566
545
 
567
546
  Args:
@@ -582,7 +561,9 @@ class KeyInputInfo(TypedDict):
582
561
  shift_key: bool
583
562
 
584
563
 
585
- def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str], Var[KeyInputInfo]]:
564
+ def key_event(
565
+ e: ObjectVar[JavasciptKeyboardEvent],
566
+ ) -> Tuple[Var[str], Var[KeyInputInfo]]:
586
567
  """Get the key from a keyboard event.
587
568
 
588
569
  Args:
@@ -592,7 +573,7 @@ def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str], Var[KeyInputInf
592
573
  The key from the keyboard event.
593
574
  """
594
575
  return (
595
- e.key,
576
+ e.key.to(str),
596
577
  Var.create(
597
578
  {
598
579
  "alt_key": e.altKey,
@@ -600,7 +581,7 @@ def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str], Var[KeyInputInf
600
581
  "meta_key": e.metaKey,
601
582
  "shift_key": e.shiftKey,
602
583
  },
603
- ),
584
+ ).to(KeyInputInfo),
604
585
  )
605
586
 
606
587
 
@@ -610,7 +591,7 @@ def no_args_event_spec() -> Tuple[()]:
610
591
  Returns:
611
592
  An empty tuple.
612
593
  """
613
- return () # type: ignore
594
+ return ()
614
595
 
615
596
 
616
597
  # These chains can be used for their side effects when no other events are desired.
@@ -638,9 +619,9 @@ class IdentityEventReturn(Generic[T], Protocol):
638
619
 
639
620
 
640
621
  @overload
641
- def passthrough_event_spec(
622
+ def passthrough_event_spec( # pyright: ignore [reportOverlappingOverload]
642
623
  event_type: Type[T], /
643
- ) -> Callable[[Var[T]], Tuple[Var[T]]]: ... # type: ignore
624
+ ) -> Callable[[Var[T]], Tuple[Var[T]]]: ...
644
625
 
645
626
 
646
627
  @overload
@@ -653,7 +634,7 @@ def passthrough_event_spec(
653
634
  def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: ...
654
635
 
655
636
 
656
- def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: # type: ignore
637
+ def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: # pyright: ignore [reportInconsistentOverload]
657
638
  """A helper function that returns the input event as output.
658
639
 
659
640
  Args:
@@ -667,9 +648,9 @@ def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: #
667
648
  return values
668
649
 
669
650
  inner_type = tuple(Var[event_type] for event_type in event_types)
670
- return_annotation = Tuple[inner_type] # type: ignore
651
+ return_annotation = Tuple[inner_type]
671
652
 
672
- inner.__signature__ = inspect.signature(inner).replace( # type: ignore
653
+ inner.__signature__ = inspect.signature(inner).replace( # pyright: ignore [reportFunctionMemberAccess]
673
654
  parameters=[
674
655
  inspect.Parameter(
675
656
  f"ev_{i}",
@@ -751,7 +732,7 @@ class FileUpload:
751
732
  # Call the lambda to get the event chain.
752
733
  events = call_event_fn(
753
734
  on_upload_progress, self.on_upload_progress_args_spec
754
- ) # type: ignore
735
+ )
755
736
  else:
756
737
  raise ValueError(f"{on_upload_progress} is not a valid event handler.")
757
738
  if isinstance(events, Var):
@@ -798,7 +779,7 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
798
779
  return None
799
780
 
800
781
  fn.__qualname__ = name
801
- fn.__signature__ = sig
782
+ fn.__signature__ = sig # pyright: ignore [reportFunctionMemberAccess]
802
783
  return EventSpec(
803
784
  handler=EventHandler(fn=fn, state_full_name=FRONTEND_EVENT_STATE),
804
785
  args=tuple(
@@ -811,29 +792,10 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
811
792
  )
812
793
 
813
794
 
814
- @overload
815
- def redirect(
816
- path: str | Var[str],
817
- is_external: Optional[bool] = None,
818
- replace: bool = False,
819
- ) -> EventSpec: ...
820
-
821
-
822
- @overload
823
- @typing_extensions.deprecated("`external` is deprecated use `is_external` instead")
824
- def redirect(
825
- path: str | Var[str],
826
- is_external: Optional[bool] = None,
827
- replace: bool = False,
828
- external: Optional[bool] = None,
829
- ) -> EventSpec: ...
830
-
831
-
832
795
  def redirect(
833
796
  path: str | Var[str],
834
- is_external: Optional[bool] = None,
797
+ is_external: bool = False,
835
798
  replace: bool = False,
836
- external: Optional[bool] = None,
837
799
  ) -> EventSpec:
838
800
  """Redirect to a new path.
839
801
 
@@ -841,26 +803,10 @@ def redirect(
841
803
  path: The path to redirect to.
842
804
  is_external: Whether to open in new tab or not.
843
805
  replace: If True, the current page will not create a new history entry.
844
- external(Deprecated): Whether to open in new tab or not.
845
806
 
846
807
  Returns:
847
808
  An event to redirect to the path.
848
809
  """
849
- if external is not None:
850
- console.deprecate(
851
- "The `external` prop in `rx.redirect`",
852
- "use `is_external` instead.",
853
- "0.6.6",
854
- "0.7.0",
855
- )
856
-
857
- # is_external should take precedence over external.
858
- is_external = (
859
- (False if external is None else external)
860
- if is_external is None
861
- else is_external
862
- )
863
-
864
810
  return server_side(
865
811
  "_redirect",
866
812
  get_fn_signature(redirect),
@@ -1106,13 +1052,13 @@ def download(
1106
1052
 
1107
1053
  is_data_url = (data.js_type() == "string") & (
1108
1054
  data.to(str).startswith("data:")
1109
- ) # type: ignore
1055
+ )
1110
1056
 
1111
1057
  # If it's a data: URI, use it as is, otherwise convert the Var to JSON in a data: URI.
1112
- url = cond( # type: ignore
1058
+ url = cond(
1113
1059
  is_data_url,
1114
1060
  data.to(str),
1115
- "data:text/plain," + data.to_string(), # type: ignore
1061
+ "data:text/plain," + data.to_string(),
1116
1062
  )
1117
1063
  elif isinstance(data, bytes):
1118
1064
  # Caller provided bytes, so base64 encode it as a data: URI.
@@ -1131,7 +1077,8 @@ def download(
1131
1077
  )
1132
1078
 
1133
1079
 
1134
- def _callback_arg_spec(eval_result):
1080
+ # This function seems unused. Check if we still need it. If not, remove in 0.7.0
1081
+ def _callback_arg_spec(eval_result: Any):
1135
1082
  """ArgSpec for call_script callback function.
1136
1083
 
1137
1084
  Args:
@@ -1145,7 +1092,7 @@ def _callback_arg_spec(eval_result):
1145
1092
 
1146
1093
  def call_script(
1147
1094
  javascript_code: str | Var[str],
1148
- callback: EventType | None = None,
1095
+ callback: EventType[Any] | None = None,
1149
1096
  ) -> EventSpec:
1150
1097
  """Create an event handler that executes arbitrary javascript code.
1151
1098
 
@@ -1184,7 +1131,7 @@ def call_script(
1184
1131
 
1185
1132
  def call_function(
1186
1133
  javascript_code: str | Var,
1187
- callback: EventType | None = None,
1134
+ callback: EventType[Any] | None = None,
1188
1135
  ) -> EventSpec:
1189
1136
  """Create an event handler that executes arbitrary javascript code.
1190
1137
 
@@ -1218,7 +1165,7 @@ def call_function(
1218
1165
 
1219
1166
  def run_script(
1220
1167
  javascript_code: str | Var,
1221
- callback: EventType | None = None,
1168
+ callback: EventType[Any] | None = None,
1222
1169
  ) -> EventSpec:
1223
1170
  """Create an event handler that executes arbitrary javascript code.
1224
1171
 
@@ -1236,7 +1183,7 @@ def run_script(
1236
1183
  return call_function(ArgsFunctionOperation.create((), javascript_code), callback)
1237
1184
 
1238
1185
 
1239
- def get_event(state, event):
1186
+ def get_event(state: BaseState, event: str):
1240
1187
  """Get the event from the given state.
1241
1188
 
1242
1189
  Args:
@@ -1249,7 +1196,7 @@ def get_event(state, event):
1249
1196
  return f"{state.get_name()}.{event}"
1250
1197
 
1251
1198
 
1252
- def get_hydrate_event(state) -> str:
1199
+ def get_hydrate_event(state: BaseState) -> str:
1253
1200
  """Get the name of the hydrate event for the state.
1254
1201
 
1255
1202
  Args:
@@ -1277,13 +1224,16 @@ def call_event_handler(
1277
1224
  event_spec: The lambda that define the argument(s) to pass to the event handler.
1278
1225
  key: The key to pass to the event handler.
1279
1226
 
1227
+ Raises:
1228
+ EventHandlerArgTypeMismatchError: If the event handler arguments do not match the event spec. #noqa: DAR402
1229
+ TypeError: If the event handler arguments are invalid.
1230
+
1280
1231
  Returns:
1281
1232
  The event spec from calling the event handler.
1282
1233
 
1283
- # noqa: DAR401 failure
1284
-
1234
+ #noqa: DAR401
1285
1235
  """
1286
- event_spec_args = parse_args_spec(event_spec) # type: ignore
1236
+ event_spec_args = parse_args_spec(event_spec)
1287
1237
 
1288
1238
  if isinstance(event_callback, EventSpec):
1289
1239
  check_fn_match_arg_spec(
@@ -1318,10 +1268,15 @@ def call_event_handler(
1318
1268
  ),
1319
1269
  )
1320
1270
  )
1271
+ type_match_found: dict[str, bool] = {}
1272
+ delayed_exceptions: list[EventHandlerArgTypeMismatchError] = []
1321
1273
 
1322
- if event_spec_return_types:
1323
- failures = []
1274
+ try:
1275
+ type_hints_of_provided_callback = get_type_hints(event_callback.fn)
1276
+ except NameError:
1277
+ type_hints_of_provided_callback = {}
1324
1278
 
1279
+ if event_spec_return_types:
1325
1280
  event_callback_spec = inspect.getfullargspec(event_callback.fn)
1326
1281
 
1327
1282
  for event_spec_index, event_spec_return_type in enumerate(
@@ -1333,43 +1288,35 @@ def call_event_handler(
1333
1288
  arg if get_origin(arg) is not Var else get_args(arg)[0] for arg in args
1334
1289
  ]
1335
1290
 
1336
- try:
1337
- type_hints_of_provided_callback = get_type_hints(event_callback.fn)
1338
- except NameError:
1339
- type_hints_of_provided_callback = {}
1340
-
1341
- failed_type_check = False
1342
-
1343
1291
  # check that args of event handler are matching the spec if type hints are provided
1344
1292
  for i, arg in enumerate(event_callback_spec.args[1:]):
1345
1293
  if arg not in type_hints_of_provided_callback:
1346
1294
  continue
1347
1295
 
1296
+ type_match_found.setdefault(arg, False)
1297
+
1348
1298
  try:
1349
1299
  compare_result = typehint_issubclass(
1350
1300
  args_types_without_vars[i], type_hints_of_provided_callback[arg]
1351
1301
  )
1352
- except TypeError:
1353
- # TODO: In 0.7.0, remove this block and raise the exception
1354
- # raise TypeError(
1355
- # 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
1356
- # ) from e
1357
- console.warn(
1302
+ except TypeError as te:
1303
+ raise TypeError(
1358
1304
  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}."
1359
- )
1360
- compare_result = False
1305
+ ) from te
1361
1306
 
1362
1307
  if compare_result:
1308
+ type_match_found[arg] = True
1363
1309
  continue
1364
1310
  else:
1365
- failure = EventHandlerArgTypeMismatch(
1366
- 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."
1311
+ type_match_found[arg] = False
1312
+ delayed_exceptions.append(
1313
+ EventHandlerArgTypeMismatchError(
1314
+ 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."
1315
+ )
1367
1316
  )
1368
- failures.append(failure)
1369
- failed_type_check = True
1370
- break
1371
1317
 
1372
- if not failed_type_check:
1318
+ if all(type_match_found.values()):
1319
+ delayed_exceptions.clear()
1373
1320
  if event_spec_index:
1374
1321
  args = get_args(event_spec_return_types[0])
1375
1322
 
@@ -1391,17 +1338,12 @@ def call_event_handler(
1391
1338
  f"Event handler {key} expects ({expect_string}) -> () but got ({given_string}) -> () as annotated in {event_callback.fn.__qualname__} instead. "
1392
1339
  f"This may lead to unexpected behavior but is intentionally ignored for {key}."
1393
1340
  )
1394
- return event_callback(*event_spec_args)
1395
-
1396
- if failures:
1397
- console.deprecate(
1398
- "Mismatched event handler argument types",
1399
- "\n".join([str(f) for f in failures]),
1400
- "0.6.5",
1401
- "0.7.0",
1402
- )
1341
+ break
1342
+
1343
+ if delayed_exceptions:
1344
+ raise delayed_exceptions[0]
1403
1345
 
1404
- return event_callback(*event_spec_args) # type: ignore
1346
+ return event_callback(*event_spec_args)
1405
1347
 
1406
1348
 
1407
1349
  def unwrap_var_annotation(annotation: GenericType):
@@ -1413,31 +1355,31 @@ def unwrap_var_annotation(annotation: GenericType):
1413
1355
  Returns:
1414
1356
  The unwrapped annotation.
1415
1357
  """
1416
- if get_origin(annotation) is Var and (args := get_args(annotation)):
1358
+ if get_origin(annotation) in (Var, ObjectVar) and (args := get_args(annotation)):
1417
1359
  return args[0]
1418
1360
  return annotation
1419
1361
 
1420
1362
 
1421
- def resolve_annotation(annotations: dict[str, Any], arg_name: str):
1363
+ def resolve_annotation(annotations: dict[str, Any], arg_name: str, spec: ArgsSpec):
1422
1364
  """Resolve the annotation for the given argument name.
1423
1365
 
1424
1366
  Args:
1425
1367
  annotations: The annotations.
1426
1368
  arg_name: The argument name.
1369
+ spec: The specs which the annotations come from.
1370
+
1371
+ Raises:
1372
+ MissingAnnotationError: If the annotation is missing for non-lambda methods.
1427
1373
 
1428
1374
  Returns:
1429
1375
  The resolved annotation.
1430
1376
  """
1431
1377
  annotation = annotations.get(arg_name)
1432
1378
  if annotation is None:
1433
- console.deprecate(
1434
- feature_name="Unannotated event handler arguments",
1435
- reason="Provide type annotations for event handler arguments.",
1436
- deprecation_version="0.6.3",
1437
- removal_version="0.7.0",
1438
- )
1439
- # Allow arbitrary attribute access two levels deep until removed.
1440
- return Dict[str, dict]
1379
+ if not isinstance(spec, types.LambdaType):
1380
+ raise MissingAnnotationError(var_name=arg_name)
1381
+ else:
1382
+ return dict[str, dict]
1441
1383
  return annotation
1442
1384
 
1443
1385
 
@@ -1459,7 +1401,13 @@ def parse_args_spec(arg_spec: ArgsSpec | Sequence[ArgsSpec]):
1459
1401
  arg_spec(
1460
1402
  *[
1461
1403
  Var(f"_{l_arg}").to(
1462
- unwrap_var_annotation(resolve_annotation(annotations, l_arg))
1404
+ unwrap_var_annotation(
1405
+ resolve_annotation(
1406
+ annotations,
1407
+ l_arg,
1408
+ spec=arg_spec,
1409
+ )
1410
+ )
1463
1411
  )
1464
1412
  for l_arg in spec.args
1465
1413
  ]
@@ -1475,7 +1423,7 @@ def check_fn_match_arg_spec(
1475
1423
  func_name: str | None = None,
1476
1424
  ):
1477
1425
  """Ensures that the function signature matches the passed argument specification
1478
- or raises an EventFnArgMismatch if they do not.
1426
+ or raises an EventFnArgMismatchError if they do not.
1479
1427
 
1480
1428
  Args:
1481
1429
  user_func: The function to be validated.
@@ -1485,7 +1433,7 @@ def check_fn_match_arg_spec(
1485
1433
  func_name: The name of the function to be validated.
1486
1434
 
1487
1435
  Raises:
1488
- EventFnArgMismatch: Raised if the number of mandatory arguments do not match
1436
+ EventFnArgMismatchError: Raised if the number of mandatory arguments do not match
1489
1437
  """
1490
1438
  user_args = inspect.getfullargspec(user_func).args
1491
1439
  # Drop the first argument if it's a bound method
@@ -1501,7 +1449,7 @@ def check_fn_match_arg_spec(
1501
1449
  number_of_event_args = len(parsed_event_args)
1502
1450
 
1503
1451
  if number_of_user_args - number_of_user_default_args > number_of_event_args:
1504
- raise EventFnArgMismatch(
1452
+ raise EventFnArgMismatchError(
1505
1453
  f"Event {key} only provides {number_of_event_args} arguments, but "
1506
1454
  f"{func_name or user_func} requires at least {number_of_user_args - number_of_user_default_args} "
1507
1455
  "arguments to be passed to the event handler.\n"
@@ -1589,7 +1537,7 @@ def get_handler_args(
1589
1537
 
1590
1538
 
1591
1539
  def fix_events(
1592
- events: list[EventHandler | EventSpec] | None,
1540
+ events: list[EventSpec | EventHandler] | None,
1593
1541
  token: str,
1594
1542
  router_data: dict[str, Any] | None = None,
1595
1543
  ) -> list[Event]:
@@ -1629,7 +1577,7 @@ def fix_events(
1629
1577
  if not isinstance(e, EventSpec):
1630
1578
  raise ValueError(f"Unexpected event type, {type(e)}.")
1631
1579
  name = format.format_event_handler(e.handler)
1632
- payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore
1580
+ payload = {k._js_expr: v._decode() for k, v in e.args}
1633
1581
 
1634
1582
  # Filter router_data to reduce payload size
1635
1583
  event_router_data = {
@@ -1673,12 +1621,12 @@ class EventVar(ObjectVar, python_types=EventSpec):
1673
1621
  @dataclasses.dataclass(
1674
1622
  eq=False,
1675
1623
  frozen=True,
1676
- **{"slots": True} if sys.version_info >= (3, 10) else {},
1624
+ slots=True,
1677
1625
  )
1678
1626
  class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
1679
1627
  """A literal event var."""
1680
1628
 
1681
- _var_value: EventSpec = dataclasses.field(default=None) # type: ignore
1629
+ _var_value: EventSpec = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
1682
1630
 
1683
1631
  def __hash__(self) -> int:
1684
1632
  """Get the hash of the var.
@@ -1734,7 +1682,7 @@ class EventChainVar(BuilderFunctionVar, python_types=EventChain):
1734
1682
  @dataclasses.dataclass(
1735
1683
  eq=False,
1736
1684
  frozen=True,
1737
- **{"slots": True} if sys.version_info >= (3, 10) else {},
1685
+ slots=True,
1738
1686
  )
1739
1687
  # Note: LiteralVar is second in the inheritance list allowing it act like a
1740
1688
  # CachedVarOperation (ArgsFunctionOperation) and get the _js_expr from the
@@ -1742,7 +1690,7 @@ class EventChainVar(BuilderFunctionVar, python_types=EventChain):
1742
1690
  class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainVar):
1743
1691
  """A literal event chain var."""
1744
1692
 
1745
- _var_value: EventChain = dataclasses.field(default=None) # type: ignore
1693
+ _var_value: EventChain = dataclasses.field(default=None) # pyright: ignore [reportAssignmentType]
1746
1694
 
1747
1695
  def __hash__(self) -> int:
1748
1696
  """Get the hash of the var.
@@ -1766,13 +1714,16 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
1766
1714
 
1767
1715
  Returns:
1768
1716
  The created LiteralEventChainVar instance.
1717
+
1718
+ Raises:
1719
+ ValueError: If the invocation is not a FunctionVar.
1769
1720
  """
1770
1721
  arg_spec = (
1771
1722
  value.args_spec[0]
1772
1723
  if isinstance(value.args_spec, Sequence)
1773
1724
  else value.args_spec
1774
1725
  )
1775
- sig = inspect.signature(arg_spec) # type: ignore
1726
+ sig = inspect.signature(arg_spec) # pyright: ignore [reportArgumentType]
1776
1727
  if sig.parameters:
1777
1728
  arg_def = tuple((f"_{p}" for p in sig.parameters))
1778
1729
  arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
@@ -1783,10 +1734,21 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
1783
1734
  arg_def_expr = Var(_js_expr="args")
1784
1735
 
1785
1736
  if value.invocation is None:
1786
- invocation = FunctionStringVar.create("addEvents")
1737
+ invocation = FunctionStringVar.create(
1738
+ CompileVars.ADD_EVENTS,
1739
+ _var_data=VarData(
1740
+ imports=Imports.EVENTS,
1741
+ hooks={Hooks.EVENTS: None},
1742
+ ),
1743
+ )
1787
1744
  else:
1788
1745
  invocation = value.invocation
1789
1746
 
1747
+ if invocation is not None and not isinstance(invocation, FunctionVar):
1748
+ raise ValueError(
1749
+ f"EventChain invocation must be a FunctionVar, got {invocation!s} of type {invocation._var_type!s}."
1750
+ )
1751
+
1790
1752
  return cls(
1791
1753
  _js_expr="",
1792
1754
  _var_type=EventChain,
@@ -1801,8 +1763,8 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
1801
1763
  )
1802
1764
 
1803
1765
 
1804
- P = ParamSpec("P")
1805
- Q = ParamSpec("Q")
1766
+ P = TypeVarTuple("P")
1767
+ Q = TypeVarTuple("Q")
1806
1768
  T = TypeVar("T")
1807
1769
  V = TypeVar("V")
1808
1770
  V2 = TypeVar("V2")
@@ -1810,13 +1772,11 @@ V3 = TypeVar("V3")
1810
1772
  V4 = TypeVar("V4")
1811
1773
  V5 = TypeVar("V5")
1812
1774
 
1813
- background_event_decorator = background
1814
1775
 
1815
-
1816
- class EventCallback(Generic[P, T]):
1776
+ class EventCallback(Generic[Unpack[P]]):
1817
1777
  """A descriptor that wraps a function to be used as an event."""
1818
1778
 
1819
- def __init__(self, func: Callable[Concatenate[Any, P], T]):
1779
+ def __init__(self, func: Callable[[Any, Unpack[P]], Any]):
1820
1780
  """Initialize the descriptor with the function to be wrapped.
1821
1781
 
1822
1782
  Args:
@@ -1844,39 +1804,39 @@ class EventCallback(Generic[P, T]):
1844
1804
 
1845
1805
  @overload
1846
1806
  def __call__(
1847
- self: EventCallback[Q, T],
1848
- ) -> EventCallback[Q, T]: ...
1807
+ self: EventCallback[Unpack[Q]],
1808
+ ) -> EventCallback[Unpack[Q]]: ...
1849
1809
 
1850
1810
  @overload
1851
1811
  def __call__(
1852
- self: EventCallback[Concatenate[V, Q], T], value: V | Var[V]
1853
- ) -> EventCallback[Q, T]: ...
1812
+ self: EventCallback[V, Unpack[Q]], value: V | Var[V]
1813
+ ) -> EventCallback[Unpack[Q]]: ...
1854
1814
 
1855
1815
  @overload
1856
1816
  def __call__(
1857
- self: EventCallback[Concatenate[V, V2, Q], T],
1817
+ self: EventCallback[V, V2, Unpack[Q]],
1858
1818
  value: V | Var[V],
1859
1819
  value2: V2 | Var[V2],
1860
- ) -> EventCallback[Q, T]: ...
1820
+ ) -> EventCallback[Unpack[Q]]: ...
1861
1821
 
1862
1822
  @overload
1863
1823
  def __call__(
1864
- self: EventCallback[Concatenate[V, V2, V3, Q], T],
1824
+ self: EventCallback[V, V2, V3, Unpack[Q]],
1865
1825
  value: V | Var[V],
1866
1826
  value2: V2 | Var[V2],
1867
1827
  value3: V3 | Var[V3],
1868
- ) -> EventCallback[Q, T]: ...
1828
+ ) -> EventCallback[Unpack[Q]]: ...
1869
1829
 
1870
1830
  @overload
1871
1831
  def __call__(
1872
- self: EventCallback[Concatenate[V, V2, V3, V4, Q], T],
1832
+ self: EventCallback[V, V2, V3, V4, Unpack[Q]],
1873
1833
  value: V | Var[V],
1874
1834
  value2: V2 | Var[V2],
1875
1835
  value3: V3 | Var[V3],
1876
1836
  value4: V4 | Var[V4],
1877
- ) -> EventCallback[Q, T]: ...
1837
+ ) -> EventCallback[Unpack[Q]]: ...
1878
1838
 
1879
- def __call__(self, *values) -> EventCallback: # type: ignore
1839
+ def __call__(self, *values) -> EventCallback: # pyright: ignore [reportInconsistentOverload]
1880
1840
  """Call the function with the values.
1881
1841
 
1882
1842
  Args:
@@ -1885,17 +1845,17 @@ class EventCallback(Generic[P, T]):
1885
1845
  Returns:
1886
1846
  The function with the values.
1887
1847
  """
1888
- return self.func(*values) # type: ignore
1848
+ return self.func(*values) # pyright: ignore [reportArgumentType]
1889
1849
 
1890
1850
  @overload
1891
1851
  def __get__(
1892
- self: EventCallback[P, T], instance: None, owner
1893
- ) -> EventCallback[P, T]: ...
1852
+ self: EventCallback[Unpack[P]], instance: None, owner: Any
1853
+ ) -> EventCallback[Unpack[P]]: ...
1894
1854
 
1895
1855
  @overload
1896
- def __get__(self, instance, owner) -> Callable[P, T]: ...
1856
+ def __get__(self, instance: Any, owner: Any) -> Callable[[Unpack[P]]]: ...
1897
1857
 
1898
- def __get__(self, instance, owner) -> Callable: # type: ignore
1858
+ def __get__(self, instance: Any, owner: Any) -> Callable:
1899
1859
  """Get the function with the instance bound to it.
1900
1860
 
1901
1861
  Args:
@@ -1906,38 +1866,74 @@ class EventCallback(Generic[P, T]):
1906
1866
  The function with the instance bound to it
1907
1867
  """
1908
1868
  if instance is None:
1909
- return self.func # type: ignore
1869
+ return self.func
1910
1870
 
1911
- return partial(self.func, instance) # type: ignore
1871
+ return partial(self.func, instance)
1912
1872
 
1913
1873
 
1914
- G = ParamSpec("G")
1874
+ class LambdaEventCallback(Protocol[Unpack[P]]):
1875
+ """A protocol for a lambda event callback."""
1915
1876
 
1916
- if TYPE_CHECKING:
1917
- from reflex.state import BaseState
1877
+ @overload
1878
+ def __call__(self: LambdaEventCallback[()]) -> Any: ...
1918
1879
 
1919
- BASE_STATE = TypeVar("BASE_STATE", bound=BaseState)
1920
- else:
1921
- BASE_STATE = TypeVar("BASE_STATE")
1880
+ @overload
1881
+ def __call__(self: LambdaEventCallback[V], value: Var[V], /) -> Any: ...
1882
+
1883
+ @overload
1884
+ def __call__(
1885
+ self: LambdaEventCallback[V, V2], value: Var[V], value2: Var[V2], /
1886
+ ) -> Any: ...
1887
+
1888
+ @overload
1889
+ def __call__(
1890
+ self: LambdaEventCallback[V, V2, V3],
1891
+ value: Var[V],
1892
+ value2: Var[V2],
1893
+ value3: Var[V3],
1894
+ /,
1895
+ ) -> Any: ...
1896
+
1897
+ def __call__(self, *args: Var) -> Any:
1898
+ """Call the lambda with the args.
1899
+
1900
+ Args:
1901
+ *args: The args to call the lambda with.
1902
+ """
1903
+
1904
+
1905
+ ARGS = TypeVarTuple("ARGS")
1906
+
1907
+
1908
+ LAMBDA_OR_STATE = TypeAliasType(
1909
+ "LAMBDA_OR_STATE",
1910
+ LambdaEventCallback[Unpack[ARGS]] | EventCallback[Unpack[ARGS]],
1911
+ type_params=(ARGS,),
1912
+ )
1913
+
1914
+ ItemOrList = V | List[V]
1922
1915
 
1923
- StateCallable = TypeAliasType(
1924
- "StateCallable",
1925
- Callable[Concatenate[BASE_STATE, G], Any],
1926
- type_params=(G, BASE_STATE),
1916
+ BASIC_EVENT_TYPES = TypeAliasType(
1917
+ "BASIC_EVENT_TYPES", EventSpec | EventHandler | Var[Any], type_params=()
1927
1918
  )
1928
1919
 
1929
- IndividualEventType = Union[
1930
- EventSpec,
1931
- EventHandler,
1932
- Callable[G, Any],
1933
- StateCallable[G, BASE_STATE],
1934
- EventCallback[G, Any],
1935
- Var[Any],
1936
- ]
1920
+ IndividualEventType = TypeAliasType(
1921
+ "IndividualEventType",
1922
+ LAMBDA_OR_STATE[Unpack[ARGS]] | BASIC_EVENT_TYPES,
1923
+ type_params=(ARGS,),
1924
+ )
1925
+
1926
+ EventType = TypeAliasType(
1927
+ "EventType", ItemOrList[IndividualEventType[Unpack[ARGS]]], type_params=(ARGS,)
1928
+ )
1937
1929
 
1938
- ItemOrList = Union[V, List[V]]
1939
1930
 
1940
- EventType = ItemOrList[IndividualEventType[G, BASE_STATE]]
1931
+ if TYPE_CHECKING:
1932
+ from reflex.state import BaseState
1933
+
1934
+ BASE_STATE = TypeVar("BASE_STATE", bound=BaseState)
1935
+ else:
1936
+ BASE_STATE = TypeVar("BASE_STATE")
1941
1937
 
1942
1938
 
1943
1939
  class EventNamespace(types.SimpleNamespace):
@@ -1959,24 +1955,26 @@ class EventNamespace(types.SimpleNamespace):
1959
1955
  @staticmethod
1960
1956
  def __call__(
1961
1957
  func: None = None, *, background: bool | None = None
1962
- ) -> Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]]: ...
1958
+ ) -> Callable[
1959
+ [Callable[[BASE_STATE, Unpack[P]], Any]], EventCallback[Unpack[P]] # pyright: ignore [reportInvalidTypeVarUse]
1960
+ ]: ...
1963
1961
 
1964
1962
  @overload
1965
1963
  @staticmethod
1966
1964
  def __call__(
1967
- func: Callable[Concatenate[BASE_STATE, P], T],
1965
+ func: Callable[[BASE_STATE, Unpack[P]], Any],
1968
1966
  *,
1969
1967
  background: bool | None = None,
1970
- ) -> EventCallback[P, T]: ...
1968
+ ) -> EventCallback[Unpack[P]]: ...
1971
1969
 
1972
1970
  @staticmethod
1973
1971
  def __call__(
1974
- func: Callable[Concatenate[BASE_STATE, P], T] | None = None,
1972
+ func: Callable[[BASE_STATE, Unpack[P]], Any] | None = None,
1975
1973
  *,
1976
1974
  background: bool | None = None,
1977
1975
  ) -> Union[
1978
- EventCallback[P, T],
1979
- Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]],
1976
+ EventCallback[Unpack[P]],
1977
+ Callable[[Callable[[BASE_STATE, Unpack[P]], Any]], EventCallback[Unpack[P]]],
1980
1978
  ]:
1981
1979
  """Wrap a function to be used as an event.
1982
1980
 
@@ -1984,16 +1982,25 @@ class EventNamespace(types.SimpleNamespace):
1984
1982
  func: The function to wrap.
1985
1983
  background: Whether the event should be run in the background. Defaults to False.
1986
1984
 
1985
+ Raises:
1986
+ TypeError: If background is True and the function is not a coroutine or async generator. # noqa: DAR402
1987
+
1987
1988
  Returns:
1988
1989
  The wrapped function.
1989
1990
  """
1990
1991
 
1991
1992
  def wrapper(
1992
- func: Callable[Concatenate[BASE_STATE, P], T],
1993
- ) -> EventCallback[P, T]:
1993
+ func: Callable[[BASE_STATE, Unpack[P]], T],
1994
+ ) -> EventCallback[Unpack[P]]:
1994
1995
  if background is True:
1995
- return background_event_decorator(func, __internal_reflex_call=True) # type: ignore
1996
- return func # type: ignore
1996
+ if not inspect.iscoroutinefunction(
1997
+ func
1998
+ ) and not inspect.isasyncgenfunction(func):
1999
+ raise TypeError(
2000
+ "Background task must be async function or generator."
2001
+ )
2002
+ setattr(func, BACKGROUND_TASK_MARKER, True)
2003
+ return func # pyright: ignore [reportReturnType]
1997
2004
 
1998
2005
  if func is not None:
1999
2006
  return wrapper(func)