reflex 0.6.0__py3-none-any.whl → 0.6.0a1__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 (253) 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 +2 -2
  4. reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +36 -0
  5. reflex/.templates/web/utils/state.js +1 -3
  6. reflex/__init__.py +2 -8
  7. reflex/__init__.pyi +1 -2
  8. reflex/app.py +2 -4
  9. reflex/app_module_for_backend.py +1 -1
  10. reflex/base.py +1 -1
  11. reflex/compiler/compiler.py +2 -2
  12. reflex/compiler/utils.py +3 -3
  13. reflex/components/base/app_wrap.py +2 -2
  14. reflex/components/base/app_wrap.pyi +27 -17
  15. reflex/components/base/bare.py +5 -4
  16. reflex/components/base/body.pyi +27 -17
  17. reflex/components/base/document.pyi +131 -81
  18. reflex/components/base/error_boundary.py +7 -6
  19. reflex/components/base/error_boundary.pyi +33 -20
  20. reflex/components/base/fragment.pyi +27 -17
  21. reflex/components/base/head.pyi +53 -33
  22. reflex/components/base/link.py +1 -1
  23. reflex/components/base/link.pyi +54 -33
  24. reflex/components/base/meta.pyi +105 -65
  25. reflex/components/base/script.py +2 -1
  26. reflex/components/base/script.pyi +38 -21
  27. reflex/components/component.py +47 -53
  28. reflex/components/core/banner.py +27 -23
  29. reflex/components/core/banner.pyi +171 -134
  30. reflex/components/core/client_side_routing.py +3 -2
  31. reflex/components/core/client_side_routing.pyi +54 -33
  32. reflex/components/core/clipboard.py +1 -2
  33. reflex/components/core/clipboard.pyi +33 -20
  34. reflex/components/core/cond.py +5 -5
  35. reflex/components/core/debounce.py +5 -5
  36. reflex/components/core/debounce.pyi +33 -20
  37. reflex/components/core/foreach.py +4 -3
  38. reflex/components/core/html.py +1 -1
  39. reflex/components/core/html.pyi +46 -35
  40. reflex/components/core/match.py +17 -17
  41. reflex/components/core/upload.py +23 -17
  42. reflex/components/core/upload.pyi +124 -78
  43. reflex/components/datadisplay/code.py +10 -9
  44. reflex/components/datadisplay/code.pyi +409 -299
  45. reflex/components/datadisplay/dataeditor.py +10 -8
  46. reflex/components/datadisplay/dataeditor.pyi +53 -40
  47. reflex/components/el/element.pyi +27 -17
  48. reflex/components/el/elements/base.py +1 -1
  49. reflex/components/el/elements/base.pyi +45 -34
  50. reflex/components/el/elements/forms.py +16 -16
  51. reflex/components/el/elements/forms.pyi +707 -554
  52. reflex/components/el/elements/inline.py +1 -1
  53. reflex/components/el/elements/inline.pyi +1218 -937
  54. reflex/components/el/elements/media.py +1 -1
  55. reflex/components/el/elements/media.pyi +997 -786
  56. reflex/components/el/elements/metadata.py +6 -3
  57. reflex/components/el/elements/metadata.pyi +242 -181
  58. reflex/components/el/elements/other.py +1 -1
  59. reflex/components/el/elements/other.pyi +306 -235
  60. reflex/components/el/elements/scripts.py +1 -1
  61. reflex/components/el/elements/scripts.pyi +140 -109
  62. reflex/components/el/elements/sectioning.py +2 -0
  63. reflex/components/el/elements/sectioning.pyi +647 -496
  64. reflex/components/el/elements/tables.py +1 -1
  65. reflex/components/el/elements/tables.pyi +452 -351
  66. reflex/components/el/elements/typography.py +1 -1
  67. reflex/components/el/elements/typography.pyi +657 -506
  68. reflex/components/gridjs/datatable.py +9 -6
  69. reflex/components/gridjs/datatable.pyi +56 -35
  70. reflex/components/lucide/icon.py +1 -1
  71. reflex/components/lucide/icon.pyi +54 -33
  72. reflex/components/markdown/markdown.py +31 -26
  73. reflex/components/markdown/markdown.pyi +37 -27
  74. reflex/components/moment/moment.py +12 -13
  75. reflex/components/moment/moment.pyi +35 -23
  76. reflex/components/next/base.pyi +27 -17
  77. reflex/components/next/image.py +1 -1
  78. reflex/components/next/image.pyi +37 -22
  79. reflex/components/next/link.py +1 -1
  80. reflex/components/next/link.pyi +28 -17
  81. reflex/components/next/video.py +1 -1
  82. reflex/components/next/video.pyi +28 -17
  83. reflex/components/plotly/plotly.py +13 -12
  84. reflex/components/plotly/plotly.pyi +54 -39
  85. reflex/components/props.py +1 -1
  86. reflex/components/radix/__init__.pyi +0 -1
  87. reflex/components/radix/primitives/__init__.pyi +0 -1
  88. reflex/components/radix/primitives/accordion.py +4 -4
  89. reflex/components/radix/primitives/accordion.pyi +495 -424
  90. reflex/components/radix/primitives/base.py +1 -1
  91. reflex/components/radix/primitives/base.pyi +54 -33
  92. reflex/components/radix/primitives/drawer.py +1 -1
  93. reflex/components/radix/primitives/drawer.pyi +273 -172
  94. reflex/components/radix/primitives/form.py +1 -1
  95. reflex/components/radix/primitives/form.pyi +364 -257
  96. reflex/components/radix/primitives/progress.py +1 -1
  97. reflex/components/radix/primitives/progress.pyi +282 -231
  98. reflex/components/radix/primitives/slider.py +1 -1
  99. reflex/components/radix/primitives/slider.pyi +138 -87
  100. reflex/components/radix/themes/base.py +24 -3
  101. reflex/components/radix/themes/base.pyi +250 -178
  102. reflex/components/radix/themes/color_mode.py +5 -5
  103. reflex/components/radix/themes/color_mode.pyi +220 -187
  104. reflex/components/radix/themes/components/alert_dialog.py +1 -1
  105. reflex/components/radix/themes/components/alert_dialog.pyi +207 -136
  106. reflex/components/radix/themes/components/aspect_ratio.py +1 -1
  107. reflex/components/radix/themes/components/aspect_ratio.pyi +28 -17
  108. reflex/components/radix/themes/components/avatar.py +1 -1
  109. reflex/components/radix/themes/components/avatar.pyi +81 -70
  110. reflex/components/radix/themes/components/badge.py +1 -1
  111. reflex/components/radix/themes/components/badge.pyi +99 -88
  112. reflex/components/radix/themes/components/button.py +1 -1
  113. reflex/components/radix/themes/components/button.pyi +109 -98
  114. reflex/components/radix/themes/components/callout.py +1 -1
  115. reflex/components/radix/themes/components/callout.pyi +373 -322
  116. reflex/components/radix/themes/components/card.py +1 -1
  117. reflex/components/radix/themes/components/card.pyi +49 -38
  118. reflex/components/radix/themes/components/checkbox.py +2 -1
  119. reflex/components/radix/themes/components/checkbox.pyi +245 -208
  120. reflex/components/radix/themes/components/checkbox_cards.py +1 -1
  121. reflex/components/radix/themes/components/checkbox_cards.pyi +115 -94
  122. reflex/components/radix/themes/components/checkbox_group.py +1 -1
  123. reflex/components/radix/themes/components/checkbox_group.pyi +107 -86
  124. reflex/components/radix/themes/components/context_menu.py +1 -1
  125. reflex/components/radix/themes/components/context_menu.pyi +319 -238
  126. reflex/components/radix/themes/components/data_list.py +1 -1
  127. reflex/components/radix/themes/components/data_list.pyi +171 -130
  128. reflex/components/radix/themes/components/dialog.py +1 -1
  129. reflex/components/radix/themes/components/dialog.pyi +210 -139
  130. reflex/components/radix/themes/components/dropdown_menu.py +1 -1
  131. reflex/components/radix/themes/components/dropdown_menu.pyi +332 -249
  132. reflex/components/radix/themes/components/hover_card.py +1 -1
  133. reflex/components/radix/themes/components/hover_card.pyi +131 -90
  134. reflex/components/radix/themes/components/icon_button.py +3 -2
  135. reflex/components/radix/themes/components/icon_button.pyi +109 -98
  136. reflex/components/radix/themes/components/inset.py +1 -1
  137. reflex/components/radix/themes/components/inset.pyi +58 -47
  138. reflex/components/radix/themes/components/popover.py +1 -1
  139. reflex/components/radix/themes/components/popover.pyi +136 -95
  140. reflex/components/radix/themes/components/progress.py +1 -1
  141. reflex/components/radix/themes/components/progress.pyi +82 -71
  142. reflex/components/radix/themes/components/radio.py +1 -1
  143. reflex/components/radix/themes/components/radio.pyi +80 -69
  144. reflex/components/radix/themes/components/radio_cards.py +1 -1
  145. reflex/components/radix/themes/components/radio_cards.pyi +119 -98
  146. reflex/components/radix/themes/components/radio_group.py +11 -8
  147. reflex/components/radix/themes/components/radio_group.pyi +271 -228
  148. reflex/components/radix/themes/components/scroll_area.py +1 -1
  149. reflex/components/radix/themes/components/scroll_area.pyi +32 -21
  150. reflex/components/radix/themes/components/segmented_control.py +1 -1
  151. reflex/components/radix/themes/components/segmented_control.pyi +113 -90
  152. reflex/components/radix/themes/components/select.py +3 -2
  153. reflex/components/radix/themes/components/select.pyi +471 -374
  154. reflex/components/radix/themes/components/separator.py +2 -1
  155. reflex/components/radix/themes/components/separator.pyi +80 -69
  156. reflex/components/radix/themes/components/skeleton.py +1 -1
  157. reflex/components/radix/themes/components/skeleton.pyi +34 -23
  158. reflex/components/radix/themes/components/slider.py +3 -2
  159. reflex/components/radix/themes/components/slider.pyi +88 -75
  160. reflex/components/radix/themes/components/spinner.py +1 -1
  161. reflex/components/radix/themes/components/spinner.pyi +30 -19
  162. reflex/components/radix/themes/components/switch.py +1 -1
  163. reflex/components/radix/themes/components/switch.pyi +84 -71
  164. reflex/components/radix/themes/components/table.py +1 -1
  165. reflex/components/radix/themes/components/table.pyi +332 -261
  166. reflex/components/radix/themes/components/tabs.py +1 -1
  167. reflex/components/radix/themes/components/tabs.pyi +194 -139
  168. reflex/components/radix/themes/components/text_area.py +1 -1
  169. reflex/components/radix/themes/components/text_area.pyi +111 -96
  170. reflex/components/radix/themes/components/text_field.py +1 -1
  171. reflex/components/radix/themes/components/text_field.pyi +286 -247
  172. reflex/components/radix/themes/components/tooltip.py +1 -1
  173. reflex/components/radix/themes/components/tooltip.pyi +37 -26
  174. reflex/components/radix/themes/layout/__init__.pyi +0 -1
  175. reflex/components/radix/themes/layout/base.py +1 -1
  176. reflex/components/radix/themes/layout/base.pyi +67 -56
  177. reflex/components/radix/themes/layout/box.pyi +45 -34
  178. reflex/components/radix/themes/layout/center.pyi +67 -56
  179. reflex/components/radix/themes/layout/container.py +2 -1
  180. reflex/components/radix/themes/layout/container.pyi +47 -36
  181. reflex/components/radix/themes/layout/flex.py +1 -1
  182. reflex/components/radix/themes/layout/flex.pyi +67 -56
  183. reflex/components/radix/themes/layout/grid.py +1 -1
  184. reflex/components/radix/themes/layout/grid.pyi +75 -64
  185. reflex/components/radix/themes/layout/list.py +6 -5
  186. reflex/components/radix/themes/layout/list.pyi +244 -193
  187. reflex/components/radix/themes/layout/section.py +2 -1
  188. reflex/components/radix/themes/layout/section.pyi +47 -36
  189. reflex/components/radix/themes/layout/spacer.pyi +67 -56
  190. reflex/components/radix/themes/layout/stack.py +1 -1
  191. reflex/components/radix/themes/layout/stack.pyi +159 -128
  192. reflex/components/radix/themes/typography/blockquote.py +1 -1
  193. reflex/components/radix/themes/typography/blockquote.pyi +100 -89
  194. reflex/components/radix/themes/typography/code.py +1 -1
  195. reflex/components/radix/themes/typography/code.pyi +101 -90
  196. reflex/components/radix/themes/typography/heading.py +1 -1
  197. reflex/components/radix/themes/typography/heading.pyi +107 -96
  198. reflex/components/radix/themes/typography/link.py +1 -1
  199. reflex/components/radix/themes/typography/link.pyi +113 -102
  200. reflex/components/radix/themes/typography/text.py +1 -1
  201. reflex/components/radix/themes/typography/text.pyi +572 -501
  202. reflex/components/react_player/audio.pyi +60 -33
  203. reflex/components/react_player/react_player.py +1 -1
  204. reflex/components/react_player/react_player.pyi +60 -33
  205. reflex/components/react_player/video.pyi +60 -33
  206. reflex/components/recharts/cartesian.py +3 -2
  207. reflex/components/recharts/cartesian.pyi +861 -678
  208. reflex/components/recharts/charts.py +5 -4
  209. reflex/components/recharts/charts.pyi +357 -252
  210. reflex/components/recharts/general.py +2 -1
  211. reflex/components/recharts/general.pyi +231 -180
  212. reflex/components/recharts/polar.py +5 -4
  213. reflex/components/recharts/polar.pyi +181 -144
  214. reflex/components/recharts/recharts.pyi +53 -33
  215. reflex/components/sonner/toast.py +17 -16
  216. reflex/components/sonner/toast.pyi +47 -36
  217. reflex/components/suneditor/editor.py +3 -2
  218. reflex/components/suneditor/editor.pyi +78 -55
  219. reflex/components/tags/cond_tag.py +4 -6
  220. reflex/components/tags/iter_tag.py +16 -28
  221. reflex/components/tags/match_tag.py +4 -6
  222. reflex/components/tags/tag.py +23 -40
  223. reflex/custom_components/custom_components.py +1 -3
  224. reflex/event.py +65 -113
  225. reflex/experimental/client_state.py +24 -25
  226. reflex/experimental/hooks.py +16 -16
  227. reflex/experimental/layout.py +5 -5
  228. reflex/experimental/layout.pyi +187 -136
  229. reflex/{vars → ivars}/__init__.py +2 -6
  230. reflex/{vars → ivars}/base.py +216 -599
  231. reflex/{vars → ivars}/function.py +19 -15
  232. reflex/{vars → ivars}/number.py +20 -41
  233. reflex/{vars → ivars}/object.py +30 -28
  234. reflex/{vars → ivars}/sequence.py +50 -53
  235. reflex/middleware/hydrate_middleware.py +0 -2
  236. reflex/middleware/middleware.py +3 -3
  237. reflex/state.py +82 -148
  238. reflex/style.py +22 -21
  239. reflex/utils/exceptions.py +0 -20
  240. reflex/utils/format.py +34 -54
  241. reflex/utils/imports.py +73 -16
  242. reflex/utils/prerequisites.py +15 -35
  243. reflex/utils/pyi_generator.py +8 -13
  244. reflex/utils/serializers.py +22 -12
  245. reflex/utils/telemetry.py +2 -3
  246. reflex/utils/types.py +5 -10
  247. reflex/vars.py +501 -0
  248. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/METADATA +5 -4
  249. reflex-0.6.0a1.dist-info/RECORD +384 -0
  250. reflex-0.6.0.dist-info/RECORD +0 -382
  251. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/LICENSE +0 -0
  252. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/WHEEL +0 -0
  253. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/entry_points.txt +0 -0
reflex/vars.py ADDED
@@ -0,0 +1,501 @@
1
+ """Define a state var."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import contextlib
6
+ import dataclasses
7
+ import random
8
+ import re
9
+ import string
10
+ from typing import (
11
+ TYPE_CHECKING,
12
+ Any,
13
+ Dict,
14
+ Iterable,
15
+ Optional,
16
+ Tuple,
17
+ Type,
18
+ _GenericAlias, # type: ignore
19
+ )
20
+
21
+ from reflex import constants
22
+ from reflex.utils import imports
23
+ from reflex.utils.exceptions import (
24
+ VarTypeError,
25
+ )
26
+
27
+ # This module used to export ImportVar itself, so we still import it for export here
28
+ from reflex.utils.imports import (
29
+ ImmutableParsedImportDict,
30
+ ImportDict,
31
+ ImportVar,
32
+ ParsedImportDict,
33
+ parse_imports,
34
+ )
35
+
36
+ if TYPE_CHECKING:
37
+ from reflex.ivars import ImmutableVar
38
+ from reflex.state import BaseState
39
+
40
+
41
+ # Set of unique variable names.
42
+ USED_VARIABLES = set()
43
+
44
+
45
+ # These names were changed in reflex 0.3.0
46
+ REPLACED_NAMES = {
47
+ "full_name": "_var_full_name",
48
+ "name": "_var_name",
49
+ "state": "_var_data.state",
50
+ "type_": "_var_type",
51
+ "is_local": "_var_is_local",
52
+ "is_string": "_var_is_string",
53
+ "set_state": "_var_set_state",
54
+ "deps": "_deps",
55
+ }
56
+
57
+
58
+ def get_unique_variable_name() -> str:
59
+ """Get a unique variable name.
60
+
61
+ Returns:
62
+ The unique variable name.
63
+ """
64
+ name = "".join([random.choice(string.ascii_lowercase) for _ in range(8)])
65
+ if name not in USED_VARIABLES:
66
+ USED_VARIABLES.add(name)
67
+ return name
68
+ return get_unique_variable_name()
69
+
70
+
71
+ @dataclasses.dataclass(
72
+ eq=True,
73
+ frozen=True,
74
+ )
75
+ class VarData:
76
+ """Metadata associated with a Var."""
77
+
78
+ # The name of the enclosing state.
79
+ state: str = dataclasses.field(default="")
80
+
81
+ # Imports needed to render this var
82
+ imports: ImmutableParsedImportDict = dataclasses.field(default_factory=tuple)
83
+
84
+ # Hooks that need to be present in the component to render this var
85
+ hooks: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
86
+
87
+ def __init__(
88
+ self,
89
+ state: str = "",
90
+ imports: ImportDict | ParsedImportDict | None = None,
91
+ hooks: dict[str, None] | None = None,
92
+ ):
93
+ """Initialize the var data.
94
+
95
+ Args:
96
+ state: The name of the enclosing state.
97
+ imports: Imports needed to render this var.
98
+ hooks: Hooks that need to be present in the component to render this var.
99
+ """
100
+ immutable_imports: ImmutableParsedImportDict = tuple(
101
+ sorted(
102
+ ((k, tuple(sorted(v))) for k, v in parse_imports(imports or {}).items())
103
+ )
104
+ )
105
+ object.__setattr__(self, "state", state)
106
+ object.__setattr__(self, "imports", immutable_imports)
107
+ object.__setattr__(self, "hooks", tuple(hooks or {}))
108
+
109
+ def old_school_imports(self) -> ImportDict:
110
+ """Return the imports as a mutable dict.
111
+
112
+ Returns:
113
+ The imports as a mutable dict.
114
+ """
115
+ return dict((k, list(v)) for k, v in self.imports)
116
+
117
+ @classmethod
118
+ def merge(cls, *others: VarData | None) -> VarData | None:
119
+ """Merge multiple var data objects.
120
+
121
+ Args:
122
+ *others: The var data objects to merge.
123
+
124
+ Returns:
125
+ The merged var data object.
126
+ """
127
+ state = ""
128
+ _imports = {}
129
+ hooks = {}
130
+ for var_data in others:
131
+ if var_data is None:
132
+ continue
133
+ state = state or var_data.state
134
+ _imports = imports.merge_imports(_imports, var_data.imports)
135
+ hooks.update(
136
+ var_data.hooks
137
+ if isinstance(var_data.hooks, dict)
138
+ else {k: None for k in var_data.hooks}
139
+ )
140
+
141
+ if state or _imports or hooks:
142
+ return VarData(
143
+ state=state,
144
+ imports=_imports,
145
+ hooks=hooks,
146
+ )
147
+ return None
148
+
149
+ def __bool__(self) -> bool:
150
+ """Check if the var data is non-empty.
151
+
152
+ Returns:
153
+ True if any field is set to a non-default value.
154
+ """
155
+ return bool(self.state or self.imports or self.hooks)
156
+
157
+ def __eq__(self, other: Any) -> bool:
158
+ """Check if two var data objects are equal.
159
+
160
+ Args:
161
+ other: The other var data object to compare.
162
+
163
+ Returns:
164
+ True if all fields are equal and collapsed imports are equal.
165
+ """
166
+ if not isinstance(other, VarData):
167
+ return False
168
+
169
+ # Don't compare interpolations - that's added in by the decoder, and
170
+ # not part of the vardata itself.
171
+ return (
172
+ self.state == other.state
173
+ and self.hooks
174
+ == (
175
+ other.hooks if isinstance(other, VarData) else tuple(other.hooks.keys())
176
+ )
177
+ and imports.collapse_imports(self.imports)
178
+ == imports.collapse_imports(other.imports)
179
+ )
180
+
181
+ @classmethod
182
+ def from_state(cls, state: Type[BaseState] | str) -> VarData:
183
+ """Set the state of the var.
184
+
185
+ Args:
186
+ state: The state to set or the full name of the state.
187
+
188
+ Returns:
189
+ The var with the set state.
190
+ """
191
+ from reflex.utils import format
192
+
193
+ state_name = state if isinstance(state, str) else state.get_full_name()
194
+ new_var_data = VarData(
195
+ state=state_name,
196
+ hooks={
197
+ "const {0} = useContext(StateContexts.{0})".format(
198
+ format.format_state_name(state_name)
199
+ ): None
200
+ },
201
+ imports={
202
+ f"/{constants.Dirs.CONTEXTS_PATH}": [ImportVar(tag="StateContexts")],
203
+ "react": [ImportVar(tag="useContext")],
204
+ },
205
+ )
206
+ return new_var_data
207
+
208
+
209
+ def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
210
+ """Decode the state name from a formatted var.
211
+
212
+ Args:
213
+ value: The value to extract the state name from.
214
+
215
+ Returns:
216
+ The extracted state name and the value without the state name.
217
+ """
218
+ var_datas = []
219
+ if isinstance(value, str):
220
+ # fast path if there is no encoded VarData
221
+ if constants.REFLEX_VAR_OPENING_TAG not in value:
222
+ return None, value
223
+
224
+ offset = 0
225
+
226
+ # Find all tags.
227
+ while m := _decode_var_pattern.search(value):
228
+ start, end = m.span()
229
+ value = value[:start] + value[end:]
230
+
231
+ serialized_data = m.group(1)
232
+
233
+ if serialized_data.isnumeric() or (
234
+ serialized_data[0] == "-" and serialized_data[1:].isnumeric()
235
+ ):
236
+ # This is a global immutable var.
237
+ var = _global_vars[int(serialized_data)]
238
+ var_data = var._get_all_var_data()
239
+
240
+ if var_data is not None:
241
+ var_datas.append(var_data)
242
+ offset += end - start
243
+
244
+ return VarData.merge(*var_datas) if var_datas else None, value
245
+
246
+
247
+ # Compile regex for finding reflex var tags.
248
+ _decode_var_pattern_re = (
249
+ rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
250
+ )
251
+ _decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
252
+
253
+ # Defined global immutable vars.
254
+ _global_vars: Dict[int, ImmutableVar] = {}
255
+
256
+
257
+ def _extract_var_data(value: Iterable) -> list[VarData | None]:
258
+ """Extract the var imports and hooks from an iterable containing a Var.
259
+
260
+ Args:
261
+ value: The iterable to extract the VarData from
262
+
263
+ Returns:
264
+ The extracted VarDatas.
265
+ """
266
+ from reflex.ivars import ImmutableVar
267
+ from reflex.style import Style
268
+
269
+ var_datas = []
270
+ with contextlib.suppress(TypeError):
271
+ for sub in value:
272
+ if isinstance(sub, ImmutableVar):
273
+ var_datas.append(sub._var_data)
274
+ elif not isinstance(sub, str):
275
+ # Recurse into dict values.
276
+ if hasattr(sub, "values") and callable(sub.values):
277
+ var_datas.extend(_extract_var_data(sub.values()))
278
+ # Recurse into iterable values (or dict keys).
279
+ var_datas.extend(_extract_var_data(sub))
280
+
281
+ # Style objects should already have _var_data.
282
+ if isinstance(value, Style):
283
+ var_datas.append(value._var_data)
284
+ else:
285
+ # Recurse when value is a dict itself.
286
+ values = getattr(value, "values", None)
287
+ if callable(values):
288
+ var_datas.extend(_extract_var_data(values()))
289
+ return var_datas
290
+
291
+
292
+ class Var:
293
+ """An abstract var."""
294
+
295
+ @classmethod
296
+ def create(
297
+ cls,
298
+ value: Any,
299
+ _var_is_local: bool = True,
300
+ _var_is_string: bool | None = None,
301
+ _var_data: Optional[VarData] = None,
302
+ ) -> ImmutableVar | None:
303
+ """Create a var from a value.
304
+
305
+ Args:
306
+ value: The value to create the var from.
307
+ _var_is_local: Whether the var is local.
308
+ _var_is_string: Whether the var is a string literal.
309
+ _var_data: Additional hooks and imports associated with the Var.
310
+
311
+ Returns:
312
+ The var.
313
+ """
314
+ from reflex.ivars import ImmutableVar, LiteralVar
315
+
316
+ # Check for none values.
317
+ if value is None:
318
+ return None
319
+
320
+ # If the value is already a var, do nothing.
321
+ if isinstance(value, ImmutableVar):
322
+ return value
323
+
324
+ # If the value is not a string, create a LiteralVar.
325
+ if not isinstance(value, str):
326
+ return LiteralVar.create(
327
+ value,
328
+ _var_data=_var_data,
329
+ )
330
+
331
+ # if _var_is_string is provided, use that
332
+ if _var_is_string is False:
333
+ return ImmutableVar.create(
334
+ value,
335
+ _var_data=_var_data,
336
+ )
337
+ if _var_is_string is True:
338
+ return LiteralVar.create(
339
+ value,
340
+ _var_data=_var_data,
341
+ )
342
+
343
+ # Otherwise, rely on _var_is_local
344
+ if _var_is_local is True:
345
+ return LiteralVar.create(
346
+ value,
347
+ _var_data=_var_data,
348
+ )
349
+
350
+ return ImmutableVar.create(
351
+ value,
352
+ _var_data=_var_data,
353
+ )
354
+
355
+ @classmethod
356
+ def create_safe(
357
+ cls,
358
+ value: Any,
359
+ _var_is_local: bool = True,
360
+ _var_is_string: bool | None = None,
361
+ _var_data: Optional[VarData] = None,
362
+ ) -> ImmutableVar:
363
+ """Create a var from a value, asserting that it is not None.
364
+
365
+ Args:
366
+ value: The value to create the var from.
367
+ _var_is_local: Whether the var is local.
368
+ _var_is_string: Whether the var is a string literal.
369
+ _var_data: Additional hooks and imports associated with the Var.
370
+
371
+ Returns:
372
+ The var.
373
+ """
374
+ var = cls.create(
375
+ value,
376
+ _var_is_local=_var_is_local,
377
+ _var_is_string=_var_is_string,
378
+ _var_data=_var_data,
379
+ )
380
+ assert var is not None
381
+ return var
382
+
383
+ @classmethod
384
+ def __class_getitem__(cls, type_: str) -> _GenericAlias:
385
+ """Get a typed var.
386
+
387
+ Args:
388
+ type_: The type of the var.
389
+
390
+ Returns:
391
+ The var class item.
392
+ """
393
+ return _GenericAlias(cls, type_)
394
+
395
+ def __bool__(self) -> bool:
396
+ """Raise exception if using Var in a boolean context.
397
+
398
+ Raises:
399
+ VarTypeError: when attempting to bool-ify the Var.
400
+ """
401
+ raise VarTypeError(
402
+ f"Cannot convert Var {str(self)!r} to bool for use with `if`, `and`, `or`, and `not`. "
403
+ "Instead use `rx.cond` and bitwise operators `&` (and), `|` (or), `~` (invert)."
404
+ )
405
+
406
+ def __iter__(self) -> Any:
407
+ """Raise exception if using Var in an iterable context.
408
+
409
+ Raises:
410
+ VarTypeError: when attempting to iterate over the Var.
411
+ """
412
+ raise VarTypeError(
413
+ f"Cannot iterate over Var {str(self)!r}. Instead use `rx.foreach`."
414
+ )
415
+
416
+ def __contains__(self, _: Any) -> ImmutableVar:
417
+ """Override the 'in' operator to alert the user that it is not supported.
418
+
419
+ Raises:
420
+ VarTypeError: the operation is not supported
421
+ """
422
+ raise VarTypeError(
423
+ "'in' operator not supported for Var types, use Var.contains() instead."
424
+ )
425
+
426
+ def __get__(self, instance: Any, owner: Any) -> ImmutableVar:
427
+ """Return the value of the Var.
428
+
429
+ Args:
430
+ instance: The instance of the Var.
431
+ owner: The owner of the Var.
432
+
433
+ Returns:
434
+ The value of the Var.
435
+ """
436
+ return self # type: ignore
437
+
438
+ @classmethod
439
+ def range(
440
+ cls,
441
+ v1: ImmutableVar | int = 0,
442
+ v2: ImmutableVar | int | None = None,
443
+ step: ImmutableVar | int | None = None,
444
+ ) -> ImmutableVar:
445
+ """Return an iterator over indices from v1 to v2 (or 0 to v1).
446
+
447
+ Args:
448
+ v1: The start of the range or end of range if v2 is not given.
449
+ v2: The end of the range.
450
+ step: The number of numbers between each item.
451
+
452
+ Returns:
453
+ A var representing range operation.
454
+ """
455
+ from reflex.ivars import ArrayVar
456
+
457
+ return ArrayVar.range(v1, v2, step) # type: ignore
458
+
459
+ def upcast(self) -> ImmutableVar:
460
+ """Upcast a Var to an ImmutableVar.
461
+
462
+ Returns:
463
+ The upcasted Var.
464
+ """
465
+ return self # type: ignore
466
+
467
+ def json(self) -> str:
468
+ """Serialize the var to a JSON string.
469
+
470
+ Raises:
471
+ NotImplementedError: If the method is not implemented.
472
+ """
473
+ raise NotImplementedError("Var subclasses must implement the json method.")
474
+
475
+
476
+ def get_uuid_string_var() -> ImmutableVar:
477
+ """Return a Var that generates a single memoized UUID via .web/utils/state.js.
478
+
479
+ useMemo with an empty dependency array ensures that the generated UUID is
480
+ consistent across re-renders of the component.
481
+
482
+ Returns:
483
+ A Var that generates a UUID at runtime.
484
+ """
485
+ from reflex.ivars import ImmutableVar
486
+ from reflex.utils.imports import ImportVar
487
+
488
+ unique_uuid_var = get_unique_variable_name()
489
+ unique_uuid_var_data = VarData(
490
+ imports={
491
+ f"/{constants.Dirs.STATE_PATH}": {ImportVar(tag="generateUUID")}, # type: ignore
492
+ "react": "useMemo",
493
+ },
494
+ hooks={f"const {unique_uuid_var} = useMemo(generateUUID, [])": None},
495
+ )
496
+
497
+ return ImmutableVar(
498
+ _var_name=unique_uuid_var,
499
+ _var_type=str,
500
+ _var_data=unique_uuid_var_data,
501
+ )
@@ -1,16 +1,17 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reflex
3
- Version: 0.6.0
3
+ Version: 0.6.0a1
4
4
  Summary: Web apps in pure Python.
5
5
  Home-page: https://reflex.dev
6
6
  License: Apache-2.0
7
7
  Keywords: web,framework
8
8
  Author: Nikhil Rao
9
9
  Author-email: nikhil@reflex.dev
10
- Requires-Python: >=3.9,<4.0
10
+ Requires-Python: >=3.8,<4.0
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
14
15
  Classifier: Programming Language :: Python :: 3.9
15
16
  Classifier: Programming Language :: Python :: 3.10
16
17
  Classifier: Programming Language :: Python :: 3.11
@@ -33,7 +34,7 @@ Requires-Dist: python-engineio (!=4.6.0)
33
34
  Requires-Dist: python-multipart (>=0.0.5,<0.1)
34
35
  Requires-Dist: python-socketio (>=5.7.0,<6.0)
35
36
  Requires-Dist: redis (>=4.3.5,<6.0)
36
- Requires-Dist: reflex-chakra (>=0.6.0a6)
37
+ Requires-Dist: reflex-chakra (>=0.6.0a)
37
38
  Requires-Dist: reflex-hosting-cli (>=0.1.2,<2.0)
38
39
  Requires-Dist: rich (>=13.0.0,<14.0)
39
40
  Requires-Dist: setuptools (>=69.1.1,<70.2)
@@ -87,7 +88,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
87
88
 
88
89
  ## ⚙️ Installation
89
90
 
90
- Open a terminal and run (Requires Python 3.9+):
91
+ Open a terminal and run (Requires Python 3.8+):
91
92
 
92
93
  ```bash
93
94
  pip install reflex