reflex 0.7.13a1__py3-none-any.whl → 0.7.14__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 (263) hide show
  1. reflex/.templates/apps/blank/code/blank.py +0 -2
  2. reflex/app.py +100 -92
  3. reflex/app_mixins/lifespan.py +2 -3
  4. reflex/app_mixins/middleware.py +1 -0
  5. reflex/app_mixins/mixin.py +0 -1
  6. reflex/assets.py +7 -4
  7. reflex/base.py +3 -2
  8. reflex/compiler/compiler.py +79 -65
  9. reflex/compiler/utils.py +8 -6
  10. reflex/components/base/app_wrap.pyi +0 -1
  11. reflex/components/base/bare.py +22 -12
  12. reflex/components/base/body.pyi +0 -1
  13. reflex/components/base/document.pyi +0 -5
  14. reflex/components/base/error_boundary.pyi +0 -1
  15. reflex/components/base/fragment.pyi +0 -1
  16. reflex/components/base/head.pyi +0 -2
  17. reflex/components/base/link.pyi +0 -2
  18. reflex/components/base/meta.py +2 -1
  19. reflex/components/base/meta.pyi +0 -4
  20. reflex/components/base/script.py +2 -1
  21. reflex/components/base/script.pyi +0 -1
  22. reflex/components/base/strict_mode.pyi +0 -1
  23. reflex/components/component.py +85 -45
  24. reflex/components/core/auto_scroll.pyi +0 -1
  25. reflex/components/core/banner.py +1 -1
  26. reflex/components/core/banner.pyi +0 -6
  27. reflex/components/core/breakpoints.py +9 -11
  28. reflex/components/core/client_side_routing.pyi +0 -2
  29. reflex/components/core/clipboard.pyi +0 -1
  30. reflex/components/core/colors.py +10 -7
  31. reflex/components/core/cond.py +4 -2
  32. reflex/components/core/debounce.py +5 -3
  33. reflex/components/core/debounce.pyi +0 -1
  34. reflex/components/core/foreach.py +8 -6
  35. reflex/components/core/html.py +3 -3
  36. reflex/components/core/html.pyi +0 -1
  37. reflex/components/core/match.py +19 -17
  38. reflex/components/core/sticky.pyi +0 -4
  39. reflex/components/core/upload.py +1 -1
  40. reflex/components/core/upload.pyi +0 -5
  41. reflex/components/datadisplay/code.py +1 -2
  42. reflex/components/datadisplay/code.pyi +0 -2
  43. reflex/components/datadisplay/dataeditor.py +7 -10
  44. reflex/components/datadisplay/dataeditor.pyi +0 -1
  45. reflex/components/datadisplay/logo.py +3 -4
  46. reflex/components/datadisplay/shiki_code_block.py +8 -11
  47. reflex/components/datadisplay/shiki_code_block.pyi +0 -3
  48. reflex/components/dynamic.py +2 -3
  49. reflex/components/el/__init__.pyi +2 -0
  50. reflex/components/el/element.pyi +0 -1
  51. reflex/components/el/elements/__init__.py +1 -0
  52. reflex/components/el/elements/__init__.pyi +3 -0
  53. reflex/components/el/elements/base.pyi +0 -1
  54. reflex/components/el/elements/forms.py +14 -15
  55. reflex/components/el/elements/forms.pyi +15 -32
  56. reflex/components/el/elements/inline.pyi +0 -28
  57. reflex/components/el/elements/media.py +26 -0
  58. reflex/components/el/elements/media.pyi +259 -25
  59. reflex/components/el/elements/metadata.py +0 -1
  60. reflex/components/el/elements/metadata.pyi +0 -6
  61. reflex/components/el/elements/other.pyi +0 -7
  62. reflex/components/el/elements/scripts.pyi +0 -3
  63. reflex/components/el/elements/sectioning.pyi +0 -15
  64. reflex/components/el/elements/tables.pyi +0 -10
  65. reflex/components/el/elements/typography.pyi +0 -15
  66. reflex/components/gridjs/datatable.py +10 -13
  67. reflex/components/gridjs/datatable.pyi +0 -2
  68. reflex/components/lucide/icon.py +10 -9
  69. reflex/components/lucide/icon.pyi +0 -3
  70. reflex/components/markdown/markdown.py +6 -8
  71. reflex/components/markdown/markdown.pyi +0 -1
  72. reflex/components/moment/moment.pyi +0 -1
  73. reflex/components/next/base.py +0 -2
  74. reflex/components/next/base.pyi +0 -3
  75. reflex/components/next/image.pyi +0 -1
  76. reflex/components/next/link.pyi +0 -1
  77. reflex/components/next/video.pyi +0 -1
  78. reflex/components/plotly/plotly.pyi +0 -9
  79. reflex/components/props.py +4 -3
  80. reflex/components/radix/primitives/accordion.py +1 -1
  81. reflex/components/radix/primitives/accordion.pyi +0 -7
  82. reflex/components/radix/primitives/base.py +1 -3
  83. reflex/components/radix/primitives/base.pyi +0 -2
  84. reflex/components/radix/primitives/drawer.py +1 -1
  85. reflex/components/radix/primitives/drawer.pyi +0 -11
  86. reflex/components/radix/primitives/form.py +5 -9
  87. reflex/components/radix/primitives/form.pyi +0 -12
  88. reflex/components/radix/primitives/progress.py +1 -1
  89. reflex/components/radix/primitives/progress.pyi +0 -5
  90. reflex/components/radix/primitives/slider.py +1 -1
  91. reflex/components/radix/primitives/slider.pyi +0 -5
  92. reflex/components/radix/themes/base.pyi +0 -8
  93. reflex/components/radix/themes/color_mode.pyi +0 -3
  94. reflex/components/radix/themes/components/alert_dialog.py +4 -2
  95. reflex/components/radix/themes/components/alert_dialog.pyi +4 -9
  96. reflex/components/radix/themes/components/aspect_ratio.py +1 -2
  97. reflex/components/radix/themes/components/aspect_ratio.pyi +1 -3
  98. reflex/components/radix/themes/components/avatar.py +5 -2
  99. reflex/components/radix/themes/components/avatar.pyi +1 -3
  100. reflex/components/radix/themes/components/badge.py +5 -2
  101. reflex/components/radix/themes/components/badge.pyi +1 -3
  102. reflex/components/radix/themes/components/button.py +2 -3
  103. reflex/components/radix/themes/components/button.pyi +1 -3
  104. reflex/components/radix/themes/components/callout.py +1 -2
  105. reflex/components/radix/themes/components/callout.pyi +1 -7
  106. reflex/components/radix/themes/components/card.py +1 -2
  107. reflex/components/radix/themes/components/card.pyi +1 -3
  108. reflex/components/radix/themes/components/checkbox.py +7 -4
  109. reflex/components/radix/themes/components/checkbox.pyi +1 -5
  110. reflex/components/radix/themes/components/checkbox_cards.py +1 -2
  111. reflex/components/radix/themes/components/checkbox_cards.pyi +1 -4
  112. reflex/components/radix/themes/components/checkbox_group.py +1 -2
  113. reflex/components/radix/themes/components/checkbox_group.pyi +1 -4
  114. reflex/components/radix/themes/components/context_menu.py +1 -1
  115. reflex/components/radix/themes/components/context_menu.pyi +1 -14
  116. reflex/components/radix/themes/components/data_list.py +1 -2
  117. reflex/components/radix/themes/components/data_list.pyi +1 -6
  118. reflex/components/radix/themes/components/dialog.py +4 -2
  119. reflex/components/radix/themes/components/dialog.pyi +4 -9
  120. reflex/components/radix/themes/components/dropdown_menu.py +5 -2
  121. reflex/components/radix/themes/components/dropdown_menu.pyi +4 -10
  122. reflex/components/radix/themes/components/hover_card.py +4 -2
  123. reflex/components/radix/themes/components/hover_card.pyi +4 -6
  124. reflex/components/radix/themes/components/icon_button.py +7 -8
  125. reflex/components/radix/themes/components/icon_button.pyi +1 -3
  126. reflex/components/radix/themes/components/inset.py +1 -2
  127. reflex/components/radix/themes/components/inset.pyi +1 -3
  128. reflex/components/radix/themes/components/popover.py +4 -2
  129. reflex/components/radix/themes/components/popover.pyi +4 -6
  130. reflex/components/radix/themes/components/progress.py +1 -2
  131. reflex/components/radix/themes/components/progress.pyi +1 -3
  132. reflex/components/radix/themes/components/radio.py +1 -2
  133. reflex/components/radix/themes/components/radio.pyi +1 -3
  134. reflex/components/radix/themes/components/radio_cards.py +1 -2
  135. reflex/components/radix/themes/components/radio_cards.pyi +1 -4
  136. reflex/components/radix/themes/components/radio_group.py +7 -5
  137. reflex/components/radix/themes/components/radio_group.pyi +1 -6
  138. reflex/components/radix/themes/components/scroll_area.py +1 -2
  139. reflex/components/radix/themes/components/scroll_area.pyi +1 -3
  140. reflex/components/radix/themes/components/segmented_control.py +1 -2
  141. reflex/components/radix/themes/components/segmented_control.pyi +1 -4
  142. reflex/components/radix/themes/components/select.py +5 -2
  143. reflex/components/radix/themes/components/select.pyi +1 -11
  144. reflex/components/radix/themes/components/separator.py +1 -2
  145. reflex/components/radix/themes/components/separator.pyi +1 -3
  146. reflex/components/radix/themes/components/skeleton.py +1 -2
  147. reflex/components/radix/themes/components/skeleton.pyi +1 -3
  148. reflex/components/radix/themes/components/slider.py +1 -2
  149. reflex/components/radix/themes/components/slider.pyi +1 -3
  150. reflex/components/radix/themes/components/spinner.py +1 -2
  151. reflex/components/radix/themes/components/spinner.pyi +1 -3
  152. reflex/components/radix/themes/components/switch.py +1 -2
  153. reflex/components/radix/themes/components/switch.pyi +1 -3
  154. reflex/components/radix/themes/components/table.py +1 -2
  155. reflex/components/radix/themes/components/table.pyi +1 -9
  156. reflex/components/radix/themes/components/tabs.py +1 -2
  157. reflex/components/radix/themes/components/tabs.pyi +1 -7
  158. reflex/components/radix/themes/components/text_area.py +5 -2
  159. reflex/components/radix/themes/components/text_area.pyi +2 -4
  160. reflex/components/radix/themes/components/text_field.py +5 -2
  161. reflex/components/radix/themes/components/text_field.pyi +1 -5
  162. reflex/components/radix/themes/components/tooltip.py +1 -2
  163. reflex/components/radix/themes/components/tooltip.pyi +1 -3
  164. reflex/components/radix/themes/layout/base.py +5 -2
  165. reflex/components/radix/themes/layout/base.pyi +5 -3
  166. reflex/components/radix/themes/layout/box.py +1 -2
  167. reflex/components/radix/themes/layout/box.pyi +1 -3
  168. reflex/components/radix/themes/layout/center.pyi +0 -1
  169. reflex/components/radix/themes/layout/container.py +1 -2
  170. reflex/components/radix/themes/layout/container.pyi +1 -3
  171. reflex/components/radix/themes/layout/flex.py +6 -2
  172. reflex/components/radix/themes/layout/flex.pyi +1 -3
  173. reflex/components/radix/themes/layout/grid.py +6 -2
  174. reflex/components/radix/themes/layout/grid.pyi +1 -3
  175. reflex/components/radix/themes/layout/list.py +2 -1
  176. reflex/components/radix/themes/layout/list.pyi +0 -5
  177. reflex/components/radix/themes/layout/section.py +1 -2
  178. reflex/components/radix/themes/layout/section.pyi +1 -3
  179. reflex/components/radix/themes/layout/spacer.pyi +0 -1
  180. reflex/components/radix/themes/layout/stack.py +1 -1
  181. reflex/components/radix/themes/layout/stack.pyi +0 -3
  182. reflex/components/radix/themes/typography/blockquote.py +1 -1
  183. reflex/components/radix/themes/typography/blockquote.pyi +1 -3
  184. reflex/components/radix/themes/typography/code.py +5 -1
  185. reflex/components/radix/themes/typography/code.pyi +1 -3
  186. reflex/components/radix/themes/typography/heading.py +1 -1
  187. reflex/components/radix/themes/typography/heading.pyi +1 -3
  188. reflex/components/radix/themes/typography/link.py +3 -2
  189. reflex/components/radix/themes/typography/link.pyi +1 -3
  190. reflex/components/radix/themes/typography/text.py +1 -1
  191. reflex/components/radix/themes/typography/text.pyi +1 -9
  192. reflex/components/react_player/audio.py +0 -2
  193. reflex/components/react_player/audio.pyi +0 -3
  194. reflex/components/react_player/react_player.pyi +0 -1
  195. reflex/components/react_player/video.py +0 -2
  196. reflex/components/react_player/video.pyi +0 -3
  197. reflex/components/recharts/__init__.py +1 -1
  198. reflex/components/recharts/__init__.pyi +1 -1
  199. reflex/components/recharts/cartesian.py +20 -25
  200. reflex/components/recharts/cartesian.pyi +20 -37
  201. reflex/components/recharts/charts.py +2 -1
  202. reflex/components/recharts/charts.pyi +0 -12
  203. reflex/components/recharts/general.pyi +0 -6
  204. reflex/components/recharts/polar.py +5 -4
  205. reflex/components/recharts/polar.pyi +4 -10
  206. reflex/components/recharts/recharts.py +12 -10
  207. reflex/components/recharts/recharts.pyi +10 -11
  208. reflex/components/sonner/toast.py +2 -2
  209. reflex/components/sonner/toast.pyi +0 -2
  210. reflex/components/suneditor/editor.py +2 -1
  211. reflex/components/suneditor/editor.pyi +0 -1
  212. reflex/components/tags/iter_tag.py +4 -2
  213. reflex/config.py +41 -615
  214. reflex/constants/base.py +6 -6
  215. reflex/constants/compiler.py +8 -6
  216. reflex/constants/installer.py +25 -16
  217. reflex/custom_components/custom_components.py +1 -2
  218. reflex/environment.py +606 -0
  219. reflex/event.py +58 -60
  220. reflex/experimental/__init__.py +2 -2
  221. reflex/experimental/client_state.py +9 -4
  222. reflex/experimental/layout.pyi +0 -5
  223. reflex/istate/manager.py +17 -20
  224. reflex/istate/proxy.py +19 -12
  225. reflex/model.py +8 -5
  226. reflex/plugins/base.py +8 -0
  227. reflex/plugins/tailwind_v3.py +8 -0
  228. reflex/plugins/tailwind_v4.py +9 -0
  229. reflex/reflex.py +11 -12
  230. reflex/route.py +7 -9
  231. reflex/state.py +67 -71
  232. reflex/style.py +3 -1
  233. reflex/testing.py +49 -30
  234. reflex/utils/build.py +2 -1
  235. reflex/utils/console.py +70 -17
  236. reflex/utils/exec.py +113 -39
  237. reflex/utils/export.py +2 -1
  238. reflex/utils/format.py +21 -24
  239. reflex/utils/imports.py +4 -3
  240. reflex/utils/lazy_loader.py +3 -3
  241. reflex/utils/misc.py +2 -1
  242. reflex/utils/net.py +2 -2
  243. reflex/utils/path_ops.py +4 -2
  244. reflex/utils/prerequisites.py +69 -39
  245. reflex/utils/processes.py +5 -7
  246. reflex/utils/pyi_generator.py +46 -41
  247. reflex/utils/redir.py +1 -1
  248. reflex/utils/registry.py +1 -1
  249. reflex/utils/serializers.py +4 -4
  250. reflex/utils/telemetry.py +36 -3
  251. reflex/utils/types.py +16 -13
  252. reflex/vars/base.py +96 -109
  253. reflex/vars/datetime.py +2 -1
  254. reflex/vars/dep_tracking.py +19 -28
  255. reflex/vars/number.py +6 -7
  256. reflex/vars/object.py +5 -6
  257. reflex/vars/sequence.py +11 -11
  258. {reflex-0.7.13a1.dist-info → reflex-0.7.14.dist-info}/METADATA +1 -1
  259. reflex-0.7.14.dist-info/RECORD +408 -0
  260. reflex-0.7.13a1.dist-info/RECORD +0 -407
  261. {reflex-0.7.13a1.dist-info → reflex-0.7.14.dist-info}/WHEEL +0 -0
  262. {reflex-0.7.13a1.dist-info → reflex-0.7.14.dist-info}/entry_points.txt +0 -0
  263. {reflex-0.7.13a1.dist-info → reflex-0.7.14.dist-info}/licenses/LICENSE +0 -0
@@ -30,6 +30,8 @@ logger = logging.getLogger("pyi_generator")
30
30
 
31
31
  PWD = Path.cwd()
32
32
 
33
+ PYI_HASHES = "pyi_hashes.json"
34
+
33
35
  EXCLUDED_FILES = [
34
36
  "app.py",
35
37
  "component.py",
@@ -157,9 +159,8 @@ def _get_type_hint(
157
159
  res_args.sort()
158
160
  if len(res_args) == 1:
159
161
  return f"{res_args[0]} | None"
160
- else:
161
- res = f"{' | '.join(res_args)}"
162
- return f"{res} | None"
162
+ res = f"{' | '.join(res_args)}"
163
+ return f"{res} | None"
163
164
 
164
165
  res_args = [
165
166
  _get_type_hint(arg, type_hint_globals, rx_types.is_optional(arg))
@@ -183,10 +184,11 @@ def _get_type_hint(
183
184
  value.__module__ not in ["builtins", "__builtins__"]
184
185
  and value.__name__ not in type_hint_globals
185
186
  ):
186
- raise TypeError(
187
+ msg = (
187
188
  f"{value.__module__ + '.' + value.__name__} is not a default import, "
188
189
  "add it to DEFAULT_IMPORTS in pyi_generator.py"
189
190
  )
191
+ raise TypeError(msg)
190
192
 
191
193
  res = f"{value.__name__}[{', '.join(inner_container_type_args)}]"
192
194
 
@@ -445,7 +447,7 @@ def type_to_ast(typ: Any, cls: type) -> ast.expr:
445
447
 
446
448
  return ast.Name(id=typ.__module__ + "." + typ.__name__)
447
449
  return ast.Name(id=typ.__name__)
448
- elif hasattr(typ, "_name"):
450
+ if hasattr(typ, "_name"):
449
451
  return ast.Name(id=typ._name)
450
452
  return ast.Name(id=str(typ))
451
453
 
@@ -510,7 +512,8 @@ def _generate_component_create_functiondef(
510
512
  TypeError: If clz is not a subclass of Component.
511
513
  """
512
514
  if not issubclass(clz, Component):
513
- raise TypeError(f"clz must be a subclass of Component, not {clz!r}")
515
+ msg = f"clz must be a subclass of Component, not {clz!r}"
516
+ raise TypeError(msg)
514
517
 
515
518
  # add the imports needed by get_type_hint later
516
519
  type_hint_globals.update(
@@ -654,7 +657,7 @@ def _generate_component_create_functiondef(
654
657
  defaults=[],
655
658
  )
656
659
 
657
- definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
660
+ return ast.FunctionDef( # pyright: ignore [reportCallIssue]
658
661
  name="create",
659
662
  args=create_args,
660
663
  body=[
@@ -676,7 +679,6 @@ def _generate_component_create_functiondef(
676
679
  lineno=lineno,
677
680
  returns=ast.Constant(value=clz.__name__),
678
681
  )
679
- return definition
680
682
 
681
683
 
682
684
  def _generate_staticmethod_call_functiondef(
@@ -710,7 +712,7 @@ def _generate_staticmethod_call_functiondef(
710
712
  else []
711
713
  ),
712
714
  )
713
- definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
715
+ return ast.FunctionDef( # pyright: ignore [reportCallIssue]
714
716
  name="__call__",
715
717
  args=call_args,
716
718
  body=[
@@ -729,7 +731,6 @@ def _generate_staticmethod_call_functiondef(
729
731
  )
730
732
  ),
731
733
  )
732
- return definition
733
734
 
734
735
 
735
736
  def _generate_namespace_call_functiondef(
@@ -841,6 +842,7 @@ class StubGenerator(ast.NodeTransformer):
841
842
  and issubclass((clz := self.classes[self.current_class]), Component)
842
843
  ):
843
844
  return clz
845
+ return None
844
846
 
845
847
  def visit_Module(self, node: ast.Module) -> ast.Module:
846
848
  """Visit a Module node and remove docstring from body.
@@ -1021,7 +1023,7 @@ class StubGenerator(ast.NodeTransformer):
1021
1023
  if isinstance(target, ast.Tuple):
1022
1024
  for name in target.elts:
1023
1025
  if isinstance(name, ast.Name) and name.id.startswith("_"):
1024
- return
1026
+ return None
1025
1027
 
1026
1028
  return node
1027
1029
 
@@ -1107,7 +1109,7 @@ class PyiGenerator:
1107
1109
  pyright_ignore_imports = getattr(mod, "_PYRIGHT_IGNORE_IMPORTS", [])
1108
1110
 
1109
1111
  if not sub_mods and not sub_mod_attrs:
1110
- return
1112
+ return None
1111
1113
  sub_mods_imports = []
1112
1114
  sub_mod_attrs_imports = []
1113
1115
 
@@ -1162,7 +1164,7 @@ class PyiGenerator:
1162
1164
  }
1163
1165
  is_init_file = _relative_to_pwd(module_path).name == "__init__.py"
1164
1166
  if not class_names and not is_init_file:
1165
- return
1167
+ return None
1166
1168
 
1167
1169
  if is_init_file:
1168
1170
  new_tree = InitStubGenerator(module, class_names).visit(
@@ -1170,7 +1172,7 @@ class PyiGenerator:
1170
1172
  )
1171
1173
  init_imports = self._get_init_lazy_imports(module, new_tree)
1172
1174
  if not init_imports:
1173
- return
1175
+ return None
1174
1176
  content_hash = self._write_pyi_file(module_path, init_imports)
1175
1177
  else:
1176
1178
  new_tree = StubGenerator(module, class_names).visit(
@@ -1264,45 +1266,48 @@ class PyiGenerator:
1264
1266
  file_parent = file_path.parent
1265
1267
  while len(file_parent.parts) > len(top_dir.parts):
1266
1268
  file_parent = file_parent.parent
1269
+ while len(top_dir.parts) > len(file_parent.parts):
1270
+ top_dir = top_dir.parent
1267
1271
  while not file_parent.samefile(top_dir):
1268
1272
  file_parent = file_parent.parent
1269
1273
  top_dir = top_dir.parent
1270
1274
 
1271
- pyi_hashes_file = top_dir / "pyi_hashes.json"
1272
- if not pyi_hashes_file.exists():
1273
- while top_dir.parent and not (top_dir / "pyi_hashes.json").exists():
1274
- top_dir = top_dir.parent
1275
- another_pyi_hashes_file = top_dir / "pyi_hashes.json"
1276
- if another_pyi_hashes_file.exists():
1277
- pyi_hashes_file = another_pyi_hashes_file
1278
-
1279
- pyi_hashes_file.write_text(
1280
- json.dumps(
1281
- dict(
1282
- zip(
1283
- [
1284
- f.relative_to(pyi_hashes_file.parent).as_posix()
1285
- for f in file_paths
1286
- ],
1287
- hashes,
1288
- strict=True,
1289
- )
1290
- ),
1291
- indent=2,
1292
- sort_keys=True,
1275
+ while (
1276
+ not top_dir.samefile(top_dir.parent)
1277
+ and not (top_dir / PYI_HASHES).exists()
1278
+ ):
1279
+ top_dir = top_dir.parent
1280
+
1281
+ pyi_hashes_file = top_dir / PYI_HASHES
1282
+
1283
+ if pyi_hashes_file.exists():
1284
+ pyi_hashes_file.write_text(
1285
+ json.dumps(
1286
+ dict(
1287
+ zip(
1288
+ [
1289
+ f.relative_to(pyi_hashes_file.parent).as_posix()
1290
+ for f in file_paths
1291
+ ],
1292
+ hashes,
1293
+ strict=True,
1294
+ )
1295
+ ),
1296
+ indent=2,
1297
+ sort_keys=True,
1298
+ )
1299
+ + "\n",
1293
1300
  )
1294
- + "\n",
1295
- )
1296
1301
  elif file_paths:
1297
1302
  file_paths = list(map(Path, file_paths))
1298
1303
  pyi_hashes_parent = file_paths[0].parent
1299
1304
  while (
1300
- pyi_hashes_parent.parent
1301
- and not (pyi_hashes_parent / "pyi_hashes.json").exists()
1305
+ not pyi_hashes_parent.samefile(pyi_hashes_parent.parent)
1306
+ and not (pyi_hashes_parent / PYI_HASHES).exists()
1302
1307
  ):
1303
1308
  pyi_hashes_parent = pyi_hashes_parent.parent
1304
1309
 
1305
- pyi_hashes_file = pyi_hashes_parent / "pyi_hashes.json"
1310
+ pyi_hashes_file = pyi_hashes_parent / PYI_HASHES
1306
1311
  if pyi_hashes_file.exists():
1307
1312
  pyi_hashes = json.loads(pyi_hashes_file.read_text())
1308
1313
  for file_path, hashed_content in zip(
reflex/utils/redir.py CHANGED
@@ -5,9 +5,9 @@ import webbrowser
5
5
 
6
6
  import httpx
7
7
 
8
+ from reflex import constants
8
9
  from reflex.utils import net
9
10
 
10
- from .. import constants
11
11
  from . import console
12
12
 
13
13
 
reflex/utils/registry.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import httpx
4
4
 
5
- from reflex.config import environment
5
+ from reflex.environment import environment
6
6
  from reflex.utils import console, net
7
7
  from reflex.utils.decorator import once
8
8
 
@@ -76,7 +76,8 @@ def serializer(
76
76
 
77
77
  # Make sure the function takes a single argument.
78
78
  if len(args) != 1:
79
- raise ValueError("Serializer must take a single argument.")
79
+ msg = "Serializer must take a single argument."
80
+ raise ValueError(msg)
80
81
 
81
82
  # Get the type of the argument.
82
83
  type_ = type_hints[args[0]]
@@ -166,8 +167,7 @@ def serialize(
166
167
  # Return the serialized value and the type.
167
168
  if get_type:
168
169
  return serialized, get_serializer_type(type(value))
169
- else:
170
- return serialized
170
+ return serialized
171
171
 
172
172
 
173
173
  @functools.lru_cache
@@ -427,7 +427,7 @@ with contextlib.suppress(ImportError):
427
427
  """
428
428
  return [
429
429
  [str(d) if isinstance(d, (list, tuple)) else d for d in data]
430
- for data in list(df.values.tolist())
430
+ for data in list(df.to_numpy().tolist())
431
431
  ]
432
432
 
433
433
  @serializer
reflex/utils/telemetry.py CHANGED
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import dataclasses
7
+ import importlib.metadata
7
8
  import multiprocessing
8
9
  import platform
9
10
  import warnings
@@ -15,11 +16,16 @@ import httpx
15
16
  import psutil
16
17
 
17
18
  from reflex import constants
18
- from reflex.config import environment
19
+ from reflex.environment import environment
19
20
  from reflex.utils import console
20
21
  from reflex.utils.decorator import once_unless_none
21
22
  from reflex.utils.exceptions import ReflexError
22
- from reflex.utils.prerequisites import ensure_reflex_installation_id, get_project_hash
23
+ from reflex.utils.prerequisites import (
24
+ ensure_reflex_installation_id,
25
+ get_bun_version,
26
+ get_node_version,
27
+ get_project_hash,
28
+ )
23
29
 
24
30
  UTC = timezone.utc
25
31
  POSTHOG_API_URL: str = "https://app.posthog.com/capture/"
@@ -71,6 +77,18 @@ def get_cpu_count() -> int:
71
77
  return multiprocessing.cpu_count()
72
78
 
73
79
 
80
+ def get_reflex_enterprise_version() -> str | None:
81
+ """Get the version of reflex-enterprise if installed.
82
+
83
+ Returns:
84
+ The version string if installed, None if not installed.
85
+ """
86
+ try:
87
+ return importlib.metadata.version("reflex-enterprise")
88
+ except importlib.metadata.PackageNotFoundError:
89
+ return None
90
+
91
+
74
92
  def get_memory() -> int:
75
93
  """Get the total memory in MB.
76
94
 
@@ -106,6 +124,9 @@ class _Properties(TypedDict):
106
124
  user_os_detail: str
107
125
  reflex_version: str
108
126
  python_version: str
127
+ node_version: str | None
128
+ bun_version: str | None
129
+ reflex_enterprise_version: str | None
109
130
  cpu_count: int
110
131
  memory: int
111
132
  cpu_info: dict
@@ -153,6 +174,13 @@ def _get_event_defaults() -> _DefaultEvent | None:
153
174
  "user_os_detail": get_detailed_platform_str(),
154
175
  "reflex_version": get_reflex_version(),
155
176
  "python_version": get_python_version(),
177
+ "node_version": (
178
+ str(node_version) if (node_version := get_node_version()) else None
179
+ ),
180
+ "bun_version": (
181
+ str(bun_version) if (bun_version := get_bun_version()) else None
182
+ ),
183
+ "reflex_enterprise_version": get_reflex_enterprise_version(),
156
184
  "cpu_count": get_cpu_count(),
157
185
  "memory": get_memory(),
158
186
  "cpu_info": dataclasses.asdict(cpuinfo) if cpuinfo else {},
@@ -232,6 +260,9 @@ def _send(event: str, telemetry_enabled: bool | None, **kwargs) -> bool:
232
260
  return False
233
261
 
234
262
 
263
+ background_tasks = set()
264
+
265
+
235
266
  def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
236
267
  """Send anonymous telemetry for Reflex.
237
268
 
@@ -246,7 +277,9 @@ def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
246
277
 
247
278
  try:
248
279
  # Within an event loop context, send the event asynchronously.
249
- asyncio.create_task(async_send(event, telemetry_enabled, **kwargs))
280
+ task = asyncio.create_task(async_send(event, telemetry_enabled, **kwargs))
281
+ background_tasks.add(task)
282
+ task.add_done_callback(background_tasks.discard)
250
283
  except RuntimeError:
251
284
  # If there is no event loop, send the event synchronously.
252
285
  warnings.filterwarnings("ignore", category=RuntimeWarning)
reflex/utils/types.py CHANGED
@@ -263,8 +263,12 @@ def is_classvar(a_type: Any) -> bool:
263
263
  Returns:
264
264
  Whether the type is a ClassVar.
265
265
  """
266
- return a_type is ClassVar or (
267
- type(a_type) is _GenericAlias and a_type.__origin__ is ClassVar
266
+ return (
267
+ a_type is ClassVar
268
+ or (type(a_type) is _GenericAlias and a_type.__origin__ is ClassVar)
269
+ or (
270
+ type(a_type) is ForwardRef and a_type.__forward_arg__.startswith("ClassVar")
271
+ )
268
272
  )
269
273
 
270
274
 
@@ -378,7 +382,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
378
382
  if hasattr(cls, "__fields__") and name in cls.__fields__:
379
383
  # pydantic models
380
384
  return get_field_type(cls, name)
381
- elif isinstance(cls, type) and issubclass(cls, DeclarativeBase):
385
+ if isinstance(cls, type) and issubclass(cls, DeclarativeBase):
382
386
  insp = sqlalchemy.inspect(cls)
383
387
  if name in insp.columns:
384
388
  # check for list types
@@ -410,8 +414,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
410
414
  if isinstance(prop, Relationship):
411
415
  type_ = prop.mapper.class_
412
416
  # TODO: check for nullable?
413
- type_ = list[type_] if prop.uselist else type_ | None
414
- return type_
417
+ return list[type_] if prop.uselist else type_ | None
415
418
  if isinstance(attr, AssociationProxyInstance):
416
419
  return list[
417
420
  get_attribute_access_type(
@@ -444,7 +447,6 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
444
447
  return hints[name]
445
448
  except exceptions as e:
446
449
  console.warn(f"Failed to resolve ForwardRefs for {cls}.{name} due to {e}")
447
- pass
448
450
  return None # Attribute is not accessible.
449
451
 
450
452
 
@@ -465,7 +467,8 @@ def get_base_class(cls: GenericType) -> type:
465
467
  # only literals of the same type are supported.
466
468
  arg_type = type(get_args(cls)[0])
467
469
  if not all(type(arg) is arg_type for arg in get_args(cls)):
468
- raise TypeError("only literals of the same type are supported")
470
+ msg = "only literals of the same type are supported"
471
+ raise TypeError(msg)
469
472
  return type(get_args(cls)[0])
470
473
 
471
474
  if is_union(cls):
@@ -493,13 +496,13 @@ def _breakpoints_satisfies_typing(cls_check: GenericType, instance: Any) -> bool
493
496
  if not isinstance(value, str) or value not in get_args(expected_type):
494
497
  return False
495
498
  return True
496
- elif isinstance(cls_check_base, tuple):
499
+ if isinstance(cls_check_base, tuple):
497
500
  # union type, so check all types
498
501
  return any(
499
502
  _breakpoints_satisfies_typing(type_to_check, instance)
500
503
  for type_to_check in get_args(cls_check)
501
504
  )
502
- elif cls_check_base == reflex.vars.Var and "__args__" in cls_check.__dict__:
505
+ if cls_check_base == reflex.vars.Var and "__args__" in cls_check.__dict__:
503
506
  return _breakpoints_satisfies_typing(get_args(cls_check)[0], instance)
504
507
 
505
508
  return False
@@ -551,7 +554,8 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None)
551
554
  except TypeError as te:
552
555
  # These errors typically arise from bad annotations and are hard to
553
556
  # debug without knowing the type that we tried to compare.
554
- raise TypeError(f"Invalid type for issubclass: {cls_base}") from te
557
+ msg = f"Invalid type for issubclass: {cls_base}"
558
+ raise TypeError(msg) from te
555
559
 
556
560
 
557
561
  def does_obj_satisfy_typed_dict(obj: Any, cls: GenericType) -> bool:
@@ -909,9 +913,8 @@ def validate_literal(key: str, value: Any, expected_type: type, comp_name: str):
909
913
  [str(v) if not isinstance(v, str) else f"'{v}'" for v in allowed_values]
910
914
  )
911
915
  value_str = f"'{value}'" if isinstance(value, str) else value
912
- raise ValueError(
913
- f"prop value for {key!s} of the `{comp_name}` component should be one of the following: {allowed_value_str}. Got {value_str} instead"
914
- )
916
+ msg = f"prop value for {key!s} of the `{comp_name}` component should be one of the following: {allowed_value_str}. Got {value_str} instead"
917
+ raise ValueError(msg)
915
918
 
916
919
 
917
920
  def validate_parameter_literals(func: Callable):