reflex 0.7.13a2__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 (261) hide show
  1. reflex/.templates/apps/blank/code/blank.py +0 -2
  2. reflex/app.py +85 -89
  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.pyi +0 -7
  81. reflex/components/radix/primitives/base.py +1 -3
  82. reflex/components/radix/primitives/base.pyi +0 -2
  83. reflex/components/radix/primitives/drawer.pyi +0 -11
  84. reflex/components/radix/primitives/form.py +4 -8
  85. reflex/components/radix/primitives/form.pyi +0 -12
  86. reflex/components/radix/primitives/progress.py +1 -1
  87. reflex/components/radix/primitives/progress.pyi +0 -5
  88. reflex/components/radix/primitives/slider.py +1 -1
  89. reflex/components/radix/primitives/slider.pyi +0 -5
  90. reflex/components/radix/themes/base.pyi +0 -8
  91. reflex/components/radix/themes/color_mode.pyi +0 -3
  92. reflex/components/radix/themes/components/alert_dialog.py +4 -2
  93. reflex/components/radix/themes/components/alert_dialog.pyi +4 -9
  94. reflex/components/radix/themes/components/aspect_ratio.py +1 -2
  95. reflex/components/radix/themes/components/aspect_ratio.pyi +1 -3
  96. reflex/components/radix/themes/components/avatar.py +5 -2
  97. reflex/components/radix/themes/components/avatar.pyi +1 -3
  98. reflex/components/radix/themes/components/badge.py +5 -2
  99. reflex/components/radix/themes/components/badge.pyi +1 -3
  100. reflex/components/radix/themes/components/button.py +2 -3
  101. reflex/components/radix/themes/components/button.pyi +1 -3
  102. reflex/components/radix/themes/components/callout.py +1 -2
  103. reflex/components/radix/themes/components/callout.pyi +1 -7
  104. reflex/components/radix/themes/components/card.py +1 -2
  105. reflex/components/radix/themes/components/card.pyi +1 -3
  106. reflex/components/radix/themes/components/checkbox.py +7 -4
  107. reflex/components/radix/themes/components/checkbox.pyi +1 -5
  108. reflex/components/radix/themes/components/checkbox_cards.py +1 -2
  109. reflex/components/radix/themes/components/checkbox_cards.pyi +1 -4
  110. reflex/components/radix/themes/components/checkbox_group.py +1 -2
  111. reflex/components/radix/themes/components/checkbox_group.pyi +1 -4
  112. reflex/components/radix/themes/components/context_menu.py +1 -1
  113. reflex/components/radix/themes/components/context_menu.pyi +1 -14
  114. reflex/components/radix/themes/components/data_list.py +1 -2
  115. reflex/components/radix/themes/components/data_list.pyi +1 -6
  116. reflex/components/radix/themes/components/dialog.py +4 -2
  117. reflex/components/radix/themes/components/dialog.pyi +4 -9
  118. reflex/components/radix/themes/components/dropdown_menu.py +5 -2
  119. reflex/components/radix/themes/components/dropdown_menu.pyi +4 -10
  120. reflex/components/radix/themes/components/hover_card.py +4 -2
  121. reflex/components/radix/themes/components/hover_card.pyi +4 -6
  122. reflex/components/radix/themes/components/icon_button.py +7 -8
  123. reflex/components/radix/themes/components/icon_button.pyi +1 -3
  124. reflex/components/radix/themes/components/inset.py +1 -2
  125. reflex/components/radix/themes/components/inset.pyi +1 -3
  126. reflex/components/radix/themes/components/popover.py +4 -2
  127. reflex/components/radix/themes/components/popover.pyi +4 -6
  128. reflex/components/radix/themes/components/progress.py +1 -2
  129. reflex/components/radix/themes/components/progress.pyi +1 -3
  130. reflex/components/radix/themes/components/radio.py +1 -2
  131. reflex/components/radix/themes/components/radio.pyi +1 -3
  132. reflex/components/radix/themes/components/radio_cards.py +1 -2
  133. reflex/components/radix/themes/components/radio_cards.pyi +1 -4
  134. reflex/components/radix/themes/components/radio_group.py +7 -5
  135. reflex/components/radix/themes/components/radio_group.pyi +1 -6
  136. reflex/components/radix/themes/components/scroll_area.py +1 -2
  137. reflex/components/radix/themes/components/scroll_area.pyi +1 -3
  138. reflex/components/radix/themes/components/segmented_control.py +1 -2
  139. reflex/components/radix/themes/components/segmented_control.pyi +1 -4
  140. reflex/components/radix/themes/components/select.py +5 -2
  141. reflex/components/radix/themes/components/select.pyi +1 -11
  142. reflex/components/radix/themes/components/separator.py +1 -2
  143. reflex/components/radix/themes/components/separator.pyi +1 -3
  144. reflex/components/radix/themes/components/skeleton.py +1 -2
  145. reflex/components/radix/themes/components/skeleton.pyi +1 -3
  146. reflex/components/radix/themes/components/slider.py +1 -2
  147. reflex/components/radix/themes/components/slider.pyi +1 -3
  148. reflex/components/radix/themes/components/spinner.py +1 -2
  149. reflex/components/radix/themes/components/spinner.pyi +1 -3
  150. reflex/components/radix/themes/components/switch.py +1 -2
  151. reflex/components/radix/themes/components/switch.pyi +1 -3
  152. reflex/components/radix/themes/components/table.py +1 -2
  153. reflex/components/radix/themes/components/table.pyi +1 -9
  154. reflex/components/radix/themes/components/tabs.py +1 -2
  155. reflex/components/radix/themes/components/tabs.pyi +1 -7
  156. reflex/components/radix/themes/components/text_area.py +5 -2
  157. reflex/components/radix/themes/components/text_area.pyi +2 -4
  158. reflex/components/radix/themes/components/text_field.py +5 -2
  159. reflex/components/radix/themes/components/text_field.pyi +1 -5
  160. reflex/components/radix/themes/components/tooltip.py +1 -2
  161. reflex/components/radix/themes/components/tooltip.pyi +1 -3
  162. reflex/components/radix/themes/layout/base.py +5 -2
  163. reflex/components/radix/themes/layout/base.pyi +5 -3
  164. reflex/components/radix/themes/layout/box.py +1 -2
  165. reflex/components/radix/themes/layout/box.pyi +1 -3
  166. reflex/components/radix/themes/layout/center.pyi +0 -1
  167. reflex/components/radix/themes/layout/container.py +1 -2
  168. reflex/components/radix/themes/layout/container.pyi +1 -3
  169. reflex/components/radix/themes/layout/flex.py +6 -2
  170. reflex/components/radix/themes/layout/flex.pyi +1 -3
  171. reflex/components/radix/themes/layout/grid.py +6 -2
  172. reflex/components/radix/themes/layout/grid.pyi +1 -3
  173. reflex/components/radix/themes/layout/list.py +2 -1
  174. reflex/components/radix/themes/layout/list.pyi +0 -5
  175. reflex/components/radix/themes/layout/section.py +1 -2
  176. reflex/components/radix/themes/layout/section.pyi +1 -3
  177. reflex/components/radix/themes/layout/spacer.pyi +0 -1
  178. reflex/components/radix/themes/layout/stack.py +1 -1
  179. reflex/components/radix/themes/layout/stack.pyi +0 -3
  180. reflex/components/radix/themes/typography/blockquote.py +1 -1
  181. reflex/components/radix/themes/typography/blockquote.pyi +1 -3
  182. reflex/components/radix/themes/typography/code.py +5 -1
  183. reflex/components/radix/themes/typography/code.pyi +1 -3
  184. reflex/components/radix/themes/typography/heading.py +1 -1
  185. reflex/components/radix/themes/typography/heading.pyi +1 -3
  186. reflex/components/radix/themes/typography/link.py +3 -2
  187. reflex/components/radix/themes/typography/link.pyi +1 -3
  188. reflex/components/radix/themes/typography/text.py +1 -1
  189. reflex/components/radix/themes/typography/text.pyi +1 -9
  190. reflex/components/react_player/audio.py +0 -2
  191. reflex/components/react_player/audio.pyi +0 -3
  192. reflex/components/react_player/react_player.pyi +0 -1
  193. reflex/components/react_player/video.py +0 -2
  194. reflex/components/react_player/video.pyi +0 -3
  195. reflex/components/recharts/__init__.py +1 -1
  196. reflex/components/recharts/__init__.pyi +1 -1
  197. reflex/components/recharts/cartesian.py +20 -25
  198. reflex/components/recharts/cartesian.pyi +20 -37
  199. reflex/components/recharts/charts.py +2 -1
  200. reflex/components/recharts/charts.pyi +0 -12
  201. reflex/components/recharts/general.pyi +0 -6
  202. reflex/components/recharts/polar.py +5 -4
  203. reflex/components/recharts/polar.pyi +4 -10
  204. reflex/components/recharts/recharts.py +12 -10
  205. reflex/components/recharts/recharts.pyi +10 -11
  206. reflex/components/sonner/toast.py +2 -2
  207. reflex/components/sonner/toast.pyi +0 -2
  208. reflex/components/suneditor/editor.py +2 -1
  209. reflex/components/suneditor/editor.pyi +0 -1
  210. reflex/components/tags/iter_tag.py +4 -2
  211. reflex/config.py +41 -615
  212. reflex/constants/base.py +6 -6
  213. reflex/constants/compiler.py +8 -6
  214. reflex/constants/installer.py +25 -16
  215. reflex/custom_components/custom_components.py +1 -2
  216. reflex/environment.py +606 -0
  217. reflex/event.py +58 -60
  218. reflex/experimental/__init__.py +2 -2
  219. reflex/experimental/client_state.py +9 -4
  220. reflex/experimental/layout.pyi +0 -5
  221. reflex/istate/manager.py +17 -20
  222. reflex/istate/proxy.py +19 -12
  223. reflex/model.py +8 -5
  224. reflex/plugins/base.py +8 -0
  225. reflex/plugins/tailwind_v3.py +8 -0
  226. reflex/plugins/tailwind_v4.py +8 -0
  227. reflex/reflex.py +11 -12
  228. reflex/route.py +7 -9
  229. reflex/state.py +67 -71
  230. reflex/style.py +3 -1
  231. reflex/testing.py +49 -30
  232. reflex/utils/build.py +2 -1
  233. reflex/utils/console.py +70 -17
  234. reflex/utils/exec.py +113 -39
  235. reflex/utils/export.py +2 -1
  236. reflex/utils/format.py +21 -24
  237. reflex/utils/imports.py +4 -3
  238. reflex/utils/lazy_loader.py +3 -3
  239. reflex/utils/misc.py +2 -1
  240. reflex/utils/net.py +2 -2
  241. reflex/utils/path_ops.py +4 -2
  242. reflex/utils/prerequisites.py +69 -39
  243. reflex/utils/processes.py +5 -7
  244. reflex/utils/pyi_generator.py +46 -41
  245. reflex/utils/redir.py +1 -1
  246. reflex/utils/registry.py +1 -1
  247. reflex/utils/serializers.py +4 -4
  248. reflex/utils/telemetry.py +36 -3
  249. reflex/utils/types.py +16 -13
  250. reflex/vars/base.py +96 -109
  251. reflex/vars/datetime.py +2 -1
  252. reflex/vars/dep_tracking.py +19 -28
  253. reflex/vars/number.py +6 -7
  254. reflex/vars/object.py +5 -6
  255. reflex/vars/sequence.py +11 -11
  256. {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/METADATA +1 -1
  257. reflex-0.7.14.dist-info/RECORD +408 -0
  258. reflex-0.7.13a2.dist-info/RECORD +0 -407
  259. {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/WHEEL +0 -0
  260. {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/entry_points.txt +0 -0
  261. {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/licenses/LICENSE +0 -0
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.environment 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.environment 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
@@ -9,7 +9,8 @@ import shutil
9
9
  import stat
10
10
  from pathlib import Path
11
11
 
12
- from reflex.config import environment, get_config
12
+ from reflex.config import get_config
13
+ from reflex.environment import environment
13
14
 
14
15
  # Shorthand for join.
15
16
  join = os.linesep.join
@@ -300,7 +301,8 @@ def update_directory_tree(src: Path, dest: Path):
300
301
  ValueError: If the source is not a directory
301
302
  """
302
303
  if not src.is_dir():
303
- raise ValueError(f"Source {src} is not a directory")
304
+ msg = f"Source {src} is not a directory"
305
+ raise ValueError(msg)
304
306
 
305
307
  # Ensure the destination directory exists
306
308
  dest.mkdir(parents=True, exist_ok=True)
@@ -36,7 +36,8 @@ from redis.exceptions import RedisError
36
36
 
37
37
  from reflex import constants, model
38
38
  from reflex.compiler import templates
39
- from reflex.config import Config, environment, get_config
39
+ from reflex.config import Config, get_config
40
+ from reflex.environment import environment
40
41
  from reflex.utils import console, net, path_ops, processes, redir
41
42
  from reflex.utils.decorator import once
42
43
  from reflex.utils.exceptions import SystemPackageMissingError
@@ -129,7 +130,6 @@ def check_latest_package_version(package_name: str):
129
130
  )
130
131
  except Exception:
131
132
  console.debug(f"Failed to check for the latest version of {package_name}.")
132
- pass
133
133
 
134
134
 
135
135
  def get_or_set_last_reflex_version_check_datetime():
@@ -255,9 +255,8 @@ def get_nodejs_compatible_package_managers(
255
255
  package_managers = list(filter(None, package_managers))
256
256
 
257
257
  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
- )
258
+ msg = "Bun or npm not found. You might need to rerun `reflex init` or install either."
259
+ raise FileNotFoundError(msg)
261
260
 
262
261
  return package_managers
263
262
 
@@ -310,9 +309,8 @@ def get_js_package_executor(raise_on_none: bool = False) -> Sequence[Sequence[st
310
309
  package_managers = list(filter(None, package_managers))
311
310
 
312
311
  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
- )
312
+ msg = "Bun or npm not found. You might need to rerun `reflex init` or install either."
313
+ raise FileNotFoundError(msg)
316
314
 
317
315
  return package_managers
318
316
 
@@ -345,10 +343,11 @@ def _check_app_name(config: Config):
345
343
  RuntimeError: If the app name is not set in the config.
346
344
  """
347
345
  if not config.app_name:
348
- raise RuntimeError(
346
+ msg = (
349
347
  "Cannot get the app module because `app_name` is not set in rxconfig! "
350
348
  "If this error occurs in a reflex test case, ensure that `get_app` is mocked."
351
349
  )
350
+ raise RuntimeError(msg)
352
351
 
353
352
 
354
353
  def get_app(reload: bool = False) -> ModuleType:
@@ -395,11 +394,14 @@ def get_app(reload: bool = False) -> ModuleType:
395
394
  return app
396
395
 
397
396
 
398
- def get_and_validate_app(reload: bool = False) -> AppInfo:
397
+ def get_and_validate_app(
398
+ reload: bool = False, check_if_schema_up_to_date: bool = False
399
+ ) -> AppInfo:
399
400
  """Get the app instance based on the default config and validate it.
400
401
 
401
402
  Args:
402
403
  reload: Re-import the app module from disk
404
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
403
405
 
404
406
  Returns:
405
407
  The app instance and the app module.
@@ -412,23 +414,34 @@ def get_and_validate_app(reload: bool = False) -> AppInfo:
412
414
  app_module = get_app(reload=reload)
413
415
  app = getattr(app_module, constants.CompileVars.APP)
414
416
  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
- )
417
+ msg = "The app instance in the specified app_module_import in rxconfig must be an instance of rx.App."
418
+ raise RuntimeError(msg)
419
+
420
+ if check_if_schema_up_to_date:
421
+ check_schema_up_to_date()
422
+
418
423
  return AppInfo(app=app, module=app_module)
419
424
 
420
425
 
421
- def validate_app(reload: bool = False) -> None:
426
+ def validate_app(
427
+ reload: bool = False, check_if_schema_up_to_date: bool = False
428
+ ) -> None:
422
429
  """Validate the app instance based on the default config.
423
430
 
424
431
  Args:
425
432
  reload: Re-import the app module from disk
433
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
426
434
  """
427
- get_and_validate_app(reload=reload)
435
+ get_and_validate_app(
436
+ reload=reload, check_if_schema_up_to_date=check_if_schema_up_to_date
437
+ )
428
438
 
429
439
 
430
440
  def get_compiled_app(
431
- reload: bool = False, export: bool = False, dry_run: bool = False
441
+ reload: bool = False,
442
+ export: bool = False,
443
+ dry_run: bool = False,
444
+ check_if_schema_up_to_date: bool = False,
432
445
  ) -> ModuleType:
433
446
  """Get the app module based on the default config after first compiling it.
434
447
 
@@ -436,11 +449,14 @@ def get_compiled_app(
436
449
  reload: Re-import the app module from disk
437
450
  export: Compile the app for export
438
451
  dry_run: If True, do not write the compiled app to disk.
452
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
439
453
 
440
454
  Returns:
441
455
  The compiled app based on the default config.
442
456
  """
443
- app, app_module = get_and_validate_app(reload=reload)
457
+ app, app_module = get_and_validate_app(
458
+ reload=reload, check_if_schema_up_to_date=check_if_schema_up_to_date
459
+ )
444
460
  # For py3.9 compatibility when redis is used, we MUST add any decorator pages
445
461
  # before compiling the app in a thread to avoid event loop error (REF-2172).
446
462
  app._apply_decorated_pages()
@@ -449,7 +465,10 @@ def get_compiled_app(
449
465
 
450
466
 
451
467
  def compile_app(
452
- reload: bool = False, export: bool = False, dry_run: bool = False
468
+ reload: bool = False,
469
+ export: bool = False,
470
+ dry_run: bool = False,
471
+ check_if_schema_up_to_date: bool = False,
453
472
  ) -> None:
454
473
  """Compile the app module based on the default config.
455
474
 
@@ -457,8 +476,14 @@ def compile_app(
457
476
  reload: Re-import the app module from disk
458
477
  export: Compile the app for export
459
478
  dry_run: If True, do not write the compiled app to disk.
479
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
460
480
  """
461
- get_compiled_app(reload=reload, export=export, dry_run=dry_run)
481
+ get_compiled_app(
482
+ reload=reload,
483
+ export=export,
484
+ dry_run=dry_run,
485
+ check_if_schema_up_to_date=check_if_schema_up_to_date,
486
+ )
462
487
 
463
488
 
464
489
  def _can_colorize() -> bool:
@@ -503,20 +528,23 @@ def _can_colorize() -> bool:
503
528
  return file.isatty()
504
529
 
505
530
 
506
- def compile_or_validate_app(compile: bool = False) -> bool:
531
+ def compile_or_validate_app(
532
+ compile: bool = False, check_if_schema_up_to_date: bool = False
533
+ ) -> bool:
507
534
  """Compile or validate the app module based on the default config.
508
535
 
509
536
  Args:
510
537
  compile: Whether to compile the app.
538
+ check_if_schema_up_to_date: If True, check if the schema is up to date.
511
539
 
512
540
  Returns:
513
541
  If the app is compiled successfully.
514
542
  """
515
543
  try:
516
544
  if compile:
517
- compile_app()
545
+ compile_app(check_if_schema_up_to_date=check_if_schema_up_to_date)
518
546
  else:
519
- validate_app()
547
+ validate_app(check_if_schema_up_to_date=check_if_schema_up_to_date)
520
548
  except Exception as e:
521
549
  if isinstance(e, click.exceptions.Exit):
522
550
  return False
@@ -575,9 +603,8 @@ def parse_redis_url() -> str | None:
575
603
  if not config.redis_url:
576
604
  return None
577
605
  if not config.redis_url.startswith(("redis://", "rediss://", "unix://")):
578
- raise ValueError(
579
- "REDIS_URL must start with 'redis://', 'rediss://', or 'unix://'."
580
- )
606
+ msg = "REDIS_URL must start with 'redis://', 'rediss://', or 'unix://'."
607
+ raise ValueError(msg)
581
608
  return config.redis_url
582
609
 
583
610
 
@@ -1157,15 +1184,16 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
1157
1184
  raise click.exceptions.Exit(1) from None
1158
1185
 
1159
1186
  # Save the script to a temporary file.
1160
- script = Path(tempfile.NamedTemporaryFile().name)
1187
+ with tempfile.NamedTemporaryFile() as tempfile_file:
1188
+ script = Path(tempfile_file.name)
1161
1189
 
1162
- script.write_text(response.text)
1190
+ script.write_text(response.text)
1163
1191
 
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)
1192
+ # Run the script.
1193
+ env = {**os.environ, **env}
1194
+ process = processes.new_process(["bash", str(script), *args], env=env)
1195
+ show = processes.show_status if show_status else processes.show_logs
1196
+ show(f"Installing {url}", process)
1169
1197
 
1170
1198
 
1171
1199
  def install_bun():
@@ -1213,7 +1241,8 @@ def install_bun():
1213
1241
  )
1214
1242
  else:
1215
1243
  if path_ops.which("unzip") is None:
1216
- raise SystemPackageMissingError("unzip")
1244
+ msg = "unzip"
1245
+ raise SystemPackageMissingError(msg)
1217
1246
 
1218
1247
  # Run the bun install script.
1219
1248
  download_and_run(
@@ -1262,13 +1291,15 @@ def cached_procedure(
1262
1291
  ValueError: If both cache_file and cache_file_fn are provided.
1263
1292
  """
1264
1293
  if cache_file and cache_file_fn is not None:
1265
- raise ValueError("cache_file and cache_file_fn cannot both be provided.")
1294
+ msg = "cache_file and cache_file_fn cannot both be provided."
1295
+ raise ValueError(msg)
1266
1296
 
1267
1297
  def _inner_decorator(func: Callable):
1268
1298
  def _inner(*args, **kwargs):
1269
1299
  _cache_file = cache_file_fn() if cache_file_fn is not None else cache_file
1270
1300
  if not _cache_file:
1271
- raise ValueError("Unknown cache file, cannot cache result.")
1301
+ msg = "Unknown cache file, cannot cache result."
1302
+ raise ValueError(msg)
1272
1303
  payload = _read_cached_procedure_file(_cache_file)
1273
1304
  new_payload = payload_fn(*args, **kwargs)
1274
1305
  if payload != new_payload:
@@ -1446,7 +1477,7 @@ def validate_bun(bun_path: Path | None = None):
1446
1477
  "Failed to obtain bun version. Make sure the specified bun path in your config is correct."
1447
1478
  )
1448
1479
  raise click.exceptions.Exit(1)
1449
- elif bun_version < version.parse(constants.Bun.MIN_VERSION):
1480
+ if bun_version < version.parse(constants.Bun.MIN_VERSION):
1450
1481
  console.warn(
1451
1482
  f"Reflex requires bun version {constants.Bun.MIN_VERSION} or higher to run, but the detected version is "
1452
1483
  f"{bun_version}. If you have specified a custom bun path in your config, make sure to provide one "
@@ -1657,8 +1688,7 @@ def fetch_app_templates(version: str) -> dict[str, Template]:
1657
1688
  if asset is None:
1658
1689
  console.warn(f"Templates metadata not found for version {version}")
1659
1690
  return {}
1660
- else:
1661
- templates_url = asset["browser_download_url"]
1691
+ templates_url = asset["browser_download_url"]
1662
1692
 
1663
1693
  templates_data = net.get(templates_url, follow_redirects=True).json()["templates"]
1664
1694
 
@@ -1864,7 +1894,7 @@ def initialize_app(app_name: str, template: str | None = None) -> str | None:
1864
1894
  # Check if the app is already initialized.
1865
1895
  if constants.Config.FILE.exists():
1866
1896
  telemetry.send("reinit")
1867
- return
1897
+ return None
1868
1898
 
1869
1899
  templates: dict[str, Template] = {}
1870
1900
 
reflex/utils/processes.py CHANGED
@@ -19,7 +19,7 @@ from redis.exceptions import RedisError
19
19
  from rich.progress import Progress
20
20
 
21
21
  from reflex import constants
22
- from reflex.config import environment
22
+ from reflex.environment import environment
23
23
  from reflex.utils import console, path_ops, prerequisites
24
24
  from reflex.utils.registry import get_npm_registry
25
25
 
@@ -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