reflex 0.7.1a4__py3-none-any.whl → 0.7.2a1__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 (226) hide show
  1. reflex/.templates/jinja/web/utils/context.js.jinja2 +8 -8
  2. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +3 -3
  3. reflex/admin.py +1 -2
  4. reflex/app.py +46 -49
  5. reflex/app_mixins/lifespan.py +2 -2
  6. reflex/app_mixins/middleware.py +1 -2
  7. reflex/assets.py +1 -2
  8. reflex/base.py +2 -2
  9. reflex/compiler/compiler.py +51 -16
  10. reflex/compiler/utils.py +4 -13
  11. reflex/components/base/app_wrap.pyi +7 -7
  12. reflex/components/base/bare.py +3 -3
  13. reflex/components/base/body.pyi +7 -7
  14. reflex/components/base/document.py +1 -3
  15. reflex/components/base/document.pyi +32 -32
  16. reflex/components/base/error_boundary.py +2 -4
  17. reflex/components/base/error_boundary.pyi +11 -13
  18. reflex/components/base/fragment.pyi +7 -7
  19. reflex/components/base/head.pyi +13 -13
  20. reflex/components/base/link.pyi +22 -22
  21. reflex/components/base/meta.py +5 -7
  22. reflex/components/base/meta.pyi +40 -40
  23. reflex/components/base/script.pyi +11 -14
  24. reflex/components/base/strict_mode.pyi +7 -7
  25. reflex/components/component.py +188 -113
  26. reflex/components/core/auto_scroll.py +8 -1
  27. reflex/components/core/auto_scroll.pyi +183 -210
  28. reflex/components/core/banner.py +2 -4
  29. reflex/components/core/banner.pyi +390 -444
  30. reflex/components/core/breakpoints.py +5 -5
  31. reflex/components/core/client_side_routing.pyi +14 -14
  32. reflex/components/core/clipboard.py +4 -4
  33. reflex/components/core/clipboard.pyi +12 -14
  34. reflex/components/core/cond.py +17 -25
  35. reflex/components/core/debounce.py +3 -3
  36. reflex/components/core/debounce.pyi +14 -14
  37. reflex/components/core/foreach.py +7 -2
  38. reflex/components/core/html.py +1 -3
  39. reflex/components/core/html.pyi +184 -213
  40. reflex/components/core/match.py +15 -19
  41. reflex/components/core/sticky.pyi +930 -1078
  42. reflex/components/core/upload.py +4 -4
  43. reflex/components/core/upload.pyi +62 -62
  44. reflex/components/datadisplay/code.py +6 -6
  45. reflex/components/datadisplay/code.pyi +1159 -1165
  46. reflex/components/datadisplay/dataeditor.py +49 -49
  47. reflex/components/datadisplay/dataeditor.pyi +95 -123
  48. reflex/components/datadisplay/logo.py +1 -3
  49. reflex/components/datadisplay/shiki_code_block.py +8 -10
  50. reflex/components/datadisplay/shiki_code_block.pyi +1678 -1720
  51. reflex/components/el/element.pyi +7 -7
  52. reflex/components/el/elements/base.pyi +183 -210
  53. reflex/components/el/elements/forms.py +23 -23
  54. reflex/components/el/elements/forms.pyi +2571 -2933
  55. reflex/components/el/elements/inline.py +4 -4
  56. reflex/components/el/elements/inline.pyi +5191 -5953
  57. reflex/components/el/elements/media.py +47 -47
  58. reflex/components/el/elements/media.pyi +4802 -5500
  59. reflex/components/el/elements/metadata.py +1 -3
  60. reflex/components/el/elements/metadata.pyi +782 -896
  61. reflex/components/el/elements/other.pyi +1278 -1467
  62. reflex/components/el/elements/scripts.pyi +580 -667
  63. reflex/components/el/elements/sectioning.pyi +2761 -3166
  64. reflex/components/el/elements/tables.pyi +1840 -2119
  65. reflex/components/el/elements/typography.pyi +2772 -3179
  66. reflex/components/gridjs/datatable.py +7 -7
  67. reflex/components/gridjs/datatable.pyi +19 -19
  68. reflex/components/lucide/icon.pyi +21 -21
  69. reflex/components/markdown/markdown.py +2 -2
  70. reflex/components/markdown/markdown.pyi +9 -9
  71. reflex/components/moment/moment.py +11 -12
  72. reflex/components/moment/moment.pyi +44 -47
  73. reflex/components/next/base.pyi +7 -7
  74. reflex/components/next/image.py +3 -3
  75. reflex/components/next/image.pyi +19 -21
  76. reflex/components/next/link.pyi +9 -9
  77. reflex/components/next/video.py +1 -3
  78. reflex/components/next/video.pyi +9 -9
  79. reflex/components/plotly/plotly.py +22 -45
  80. reflex/components/plotly/plotly.pyi +164 -164
  81. reflex/components/radix/primitives/accordion.py +14 -14
  82. reflex/components/radix/primitives/accordion.pyi +439 -487
  83. reflex/components/radix/primitives/base.py +1 -3
  84. reflex/components/radix/primitives/base.pyi +15 -15
  85. reflex/components/radix/primitives/drawer.py +3 -3
  86. reflex/components/radix/primitives/drawer.pyi +110 -116
  87. reflex/components/radix/primitives/form.py +1 -1
  88. reflex/components/radix/primitives/form.pyi +668 -752
  89. reflex/components/radix/primitives/progress.py +6 -6
  90. reflex/components/radix/primitives/progress.pyi +225 -243
  91. reflex/components/radix/primitives/slider.py +6 -6
  92. reflex/components/radix/primitives/slider.pyi +52 -55
  93. reflex/components/radix/themes/base.py +3 -6
  94. reflex/components/radix/themes/base.pyi +197 -303
  95. reflex/components/radix/themes/color_mode.py +5 -5
  96. reflex/components/radix/themes/color_mode.pyi +366 -436
  97. reflex/components/radix/themes/components/alert_dialog.pyi +229 -262
  98. reflex/components/radix/themes/components/aspect_ratio.py +1 -3
  99. reflex/components/radix/themes/components/aspect_ratio.pyi +8 -8
  100. reflex/components/radix/themes/components/avatar.pyi +79 -94
  101. reflex/components/radix/themes/components/badge.pyi +252 -295
  102. reflex/components/radix/themes/components/button.pyi +269 -314
  103. reflex/components/radix/themes/components/callout.py +2 -2
  104. reflex/components/radix/themes/components/callout.pyi +1116 -1290
  105. reflex/components/radix/themes/components/card.pyi +194 -229
  106. reflex/components/radix/themes/components/checkbox.pyi +243 -278
  107. reflex/components/radix/themes/components/checkbox_cards.py +3 -7
  108. reflex/components/radix/themes/components/checkbox_cards.pyi +101 -135
  109. reflex/components/radix/themes/components/checkbox_group.py +2 -2
  110. reflex/components/radix/themes/components/checkbox_group.pyi +83 -96
  111. reflex/components/radix/themes/components/context_menu.py +18 -15
  112. reflex/components/radix/themes/components/context_menu.pyi +408 -458
  113. reflex/components/radix/themes/components/data_list.pyi +122 -147
  114. reflex/components/radix/themes/components/dialog.pyi +231 -264
  115. reflex/components/radix/themes/components/dropdown_menu.py +16 -13
  116. reflex/components/radix/themes/components/dropdown_menu.pyi +223 -246
  117. reflex/components/radix/themes/components/hover_card.py +2 -2
  118. reflex/components/radix/themes/components/hover_card.pyi +237 -282
  119. reflex/components/radix/themes/components/icon_button.pyi +269 -314
  120. reflex/components/radix/themes/components/inset.py +8 -8
  121. reflex/components/radix/themes/components/inset.pyi +232 -292
  122. reflex/components/radix/themes/components/popover.py +2 -2
  123. reflex/components/radix/themes/components/popover.pyi +229 -271
  124. reflex/components/radix/themes/components/progress.pyi +80 -96
  125. reflex/components/radix/themes/components/radio.pyi +73 -86
  126. reflex/components/radix/themes/components/radio_cards.py +4 -8
  127. reflex/components/radix/themes/components/radio_cards.pyi +117 -154
  128. reflex/components/radix/themes/components/radio_group.py +3 -3
  129. reflex/components/radix/themes/components/radio_group.pyi +250 -291
  130. reflex/components/radix/themes/components/scroll_area.pyi +14 -20
  131. reflex/components/radix/themes/components/segmented_control.py +6 -6
  132. reflex/components/radix/themes/components/segmented_control.pyi +89 -108
  133. reflex/components/radix/themes/components/select.py +7 -7
  134. reflex/components/radix/themes/components/select.pyi +376 -444
  135. reflex/components/radix/themes/components/separator.pyi +79 -93
  136. reflex/components/radix/themes/components/skeleton.pyi +32 -26
  137. reflex/components/radix/themes/components/slider.py +8 -8
  138. reflex/components/radix/themes/components/slider.pyi +99 -122
  139. reflex/components/radix/themes/components/spinner.pyi +12 -19
  140. reflex/components/radix/themes/components/switch.pyi +84 -99
  141. reflex/components/radix/themes/components/table.py +9 -9
  142. reflex/components/radix/themes/components/table.pyi +1440 -1794
  143. reflex/components/radix/themes/components/tabs.py +4 -4
  144. reflex/components/radix/themes/components/tabs.pyi +120 -132
  145. reflex/components/radix/themes/components/text_area.pyi +281 -331
  146. reflex/components/radix/themes/components/text_field.py +2 -2
  147. reflex/components/radix/themes/components/text_field.pyi +639 -734
  148. reflex/components/radix/themes/components/tooltip.py +6 -6
  149. reflex/components/radix/themes/components/tooltip.pyi +34 -43
  150. reflex/components/radix/themes/layout/base.pyi +85 -182
  151. reflex/components/radix/themes/layout/box.pyi +183 -210
  152. reflex/components/radix/themes/layout/center.pyi +225 -286
  153. reflex/components/radix/themes/layout/container.pyi +191 -224
  154. reflex/components/radix/themes/layout/flex.py +2 -2
  155. reflex/components/radix/themes/layout/flex.pyi +225 -286
  156. reflex/components/radix/themes/layout/grid.py +2 -2
  157. reflex/components/radix/themes/layout/grid.pyi +245 -315
  158. reflex/components/radix/themes/layout/list.py +2 -2
  159. reflex/components/radix/themes/layout/list.pyi +712 -815
  160. reflex/components/radix/themes/layout/section.pyi +187 -221
  161. reflex/components/radix/themes/layout/spacer.pyi +225 -286
  162. reflex/components/radix/themes/layout/stack.pyi +625 -768
  163. reflex/components/radix/themes/typography/blockquote.pyi +257 -299
  164. reflex/components/radix/themes/typography/code.pyi +259 -304
  165. reflex/components/radix/themes/typography/heading.pyi +272 -324
  166. reflex/components/radix/themes/typography/link.pyi +302 -358
  167. reflex/components/radix/themes/typography/text.pyi +1669 -1945
  168. reflex/components/react_player/audio.pyi +20 -22
  169. reflex/components/react_player/react_player.pyi +19 -19
  170. reflex/components/react_player/video.pyi +20 -22
  171. reflex/components/recharts/cartesian.py +100 -97
  172. reflex/components/recharts/cartesian.pyi +891 -1007
  173. reflex/components/recharts/charts.py +42 -42
  174. reflex/components/recharts/charts.pyi +212 -249
  175. reflex/components/recharts/general.py +22 -21
  176. reflex/components/recharts/general.pyi +198 -223
  177. reflex/components/recharts/polar.py +42 -45
  178. reflex/components/recharts/polar.pyi +254 -288
  179. reflex/components/recharts/recharts.pyi +13 -13
  180. reflex/components/sonner/toast.py +20 -20
  181. reflex/components/sonner/toast.pyi +58 -61
  182. reflex/components/suneditor/editor.py +9 -9
  183. reflex/components/suneditor/editor.pyi +78 -83
  184. reflex/components/tags/cond_tag.py +2 -2
  185. reflex/components/tags/iter_tag.py +10 -14
  186. reflex/components/tags/match_tag.py +2 -2
  187. reflex/components/tags/tag.py +10 -10
  188. reflex/config.py +36 -35
  189. reflex/constants/__init__.py +56 -53
  190. reflex/custom_components/custom_components.py +6 -7
  191. reflex/event.py +38 -42
  192. reflex/experimental/client_state.py +2 -4
  193. reflex/experimental/layout.py +2 -2
  194. reflex/experimental/layout.pyi +579 -663
  195. reflex/istate/data.py +4 -5
  196. reflex/middleware/hydrate_middleware.py +2 -2
  197. reflex/middleware/middleware.py +2 -2
  198. reflex/model.py +3 -5
  199. reflex/page.py +2 -2
  200. reflex/reflex.py +9 -10
  201. reflex/state.py +77 -49
  202. reflex/style.py +9 -3
  203. reflex/testing.py +21 -24
  204. reflex/utils/console.py +1 -1
  205. reflex/utils/decorator.py +26 -1
  206. reflex/utils/exec.py +6 -11
  207. reflex/utils/export.py +2 -3
  208. reflex/utils/format.py +4 -4
  209. reflex/utils/imports.py +12 -12
  210. reflex/utils/prerequisites.py +35 -84
  211. reflex/utils/processes.py +5 -5
  212. reflex/utils/pyi_generator.py +33 -22
  213. reflex/utils/serializers.py +60 -15
  214. reflex/utils/types.py +237 -56
  215. reflex/vars/base.py +122 -72
  216. reflex/vars/datetime.py +2 -2
  217. reflex/vars/function.py +52 -55
  218. reflex/vars/number.py +59 -5
  219. reflex/vars/object.py +57 -26
  220. reflex/vars/sequence.py +983 -958
  221. {reflex-0.7.1a4.dist-info → reflex-0.7.2a1.dist-info}/METADATA +3 -6
  222. reflex-0.7.2a1.dist-info/RECORD +405 -0
  223. {reflex-0.7.1a4.dist-info → reflex-0.7.2a1.dist-info}/WHEEL +1 -1
  224. reflex-0.7.1a4.dist-info/RECORD +0 -405
  225. {reflex-0.7.1a4.dist-info → reflex-0.7.2a1.dist-info}/LICENSE +0 -0
  226. {reflex-0.7.1a4.dist-info → reflex-0.7.2a1.dist-info}/entry_points.txt +0 -0
reflex/testing.py CHANGED
@@ -26,11 +26,9 @@ from typing import (
26
26
  AsyncIterator,
27
27
  Callable,
28
28
  Coroutine,
29
- List,
30
29
  Optional,
31
30
  Type,
32
31
  TypeVar,
33
- Union,
34
32
  )
35
33
 
36
34
  import psutil
@@ -78,8 +76,7 @@ DEFAULT_TIMEOUT = 15
78
76
  POLL_INTERVAL = 0.25
79
77
  FRONTEND_POPEN_ARGS = {}
80
78
  T = TypeVar("T")
81
- TimeoutType = Optional[Union[int, float]]
82
-
79
+ TimeoutType = int | float | None
83
80
  if platform.system() == "Windows":
84
81
  FRONTEND_POPEN_ARGS["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # pyright: ignore [reportAttributeAccessIssue]
85
82
  FRONTEND_POPEN_ARGS["shell"] = True
@@ -119,19 +116,19 @@ class AppHarness:
119
116
  """AppHarness executes a reflex app in-process for testing."""
120
117
 
121
118
  app_name: str
122
- app_source: Optional[
123
- Callable[[], None] | types.ModuleType | str | functools.partial[Any]
124
- ]
119
+ app_source: (
120
+ Callable[[], None] | types.ModuleType | str | functools.partial[Any] | None
121
+ )
125
122
  app_path: Path
126
123
  app_module_path: Path
127
- app_module: Optional[types.ModuleType] = None
128
- app_instance: Optional[reflex.App] = None
129
- frontend_process: Optional[subprocess.Popen] = None
130
- frontend_url: Optional[str] = None
131
- frontend_output_thread: Optional[threading.Thread] = None
132
- backend_thread: Optional[threading.Thread] = None
133
- backend: Optional[uvicorn.Server] = None
134
- state_manager: Optional[StateManager] = None
124
+ app_module: types.ModuleType | None = None
125
+ app_instance: reflex.App | None = None
126
+ frontend_process: subprocess.Popen | None = None
127
+ frontend_url: str | None = None
128
+ frontend_output_thread: threading.Thread | None = None
129
+ backend_thread: threading.Thread | None = None
130
+ backend: uvicorn.Server | None = None
131
+ state_manager: StateManager | None = None
135
132
  _frontends: list["WebDriver"] = dataclasses.field(default_factory=list)
136
133
  _decorated_pages: list = dataclasses.field(default_factory=list)
137
134
 
@@ -139,10 +136,10 @@ class AppHarness:
139
136
  def create(
140
137
  cls,
141
138
  root: Path,
142
- app_source: Optional[
143
- Callable[[], None] | types.ModuleType | str | functools.partial[Any]
144
- ] = None,
145
- app_name: Optional[str] = None,
139
+ app_source: (
140
+ Callable[[], None] | types.ModuleType | str | functools.partial[Any] | None
141
+ ) = None,
142
+ app_name: str | None = None,
146
143
  ) -> "AppHarness":
147
144
  """Create an AppHarness instance at root.
148
145
 
@@ -198,7 +195,7 @@ class AppHarness:
198
195
  f"{self.app_name}___{self.app_name}___" + state_cls_name
199
196
  )
200
197
 
201
- def get_full_state_name(self, path: List[str]) -> str:
198
+ def get_full_state_name(self, path: list[str]) -> str:
202
199
  """Get the full state name for the given state class name.
203
200
 
204
201
  Args:
@@ -596,7 +593,7 @@ class AppHarness:
596
593
  driver_clz: Optional[Type["WebDriver"]] = None,
597
594
  driver_kwargs: dict[str, Any] | None = None,
598
595
  driver_options: ArgOptions | None = None,
599
- driver_option_args: List[str] | None = None,
596
+ driver_option_args: list[str] | None = None,
600
597
  driver_option_capabilities: dict[str, Any] | None = None,
601
598
  ) -> "WebDriver":
602
599
  """Get a selenium webdriver instance pointed at the app.
@@ -768,7 +765,7 @@ class AppHarness:
768
765
  element: "WebElement",
769
766
  timeout: TimeoutType = None,
770
767
  exp_not_equal: str = "",
771
- ) -> Optional[str]:
768
+ ) -> str | None:
772
769
  """Poll element.get_attribute("value") for change.
773
770
 
774
771
  Args:
@@ -904,8 +901,8 @@ class AppHarnessProd(AppHarness):
904
901
  handling. Additionally, the backend runs in multi-worker mode.
905
902
  """
906
903
 
907
- frontend_thread: Optional[threading.Thread] = None
908
- frontend_server: Optional[Subdir404TCPServer] = None
904
+ frontend_thread: threading.Thread | None = None
905
+ frontend_server: Subdir404TCPServer | None = None
909
906
 
910
907
  def _run_frontend(self):
911
908
  web_root = (
reflex/utils/console.py CHANGED
@@ -250,7 +250,7 @@ def deprecate(
250
250
 
251
251
  if dedupe_key not in _EMITTED_DEPRECATION_WARNINGS:
252
252
  msg = (
253
- f"{feature_name} has been deprecated in version {deprecation_version} {reason.rstrip('.')}. It will be completely "
253
+ f"{feature_name} has been deprecated in version {deprecation_version}. {reason.rstrip('.').lstrip('. ')}. It will be completely "
254
254
  f"removed in {removal_version}. ({loc})"
255
255
  )
256
256
  if _LOG_LEVEL <= LogLevel.WARNING:
reflex/utils/decorator.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """Decorator utilities."""
2
2
 
3
- from typing import Callable, TypeVar
3
+ import functools
4
+ from typing import Callable, ParamSpec, TypeVar
4
5
 
5
6
  T = TypeVar("T")
6
7
 
@@ -23,3 +24,27 @@ def once(f: Callable[[], T]) -> Callable[[], T]:
23
24
  return value # pyright: ignore[reportReturnType]
24
25
 
25
26
  return wrapper
27
+
28
+
29
+ P = ParamSpec("P")
30
+
31
+
32
+ def debug(f: Callable[P, T]) -> Callable[P, T]:
33
+ """A decorator that prints the function name, arguments, and result.
34
+
35
+ Args:
36
+ f: The function to call.
37
+
38
+ Returns:
39
+ A function that prints the function name, arguments, and result.
40
+ """
41
+
42
+ @functools.wraps(f)
43
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
44
+ result = f(*args, **kwargs)
45
+ print( # noqa: T201
46
+ f"Calling {f.__name__} with args: {args} and kwargs: {kwargs}, result: {result}"
47
+ )
48
+ return result
49
+
50
+ return wrapper
reflex/utils/exec.py CHANGED
@@ -524,17 +524,12 @@ def output_system_info():
524
524
 
525
525
  fnm_info = f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]"
526
526
 
527
- if system != "Windows" or (
528
- system == "Windows" and prerequisites.is_windows_bun_supported()
529
- ):
530
- dependencies.extend(
531
- [
532
- fnm_info,
533
- f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
534
- ],
535
- )
536
- else:
537
- dependencies.append(fnm_info)
527
+ dependencies.extend(
528
+ [
529
+ fnm_info,
530
+ f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
531
+ ],
532
+ )
538
533
 
539
534
  if system == "Linux":
540
535
  import distro # pyright: ignore[reportMissingImports]
reflex/utils/export.py CHANGED
@@ -1,7 +1,6 @@
1
1
  """Export utilities."""
2
2
 
3
3
  from pathlib import Path
4
- from typing import Optional
5
4
 
6
5
  from reflex import constants
7
6
  from reflex.config import environment, get_config
@@ -16,8 +15,8 @@ def export(
16
15
  backend: bool = True,
17
16
  zip_dest_dir: str = str(Path.cwd()),
18
17
  upload_db_file: bool = False,
19
- api_url: Optional[str] = None,
20
- deploy_url: Optional[str] = None,
18
+ api_url: str | None = None,
19
+ deploy_url: str | None = None,
21
20
  env: constants.Env = constants.Env.PROD,
22
21
  loglevel: constants.LogLevel = console._LOG_LEVEL,
23
22
  ):
reflex/utils/format.py CHANGED
@@ -6,7 +6,7 @@ import inspect
6
6
  import json
7
7
  import os
8
8
  import re
9
- from typing import TYPE_CHECKING, Any, List, Optional, Union
9
+ from typing import TYPE_CHECKING, Any, Union
10
10
 
11
11
  from reflex import constants
12
12
  from reflex.constants.state import FRONTEND_EVENT_STATE
@@ -336,7 +336,7 @@ def format_route(route: str, format_case: bool = True) -> str:
336
336
 
337
337
  def format_match(
338
338
  cond: str | Var,
339
- match_cases: List[List[Var]],
339
+ match_cases: list[list[Var]],
340
340
  default: Var,
341
341
  ) -> str:
342
342
  """Format a match expression whose return type is a Var.
@@ -370,7 +370,7 @@ def format_match(
370
370
 
371
371
  def format_prop(
372
372
  prop: Union[Var, EventChain, ComponentStyle, str],
373
- ) -> Union[int, float, str]:
373
+ ) -> int | float | str:
374
374
  """Format a prop.
375
375
 
376
376
  Args:
@@ -532,7 +532,7 @@ if TYPE_CHECKING:
532
532
 
533
533
  def format_queue_events(
534
534
  events: EventType[Any] | None = None,
535
- args_spec: Optional[ArgsSpec] = None,
535
+ args_spec: ArgsSpec | None = None,
536
536
  ) -> Var[EventChain]:
537
537
  """Format a list of event handler / event spec as a javascript callback.
538
538
 
reflex/utils/imports.py CHANGED
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import dataclasses
6
6
  from collections import defaultdict
7
- from typing import DefaultDict, Dict, List, Optional, Tuple, Union
7
+ from typing import DefaultDict, Union
8
8
 
9
9
 
10
10
  def merge_imports(
@@ -18,7 +18,7 @@ def merge_imports(
18
18
  Returns:
19
19
  The merged import dicts.
20
20
  """
21
- all_imports: DefaultDict[str, List[ImportVar]] = defaultdict(list)
21
+ all_imports: DefaultDict[str, list[ImportVar]] = defaultdict(list)
22
22
  for import_dict in imports:
23
23
  for lib, fields in (
24
24
  import_dict if isinstance(import_dict, tuple) else import_dict.items()
@@ -95,26 +95,26 @@ class ImportVar:
95
95
  """An import var."""
96
96
 
97
97
  # The name of the import tag.
98
- tag: Optional[str]
98
+ tag: str | None
99
99
 
100
100
  # whether the import is default or named.
101
- is_default: Optional[bool] = False
101
+ is_default: bool | None = False
102
102
 
103
103
  # The tag alias.
104
- alias: Optional[str] = None
104
+ alias: str | None = None
105
105
 
106
106
  # Whether this import need to install the associated lib
107
- install: Optional[bool] = True
107
+ install: bool | None = True
108
108
 
109
109
  # whether this import should be rendered or not
110
- render: Optional[bool] = True
110
+ render: bool | None = True
111
111
 
112
112
  # The path of the package to import from.
113
113
  package_path: str = "/"
114
114
 
115
115
  # whether this import package should be added to transpilePackages in next.config.js
116
116
  # https://nextjs.org/docs/app/api-reference/next-config-js/transpilePackages
117
- transpile: Optional[bool] = False
117
+ transpile: bool | None = False
118
118
 
119
119
  @property
120
120
  def name(self) -> str:
@@ -131,7 +131,7 @@ class ImportVar:
131
131
  return self.tag or ""
132
132
 
133
133
 
134
- ImportTypes = Union[str, ImportVar, List[Union[str, ImportVar]], List[ImportVar]]
135
- ImportDict = Dict[str, ImportTypes]
136
- ParsedImportDict = Dict[str, List[ImportVar]]
137
- ImmutableParsedImportDict = Tuple[Tuple[str, Tuple[ImportVar, ...]], ...]
134
+ ImportTypes = Union[str, ImportVar, list[str | ImportVar], list[ImportVar]]
135
+ ImportDict = dict[str, ImportTypes]
136
+ ParsedImportDict = dict[str, list[ImportVar]]
137
+ ImmutableParsedImportDict = tuple[tuple[str, tuple[ImportVar, ...]], ...]
@@ -23,7 +23,7 @@ import zipfile
23
23
  from datetime import datetime
24
24
  from pathlib import Path
25
25
  from types import ModuleType
26
- from typing import Any, Callable, List, NamedTuple, Optional
26
+ from typing import Callable, NamedTuple
27
27
  from urllib.parse import urlparse
28
28
 
29
29
  import httpx
@@ -72,9 +72,9 @@ class Template:
72
72
  class CpuInfo:
73
73
  """Model to save cpu info."""
74
74
 
75
- manufacturer_id: Optional[str]
76
- model_name: Optional[str]
77
- address_width: Optional[int]
75
+ manufacturer_id: str | None
76
+ model_name: str | None
77
+ address_width: int | None
78
78
 
79
79
 
80
80
  def get_web_dir() -> Path:
@@ -242,9 +242,7 @@ def get_install_package_manager(on_failure_return_none: bool = False) -> str | N
242
242
  The path to the package manager.
243
243
  """
244
244
  if constants.IS_WINDOWS and (
245
- not is_windows_bun_supported()
246
- or windows_check_onedrive_in_path()
247
- or windows_npm_escape_hatch()
245
+ windows_check_onedrive_in_path() or windows_npm_escape_hatch()
248
246
  ):
249
247
  return get_package_manager(on_failure_return_none)
250
248
  return str(get_config().bun_path)
@@ -896,7 +894,7 @@ def init_reflex_json(project_hash: int | None):
896
894
 
897
895
 
898
896
  def update_next_config(
899
- export: bool = False, transpile_packages: Optional[List[str]] = None
897
+ export: bool = False, transpile_packages: list[str] | None = None
900
898
  ):
901
899
  """Update Next.js config from Reflex config.
902
900
 
@@ -918,7 +916,7 @@ def update_next_config(
918
916
 
919
917
 
920
918
  def _update_next_config(
921
- config: Config, export: bool = False, transpile_packages: Optional[List[str]] = None
919
+ config: Config, export: bool = False, transpile_packages: list[str] | None = None
922
920
  ):
923
921
  next_config = {
924
922
  "basePath": config.frontend_path or "",
@@ -1064,17 +1062,11 @@ def install_bun():
1064
1062
  Raises:
1065
1063
  SystemPackageMissingError: If "unzip" is missing.
1066
1064
  """
1067
- win_supported = is_windows_bun_supported()
1068
1065
  one_drive_in_path = windows_check_onedrive_in_path()
1069
- if constants.IS_WINDOWS and (not win_supported or one_drive_in_path):
1070
- if not win_supported:
1071
- console.warn(
1072
- "Bun for Windows is currently only available for x86 64-bit Windows. Installation will fall back on npm."
1073
- )
1074
- if one_drive_in_path:
1075
- console.warn(
1076
- "Creating project directories in OneDrive is not recommended for bun usage on windows. This will fallback to npm."
1077
- )
1066
+ if constants.IS_WINDOWS and one_drive_in_path:
1067
+ console.warn(
1068
+ "Creating project directories in OneDrive is not recommended for bun usage on windows. This will fallback to npm."
1069
+ )
1078
1070
 
1079
1071
  # Skip if bun is already installed.
1080
1072
  if get_bun_version() == version.parse(constants.Bun.VERSION):
@@ -1176,12 +1168,7 @@ def install_frontend_packages(packages: set[str], config: Config):
1176
1168
  get_package_manager(on_failure_return_none=True)
1177
1169
  if (
1178
1170
  not constants.IS_WINDOWS
1179
- or (
1180
- constants.IS_WINDOWS
1181
- and (
1182
- is_windows_bun_supported() and not windows_check_onedrive_in_path()
1183
- )
1184
- )
1171
+ or (constants.IS_WINDOWS and not windows_check_onedrive_in_path())
1185
1172
  )
1186
1173
  else None
1187
1174
  )
@@ -1200,7 +1187,7 @@ def install_frontend_packages(packages: set[str], config: Config):
1200
1187
  )
1201
1188
 
1202
1189
  processes.run_process_with_fallback(
1203
- [install_package_manager, "install"],
1190
+ [install_package_manager, "install", "--legacy-peer-deps"],
1204
1191
  fallback=fallback_command,
1205
1192
  analytics_enabled=True,
1206
1193
  show_status_message="Installing base frontend packages",
@@ -1213,6 +1200,7 @@ def install_frontend_packages(packages: set[str], config: Config):
1213
1200
  [
1214
1201
  install_package_manager,
1215
1202
  "add",
1203
+ "--legacy-peer-deps",
1216
1204
  "-d",
1217
1205
  constants.Tailwind.VERSION,
1218
1206
  *((config.tailwind or {}).get("plugins", [])),
@@ -1227,7 +1215,7 @@ def install_frontend_packages(packages: set[str], config: Config):
1227
1215
  # Install custom packages defined in frontend_packages
1228
1216
  if len(packages) > 0:
1229
1217
  processes.run_process_with_fallback(
1230
- [install_package_manager, "add", *packages],
1218
+ [install_package_manager, "add", "--legacy-peer-deps", *packages],
1231
1219
  fallback=fallback_command,
1232
1220
  analytics_enabled=True,
1233
1221
  show_status_message="Installing frontend packages from config and components",
@@ -1371,7 +1359,7 @@ def validate_frontend_dependencies(init: bool = True):
1371
1359
  validate_bun()
1372
1360
 
1373
1361
 
1374
- def ensure_reflex_installation_id() -> Optional[int]:
1362
+ def ensure_reflex_installation_id() -> int | None:
1375
1363
  """Ensures that a reflex distinct id has been generated and stored in the reflex directory.
1376
1364
 
1377
1365
  Returns:
@@ -1925,24 +1913,23 @@ def format_address_width(address_width: str | None) -> int | None:
1925
1913
  return None
1926
1914
 
1927
1915
 
1928
- @functools.lru_cache(maxsize=None)
1929
- def get_cpu_info() -> CpuInfo | None:
1930
- """Get the CPU info of the underlining host.
1916
+ def _retrieve_cpu_info() -> CpuInfo | None:
1917
+ """Retrieve the CPU info of the host.
1931
1918
 
1932
1919
  Returns:
1933
- The CPU info.
1920
+ The CPU info.
1934
1921
  """
1935
1922
  platform_os = platform.system()
1936
1923
  cpuinfo = {}
1937
1924
  try:
1938
1925
  if platform_os == "Windows":
1939
- cmd = "wmic cpu get addresswidth,caption,manufacturer /FORMAT:csv"
1926
+ cmd = 'powershell -Command "Get-CimInstance Win32_Processor | Select-Object -First 1 | Select-Object AddressWidth,Manufacturer,Name | ConvertTo-Json"'
1940
1927
  output = processes.execute_command_and_return_output(cmd)
1941
1928
  if output:
1942
- val = output.splitlines()[-1].split(",")[1:]
1943
- cpuinfo["manufacturer_id"] = val[2]
1944
- cpuinfo["model_name"] = val[1].split("Family")[0].strip()
1945
- cpuinfo["address_width"] = format_address_width(val[0])
1929
+ cpu_data = json.loads(output)
1930
+ cpuinfo["address_width"] = cpu_data["AddressWidth"]
1931
+ cpuinfo["manufacturer_id"] = cpu_data["Manufacturer"]
1932
+ cpuinfo["model_name"] = cpu_data["Name"]
1946
1933
  elif platform_os == "Linux":
1947
1934
  output = processes.execute_command_and_return_output("lscpu")
1948
1935
  if output:
@@ -1982,21 +1969,20 @@ def get_cpu_info() -> CpuInfo | None:
1982
1969
 
1983
1970
 
1984
1971
  @functools.lru_cache(maxsize=None)
1985
- def is_windows_bun_supported() -> bool:
1986
- """Check whether the underlining host running windows qualifies to run bun.
1987
- We typically do not run bun on ARM or 32 bit devices that use windows.
1972
+ def get_cpu_info() -> CpuInfo | None:
1973
+ """Get the CPU info of the underlining host.
1988
1974
 
1989
1975
  Returns:
1990
- Whether the host is qualified to use bun.
1976
+ The CPU info.
1991
1977
  """
1992
- cpu_info = get_cpu_info()
1993
- return (
1994
- constants.IS_WINDOWS
1995
- and cpu_info is not None
1996
- and cpu_info.address_width == 64
1997
- and cpu_info.model_name is not None
1998
- and "ARM" not in cpu_info.model_name
1999
- )
1978
+ cpu_info_file = environment.REFLEX_DIR.get() / "cpu_info.json"
1979
+ if cpu_info_file.exists() and (cpu_info := json.loads(cpu_info_file.read_text())):
1980
+ return CpuInfo(**cpu_info)
1981
+ cpu_info = _retrieve_cpu_info()
1982
+ if cpu_info:
1983
+ cpu_info_file.parent.mkdir(parents=True, exist_ok=True)
1984
+ cpu_info_file.write_text(json.dumps(dataclasses.asdict(cpu_info)))
1985
+ return cpu_info
2000
1986
 
2001
1987
 
2002
1988
  def is_generation_hash(template: str) -> bool:
@@ -2025,38 +2011,3 @@ def get_user_tier():
2025
2011
  if authenticated_token[0]
2026
2012
  else "anonymous"
2027
2013
  )
2028
-
2029
-
2030
- def check_config_option_in_tier(
2031
- option_name: str,
2032
- allowed_tiers: list[str],
2033
- fallback_value: Any,
2034
- help_link: str | None = None,
2035
- ):
2036
- """Check if a config option is allowed for the authenticated user's current tier.
2037
-
2038
- Args:
2039
- option_name: The name of the option to check.
2040
- allowed_tiers: The tiers that are allowed to use the option.
2041
- fallback_value: The fallback value if the option is not allowed.
2042
- help_link: The help link to show to a user that is authenticated.
2043
- """
2044
- config = get_config()
2045
- current_tier = get_user_tier()
2046
-
2047
- if current_tier == "anonymous":
2048
- the_remedy = (
2049
- "You are currently logged out. Run `reflex login` to access this option."
2050
- )
2051
- else:
2052
- the_remedy = (
2053
- f"Your current subscription tier is `{current_tier}`. "
2054
- f"Please upgrade to {allowed_tiers} to access this option. "
2055
- )
2056
- if help_link:
2057
- the_remedy += f"See {help_link} for more information."
2058
-
2059
- if current_tier not in allowed_tiers:
2060
- console.warn(f"Config option `{option_name}` is restricted. {the_remedy}")
2061
- setattr(config, option_name, fallback_value)
2062
- config._set_persistent(**{option_name: fallback_value})
reflex/utils/processes.py CHANGED
@@ -10,7 +10,7 @@ import signal
10
10
  import subprocess
11
11
  from concurrent import futures
12
12
  from pathlib import Path
13
- from typing import Callable, Generator, List, Optional, Tuple, Union
13
+ from typing import Callable, Generator, Tuple
14
14
 
15
15
  import psutil
16
16
  import typer
@@ -50,7 +50,7 @@ def get_num_workers() -> int:
50
50
  return (os.cpu_count() or 1) * 2 + 1
51
51
 
52
52
 
53
- def get_process_on_port(port: int) -> Optional[psutil.Process]:
53
+ def get_process_on_port(port: int) -> psutil.Process | None:
54
54
  """Get the process on the given port.
55
55
 
56
56
  Args:
@@ -202,7 +202,7 @@ def new_process(
202
202
 
203
203
  @contextlib.contextmanager
204
204
  def run_concurrently_context(
205
- *fns: Union[Callable, Tuple],
205
+ *fns: Callable | Tuple,
206
206
  ) -> Generator[list[futures.Future], None, None]:
207
207
  """Run functions concurrently in a thread pool.
208
208
 
@@ -240,7 +240,7 @@ def run_concurrently_context(
240
240
  executor.shutdown(wait=False)
241
241
 
242
242
 
243
- def run_concurrently(*fns: Union[Callable, Tuple]) -> None:
243
+ def run_concurrently(*fns: Callable | Tuple) -> None:
244
244
  """Run functions concurrently in a thread pool.
245
245
 
246
246
  Args:
@@ -335,7 +335,7 @@ def show_status(
335
335
  status.update(f"{message} {line}")
336
336
 
337
337
 
338
- def show_progress(message: str, process: subprocess.Popen, checkpoints: List[str]):
338
+ def show_progress(message: str, process: subprocess.Popen, checkpoints: list[str]):
339
339
  """Show a progress bar for a process.
340
340
 
341
341
  Args: