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.
- reflex/.templates/apps/blank/code/blank.py +0 -2
- reflex/app.py +64 -69
- reflex/app_mixins/lifespan.py +2 -3
- reflex/app_mixins/middleware.py +1 -0
- reflex/app_mixins/mixin.py +0 -1
- reflex/assets.py +6 -3
- reflex/base.py +3 -2
- reflex/compiler/compiler.py +77 -64
- reflex/compiler/utils.py +8 -6
- reflex/components/base/app_wrap.pyi +0 -1
- reflex/components/base/bare.py +5 -7
- 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 +49 -41
- reflex/components/core/auto_scroll.pyi +0 -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.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.pyi +0 -7
- reflex/components/radix/primitives/base.py +1 -3
- reflex/components/radix/primitives/base.pyi +0 -2
- reflex/components/radix/primitives/drawer.pyi +0 -11
- reflex/components/radix/primitives/form.py +4 -8
- 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 +47 -35
- reflex/constants/base.py +3 -3
- reflex/constants/compiler.py +8 -6
- reflex/constants/installer.py +24 -15
- reflex/custom_components/custom_components.py +1 -2
- 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 +15 -19
- reflex/istate/proxy.py +19 -12
- reflex/model.py +6 -4
- reflex/plugins/base.py +8 -0
- reflex/plugins/tailwind_v3.py +8 -0
- reflex/plugins/tailwind_v4.py +8 -0
- reflex/reflex.py +9 -11
- reflex/route.py +7 -9
- reflex/state.py +66 -70
- reflex/style.py +3 -1
- reflex/testing.py +46 -29
- reflex/utils/build.py +2 -1
- reflex/utils/console.py +9 -17
- reflex/utils/exec.py +9 -11
- 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 +2 -1
- reflex/utils/prerequisites.py +67 -38
- reflex/utils/processes.py +4 -6
- reflex/utils/pyi_generator.py +46 -41
- reflex/utils/redir.py +1 -1
- reflex/utils/serializers.py +4 -4
- reflex/utils/telemetry.py +20 -2
- 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.13a2.dist-info → reflex-0.7.14a2.dist-info}/METADATA +1 -1
- reflex-0.7.14a2.dist-info/RECORD +407 -0
- reflex-0.7.13a2.dist-info/RECORD +0 -407
- {reflex-0.7.13a2.dist-info → reflex-0.7.14a2.dist-info}/WHEEL +0 -0
- {reflex-0.7.13a2.dist-info → reflex-0.7.14a2.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
248
|
-
|
|
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
|
-
|
|
253
|
-
|
|
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(
|
|
304
|
-
if config.
|
|
305
|
-
module_path = Path(
|
|
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
|
-
|
|
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.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
|
|
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
|
-
|
|
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)
|
reflex/utils/prerequisites.py
CHANGED
|
@@ -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
|
-
|
|
259
|
-
|
|
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
|
-
|
|
314
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
416
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
-
|
|
579
|
-
|
|
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
|
-
|
|
1186
|
+
with tempfile.NamedTemporaryFile() as tempfile_file:
|
|
1187
|
+
script = Path(tempfile_file.name)
|
|
1161
1188
|
|
|
1162
|
-
|
|
1189
|
+
script.write_text(response.text)
|
|
1163
1190
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|