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/utils/format.py CHANGED
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
10
10
 
11
11
  from reflex import constants
12
12
  from reflex.utils import exceptions, types
13
- from reflex.vars import BaseVar, Var
13
+ from reflex.utils.console import deprecate
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from reflex.components.component import ComponentStyle
@@ -263,32 +263,6 @@ def format_string(string: str) -> str:
263
263
  return _wrap_js_string(_escape_js_string(string))
264
264
 
265
265
 
266
- def format_f_string_prop(prop: BaseVar) -> str:
267
- """Format the string in a given prop as an f-string.
268
-
269
- Args:
270
- prop: The prop to format.
271
-
272
- Returns:
273
- The formatted string.
274
- """
275
- s = prop._var_full_name
276
- var_data = prop._var_data
277
- interps = var_data.interpolations if var_data else []
278
- parts: List[str] = []
279
-
280
- if interps:
281
- for i, (start, end) in enumerate(interps):
282
- prev_end = interps[i - 1][1] if i > 0 else 0
283
- parts.append(_escape_js_string(s[prev_end:start]))
284
- parts.append(s[start:end])
285
- parts.append(_escape_js_string(s[interps[-1][1] :]))
286
- else:
287
- parts.append(_escape_js_string(s))
288
-
289
- return _wrap_js_string("".join(parts))
290
-
291
-
292
266
  def format_var(var: Var) -> str:
293
267
  """Format the given Var as a javascript value.
294
268
 
@@ -298,13 +272,7 @@ def format_var(var: Var) -> str:
298
272
  Returns:
299
273
  The formatted Var.
300
274
  """
301
- if not var._var_is_local or var._var_is_string:
302
- return str(var)
303
- if types._issubclass(var._var_type, str):
304
- return format_string(var._var_full_name)
305
- if is_wrapped(var._var_full_name, "{"):
306
- return var._var_full_name
307
- return json_dumps(var._var_full_name)
275
+ return str(var)
308
276
 
309
277
 
310
278
  def format_route(route: str, format_case=True) -> str:
@@ -329,46 +297,11 @@ def format_route(route: str, format_case=True) -> str:
329
297
  return route
330
298
 
331
299
 
332
- def format_cond(
300
+ def format_match(
333
301
  cond: str | Var,
334
- true_value: str | Var,
335
- false_value: str | Var = '""',
336
- is_prop=False,
302
+ match_cases: List[List[Var]],
303
+ default: Var,
337
304
  ) -> str:
338
- """Format a conditional expression.
339
-
340
- Args:
341
- cond: The cond.
342
- true_value: The value to return if the cond is true.
343
- false_value: The value to return if the cond is false.
344
- is_prop: Whether the cond is a prop
345
-
346
- Returns:
347
- The formatted conditional expression.
348
- """
349
- # Use Python truthiness.
350
- cond = f"isTrue({cond})"
351
-
352
- def create_var(cond_part):
353
- return Var.create_safe(cond_part, _var_is_string=isinstance(cond_part, str))
354
-
355
- # Format prop conds.
356
- if is_prop:
357
- true_value = create_var(true_value)
358
- prop1 = true_value._replace(
359
- _var_is_local=True,
360
- )
361
-
362
- false_value = create_var(false_value)
363
- prop2 = false_value._replace(_var_is_local=True)
364
- # unwrap '{}' to avoid f-string semantics for Var
365
- return f"{cond} ? {prop1._var_name_unwrapped} : {prop2._var_name_unwrapped}"
366
-
367
- # Format component conds.
368
- return wrap(f"{cond} ? {true_value} : {false_value}", "{")
369
-
370
-
371
- def format_match(cond: str | Var, match_cases: List[BaseVar], default: Var) -> str:
372
305
  """Format a match expression whose return type is a Var.
373
306
 
374
307
  Args:
@@ -387,17 +320,12 @@ def format_match(cond: str | Var, match_cases: List[BaseVar], default: Var) -> s
387
320
  return_value = case[-1]
388
321
 
389
322
  case_conditions = " ".join(
390
- [
391
- f"case JSON.stringify({condition._var_name_unwrapped}):"
392
- for condition in conditions
393
- ]
394
- )
395
- case_code = (
396
- f"{case_conditions} return ({return_value._var_name_unwrapped}); break;"
323
+ [f"case JSON.stringify({str(condition)}):" for condition in conditions]
397
324
  )
325
+ case_code = f"{case_conditions} return ({str(return_value)}); break;"
398
326
  switch_code += case_code
399
327
 
400
- switch_code += f"default: return ({default._var_name_unwrapped}); break;"
328
+ switch_code += f"default: return ({str(default)}); break;"
401
329
  switch_code += "};})()"
402
330
 
403
331
  return switch_code
@@ -421,20 +349,15 @@ def format_prop(
421
349
  # import here to avoid circular import.
422
350
  from reflex.event import EventChain
423
351
  from reflex.utils import serializers
352
+ from reflex.vars import Var
424
353
 
425
354
  try:
426
355
  # Handle var props.
427
356
  if isinstance(prop, Var):
428
- if not prop._var_is_local or prop._var_is_string:
429
- return str(prop)
430
- if isinstance(prop, BaseVar) and types._issubclass(prop._var_type, str):
431
- if prop._var_data and prop._var_data.interpolations:
432
- return format_f_string_prop(prop)
433
- return format_string(prop._var_full_name)
434
- prop = prop._var_full_name
357
+ return str(prop)
435
358
 
436
359
  # Handle event props.
437
- elif isinstance(prop, EventChain):
360
+ if isinstance(prop, EventChain):
438
361
  sig = inspect.signature(prop.args_spec) # type: ignore
439
362
  if sig.parameters:
440
363
  arg_def = ",".join(f"_{p}" for p in sig.parameters)
@@ -483,11 +406,15 @@ def format_props(*single_props, **key_value_props) -> list[str]:
483
406
  The formatted props list.
484
407
  """
485
408
  # Format all the props.
409
+ from reflex.vars.base import LiteralVar, Var
410
+
486
411
  return [
487
- f"{name}={format_prop(prop)}"
412
+ (
413
+ f"{name}={{{format_prop(prop if isinstance(prop, Var) else LiteralVar.create(prop))}}}"
414
+ )
488
415
  for name, prop in sorted(key_value_props.items())
489
416
  if prop is not None
490
- ] + [str(prop) for prop in single_props]
417
+ ] + [(f"{str(LiteralVar.create(prop))}") for prop in single_props]
491
418
 
492
419
 
493
420
  def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]:
@@ -502,13 +429,13 @@ def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]:
502
429
  # Get the class that defines the event handler.
503
430
  parts = handler.fn.__qualname__.split(".")
504
431
 
505
- # If there's no enclosing class, just return the function name.
506
- if len(parts) == 1:
507
- return ("", parts[-1])
508
-
509
432
  # Get the state full name
510
433
  state_full_name = handler.state_full_name
511
434
 
435
+ # If there's no enclosing class, just return the function name.
436
+ if not state_full_name:
437
+ return ("", parts[-1])
438
+
512
439
  # Get the function name
513
440
  name = parts[-1]
514
441
 
@@ -548,14 +475,14 @@ def format_event(event_spec: EventSpec) -> str:
548
475
  [
549
476
  ":".join(
550
477
  (
551
- name._var_name,
478
+ name._js_expr,
552
479
  (
553
480
  wrap(
554
- json.dumps(val._var_name).strip('"').replace("`", "\\`"),
481
+ json.dumps(val._js_expr).strip('"').replace("`", "\\`"),
555
482
  "`",
556
483
  )
557
484
  if val._var_is_string
558
- else val._var_full_name
485
+ else str(val)
559
486
  ),
560
487
  )
561
488
  )
@@ -572,52 +499,49 @@ def format_event(event_spec: EventSpec) -> str:
572
499
  return f"Event({', '.join(event_args)})"
573
500
 
574
501
 
502
+ if TYPE_CHECKING:
503
+ from reflex.vars import Var
504
+
505
+
575
506
  def format_event_chain(
576
507
  event_chain: EventChain | Var[EventChain],
577
508
  event_arg: Var | None = None,
578
509
  ) -> str:
579
- """Format an event chain as a javascript invocation.
510
+ """DEPRECATED: format an event chain as a javascript invocation.
511
+
512
+ Use str(rx.Var.create(event_chain)) instead.
580
513
 
581
514
  Args:
582
- event_chain: The event chain to queue on the frontend.
583
- event_arg: The browser-native event (only used to preventDefault).
515
+ event_chain: The event chain to format.
516
+ event_arg: this argument is ignored.
584
517
 
585
518
  Returns:
586
519
  Compiled javascript code to queue the given event chain on the frontend.
520
+ """
521
+ deprecate(
522
+ feature_name="format_event_chain",
523
+ reason="Use str(rx.Var.create(event_chain)) instead",
524
+ deprecation_version="0.6.0",
525
+ removal_version="0.7.0",
526
+ )
587
527
 
588
- Raises:
589
- ValueError: When the given event chain is not a valid event chain.
590
- """
591
- if isinstance(event_chain, Var):
592
- from reflex.event import EventChain
593
-
594
- if event_chain._var_type is not EventChain:
595
- raise ValueError(f"Invalid event chain: {event_chain}")
596
- return "".join(
597
- [
598
- "(() => {",
599
- format_var(event_chain),
600
- f"; preventDefault({format_var(event_arg)})" if event_arg else "",
601
- "})()",
602
- ]
603
- )
528
+ from reflex.vars import Var
529
+ from reflex.vars.function import ArgsFunctionOperation
604
530
 
605
- chain = ",".join([format_event(event) for event in event_chain.events])
606
- return "".join(
607
- [
608
- f"addEvents([{chain}]",
609
- f", {format_var(event_arg)}" if event_arg else "",
610
- ")",
611
- ]
612
- )
531
+ result = Var.create(event_chain)
532
+ if isinstance(result, ArgsFunctionOperation):
533
+ result = result._return_expr
534
+ return str(result)
613
535
 
614
536
 
615
537
  def format_queue_events(
616
- events: EventSpec
617
- | EventHandler
618
- | Callable
619
- | List[EventSpec | EventHandler | Callable]
620
- | None = None,
538
+ events: (
539
+ EventSpec
540
+ | EventHandler
541
+ | Callable
542
+ | List[EventSpec | EventHandler | Callable]
543
+ | None
544
+ ) = None,
621
545
  args_spec: Optional[ArgsSpec] = None,
622
546
  ) -> Var[EventChain]:
623
547
  """Format a list of event handler / event spec as a javascript callback.
@@ -645,11 +569,10 @@ def format_queue_events(
645
569
  call_event_fn,
646
570
  call_event_handler,
647
571
  )
572
+ from reflex.vars import FunctionVar, Var
648
573
 
649
574
  if not events:
650
- return Var.create_safe(
651
- "() => null", _var_is_string=False, _var_is_local=False
652
- ).to(EventChain)
575
+ return Var("(() => null)").to(FunctionVar, EventChain) # type: ignore
653
576
 
654
577
  # If no spec is provided, the function will take no arguments.
655
578
  def _default_args_spec():
@@ -682,12 +605,10 @@ def format_queue_events(
682
605
 
683
606
  # Return the final code snippet, expecting queueEvents, processEvent, and socket to be in scope.
684
607
  # Typically this snippet will _only_ run from within an rx.call_script eval context.
685
- return Var.create_safe(
608
+ return Var(
686
609
  f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); "
687
610
  f"processEvent({constants.CompileVars.SOCKET})}}",
688
- _var_is_string=False,
689
- _var_is_local=False,
690
- ).to(EventChain)
611
+ ).to(FunctionVar, EventChain) # type: ignore
691
612
 
692
613
 
693
614
  def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
@@ -774,41 +695,6 @@ def format_ref(ref: str) -> str:
774
695
  return f"ref_{clean_ref}"
775
696
 
776
697
 
777
- def format_array_ref(refs: str, idx: Var | None) -> str:
778
- """Format a ref accessed by array.
779
-
780
- Args:
781
- refs : The ref array to access.
782
- idx : The index of the ref in the array.
783
-
784
- Returns:
785
- The formatted ref.
786
- """
787
- clean_ref = re.sub(r"[^\w]+", "_", refs)
788
- if idx is not None:
789
- idx._var_is_local = True
790
- return f"refs_{clean_ref}[{idx}]"
791
- return f"refs_{clean_ref}"
792
-
793
-
794
- def format_breadcrumbs(route: str) -> list[tuple[str, str]]:
795
- """Take a route and return a list of tuple for use in breadcrumb.
796
-
797
- Args:
798
- route: The route to transform.
799
-
800
- Returns:
801
- list[tuple[str, str]]: the list of tuples for the breadcrumb.
802
- """
803
- route_parts = route.lstrip("/").split("/")
804
-
805
- # create and return breadcrumbs
806
- return [
807
- (part, "/".join(["", *route_parts[: i + 1]]))
808
- for i, part in enumerate(route_parts)
809
- ]
810
-
811
-
812
698
  def format_library_name(library_fullname: str):
813
699
  """Format the name of a library.
814
700
 
@@ -839,42 +725,6 @@ def json_dumps(obj: Any) -> str:
839
725
  return json.dumps(obj, ensure_ascii=False, default=serializers.serialize)
840
726
 
841
727
 
842
- def unwrap_vars(value: str) -> str:
843
- """Unwrap var values from a JSON string.
844
-
845
- For example, "{var}" will be unwrapped to "var".
846
-
847
- Args:
848
- value: The JSON string to unwrap.
849
-
850
- Returns:
851
- The unwrapped JSON string.
852
- """
853
-
854
- def unescape_double_quotes_in_var(m: re.Match) -> str:
855
- prefix = m.group(1) or ""
856
- # Since the outer quotes are removed, the inner escaped quotes must be unescaped.
857
- return prefix + re.sub('\\\\"', '"', m.group(2))
858
-
859
- # This substitution is necessary to unwrap var values.
860
- return (
861
- re.sub(
862
- pattern=r"""
863
- (?<!\\) # must NOT start with a backslash
864
- " # match opening double quote of JSON value
865
- (<reflex.Var>.*?</reflex.Var>)? # Optional encoded VarData (non-greedy)
866
- {(.*?)} # extract the value between curly braces (non-greedy)
867
- " # match must end with an unescaped double quote
868
- """,
869
- repl=unescape_double_quotes_in_var,
870
- string=value,
871
- flags=re.VERBOSE,
872
- )
873
- .replace('"`', "`")
874
- .replace('`"', "`")
875
- )
876
-
877
-
878
728
  def collect_form_dict_names(form_dict: dict[str, Any]) -> dict[str, Any]:
879
729
  """Collapse keys with consecutive suffixes into a single list value.
880
730
 
@@ -897,6 +747,23 @@ def collect_form_dict_names(form_dict: dict[str, Any]) -> dict[str, Any]:
897
747
  return collapsed
898
748
 
899
749
 
750
+ def format_array_ref(refs: str, idx: Var | None) -> str:
751
+ """Format a ref accessed by array.
752
+
753
+ Args:
754
+ refs : The ref array to access.
755
+ idx : The index of the ref in the array.
756
+
757
+ Returns:
758
+ The formatted ref.
759
+ """
760
+ clean_ref = re.sub(r"[^\w]+", "_", refs)
761
+ if idx is not None:
762
+ # idx._var_is_local = True
763
+ return f"refs_{clean_ref}[{str(idx)}]"
764
+ return f"refs_{clean_ref}"
765
+
766
+
900
767
  def format_data_editor_column(col: str | dict):
901
768
  """Format a given column into the proper format.
902
769
 
@@ -909,6 +776,8 @@ def format_data_editor_column(col: str | dict):
909
776
  Returns:
910
777
  The formatted column.
911
778
  """
779
+ from reflex.vars import Var
780
+
912
781
  if isinstance(col, str):
913
782
  return {"title": col, "id": col.lower(), "type": "str"}
914
783
 
@@ -921,7 +790,7 @@ def format_data_editor_column(col: str | dict):
921
790
  col["overlayIcon"] = None
922
791
  return col
923
792
 
924
- if isinstance(col, BaseVar):
793
+ if isinstance(col, Var):
925
794
  return col
926
795
 
927
796
  raise ValueError(
@@ -938,7 +807,9 @@ def format_data_editor_cell(cell: Any):
938
807
  Returns:
939
808
  The formatted cell.
940
809
  """
810
+ from reflex.vars.base import Var
811
+
941
812
  return {
942
- "kind": Var.create(value="GridCellKind.Text", _var_is_string=False),
813
+ "kind": Var(_js_expr="GridCellKind.Text"),
943
814
  "data": cell,
944
815
  }
reflex/utils/imports.py CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import dataclasses
5
6
  from collections import defaultdict
6
- from typing import Dict, List, Optional, Tuple, Union
7
-
8
- from reflex.base import Base
7
+ from typing import DefaultDict, Dict, List, Optional, Tuple, Union
9
8
 
10
9
 
11
10
  def merge_imports(
@@ -19,12 +18,22 @@ def merge_imports(
19
18
  Returns:
20
19
  The merged import dicts.
21
20
  """
22
- all_imports = defaultdict(list)
21
+ all_imports: DefaultDict[str, List[ImportVar]] = defaultdict(list)
23
22
  for import_dict in imports:
24
23
  for lib, fields in (
25
24
  import_dict if isinstance(import_dict, tuple) else import_dict.items()
26
25
  ):
27
- all_imports[lib].extend(fields)
26
+ if isinstance(fields, (list, tuple, set)):
27
+ all_imports[lib].extend(
28
+ (
29
+ ImportVar(field) if isinstance(field, str) else field
30
+ for field in fields
31
+ )
32
+ )
33
+ else:
34
+ all_imports[lib].append(
35
+ ImportVar(fields) if isinstance(fields, str) else fields
36
+ )
28
37
  return all_imports
29
38
 
30
39
 
@@ -75,7 +84,8 @@ def collapse_imports(
75
84
  }
76
85
 
77
86
 
78
- class ImportVar(Base):
87
+ @dataclasses.dataclass(order=True, frozen=True)
88
+ class ImportVar:
79
89
  """An import var."""
80
90
 
81
91
  # The name of the import tag.
@@ -111,73 +121,6 @@ class ImportVar(Base):
111
121
  else:
112
122
  return self.tag or ""
113
123
 
114
- def __lt__(self, other: ImportVar) -> bool:
115
- """Compare two ImportVar objects.
116
-
117
- Args:
118
- other: The other ImportVar object to compare.
119
-
120
- Returns:
121
- Whether this ImportVar object is less than the other.
122
- """
123
- return (
124
- self.tag,
125
- self.is_default,
126
- self.alias,
127
- self.install,
128
- self.render,
129
- self.transpile,
130
- ) < (
131
- other.tag,
132
- other.is_default,
133
- other.alias,
134
- other.install,
135
- other.render,
136
- other.transpile,
137
- )
138
-
139
- def __eq__(self, other: ImportVar) -> bool:
140
- """Check if two ImportVar objects are equal.
141
-
142
- Args:
143
- other: The other ImportVar object to compare.
144
-
145
- Returns:
146
- Whether the two ImportVar objects are equal.
147
- """
148
- return (
149
- self.tag,
150
- self.is_default,
151
- self.alias,
152
- self.install,
153
- self.render,
154
- self.transpile,
155
- ) == (
156
- other.tag,
157
- other.is_default,
158
- other.alias,
159
- other.install,
160
- other.render,
161
- other.transpile,
162
- )
163
-
164
- def __hash__(self) -> int:
165
- """Hash the ImportVar object.
166
-
167
- Returns:
168
- The hash of the ImportVar object.
169
- """
170
- return hash(
171
- (
172
- self.tag,
173
- self.is_default,
174
- self.alias,
175
- self.install,
176
- self.render,
177
- self.transpile,
178
- )
179
- )
180
-
181
124
 
182
125
  ImportTypes = Union[str, ImportVar, List[Union[str, ImportVar]], List[ImportVar]]
183
126
  ImportDict = Dict[str, ImportTypes]
reflex/utils/net.py ADDED
@@ -0,0 +1,43 @@
1
+ """Helpers for downloading files from the network."""
2
+
3
+ import os
4
+
5
+ import httpx
6
+
7
+ from . import console
8
+
9
+
10
+ def _httpx_verify_kwarg() -> bool:
11
+ """Get the value of the HTTPX verify keyword argument.
12
+
13
+ Returns:
14
+ True if SSL verification is enabled, False otherwise
15
+ """
16
+ ssl_no_verify = os.environ.get("SSL_NO_VERIFY", "").lower() in ["true", "1", "yes"]
17
+ return not ssl_no_verify
18
+
19
+
20
+ def get(url: str, **kwargs) -> httpx.Response:
21
+ """Make an HTTP GET request.
22
+
23
+ Args:
24
+ url: The URL to request.
25
+ **kwargs: Additional keyword arguments to pass to httpx.get.
26
+
27
+ Returns:
28
+ The response object.
29
+
30
+ Raises:
31
+ httpx.ConnectError: If the connection cannot be established.
32
+ """
33
+ kwargs.setdefault("verify", _httpx_verify_kwarg())
34
+ try:
35
+ return httpx.get(url, **kwargs)
36
+ except httpx.ConnectError as err:
37
+ if "CERTIFICATE_VERIFY_FAILED" in str(err):
38
+ # If the error is a certificate verification error, recommend mitigating steps.
39
+ console.error(
40
+ f"Certificate verification failed for {url}. Set environment variable SSL_CERT_FILE to the "
41
+ "path of the certificate file or SSL_NO_VERIFY=1 to disable verification."
42
+ )
43
+ raise
reflex/utils/path_ops.py CHANGED
@@ -81,6 +81,18 @@ def mkdir(path: str | Path):
81
81
  Path(path).mkdir(parents=True, exist_ok=True)
82
82
 
83
83
 
84
+ def ls(path: str | Path) -> list[Path]:
85
+ """List the contents of a directory.
86
+
87
+ Args:
88
+ path: The path to the directory.
89
+
90
+ Returns:
91
+ A list of paths to the contents of the directory.
92
+ """
93
+ return list(Path(path).iterdir())
94
+
95
+
84
96
  def ln(src: str | Path, dest: str | Path, overwrite: bool = False) -> bool:
85
97
  """Create a symbolic link.
86
98
 
@@ -197,4 +209,4 @@ def find_replace(directory: str | Path, find: str, replace: str):
197
209
  filepath = Path(root, file)
198
210
  text = filepath.read_text(encoding="utf-8")
199
211
  text = re.sub(find, replace, text)
200
- filepath.write_text(text)
212
+ filepath.write_text(text, encoding="utf-8")