reflex 0.7.13a2__py3-none-any.whl → 0.7.14a2__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 (256) hide show
  1. reflex/.templates/apps/blank/code/blank.py +0 -2
  2. reflex/app.py +64 -69
  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 +6 -3
  7. reflex/base.py +3 -2
  8. reflex/compiler/compiler.py +77 -64
  9. reflex/compiler/utils.py +8 -6
  10. reflex/components/base/app_wrap.pyi +0 -1
  11. reflex/components/base/bare.py +5 -7
  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 +49 -41
  24. reflex/components/core/auto_scroll.pyi +0 -1
  25. reflex/components/core/banner.pyi +0 -6
  26. reflex/components/core/breakpoints.py +9 -11
  27. reflex/components/core/client_side_routing.pyi +0 -2
  28. reflex/components/core/clipboard.pyi +0 -1
  29. reflex/components/core/colors.py +10 -7
  30. reflex/components/core/cond.py +4 -2
  31. reflex/components/core/debounce.py +5 -3
  32. reflex/components/core/debounce.pyi +0 -1
  33. reflex/components/core/foreach.py +8 -6
  34. reflex/components/core/html.py +3 -3
  35. reflex/components/core/html.pyi +0 -1
  36. reflex/components/core/match.py +19 -17
  37. reflex/components/core/sticky.pyi +0 -4
  38. reflex/components/core/upload.pyi +0 -5
  39. reflex/components/datadisplay/code.py +1 -2
  40. reflex/components/datadisplay/code.pyi +0 -2
  41. reflex/components/datadisplay/dataeditor.py +7 -10
  42. reflex/components/datadisplay/dataeditor.pyi +0 -1
  43. reflex/components/datadisplay/logo.py +3 -4
  44. reflex/components/datadisplay/shiki_code_block.py +8 -11
  45. reflex/components/datadisplay/shiki_code_block.pyi +0 -3
  46. reflex/components/dynamic.py +2 -3
  47. reflex/components/el/__init__.pyi +2 -0
  48. reflex/components/el/element.pyi +0 -1
  49. reflex/components/el/elements/__init__.py +1 -0
  50. reflex/components/el/elements/__init__.pyi +3 -0
  51. reflex/components/el/elements/base.pyi +0 -1
  52. reflex/components/el/elements/forms.py +14 -15
  53. reflex/components/el/elements/forms.pyi +15 -32
  54. reflex/components/el/elements/inline.pyi +0 -28
  55. reflex/components/el/elements/media.py +26 -0
  56. reflex/components/el/elements/media.pyi +259 -25
  57. reflex/components/el/elements/metadata.py +0 -1
  58. reflex/components/el/elements/metadata.pyi +0 -6
  59. reflex/components/el/elements/other.pyi +0 -7
  60. reflex/components/el/elements/scripts.pyi +0 -3
  61. reflex/components/el/elements/sectioning.pyi +0 -15
  62. reflex/components/el/elements/tables.pyi +0 -10
  63. reflex/components/el/elements/typography.pyi +0 -15
  64. reflex/components/gridjs/datatable.py +10 -13
  65. reflex/components/gridjs/datatable.pyi +0 -2
  66. reflex/components/lucide/icon.py +10 -9
  67. reflex/components/lucide/icon.pyi +0 -3
  68. reflex/components/markdown/markdown.py +6 -8
  69. reflex/components/markdown/markdown.pyi +0 -1
  70. reflex/components/moment/moment.pyi +0 -1
  71. reflex/components/next/base.py +0 -2
  72. reflex/components/next/base.pyi +0 -3
  73. reflex/components/next/image.pyi +0 -1
  74. reflex/components/next/link.pyi +0 -1
  75. reflex/components/next/video.pyi +0 -1
  76. reflex/components/plotly/plotly.pyi +0 -9
  77. reflex/components/props.py +4 -3
  78. reflex/components/radix/primitives/accordion.pyi +0 -7
  79. reflex/components/radix/primitives/base.py +1 -3
  80. reflex/components/radix/primitives/base.pyi +0 -2
  81. reflex/components/radix/primitives/drawer.pyi +0 -11
  82. reflex/components/radix/primitives/form.py +4 -8
  83. reflex/components/radix/primitives/form.pyi +0 -12
  84. reflex/components/radix/primitives/progress.py +1 -1
  85. reflex/components/radix/primitives/progress.pyi +0 -5
  86. reflex/components/radix/primitives/slider.py +1 -1
  87. reflex/components/radix/primitives/slider.pyi +0 -5
  88. reflex/components/radix/themes/base.pyi +0 -8
  89. reflex/components/radix/themes/color_mode.pyi +0 -3
  90. reflex/components/radix/themes/components/alert_dialog.py +4 -2
  91. reflex/components/radix/themes/components/alert_dialog.pyi +4 -9
  92. reflex/components/radix/themes/components/aspect_ratio.py +1 -2
  93. reflex/components/radix/themes/components/aspect_ratio.pyi +1 -3
  94. reflex/components/radix/themes/components/avatar.py +5 -2
  95. reflex/components/radix/themes/components/avatar.pyi +1 -3
  96. reflex/components/radix/themes/components/badge.py +5 -2
  97. reflex/components/radix/themes/components/badge.pyi +1 -3
  98. reflex/components/radix/themes/components/button.py +2 -3
  99. reflex/components/radix/themes/components/button.pyi +1 -3
  100. reflex/components/radix/themes/components/callout.py +1 -2
  101. reflex/components/radix/themes/components/callout.pyi +1 -7
  102. reflex/components/radix/themes/components/card.py +1 -2
  103. reflex/components/radix/themes/components/card.pyi +1 -3
  104. reflex/components/radix/themes/components/checkbox.py +7 -4
  105. reflex/components/radix/themes/components/checkbox.pyi +1 -5
  106. reflex/components/radix/themes/components/checkbox_cards.py +1 -2
  107. reflex/components/radix/themes/components/checkbox_cards.pyi +1 -4
  108. reflex/components/radix/themes/components/checkbox_group.py +1 -2
  109. reflex/components/radix/themes/components/checkbox_group.pyi +1 -4
  110. reflex/components/radix/themes/components/context_menu.py +1 -1
  111. reflex/components/radix/themes/components/context_menu.pyi +1 -14
  112. reflex/components/radix/themes/components/data_list.py +1 -2
  113. reflex/components/radix/themes/components/data_list.pyi +1 -6
  114. reflex/components/radix/themes/components/dialog.py +4 -2
  115. reflex/components/radix/themes/components/dialog.pyi +4 -9
  116. reflex/components/radix/themes/components/dropdown_menu.py +5 -2
  117. reflex/components/radix/themes/components/dropdown_menu.pyi +4 -10
  118. reflex/components/radix/themes/components/hover_card.py +4 -2
  119. reflex/components/radix/themes/components/hover_card.pyi +4 -6
  120. reflex/components/radix/themes/components/icon_button.py +7 -8
  121. reflex/components/radix/themes/components/icon_button.pyi +1 -3
  122. reflex/components/radix/themes/components/inset.py +1 -2
  123. reflex/components/radix/themes/components/inset.pyi +1 -3
  124. reflex/components/radix/themes/components/popover.py +4 -2
  125. reflex/components/radix/themes/components/popover.pyi +4 -6
  126. reflex/components/radix/themes/components/progress.py +1 -2
  127. reflex/components/radix/themes/components/progress.pyi +1 -3
  128. reflex/components/radix/themes/components/radio.py +1 -2
  129. reflex/components/radix/themes/components/radio.pyi +1 -3
  130. reflex/components/radix/themes/components/radio_cards.py +1 -2
  131. reflex/components/radix/themes/components/radio_cards.pyi +1 -4
  132. reflex/components/radix/themes/components/radio_group.py +7 -5
  133. reflex/components/radix/themes/components/radio_group.pyi +1 -6
  134. reflex/components/radix/themes/components/scroll_area.py +1 -2
  135. reflex/components/radix/themes/components/scroll_area.pyi +1 -3
  136. reflex/components/radix/themes/components/segmented_control.py +1 -2
  137. reflex/components/radix/themes/components/segmented_control.pyi +1 -4
  138. reflex/components/radix/themes/components/select.py +5 -2
  139. reflex/components/radix/themes/components/select.pyi +1 -11
  140. reflex/components/radix/themes/components/separator.py +1 -2
  141. reflex/components/radix/themes/components/separator.pyi +1 -3
  142. reflex/components/radix/themes/components/skeleton.py +1 -2
  143. reflex/components/radix/themes/components/skeleton.pyi +1 -3
  144. reflex/components/radix/themes/components/slider.py +1 -2
  145. reflex/components/radix/themes/components/slider.pyi +1 -3
  146. reflex/components/radix/themes/components/spinner.py +1 -2
  147. reflex/components/radix/themes/components/spinner.pyi +1 -3
  148. reflex/components/radix/themes/components/switch.py +1 -2
  149. reflex/components/radix/themes/components/switch.pyi +1 -3
  150. reflex/components/radix/themes/components/table.py +1 -2
  151. reflex/components/radix/themes/components/table.pyi +1 -9
  152. reflex/components/radix/themes/components/tabs.py +1 -2
  153. reflex/components/radix/themes/components/tabs.pyi +1 -7
  154. reflex/components/radix/themes/components/text_area.py +5 -2
  155. reflex/components/radix/themes/components/text_area.pyi +2 -4
  156. reflex/components/radix/themes/components/text_field.py +5 -2
  157. reflex/components/radix/themes/components/text_field.pyi +1 -5
  158. reflex/components/radix/themes/components/tooltip.py +1 -2
  159. reflex/components/radix/themes/components/tooltip.pyi +1 -3
  160. reflex/components/radix/themes/layout/base.py +5 -2
  161. reflex/components/radix/themes/layout/base.pyi +5 -3
  162. reflex/components/radix/themes/layout/box.py +1 -2
  163. reflex/components/radix/themes/layout/box.pyi +1 -3
  164. reflex/components/radix/themes/layout/center.pyi +0 -1
  165. reflex/components/radix/themes/layout/container.py +1 -2
  166. reflex/components/radix/themes/layout/container.pyi +1 -3
  167. reflex/components/radix/themes/layout/flex.py +6 -2
  168. reflex/components/radix/themes/layout/flex.pyi +1 -3
  169. reflex/components/radix/themes/layout/grid.py +6 -2
  170. reflex/components/radix/themes/layout/grid.pyi +1 -3
  171. reflex/components/radix/themes/layout/list.py +2 -1
  172. reflex/components/radix/themes/layout/list.pyi +0 -5
  173. reflex/components/radix/themes/layout/section.py +1 -2
  174. reflex/components/radix/themes/layout/section.pyi +1 -3
  175. reflex/components/radix/themes/layout/spacer.pyi +0 -1
  176. reflex/components/radix/themes/layout/stack.py +1 -1
  177. reflex/components/radix/themes/layout/stack.pyi +0 -3
  178. reflex/components/radix/themes/typography/blockquote.py +1 -1
  179. reflex/components/radix/themes/typography/blockquote.pyi +1 -3
  180. reflex/components/radix/themes/typography/code.py +5 -1
  181. reflex/components/radix/themes/typography/code.pyi +1 -3
  182. reflex/components/radix/themes/typography/heading.py +1 -1
  183. reflex/components/radix/themes/typography/heading.pyi +1 -3
  184. reflex/components/radix/themes/typography/link.py +3 -2
  185. reflex/components/radix/themes/typography/link.pyi +1 -3
  186. reflex/components/radix/themes/typography/text.py +1 -1
  187. reflex/components/radix/themes/typography/text.pyi +1 -9
  188. reflex/components/react_player/audio.py +0 -2
  189. reflex/components/react_player/audio.pyi +0 -3
  190. reflex/components/react_player/react_player.pyi +0 -1
  191. reflex/components/react_player/video.py +0 -2
  192. reflex/components/react_player/video.pyi +0 -3
  193. reflex/components/recharts/__init__.py +1 -1
  194. reflex/components/recharts/__init__.pyi +1 -1
  195. reflex/components/recharts/cartesian.py +20 -25
  196. reflex/components/recharts/cartesian.pyi +20 -37
  197. reflex/components/recharts/charts.py +2 -1
  198. reflex/components/recharts/charts.pyi +0 -12
  199. reflex/components/recharts/general.pyi +0 -6
  200. reflex/components/recharts/polar.py +5 -4
  201. reflex/components/recharts/polar.pyi +4 -10
  202. reflex/components/recharts/recharts.py +12 -10
  203. reflex/components/recharts/recharts.pyi +10 -11
  204. reflex/components/sonner/toast.py +2 -2
  205. reflex/components/sonner/toast.pyi +0 -2
  206. reflex/components/suneditor/editor.py +2 -1
  207. reflex/components/suneditor/editor.pyi +0 -1
  208. reflex/components/tags/iter_tag.py +4 -2
  209. reflex/config.py +47 -35
  210. reflex/constants/base.py +3 -3
  211. reflex/constants/compiler.py +8 -6
  212. reflex/constants/installer.py +24 -15
  213. reflex/custom_components/custom_components.py +1 -2
  214. reflex/event.py +58 -60
  215. reflex/experimental/__init__.py +2 -2
  216. reflex/experimental/client_state.py +9 -4
  217. reflex/experimental/layout.pyi +0 -5
  218. reflex/istate/manager.py +15 -19
  219. reflex/istate/proxy.py +19 -12
  220. reflex/model.py +6 -4
  221. reflex/plugins/base.py +8 -0
  222. reflex/plugins/tailwind_v3.py +8 -0
  223. reflex/plugins/tailwind_v4.py +8 -0
  224. reflex/reflex.py +9 -11
  225. reflex/route.py +7 -9
  226. reflex/state.py +66 -70
  227. reflex/style.py +3 -1
  228. reflex/testing.py +46 -29
  229. reflex/utils/build.py +2 -1
  230. reflex/utils/console.py +9 -17
  231. reflex/utils/exec.py +9 -11
  232. reflex/utils/format.py +21 -24
  233. reflex/utils/imports.py +4 -3
  234. reflex/utils/lazy_loader.py +3 -3
  235. reflex/utils/misc.py +2 -1
  236. reflex/utils/net.py +2 -2
  237. reflex/utils/path_ops.py +2 -1
  238. reflex/utils/prerequisites.py +67 -38
  239. reflex/utils/processes.py +4 -6
  240. reflex/utils/pyi_generator.py +46 -41
  241. reflex/utils/redir.py +1 -1
  242. reflex/utils/serializers.py +4 -4
  243. reflex/utils/telemetry.py +20 -2
  244. reflex/utils/types.py +16 -13
  245. reflex/vars/base.py +96 -109
  246. reflex/vars/datetime.py +2 -1
  247. reflex/vars/dep_tracking.py +19 -28
  248. reflex/vars/number.py +6 -7
  249. reflex/vars/object.py +5 -6
  250. reflex/vars/sequence.py +11 -11
  251. {reflex-0.7.13a2.dist-info → reflex-0.7.14a2.dist-info}/METADATA +1 -1
  252. reflex-0.7.14a2.dist-info/RECORD +407 -0
  253. reflex-0.7.13a2.dist-info/RECORD +0 -407
  254. {reflex-0.7.13a2.dist-info → reflex-0.7.14a2.dist-info}/WHEEL +0 -0
  255. {reflex-0.7.13a2.dist-info → reflex-0.7.14a2.dist-info}/entry_points.txt +0 -0
  256. {reflex-0.7.13a2.dist-info → reflex-0.7.14a2.dist-info}/licenses/LICENSE +0 -0
reflex/utils/console.py CHANGED
@@ -59,9 +59,8 @@ def set_log_level(log_level: LogLevel | None):
59
59
  if log_level is None:
60
60
  return
61
61
  if not isinstance(log_level, LogLevel):
62
- raise TypeError(
63
- f"log_level must be a LogLevel enum value, got {log_level} of type {type(log_level)} instead."
64
- )
62
+ msg = f"log_level must be a LogLevel enum value, got {log_level} of type {type(log_level)} instead."
63
+ raise TypeError(msg)
65
64
  global _LOG_LEVEL
66
65
  if log_level != _LOG_LEVEL:
67
66
  # Set the loglevel persistenly for subprocesses.
@@ -89,8 +88,7 @@ def print(msg: str, dedupe: bool = False, **kwargs):
89
88
  if dedupe:
90
89
  if msg in _EMITTED_PRINTS:
91
90
  return
92
- else:
93
- _EMITTED_PRINTS.add(msg)
91
+ _EMITTED_PRINTS.add(msg)
94
92
  _console.print(msg, **kwargs)
95
93
 
96
94
 
@@ -107,8 +105,7 @@ def debug(msg: str, dedupe: bool = False, **kwargs):
107
105
  if dedupe:
108
106
  if msg_ in _EMITTED_DEBUG:
109
107
  return
110
- else:
111
- _EMITTED_DEBUG.add(msg_)
108
+ _EMITTED_DEBUG.add(msg_)
112
109
  if progress := kwargs.pop("progress", None):
113
110
  progress.console.print(msg_, **kwargs)
114
111
  else:
@@ -127,8 +124,7 @@ def info(msg: str, dedupe: bool = False, **kwargs):
127
124
  if dedupe:
128
125
  if msg in _EMITTED_INFO:
129
126
  return
130
- else:
131
- _EMITTED_INFO.add(msg)
127
+ _EMITTED_INFO.add(msg)
132
128
  print(f"[cyan]Info: {msg}[/cyan]", **kwargs)
133
129
 
134
130
 
@@ -144,8 +140,7 @@ def success(msg: str, dedupe: bool = False, **kwargs):
144
140
  if dedupe:
145
141
  if msg in _EMITTED_SUCCESS:
146
142
  return
147
- else:
148
- _EMITTED_SUCCESS.add(msg)
143
+ _EMITTED_SUCCESS.add(msg)
149
144
  print(f"[green]Success: {msg}[/green]", **kwargs)
150
145
 
151
146
 
@@ -161,8 +156,7 @@ def log(msg: str, dedupe: bool = False, **kwargs):
161
156
  if dedupe:
162
157
  if msg in _EMITTED_LOGS:
163
158
  return
164
- else:
165
- _EMITTED_LOGS.add(msg)
159
+ _EMITTED_LOGS.add(msg)
166
160
  _console.log(msg, **kwargs)
167
161
 
168
162
 
@@ -188,8 +182,7 @@ def warn(msg: str, dedupe: bool = False, **kwargs):
188
182
  if dedupe:
189
183
  if msg in _EMIITED_WARNINGS:
190
184
  return
191
- else:
192
- _EMIITED_WARNINGS.add(msg)
185
+ _EMIITED_WARNINGS.add(msg)
193
186
  print(f"[orange1]Warning: {msg}[/orange1]", **kwargs)
194
187
 
195
188
 
@@ -271,8 +264,7 @@ def error(msg: str, dedupe: bool = False, **kwargs):
271
264
  if dedupe:
272
265
  if msg in _EMITTED_ERRORS:
273
266
  return
274
- else:
275
- _EMITTED_ERRORS.add(msg)
267
+ _EMITTED_ERRORS.add(msg)
276
268
  print(f"[red]{msg}[/red]", **kwargs)
277
269
 
278
270
 
reflex/utils/exec.py CHANGED
@@ -244,14 +244,12 @@ def get_app_file() -> Path:
244
244
  sys.path.insert(0, current_working_dir)
245
245
  module_spec = importlib.util.find_spec(get_app_module())
246
246
  if module_spec is None:
247
- raise ImportError(
248
- f"Module {get_app_module()} not found. Make sure the module is installed."
249
- )
247
+ msg = f"Module {get_app_module()} not found. Make sure the module is installed."
248
+ raise ImportError(msg)
250
249
  file_name = module_spec.origin
251
250
  if file_name is None:
252
- raise ImportError(
253
- f"Module {get_app_module()} not found. Make sure the module is installed."
254
- )
251
+ msg = f"Module {get_app_module()} not found. Make sure the module is installed."
252
+ raise ImportError(msg)
255
253
  return Path(file_name).resolve()
256
254
 
257
255
 
@@ -300,13 +298,12 @@ def get_reload_paths() -> Sequence[Path]:
300
298
  The reload paths for the backend.
301
299
  """
302
300
  config = get_config()
303
- reload_paths = [Path(config.app_name).parent]
304
- if config.app_module is not None and config.app_module.__file__:
305
- module_path = Path(config.app_module.__file__).resolve().parent
301
+ reload_paths = [Path.cwd()]
302
+ if (spec := importlib.util.find_spec(config.module)) is not None and spec.origin:
303
+ module_path = Path(spec.origin).resolve().parent
306
304
 
307
305
  while module_path.parent.name and any(
308
- sibling_file.name == "__init__.py"
309
- for sibling_file in module_path.parent.iterdir()
306
+ sibling_file.name == "__init__.py" for sibling_file in module_path.iterdir()
310
307
  ):
311
308
  # go up a level to find dir without `__init__.py`
312
309
  module_path = module_path.parent
@@ -383,6 +380,7 @@ HOTRELOAD_IGNORE_EXTENSIONS = (
383
380
  "json",
384
381
  "sh",
385
382
  "bash",
383
+ "log",
386
384
  )
387
385
 
388
386
  HOTRELOAD_IGNORE_PATTERNS = (
reflex/utils/format.py CHANGED
@@ -73,7 +73,8 @@ def get_close_char(open: str, close: str | None = None) -> str:
73
73
  if close is not None:
74
74
  return close
75
75
  if open not in WRAP_MAP:
76
- raise ValueError(f"Invalid wrap open: {open}, must be one of {WRAP_MAP.keys()}")
76
+ msg = f"Invalid wrap open: {open}, must be one of {WRAP_MAP.keys()}"
77
+ raise ValueError(msg)
77
78
  return WRAP_MAP[open]
78
79
 
79
80
 
@@ -187,8 +188,7 @@ def to_camel_case(text: str, treat_hyphens_as_underscores: bool = True) -> str:
187
188
  # Capitalize the first letter of each word except the first one
188
189
  if len(words) == 1:
189
190
  return words[0]
190
- converted_word = words[0] + "".join([w.capitalize() for w in words[1:]])
191
- return converted_word
191
+ return words[0] + "".join([w.capitalize() for w in words[1:]])
192
192
 
193
193
 
194
194
  def to_title_case(text: str, sep: str = "") -> str:
@@ -264,17 +264,13 @@ def _escape_js_string(string: str) -> str:
264
264
  if segment.startswith("${") and segment.endswith("}"):
265
265
  # Return the `${}` segment unchanged
266
266
  return segment
267
- else:
268
- # Escape backticks in the segment
269
- segment = segment.replace(r"\`", "`")
270
- segment = segment.replace("`", r"\`")
271
- return segment
267
+ # Escape backticks in the segment
268
+ return segment.replace(r"\`", "`").replace("`", r"\`")
272
269
 
273
270
  # Split the string into parts, keeping the `${}` segments
274
271
  parts = re.split(r"(\$\{.*?\})", string)
275
272
  escaped_parts = [escape_outside_segments(part) for part in parts]
276
- escaped_string = "".join(escaped_parts)
277
- return escaped_string
273
+ return "".join(escaped_parts)
278
274
 
279
275
 
280
276
  def _wrap_js_string(string: str) -> str:
@@ -287,8 +283,7 @@ def _wrap_js_string(string: str) -> str:
287
283
  The wrapped string.
288
284
  """
289
285
  string = wrap(string, "`")
290
- string = wrap(string, "{")
291
- return string
286
+ return wrap(string, "{")
292
287
 
293
288
 
294
289
  def format_string(string: str) -> str:
@@ -402,13 +397,13 @@ def format_prop(
402
397
  return str(Var.create(prop))
403
398
 
404
399
  # Handle other types.
405
- elif isinstance(prop, str):
400
+ if isinstance(prop, str):
406
401
  if is_wrapped(prop, "{"):
407
402
  return prop
408
403
  return json_dumps(prop)
409
404
 
410
405
  # For dictionaries, convert any properties to strings.
411
- elif isinstance(prop, dict):
406
+ if isinstance(prop, dict):
412
407
  prop = serializers.serialize_dict(prop) # pyright: ignore [reportAttributeAccessIssue]
413
408
 
414
409
  else:
@@ -417,11 +412,13 @@ def format_prop(
417
412
  except exceptions.InvalidStylePropError:
418
413
  raise
419
414
  except TypeError as e:
420
- raise TypeError(f"Could not format prop: {prop} of type {type(prop)}") from e
415
+ msg = f"Could not format prop: {prop} of type {type(prop)}"
416
+ raise TypeError(msg) from e
421
417
 
422
418
  # Wrap the variable in braces.
423
419
  if not isinstance(prop, str):
424
- raise ValueError(f"Invalid prop: {prop}. Expected a string.")
420
+ msg = f"Invalid prop: {prop}. Expected a string."
421
+ raise ValueError(msg)
425
422
  return wrap(prop, "{", check_first=False)
426
423
 
427
424
 
@@ -591,9 +588,8 @@ def format_queue_events(
591
588
  elif isinstance(spec, type(lambda: None)):
592
589
  specs = call_event_fn(spec, args_spec or _default_args_spec) # pyright: ignore [reportAssignmentType, reportArgumentType]
593
590
  if isinstance(specs, Var):
594
- raise ValueError(
595
- f"Invalid event spec: {specs}. Expected a list of EventSpecs."
596
- )
591
+ msg = f"Invalid event spec: {specs}. Expected a list of EventSpecs."
592
+ raise ValueError(msg)
597
593
  payloads.extend(format_event(s) for s in specs)
598
594
 
599
595
  # Return the final code snippet, expecting queueEvents, processEvent, and socket to be in scope.
@@ -662,12 +658,14 @@ def format_library_name(library_fullname: str | dict[str, Any]) -> str:
662
658
  # If input is a dictionary, extract the 'name' key
663
659
  if isinstance(library_fullname, dict):
664
660
  if "name" not in library_fullname:
665
- raise KeyError("Dictionary input must contain a 'name' key")
661
+ msg = "Dictionary input must contain a 'name' key"
662
+ raise KeyError(msg)
666
663
  library_fullname = library_fullname["name"]
667
664
 
668
665
  # Process the library name as a string
669
666
  if not isinstance(library_fullname, str):
670
- raise TypeError("Library name must be a string")
667
+ msg = "Library name must be a string"
668
+ raise TypeError(msg)
671
669
 
672
670
  if library_fullname.startswith("https://"):
673
671
  return library_fullname
@@ -764,9 +762,8 @@ def format_data_editor_column(col: str | dict):
764
762
  if isinstance(col, Var):
765
763
  return col
766
764
 
767
- raise ValueError(
768
- f"unexpected type ({(type(col).__name__)}: {col}) for column header in data_editor"
769
- )
765
+ msg = f"unexpected type ({(type(col).__name__)}: {col}) for column header in data_editor"
766
+ raise ValueError(msg)
770
767
 
771
768
 
772
769
  def format_data_editor_cell(cell: Any):
reflex/utils/imports.py CHANGED
@@ -127,10 +127,11 @@ class ImportVar:
127
127
  """
128
128
  if self.alias:
129
129
  return (
130
- self.alias if self.is_default else " as ".join([self.tag, self.alias]) # pyright: ignore [reportCallIssue,reportArgumentType]
130
+ self.alias
131
+ if self.is_default
132
+ else (self.tag + " as " + self.alias if self.tag else self.alias)
131
133
  )
132
- else:
133
- return self.tag or ""
134
+ return self.tag or ""
134
135
 
135
136
 
136
137
  ImportTypes = str | ImportVar | list[str | ImportVar] | list[ImportVar]
@@ -65,7 +65,7 @@ def attach(
65
65
  def __getattr__(name: str): # noqa: N807
66
66
  if name in submodules:
67
67
  return importlib.import_module(f"{package_name}.{name}")
68
- elif name in attr_to_modules:
68
+ if name in attr_to_modules:
69
69
  submod_path = f"{package_name}.{attr_to_modules[name]}"
70
70
  submod = importlib.import_module(submod_path)
71
71
  attr = getattr(submod, name)
@@ -78,8 +78,8 @@ def attach(
78
78
  pkg.__dict__[name] = attr
79
79
 
80
80
  return attr
81
- else:
82
- raise AttributeError(f"No {package_name} attribute {name}")
81
+ msg = f"No {package_name} attribute {name}"
82
+ raise AttributeError(msg)
83
83
 
84
84
  def __dir__(): # noqa: N807
85
85
  return __all__
reflex/utils/misc.py CHANGED
@@ -20,5 +20,6 @@ async def run_in_thread(func: Callable) -> Any:
20
20
  Any: The return value of the function.
21
21
  """
22
22
  if asyncio.coroutines.iscoroutinefunction(func):
23
- raise ValueError("func must be a non-async function")
23
+ msg = "func must be a non-async function"
24
+ raise ValueError(msg)
24
25
  return await asyncio.get_event_loop().run_in_executor(None, func)
reflex/utils/net.py CHANGED
@@ -19,7 +19,7 @@ def _httpx_verify_kwarg() -> bool:
19
19
  Returns:
20
20
  True if SSL verification is enabled, False otherwise
21
21
  """
22
- from ..config import environment
22
+ from reflex.config import environment
23
23
 
24
24
  return not environment.SSL_NO_VERIFY.get()
25
25
 
@@ -131,7 +131,7 @@ def _httpx_local_address_kwarg() -> str:
131
131
  Returns:
132
132
  The local address to bind to
133
133
  """
134
- from ..config import environment
134
+ from reflex.config import environment
135
135
 
136
136
  return environment.REFLEX_HTTP_CLIENT_BIND_ADDRESS.get() or (
137
137
  "::" if _should_use_ipv6() else "0.0.0.0"
reflex/utils/path_ops.py CHANGED
@@ -300,7 +300,8 @@ def update_directory_tree(src: Path, dest: Path):
300
300
  ValueError: If the source is not a directory
301
301
  """
302
302
  if not src.is_dir():
303
- raise ValueError(f"Source {src} is not a directory")
303
+ msg = f"Source {src} is not a directory"
304
+ raise ValueError(msg)
304
305
 
305
306
  # Ensure the destination directory exists
306
307
  dest.mkdir(parents=True, exist_ok=True)
@@ -129,7 +129,6 @@ def check_latest_package_version(package_name: str):
129
129
  )
130
130
  except Exception:
131
131
  console.debug(f"Failed to check for the latest version of {package_name}.")
132
- pass
133
132
 
134
133
 
135
134
  def get_or_set_last_reflex_version_check_datetime():
@@ -255,9 +254,8 @@ def get_nodejs_compatible_package_managers(
255
254
  package_managers = list(filter(None, package_managers))
256
255
 
257
256
  if not package_managers and raise_on_none:
258
- raise FileNotFoundError(
259
- "Bun or npm not found. You might need to rerun `reflex init` or install either."
260
- )
257
+ msg = "Bun or npm not found. You might need to rerun `reflex init` or install either."
258
+ raise FileNotFoundError(msg)
261
259
 
262
260
  return package_managers
263
261
 
@@ -310,9 +308,8 @@ def get_js_package_executor(raise_on_none: bool = False) -> Sequence[Sequence[st
310
308
  package_managers = list(filter(None, package_managers))
311
309
 
312
310
  if not package_managers and raise_on_none:
313
- raise FileNotFoundError(
314
- "Bun or npm not found. You might need to rerun `reflex init` or install either."
315
- )
311
+ msg = "Bun or npm not found. You might need to rerun `reflex init` or install either."
312
+ raise FileNotFoundError(msg)
316
313
 
317
314
  return package_managers
318
315
 
@@ -345,10 +342,11 @@ def _check_app_name(config: Config):
345
342
  RuntimeError: If the app name is not set in the config.
346
343
  """
347
344
  if not config.app_name:
348
- raise RuntimeError(
345
+ msg = (
349
346
  "Cannot get the app module because `app_name` is not set in rxconfig! "
350
347
  "If this error occurs in a reflex test case, ensure that `get_app` is mocked."
351
348
  )
349
+ raise RuntimeError(msg)
352
350
 
353
351
 
354
352
  def get_app(reload: bool = False) -> ModuleType:
@@ -395,11 +393,14 @@ def get_app(reload: bool = False) -> ModuleType:
395
393
  return app
396
394
 
397
395
 
398
- def get_and_validate_app(reload: bool = False) -> AppInfo:
396
+ def get_and_validate_app(
397
+ reload: bool = False, check_if_schema_up_to_date: bool = False
398
+ ) -> AppInfo:
399
399
  """Get the app instance based on the default config and validate it.
400
400
 
401
401
  Args:
402
402
  reload: Re-import the app module from disk
403
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
403
404
 
404
405
  Returns:
405
406
  The app instance and the app module.
@@ -412,23 +413,34 @@ def get_and_validate_app(reload: bool = False) -> AppInfo:
412
413
  app_module = get_app(reload=reload)
413
414
  app = getattr(app_module, constants.CompileVars.APP)
414
415
  if not isinstance(app, App):
415
- raise RuntimeError(
416
- "The app instance in the specified app_module_import in rxconfig must be an instance of rx.App."
417
- )
416
+ msg = "The app instance in the specified app_module_import in rxconfig must be an instance of rx.App."
417
+ raise RuntimeError(msg)
418
+
419
+ if check_if_schema_up_to_date:
420
+ check_schema_up_to_date()
421
+
418
422
  return AppInfo(app=app, module=app_module)
419
423
 
420
424
 
421
- def validate_app(reload: bool = False) -> None:
425
+ def validate_app(
426
+ reload: bool = False, check_if_schema_up_to_date: bool = False
427
+ ) -> None:
422
428
  """Validate the app instance based on the default config.
423
429
 
424
430
  Args:
425
431
  reload: Re-import the app module from disk
432
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
426
433
  """
427
- get_and_validate_app(reload=reload)
434
+ get_and_validate_app(
435
+ reload=reload, check_if_schema_up_to_date=check_if_schema_up_to_date
436
+ )
428
437
 
429
438
 
430
439
  def get_compiled_app(
431
- reload: bool = False, export: bool = False, dry_run: bool = False
440
+ reload: bool = False,
441
+ export: bool = False,
442
+ dry_run: bool = False,
443
+ check_if_schema_up_to_date: bool = False,
432
444
  ) -> ModuleType:
433
445
  """Get the app module based on the default config after first compiling it.
434
446
 
@@ -436,11 +448,14 @@ def get_compiled_app(
436
448
  reload: Re-import the app module from disk
437
449
  export: Compile the app for export
438
450
  dry_run: If True, do not write the compiled app to disk.
451
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
439
452
 
440
453
  Returns:
441
454
  The compiled app based on the default config.
442
455
  """
443
- app, app_module = get_and_validate_app(reload=reload)
456
+ app, app_module = get_and_validate_app(
457
+ reload=reload, check_if_schema_up_to_date=check_if_schema_up_to_date
458
+ )
444
459
  # For py3.9 compatibility when redis is used, we MUST add any decorator pages
445
460
  # before compiling the app in a thread to avoid event loop error (REF-2172).
446
461
  app._apply_decorated_pages()
@@ -449,7 +464,10 @@ def get_compiled_app(
449
464
 
450
465
 
451
466
  def compile_app(
452
- reload: bool = False, export: bool = False, dry_run: bool = False
467
+ reload: bool = False,
468
+ export: bool = False,
469
+ dry_run: bool = False,
470
+ check_if_schema_up_to_date: bool = False,
453
471
  ) -> None:
454
472
  """Compile the app module based on the default config.
455
473
 
@@ -457,8 +475,14 @@ def compile_app(
457
475
  reload: Re-import the app module from disk
458
476
  export: Compile the app for export
459
477
  dry_run: If True, do not write the compiled app to disk.
478
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
460
479
  """
461
- get_compiled_app(reload=reload, export=export, dry_run=dry_run)
480
+ get_compiled_app(
481
+ reload=reload,
482
+ export=export,
483
+ dry_run=dry_run,
484
+ check_if_schema_up_to_date=check_if_schema_up_to_date,
485
+ )
462
486
 
463
487
 
464
488
  def _can_colorize() -> bool:
@@ -503,20 +527,23 @@ def _can_colorize() -> bool:
503
527
  return file.isatty()
504
528
 
505
529
 
506
- def compile_or_validate_app(compile: bool = False) -> bool:
530
+ def compile_or_validate_app(
531
+ compile: bool = False, check_if_schema_up_to_date: bool = False
532
+ ) -> bool:
507
533
  """Compile or validate the app module based on the default config.
508
534
 
509
535
  Args:
510
536
  compile: Whether to compile the app.
537
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
511
538
 
512
539
  Returns:
513
540
  If the app is compiled successfully.
514
541
  """
515
542
  try:
516
543
  if compile:
517
- compile_app()
544
+ compile_app(check_if_schema_up_to_date=check_if_schema_up_to_date)
518
545
  else:
519
- validate_app()
546
+ validate_app(check_if_schema_up_to_date=check_if_schema_up_to_date)
520
547
  except Exception as e:
521
548
  if isinstance(e, click.exceptions.Exit):
522
549
  return False
@@ -575,9 +602,8 @@ def parse_redis_url() -> str | None:
575
602
  if not config.redis_url:
576
603
  return None
577
604
  if not config.redis_url.startswith(("redis://", "rediss://", "unix://")):
578
- raise ValueError(
579
- "REDIS_URL must start with 'redis://', 'rediss://', or 'unix://'."
580
- )
605
+ msg = "REDIS_URL must start with 'redis://', 'rediss://', or 'unix://'."
606
+ raise ValueError(msg)
581
607
  return config.redis_url
582
608
 
583
609
 
@@ -1157,15 +1183,16 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
1157
1183
  raise click.exceptions.Exit(1) from None
1158
1184
 
1159
1185
  # Save the script to a temporary file.
1160
- script = Path(tempfile.NamedTemporaryFile().name)
1186
+ with tempfile.NamedTemporaryFile() as tempfile_file:
1187
+ script = Path(tempfile_file.name)
1161
1188
 
1162
- script.write_text(response.text)
1189
+ script.write_text(response.text)
1163
1190
 
1164
- # Run the script.
1165
- env = {**os.environ, **env}
1166
- process = processes.new_process(["bash", str(script), *args], env=env)
1167
- show = processes.show_status if show_status else processes.show_logs
1168
- show(f"Installing {url}", process)
1191
+ # Run the script.
1192
+ env = {**os.environ, **env}
1193
+ process = processes.new_process(["bash", str(script), *args], env=env)
1194
+ show = processes.show_status if show_status else processes.show_logs
1195
+ show(f"Installing {url}", process)
1169
1196
 
1170
1197
 
1171
1198
  def install_bun():
@@ -1213,7 +1240,8 @@ def install_bun():
1213
1240
  )
1214
1241
  else:
1215
1242
  if path_ops.which("unzip") is None:
1216
- raise SystemPackageMissingError("unzip")
1243
+ msg = "unzip"
1244
+ raise SystemPackageMissingError(msg)
1217
1245
 
1218
1246
  # Run the bun install script.
1219
1247
  download_and_run(
@@ -1262,13 +1290,15 @@ def cached_procedure(
1262
1290
  ValueError: If both cache_file and cache_file_fn are provided.
1263
1291
  """
1264
1292
  if cache_file and cache_file_fn is not None:
1265
- raise ValueError("cache_file and cache_file_fn cannot both be provided.")
1293
+ msg = "cache_file and cache_file_fn cannot both be provided."
1294
+ raise ValueError(msg)
1266
1295
 
1267
1296
  def _inner_decorator(func: Callable):
1268
1297
  def _inner(*args, **kwargs):
1269
1298
  _cache_file = cache_file_fn() if cache_file_fn is not None else cache_file
1270
1299
  if not _cache_file:
1271
- raise ValueError("Unknown cache file, cannot cache result.")
1300
+ msg = "Unknown cache file, cannot cache result."
1301
+ raise ValueError(msg)
1272
1302
  payload = _read_cached_procedure_file(_cache_file)
1273
1303
  new_payload = payload_fn(*args, **kwargs)
1274
1304
  if payload != new_payload:
@@ -1446,7 +1476,7 @@ def validate_bun(bun_path: Path | None = None):
1446
1476
  "Failed to obtain bun version. Make sure the specified bun path in your config is correct."
1447
1477
  )
1448
1478
  raise click.exceptions.Exit(1)
1449
- elif bun_version < version.parse(constants.Bun.MIN_VERSION):
1479
+ if bun_version < version.parse(constants.Bun.MIN_VERSION):
1450
1480
  console.warn(
1451
1481
  f"Reflex requires bun version {constants.Bun.MIN_VERSION} or higher to run, but the detected version is "
1452
1482
  f"{bun_version}. If you have specified a custom bun path in your config, make sure to provide one "
@@ -1657,8 +1687,7 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
1657
1687
  if asset is None:
1658
1688
  console.warn(f"Templates metadata not found for version {version}")
1659
1689
  return {}
1660
- else:
1661
- templates_url = asset["browser_download_url"]
1690
+ templates_url = asset["browser_download_url"]
1662
1691
 
1663
1692
  templates_data = net.get(templates_url, follow_redirects=True).json()["templates"]
1664
1693
 
@@ -1864,7 +1893,7 @@ def initialize_app(app_name: str, template: str | None = None) -> str | None:
1864
1893
  # Check if the app is already initialized.
1865
1894
  if constants.Config.FILE.exists():
1866
1895
  telemetry.send("reinit")
1867
- return
1896
+ return None
1868
1897
 
1869
1898
  templates: dict[str, Template] = {}
1870
1899
 
reflex/utils/processes.py CHANGED
@@ -137,11 +137,10 @@ def handle_port(service_name: str, port: int, auto_increment: bool) -> int:
137
137
  return port
138
138
  if auto_increment:
139
139
  return change_port(port, service_name)
140
- else:
141
- console.error(
142
- f"{service_name.capitalize()} port: {port} is already in use by PID: {process.pid}."
143
- )
144
- raise click.exceptions.Exit()
140
+ console.error(
141
+ f"{service_name.capitalize()} port: {port} is already in use by PID: {process.pid}."
142
+ )
143
+ raise click.exceptions.Exit
145
144
 
146
145
 
147
146
  @overload
@@ -316,7 +315,6 @@ def stream_logs(
316
315
  # But if the process is still running that is weird.
317
316
  raise
318
317
  # If the process exited, break out of the loop for post processing.
319
- pass
320
318
 
321
319
  # Check if the process failed (not printing the logs for SIGINT).
322
320