reflex 0.6.8a2__py3-none-any.whl → 0.7.0a1__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 (154) 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 +2 -2
  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 +244 -109
  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/bare.py +1 -1
  16. reflex/components/base/error_boundary.py +2 -1
  17. reflex/components/base/error_boundary.pyi +2 -1
  18. reflex/components/base/meta.py +2 -2
  19. reflex/components/base/strict_mode.py +10 -0
  20. reflex/components/base/strict_mode.pyi +57 -0
  21. reflex/components/component.py +38 -77
  22. reflex/components/core/banner.py +83 -4
  23. reflex/components/core/banner.pyi +86 -0
  24. reflex/components/core/breakpoints.py +3 -1
  25. reflex/components/core/client_side_routing.py +1 -1
  26. reflex/components/core/client_side_routing.pyi +1 -1
  27. reflex/components/core/cond.py +9 -10
  28. reflex/components/core/debounce.py +1 -1
  29. reflex/components/core/foreach.py +23 -3
  30. reflex/components/core/html.py +1 -1
  31. reflex/components/core/match.py +5 -5
  32. reflex/components/core/sticky.py +160 -0
  33. reflex/components/core/sticky.pyi +449 -0
  34. reflex/components/core/upload.py +2 -2
  35. reflex/components/datadisplay/code.py +5 -14
  36. reflex/components/datadisplay/dataeditor.py +7 -4
  37. reflex/components/datadisplay/logo.py +13 -8
  38. reflex/components/datadisplay/shiki_code_block.py +14 -9
  39. reflex/components/dynamic.py +22 -3
  40. reflex/components/el/constants/reflex.py +1 -1
  41. reflex/components/el/element.py +1 -1
  42. reflex/components/el/elements/forms.py +4 -4
  43. reflex/components/el/elements/forms.pyi +4 -4
  44. reflex/components/lucide/icon.py +46 -8
  45. reflex/components/lucide/icon.pyi +54 -0
  46. reflex/components/markdown/markdown.py +10 -8
  47. reflex/components/moment/moment.py +2 -2
  48. reflex/components/next/image.py +16 -4
  49. reflex/components/next/image.pyi +4 -2
  50. reflex/components/next/link.py +1 -1
  51. reflex/components/plotly/plotly.py +5 -5
  52. reflex/components/props.py +3 -3
  53. reflex/components/radix/__init__.pyi +1 -1
  54. reflex/components/radix/primitives/accordion.py +9 -5
  55. reflex/components/radix/primitives/accordion.pyi +3 -1
  56. reflex/components/radix/primitives/drawer.py +5 -2
  57. reflex/components/radix/primitives/drawer.pyi +4 -4
  58. reflex/components/radix/primitives/form.pyi +6 -6
  59. reflex/components/radix/primitives/progress.py +1 -1
  60. reflex/components/radix/primitives/slider.py +1 -1
  61. reflex/components/radix/themes/color_mode.py +11 -9
  62. reflex/components/radix/themes/components/alert_dialog.py +3 -0
  63. reflex/components/radix/themes/components/card.py +1 -1
  64. reflex/components/radix/themes/components/card.pyi +1 -1
  65. reflex/components/radix/themes/components/context_menu.py +5 -0
  66. reflex/components/radix/themes/components/dialog.py +3 -0
  67. reflex/components/radix/themes/components/dropdown_menu.py +5 -0
  68. reflex/components/radix/themes/components/hover_card.py +3 -0
  69. reflex/components/radix/themes/components/icon_button.py +2 -2
  70. reflex/components/radix/themes/components/icon_button.pyi +1 -0
  71. reflex/components/radix/themes/components/popover.py +3 -0
  72. reflex/components/radix/themes/components/radio_cards.py +2 -0
  73. reflex/components/radix/themes/components/radio_group.py +1 -1
  74. reflex/components/radix/themes/components/select.py +3 -0
  75. reflex/components/radix/themes/components/tabs.py +3 -0
  76. reflex/components/radix/themes/components/text_area.py +12 -0
  77. reflex/components/radix/themes/components/text_area.pyi +2 -0
  78. reflex/components/radix/themes/components/text_field.py +1 -1
  79. reflex/components/radix/themes/components/tooltip.py +3 -1
  80. reflex/components/radix/themes/components/tooltip.pyi +1 -0
  81. reflex/components/radix/themes/layout/__init__.pyi +1 -1
  82. reflex/components/radix/themes/layout/list.py +2 -2
  83. reflex/components/radix/themes/layout/stack.py +2 -2
  84. reflex/components/radix/themes/typography/link.py +1 -1
  85. reflex/components/radix/themes/typography/text.py +2 -2
  86. reflex/components/react_player/react_player.py +1 -1
  87. reflex/components/recharts/__init__.py +2 -0
  88. reflex/components/recharts/__init__.pyi +2 -0
  89. reflex/components/recharts/charts.py +15 -15
  90. reflex/components/recharts/general.py +19 -4
  91. reflex/components/recharts/general.pyi +55 -4
  92. reflex/components/recharts/polar.py +2 -2
  93. reflex/components/recharts/recharts.py +4 -4
  94. reflex/components/sonner/toast.py +15 -13
  95. reflex/components/sonner/toast.pyi +6 -6
  96. reflex/components/suneditor/editor.py +6 -4
  97. reflex/components/suneditor/editor.pyi +2 -2
  98. reflex/components/tags/iter_tag.py +3 -3
  99. reflex/components/tags/tag.py +25 -3
  100. reflex/config.py +48 -15
  101. reflex/constants/__init__.py +1 -0
  102. reflex/constants/base.py +4 -1
  103. reflex/constants/compiler.py +5 -2
  104. reflex/constants/config.py +8 -1
  105. reflex/constants/installer.py +9 -9
  106. reflex/constants/style.py +1 -1
  107. reflex/custom_components/custom_components.py +9 -7
  108. reflex/event.py +130 -161
  109. reflex/experimental/__init__.py +19 -11
  110. reflex/experimental/client_state.py +53 -28
  111. reflex/experimental/hooks.py +5 -5
  112. reflex/experimental/layout.py +8 -5
  113. reflex/experimental/layout.pyi +1 -1
  114. reflex/experimental/misc.py +3 -3
  115. reflex/istate/wrappers.py +1 -1
  116. reflex/middleware/hydrate_middleware.py +2 -2
  117. reflex/model.py +11 -6
  118. reflex/page.py +3 -3
  119. reflex/reflex.py +90 -19
  120. reflex/route.py +1 -1
  121. reflex/state.py +358 -401
  122. reflex/style.py +27 -3
  123. reflex/testing.py +29 -23
  124. reflex/utils/build.py +6 -2
  125. reflex/utils/codespaces.py +1 -4
  126. reflex/utils/compat.py +6 -5
  127. reflex/utils/console.py +52 -16
  128. reflex/utils/exceptions.py +76 -26
  129. reflex/utils/exec.py +69 -74
  130. reflex/utils/export.py +6 -1
  131. reflex/utils/format.py +7 -39
  132. reflex/utils/imports.py +2 -2
  133. reflex/utils/lazy_loader.py +7 -1
  134. reflex/utils/path_ops.py +28 -14
  135. reflex/utils/prerequisites.py +324 -65
  136. reflex/utils/processes.py +45 -32
  137. reflex/utils/pyi_generator.py +30 -25
  138. reflex/utils/registry.py +4 -4
  139. reflex/utils/serializers.py +1 -1
  140. reflex/utils/telemetry.py +5 -4
  141. reflex/utils/types.py +42 -18
  142. reflex/vars/base.py +650 -333
  143. reflex/vars/datetime.py +6 -7
  144. reflex/vars/dep_tracking.py +344 -0
  145. reflex/vars/function.py +11 -5
  146. reflex/vars/number.py +31 -43
  147. reflex/vars/object.py +63 -62
  148. reflex/vars/sequence.py +79 -67
  149. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/METADATA +7 -8
  150. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/RECORD +153 -149
  151. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/WHEEL +1 -1
  152. reflex/experimental/assets.py +0 -37
  153. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/LICENSE +0 -0
  154. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.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,7 +24,6 @@ from typing import (
25
24
  overload,
26
25
  )
27
26
 
28
- import typing_extensions
29
27
  from typing_extensions import (
30
28
  Concatenate,
31
29
  ParamSpec,
@@ -38,9 +36,14 @@ from typing_extensions import (
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:
@@ -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
1403
1342
 
1404
- return event_callback(*event_spec_args) # type: ignore
1343
+ if delayed_exceptions:
1344
+ raise delayed_exceptions[0]
1345
+
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,
@@ -1810,8 +1772,6 @@ V3 = TypeVar("V3")
1810
1772
  V4 = TypeVar("V4")
1811
1773
  V5 = TypeVar("V5")
1812
1774
 
1813
- background_event_decorator = background
1814
-
1815
1775
 
1816
1776
  class EventCallback(Generic[P, T]):
1817
1777
  """A descriptor that wraps a function to be used as an event."""
@@ -1876,7 +1836,7 @@ class EventCallback(Generic[P, T]):
1876
1836
  value4: V4 | Var[V4],
1877
1837
  ) -> EventCallback[Q, T]: ...
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 [reportCallIssue, reportReturnType]
1889
1849
 
1890
1850
  @overload
1891
1851
  def __get__(
1892
- self: EventCallback[P, T], instance: None, owner
1852
+ self: EventCallback[P, T], instance: None, owner: Any
1893
1853
  ) -> EventCallback[P, T]: ...
1894
1854
 
1895
1855
  @overload
1896
- def __get__(self, instance, owner) -> Callable[P, T]: ...
1856
+ def __get__(self, instance: Any, owner: Any) -> Callable[P, T]: ...
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,9 +1866,9 @@ 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
1874
  G = ParamSpec("G")
@@ -1959,7 +1919,7 @@ class EventNamespace(types.SimpleNamespace):
1959
1919
  @staticmethod
1960
1920
  def __call__(
1961
1921
  func: None = None, *, background: bool | None = None
1962
- ) -> Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]]: ...
1922
+ ) -> Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]]: ... # pyright: ignore [reportInvalidTypeVarUse]
1963
1923
 
1964
1924
  @overload
1965
1925
  @staticmethod
@@ -1984,6 +1944,9 @@ class EventNamespace(types.SimpleNamespace):
1984
1944
  func: The function to wrap.
1985
1945
  background: Whether the event should be run in the background. Defaults to False.
1986
1946
 
1947
+ Raises:
1948
+ TypeError: If background is True and the function is not a coroutine or async generator. # noqa: DAR402
1949
+
1987
1950
  Returns:
1988
1951
  The wrapped function.
1989
1952
  """
@@ -1992,8 +1955,14 @@ class EventNamespace(types.SimpleNamespace):
1992
1955
  func: Callable[Concatenate[BASE_STATE, P], T],
1993
1956
  ) -> EventCallback[P, T]:
1994
1957
  if background is True:
1995
- return background_event_decorator(func, __internal_reflex_call=True) # type: ignore
1996
- return func # type: ignore
1958
+ if not inspect.iscoroutinefunction(
1959
+ func
1960
+ ) and not inspect.isasyncgenfunction(func):
1961
+ raise TypeError(
1962
+ "Background task must be async function or generator."
1963
+ )
1964
+ setattr(func, BACKGROUND_TASK_MARKER, True)
1965
+ return func # pyright: ignore [reportReturnType]
1997
1966
 
1998
1967
  if func is not None:
1999
1968
  return wrapper(func)