reflex 0.7.13a1__py3-none-any.whl → 0.7.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/apps/blank/code/blank.py +0 -2
- reflex/app.py +100 -92
- reflex/app_mixins/lifespan.py +2 -3
- reflex/app_mixins/middleware.py +1 -0
- reflex/app_mixins/mixin.py +0 -1
- reflex/assets.py +7 -4
- reflex/base.py +3 -2
- reflex/compiler/compiler.py +79 -65
- reflex/compiler/utils.py +8 -6
- reflex/components/base/app_wrap.pyi +0 -1
- reflex/components/base/bare.py +22 -12
- reflex/components/base/body.pyi +0 -1
- reflex/components/base/document.pyi +0 -5
- reflex/components/base/error_boundary.pyi +0 -1
- reflex/components/base/fragment.pyi +0 -1
- reflex/components/base/head.pyi +0 -2
- reflex/components/base/link.pyi +0 -2
- reflex/components/base/meta.py +2 -1
- reflex/components/base/meta.pyi +0 -4
- reflex/components/base/script.py +2 -1
- reflex/components/base/script.pyi +0 -1
- reflex/components/base/strict_mode.pyi +0 -1
- reflex/components/component.py +85 -45
- reflex/components/core/auto_scroll.pyi +0 -1
- reflex/components/core/banner.py +1 -1
- reflex/components/core/banner.pyi +0 -6
- reflex/components/core/breakpoints.py +9 -11
- reflex/components/core/client_side_routing.pyi +0 -2
- reflex/components/core/clipboard.pyi +0 -1
- reflex/components/core/colors.py +10 -7
- reflex/components/core/cond.py +4 -2
- reflex/components/core/debounce.py +5 -3
- reflex/components/core/debounce.pyi +0 -1
- reflex/components/core/foreach.py +8 -6
- reflex/components/core/html.py +3 -3
- reflex/components/core/html.pyi +0 -1
- reflex/components/core/match.py +19 -17
- reflex/components/core/sticky.pyi +0 -4
- reflex/components/core/upload.py +1 -1
- reflex/components/core/upload.pyi +0 -5
- reflex/components/datadisplay/code.py +1 -2
- reflex/components/datadisplay/code.pyi +0 -2
- reflex/components/datadisplay/dataeditor.py +7 -10
- reflex/components/datadisplay/dataeditor.pyi +0 -1
- reflex/components/datadisplay/logo.py +3 -4
- reflex/components/datadisplay/shiki_code_block.py +8 -11
- reflex/components/datadisplay/shiki_code_block.pyi +0 -3
- reflex/components/dynamic.py +2 -3
- reflex/components/el/__init__.pyi +2 -0
- reflex/components/el/element.pyi +0 -1
- reflex/components/el/elements/__init__.py +1 -0
- reflex/components/el/elements/__init__.pyi +3 -0
- reflex/components/el/elements/base.pyi +0 -1
- reflex/components/el/elements/forms.py +14 -15
- reflex/components/el/elements/forms.pyi +15 -32
- reflex/components/el/elements/inline.pyi +0 -28
- reflex/components/el/elements/media.py +26 -0
- reflex/components/el/elements/media.pyi +259 -25
- reflex/components/el/elements/metadata.py +0 -1
- reflex/components/el/elements/metadata.pyi +0 -6
- reflex/components/el/elements/other.pyi +0 -7
- reflex/components/el/elements/scripts.pyi +0 -3
- reflex/components/el/elements/sectioning.pyi +0 -15
- reflex/components/el/elements/tables.pyi +0 -10
- reflex/components/el/elements/typography.pyi +0 -15
- reflex/components/gridjs/datatable.py +10 -13
- reflex/components/gridjs/datatable.pyi +0 -2
- reflex/components/lucide/icon.py +10 -9
- reflex/components/lucide/icon.pyi +0 -3
- reflex/components/markdown/markdown.py +6 -8
- reflex/components/markdown/markdown.pyi +0 -1
- reflex/components/moment/moment.pyi +0 -1
- reflex/components/next/base.py +0 -2
- reflex/components/next/base.pyi +0 -3
- reflex/components/next/image.pyi +0 -1
- reflex/components/next/link.pyi +0 -1
- reflex/components/next/video.pyi +0 -1
- reflex/components/plotly/plotly.pyi +0 -9
- reflex/components/props.py +4 -3
- reflex/components/radix/primitives/accordion.py +1 -1
- reflex/components/radix/primitives/accordion.pyi +0 -7
- reflex/components/radix/primitives/base.py +1 -3
- reflex/components/radix/primitives/base.pyi +0 -2
- reflex/components/radix/primitives/drawer.py +1 -1
- reflex/components/radix/primitives/drawer.pyi +0 -11
- reflex/components/radix/primitives/form.py +5 -9
- reflex/components/radix/primitives/form.pyi +0 -12
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/progress.pyi +0 -5
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/primitives/slider.pyi +0 -5
- reflex/components/radix/themes/base.pyi +0 -8
- reflex/components/radix/themes/color_mode.pyi +0 -3
- reflex/components/radix/themes/components/alert_dialog.py +4 -2
- reflex/components/radix/themes/components/alert_dialog.pyi +4 -9
- reflex/components/radix/themes/components/aspect_ratio.py +1 -2
- reflex/components/radix/themes/components/aspect_ratio.pyi +1 -3
- reflex/components/radix/themes/components/avatar.py +5 -2
- reflex/components/radix/themes/components/avatar.pyi +1 -3
- reflex/components/radix/themes/components/badge.py +5 -2
- reflex/components/radix/themes/components/badge.pyi +1 -3
- reflex/components/radix/themes/components/button.py +2 -3
- reflex/components/radix/themes/components/button.pyi +1 -3
- reflex/components/radix/themes/components/callout.py +1 -2
- reflex/components/radix/themes/components/callout.pyi +1 -7
- reflex/components/radix/themes/components/card.py +1 -2
- reflex/components/radix/themes/components/card.pyi +1 -3
- reflex/components/radix/themes/components/checkbox.py +7 -4
- reflex/components/radix/themes/components/checkbox.pyi +1 -5
- reflex/components/radix/themes/components/checkbox_cards.py +1 -2
- reflex/components/radix/themes/components/checkbox_cards.pyi +1 -4
- reflex/components/radix/themes/components/checkbox_group.py +1 -2
- reflex/components/radix/themes/components/checkbox_group.pyi +1 -4
- reflex/components/radix/themes/components/context_menu.py +1 -1
- reflex/components/radix/themes/components/context_menu.pyi +1 -14
- reflex/components/radix/themes/components/data_list.py +1 -2
- reflex/components/radix/themes/components/data_list.pyi +1 -6
- reflex/components/radix/themes/components/dialog.py +4 -2
- reflex/components/radix/themes/components/dialog.pyi +4 -9
- reflex/components/radix/themes/components/dropdown_menu.py +5 -2
- reflex/components/radix/themes/components/dropdown_menu.pyi +4 -10
- reflex/components/radix/themes/components/hover_card.py +4 -2
- reflex/components/radix/themes/components/hover_card.pyi +4 -6
- reflex/components/radix/themes/components/icon_button.py +7 -8
- reflex/components/radix/themes/components/icon_button.pyi +1 -3
- reflex/components/radix/themes/components/inset.py +1 -2
- reflex/components/radix/themes/components/inset.pyi +1 -3
- reflex/components/radix/themes/components/popover.py +4 -2
- reflex/components/radix/themes/components/popover.pyi +4 -6
- reflex/components/radix/themes/components/progress.py +1 -2
- reflex/components/radix/themes/components/progress.pyi +1 -3
- reflex/components/radix/themes/components/radio.py +1 -2
- reflex/components/radix/themes/components/radio.pyi +1 -3
- reflex/components/radix/themes/components/radio_cards.py +1 -2
- reflex/components/radix/themes/components/radio_cards.pyi +1 -4
- reflex/components/radix/themes/components/radio_group.py +7 -5
- reflex/components/radix/themes/components/radio_group.pyi +1 -6
- reflex/components/radix/themes/components/scroll_area.py +1 -2
- reflex/components/radix/themes/components/scroll_area.pyi +1 -3
- reflex/components/radix/themes/components/segmented_control.py +1 -2
- reflex/components/radix/themes/components/segmented_control.pyi +1 -4
- reflex/components/radix/themes/components/select.py +5 -2
- reflex/components/radix/themes/components/select.pyi +1 -11
- reflex/components/radix/themes/components/separator.py +1 -2
- reflex/components/radix/themes/components/separator.pyi +1 -3
- reflex/components/radix/themes/components/skeleton.py +1 -2
- reflex/components/radix/themes/components/skeleton.pyi +1 -3
- reflex/components/radix/themes/components/slider.py +1 -2
- reflex/components/radix/themes/components/slider.pyi +1 -3
- reflex/components/radix/themes/components/spinner.py +1 -2
- reflex/components/radix/themes/components/spinner.pyi +1 -3
- reflex/components/radix/themes/components/switch.py +1 -2
- reflex/components/radix/themes/components/switch.pyi +1 -3
- reflex/components/radix/themes/components/table.py +1 -2
- reflex/components/radix/themes/components/table.pyi +1 -9
- reflex/components/radix/themes/components/tabs.py +1 -2
- reflex/components/radix/themes/components/tabs.pyi +1 -7
- reflex/components/radix/themes/components/text_area.py +5 -2
- reflex/components/radix/themes/components/text_area.pyi +2 -4
- reflex/components/radix/themes/components/text_field.py +5 -2
- reflex/components/radix/themes/components/text_field.pyi +1 -5
- reflex/components/radix/themes/components/tooltip.py +1 -2
- reflex/components/radix/themes/components/tooltip.pyi +1 -3
- reflex/components/radix/themes/layout/base.py +5 -2
- reflex/components/radix/themes/layout/base.pyi +5 -3
- reflex/components/radix/themes/layout/box.py +1 -2
- reflex/components/radix/themes/layout/box.pyi +1 -3
- reflex/components/radix/themes/layout/center.pyi +0 -1
- reflex/components/radix/themes/layout/container.py +1 -2
- reflex/components/radix/themes/layout/container.pyi +1 -3
- reflex/components/radix/themes/layout/flex.py +6 -2
- reflex/components/radix/themes/layout/flex.pyi +1 -3
- reflex/components/radix/themes/layout/grid.py +6 -2
- reflex/components/radix/themes/layout/grid.pyi +1 -3
- reflex/components/radix/themes/layout/list.py +2 -1
- reflex/components/radix/themes/layout/list.pyi +0 -5
- reflex/components/radix/themes/layout/section.py +1 -2
- reflex/components/radix/themes/layout/section.pyi +1 -3
- reflex/components/radix/themes/layout/spacer.pyi +0 -1
- reflex/components/radix/themes/layout/stack.py +1 -1
- reflex/components/radix/themes/layout/stack.pyi +0 -3
- reflex/components/radix/themes/typography/blockquote.py +1 -1
- reflex/components/radix/themes/typography/blockquote.pyi +1 -3
- reflex/components/radix/themes/typography/code.py +5 -1
- reflex/components/radix/themes/typography/code.pyi +1 -3
- reflex/components/radix/themes/typography/heading.py +1 -1
- reflex/components/radix/themes/typography/heading.pyi +1 -3
- reflex/components/radix/themes/typography/link.py +3 -2
- reflex/components/radix/themes/typography/link.pyi +1 -3
- reflex/components/radix/themes/typography/text.py +1 -1
- reflex/components/radix/themes/typography/text.pyi +1 -9
- reflex/components/react_player/audio.py +0 -2
- reflex/components/react_player/audio.pyi +0 -3
- reflex/components/react_player/react_player.pyi +0 -1
- reflex/components/react_player/video.py +0 -2
- reflex/components/react_player/video.pyi +0 -3
- reflex/components/recharts/__init__.py +1 -1
- reflex/components/recharts/__init__.pyi +1 -1
- reflex/components/recharts/cartesian.py +20 -25
- reflex/components/recharts/cartesian.pyi +20 -37
- reflex/components/recharts/charts.py +2 -1
- reflex/components/recharts/charts.pyi +0 -12
- reflex/components/recharts/general.pyi +0 -6
- reflex/components/recharts/polar.py +5 -4
- reflex/components/recharts/polar.pyi +4 -10
- reflex/components/recharts/recharts.py +12 -10
- reflex/components/recharts/recharts.pyi +10 -11
- reflex/components/sonner/toast.py +2 -2
- reflex/components/sonner/toast.pyi +0 -2
- reflex/components/suneditor/editor.py +2 -1
- reflex/components/suneditor/editor.pyi +0 -1
- reflex/components/tags/iter_tag.py +4 -2
- reflex/config.py +41 -615
- reflex/constants/base.py +6 -6
- reflex/constants/compiler.py +8 -6
- reflex/constants/installer.py +25 -16
- reflex/custom_components/custom_components.py +1 -2
- reflex/environment.py +606 -0
- reflex/event.py +58 -60
- reflex/experimental/__init__.py +2 -2
- reflex/experimental/client_state.py +9 -4
- reflex/experimental/layout.pyi +0 -5
- reflex/istate/manager.py +17 -20
- reflex/istate/proxy.py +19 -12
- reflex/model.py +8 -5
- reflex/plugins/base.py +8 -0
- reflex/plugins/tailwind_v3.py +8 -0
- reflex/plugins/tailwind_v4.py +9 -0
- reflex/reflex.py +11 -12
- reflex/route.py +7 -9
- reflex/state.py +67 -71
- reflex/style.py +3 -1
- reflex/testing.py +49 -30
- reflex/utils/build.py +2 -1
- reflex/utils/console.py +70 -17
- reflex/utils/exec.py +113 -39
- reflex/utils/export.py +2 -1
- reflex/utils/format.py +21 -24
- reflex/utils/imports.py +4 -3
- reflex/utils/lazy_loader.py +3 -3
- reflex/utils/misc.py +2 -1
- reflex/utils/net.py +2 -2
- reflex/utils/path_ops.py +4 -2
- reflex/utils/prerequisites.py +69 -39
- reflex/utils/processes.py +5 -7
- reflex/utils/pyi_generator.py +46 -41
- reflex/utils/redir.py +1 -1
- reflex/utils/registry.py +1 -1
- reflex/utils/serializers.py +4 -4
- reflex/utils/telemetry.py +36 -3
- reflex/utils/types.py +16 -13
- reflex/vars/base.py +96 -109
- reflex/vars/datetime.py +2 -1
- reflex/vars/dep_tracking.py +19 -28
- reflex/vars/number.py +6 -7
- reflex/vars/object.py +5 -6
- reflex/vars/sequence.py +11 -11
- {reflex-0.7.13a1.dist-info → reflex-0.7.14.dist-info}/METADATA +1 -1
- reflex-0.7.14.dist-info/RECORD +408 -0
- reflex-0.7.13a1.dist-info/RECORD +0 -407
- {reflex-0.7.13a1.dist-info → reflex-0.7.14.dist-info}/WHEEL +0 -0
- {reflex-0.7.13a1.dist-info → reflex-0.7.14.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.13a1.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
268
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
595
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
768
|
-
|
|
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
|
|
130
|
+
self.alias
|
|
131
|
+
if self.is_default
|
|
132
|
+
else (self.tag + " as " + self.alias if self.tag else self.alias)
|
|
131
133
|
)
|
|
132
|
-
|
|
133
|
-
return self.tag or ""
|
|
134
|
+
return self.tag or ""
|
|
134
135
|
|
|
135
136
|
|
|
136
137
|
ImportTypes = str | ImportVar | list[str | ImportVar] | list[ImportVar]
|
reflex/utils/lazy_loader.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
82
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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)
|
reflex/utils/prerequisites.py
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
259
|
-
|
|
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
|
-
|
|
314
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
416
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
-
|
|
579
|
-
|
|
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
|
-
|
|
1187
|
+
with tempfile.NamedTemporaryFile() as tempfile_file:
|
|
1188
|
+
script = Path(tempfile_file.name)
|
|
1161
1189
|
|
|
1162
|
-
|
|
1190
|
+
script.write_text(response.text)
|
|
1163
1191
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
|