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
@@ -12,7 +12,7 @@ from typing import Callable, Coroutine, Set, Union
12
12
  from fastapi import FastAPI
13
13
 
14
14
  from reflex.utils import console
15
- from reflex.utils.exceptions import InvalidLifespanTaskType
15
+ from reflex.utils.exceptions import InvalidLifespanTaskTypeError
16
16
 
17
17
  from .mixin import AppMixin
18
18
 
@@ -32,7 +32,7 @@ class LifespanMixin(AppMixin):
32
32
  try:
33
33
  async with contextlib.AsyncExitStack() as stack:
34
34
  for task in self.lifespan_tasks:
35
- run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # type: ignore
35
+ run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # pyright: ignore [reportAttributeAccessIssue]
36
36
  if isinstance(task, asyncio.Task):
37
37
  running_tasks.append(task)
38
38
  else:
@@ -61,19 +61,19 @@ class LifespanMixin(AppMixin):
61
61
 
62
62
  Args:
63
63
  task: The task to register.
64
- task_kwargs: The kwargs of the task.
64
+ **task_kwargs: The kwargs of the task.
65
65
 
66
66
  Raises:
67
- InvalidLifespanTaskType: If the task is a generator function.
67
+ InvalidLifespanTaskTypeError: If the task is a generator function.
68
68
  """
69
69
  if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task):
70
- raise InvalidLifespanTaskType(
70
+ raise InvalidLifespanTaskTypeError(
71
71
  f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
72
72
  )
73
73
 
74
74
  if task_kwargs:
75
75
  original_task = task
76
- task = functools.partial(task, **task_kwargs) # type: ignore
77
- functools.update_wrapper(task, original_task) # type: ignore
78
- self.lifespan_tasks.add(task) # type: ignore
79
- console.debug(f"Registered lifespan task: {task.__name__}") # type: ignore
76
+ task = functools.partial(task, **task_kwargs) # pyright: ignore [reportArgumentType]
77
+ functools.update_wrapper(task, original_task) # pyright: ignore [reportArgumentType]
78
+ self.lifespan_tasks.add(task)
79
+ console.debug(f"Registered lifespan task: {task.__name__}") # pyright: ignore [reportAttributeAccessIssue]
@@ -53,11 +53,11 @@ class MiddlewareMixin(AppMixin):
53
53
  """
54
54
  for middleware in self.middleware:
55
55
  if asyncio.iscoroutinefunction(middleware.preprocess):
56
- out = await middleware.preprocess(app=self, state=state, event=event) # type: ignore
56
+ out = await middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
57
57
  else:
58
- out = middleware.preprocess(app=self, state=state, event=event) # type: ignore
58
+ out = middleware.preprocess(app=self, state=state, event=event) # pyright: ignore [reportArgumentType]
59
59
  if out is not None:
60
- return out # type: ignore
60
+ return out # pyright: ignore [reportReturnType]
61
61
 
62
62
  async def _postprocess(
63
63
  self, state: BaseState, event: Event, update: StateUpdate
@@ -78,18 +78,18 @@ class MiddlewareMixin(AppMixin):
78
78
  for middleware in self.middleware:
79
79
  if asyncio.iscoroutinefunction(middleware.postprocess):
80
80
  out = await middleware.postprocess(
81
- app=self, # type: ignore
81
+ app=self, # pyright: ignore [reportArgumentType]
82
82
  state=state,
83
83
  event=event,
84
84
  update=update,
85
85
  )
86
86
  else:
87
87
  out = middleware.postprocess(
88
- app=self, # type: ignore
88
+ app=self, # pyright: ignore [reportArgumentType]
89
89
  state=state,
90
90
  event=event,
91
91
  update=update,
92
92
  )
93
93
  if out is not None:
94
- return out # type: ignore
94
+ return out # pyright: ignore [reportReturnType]
95
95
  return update
@@ -5,16 +5,13 @@ Only the app attribute is explicitly exposed.
5
5
  from concurrent.futures import ThreadPoolExecutor
6
6
 
7
7
  from reflex import constants
8
- from reflex.utils import telemetry
9
8
  from reflex.utils.exec import is_prod_mode
10
- from reflex.utils.prerequisites import get_app
9
+ from reflex.utils.prerequisites import get_and_validate_app
11
10
 
12
11
  if constants.CompileVars.APP != "app":
13
12
  raise AssertionError("unexpected variable name for 'app'")
14
13
 
15
- telemetry.send("compile")
16
- app_module = get_app(reload=False)
17
- app = getattr(app_module, constants.CompileVars.APP)
14
+ app, app_module = get_and_validate_app(reload=False)
18
15
  # For py3.9 compatibility when redis is used, we MUST add any decorator pages
19
16
  # before compiling the app in a thread to avoid event loop error (REF-2172).
20
17
  app._apply_decorated_pages()
@@ -30,8 +27,7 @@ if is_prod_mode():
30
27
  # ensure only "app" is exposed.
31
28
  del app_module
32
29
  del compile_future
33
- del get_app
30
+ del get_and_validate_app
34
31
  del is_prod_mode
35
- del telemetry
36
32
  del constants
37
33
  del ThreadPoolExecutor
reflex/base.py CHANGED
@@ -13,7 +13,7 @@ except ModuleNotFoundError:
13
13
  if not TYPE_CHECKING:
14
14
  import pydantic.main as pydantic_main
15
15
  from pydantic import BaseModel
16
- from pydantic.fields import ModelField # type: ignore
16
+ from pydantic.fields import ModelField
17
17
 
18
18
 
19
19
  def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None:
@@ -44,13 +44,13 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
44
44
 
45
45
  # monkeypatch pydantic validate_field_name method to skip validating
46
46
  # shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
47
- pydantic_main.validate_field_name = validate_field_name # type: ignore
47
+ pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPossiblyUnboundVariable, reportPrivateImportUsage]
48
48
 
49
49
  if TYPE_CHECKING:
50
50
  from reflex.vars import Var
51
51
 
52
52
 
53
- class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
53
+ class Base(BaseModel): # pyright: ignore [reportPossiblyUnboundVariable]
54
54
  """The base class subclassed by all Reflex classes.
55
55
 
56
56
  This class wraps Pydantic and provides common methods such as
@@ -75,12 +75,12 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
75
75
  """
76
76
  from reflex.utils.serializers import serialize
77
77
 
78
- return self.__config__.json_dumps( # type: ignore
78
+ return self.__config__.json_dumps(
79
79
  self.dict(),
80
80
  default=serialize,
81
81
  )
82
82
 
83
- def set(self, **kwargs):
83
+ def set(self, **kwargs: Any):
84
84
  """Set multiple fields and return the object.
85
85
 
86
86
  Args:
@@ -113,12 +113,12 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
113
113
  default_value: The default value of the field
114
114
  """
115
115
  var_name = var._var_field_name
116
- new_field = ModelField.infer(
116
+ new_field = ModelField.infer( # pyright: ignore [reportPossiblyUnboundVariable]
117
117
  name=var_name,
118
118
  value=default_value,
119
119
  annotation=var._var_type,
120
120
  class_validators=None,
121
- config=cls.__config__, # type: ignore
121
+ config=cls.__config__,
122
122
  )
123
123
  cls.__fields__.update({var_name: new_field})
124
124
 
@@ -239,11 +239,19 @@ def _compile_components(
239
239
  component_renders.append(component_render)
240
240
  imports = utils.merge_imports(imports, component_imports)
241
241
 
242
+ dynamic_imports = {
243
+ comp_import: None
244
+ for comp_render in component_renders
245
+ if "dynamic_imports" in comp_render
246
+ for comp_import in comp_render["dynamic_imports"]
247
+ }
248
+
242
249
  # Compile the components page.
243
250
  return (
244
251
  templates.COMPONENTS.render(
245
252
  imports=utils.compile_imports(imports),
246
253
  components=component_renders,
254
+ dynamic_imports=dynamic_imports,
247
255
  ),
248
256
  imports,
249
257
  )
reflex/compiler/utils.py CHANGED
@@ -2,17 +2,24 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import asyncio
6
+ import concurrent.futures
7
+ import traceback
8
+ from datetime import datetime
5
9
  from pathlib import Path
6
10
  from typing import Any, Callable, Dict, Optional, Type, Union
7
11
  from urllib.parse import urlparse
8
12
 
13
+ from reflex.utils.exec import is_in_app_harness
9
14
  from reflex.utils.prerequisites import get_web_dir
10
15
  from reflex.vars.base import Var
11
16
 
12
17
  try:
13
18
  from pydantic.v1.fields import ModelField
14
19
  except ModuleNotFoundError:
15
- from pydantic.fields import ModelField # type: ignore
20
+ from pydantic.fields import (
21
+ ModelField, # pyright: ignore [reportAttributeAccessIssue]
22
+ )
16
23
 
17
24
  from reflex import constants
18
25
  from reflex.components.base import (
@@ -29,7 +36,7 @@ from reflex.components.base import (
29
36
  )
30
37
  from reflex.components.component import Component, ComponentStyle, CustomComponent
31
38
  from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
32
- from reflex.state import BaseState
39
+ from reflex.state import BaseState, _resolve_delta
33
40
  from reflex.style import Style
34
41
  from reflex.utils import console, format, imports, path_ops
35
42
  from reflex.utils.imports import ImportVar, ParsedImportDict
@@ -112,24 +119,34 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
112
119
  validate_imports(collapsed_import_dict)
113
120
  import_dicts = []
114
121
  for lib, fields in collapsed_import_dict.items():
115
- default, rest = compile_import_statement(fields)
116
-
117
122
  # prevent lib from being rendered on the page if all imports are non rendered kind
118
- if not any(f.render for f in fields): # type: ignore
123
+ if not any(f.render for f in fields):
119
124
  continue
120
125
 
121
- if not lib:
122
- if default:
123
- raise ValueError("No default field allowed for empty library.")
124
- if rest is None or len(rest) == 0:
125
- raise ValueError("No fields to import.")
126
- import_dicts.extend(get_import_dict(module) for module in sorted(rest))
127
- continue
126
+ lib_paths: dict[str, list[ImportVar]] = {}
127
+
128
+ for field in fields:
129
+ lib_paths.setdefault(field.package_path, []).append(field)
130
+
131
+ compiled = {
132
+ path: compile_import_statement(fields) for path, fields in lib_paths.items()
133
+ }
128
134
 
129
- # remove the version before rendering the package imports
130
- lib = format.format_library_name(lib)
135
+ for path, (default, rest) in compiled.items():
136
+ if not lib:
137
+ if default:
138
+ raise ValueError("No default field allowed for empty library.")
139
+ if rest is None or len(rest) == 0:
140
+ raise ValueError("No fields to import.")
141
+ import_dicts.extend(get_import_dict(module) for module in sorted(rest))
142
+ continue
131
143
 
132
- import_dicts.append(get_import_dict(lib, default, rest))
144
+ # remove the version before rendering the package imports
145
+ formatted_lib = format.format_library_name(lib) + (
146
+ path if path != "/" else ""
147
+ )
148
+
149
+ import_dicts.append(get_import_dict(formatted_lib, default, rest))
133
150
  return import_dicts
134
151
 
135
152
 
@@ -163,13 +180,34 @@ def compile_state(state: Type[BaseState]) -> dict:
163
180
  try:
164
181
  initial_state = state(_reflex_internal_init=True).dict(initial=True)
165
182
  except Exception as e:
183
+ timestamp = datetime.now().strftime("%Y-%m-%d__%H-%M-%S")
184
+ constants.Reflex.LOGS_DIR.mkdir(parents=True, exist_ok=True)
185
+ log_path = constants.Reflex.LOGS_DIR / f"state_compile_error_{timestamp}.log"
186
+ traceback.TracebackException.from_exception(e).print(file=log_path.open("w+"))
166
187
  console.warn(
167
- f"Failed to compile initial state with computed vars, excluding them: {e}"
188
+ f"Failed to compile initial state with computed vars. Error log saved to {log_path}"
168
189
  )
169
190
  initial_state = state(_reflex_internal_init=True).dict(
170
191
  initial=True, include_computed=False
171
192
  )
172
- return initial_state
193
+ try:
194
+ _ = asyncio.get_running_loop()
195
+ except RuntimeError:
196
+ pass
197
+ else:
198
+ if is_in_app_harness():
199
+ # Playwright tests already have an event loop running, so we can't use asyncio.run.
200
+ with concurrent.futures.ThreadPoolExecutor() as pool:
201
+ resolved_initial_state = pool.submit(
202
+ asyncio.run, _resolve_delta(initial_state)
203
+ ).result()
204
+ console.warn(
205
+ f"Had to get initial state in a thread 🤮 {resolved_initial_state}",
206
+ )
207
+ return resolved_initial_state
208
+
209
+ # Normally the compile runs before any event loop starts, we asyncio.run is available for calling.
210
+ return asyncio.run(_resolve_delta(initial_state))
173
211
 
174
212
 
175
213
  def _compile_client_storage_field(
@@ -292,6 +330,7 @@ def compile_custom_component(
292
330
  "render": render.render(),
293
331
  "hooks": render._get_all_hooks(),
294
332
  "custom_code": render._get_all_custom_code(),
333
+ "dynamic_imports": render._get_all_dynamic_imports(),
295
334
  },
296
335
  imports,
297
336
  )
@@ -494,7 +533,7 @@ def empty_dir(path: str | Path, keep_files: list[str] | None = None):
494
533
  path_ops.rm(element)
495
534
 
496
535
 
497
- def is_valid_url(url) -> bool:
536
+ def is_valid_url(url: str) -> bool:
498
537
  """Check if a url is valid.
499
538
 
500
539
  Args:
@@ -6,7 +6,7 @@
6
6
  from typing import Any, Dict, Optional, Union, overload
7
7
 
8
8
  from reflex.components.base.fragment import Fragment
9
- from reflex.event import BASE_STATE, EventType
9
+ from reflex.event import EventType
10
10
  from reflex.style import Style
11
11
  from reflex.vars.base import Var
12
12
 
@@ -22,21 +22,21 @@ class AppWrap(Fragment):
22
22
  class_name: Optional[Any] = None,
23
23
  autofocus: Optional[bool] = None,
24
24
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
25
- on_blur: Optional[EventType[[], BASE_STATE]] = None,
26
- on_click: Optional[EventType[[], BASE_STATE]] = None,
27
- on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
28
- on_double_click: Optional[EventType[[], BASE_STATE]] = None,
29
- on_focus: Optional[EventType[[], BASE_STATE]] = None,
30
- on_mount: Optional[EventType[[], BASE_STATE]] = None,
31
- on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
32
- on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
33
- on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
34
- on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
35
- on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
36
- on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
37
- on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
38
- on_scroll: Optional[EventType[[], BASE_STATE]] = None,
39
- on_unmount: Optional[EventType[[], BASE_STATE]] = None,
25
+ on_blur: Optional[EventType[()]] = None,
26
+ on_click: Optional[EventType[()]] = None,
27
+ on_context_menu: Optional[EventType[()]] = None,
28
+ on_double_click: Optional[EventType[()]] = None,
29
+ on_focus: Optional[EventType[()]] = None,
30
+ on_mount: Optional[EventType[()]] = None,
31
+ on_mouse_down: Optional[EventType[()]] = None,
32
+ on_mouse_enter: Optional[EventType[()]] = None,
33
+ on_mouse_leave: Optional[EventType[()]] = None,
34
+ on_mouse_move: Optional[EventType[()]] = None,
35
+ on_mouse_out: Optional[EventType[()]] = None,
36
+ on_mouse_over: Optional[EventType[()]] = None,
37
+ on_mouse_up: Optional[EventType[()]] = None,
38
+ on_scroll: Optional[EventType[()]] = None,
39
+ on_unmount: Optional[EventType[()]] = None,
40
40
  **props,
41
41
  ) -> "AppWrap":
42
42
  """Create a new AppWrap component.
@@ -31,7 +31,7 @@ class Bare(Component):
31
31
  return cls(contents=contents)
32
32
  else:
33
33
  contents = str(contents) if contents is not None else ""
34
- return cls(contents=contents) # type: ignore
34
+ return cls(contents=contents)
35
35
 
36
36
  def _get_all_hooks_internal(self) -> dict[str, VarData | None]:
37
37
  """Include the hooks for the component.
@@ -6,7 +6,7 @@
6
6
  from typing import Any, Dict, Optional, Union, overload
7
7
 
8
8
  from reflex.components.component import Component
9
- from reflex.event import BASE_STATE, EventType
9
+ from reflex.event import EventType
10
10
  from reflex.style import Style
11
11
  from reflex.vars.base import Var
12
12
 
@@ -22,21 +22,21 @@ class Body(Component):
22
22
  class_name: Optional[Any] = None,
23
23
  autofocus: Optional[bool] = None,
24
24
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
25
- on_blur: Optional[EventType[[], BASE_STATE]] = None,
26
- on_click: Optional[EventType[[], BASE_STATE]] = None,
27
- on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
28
- on_double_click: Optional[EventType[[], BASE_STATE]] = None,
29
- on_focus: Optional[EventType[[], BASE_STATE]] = None,
30
- on_mount: Optional[EventType[[], BASE_STATE]] = None,
31
- on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
32
- on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
33
- on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
34
- on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
35
- on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
36
- on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
37
- on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
38
- on_scroll: Optional[EventType[[], BASE_STATE]] = None,
39
- on_unmount: Optional[EventType[[], BASE_STATE]] = None,
25
+ on_blur: Optional[EventType[()]] = None,
26
+ on_click: Optional[EventType[()]] = None,
27
+ on_context_menu: Optional[EventType[()]] = None,
28
+ on_double_click: Optional[EventType[()]] = None,
29
+ on_focus: Optional[EventType[()]] = None,
30
+ on_mount: Optional[EventType[()]] = None,
31
+ on_mouse_down: Optional[EventType[()]] = None,
32
+ on_mouse_enter: Optional[EventType[()]] = None,
33
+ on_mouse_leave: Optional[EventType[()]] = None,
34
+ on_mouse_move: Optional[EventType[()]] = None,
35
+ on_mouse_out: Optional[EventType[()]] = None,
36
+ on_mouse_over: Optional[EventType[()]] = None,
37
+ on_mouse_up: Optional[EventType[()]] = None,
38
+ on_scroll: Optional[EventType[()]] = None,
39
+ on_unmount: Optional[EventType[()]] = None,
40
40
  **props,
41
41
  ) -> "Body":
42
42
  """Create the component.
@@ -6,7 +6,7 @@
6
6
  from typing import Any, Dict, Optional, Union, overload
7
7
 
8
8
  from reflex.components.component import Component
9
- from reflex.event import BASE_STATE, EventType
9
+ from reflex.event import EventType
10
10
  from reflex.style import Style
11
11
  from reflex.vars.base import Var
12
12
 
@@ -22,21 +22,21 @@ class NextDocumentLib(Component):
22
22
  class_name: Optional[Any] = None,
23
23
  autofocus: Optional[bool] = None,
24
24
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
25
- on_blur: Optional[EventType[[], BASE_STATE]] = None,
26
- on_click: Optional[EventType[[], BASE_STATE]] = None,
27
- on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
28
- on_double_click: Optional[EventType[[], BASE_STATE]] = None,
29
- on_focus: Optional[EventType[[], BASE_STATE]] = None,
30
- on_mount: Optional[EventType[[], BASE_STATE]] = None,
31
- on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
32
- on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
33
- on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
34
- on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
35
- on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
36
- on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
37
- on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
38
- on_scroll: Optional[EventType[[], BASE_STATE]] = None,
39
- on_unmount: Optional[EventType[[], BASE_STATE]] = None,
25
+ on_blur: Optional[EventType[()]] = None,
26
+ on_click: Optional[EventType[()]] = None,
27
+ on_context_menu: Optional[EventType[()]] = None,
28
+ on_double_click: Optional[EventType[()]] = None,
29
+ on_focus: Optional[EventType[()]] = None,
30
+ on_mount: Optional[EventType[()]] = None,
31
+ on_mouse_down: Optional[EventType[()]] = None,
32
+ on_mouse_enter: Optional[EventType[()]] = None,
33
+ on_mouse_leave: Optional[EventType[()]] = None,
34
+ on_mouse_move: Optional[EventType[()]] = None,
35
+ on_mouse_out: Optional[EventType[()]] = None,
36
+ on_mouse_over: Optional[EventType[()]] = None,
37
+ on_mouse_up: Optional[EventType[()]] = None,
38
+ on_scroll: Optional[EventType[()]] = None,
39
+ on_unmount: Optional[EventType[()]] = None,
40
40
  **props,
41
41
  ) -> "NextDocumentLib":
42
42
  """Create the component.
@@ -69,21 +69,21 @@ class Html(NextDocumentLib):
69
69
  class_name: Optional[Any] = None,
70
70
  autofocus: Optional[bool] = None,
71
71
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
72
- on_blur: Optional[EventType[[], BASE_STATE]] = None,
73
- on_click: Optional[EventType[[], BASE_STATE]] = None,
74
- on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
75
- on_double_click: Optional[EventType[[], BASE_STATE]] = None,
76
- on_focus: Optional[EventType[[], BASE_STATE]] = None,
77
- on_mount: Optional[EventType[[], BASE_STATE]] = None,
78
- on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
79
- on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
80
- on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
81
- on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
82
- on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
83
- on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
84
- on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
85
- on_scroll: Optional[EventType[[], BASE_STATE]] = None,
86
- on_unmount: Optional[EventType[[], BASE_STATE]] = None,
72
+ on_blur: Optional[EventType[()]] = None,
73
+ on_click: Optional[EventType[()]] = None,
74
+ on_context_menu: Optional[EventType[()]] = None,
75
+ on_double_click: Optional[EventType[()]] = None,
76
+ on_focus: Optional[EventType[()]] = None,
77
+ on_mount: Optional[EventType[()]] = None,
78
+ on_mouse_down: Optional[EventType[()]] = None,
79
+ on_mouse_enter: Optional[EventType[()]] = None,
80
+ on_mouse_leave: Optional[EventType[()]] = None,
81
+ on_mouse_move: Optional[EventType[()]] = None,
82
+ on_mouse_out: Optional[EventType[()]] = None,
83
+ on_mouse_over: Optional[EventType[()]] = None,
84
+ on_mouse_up: Optional[EventType[()]] = None,
85
+ on_scroll: Optional[EventType[()]] = None,
86
+ on_unmount: Optional[EventType[()]] = None,
87
87
  **props,
88
88
  ) -> "Html":
89
89
  """Create the component.
@@ -115,21 +115,21 @@ class DocumentHead(NextDocumentLib):
115
115
  class_name: Optional[Any] = None,
116
116
  autofocus: Optional[bool] = None,
117
117
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
118
- on_blur: Optional[EventType[[], BASE_STATE]] = None,
119
- on_click: Optional[EventType[[], BASE_STATE]] = None,
120
- on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
121
- on_double_click: Optional[EventType[[], BASE_STATE]] = None,
122
- on_focus: Optional[EventType[[], BASE_STATE]] = None,
123
- on_mount: Optional[EventType[[], BASE_STATE]] = None,
124
- on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
125
- on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
126
- on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
127
- on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
128
- on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
129
- on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
130
- on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
131
- on_scroll: Optional[EventType[[], BASE_STATE]] = None,
132
- on_unmount: Optional[EventType[[], BASE_STATE]] = None,
118
+ on_blur: Optional[EventType[()]] = None,
119
+ on_click: Optional[EventType[()]] = None,
120
+ on_context_menu: Optional[EventType[()]] = None,
121
+ on_double_click: Optional[EventType[()]] = None,
122
+ on_focus: Optional[EventType[()]] = None,
123
+ on_mount: Optional[EventType[()]] = None,
124
+ on_mouse_down: Optional[EventType[()]] = None,
125
+ on_mouse_enter: Optional[EventType[()]] = None,
126
+ on_mouse_leave: Optional[EventType[()]] = None,
127
+ on_mouse_move: Optional[EventType[()]] = None,
128
+ on_mouse_out: Optional[EventType[()]] = None,
129
+ on_mouse_over: Optional[EventType[()]] = None,
130
+ on_mouse_up: Optional[EventType[()]] = None,
131
+ on_scroll: Optional[EventType[()]] = None,
132
+ on_unmount: Optional[EventType[()]] = None,
133
133
  **props,
134
134
  ) -> "DocumentHead":
135
135
  """Create the component.
@@ -161,21 +161,21 @@ class Main(NextDocumentLib):
161
161
  class_name: Optional[Any] = None,
162
162
  autofocus: Optional[bool] = None,
163
163
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
164
- on_blur: Optional[EventType[[], BASE_STATE]] = None,
165
- on_click: Optional[EventType[[], BASE_STATE]] = None,
166
- on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
167
- on_double_click: Optional[EventType[[], BASE_STATE]] = None,
168
- on_focus: Optional[EventType[[], BASE_STATE]] = None,
169
- on_mount: Optional[EventType[[], BASE_STATE]] = None,
170
- on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
171
- on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
172
- on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
173
- on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
174
- on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
175
- on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
176
- on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
177
- on_scroll: Optional[EventType[[], BASE_STATE]] = None,
178
- on_unmount: Optional[EventType[[], BASE_STATE]] = None,
164
+ on_blur: Optional[EventType[()]] = None,
165
+ on_click: Optional[EventType[()]] = None,
166
+ on_context_menu: Optional[EventType[()]] = None,
167
+ on_double_click: Optional[EventType[()]] = None,
168
+ on_focus: Optional[EventType[()]] = None,
169
+ on_mount: Optional[EventType[()]] = None,
170
+ on_mouse_down: Optional[EventType[()]] = None,
171
+ on_mouse_enter: Optional[EventType[()]] = None,
172
+ on_mouse_leave: Optional[EventType[()]] = None,
173
+ on_mouse_move: Optional[EventType[()]] = None,
174
+ on_mouse_out: Optional[EventType[()]] = None,
175
+ on_mouse_over: Optional[EventType[()]] = None,
176
+ on_mouse_up: Optional[EventType[()]] = None,
177
+ on_scroll: Optional[EventType[()]] = None,
178
+ on_unmount: Optional[EventType[()]] = None,
179
179
  **props,
180
180
  ) -> "Main":
181
181
  """Create the component.
@@ -207,21 +207,21 @@ class NextScript(NextDocumentLib):
207
207
  class_name: Optional[Any] = None,
208
208
  autofocus: Optional[bool] = None,
209
209
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
210
- on_blur: Optional[EventType[[], BASE_STATE]] = None,
211
- on_click: Optional[EventType[[], BASE_STATE]] = None,
212
- on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
213
- on_double_click: Optional[EventType[[], BASE_STATE]] = None,
214
- on_focus: Optional[EventType[[], BASE_STATE]] = None,
215
- on_mount: Optional[EventType[[], BASE_STATE]] = None,
216
- on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
217
- on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
218
- on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
219
- on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
220
- on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
221
- on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
222
- on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
223
- on_scroll: Optional[EventType[[], BASE_STATE]] = None,
224
- on_unmount: Optional[EventType[[], BASE_STATE]] = None,
210
+ on_blur: Optional[EventType[()]] = None,
211
+ on_click: Optional[EventType[()]] = None,
212
+ on_context_menu: Optional[EventType[()]] = None,
213
+ on_double_click: Optional[EventType[()]] = None,
214
+ on_focus: Optional[EventType[()]] = None,
215
+ on_mount: Optional[EventType[()]] = None,
216
+ on_mouse_down: Optional[EventType[()]] = None,
217
+ on_mouse_enter: Optional[EventType[()]] = None,
218
+ on_mouse_leave: Optional[EventType[()]] = None,
219
+ on_mouse_move: Optional[EventType[()]] = None,
220
+ on_mouse_out: Optional[EventType[()]] = None,
221
+ on_mouse_over: Optional[EventType[()]] = None,
222
+ on_mouse_up: Optional[EventType[()]] = None,
223
+ on_scroll: Optional[EventType[()]] = None,
224
+ on_unmount: Optional[EventType[()]] = None,
225
225
  **props,
226
226
  ) -> "NextScript":
227
227
  """Create the component.
@@ -11,10 +11,11 @@ from reflex.event import EventHandler, set_clipboard
11
11
  from reflex.state import FrontendEventExceptionState
12
12
  from reflex.vars.base import Var
13
13
  from reflex.vars.function import ArgsFunctionOperation
14
+ from reflex.vars.object import ObjectVar
14
15
 
15
16
 
16
17
  def on_error_spec(
17
- error: Var[Dict[str, str]], info: Var[Dict[str, str]]
18
+ error: ObjectVar[Dict[str, str]], info: ObjectVar[Dict[str, str]]
18
19
  ) -> Tuple[Var[str], Var[str]]:
19
20
  """The spec for the on_error event handler.
20
21