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
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import dataclasses
5
6
  import functools
6
7
  import glob
7
8
  import importlib
@@ -28,20 +29,21 @@ import typer
28
29
  from alembic.util.exc import CommandError
29
30
  from packaging import version
30
31
  from redis import Redis as RedisSync
32
+ from redis import exceptions
31
33
  from redis.asyncio import Redis
32
34
 
33
35
  from reflex import constants, model
34
- from reflex.base import Base
35
36
  from reflex.compiler import templates
36
37
  from reflex.config import Config, get_config
37
- from reflex.utils import console, path_ops, processes
38
+ from reflex.utils import console, net, path_ops, processes
38
39
  from reflex.utils.format import format_library_name
39
40
  from reflex.utils.registry import _get_best_registry
40
41
 
41
42
  CURRENTLY_INSTALLING_NODE = False
42
43
 
43
44
 
44
- class Template(Base):
45
+ @dataclasses.dataclass(frozen=True)
46
+ class Template:
45
47
  """A template for a Reflex app."""
46
48
 
47
49
  name: str
@@ -50,7 +52,8 @@ class Template(Base):
50
52
  demo_url: str
51
53
 
52
54
 
53
- class CpuInfo(Base):
55
+ @dataclasses.dataclass(frozen=True)
56
+ class CpuInfo:
54
57
  """Model to save cpu info."""
55
58
 
56
59
  manufacturer_id: Optional[str]
@@ -70,6 +73,18 @@ def get_web_dir() -> Path:
70
73
  return workdir
71
74
 
72
75
 
76
+ def _python_version_check():
77
+ """Emit deprecation warning for deprecated python versions."""
78
+ # Check for end-of-life python versions.
79
+ if sys.version_info < (3, 10):
80
+ console.deprecate(
81
+ feature_name="Support for Python 3.9 and older",
82
+ reason="please upgrade to Python 3.10 or newer",
83
+ deprecation_version="0.6.0",
84
+ removal_version="0.7.0",
85
+ )
86
+
87
+
73
88
  def check_latest_package_version(package_name: str):
74
89
  """Check if the latest version of the package is installed.
75
90
 
@@ -80,17 +95,18 @@ def check_latest_package_version(package_name: str):
80
95
  # Get the latest version from PyPI
81
96
  current_version = importlib.metadata.version(package_name)
82
97
  url = f"https://pypi.org/pypi/{package_name}/json"
83
- response = httpx.get(url)
98
+ response = net.get(url)
84
99
  latest_version = response.json()["info"]["version"]
85
- if (
86
- version.parse(current_version) < version.parse(latest_version)
87
- and not get_or_set_last_reflex_version_check_datetime()
88
- ):
89
- # only show a warning when the host version is outdated and
90
- # the last_version_check_datetime is not set in reflex.json
100
+ if get_or_set_last_reflex_version_check_datetime():
101
+ # Versions were already checked and saved in reflex.json, no need to warn again
102
+ return
103
+ if version.parse(current_version) < version.parse(latest_version):
104
+ # Show a warning when the host version is older than PyPI version
91
105
  console.warn(
92
106
  f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'"
93
107
  )
108
+ # Check for depreacted python versions
109
+ _python_version_check()
94
110
  except Exception:
95
111
  pass
96
112
 
@@ -287,7 +303,7 @@ def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
287
303
  """
288
304
  app_module = get_app(reload=reload)
289
305
  app = getattr(app_module, constants.CompileVars.APP)
290
- # For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
306
+ # For py3.9 compatibility when redis is used, we MUST add any decorator pages
291
307
  # before compiling the app in a thread to avoid event loop error (REF-2172).
292
308
  app._apply_decorated_pages()
293
309
  app._compile(export=export)
@@ -324,24 +340,43 @@ def parse_redis_url() -> str | dict | None:
324
340
  """Parse the REDIS_URL in config if applicable.
325
341
 
326
342
  Returns:
327
- If redis-py syntax, return the URL as it is. Otherwise, return the host/port/db as a dict.
343
+ If url is non-empty, return the URL as it is.
344
+
345
+ Raises:
346
+ ValueError: If the REDIS_URL is not a supported scheme.
328
347
  """
329
348
  config = get_config()
330
349
  if not config.redis_url:
331
350
  return None
332
- if config.redis_url.startswith(("redis://", "rediss://", "unix://")):
333
- return config.redis_url
334
- console.deprecate(
335
- feature_name="host[:port] style redis urls",
336
- reason="redis-py url syntax is now being used",
337
- deprecation_version="0.3.6",
338
- removal_version="0.6.0",
339
- )
340
- redis_url, has_port, redis_port = config.redis_url.partition(":")
341
- if not has_port:
342
- redis_port = 6379
343
- console.info(f"Using redis at {config.redis_url}")
344
- return dict(host=redis_url, port=int(redis_port), db=0)
351
+ if not config.redis_url.startswith(("redis://", "rediss://", "unix://")):
352
+ raise ValueError(
353
+ "REDIS_URL must start with 'redis://', 'rediss://', or 'unix://'."
354
+ )
355
+ return config.redis_url
356
+
357
+
358
+ async def get_redis_status() -> bool | None:
359
+ """Checks the status of the Redis connection.
360
+
361
+ Attempts to connect to Redis and send a ping command to verify connectivity.
362
+
363
+ Returns:
364
+ bool or None: The status of the Redis connection:
365
+ - True: Redis is accessible and responding.
366
+ - False: Redis is not accessible due to a connection error.
367
+ - None: Redis not used i.e redis_url is not set in rxconfig.
368
+ """
369
+ try:
370
+ status = True
371
+ redis_client = get_redis_sync()
372
+ if redis_client is not None:
373
+ redis_client.ping()
374
+ else:
375
+ status = None
376
+ except exceptions.RedisError:
377
+ status = False
378
+
379
+ return status
345
380
 
346
381
 
347
382
  def validate_app_name(app_name: str | None = None) -> str:
@@ -670,7 +705,7 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
670
705
  """
671
706
  # Download the script
672
707
  console.debug(f"Downloading {url}")
673
- response = httpx.get(url)
708
+ response = net.get(url)
674
709
  if response.status_code != httpx.codes.OK:
675
710
  response.raise_for_status()
676
711
 
@@ -700,11 +735,11 @@ def download_and_extract_fnm_zip():
700
735
  try:
701
736
  # Download the FNM zip release.
702
737
  # TODO: show progress to improve UX
703
- with httpx.stream("GET", url, follow_redirects=True) as response:
704
- response.raise_for_status()
705
- with open(fnm_zip_file, "wb") as output_file:
706
- for chunk in response.iter_bytes():
707
- output_file.write(chunk)
738
+ response = net.get(url, follow_redirects=True)
739
+ response.raise_for_status()
740
+ with open(fnm_zip_file, "wb") as output_file:
741
+ for chunk in response.iter_bytes():
742
+ output_file.write(chunk)
708
743
 
709
744
  # Extract the downloaded zip file.
710
745
  with zipfile.ZipFile(fnm_zip_file, "r") as zip_ref:
@@ -1222,7 +1257,7 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
1222
1257
  """
1223
1258
 
1224
1259
  def get_release_by_tag(tag: str) -> dict | None:
1225
- response = httpx.get(constants.Reflex.RELEASES_URL)
1260
+ response = net.get(constants.Reflex.RELEASES_URL)
1226
1261
  response.raise_for_status()
1227
1262
  releases = response.json()
1228
1263
  for release in releases:
@@ -1243,7 +1278,7 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
1243
1278
  else:
1244
1279
  templates_url = asset["browser_download_url"]
1245
1280
 
1246
- templates_data = httpx.get(templates_url, follow_redirects=True).json()["templates"]
1281
+ templates_data = net.get(templates_url, follow_redirects=True).json()["templates"]
1247
1282
 
1248
1283
  for template in templates_data:
1249
1284
  if template["name"] == "blank":
@@ -1257,11 +1292,16 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
1257
1292
  ),
1258
1293
  None,
1259
1294
  )
1260
- return {
1261
- tp["name"]: Template.parse_obj(tp)
1262
- for tp in templates_data
1263
- if not tp["hidden"] and tp["code_url"] is not None
1264
- }
1295
+
1296
+ filtered_templates = {}
1297
+ for tp in templates_data:
1298
+ if tp["hidden"] or tp["code_url"] is None:
1299
+ continue
1300
+ known_fields = set(f.name for f in dataclasses.fields(Template))
1301
+ filtered_templates[tp["name"]] = Template(
1302
+ **{k: v for k, v in tp.items() if k in known_fields}
1303
+ )
1304
+ return filtered_templates
1265
1305
 
1266
1306
 
1267
1307
  def create_config_init_app_from_remote_template(app_name: str, template_url: str):
@@ -1286,7 +1326,7 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
1286
1326
  zip_file_path = Path(temp_dir) / "template.zip"
1287
1327
  try:
1288
1328
  # Note: following redirects can be risky. We only allow this for reflex built templates at the moment.
1289
- response = httpx.get(template_url, follow_redirects=True)
1329
+ response = net.get(template_url, follow_redirects=True)
1290
1330
  console.debug(f"Server responded download request: {response}")
1291
1331
  response.raise_for_status()
1292
1332
  except httpx.HTTPError as he:
@@ -1417,7 +1457,7 @@ def initialize_main_module_index_from_generation(app_name: str, generation_hash:
1417
1457
  generation_hash: The generation hash from reflex.build.
1418
1458
  """
1419
1459
  # Download the reflex code for the generation.
1420
- resp = httpx.get(
1460
+ resp = net.get(
1421
1461
  constants.Templates.REFLEX_BUILD_CODE_URL.format(
1422
1462
  generation_hash=generation_hash
1423
1463
  )
@@ -20,7 +20,7 @@ from typing import Any, Callable, Iterable, Type, get_args
20
20
 
21
21
  from reflex.components.component import Component
22
22
  from reflex.utils import types as rx_types
23
- from reflex.vars import Var
23
+ from reflex.vars.base import Var
24
24
 
25
25
  logger = logging.getLogger("pyi_generator")
26
26
 
@@ -69,10 +69,10 @@ DEFAULT_TYPING_IMPORTS = {
69
69
  # TODO: fix import ordering and unused imports with ruff later
70
70
  DEFAULT_IMPORTS = {
71
71
  "typing": sorted(DEFAULT_TYPING_IMPORTS),
72
- "reflex.vars": ["Var", "BaseVar", "ComputedVar"],
73
72
  "reflex.components.core.breakpoints": ["Breakpoints"],
74
73
  "reflex.event": ["EventChain", "EventHandler", "EventSpec"],
75
74
  "reflex.style": ["Style"],
75
+ "reflex.vars.base": ["Var"],
76
76
  }
77
77
 
78
78
 
@@ -150,7 +150,7 @@ def _get_type_hint(value, type_hint_globals, is_optional=True) -> str:
150
150
 
151
151
  if args:
152
152
  inner_container_type_args = (
153
- [repr(arg) for arg in args]
153
+ sorted((repr(arg) for arg in args))
154
154
  if rx_types.is_literal(value)
155
155
  else [
156
156
  _get_type_hint(arg, type_hint_globals, is_optional=False)
@@ -184,7 +184,7 @@ def _get_type_hint(value, type_hint_globals, is_optional=True) -> str:
184
184
  if arg is not type(None)
185
185
  ]
186
186
  if len(types) > 1:
187
- res = ", ".join(types)
187
+ res = ", ".join(sorted(types))
188
188
  res = f"Union[{res}]"
189
189
  elif isinstance(value, str):
190
190
  ev = eval(value, type_hint_globals)
@@ -433,7 +433,7 @@ def _generate_component_create_functiondef(
433
433
  ast.arg(
434
434
  arg=trigger,
435
435
  annotation=ast.Name(
436
- id="Optional[Union[EventHandler, EventSpec, list, Callable, BaseVar]]"
436
+ id="Optional[Union[EventHandler, EventSpec, list, Callable, Var]]"
437
437
  ),
438
438
  ),
439
439
  ast.Constant(value=None),
@@ -902,7 +902,13 @@ class PyiGenerator:
902
902
  # construct the import statement and handle special cases for aliases
903
903
  sub_mod_attrs_imports = [
904
904
  f"from .{path} import {mod if not isinstance(mod, tuple) else mod[0]} as {mod if not isinstance(mod, tuple) else mod[1]}"
905
- + (" # type: ignore" if mod in pyright_ignore_imports else "")
905
+ + (
906
+ " # type: ignore"
907
+ if mod in pyright_ignore_imports
908
+ else " # noqa" # ignore ruff formatting here for cases like rx.list.
909
+ if isinstance(mod, tuple)
910
+ else ""
911
+ )
906
912
  for mod, path in sub_mod_attrs.items()
907
913
  ]
908
914
  sub_mod_attrs_imports.append("")
@@ -2,9 +2,9 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import dataclasses
5
6
  import functools
6
7
  import json
7
- import types as builtin_types
8
8
  import warnings
9
9
  from datetime import date, datetime, time, timedelta
10
10
  from enum import Enum
@@ -26,11 +26,11 @@ from typing import (
26
26
 
27
27
  from reflex.base import Base
28
28
  from reflex.constants.colors import Color, format_color
29
- from reflex.utils import exceptions, types
29
+ from reflex.utils import types
30
30
 
31
31
  # Mapping from type to a serializer.
32
32
  # The serializer should convert the type to a JSON object.
33
- SerializedType = Union[str, bool, int, float, list, dict]
33
+ SerializedType = Union[str, bool, int, float, list, dict, None]
34
34
 
35
35
 
36
36
  Serializer = Callable[[Type], SerializedType]
@@ -125,6 +125,8 @@ def serialize(
125
125
 
126
126
  # If there is no serializer, return None.
127
127
  if serializer is None:
128
+ if dataclasses.is_dataclass(value) and not isinstance(value, type):
129
+ return serialize(dataclasses.asdict(value))
128
130
  if get_type:
129
131
  return None, None
130
132
  return None
@@ -226,7 +228,7 @@ def serialize_str(value: str) -> str:
226
228
 
227
229
 
228
230
  @serializer
229
- def serialize_primitive(value: Union[bool, int, float, None]) -> str:
231
+ def serialize_primitive(value: Union[bool, int, float, None]):
230
232
  """Serialize a primitive type.
231
233
 
232
234
  Args:
@@ -235,13 +237,11 @@ def serialize_primitive(value: Union[bool, int, float, None]) -> str:
235
237
  Returns:
236
238
  The serialized number/bool/None.
237
239
  """
238
- from reflex.utils import format
239
-
240
- return format.json_dumps(value)
240
+ return value
241
241
 
242
242
 
243
243
  @serializer
244
- def serialize_base(value: Base) -> str:
244
+ def serialize_base(value: Base) -> dict:
245
245
  """Serialize a Base instance.
246
246
 
247
247
  Args:
@@ -250,11 +250,11 @@ def serialize_base(value: Base) -> str:
250
250
  Returns:
251
251
  The serialized Base.
252
252
  """
253
- return value.json()
253
+ return {k: serialize(v) for k, v in value.dict().items() if not callable(v)}
254
254
 
255
255
 
256
256
  @serializer
257
- def serialize_list(value: Union[List, Tuple, Set]) -> str:
257
+ def serialize_list(value: Union[List, Tuple, Set]) -> list:
258
258
  """Serialize a list to a JSON string.
259
259
 
260
260
  Args:
@@ -263,17 +263,11 @@ def serialize_list(value: Union[List, Tuple, Set]) -> str:
263
263
  Returns:
264
264
  The serialized list.
265
265
  """
266
- from reflex.utils import format
267
-
268
- # Dump the list to a string.
269
- fprop = format.json_dumps(list(value))
270
-
271
- # Unwrap var values.
272
- return format.unwrap_vars(fprop)
266
+ return [serialize(item) for item in value]
273
267
 
274
268
 
275
269
  @serializer
276
- def serialize_dict(prop: Dict[str, Any]) -> str:
270
+ def serialize_dict(prop: Dict[str, Any]) -> dict:
277
271
  """Serialize a dictionary to a JSON string.
278
272
 
279
273
  Args:
@@ -281,30 +275,8 @@ def serialize_dict(prop: Dict[str, Any]) -> str:
281
275
 
282
276
  Returns:
283
277
  The serialized dictionary.
284
-
285
- Raises:
286
- InvalidStylePropError: If the style prop is invalid.
287
278
  """
288
- # Import here to avoid circular imports.
289
- from reflex.event import EventHandler
290
- from reflex.utils import format
291
-
292
- prop_dict = {}
293
-
294
- for key, value in prop.items():
295
- if types._issubclass(type(value), Callable):
296
- raise exceptions.InvalidStylePropError(
297
- f"The style prop `{format.to_snake_case(key)}` cannot have " # type: ignore
298
- f"`{value.fn.__qualname__ if isinstance(value, EventHandler) else value.__qualname__ if isinstance(value, builtin_types.FunctionType) else value}`, "
299
- f"an event handler or callable as its value"
300
- )
301
- prop_dict[key] = value
302
-
303
- # Dump the dict to a string.
304
- fprop = format.json_dumps(prop_dict)
305
-
306
- # Unwrap var values.
307
- return format.unwrap_vars(fprop)
279
+ return {k: serialize(v) for k, v in prop.items()}
308
280
 
309
281
 
310
282
  @serializer(to=str)
reflex/utils/telemetry.py CHANGED
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import dataclasses
6
7
  import multiprocessing
7
8
  import platform
8
9
  import warnings
@@ -120,7 +121,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
120
121
  return {}
121
122
 
122
123
  if UTC is None:
123
- # for python 3.8, 3.9 & 3.10
124
+ # for python 3.9 & 3.10
124
125
  stamp = datetime.utcnow().isoformat()
125
126
  else:
126
127
  # for python 3.11 & 3.12
@@ -144,7 +145,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
144
145
  "python_version": get_python_version(),
145
146
  "cpu_count": get_cpu_count(),
146
147
  "memory": get_memory(),
147
- "cpu_info": dict(cpuinfo) if cpuinfo else {},
148
+ "cpu_info": dataclasses.asdict(cpuinfo) if cpuinfo else {},
148
149
  **additional_fields,
149
150
  },
150
151
  "timestamp": stamp,
reflex/utils/types.py CHANGED
@@ -3,10 +3,11 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import contextlib
6
+ import dataclasses
6
7
  import inspect
7
8
  import sys
8
9
  import types
9
- from functools import cached_property, wraps
10
+ from functools import cached_property, lru_cache, wraps
10
11
  from typing import (
11
12
  Any,
12
13
  Callable,
@@ -21,9 +22,11 @@ from typing import (
21
22
  Union,
22
23
  _GenericAlias, # type: ignore
23
24
  get_args,
24
- get_origin,
25
25
  get_type_hints,
26
26
  )
27
+ from typing import (
28
+ get_origin as get_origin_og,
29
+ )
27
30
 
28
31
  import sqlalchemy
29
32
 
@@ -109,6 +112,11 @@ RESERVED_BACKEND_VAR_NAMES = {
109
112
  "_was_touched",
110
113
  }
111
114
 
115
+ if sys.version_info >= (3, 11):
116
+ from typing import Self as Self
117
+ else:
118
+ from typing_extensions import Self as Self
119
+
112
120
 
113
121
  class Unset:
114
122
  """A class to represent an unset value.
@@ -133,6 +141,20 @@ class Unset:
133
141
  return False
134
142
 
135
143
 
144
+ @lru_cache()
145
+ def get_origin(tp):
146
+ """Get the origin of a class.
147
+
148
+ Args:
149
+ tp: The class to get the origin of.
150
+
151
+ Returns:
152
+ The origin of the class.
153
+ """
154
+ return get_origin_og(tp)
155
+
156
+
157
+ @lru_cache()
136
158
  def is_generic_alias(cls: GenericType) -> bool:
137
159
  """Check whether the class is a generic alias.
138
160
 
@@ -157,6 +179,7 @@ def is_none(cls: GenericType) -> bool:
157
179
  return cls is type(None) or cls is None
158
180
 
159
181
 
182
+ @lru_cache()
160
183
  def is_union(cls: GenericType) -> bool:
161
184
  """Check if a class is a Union.
162
185
 
@@ -169,6 +192,7 @@ def is_union(cls: GenericType) -> bool:
169
192
  return get_origin(cls) in UnionTypes
170
193
 
171
194
 
195
+ @lru_cache()
172
196
  def is_literal(cls: GenericType) -> bool:
173
197
  """Check if a class is a Literal.
174
198
 
@@ -222,9 +246,14 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
222
246
  """
223
247
  from reflex.model import Model
224
248
 
225
- attr = getattr(cls, name, None)
249
+ try:
250
+ attr = getattr(cls, name, None)
251
+ except NotImplementedError:
252
+ attr = None
253
+
226
254
  if hint := get_property_hint(attr):
227
255
  return hint
256
+
228
257
  if (
229
258
  hasattr(cls, "__fields__")
230
259
  and name in cls.__fields__
@@ -314,6 +343,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
314
343
  return None # Attribute is not accessible.
315
344
 
316
345
 
346
+ @lru_cache()
317
347
  def get_base_class(cls: GenericType) -> Type:
318
348
  """Get the base class of a class.
319
349
 
@@ -451,7 +481,11 @@ def is_valid_var_type(type_: Type) -> bool:
451
481
 
452
482
  if is_union(type_):
453
483
  return all((is_valid_var_type(arg) for arg in get_args(type_)))
454
- return _issubclass(type_, StateVar) or serializers.has_serializer(type_)
484
+ return (
485
+ _issubclass(type_, StateVar)
486
+ or serializers.has_serializer(type_)
487
+ or dataclasses.is_dataclass(type_)
488
+ )
455
489
 
456
490
 
457
491
  def is_backend_base_variable(name: str, cls: Type) -> bool:
@@ -485,17 +519,23 @@ def is_backend_base_variable(name: str, cls: Type) -> bool:
485
519
  if name in cls.inherited_backend_vars:
486
520
  return False
487
521
 
522
+ from reflex.vars.base import is_computed_var
523
+
488
524
  if name in cls.__dict__:
489
525
  value = cls.__dict__[name]
490
526
  if type(value) == classmethod:
491
527
  return False
492
528
  if callable(value):
493
529
  return False
494
- from reflex.vars import ComputedVar
495
530
 
496
531
  if isinstance(
497
- value, (types.FunctionType, property, cached_property, ComputedVar)
498
- ):
532
+ value,
533
+ (
534
+ types.FunctionType,
535
+ property,
536
+ cached_property,
537
+ ),
538
+ ) or is_computed_var(value):
499
539
  return False
500
540
 
501
541
  return True
@@ -1,8 +1,12 @@
1
- """Experimental Immutable-Based Var System."""
1
+ """Immutable-Based Var System."""
2
2
 
3
- from .base import ImmutableVar as ImmutableVar
4
3
  from .base import LiteralVar as LiteralVar
4
+ from .base import Var as Var
5
+ from .base import VarData as VarData
6
+ from .base import get_unique_variable_name as get_unique_variable_name
7
+ from .base import get_uuid_string_var as get_uuid_string_var
5
8
  from .base import var_operation as var_operation
9
+ from .base import var_operation_return as var_operation_return
6
10
  from .function import FunctionStringVar as FunctionStringVar
7
11
  from .function import FunctionVar as FunctionVar
8
12
  from .function import VarOperationCall as VarOperationCall
@@ -12,7 +16,6 @@ from .number import LiteralNumberVar as LiteralNumberVar
12
16
  from .number import NumberVar as NumberVar
13
17
  from .object import LiteralObjectVar as LiteralObjectVar
14
18
  from .object import ObjectVar as ObjectVar
15
- from .sequence import ArrayJoinOperation as ArrayJoinOperation
16
19
  from .sequence import ArrayVar as ArrayVar
17
20
  from .sequence import ConcatVarOperation as ConcatVarOperation
18
21
  from .sequence import LiteralArrayVar as LiteralArrayVar