reflex 0.5.10a3__py3-none-any.whl → 0.6.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 (303) hide show
  1. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +2 -2
  2. reflex/.templates/jinja/web/pages/_app.js.jinja2 +1 -1
  3. reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -4
  4. reflex/.templates/jinja/web/utils/context.js.jinja2 +1 -1
  5. reflex/.templates/jinja/web/utils/theme.js.jinja2 +1 -1
  6. reflex/.templates/web/utils/state.js +3 -1
  7. reflex/__init__.py +10 -3
  8. reflex/__init__.pyi +3 -2
  9. reflex/app.py +47 -11
  10. reflex/app_module_for_backend.py +1 -1
  11. reflex/base.py +3 -2
  12. reflex/compiler/compiler.py +5 -5
  13. reflex/compiler/utils.py +5 -3
  14. reflex/components/base/app_wrap.py +2 -4
  15. reflex/components/base/app_wrap.pyi +16 -26
  16. reflex/components/base/bare.py +6 -4
  17. reflex/components/base/body.pyi +16 -26
  18. reflex/components/base/document.pyi +76 -126
  19. reflex/components/base/error_boundary.py +9 -8
  20. reflex/components/base/error_boundary.pyi +18 -30
  21. reflex/components/base/fragment.pyi +16 -26
  22. reflex/components/base/head.pyi +31 -51
  23. reflex/components/base/link.py +1 -1
  24. reflex/components/base/link.pyi +31 -51
  25. reflex/components/base/meta.pyi +61 -101
  26. reflex/components/base/script.py +2 -2
  27. reflex/components/base/script.pyi +20 -36
  28. reflex/components/component.py +107 -130
  29. reflex/components/core/banner.py +61 -66
  30. reflex/components/core/banner.pyi +129 -230
  31. reflex/components/core/client_side_routing.py +2 -2
  32. reflex/components/core/client_side_routing.pyi +31 -51
  33. reflex/components/core/clipboard.py +4 -3
  34. reflex/components/core/clipboard.pyi +19 -31
  35. reflex/components/core/cond.py +21 -44
  36. reflex/components/core/debounce.py +7 -9
  37. reflex/components/core/debounce.pyi +19 -31
  38. reflex/components/core/foreach.py +4 -14
  39. reflex/components/core/html.py +1 -1
  40. reflex/components/core/html.pyi +34 -44
  41. reflex/components/core/match.py +36 -43
  42. reflex/components/core/upload.py +27 -26
  43. reflex/components/core/upload.pyi +81 -116
  44. reflex/components/datadisplay/code.py +55 -29
  45. reflex/components/datadisplay/code.pyi +303 -410
  46. reflex/components/datadisplay/dataeditor.py +13 -9
  47. reflex/components/datadisplay/dataeditor.pyi +39 -51
  48. reflex/components/el/__init__.py +0 -1
  49. reflex/components/el/__init__.pyi +0 -11
  50. reflex/components/el/element.pyi +16 -26
  51. reflex/components/el/elements/__init__.py +1 -7
  52. reflex/components/el/elements/__init__.pyi +1 -15
  53. reflex/components/el/elements/base.py +1 -1
  54. reflex/components/el/elements/base.pyi +33 -43
  55. reflex/components/el/elements/forms.py +26 -33
  56. reflex/components/el/elements/forms.pyi +542 -694
  57. reflex/components/el/elements/inline.py +1 -1
  58. reflex/components/el/elements/inline.pyi +909 -1189
  59. reflex/components/el/elements/media.py +1 -22
  60. reflex/components/el/elements/media.pyi +765 -975
  61. reflex/components/el/elements/metadata.py +3 -5
  62. reflex/components/el/elements/metadata.pyi +175 -235
  63. reflex/components/el/elements/other.py +1 -1
  64. reflex/components/el/elements/other.pyi +228 -298
  65. reflex/components/el/elements/scripts.py +1 -1
  66. reflex/components/el/elements/scripts.pyi +106 -136
  67. reflex/components/el/elements/sectioning.py +0 -2
  68. reflex/components/el/elements/sectioning.pyi +481 -631
  69. reflex/components/el/elements/tables.py +1 -1
  70. reflex/components/el/elements/tables.pyi +341 -441
  71. reflex/components/el/elements/typography.py +1 -1
  72. reflex/components/el/elements/typography.pyi +491 -641
  73. reflex/components/gridjs/datatable.py +9 -13
  74. reflex/components/gridjs/datatable.pyi +33 -53
  75. reflex/components/lucide/icon.py +3 -127
  76. reflex/components/lucide/icon.pyi +31 -160
  77. reflex/components/markdown/markdown.py +32 -42
  78. reflex/components/markdown/markdown.pyi +28 -41
  79. reflex/components/moment/moment.py +13 -12
  80. reflex/components/moment/moment.pyi +22 -33
  81. reflex/components/next/base.pyi +16 -26
  82. reflex/components/next/image.py +1 -5
  83. reflex/components/next/image.pyi +21 -35
  84. reflex/components/next/link.py +1 -1
  85. reflex/components/next/link.pyi +16 -26
  86. reflex/components/next/video.py +1 -1
  87. reflex/components/next/video.pyi +16 -26
  88. reflex/components/plotly/plotly.py +17 -30
  89. reflex/components/plotly/plotly.pyi +38 -52
  90. reflex/components/props.py +21 -10
  91. reflex/components/radix/__init__.pyi +2 -1
  92. reflex/components/radix/primitives/accordion.py +6 -7
  93. reflex/components/radix/primitives/accordion.pyi +415 -485
  94. reflex/components/radix/primitives/base.py +1 -1
  95. reflex/components/radix/primitives/base.pyi +31 -51
  96. reflex/components/radix/primitives/drawer.py +1 -1
  97. reflex/components/radix/primitives/drawer.pyi +162 -262
  98. reflex/components/radix/primitives/form.py +1 -1
  99. reflex/components/radix/primitives/form.pyi +247 -353
  100. reflex/components/radix/primitives/progress.py +1 -1
  101. reflex/components/radix/primitives/progress.pyi +226 -276
  102. reflex/components/radix/primitives/slider.py +1 -1
  103. reflex/components/radix/primitives/slider.pyi +82 -132
  104. reflex/components/radix/themes/base.py +8 -25
  105. reflex/components/radix/themes/base.pyi +171 -242
  106. reflex/components/radix/themes/color_mode.py +11 -20
  107. reflex/components/radix/themes/color_mode.pyi +198 -231
  108. reflex/components/radix/themes/components/__init__.pyi +1 -0
  109. reflex/components/radix/themes/components/alert_dialog.py +1 -1
  110. reflex/components/radix/themes/components/alert_dialog.pyi +129 -199
  111. reflex/components/radix/themes/components/aspect_ratio.py +1 -1
  112. reflex/components/radix/themes/components/aspect_ratio.pyi +16 -26
  113. reflex/components/radix/themes/components/avatar.py +1 -1
  114. reflex/components/radix/themes/components/avatar.pyi +69 -79
  115. reflex/components/radix/themes/components/badge.py +1 -1
  116. reflex/components/radix/themes/components/badge.pyi +87 -97
  117. reflex/components/radix/themes/components/button.py +1 -1
  118. reflex/components/radix/themes/components/button.pyi +97 -107
  119. reflex/components/radix/themes/components/callout.py +1 -1
  120. reflex/components/radix/themes/components/callout.pyi +317 -367
  121. reflex/components/radix/themes/components/card.py +1 -1
  122. reflex/components/radix/themes/components/card.pyi +37 -47
  123. reflex/components/radix/themes/components/checkbox.py +2 -4
  124. reflex/components/radix/themes/components/checkbox.pyi +205 -241
  125. reflex/components/radix/themes/components/checkbox_cards.py +1 -1
  126. reflex/components/radix/themes/components/checkbox_cards.pyi +92 -112
  127. reflex/components/radix/themes/components/checkbox_group.py +1 -1
  128. reflex/components/radix/themes/components/checkbox_group.pyi +84 -104
  129. reflex/components/radix/themes/components/context_menu.py +1 -1
  130. reflex/components/radix/themes/components/context_menu.pyi +230 -310
  131. reflex/components/radix/themes/components/data_list.py +6 -1
  132. reflex/components/radix/themes/components/data_list.pyi +131 -166
  133. reflex/components/radix/themes/components/dialog.py +1 -1
  134. reflex/components/radix/themes/components/dialog.pyi +132 -202
  135. reflex/components/radix/themes/components/dropdown_menu.py +1 -1
  136. reflex/components/radix/themes/components/dropdown_menu.pyi +241 -323
  137. reflex/components/radix/themes/components/hover_card.py +1 -1
  138. reflex/components/radix/themes/components/hover_card.pyi +86 -126
  139. reflex/components/radix/themes/components/icon_button.py +1 -1
  140. reflex/components/radix/themes/components/icon_button.pyi +97 -107
  141. reflex/components/radix/themes/components/inset.py +1 -1
  142. reflex/components/radix/themes/components/inset.pyi +46 -56
  143. reflex/components/radix/themes/components/popover.py +1 -1
  144. reflex/components/radix/themes/components/popover.pyi +91 -131
  145. reflex/components/radix/themes/components/progress.py +1 -1
  146. reflex/components/radix/themes/components/progress.pyi +70 -80
  147. reflex/components/radix/themes/components/radio.py +1 -1
  148. reflex/components/radix/themes/components/radio.pyi +68 -78
  149. reflex/components/radix/themes/components/radio_cards.py +1 -1
  150. reflex/components/radix/themes/components/radio_cards.pyi +96 -116
  151. reflex/components/radix/themes/components/radio_group.py +32 -31
  152. reflex/components/radix/themes/components/radio_group.pyi +230 -266
  153. reflex/components/radix/themes/components/scroll_area.py +1 -1
  154. reflex/components/radix/themes/components/scroll_area.pyi +20 -30
  155. reflex/components/radix/themes/components/segmented_control.py +1 -1
  156. reflex/components/radix/themes/components/segmented_control.pyi +88 -110
  157. reflex/components/radix/themes/components/select.py +1 -1
  158. reflex/components/radix/themes/components/select.pyi +365 -461
  159. reflex/components/radix/themes/components/separator.py +2 -4
  160. reflex/components/radix/themes/components/separator.pyi +68 -78
  161. reflex/components/radix/themes/components/skeleton.py +1 -1
  162. reflex/components/radix/themes/components/skeleton.pyi +22 -32
  163. reflex/components/radix/themes/components/slider.py +1 -1
  164. reflex/components/radix/themes/components/slider.pyi +74 -86
  165. reflex/components/radix/themes/components/spinner.py +1 -1
  166. reflex/components/radix/themes/components/spinner.pyi +18 -28
  167. reflex/components/radix/themes/components/switch.py +1 -1
  168. reflex/components/radix/themes/components/switch.pyi +70 -82
  169. reflex/components/radix/themes/components/table.py +1 -1
  170. reflex/components/radix/themes/components/table.pyi +254 -324
  171. reflex/components/radix/themes/components/tabs.py +1 -1
  172. reflex/components/radix/themes/components/tabs.pyi +134 -188
  173. reflex/components/radix/themes/components/text_area.py +1 -1
  174. reflex/components/radix/themes/components/text_area.pyi +95 -109
  175. reflex/components/radix/themes/components/text_field.py +1 -80
  176. reflex/components/radix/themes/components/text_field.pyi +245 -290
  177. reflex/components/radix/themes/components/tooltip.py +1 -1
  178. reflex/components/radix/themes/components/tooltip.pyi +25 -35
  179. reflex/components/radix/themes/layout/__init__.pyi +1 -0
  180. reflex/components/radix/themes/layout/base.py +1 -1
  181. reflex/components/radix/themes/layout/base.pyi +55 -65
  182. reflex/components/radix/themes/layout/box.pyi +33 -43
  183. reflex/components/radix/themes/layout/center.pyi +55 -65
  184. reflex/components/radix/themes/layout/container.py +2 -4
  185. reflex/components/radix/themes/layout/container.pyi +35 -45
  186. reflex/components/radix/themes/layout/flex.py +1 -1
  187. reflex/components/radix/themes/layout/flex.pyi +55 -65
  188. reflex/components/radix/themes/layout/grid.py +1 -1
  189. reflex/components/radix/themes/layout/grid.pyi +63 -73
  190. reflex/components/radix/themes/layout/list.py +1 -1
  191. reflex/components/radix/themes/layout/list.pyi +188 -238
  192. reflex/components/radix/themes/layout/section.py +2 -4
  193. reflex/components/radix/themes/layout/section.pyi +35 -45
  194. reflex/components/radix/themes/layout/spacer.pyi +55 -65
  195. reflex/components/radix/themes/layout/stack.py +1 -1
  196. reflex/components/radix/themes/layout/stack.pyi +125 -155
  197. reflex/components/radix/themes/typography/blockquote.py +1 -1
  198. reflex/components/radix/themes/typography/blockquote.pyi +88 -98
  199. reflex/components/radix/themes/typography/code.py +1 -1
  200. reflex/components/radix/themes/typography/code.pyi +89 -99
  201. reflex/components/radix/themes/typography/heading.py +1 -1
  202. reflex/components/radix/themes/typography/heading.pyi +95 -105
  203. reflex/components/radix/themes/typography/link.py +1 -1
  204. reflex/components/radix/themes/typography/link.pyi +101 -111
  205. reflex/components/radix/themes/typography/text.py +1 -1
  206. reflex/components/radix/themes/typography/text.pyi +494 -564
  207. reflex/components/react_player/audio.pyi +32 -58
  208. reflex/components/react_player/react_player.py +1 -1
  209. reflex/components/react_player/react_player.pyi +32 -58
  210. reflex/components/react_player/video.pyi +32 -58
  211. reflex/components/recharts/cartesian.py +22 -19
  212. reflex/components/recharts/cartesian.pyi +658 -840
  213. reflex/components/recharts/charts.py +3 -3
  214. reflex/components/recharts/charts.pyi +238 -342
  215. reflex/components/recharts/general.py +8 -8
  216. reflex/components/recharts/general.pyi +175 -225
  217. reflex/components/recharts/polar.py +11 -11
  218. reflex/components/recharts/polar.pyi +135 -171
  219. reflex/components/recharts/recharts.pyi +31 -51
  220. reflex/components/sonner/toast.py +27 -31
  221. reflex/components/sonner/toast.pyi +36 -45
  222. reflex/components/suneditor/editor.py +1 -1
  223. reflex/components/suneditor/editor.pyi +54 -76
  224. reflex/components/tags/cond_tag.py +6 -4
  225. reflex/components/tags/iter_tag.py +37 -25
  226. reflex/components/tags/match_tag.py +6 -4
  227. reflex/components/tags/tag.py +43 -28
  228. reflex/constants/base.py +3 -1
  229. reflex/constants/event.py +1 -0
  230. reflex/custom_components/custom_components.py +3 -1
  231. reflex/event.py +166 -108
  232. reflex/experimental/__init__.py +25 -6
  233. reflex/experimental/client_state.py +34 -57
  234. reflex/experimental/hooks.py +12 -17
  235. reflex/experimental/layout.py +4 -4
  236. reflex/experimental/layout.pyi +130 -180
  237. reflex/middleware/hydrate_middleware.py +2 -0
  238. reflex/middleware/middleware.py +3 -3
  239. reflex/model.py +22 -0
  240. reflex/reflex.py +4 -0
  241. reflex/state.py +491 -110
  242. reflex/style.py +56 -39
  243. reflex/testing.py +8 -3
  244. reflex/utils/exceptions.py +32 -0
  245. reflex/utils/exec.py +0 -14
  246. reflex/utils/format.py +80 -209
  247. reflex/utils/imports.py +16 -73
  248. reflex/utils/net.py +43 -0
  249. reflex/utils/path_ops.py +13 -1
  250. reflex/utils/prerequisites.py +81 -41
  251. reflex/utils/pyi_generator.py +12 -6
  252. reflex/utils/serializers.py +13 -41
  253. reflex/utils/telemetry.py +3 -2
  254. reflex/utils/types.py +47 -7
  255. reflex/{experimental/vars → vars}/__init__.py +6 -3
  256. reflex/vars/base.py +2563 -0
  257. reflex/vars/function.py +196 -0
  258. reflex/vars/number.py +1158 -0
  259. reflex/vars/object.py +562 -0
  260. reflex/vars/sequence.py +1604 -0
  261. {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/METADATA +6 -9
  262. reflex-0.6.0.dist-info/RECORD +382 -0
  263. reflex/.templates/apps/demo/.gitignore +0 -4
  264. reflex/.templates/apps/demo/assets/favicon.ico +0 -0
  265. reflex/.templates/apps/demo/assets/github.svg +0 -10
  266. reflex/.templates/apps/demo/assets/icon.svg +0 -37
  267. reflex/.templates/apps/demo/assets/logo.svg +0 -68
  268. reflex/.templates/apps/demo/assets/paneleft.svg +0 -13
  269. reflex/.templates/apps/demo/code/__init__.py +0 -1
  270. reflex/.templates/apps/demo/code/demo.py +0 -127
  271. reflex/.templates/apps/demo/code/pages/__init__.py +0 -7
  272. reflex/.templates/apps/demo/code/pages/chatapp.py +0 -31
  273. reflex/.templates/apps/demo/code/pages/datatable.py +0 -360
  274. reflex/.templates/apps/demo/code/pages/forms.py +0 -257
  275. reflex/.templates/apps/demo/code/pages/graphing.py +0 -253
  276. reflex/.templates/apps/demo/code/pages/home.py +0 -56
  277. reflex/.templates/apps/demo/code/sidebar.py +0 -178
  278. reflex/.templates/apps/demo/code/state.py +0 -22
  279. reflex/.templates/apps/demo/code/states/form_state.py +0 -40
  280. reflex/.templates/apps/demo/code/states/pie_state.py +0 -47
  281. reflex/.templates/apps/demo/code/styles.py +0 -68
  282. reflex/.templates/apps/demo/code/webui/__init__.py +0 -0
  283. reflex/.templates/apps/demo/code/webui/components/__init__.py +0 -4
  284. reflex/.templates/apps/demo/code/webui/components/chat.py +0 -118
  285. reflex/.templates/apps/demo/code/webui/components/loading_icon.py +0 -19
  286. reflex/.templates/apps/demo/code/webui/components/modal.py +0 -56
  287. reflex/.templates/apps/demo/code/webui/components/navbar.py +0 -70
  288. reflex/.templates/apps/demo/code/webui/components/sidebar.py +0 -66
  289. reflex/.templates/apps/demo/code/webui/state.py +0 -146
  290. reflex/.templates/apps/demo/code/webui/styles.py +0 -88
  291. reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +0 -36
  292. reflex/experimental/vars/base.py +0 -583
  293. reflex/experimental/vars/function.py +0 -290
  294. reflex/experimental/vars/number.py +0 -1458
  295. reflex/experimental/vars/object.py +0 -804
  296. reflex/experimental/vars/sequence.py +0 -1764
  297. reflex/utils/watch.py +0 -96
  298. reflex/vars.py +0 -2604
  299. reflex/vars.pyi +0 -218
  300. reflex-0.5.10a3.dist-info/RECORD +0 -413
  301. {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/LICENSE +0 -0
  302. {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/WHEEL +0 -0
  303. {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/entry_points.txt +0 -0
reflex/event.py CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import dataclasses
5
6
  import inspect
7
+ import types
6
8
  import urllib.parse
7
9
  from base64 import b64encode
8
10
  from typing import (
@@ -17,10 +19,13 @@ from typing import (
17
19
  )
18
20
 
19
21
  from reflex import constants
20
- from reflex.base import Base
21
22
  from reflex.utils import format
23
+ from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
22
24
  from reflex.utils.types import ArgsSpec
23
- from reflex.vars import BaseVar, Var
25
+ from reflex.vars import VarData
26
+ from reflex.vars.base import LiteralVar, Var
27
+ from reflex.vars.function import FunctionStringVar, FunctionVar
28
+ from reflex.vars.object import ObjectVar
24
29
 
25
30
  try:
26
31
  from typing import Annotated
@@ -28,7 +33,11 @@ except ImportError:
28
33
  from typing_extensions import Annotated
29
34
 
30
35
 
31
- class Event(Base):
36
+ @dataclasses.dataclass(
37
+ init=True,
38
+ frozen=True,
39
+ )
40
+ class Event:
32
41
  """An event that describes any state change in the app."""
33
42
 
34
43
  # The token to specify the client that the event is for.
@@ -38,10 +47,10 @@ class Event(Base):
38
47
  name: str
39
48
 
40
49
  # The routing data where event occurred
41
- router_data: Dict[str, Any] = {}
50
+ router_data: Dict[str, Any] = dataclasses.field(default_factory=dict)
42
51
 
43
52
  # The event payload.
44
- payload: Dict[str, Any] = {}
53
+ payload: Dict[str, Any] = dataclasses.field(default_factory=dict)
45
54
 
46
55
  @property
47
56
  def substate_token(self) -> str:
@@ -76,11 +85,15 @@ def background(fn):
76
85
  return fn
77
86
 
78
87
 
79
- class EventActionsMixin(Base):
88
+ @dataclasses.dataclass(
89
+ init=True,
90
+ frozen=True,
91
+ )
92
+ class EventActionsMixin:
80
93
  """Mixin for DOM event actions."""
81
94
 
82
95
  # Whether to `preventDefault` or `stopPropagation` on the event.
83
- event_actions: Dict[str, Union[bool, int]] = {}
96
+ event_actions: Dict[str, Union[bool, int]] = dataclasses.field(default_factory=dict)
84
97
 
85
98
  @property
86
99
  def stop_propagation(self):
@@ -89,8 +102,9 @@ class EventActionsMixin(Base):
89
102
  Returns:
90
103
  New EventHandler-like with stopPropagation set to True.
91
104
  """
92
- return self.copy(
93
- update={"event_actions": {"stopPropagation": True, **self.event_actions}},
105
+ return dataclasses.replace(
106
+ self,
107
+ event_actions={"stopPropagation": True, **self.event_actions},
94
108
  )
95
109
 
96
110
  @property
@@ -100,8 +114,9 @@ class EventActionsMixin(Base):
100
114
  Returns:
101
115
  New EventHandler-like with preventDefault set to True.
102
116
  """
103
- return self.copy(
104
- update={"event_actions": {"preventDefault": True, **self.event_actions}},
117
+ return dataclasses.replace(
118
+ self,
119
+ event_actions={"preventDefault": True, **self.event_actions},
105
120
  )
106
121
 
107
122
  def throttle(self, limit_ms: int):
@@ -113,8 +128,9 @@ class EventActionsMixin(Base):
113
128
  Returns:
114
129
  New EventHandler-like with throttle set to limit_ms.
115
130
  """
116
- return self.copy(
117
- update={"event_actions": {"throttle": limit_ms, **self.event_actions}},
131
+ return dataclasses.replace(
132
+ self,
133
+ event_actions={"throttle": limit_ms, **self.event_actions},
118
134
  )
119
135
 
120
136
  def debounce(self, delay_ms: int):
@@ -126,26 +142,25 @@ class EventActionsMixin(Base):
126
142
  Returns:
127
143
  New EventHandler-like with debounce set to delay_ms.
128
144
  """
129
- return self.copy(
130
- update={"event_actions": {"debounce": delay_ms, **self.event_actions}},
145
+ return dataclasses.replace(
146
+ self,
147
+ event_actions={"debounce": delay_ms, **self.event_actions},
131
148
  )
132
149
 
133
150
 
151
+ @dataclasses.dataclass(
152
+ init=True,
153
+ frozen=True,
154
+ )
134
155
  class EventHandler(EventActionsMixin):
135
156
  """An event handler responds to an event to update the state."""
136
157
 
137
158
  # The function to call in response to the event.
138
- fn: Any
159
+ fn: Any = dataclasses.field(default=None)
139
160
 
140
161
  # The full name of the state class this event handler is attached to.
141
162
  # Empty string means this event handler is a server side event.
142
- state_full_name: str = ""
143
-
144
- class Config:
145
- """The Pydantic config."""
146
-
147
- # Needed to allow serialization of Callable.
148
- frozen = True
163
+ state_full_name: str = dataclasses.field(default="")
149
164
 
150
165
  @classmethod
151
166
  def __class_getitem__(cls, args_spec: str) -> Annotated:
@@ -186,7 +201,7 @@ class EventHandler(EventActionsMixin):
186
201
 
187
202
  # Get the function args.
188
203
  fn_args = inspect.getfullargspec(self.fn).args[1:]
189
- fn_args = (Var.create_safe(arg, _var_is_string=False) for arg in fn_args)
204
+ fn_args = (Var(_js_expr=arg) for arg in fn_args)
190
205
 
191
206
  # Construct the payload.
192
207
  values = []
@@ -197,7 +212,7 @@ class EventHandler(EventActionsMixin):
197
212
 
198
213
  # Otherwise, convert to JSON.
199
214
  try:
200
- values.append(Var.create(arg, _var_is_string=isinstance(arg, str)))
215
+ values.append(LiteralVar.create(arg))
201
216
  except TypeError as e:
202
217
  raise EventHandlerTypeError(
203
218
  f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
@@ -210,6 +225,10 @@ class EventHandler(EventActionsMixin):
210
225
  )
211
226
 
212
227
 
228
+ @dataclasses.dataclass(
229
+ init=True,
230
+ frozen=True,
231
+ )
213
232
  class EventSpec(EventActionsMixin):
214
233
  """An event specification.
215
234
 
@@ -218,19 +237,35 @@ class EventSpec(EventActionsMixin):
218
237
  """
219
238
 
220
239
  # The event handler.
221
- handler: EventHandler
240
+ handler: EventHandler = dataclasses.field(default=None) # type: ignore
222
241
 
223
242
  # The handler on the client to process event.
224
- client_handler_name: str = ""
243
+ client_handler_name: str = dataclasses.field(default="")
225
244
 
226
245
  # The arguments to pass to the function.
227
- args: Tuple[Tuple[Var, Var], ...] = ()
246
+ args: Tuple[Tuple[Var, Var], ...] = dataclasses.field(default_factory=tuple)
228
247
 
229
- class Config:
230
- """The Pydantic config."""
248
+ def __init__(
249
+ self,
250
+ handler: EventHandler,
251
+ event_actions: Dict[str, Union[bool, int]] | None = None,
252
+ client_handler_name: str = "",
253
+ args: Tuple[Tuple[Var, Var], ...] = tuple(),
254
+ ):
255
+ """Initialize an EventSpec.
231
256
 
232
- # Required to allow tuple fields.
233
- frozen = True
257
+ Args:
258
+ event_actions: The event actions.
259
+ handler: The event handler.
260
+ client_handler_name: The client handler name.
261
+ args: The arguments to pass to the function.
262
+ """
263
+ if event_actions is None:
264
+ event_actions = {}
265
+ object.__setattr__(self, "event_actions", event_actions)
266
+ object.__setattr__(self, "handler", handler)
267
+ object.__setattr__(self, "client_handler_name", client_handler_name)
268
+ object.__setattr__(self, "args", args or tuple())
234
269
 
235
270
  def with_args(self, args: Tuple[Tuple[Var, Var], ...]) -> EventSpec:
236
271
  """Copy the event spec, with updated args.
@@ -264,13 +299,13 @@ class EventSpec(EventActionsMixin):
264
299
 
265
300
  # Get the remaining unfilled function args.
266
301
  fn_args = inspect.getfullargspec(self.handler.fn).args[1 + len(self.args) :]
267
- fn_args = (Var.create_safe(arg, _var_is_string=False) for arg in fn_args)
302
+ fn_args = (Var(_js_expr=arg) for arg in fn_args)
268
303
 
269
304
  # Construct the payload.
270
305
  values = []
271
306
  for arg in args:
272
307
  try:
273
- values.append(Var.create(arg, _var_is_string=isinstance(arg, str)))
308
+ values.append(LiteralVar.create(arg))
274
309
  except TypeError as e:
275
310
  raise EventHandlerTypeError(
276
311
  f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
@@ -279,6 +314,9 @@ class EventSpec(EventActionsMixin):
279
314
  return self.with_args(self.args + new_payload)
280
315
 
281
316
 
317
+ @dataclasses.dataclass(
318
+ frozen=True,
319
+ )
282
320
  class CallableEventSpec(EventSpec):
283
321
  """Decorate an EventSpec-returning function to act as both a EventSpec and a function.
284
322
 
@@ -298,10 +336,13 @@ class CallableEventSpec(EventSpec):
298
336
  if fn is not None:
299
337
  default_event_spec = fn()
300
338
  super().__init__(
301
- fn=fn, # type: ignore
302
- **default_event_spec.dict(),
339
+ event_actions=default_event_spec.event_actions,
340
+ client_handler_name=default_event_spec.client_handler_name,
341
+ args=default_event_spec.args,
342
+ handler=default_event_spec.handler,
303
343
  **kwargs,
304
344
  )
345
+ object.__setattr__(self, "fn", fn)
305
346
  else:
306
347
  super().__init__(**kwargs)
307
348
 
@@ -325,12 +366,16 @@ class CallableEventSpec(EventSpec):
325
366
  return self.fn(*args, **kwargs)
326
367
 
327
368
 
369
+ @dataclasses.dataclass(
370
+ init=True,
371
+ frozen=True,
372
+ )
328
373
  class EventChain(EventActionsMixin):
329
374
  """Container for a chain of events that will be executed in order."""
330
375
 
331
- events: List[EventSpec]
376
+ events: List[EventSpec] = dataclasses.field(default_factory=list)
332
377
 
333
- args_spec: Optional[Callable]
378
+ args_spec: Optional[Callable] = dataclasses.field(default=None)
334
379
 
335
380
 
336
381
  # These chains can be used for their side effects when no other events are desired.
@@ -338,14 +383,22 @@ stop_propagation = EventChain(events=[], args_spec=lambda: []).stop_propagation
338
383
  prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default
339
384
 
340
385
 
341
- class Target(Base):
386
+ @dataclasses.dataclass(
387
+ init=True,
388
+ frozen=True,
389
+ )
390
+ class Target:
342
391
  """A Javascript event target."""
343
392
 
344
393
  checked: bool = False
345
394
  value: Any = None
346
395
 
347
396
 
348
- class FrontendEvent(Base):
397
+ @dataclasses.dataclass(
398
+ init=True,
399
+ frozen=True,
400
+ )
401
+ class FrontendEvent:
349
402
  """A Javascript event."""
350
403
 
351
404
  target: Target = Target()
@@ -353,7 +406,11 @@ class FrontendEvent(Base):
353
406
  value: Any = None
354
407
 
355
408
 
356
- class FileUpload(Base):
409
+ @dataclasses.dataclass(
410
+ init=True,
411
+ frozen=True,
412
+ )
413
+ class FileUpload:
357
414
  """Class to represent a file upload."""
358
415
 
359
416
  upload_id: Optional[str] = None
@@ -388,15 +445,16 @@ class FileUpload(Base):
388
445
  upload_id = self.upload_id or DEFAULT_UPLOAD_ID
389
446
  spec_args = [
390
447
  (
391
- Var.create_safe("files", _var_is_string=False),
392
- Var.create_safe(
393
- f"filesById[{Var.create_safe(upload_id, _var_is_string=True)._var_name_unwrapped}]",
394
- _var_is_string=False,
395
- )._replace(_var_data=upload_files_context_var_data),
448
+ Var(_js_expr="files"),
449
+ Var(
450
+ _js_expr="filesById",
451
+ _var_type=Dict[str, Any],
452
+ _var_data=VarData.merge(upload_files_context_var_data),
453
+ ).to(ObjectVar)[LiteralVar.create(upload_id)],
396
454
  ),
397
455
  (
398
- Var.create_safe("upload_id", _var_is_string=False),
399
- Var.create_safe(upload_id, _var_is_string=True),
456
+ Var(_js_expr="upload_id"),
457
+ LiteralVar.create(upload_id),
400
458
  ),
401
459
  ]
402
460
  if self.on_upload_progress is not None:
@@ -424,11 +482,10 @@ class FileUpload(Base):
424
482
  formatted_chain = str(format.format_prop(on_upload_progress_chain))
425
483
  spec_args.append(
426
484
  (
427
- Var.create_safe("on_upload_progress", _var_is_string=False),
428
- BaseVar(
429
- _var_name=formatted_chain.strip("{}"),
430
- _var_type=EventChain,
431
- ),
485
+ Var(_js_expr="on_upload_progress"),
486
+ FunctionStringVar(
487
+ formatted_chain.strip("{}"),
488
+ ).to(FunctionVar, EventChain),
432
489
  ),
433
490
  )
434
491
  return EventSpec(
@@ -465,8 +522,8 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
465
522
  handler=EventHandler(fn=fn),
466
523
  args=tuple(
467
524
  (
468
- Var.create_safe(k, _var_is_string=False),
469
- Var.create_safe(v, _var_is_string=isinstance(v, str)),
525
+ Var(_js_expr=k),
526
+ LiteralVar.create(v),
470
527
  )
471
528
  for k, v in kwargs.items()
472
529
  ),
@@ -542,7 +599,7 @@ def set_focus(ref: str) -> EventSpec:
542
599
  return server_side(
543
600
  "_set_focus",
544
601
  get_fn_signature(set_focus),
545
- ref=Var.create_safe(format.format_ref(ref), _var_is_string=True),
602
+ ref=LiteralVar.create(format.format_ref(ref)),
546
603
  )
547
604
 
548
605
 
@@ -573,7 +630,7 @@ def set_value(ref: str, value: Any) -> EventSpec:
573
630
  return server_side(
574
631
  "_set_value",
575
632
  get_fn_signature(set_value),
576
- ref=Var.create_safe(format.format_ref(ref), _var_is_string=True),
633
+ ref=LiteralVar.create(format.format_ref(ref)),
577
634
  value=value,
578
635
  )
579
636
 
@@ -711,19 +768,15 @@ def download(
711
768
  url = "data:text/plain," + urllib.parse.quote(data)
712
769
  elif isinstance(data, Var):
713
770
  # Need to check on the frontend if the Var already looks like a data: URI.
714
- is_data_url = data._replace(
715
- _var_name=(
716
- f"typeof {data._var_full_name} == 'string' && "
717
- f"{data._var_full_name}.startsWith('data:')"
718
- ),
719
- _var_type=bool,
720
- _var_is_string=False,
721
- _var_full_name_needs_state_prefix=False,
722
- )
771
+
772
+ is_data_url = (data.js_type() == "string") & (
773
+ data.to(str).startswith("data:")
774
+ ) # type: ignore
775
+
723
776
  # If it's a data: URI, use it as is, otherwise convert the Var to JSON in a data: URI.
724
777
  url = cond( # type: ignore
725
778
  is_data_url,
726
- data,
779
+ data.to(str),
727
780
  "data:text/plain," + data.to_string(), # type: ignore
728
781
  )
729
782
  elif isinstance(data, bytes):
@@ -757,11 +810,13 @@ def _callback_arg_spec(eval_result):
757
810
 
758
811
  def call_script(
759
812
  javascript_code: str | Var[str],
760
- callback: EventSpec
761
- | EventHandler
762
- | Callable
763
- | List[EventSpec | EventHandler | Callable]
764
- | None = None,
813
+ callback: (
814
+ EventSpec
815
+ | EventHandler
816
+ | Callable
817
+ | List[EventSpec | EventHandler | Callable]
818
+ | None
819
+ ) = None,
765
820
  ) -> EventSpec:
766
821
  """Create an event handler that executes arbitrary javascript code.
767
822
 
@@ -830,7 +885,7 @@ def call_event_handler(
830
885
  arg_spec: The lambda that define the argument(s) to pass to the event handler.
831
886
 
832
887
  Raises:
833
- ValueError: if number of arguments expected by event_handler doesn't match the spec.
888
+ EventHandlerArgMismatch: if number of arguments expected by event_handler doesn't match the spec.
834
889
 
835
890
  Returns:
836
891
  The event spec from calling the event handler.
@@ -842,13 +897,16 @@ def call_event_handler(
842
897
  return event_handler.add_args(*parsed_args)
843
898
 
844
899
  args = inspect.getfullargspec(event_handler.fn).args
845
- if len(args) == len(["self", *parsed_args]):
900
+ n_args = len(args) - 1 # subtract 1 for bound self arg
901
+ if n_args == len(parsed_args):
846
902
  return event_handler(*parsed_args) # type: ignore
847
903
  else:
848
- source = inspect.getsource(arg_spec) # type: ignore
849
- raise ValueError(
850
- f"number of arguments in {event_handler.fn.__qualname__} "
851
- f"doesn't match the definition of the event trigger '{source.strip().strip(',')}'"
904
+ raise EventHandlerArgMismatch(
905
+ "The number of arguments accepted by "
906
+ f"{event_handler.fn.__qualname__} ({n_args}) "
907
+ "does not match the arguments passed by the event trigger: "
908
+ f"{[str(v) for v in parsed_args]}\n"
909
+ "See https://reflex.dev/docs/events/event-arguments/"
852
910
  )
853
911
 
854
912
 
@@ -865,68 +923,66 @@ def parse_args_spec(arg_spec: ArgsSpec):
865
923
  annotations = get_type_hints(arg_spec)
866
924
  return arg_spec(
867
925
  *[
868
- BaseVar(
869
- _var_name=f"_{l_arg}",
870
- _var_type=annotations.get(l_arg, FrontendEvent),
871
- _var_is_local=True,
872
- )
926
+ Var(f"_{l_arg}").to(annotations.get(l_arg, FrontendEvent))
873
927
  for l_arg in spec.args
874
928
  ]
875
929
  )
876
930
 
877
931
 
878
- def call_event_fn(fn: Callable, arg: Union[Var, ArgsSpec]) -> list[EventSpec] | Var:
932
+ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
879
933
  """Call a function to a list of event specs.
880
934
 
881
935
  The function should return a single EventSpec, a list of EventSpecs, or a
882
- single Var. If the function takes in an arg, the arg will be passed to the
883
- function. Otherwise, the function will be called with no args.
936
+ single Var. The function signature must match the passed arg_spec or
937
+ EventFnArgsMismatch will be raised.
884
938
 
885
939
  Args:
886
940
  fn: The function to call.
887
- arg: The argument to pass to the function.
941
+ arg_spec: The argument spec for the event trigger.
888
942
 
889
943
  Returns:
890
944
  The event specs from calling the function or a Var.
891
945
 
892
946
  Raises:
893
- EventHandlerValueError: If the lambda has an invalid signature.
947
+ EventFnArgMismatch: If the function signature doesn't match the arg spec.
948
+ EventHandlerValueError: If the lambda returns an unusable value.
894
949
  """
895
950
  # Import here to avoid circular imports.
896
951
  from reflex.event import EventHandler, EventSpec
897
952
  from reflex.utils.exceptions import EventHandlerValueError
898
953
 
899
- # Get the args of the lambda.
900
- args = inspect.getfullargspec(fn).args
954
+ # Check that fn signature matches arg_spec
955
+ fn_args = inspect.getfullargspec(fn).args
956
+ n_fn_args = len(fn_args)
957
+ if isinstance(fn, types.MethodType):
958
+ n_fn_args -= 1 # subtract 1 for bound self arg
959
+ parsed_args = parse_args_spec(arg_spec)
960
+ if len(parsed_args) != n_fn_args:
961
+ raise EventFnArgMismatch(
962
+ "The number of arguments accepted by "
963
+ f"{fn} ({n_fn_args}) "
964
+ "does not match the arguments passed by the event trigger: "
965
+ f"{[str(v) for v in parsed_args]}\n"
966
+ "See https://reflex.dev/docs/events/event-arguments/"
967
+ )
901
968
 
902
- if isinstance(arg, ArgsSpec):
903
- out = fn(*parse_args_spec(arg)) # type: ignore
904
- else:
905
- # Call the lambda.
906
- if len(args) == 0:
907
- out = fn()
908
- elif len(args) == 1:
909
- out = fn(arg)
910
- else:
911
- raise EventHandlerValueError(f"Lambda {fn} must have 0 or 1 arguments.")
969
+ # Call the function with the parsed args.
970
+ out = fn(*parsed_args)
912
971
 
913
972
  # If the function returns a Var, assume it's an EventChain and render it directly.
914
973
  if isinstance(out, Var):
915
974
  return out
916
975
 
917
976
  # Convert the output to a list.
918
- if not isinstance(out, List):
977
+ if not isinstance(out, list):
919
978
  out = [out]
920
979
 
921
980
  # Convert any event specs to event specs.
922
981
  events = []
923
982
  for e in out:
924
- # Convert handlers to event specs.
925
983
  if isinstance(e, EventHandler):
926
- if len(args) == 0:
927
- e = e()
928
- elif len(args) == 1:
929
- e = e(arg) # type: ignore
984
+ # An un-called EventHandler gets all of the args of the event trigger.
985
+ e = call_event_handler(e, arg_spec)
930
986
 
931
987
  # Make sure the event spec is valid.
932
988
  if not isinstance(e, EventSpec):
@@ -941,7 +997,9 @@ def call_event_fn(fn: Callable, arg: Union[Var, ArgsSpec]) -> list[EventSpec] |
941
997
  return events
942
998
 
943
999
 
944
- def get_handler_args(event_spec: EventSpec) -> tuple[tuple[Var, Var], ...]:
1000
+ def get_handler_args(
1001
+ event_spec: EventSpec,
1002
+ ) -> tuple[tuple[Var, Var], ...]:
945
1003
  """Get the handler args for the given event spec.
946
1004
 
947
1005
  Args:
@@ -992,7 +1050,7 @@ def fix_events(
992
1050
  e = e()
993
1051
  assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}."
994
1052
  name = format.format_event_handler(e.handler)
995
- payload = {k._var_name: v._decode() for k, v in e.args} # type: ignore
1053
+ payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore
996
1054
 
997
1055
  # Filter router_data to reduce payload size
998
1056
  event_router_data = {
@@ -8,7 +8,6 @@ from reflex.components.sonner.toast import toast as toast
8
8
 
9
9
  from ..utils.console import warn
10
10
  from . import hooks as hooks
11
- from . import vars as vars
12
11
  from .assets import asset as asset
13
12
  from .client_state import ClientStateVar as ClientStateVar
14
13
  from .layout import layout as layout
@@ -33,19 +32,39 @@ class ExperimentalNamespace(SimpleNamespace):
33
32
  Returns:
34
33
  The toast namespace.
35
34
  """
36
- if "toast" not in _EMITTED_PROMOTION_WARNINGS:
37
- _EMITTED_PROMOTION_WARNINGS.add("toast")
38
- warn(f"`rx._x.toast` was promoted to `rx.toast`.")
35
+ self.register_component_warning("toast")
39
36
  return toast
40
37
 
38
+ @property
39
+ def progress(self):
40
+ """Temporary property returning the toast namespace.
41
+
42
+ Remove this property when toast is fully promoted.
43
+
44
+ Returns:
45
+ The toast namespace.
46
+ """
47
+ self.register_component_warning("progress")
48
+ return progress
49
+
50
+ @staticmethod
51
+ def register_component_warning(component_name: str):
52
+ """Add component to emitted warnings and throw a warning if it
53
+ doesn't exist.
54
+
55
+ Args:
56
+ component_name: name of the component.
57
+ """
58
+ if component_name not in _EMITTED_PROMOTION_WARNINGS:
59
+ _EMITTED_PROMOTION_WARNINGS.add(component_name)
60
+ warn(f"`rx._x.{component_name}` was promoted to `rx.{component_name}`.")
61
+
41
62
 
42
63
  _x = ExperimentalNamespace(
43
64
  asset=asset,
44
65
  client_state=ClientStateVar.create,
45
66
  hooks=hooks,
46
- vars=vars,
47
67
  layout=layout,
48
- progress=progress,
49
68
  PropsBase=PropsBase,
50
69
  run_in_thread=run_in_thread,
51
70
  )