reflex 0.7.13a2__py3-none-any.whl → 0.7.14a1__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 (256) hide show
  1. reflex/.templates/apps/blank/code/blank.py +0 -2
  2. reflex/app.py +64 -69
  3. reflex/app_mixins/lifespan.py +2 -3
  4. reflex/app_mixins/middleware.py +1 -0
  5. reflex/app_mixins/mixin.py +0 -1
  6. reflex/assets.py +6 -3
  7. reflex/base.py +3 -2
  8. reflex/compiler/compiler.py +77 -64
  9. reflex/compiler/utils.py +8 -6
  10. reflex/components/base/app_wrap.pyi +0 -1
  11. reflex/components/base/bare.py +5 -7
  12. reflex/components/base/body.pyi +0 -1
  13. reflex/components/base/document.pyi +0 -5
  14. reflex/components/base/error_boundary.pyi +0 -1
  15. reflex/components/base/fragment.pyi +0 -1
  16. reflex/components/base/head.pyi +0 -2
  17. reflex/components/base/link.pyi +0 -2
  18. reflex/components/base/meta.py +2 -1
  19. reflex/components/base/meta.pyi +0 -4
  20. reflex/components/base/script.py +2 -1
  21. reflex/components/base/script.pyi +0 -1
  22. reflex/components/base/strict_mode.pyi +0 -1
  23. reflex/components/component.py +38 -40
  24. reflex/components/core/auto_scroll.pyi +0 -1
  25. reflex/components/core/banner.pyi +0 -6
  26. reflex/components/core/breakpoints.py +9 -11
  27. reflex/components/core/client_side_routing.pyi +0 -2
  28. reflex/components/core/clipboard.pyi +0 -1
  29. reflex/components/core/colors.py +10 -7
  30. reflex/components/core/cond.py +4 -2
  31. reflex/components/core/debounce.py +5 -3
  32. reflex/components/core/debounce.pyi +0 -1
  33. reflex/components/core/foreach.py +8 -6
  34. reflex/components/core/html.py +3 -3
  35. reflex/components/core/html.pyi +0 -1
  36. reflex/components/core/match.py +19 -17
  37. reflex/components/core/sticky.pyi +0 -4
  38. reflex/components/core/upload.pyi +0 -5
  39. reflex/components/datadisplay/code.py +1 -2
  40. reflex/components/datadisplay/code.pyi +0 -2
  41. reflex/components/datadisplay/dataeditor.py +7 -10
  42. reflex/components/datadisplay/dataeditor.pyi +0 -1
  43. reflex/components/datadisplay/logo.py +3 -4
  44. reflex/components/datadisplay/shiki_code_block.py +8 -11
  45. reflex/components/datadisplay/shiki_code_block.pyi +0 -3
  46. reflex/components/dynamic.py +2 -3
  47. reflex/components/el/__init__.pyi +2 -0
  48. reflex/components/el/element.pyi +0 -1
  49. reflex/components/el/elements/__init__.py +1 -0
  50. reflex/components/el/elements/__init__.pyi +3 -0
  51. reflex/components/el/elements/base.pyi +0 -1
  52. reflex/components/el/elements/forms.py +3 -4
  53. reflex/components/el/elements/forms.pyi +1 -18
  54. reflex/components/el/elements/inline.pyi +0 -28
  55. reflex/components/el/elements/media.py +26 -0
  56. reflex/components/el/elements/media.pyi +259 -25
  57. reflex/components/el/elements/metadata.py +0 -1
  58. reflex/components/el/elements/metadata.pyi +0 -6
  59. reflex/components/el/elements/other.pyi +0 -7
  60. reflex/components/el/elements/scripts.pyi +0 -3
  61. reflex/components/el/elements/sectioning.pyi +0 -15
  62. reflex/components/el/elements/tables.pyi +0 -10
  63. reflex/components/el/elements/typography.pyi +0 -15
  64. reflex/components/gridjs/datatable.py +10 -13
  65. reflex/components/gridjs/datatable.pyi +0 -2
  66. reflex/components/lucide/icon.py +10 -9
  67. reflex/components/lucide/icon.pyi +0 -3
  68. reflex/components/markdown/markdown.py +6 -8
  69. reflex/components/markdown/markdown.pyi +0 -1
  70. reflex/components/moment/moment.pyi +0 -1
  71. reflex/components/next/base.py +0 -2
  72. reflex/components/next/base.pyi +0 -3
  73. reflex/components/next/image.pyi +0 -1
  74. reflex/components/next/link.pyi +0 -1
  75. reflex/components/next/video.pyi +0 -1
  76. reflex/components/plotly/plotly.pyi +0 -9
  77. reflex/components/props.py +4 -3
  78. reflex/components/radix/primitives/accordion.pyi +0 -7
  79. reflex/components/radix/primitives/base.py +1 -3
  80. reflex/components/radix/primitives/base.pyi +0 -2
  81. reflex/components/radix/primitives/drawer.pyi +0 -11
  82. reflex/components/radix/primitives/form.py +4 -8
  83. reflex/components/radix/primitives/form.pyi +0 -12
  84. reflex/components/radix/primitives/progress.py +1 -1
  85. reflex/components/radix/primitives/progress.pyi +0 -5
  86. reflex/components/radix/primitives/slider.py +1 -1
  87. reflex/components/radix/primitives/slider.pyi +0 -5
  88. reflex/components/radix/themes/base.pyi +0 -8
  89. reflex/components/radix/themes/color_mode.pyi +0 -3
  90. reflex/components/radix/themes/components/alert_dialog.py +4 -2
  91. reflex/components/radix/themes/components/alert_dialog.pyi +4 -9
  92. reflex/components/radix/themes/components/aspect_ratio.py +1 -2
  93. reflex/components/radix/themes/components/aspect_ratio.pyi +1 -3
  94. reflex/components/radix/themes/components/avatar.py +5 -2
  95. reflex/components/radix/themes/components/avatar.pyi +1 -3
  96. reflex/components/radix/themes/components/badge.py +5 -2
  97. reflex/components/radix/themes/components/badge.pyi +1 -3
  98. reflex/components/radix/themes/components/button.py +2 -3
  99. reflex/components/radix/themes/components/button.pyi +1 -3
  100. reflex/components/radix/themes/components/callout.py +1 -2
  101. reflex/components/radix/themes/components/callout.pyi +1 -7
  102. reflex/components/radix/themes/components/card.py +1 -2
  103. reflex/components/radix/themes/components/card.pyi +1 -3
  104. reflex/components/radix/themes/components/checkbox.py +7 -4
  105. reflex/components/radix/themes/components/checkbox.pyi +1 -5
  106. reflex/components/radix/themes/components/checkbox_cards.py +1 -2
  107. reflex/components/radix/themes/components/checkbox_cards.pyi +1 -4
  108. reflex/components/radix/themes/components/checkbox_group.py +1 -2
  109. reflex/components/radix/themes/components/checkbox_group.pyi +1 -4
  110. reflex/components/radix/themes/components/context_menu.py +1 -1
  111. reflex/components/radix/themes/components/context_menu.pyi +1 -14
  112. reflex/components/radix/themes/components/data_list.py +1 -2
  113. reflex/components/radix/themes/components/data_list.pyi +1 -6
  114. reflex/components/radix/themes/components/dialog.py +4 -2
  115. reflex/components/radix/themes/components/dialog.pyi +4 -9
  116. reflex/components/radix/themes/components/dropdown_menu.py +5 -2
  117. reflex/components/radix/themes/components/dropdown_menu.pyi +4 -10
  118. reflex/components/radix/themes/components/hover_card.py +4 -2
  119. reflex/components/radix/themes/components/hover_card.pyi +4 -6
  120. reflex/components/radix/themes/components/icon_button.py +7 -8
  121. reflex/components/radix/themes/components/icon_button.pyi +1 -3
  122. reflex/components/radix/themes/components/inset.py +1 -2
  123. reflex/components/radix/themes/components/inset.pyi +1 -3
  124. reflex/components/radix/themes/components/popover.py +4 -2
  125. reflex/components/radix/themes/components/popover.pyi +4 -6
  126. reflex/components/radix/themes/components/progress.py +1 -2
  127. reflex/components/radix/themes/components/progress.pyi +1 -3
  128. reflex/components/radix/themes/components/radio.py +1 -2
  129. reflex/components/radix/themes/components/radio.pyi +1 -3
  130. reflex/components/radix/themes/components/radio_cards.py +1 -2
  131. reflex/components/radix/themes/components/radio_cards.pyi +1 -4
  132. reflex/components/radix/themes/components/radio_group.py +7 -5
  133. reflex/components/radix/themes/components/radio_group.pyi +1 -6
  134. reflex/components/radix/themes/components/scroll_area.py +1 -2
  135. reflex/components/radix/themes/components/scroll_area.pyi +1 -3
  136. reflex/components/radix/themes/components/segmented_control.py +1 -2
  137. reflex/components/radix/themes/components/segmented_control.pyi +1 -4
  138. reflex/components/radix/themes/components/select.py +5 -2
  139. reflex/components/radix/themes/components/select.pyi +1 -11
  140. reflex/components/radix/themes/components/separator.py +1 -2
  141. reflex/components/radix/themes/components/separator.pyi +1 -3
  142. reflex/components/radix/themes/components/skeleton.py +1 -2
  143. reflex/components/radix/themes/components/skeleton.pyi +1 -3
  144. reflex/components/radix/themes/components/slider.py +1 -2
  145. reflex/components/radix/themes/components/slider.pyi +1 -3
  146. reflex/components/radix/themes/components/spinner.py +1 -2
  147. reflex/components/radix/themes/components/spinner.pyi +1 -3
  148. reflex/components/radix/themes/components/switch.py +1 -2
  149. reflex/components/radix/themes/components/switch.pyi +1 -3
  150. reflex/components/radix/themes/components/table.py +1 -2
  151. reflex/components/radix/themes/components/table.pyi +1 -9
  152. reflex/components/radix/themes/components/tabs.py +1 -2
  153. reflex/components/radix/themes/components/tabs.pyi +1 -7
  154. reflex/components/radix/themes/components/text_area.py +5 -2
  155. reflex/components/radix/themes/components/text_area.pyi +1 -3
  156. reflex/components/radix/themes/components/text_field.py +5 -2
  157. reflex/components/radix/themes/components/text_field.pyi +1 -5
  158. reflex/components/radix/themes/components/tooltip.py +1 -2
  159. reflex/components/radix/themes/components/tooltip.pyi +1 -3
  160. reflex/components/radix/themes/layout/base.py +5 -2
  161. reflex/components/radix/themes/layout/base.pyi +5 -3
  162. reflex/components/radix/themes/layout/box.py +1 -2
  163. reflex/components/radix/themes/layout/box.pyi +1 -3
  164. reflex/components/radix/themes/layout/center.pyi +0 -1
  165. reflex/components/radix/themes/layout/container.py +1 -2
  166. reflex/components/radix/themes/layout/container.pyi +1 -3
  167. reflex/components/radix/themes/layout/flex.py +6 -2
  168. reflex/components/radix/themes/layout/flex.pyi +1 -3
  169. reflex/components/radix/themes/layout/grid.py +6 -2
  170. reflex/components/radix/themes/layout/grid.pyi +1 -3
  171. reflex/components/radix/themes/layout/list.py +2 -1
  172. reflex/components/radix/themes/layout/list.pyi +0 -5
  173. reflex/components/radix/themes/layout/section.py +1 -2
  174. reflex/components/radix/themes/layout/section.pyi +1 -3
  175. reflex/components/radix/themes/layout/spacer.pyi +0 -1
  176. reflex/components/radix/themes/layout/stack.py +1 -1
  177. reflex/components/radix/themes/layout/stack.pyi +0 -3
  178. reflex/components/radix/themes/typography/blockquote.py +1 -1
  179. reflex/components/radix/themes/typography/blockquote.pyi +1 -3
  180. reflex/components/radix/themes/typography/code.py +5 -1
  181. reflex/components/radix/themes/typography/code.pyi +1 -3
  182. reflex/components/radix/themes/typography/heading.py +1 -1
  183. reflex/components/radix/themes/typography/heading.pyi +1 -3
  184. reflex/components/radix/themes/typography/link.py +3 -2
  185. reflex/components/radix/themes/typography/link.pyi +1 -3
  186. reflex/components/radix/themes/typography/text.py +1 -1
  187. reflex/components/radix/themes/typography/text.pyi +1 -9
  188. reflex/components/react_player/audio.py +0 -2
  189. reflex/components/react_player/audio.pyi +0 -3
  190. reflex/components/react_player/react_player.pyi +0 -1
  191. reflex/components/react_player/video.py +0 -2
  192. reflex/components/react_player/video.pyi +0 -3
  193. reflex/components/recharts/__init__.py +1 -1
  194. reflex/components/recharts/__init__.pyi +1 -1
  195. reflex/components/recharts/cartesian.py +20 -25
  196. reflex/components/recharts/cartesian.pyi +20 -37
  197. reflex/components/recharts/charts.py +2 -1
  198. reflex/components/recharts/charts.pyi +0 -12
  199. reflex/components/recharts/general.pyi +0 -6
  200. reflex/components/recharts/polar.py +5 -4
  201. reflex/components/recharts/polar.pyi +4 -10
  202. reflex/components/recharts/recharts.py +12 -10
  203. reflex/components/recharts/recharts.pyi +10 -11
  204. reflex/components/sonner/toast.py +2 -2
  205. reflex/components/sonner/toast.pyi +0 -2
  206. reflex/components/suneditor/editor.py +2 -1
  207. reflex/components/suneditor/editor.pyi +0 -1
  208. reflex/components/tags/iter_tag.py +4 -2
  209. reflex/config.py +47 -35
  210. reflex/constants/base.py +3 -3
  211. reflex/constants/compiler.py +8 -6
  212. reflex/constants/installer.py +24 -15
  213. reflex/custom_components/custom_components.py +1 -2
  214. reflex/event.py +58 -60
  215. reflex/experimental/__init__.py +2 -2
  216. reflex/experimental/client_state.py +9 -4
  217. reflex/experimental/layout.pyi +0 -5
  218. reflex/istate/manager.py +15 -19
  219. reflex/istate/proxy.py +19 -12
  220. reflex/model.py +6 -4
  221. reflex/plugins/base.py +8 -0
  222. reflex/plugins/tailwind_v3.py +8 -0
  223. reflex/plugins/tailwind_v4.py +8 -0
  224. reflex/reflex.py +9 -11
  225. reflex/route.py +7 -9
  226. reflex/state.py +66 -70
  227. reflex/style.py +3 -1
  228. reflex/testing.py +46 -29
  229. reflex/utils/build.py +2 -1
  230. reflex/utils/console.py +9 -17
  231. reflex/utils/exec.py +9 -11
  232. reflex/utils/format.py +21 -24
  233. reflex/utils/imports.py +4 -3
  234. reflex/utils/lazy_loader.py +3 -3
  235. reflex/utils/misc.py +2 -1
  236. reflex/utils/net.py +2 -2
  237. reflex/utils/path_ops.py +2 -1
  238. reflex/utils/prerequisites.py +67 -38
  239. reflex/utils/processes.py +4 -6
  240. reflex/utils/pyi_generator.py +46 -41
  241. reflex/utils/redir.py +1 -1
  242. reflex/utils/serializers.py +4 -4
  243. reflex/utils/telemetry.py +42 -4
  244. reflex/utils/types.py +16 -13
  245. reflex/vars/base.py +96 -109
  246. reflex/vars/datetime.py +2 -1
  247. reflex/vars/dep_tracking.py +19 -28
  248. reflex/vars/number.py +6 -7
  249. reflex/vars/object.py +5 -6
  250. reflex/vars/sequence.py +11 -11
  251. {reflex-0.7.13a2.dist-info → reflex-0.7.14a1.dist-info}/METADATA +1 -1
  252. reflex-0.7.14a1.dist-info/RECORD +407 -0
  253. reflex-0.7.13a2.dist-info/RECORD +0 -407
  254. {reflex-0.7.13a2.dist-info → reflex-0.7.14a1.dist-info}/WHEEL +0 -0
  255. {reflex-0.7.13a2.dist-info → reflex-0.7.14a1.dist-info}/entry_points.txt +0 -0
  256. {reflex-0.7.13a2.dist-info → reflex-0.7.14a1.dist-info}/licenses/LICENSE +0 -0
@@ -8,8 +8,6 @@ from rxconfig import config
8
8
  class State(rx.State):
9
9
  """The app state."""
10
10
 
11
- ...
12
-
13
11
 
14
12
  def index() -> rx.Component:
15
13
  # Welcome Page (Index)
reflex/app.py CHANGED
@@ -229,8 +229,6 @@ def default_error_boundary(*children: Component) -> Component:
229
229
  class OverlayFragment(Fragment):
230
230
  """Alias for Fragment, used to wrap the overlay_component."""
231
231
 
232
- pass
233
-
234
232
 
235
233
  @dataclasses.dataclass(frozen=True)
236
234
  class UploadFile(StarletteUploadFile):
@@ -262,6 +260,7 @@ class UploadFile(StarletteUploadFile):
262
260
  """
263
261
  if self.path:
264
262
  return self.path.name
263
+ return None
265
264
 
266
265
  @property
267
266
  def filename(self) -> str | None:
@@ -481,9 +480,8 @@ class App(MiddlewareMixin, LifespanMixin):
481
480
  # Special case to allow test cases have multiple subclasses of rx.BaseState.
482
481
  if not is_testing_env() and BaseState.__subclasses__() != [State]:
483
482
  # Only rx.State is allowed as Base State subclass.
484
- raise ValueError(
485
- "rx.BaseState cannot be subclassed directly. Use rx.State instead"
486
- )
483
+ msg = "rx.BaseState cannot be subclassed directly. Use rx.State instead"
484
+ raise ValueError(msg)
487
485
 
488
486
  get_config(reload=True)
489
487
 
@@ -552,9 +550,8 @@ class App(MiddlewareMixin, LifespanMixin):
552
550
  transports=["websocket"],
553
551
  )
554
552
  elif getattr(self.sio, "async_mode", "") != "asgi":
555
- raise RuntimeError(
556
- f"Custom `sio` must use `async_mode='asgi'`, not '{self.sio.async_mode}'."
557
- )
553
+ msg = f"Custom `sio` must use `async_mode='asgi'`, not '{self.sio.async_mode}'."
554
+ raise RuntimeError(msg)
558
555
 
559
556
  # Create the socket app. Note event endpoint constant replaces the default 'socket.io' path.
560
557
  socket_app = EngineIOApp(self.sio, socketio_path="")
@@ -633,7 +630,8 @@ class App(MiddlewareMixin, LifespanMixin):
633
630
  compile_future.result()
634
631
 
635
632
  if not self._api:
636
- raise ValueError("The app has not been initialized.")
633
+ msg = "The app has not been initialized."
634
+ raise ValueError(msg)
637
635
 
638
636
  if self._cached_fastapi_app is not None:
639
637
  asgi_app = self._cached_fastapi_app
@@ -741,7 +739,8 @@ class App(MiddlewareMixin, LifespanMixin):
741
739
  ValueError: if the state has not been initialized.
742
740
  """
743
741
  if self._state_manager is None:
744
- raise ValueError("The state manager has not been initialized.")
742
+ msg = "The state manager has not been initialized."
743
+ raise ValueError(msg)
745
744
  return self._state_manager
746
745
 
747
746
  @staticmethod
@@ -791,9 +790,8 @@ class App(MiddlewareMixin, LifespanMixin):
791
790
  # If the route is not set, get it from the callable.
792
791
  if route is None:
793
792
  if not isinstance(component, Callable):
794
- raise exceptions.RouteValueError(
795
- "Route must be set if component is not a callable."
796
- )
793
+ msg = "Route must be set if component is not a callable."
794
+ raise exceptions.RouteValueError(msg)
797
795
  # Format the route.
798
796
  route = format.format_route(component.__name__)
799
797
  else:
@@ -808,9 +806,8 @@ class App(MiddlewareMixin, LifespanMixin):
808
806
  image = image or constants.Page404.IMAGE
809
807
  else:
810
808
  if component is None:
811
- raise exceptions.PageValueError(
812
- "Component must be set for a non-404 page."
813
- )
809
+ msg = "Component must be set for a non-404 page."
810
+ raise exceptions.PageValueError(msg)
814
811
 
815
812
  # Check if the route given is valid
816
813
  verify_route_validity(route)
@@ -841,11 +838,12 @@ class App(MiddlewareMixin, LifespanMixin):
841
838
  else f"`{route}`"
842
839
  )
843
840
  existing_component = self._unevaluated_pages[route].component
844
- raise exceptions.RouteValueError(
841
+ msg = (
845
842
  f"Tried to add page {readable_name_from_component(component)} with route {route_name} but "
846
843
  f"page {readable_name_from_component(existing_component)} with the same route already exists. "
847
844
  "Make sure you do not have two pages with the same route."
848
845
  )
846
+ raise exceptions.RouteValueError(msg)
849
847
 
850
848
  # Setup dynamic args for the route.
851
849
  # this state assignment is only required for tests using the deprecated state kwarg for App
@@ -930,10 +928,9 @@ class App(MiddlewareMixin, LifespanMixin):
930
928
  ):
931
929
  if rw in segments and r != nr:
932
930
  # If the slugs in the segments of both routes are not the same, then the route is invalid
933
- raise RouteValueError(
934
- f"You cannot use different slug names for the same dynamic path in {route} and {new_route} ('{r}' != '{nr}')"
935
- )
936
- elif rw not in segments and r != nr:
931
+ msg = f"You cannot use different slug names for the same dynamic path in {route} and {new_route} ('{r}' != '{nr}')"
932
+ raise RouteValueError(msg)
933
+ if rw not in segments and r != nr:
937
934
  # if the section being compared in both routes is not a dynamic segment(i.e not wrapped in brackets)
938
935
  # then we are guaranteed that the route is valid and there's no need checking the rest.
939
936
  # eg. /posts/[id]/info/[slug1] and /posts/[id]/info1/[slug1] is always going to be valid since
@@ -1019,11 +1016,13 @@ class App(MiddlewareMixin, LifespanMixin):
1019
1016
  Example:
1020
1017
  >>> _get_frontend_packages({"react": "16.14.0", "react-dom": "16.14.0"})
1021
1018
  """
1019
+ dependencies = constants.PackageJson.DEPENDENCIES
1020
+ dev_dependencies = constants.PackageJson.DEV_DEPENDENCIES
1022
1021
  page_imports = {
1023
1022
  i
1024
1023
  for i, tags in imports.items()
1025
- if i not in constants.PackageJson.DEPENDENCIES
1026
- and i not in constants.PackageJson.DEV_DEPENDENCIES
1024
+ if i not in dependencies
1025
+ and i not in dev_dependencies
1027
1026
  and not any(i.startswith(prefix) for prefix in ["/", "$/", ".", "next/"])
1028
1027
  and i != ""
1029
1028
  and any(tag.install for tag in tags)
@@ -1086,9 +1085,7 @@ class App(MiddlewareMixin, LifespanMixin):
1086
1085
  return component
1087
1086
 
1088
1087
  # recreate OverlayFragment with overlay_component as first child
1089
- component = OverlayFragment.create(overlay_component, *children)
1090
-
1091
- return component
1088
+ return OverlayFragment.create(overlay_component, *children)
1092
1089
 
1093
1090
  def _setup_overlay_component(self):
1094
1091
  """If a State is not used and no overlay_component is specified, do not render the connection modal."""
@@ -1150,9 +1147,8 @@ class App(MiddlewareMixin, LifespanMixin):
1150
1147
  )
1151
1148
  for dep in dep_set:
1152
1149
  if dep not in state_cls.vars and dep not in state_cls.backend_vars:
1153
- raise exceptions.VarDependencyError(
1154
- f"ComputedVar {var._js_expr} on state {state.__name__} has an invalid dependency {state_name}.{dep}"
1155
- )
1150
+ msg = f"ComputedVar {var._js_expr} on state {state.__name__} has an invalid dependency {state_name}.{dep}"
1151
+ raise exceptions.VarDependencyError(msg)
1156
1152
 
1157
1153
  for substate in state.class_subclasses:
1158
1154
  self._validate_var_dependencies(substate)
@@ -1344,10 +1340,11 @@ class App(MiddlewareMixin, LifespanMixin):
1344
1340
 
1345
1341
  # Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State.
1346
1342
  if code_uses_state_contexts(stateful_components_code) and self._state is None:
1347
- raise ReflexRuntimeError(
1343
+ msg = (
1348
1344
  "To access rx.State in frontend components, at least one "
1349
1345
  "subclass of rx.State must be defined in the app."
1350
1346
  )
1347
+ raise ReflexRuntimeError(msg)
1351
1348
  compile_results.append((stateful_components_path, stateful_components_code))
1352
1349
 
1353
1350
  progress.advance(task)
@@ -1541,9 +1538,8 @@ class App(MiddlewareMixin, LifespanMixin):
1541
1538
  if path.exists():
1542
1539
  file_content = path.read_text()
1543
1540
  else:
1544
- raise FileNotFoundError(
1545
- f"Plugin {plugin_name} is trying to modify {path} but it does not exist."
1546
- )
1541
+ msg = f"Plugin {plugin_name} is trying to modify {path} but it does not exist."
1542
+ raise FileNotFoundError(msg)
1547
1543
  output_mapping[path] = modify_fn(file_content)
1548
1544
 
1549
1545
  with console.timing("Write to Disk"):
@@ -1586,7 +1582,8 @@ class App(MiddlewareMixin, LifespanMixin):
1586
1582
  RuntimeError: If the app has not been initialized yet.
1587
1583
  """
1588
1584
  if self.event_namespace is None:
1589
- raise RuntimeError("App has not been initialized yet.")
1585
+ msg = "App has not been initialized yet."
1586
+ raise RuntimeError(msg)
1590
1587
 
1591
1588
  # Get exclusive access to the state.
1592
1589
  async with self.state_manager.modify_state(token) as state:
@@ -1625,7 +1622,8 @@ class App(MiddlewareMixin, LifespanMixin):
1625
1622
  RuntimeError: If the app has not been initialized yet.
1626
1623
  """
1627
1624
  if self.event_namespace is None:
1628
- raise RuntimeError("App has not been initialized yet.")
1625
+ msg = "App has not been initialized yet."
1626
+ raise RuntimeError(msg)
1629
1627
 
1630
1628
  # Process the event.
1631
1629
  async for update in state._process_event(
@@ -1676,20 +1674,17 @@ class App(MiddlewareMixin, LifespanMixin):
1676
1674
  _fn_name = type(handler_fn).__name__
1677
1675
 
1678
1676
  if isinstance(handler_fn, functools.partial):
1679
- raise ValueError(
1680
- f"Provided custom {handler_domain} exception handler `{_fn_name}` is a partial function. Please provide a named function instead."
1681
- )
1677
+ msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` is a partial function. Please provide a named function instead."
1678
+ raise ValueError(msg)
1682
1679
 
1683
1680
  if not callable(handler_fn):
1684
- raise ValueError(
1685
- f"Provided custom {handler_domain} exception handler `{_fn_name}` is not a function."
1686
- )
1681
+ msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` is not a function."
1682
+ raise ValueError(msg)
1687
1683
 
1688
1684
  # Allow named functions only as lambda functions cannot be introspected
1689
1685
  if _fn_name == "<lambda>":
1690
- raise ValueError(
1691
- f"Provided custom {handler_domain} exception handler `{_fn_name}` is a lambda function. Please use a named function instead."
1692
- )
1686
+ msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` is a lambda function. Please use a named function instead."
1687
+ raise ValueError(msg)
1693
1688
 
1694
1689
  # Check if the function has the necessary annotations and types in the right order
1695
1690
  argspec = inspect.getfullargspec(handler_fn)
@@ -1701,22 +1696,21 @@ class App(MiddlewareMixin, LifespanMixin):
1701
1696
 
1702
1697
  for required_arg_index, required_arg in enumerate(handler_spec):
1703
1698
  if required_arg not in arg_annotations:
1704
- raise ValueError(
1705
- f"Provided custom {handler_domain} exception handler `{_fn_name}` does not take the required argument `{required_arg}`"
1706
- )
1707
- elif (
1708
- not list(arg_annotations.keys())[required_arg_index] == required_arg
1709
- ):
1710
- raise ValueError(
1699
+ msg = f"Provided custom {handler_domain} exception handler `{_fn_name}` does not take the required argument `{required_arg}`"
1700
+ raise ValueError(msg)
1701
+ if list(arg_annotations.keys())[required_arg_index] != required_arg:
1702
+ msg = (
1711
1703
  f"Provided custom {handler_domain} exception handler `{_fn_name}` has the wrong argument order."
1712
1704
  f"Expected `{required_arg}` as the {required_arg_index + 1} argument but got `{list(arg_annotations.keys())[required_arg_index]}`"
1713
1705
  )
1706
+ raise ValueError(msg)
1714
1707
 
1715
1708
  if not issubclass(arg_annotations[required_arg], Exception):
1716
- raise ValueError(
1709
+ msg = (
1717
1710
  f"Provided custom {handler_domain} exception handler `{_fn_name}` has the wrong type for {required_arg} argument."
1718
1711
  f"Expected to be `Exception` but got `{arg_annotations[required_arg]}`"
1719
1712
  )
1713
+ raise ValueError(msg)
1720
1714
 
1721
1715
  # Check if the return type is valid for backend exception handler
1722
1716
  if handler_domain == "backend":
@@ -1736,10 +1730,11 @@ class App(MiddlewareMixin, LifespanMixin):
1736
1730
  )
1737
1731
 
1738
1732
  if not valid:
1739
- raise ValueError(
1733
+ msg = (
1740
1734
  f"Provided custom {handler_domain} exception handler `{_fn_name}` has the wrong return type."
1741
1735
  f"Expected `EventSpec | list[EventSpec] | None` but got `{return_type}`"
1742
1736
  )
1737
+ raise ValueError(msg)
1743
1738
 
1744
1739
 
1745
1740
  async def process(
@@ -1908,7 +1903,8 @@ def upload(app: App):
1908
1903
  return Response() # user cancelled
1909
1904
  files = files.getlist("files")
1910
1905
  if not files:
1911
- raise UploadValueError("No files were uploaded.")
1906
+ msg = "No files were uploaded."
1907
+ raise UploadValueError(msg)
1912
1908
 
1913
1909
  token = request.headers.get("reflex-client-token")
1914
1910
  handler = request.headers.get("reflex-event-handler")
@@ -1935,9 +1931,8 @@ def upload(app: App):
1935
1931
  # check if there exists any handler args with annotation, list[UploadFile]
1936
1932
  if isinstance(func, EventHandler):
1937
1933
  if func.is_background:
1938
- raise UploadTypeError(
1939
- f"@rx.event(background=True) is not supported for upload handler `{handler}`.",
1940
- )
1934
+ msg = f"@rx.event(background=True) is not supported for upload handler `{handler}`."
1935
+ raise UploadTypeError(msg)
1941
1936
  func = func.fn
1942
1937
  if isinstance(func, functools.partial):
1943
1938
  func = func.func
@@ -1950,10 +1945,11 @@ def upload(app: App):
1950
1945
  break
1951
1946
 
1952
1947
  if not handler_upload_param:
1953
- raise UploadValueError(
1948
+ msg = (
1954
1949
  f"`{handler}` handler should have a parameter annotated as "
1955
1950
  "list[rx.UploadFile]"
1956
1951
  )
1952
+ raise UploadValueError(msg)
1957
1953
 
1958
1954
  # Make a copy of the files as they are closed after the request.
1959
1955
  # This behaviour changed from fastapi 0.103.0 to 0.103.1 as the
@@ -2096,32 +2092,31 @@ class EventNamespace(AsyncNamespace):
2096
2092
  try:
2097
2093
  fields = json.loads(fields)
2098
2094
  except json.JSONDecodeError as ex:
2099
- raise exceptions.EventDeserializationError(
2100
- f"Failed to deserialize event data: {fields}."
2101
- ) from ex
2095
+ msg = f"Failed to deserialize event data: {fields}."
2096
+ raise exceptions.EventDeserializationError(msg) from ex
2102
2097
 
2103
2098
  if not isinstance(fields, dict):
2104
- raise exceptions.EventDeserializationError(
2105
- f"Event data must be a dictionary, but received {fields} of type {type(fields)}."
2106
- )
2099
+ msg = f"Event data must be a dictionary, but received {fields} of type {type(fields)}."
2100
+ raise exceptions.EventDeserializationError(msg)
2107
2101
 
2108
2102
  try:
2109
2103
  # Get the event.
2110
2104
  event = Event(**{k: v for k, v in fields.items() if k in _EVENT_FIELDS})
2111
2105
  except (TypeError, ValueError) as ex:
2112
- raise exceptions.EventDeserializationError(
2113
- f"Failed to deserialize event data: {fields}."
2114
- ) from ex
2106
+ msg = f"Failed to deserialize event data: {fields}."
2107
+ raise exceptions.EventDeserializationError(msg) from ex
2115
2108
 
2116
2109
  self.token_to_sid[event.token] = sid
2117
2110
  self.sid_to_token[sid] = event.token
2118
2111
 
2119
2112
  # Get the event environment.
2120
2113
  if self.app.sio is None:
2121
- raise RuntimeError("Socket.IO is not initialized.")
2114
+ msg = "Socket.IO is not initialized."
2115
+ raise RuntimeError(msg)
2122
2116
  environ = self.app.sio.get_environ(sid, self.namespace)
2123
2117
  if environ is None:
2124
- raise RuntimeError("Socket.IO environ is not initialized.")
2118
+ msg = "Socket.IO environ is not initialized."
2119
+ raise RuntimeError(msg)
2125
2120
 
2126
2121
  # Get the client headers.
2127
2122
  headers = {
@@ -67,9 +67,8 @@ class LifespanMixin(AppMixin):
67
67
  InvalidLifespanTaskTypeError: If the task is a generator function.
68
68
  """
69
69
  if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task):
70
- raise InvalidLifespanTaskTypeError(
71
- f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
72
- )
70
+ msg = f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
71
+ raise InvalidLifespanTaskTypeError(msg)
73
72
 
74
73
  if task_kwargs:
75
74
  original_task = task
@@ -56,6 +56,7 @@ class MiddlewareMixin(AppMixin):
56
56
  out = await out
57
57
  if out is not None:
58
58
  return out
59
+ return None
59
60
 
60
61
  async def _postprocess(
61
62
  self, state: BaseState, event: Event, update: StateUpdate
@@ -12,4 +12,3 @@ class AppMixin:
12
12
 
13
13
  Any App mixin can override this method to perform any initialization.
14
14
  """
15
- ...
reflex/assets.py CHANGED
@@ -58,9 +58,11 @@ def asset(
58
58
  cwd = Path.cwd()
59
59
  src_file_local = cwd / assets / path
60
60
  if subfolder is not None:
61
- raise ValueError("Subfolder is not supported for local assets.")
61
+ msg = "Subfolder is not supported for local assets."
62
+ raise ValueError(msg)
62
63
  if not backend_only and not src_file_local.exists():
63
- raise FileNotFoundError(f"File not found: {src_file_local}")
64
+ msg = f"File not found: {src_file_local}"
65
+ raise FileNotFoundError(msg)
64
66
  return f"/{path}"
65
67
 
66
68
  # Shared asset handling
@@ -73,7 +75,8 @@ def asset(
73
75
  external = constants.Dirs.EXTERNAL_APP_ASSETS
74
76
  src_file_shared = Path(calling_file).parent / path
75
77
  if not src_file_shared.exists():
76
- raise FileNotFoundError(f"File not found: {src_file_shared}")
78
+ msg = f"File not found: {src_file_shared}"
79
+ raise FileNotFoundError(msg)
77
80
 
78
81
  caller_module_path = module.__name__.replace(".", "/")
79
82
  subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path
reflex/base.py CHANGED
@@ -30,10 +30,11 @@ def validate_field_name(bases: list[type[BaseModel]], field_name: str) -> None:
30
30
  if not reload and getattr(base, field_name, None):
31
31
  pass
32
32
  except TypeError as te:
33
- raise VarNameError(
33
+ msg = (
34
34
  f'State var "{field_name}" in {base} has been shadowed by a substate var; '
35
35
  f'use a different field name instead".'
36
- ) from te
36
+ )
37
+ raise VarNameError(msg) from te
37
38
 
38
39
 
39
40
  # monkeypatch pydantic validate_field_name method to skip validating
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import sys
5
6
  from collections.abc import Iterable, Sequence
6
7
  from datetime import datetime
7
8
  from inspect import getmodule
@@ -200,15 +201,14 @@ def _validate_stylesheet(stylesheet_full_path: Path, assets_app_path: Path) -> N
200
201
  """
201
202
  suffix = stylesheet_full_path.suffix[1:] if stylesheet_full_path.suffix else ""
202
203
  if suffix not in constants.Reflex.STYLESHEETS_SUPPORTED:
203
- raise ValueError(f"Stylesheet file {stylesheet_full_path} is not supported.")
204
+ msg = f"Stylesheet file {stylesheet_full_path} is not supported."
205
+ raise ValueError(msg)
204
206
  if not stylesheet_full_path.absolute().is_relative_to(assets_app_path.absolute()):
205
- raise FileNotFoundError(
206
- f"Cannot include stylesheets from outside the assets directory: {stylesheet_full_path}"
207
- )
207
+ msg = f"Cannot include stylesheets from outside the assets directory: {stylesheet_full_path}"
208
+ raise FileNotFoundError(msg)
208
209
  if not stylesheet_full_path.name:
209
- raise ValueError(
210
- f"Stylesheet file name cannot be empty: {stylesheet_full_path}"
211
- )
210
+ msg = f"Stylesheet file name cannot be empty: {stylesheet_full_path}"
211
+ raise ValueError(msg)
212
212
  if (
213
213
  len(
214
214
  stylesheet_full_path.absolute()
@@ -218,9 +218,8 @@ def _validate_stylesheet(stylesheet_full_path: Path, assets_app_path: Path) -> N
218
218
  == 1
219
219
  and stylesheet_full_path.stem == PageNames.STYLESHEET_ROOT
220
220
  ):
221
- raise ValueError(
222
- f"Stylesheet file name cannot be '{PageNames.STYLESHEET_ROOT}': {stylesheet_full_path}"
223
- )
221
+ msg = f"Stylesheet file name cannot be '{PageNames.STYLESHEET_ROOT}': {stylesheet_full_path}"
222
+ raise ValueError(msg)
224
223
 
225
224
 
226
225
  RADIX_THEMES_STYLESHEET = "@radix-ui/themes/styles.css"
@@ -257,9 +256,8 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
257
256
  stylesheet_full_path = assets_app_path / stylesheet.strip("/")
258
257
 
259
258
  if not stylesheet_full_path.exists():
260
- raise FileNotFoundError(
261
- f"The stylesheet file {stylesheet_full_path} does not exist."
262
- )
259
+ msg = f"The stylesheet file {stylesheet_full_path} does not exist."
260
+ raise FileNotFoundError(msg)
263
261
 
264
262
  if stylesheet_full_path.is_dir():
265
263
  all_files = (
@@ -685,12 +683,12 @@ def into_component(component: Component | ComponentCallable) -> Component:
685
683
  """
686
684
  if (converted := _into_component_once(component)) is not None:
687
685
  return converted
686
+ if not callable(component):
687
+ msg = f"Expected a Component or callable, got {component!r} of type {type(component)}"
688
+ raise TypeError(msg)
689
+
688
690
  try:
689
- if (
690
- callable(component)
691
- and (converted := _into_component_once(component())) is not None
692
- ):
693
- return converted
691
+ component_called = component()
694
692
  except KeyError as e:
695
693
  if isinstance(e, ReflexError):
696
694
  raise
@@ -714,9 +712,10 @@ def into_component(component: Component | ComponentCallable) -> Component:
714
712
  "Cannot pass a Var to a built-in function. Consider using .length() for accessing the length of an iterable Var."
715
713
  ).with_traceback(e.__traceback__) from None
716
714
  if message.endswith(
717
- "indices must be integers or slices, not NumberCastedVar"
718
- ) or message.endswith(
719
- "indices must be integers or slices, not BooleanCastedVar"
715
+ (
716
+ "indices must be integers or slices, not NumberCastedVar",
717
+ "indices must be integers or slices, not BooleanCastedVar",
718
+ )
720
719
  ):
721
720
  raise TypeError(
722
721
  "Cannot index into a primitive sequence with a Var. Consider calling rx.Var.create() on the sequence."
@@ -727,7 +726,11 @@ def into_component(component: Component | ComponentCallable) -> Component:
727
726
  ).with_traceback(e.__traceback__) from None
728
727
  raise
729
728
 
730
- raise TypeError(f"Expected a Component, got {type(component)}")
729
+ if (converted := _into_component_once(component_called)) is not None:
730
+ return converted
731
+
732
+ msg = f"Expected a Component, got {component_called!r} of type {type(component_called)}"
733
+ raise TypeError(msg)
731
734
 
732
735
 
733
736
  def compile_unevaluated_page(
@@ -748,52 +751,61 @@ def compile_unevaluated_page(
748
751
 
749
752
  Returns:
750
753
  The compiled component and whether state should be enabled.
754
+
755
+ Raises:
756
+ Exception: If an error occurs while evaluating the page.
751
757
  """
752
- # Generate the component if it is a callable.
753
- component = into_component(page.component)
758
+ try:
759
+ # Generate the component if it is a callable.
760
+ component = into_component(page.component)
754
761
 
755
- component._add_style_recursive(style or {}, theme)
762
+ component._add_style_recursive(style or {}, theme)
756
763
 
757
- enable_state = False
758
- # Ensure state is enabled if this page uses state.
759
- if state is None:
760
- if page.on_load or component._has_stateful_event_triggers():
761
- enable_state = True
762
- else:
763
- for var in component._get_vars(include_children=True):
764
- var_data = var._get_all_var_data()
765
- if not var_data:
766
- continue
767
- if not var_data.state:
768
- continue
764
+ enable_state = False
765
+ # Ensure state is enabled if this page uses state.
766
+ if state is None:
767
+ if page.on_load or component._has_stateful_event_triggers():
769
768
  enable_state = True
770
- break
771
-
772
- from reflex.app import OverlayFragment
773
- from reflex.utils.format import make_default_page_title
774
-
775
- component = OverlayFragment.create(component)
776
-
777
- meta_args = {
778
- "title": (
779
- page.title
780
- if page.title is not None
781
- else make_default_page_title(get_config().app_name, route)
782
- ),
783
- "image": page.image,
784
- "meta": page.meta,
785
- }
786
-
787
- if page.description is not None:
788
- meta_args["description"] = page.description
789
-
790
- # Add meta information to the component.
791
- utils.add_meta(
792
- component,
793
- **meta_args,
794
- )
769
+ else:
770
+ for var in component._get_vars(include_children=True):
771
+ var_data = var._get_all_var_data()
772
+ if not var_data:
773
+ continue
774
+ if not var_data.state:
775
+ continue
776
+ enable_state = True
777
+ break
778
+
779
+ from reflex.app import OverlayFragment
780
+ from reflex.utils.format import make_default_page_title
781
+
782
+ component = OverlayFragment.create(component)
783
+
784
+ meta_args = {
785
+ "title": (
786
+ page.title
787
+ if page.title is not None
788
+ else make_default_page_title(get_config().app_name, route)
789
+ ),
790
+ "image": page.image,
791
+ "meta": page.meta,
792
+ }
793
+
794
+ if page.description is not None:
795
+ meta_args["description"] = page.description
796
+
797
+ # Add meta information to the component.
798
+ utils.add_meta(
799
+ component,
800
+ **meta_args,
801
+ )
795
802
 
796
- return component, enable_state
803
+ except Exception as e:
804
+ if sys.version_info >= (3, 11):
805
+ e.add_note(f"Happened while evaluating page {route!r}")
806
+ raise
807
+ else:
808
+ return component, enable_state
797
809
 
798
810
 
799
811
  class ExecutorSafeFunctions:
@@ -873,5 +885,6 @@ class ExecutorSafeFunctions:
873
885
  ValueError: If the style is not set.
874
886
  """
875
887
  if style is None:
876
- raise ValueError("STYLE should be set")
888
+ msg = "STYLE should be set"
889
+ raise ValueError(msg)
877
890
  return compile_theme(style)
reflex/compiler/utils.py CHANGED
@@ -60,7 +60,8 @@ def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]:
60
60
  # Check for default imports.
61
61
  defaults = {field for field in fields_set if field.is_default}
62
62
  if len(defaults) >= 2:
63
- raise ValueError("Only one default import is allowed.")
63
+ msg = "Only one default import is allowed."
64
+ raise ValueError(msg)
64
65
 
65
66
  # Get the default import, and the specific imports.
66
67
  default = next(iter({field.name for field in defaults}), "")
@@ -91,9 +92,8 @@ def validate_imports(import_dict: ParsedImportDict):
91
92
  ):
92
93
  used_tags[import_name] = lib if lib[0] == "$" else already_imported
93
94
  continue
94
- raise ValueError(
95
- f"Can not compile, the tag {import_name} is used multiple time from {lib} and {used_tags[import_name]}"
96
- )
95
+ msg = f"Can not compile, the tag {import_name} is used multiple time from {lib} and {used_tags[import_name]}"
96
+ raise ValueError(msg)
97
97
  if import_name is not None:
98
98
  used_tags[import_name] = lib
99
99
 
@@ -130,9 +130,11 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
130
130
  for path, (default, rest) in compiled.items():
131
131
  if not lib:
132
132
  if default:
133
- raise ValueError("No default field allowed for empty library.")
133
+ msg = "No default field allowed for empty library."
134
+ raise ValueError(msg)
134
135
  if rest is None or len(rest) == 0:
135
- raise ValueError("No fields to import.")
136
+ msg = "No fields to import."
137
+ raise ValueError(msg)
136
138
  import_dicts.extend(get_import_dict(module) for module in sorted(rest))
137
139
  continue
138
140