reflex 0.6.8a1__py3-none-any.whl → 0.7.0__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/jinja/custom_components/pyproject.toml.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +3 -3
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
- reflex/.templates/web/utils/state.js +65 -36
- reflex/__init__.py +4 -17
- reflex/__init__.pyi +1 -2
- reflex/app.py +286 -135
- reflex/app_mixins/lifespan.py +9 -9
- reflex/app_mixins/middleware.py +6 -6
- reflex/app_module_for_backend.py +3 -7
- reflex/base.py +7 -7
- reflex/compiler/compiler.py +8 -0
- reflex/compiler/utils.py +57 -18
- reflex/components/base/app_wrap.pyi +16 -16
- reflex/components/base/bare.py +1 -1
- reflex/components/base/body.pyi +16 -16
- reflex/components/base/document.pyi +76 -76
- reflex/components/base/error_boundary.py +2 -1
- reflex/components/base/error_boundary.pyi +19 -22
- reflex/components/base/fragment.pyi +16 -16
- reflex/components/base/head.pyi +31 -31
- reflex/components/base/link.pyi +31 -31
- reflex/components/base/meta.py +2 -2
- reflex/components/base/meta.pyi +61 -61
- reflex/components/base/script.pyi +19 -19
- reflex/components/base/strict_mode.py +10 -0
- reflex/components/base/strict_mode.pyi +57 -0
- reflex/components/component.py +38 -77
- reflex/components/core/banner.py +159 -4
- reflex/components/core/banner.pyi +162 -76
- reflex/components/core/breakpoints.py +3 -1
- reflex/components/core/client_side_routing.py +1 -1
- reflex/components/core/client_side_routing.pyi +32 -32
- reflex/components/core/clipboard.pyi +17 -20
- reflex/components/core/cond.py +9 -10
- reflex/components/core/debounce.py +1 -1
- reflex/components/core/debounce.pyi +17 -17
- reflex/components/core/foreach.py +28 -3
- reflex/components/core/html.py +1 -1
- reflex/components/core/html.pyi +16 -16
- reflex/components/core/match.py +5 -5
- reflex/components/core/sticky.py +134 -0
- reflex/components/core/sticky.pyi +449 -0
- reflex/components/core/upload.py +2 -2
- reflex/components/core/upload.pyi +80 -88
- reflex/components/datadisplay/code.py +5 -14
- reflex/components/datadisplay/code.pyi +31 -31
- reflex/components/datadisplay/dataeditor.py +7 -4
- reflex/components/datadisplay/dataeditor.pyi +40 -54
- reflex/components/datadisplay/logo.py +13 -8
- reflex/components/datadisplay/shiki_code_block.py +14 -9
- reflex/components/datadisplay/shiki_code_block.pyi +46 -46
- reflex/components/dynamic.py +22 -3
- reflex/components/el/constants/reflex.py +1 -1
- reflex/components/el/element.py +1 -1
- reflex/components/el/element.pyi +16 -16
- reflex/components/el/elements/base.pyi +16 -16
- reflex/components/el/elements/forms.py +4 -4
- reflex/components/el/elements/forms.pyi +224 -258
- reflex/components/el/elements/inline.pyi +421 -421
- reflex/components/el/elements/media.pyi +376 -376
- reflex/components/el/elements/metadata.pyi +91 -91
- reflex/components/el/elements/other.pyi +106 -106
- reflex/components/el/elements/scripts.pyi +46 -46
- reflex/components/el/elements/sectioning.pyi +226 -226
- reflex/components/el/elements/tables.pyi +151 -151
- reflex/components/el/elements/typography.pyi +226 -226
- reflex/components/gridjs/datatable.pyi +31 -31
- reflex/components/lucide/icon.py +46 -8
- reflex/components/lucide/icon.pyi +85 -31
- reflex/components/markdown/markdown.py +10 -8
- reflex/components/markdown/markdown.pyi +16 -16
- reflex/components/moment/moment.py +2 -2
- reflex/components/moment/moment.pyi +17 -19
- reflex/components/next/base.pyi +16 -16
- reflex/components/next/image.py +16 -4
- reflex/components/next/image.pyi +22 -20
- reflex/components/next/link.py +1 -1
- reflex/components/next/link.pyi +16 -16
- reflex/components/next/video.pyi +16 -16
- reflex/components/plotly/__init__.py +29 -2
- reflex/components/plotly/plotly.py +240 -5
- reflex/components/plotly/plotly.pyi +799 -44
- reflex/components/props.py +3 -3
- reflex/components/radix/__init__.pyi +1 -1
- reflex/components/radix/primitives/accordion.py +9 -5
- reflex/components/radix/primitives/accordion.pyi +110 -108
- reflex/components/radix/primitives/base.pyi +31 -31
- reflex/components/radix/primitives/drawer.py +5 -2
- reflex/components/radix/primitives/drawer.pyi +179 -187
- reflex/components/radix/primitives/form.pyi +160 -172
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/progress.pyi +76 -76
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/primitives/slider.pyi +78 -82
- reflex/components/radix/themes/base.pyi +121 -121
- reflex/components/radix/themes/color_mode.py +11 -9
- reflex/components/radix/themes/color_mode.pyi +47 -49
- reflex/components/radix/themes/components/alert_dialog.py +3 -0
- reflex/components/radix/themes/components/alert_dialog.pyi +110 -112
- reflex/components/radix/themes/components/aspect_ratio.pyi +16 -16
- reflex/components/radix/themes/components/avatar.pyi +16 -16
- reflex/components/radix/themes/components/badge.pyi +16 -16
- reflex/components/radix/themes/components/button.pyi +16 -16
- reflex/components/radix/themes/components/callout.pyi +76 -76
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +17 -17
- reflex/components/radix/themes/components/checkbox.pyi +49 -55
- reflex/components/radix/themes/components/checkbox_cards.pyi +31 -31
- reflex/components/radix/themes/components/checkbox_group.pyi +31 -31
- reflex/components/radix/themes/components/context_menu.py +5 -0
- reflex/components/radix/themes/components/context_menu.pyi +149 -155
- reflex/components/radix/themes/components/data_list.pyi +61 -61
- reflex/components/radix/themes/components/dialog.py +3 -0
- reflex/components/radix/themes/components/dialog.pyi +113 -117
- reflex/components/radix/themes/components/dropdown_menu.py +5 -0
- reflex/components/radix/themes/components/dropdown_menu.pyi +133 -137
- reflex/components/radix/themes/components/hover_card.py +3 -0
- reflex/components/radix/themes/components/hover_card.pyi +63 -67
- reflex/components/radix/themes/components/icon_button.py +2 -2
- reflex/components/radix/themes/components/icon_button.pyi +17 -16
- reflex/components/radix/themes/components/inset.pyi +16 -16
- reflex/components/radix/themes/components/popover.py +3 -0
- reflex/components/radix/themes/components/popover.pyi +68 -70
- reflex/components/radix/themes/components/progress.pyi +16 -16
- reflex/components/radix/themes/components/radio.pyi +16 -16
- reflex/components/radix/themes/components/radio_cards.py +2 -0
- reflex/components/radix/themes/components/radio_cards.pyi +32 -34
- reflex/components/radix/themes/components/radio_group.py +1 -1
- reflex/components/radix/themes/components/radio_group.pyi +62 -64
- reflex/components/radix/themes/components/scroll_area.pyi +16 -16
- reflex/components/radix/themes/components/segmented_control.pyi +32 -35
- reflex/components/radix/themes/components/select.py +4 -0
- reflex/components/radix/themes/components/select.pyi +145 -157
- reflex/components/radix/themes/components/separator.pyi +16 -16
- reflex/components/radix/themes/components/skeleton.py +3 -0
- reflex/components/radix/themes/components/skeleton.pyi +16 -16
- reflex/components/radix/themes/components/slider.pyi +22 -28
- reflex/components/radix/themes/components/spinner.pyi +16 -16
- reflex/components/radix/themes/components/switch.pyi +17 -19
- reflex/components/radix/themes/components/table.pyi +106 -106
- reflex/components/radix/themes/components/tabs.py +3 -0
- reflex/components/radix/themes/components/tabs.pyi +78 -82
- reflex/components/radix/themes/components/text_area.py +12 -0
- reflex/components/radix/themes/components/text_area.pyi +21 -33
- reflex/components/radix/themes/components/text_field.py +1 -1
- reflex/components/radix/themes/components/text_field.pyi +52 -80
- reflex/components/radix/themes/components/tooltip.py +6 -1
- reflex/components/radix/themes/components/tooltip.pyi +20 -21
- reflex/components/radix/themes/layout/__init__.pyi +1 -1
- reflex/components/radix/themes/layout/base.pyi +16 -16
- reflex/components/radix/themes/layout/box.pyi +16 -16
- reflex/components/radix/themes/layout/center.pyi +16 -16
- reflex/components/radix/themes/layout/container.pyi +16 -16
- reflex/components/radix/themes/layout/flex.pyi +16 -16
- reflex/components/radix/themes/layout/grid.pyi +16 -16
- reflex/components/radix/themes/layout/list.py +2 -2
- reflex/components/radix/themes/layout/list.pyi +76 -76
- reflex/components/radix/themes/layout/section.pyi +16 -16
- reflex/components/radix/themes/layout/spacer.pyi +16 -16
- reflex/components/radix/themes/layout/stack.py +2 -2
- reflex/components/radix/themes/layout/stack.pyi +46 -46
- reflex/components/radix/themes/typography/blockquote.pyi +16 -16
- reflex/components/radix/themes/typography/code.pyi +16 -16
- reflex/components/radix/themes/typography/heading.pyi +16 -16
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/link.pyi +16 -16
- reflex/components/radix/themes/typography/text.py +2 -2
- reflex/components/radix/themes/typography/text.pyi +106 -106
- reflex/components/react_player/audio.pyi +33 -39
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/react_player/react_player.pyi +32 -38
- reflex/components/react_player/video.pyi +33 -39
- reflex/components/recharts/__init__.py +2 -0
- reflex/components/recharts/__init__.pyi +2 -0
- reflex/components/recharts/cartesian.pyi +282 -282
- reflex/components/recharts/charts.py +15 -15
- reflex/components/recharts/charts.pyi +164 -164
- reflex/components/recharts/general.py +19 -4
- reflex/components/recharts/general.pyi +132 -81
- reflex/components/recharts/polar.py +2 -2
- reflex/components/recharts/polar.pyi +55 -55
- reflex/components/recharts/recharts.py +4 -4
- reflex/components/recharts/recharts.pyi +31 -31
- reflex/components/sonner/toast.py +15 -13
- reflex/components/sonner/toast.pyi +22 -22
- reflex/components/suneditor/editor.py +6 -4
- reflex/components/suneditor/editor.pyi +26 -40
- reflex/components/tags/iter_tag.py +3 -3
- reflex/components/tags/tag.py +25 -3
- reflex/config.py +48 -20
- reflex/constants/__init__.py +1 -0
- reflex/constants/base.py +4 -1
- reflex/constants/compiler.py +5 -2
- reflex/constants/config.py +8 -1
- reflex/constants/installer.py +9 -9
- reflex/constants/style.py +1 -1
- reflex/custom_components/custom_components.py +18 -10
- reflex/event.py +228 -233
- reflex/experimental/__init__.py +19 -11
- reflex/experimental/client_state.py +53 -28
- reflex/experimental/hooks.py +5 -5
- reflex/experimental/layout.py +8 -5
- reflex/experimental/layout.pyi +79 -83
- reflex/experimental/misc.py +3 -3
- reflex/istate/wrappers.py +1 -1
- reflex/middleware/hydrate_middleware.py +2 -2
- reflex/model.py +11 -6
- reflex/page.py +5 -5
- reflex/reflex.py +104 -26
- reflex/route.py +1 -1
- reflex/state.py +358 -401
- reflex/style.py +27 -3
- reflex/testing.py +34 -39
- reflex/utils/build.py +6 -2
- reflex/utils/codespaces.py +1 -4
- reflex/utils/compat.py +6 -5
- reflex/utils/console.py +71 -21
- reflex/utils/exceptions.py +89 -26
- reflex/utils/exec.py +69 -74
- reflex/utils/export.py +6 -1
- reflex/utils/format.py +8 -40
- reflex/utils/imports.py +5 -2
- reflex/utils/lazy_loader.py +7 -1
- reflex/utils/path_ops.py +74 -14
- reflex/utils/prerequisites.py +345 -68
- reflex/utils/processes.py +45 -32
- reflex/utils/pyi_generator.py +39 -33
- reflex/utils/registry.py +4 -4
- reflex/utils/serializers.py +1 -1
- reflex/utils/telemetry.py +5 -4
- reflex/utils/types.py +42 -18
- reflex/vars/base.py +695 -330
- reflex/vars/datetime.py +6 -7
- reflex/vars/dep_tracking.py +344 -0
- reflex/vars/function.py +11 -5
- reflex/vars/number.py +31 -43
- reflex/vars/object.py +74 -64
- reflex/vars/sequence.py +79 -67
- {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/METADATA +7 -10
- reflex-0.7.0.dist-info/RECORD +401 -0
- {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/WHEEL +1 -1
- reflex/experimental/assets.py +0 -37
- reflex/proxy.py +0 -119
- reflex-0.6.8a1.dist-info/RECORD +0 -398
- {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/LICENSE +0 -0
- {reflex-0.6.8a1.dist-info → reflex-0.7.0.dist-info}/entry_points.txt +0 -0
reflex/style.py
CHANGED
|
@@ -78,7 +78,7 @@ def set_color_mode(
|
|
|
78
78
|
_var_data=VarData.merge(
|
|
79
79
|
base_setter._get_all_var_data(), new_color_mode._get_all_var_data()
|
|
80
80
|
),
|
|
81
|
-
).to(FunctionVar, EventChain)
|
|
81
|
+
).to(FunctionVar, EventChain)
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
# Var resolves to the current color mode for the app ("light", "dark" or "system")
|
|
@@ -182,7 +182,9 @@ def convert(
|
|
|
182
182
|
var_data = None # Track import/hook data from any Vars in the style dict.
|
|
183
183
|
out = {}
|
|
184
184
|
|
|
185
|
-
def update_out_dict(
|
|
185
|
+
def update_out_dict(
|
|
186
|
+
return_value: Var | dict | list | str, keys_to_update: tuple[str, ...]
|
|
187
|
+
):
|
|
186
188
|
for k in keys_to_update:
|
|
187
189
|
out[k] = return_value
|
|
188
190
|
|
|
@@ -287,9 +289,31 @@ class Style(dict):
|
|
|
287
289
|
_var = LiteralVar.create(value)
|
|
288
290
|
if _var is not None:
|
|
289
291
|
# Carry the imports/hooks when setting a Var as a value.
|
|
290
|
-
self._var_data = VarData.merge(
|
|
292
|
+
self._var_data = VarData.merge(
|
|
293
|
+
getattr(self, "_var_data", None), _var._get_all_var_data()
|
|
294
|
+
)
|
|
291
295
|
super().__setitem__(key, value)
|
|
292
296
|
|
|
297
|
+
def __or__(self, other: Style | dict) -> Style:
|
|
298
|
+
"""Combine two styles.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
other: The other style to combine.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
The combined style.
|
|
305
|
+
"""
|
|
306
|
+
other_var_data = None
|
|
307
|
+
if not isinstance(other, Style):
|
|
308
|
+
other_dict, other_var_data = convert(other)
|
|
309
|
+
else:
|
|
310
|
+
other_dict, other_var_data = other, other._var_data
|
|
311
|
+
|
|
312
|
+
new_style = Style(super().__or__(other_dict))
|
|
313
|
+
if self._var_data or other_var_data:
|
|
314
|
+
new_style._var_data = VarData.merge(self._var_data, other_var_data)
|
|
315
|
+
return new_style
|
|
316
|
+
|
|
293
317
|
|
|
294
318
|
def _format_emotion_style_pseudo_selector(key: str) -> str:
|
|
295
319
|
"""Format a pseudo selector for emotion CSS-in-JS.
|
reflex/testing.py
CHANGED
|
@@ -44,7 +44,6 @@ import reflex.utils.format
|
|
|
44
44
|
import reflex.utils.prerequisites
|
|
45
45
|
import reflex.utils.processes
|
|
46
46
|
from reflex.config import environment
|
|
47
|
-
from reflex.proxy import proxy_middleware
|
|
48
47
|
from reflex.state import (
|
|
49
48
|
BaseState,
|
|
50
49
|
StateManager,
|
|
@@ -81,17 +80,17 @@ T = TypeVar("T")
|
|
|
81
80
|
TimeoutType = Optional[Union[int, float]]
|
|
82
81
|
|
|
83
82
|
if platform.system() == "Windows":
|
|
84
|
-
FRONTEND_POPEN_ARGS["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP #
|
|
83
|
+
FRONTEND_POPEN_ARGS["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # pyright: ignore [reportAttributeAccessIssue]
|
|
85
84
|
FRONTEND_POPEN_ARGS["shell"] = True
|
|
86
85
|
else:
|
|
87
86
|
FRONTEND_POPEN_ARGS["start_new_session"] = True
|
|
88
87
|
|
|
89
88
|
|
|
90
89
|
# borrowed from py3.11
|
|
91
|
-
class chdir(contextlib.AbstractContextManager):
|
|
90
|
+
class chdir(contextlib.AbstractContextManager): # noqa: N801
|
|
92
91
|
"""Non thread-safe context manager to change the current working directory."""
|
|
93
92
|
|
|
94
|
-
def __init__(self, path):
|
|
93
|
+
def __init__(self, path: str | Path):
|
|
95
94
|
"""Prepare contextmanager.
|
|
96
95
|
|
|
97
96
|
Args:
|
|
@@ -259,7 +258,7 @@ class AppHarness:
|
|
|
259
258
|
if self.app_source is not None:
|
|
260
259
|
app_globals = self._get_globals_from_signature(self.app_source)
|
|
261
260
|
if isinstance(self.app_source, functools.partial):
|
|
262
|
-
self.app_source = self.app_source.func
|
|
261
|
+
self.app_source = self.app_source.func
|
|
263
262
|
# get the source from a function or module object
|
|
264
263
|
source_code = "\n".join(
|
|
265
264
|
[
|
|
@@ -283,6 +282,7 @@ class AppHarness:
|
|
|
283
282
|
before_decorated_pages = reflex.app.DECORATED_PAGES[self.app_name].copy()
|
|
284
283
|
# Ensure the AppHarness test does not skip State assignment due to running via pytest
|
|
285
284
|
os.environ.pop(reflex.constants.PYTEST_CURRENT_TEST, None)
|
|
285
|
+
os.environ[reflex.constants.APP_HARNESS_FLAG] = "true"
|
|
286
286
|
self.app_module = reflex.utils.prerequisites.get_compiled_app(
|
|
287
287
|
# Do not reload the module for pre-existing apps (only apps generated from source)
|
|
288
288
|
reload=self.app_source is not None
|
|
@@ -294,14 +294,15 @@ class AppHarness:
|
|
|
294
294
|
if p not in before_decorated_pages
|
|
295
295
|
]
|
|
296
296
|
self.app_instance = self.app_module.app
|
|
297
|
-
if
|
|
297
|
+
if self.app_instance and isinstance(
|
|
298
|
+
self.app_instance._state_manager, StateManagerRedis
|
|
299
|
+
):
|
|
298
300
|
# Create our own redis connection for testing.
|
|
299
|
-
self.state_manager = StateManagerRedis.create(self.app_instance.
|
|
301
|
+
self.state_manager = StateManagerRedis.create(self.app_instance._state) # pyright: ignore [reportArgumentType]
|
|
300
302
|
else:
|
|
301
|
-
self.state_manager =
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
self.app_instance.lifespan_tasks.remove(proxy_middleware)
|
|
303
|
+
self.state_manager = (
|
|
304
|
+
self.app_instance._state_manager if self.app_instance else None
|
|
305
|
+
)
|
|
305
306
|
|
|
306
307
|
def _reload_state_module(self):
|
|
307
308
|
"""Reload the rx.State module to avoid conflict when reloading."""
|
|
@@ -326,8 +327,8 @@ class AppHarness:
|
|
|
326
327
|
|
|
327
328
|
return _shutdown_redis
|
|
328
329
|
|
|
329
|
-
def _start_backend(self, port=0):
|
|
330
|
-
if self.app_instance is None:
|
|
330
|
+
def _start_backend(self, port: int = 0):
|
|
331
|
+
if self.app_instance is None or self.app_instance.api is None:
|
|
331
332
|
raise RuntimeError("App was not initialized.")
|
|
332
333
|
self.backend = uvicorn.Server(
|
|
333
334
|
uvicorn.Config(
|
|
@@ -356,12 +357,12 @@ class AppHarness:
|
|
|
356
357
|
self.app_instance.state_manager,
|
|
357
358
|
StateManagerRedis,
|
|
358
359
|
)
|
|
359
|
-
and self.app_instance.
|
|
360
|
+
and self.app_instance._state is not None
|
|
360
361
|
):
|
|
361
362
|
with contextlib.suppress(RuntimeError):
|
|
362
363
|
await self.app_instance.state_manager.close()
|
|
363
364
|
self.app_instance._state_manager = StateManagerRedis.create(
|
|
364
|
-
state=self.app_instance.
|
|
365
|
+
state=self.app_instance._state,
|
|
365
366
|
)
|
|
366
367
|
if not isinstance(self.app_instance.state_manager, StateManagerRedis):
|
|
367
368
|
raise RuntimeError("Failed to reset state manager.")
|
|
@@ -369,12 +370,9 @@ class AppHarness:
|
|
|
369
370
|
def _start_frontend(self):
|
|
370
371
|
# Set up the frontend.
|
|
371
372
|
with chdir(self.app_path):
|
|
372
|
-
backend_host, backend_port = self._poll_for_servers().getsockname()
|
|
373
373
|
config = reflex.config.get_config()
|
|
374
|
-
config.backend_port = backend_port
|
|
375
374
|
config.api_url = "http://{0}:{1}".format(
|
|
376
|
-
|
|
377
|
-
backend_port,
|
|
375
|
+
*self._poll_for_servers().getsockname(),
|
|
378
376
|
)
|
|
379
377
|
reflex.utils.build.setup_frontend(self.app_path)
|
|
380
378
|
|
|
@@ -399,7 +397,6 @@ class AppHarness:
|
|
|
399
397
|
self.frontend_url = m.group(1)
|
|
400
398
|
config = reflex.config.get_config()
|
|
401
399
|
config.deploy_url = self.frontend_url
|
|
402
|
-
config.frontend_port = int(self.frontend_url.rpartition(":")[2])
|
|
403
400
|
break
|
|
404
401
|
if self.frontend_url is None:
|
|
405
402
|
raise RuntimeError("Frontend did not start")
|
|
@@ -433,7 +430,7 @@ class AppHarness:
|
|
|
433
430
|
return self
|
|
434
431
|
|
|
435
432
|
@staticmethod
|
|
436
|
-
def get_app_global_source(key, value):
|
|
433
|
+
def get_app_global_source(key: str, value: Any):
|
|
437
434
|
"""Get the source code of a global object.
|
|
438
435
|
If value is a function or class we render the actual
|
|
439
436
|
source of value otherwise we assign value to key.
|
|
@@ -628,23 +625,23 @@ class AppHarness:
|
|
|
628
625
|
want_headless = True
|
|
629
626
|
if driver_clz is None:
|
|
630
627
|
requested_driver = environment.APP_HARNESS_DRIVER.get()
|
|
631
|
-
driver_clz = getattr(webdriver, requested_driver)
|
|
628
|
+
driver_clz = getattr(webdriver, requested_driver) # pyright: ignore [reportPossiblyUnboundVariable]
|
|
632
629
|
if driver_options is None:
|
|
633
|
-
driver_options = getattr(webdriver, f"{requested_driver}Options")()
|
|
634
|
-
if driver_clz is webdriver.Chrome:
|
|
630
|
+
driver_options = getattr(webdriver, f"{requested_driver}Options")() # pyright: ignore [reportPossiblyUnboundVariable]
|
|
631
|
+
if driver_clz is webdriver.Chrome: # pyright: ignore [reportPossiblyUnboundVariable]
|
|
635
632
|
if driver_options is None:
|
|
636
|
-
driver_options = webdriver.ChromeOptions()
|
|
633
|
+
driver_options = webdriver.ChromeOptions() # pyright: ignore [reportPossiblyUnboundVariable]
|
|
637
634
|
driver_options.add_argument("--class=AppHarness")
|
|
638
635
|
if want_headless:
|
|
639
636
|
driver_options.add_argument("--headless=new")
|
|
640
|
-
elif driver_clz is webdriver.Firefox:
|
|
637
|
+
elif driver_clz is webdriver.Firefox: # pyright: ignore [reportPossiblyUnboundVariable]
|
|
641
638
|
if driver_options is None:
|
|
642
|
-
driver_options = webdriver.FirefoxOptions()
|
|
639
|
+
driver_options = webdriver.FirefoxOptions() # pyright: ignore [reportPossiblyUnboundVariable]
|
|
643
640
|
if want_headless:
|
|
644
641
|
driver_options.add_argument("-headless")
|
|
645
|
-
elif driver_clz is webdriver.Edge:
|
|
642
|
+
elif driver_clz is webdriver.Edge: # pyright: ignore [reportPossiblyUnboundVariable]
|
|
646
643
|
if driver_options is None:
|
|
647
|
-
driver_options = webdriver.EdgeOptions()
|
|
644
|
+
driver_options = webdriver.EdgeOptions() # pyright: ignore [reportPossiblyUnboundVariable]
|
|
648
645
|
if want_headless:
|
|
649
646
|
driver_options.add_argument("headless")
|
|
650
647
|
if driver_options is None:
|
|
@@ -660,7 +657,7 @@ class AppHarness:
|
|
|
660
657
|
driver_options.set_capability(key, value)
|
|
661
658
|
if driver_kwargs is None:
|
|
662
659
|
driver_kwargs = {}
|
|
663
|
-
driver = driver_clz(options=driver_options, **driver_kwargs) #
|
|
660
|
+
driver = driver_clz(options=driver_options, **driver_kwargs) # pyright: ignore [reportOptionalCall, reportArgumentType]
|
|
664
661
|
driver.get(self.frontend_url)
|
|
665
662
|
self._frontends.append(driver)
|
|
666
663
|
return driver
|
|
@@ -892,8 +889,8 @@ class Subdir404TCPServer(socketserver.TCPServer):
|
|
|
892
889
|
request,
|
|
893
890
|
client_address,
|
|
894
891
|
self,
|
|
895
|
-
directory=str(self.root), #
|
|
896
|
-
error_page_map=self.error_page_map, #
|
|
892
|
+
directory=str(self.root), # pyright: ignore [reportCallIssue]
|
|
893
|
+
error_page_map=self.error_page_map, # pyright: ignore [reportCallIssue]
|
|
897
894
|
)
|
|
898
895
|
|
|
899
896
|
|
|
@@ -923,26 +920,24 @@ class AppHarnessProd(AppHarness):
|
|
|
923
920
|
root=web_root,
|
|
924
921
|
error_page_map=error_page_map,
|
|
925
922
|
) as self.frontend_server:
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
923
|
+
self.frontend_url = "http://localhost:{1}".format(
|
|
924
|
+
*self.frontend_server.socket.getsockname()
|
|
925
|
+
)
|
|
929
926
|
self.frontend_server.serve_forever()
|
|
930
927
|
|
|
931
928
|
def _start_frontend(self):
|
|
932
929
|
# Set up the frontend.
|
|
933
930
|
with chdir(self.app_path):
|
|
934
|
-
backend_host, backend_port = self._poll_for_servers().getsockname()
|
|
935
931
|
config = reflex.config.get_config()
|
|
936
|
-
config.backend_port = backend_port
|
|
937
932
|
config.api_url = "http://{0}:{1}".format(
|
|
938
|
-
|
|
939
|
-
backend_port,
|
|
933
|
+
*self._poll_for_servers().getsockname(),
|
|
940
934
|
)
|
|
941
935
|
reflex.reflex.export(
|
|
942
936
|
zipping=False,
|
|
943
937
|
frontend=True,
|
|
944
938
|
backend=False,
|
|
945
939
|
loglevel=reflex.constants.LogLevel.INFO,
|
|
940
|
+
env=reflex.constants.Env.PROD,
|
|
946
941
|
)
|
|
947
942
|
|
|
948
943
|
self.frontend_thread = threading.Thread(target=self._run_frontend)
|
reflex/utils/build.py
CHANGED
|
@@ -13,17 +13,21 @@ from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
|
|
|
13
13
|
from reflex import constants
|
|
14
14
|
from reflex.config import get_config
|
|
15
15
|
from reflex.utils import console, path_ops, prerequisites, processes
|
|
16
|
+
from reflex.utils.exec import is_in_app_harness
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def set_env_json():
|
|
19
20
|
"""Write the upload url to a REFLEX_JSON."""
|
|
20
21
|
path_ops.update_json_file(
|
|
21
22
|
str(prerequisites.get_web_dir() / constants.Dirs.ENV_JSON),
|
|
22
|
-
{
|
|
23
|
+
{
|
|
24
|
+
**{endpoint.name: endpoint.get_url() for endpoint in constants.Endpoint},
|
|
25
|
+
"TEST_MODE": is_in_app_harness(),
|
|
26
|
+
},
|
|
23
27
|
)
|
|
24
28
|
|
|
25
29
|
|
|
26
|
-
def generate_sitemap_config(deploy_url: str, export=False):
|
|
30
|
+
def generate_sitemap_config(deploy_url: str, export: bool = False):
|
|
27
31
|
"""Generate the sitemap config file.
|
|
28
32
|
|
|
29
33
|
Args:
|
reflex/utils/codespaces.py
CHANGED
|
@@ -42,10 +42,7 @@ def codespaces_port_forwarding_domain() -> str | None:
|
|
|
42
42
|
Returns:
|
|
43
43
|
The domain for port forwarding in Github Codespaces, or None if not running in Codespaces.
|
|
44
44
|
"""
|
|
45
|
-
|
|
46
|
-
"GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN"
|
|
47
|
-
)
|
|
48
|
-
return GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
|
|
45
|
+
return os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN")
|
|
49
46
|
|
|
50
47
|
|
|
51
48
|
def is_running_in_codespaces() -> bool:
|
reflex/utils/compat.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
4
|
import sys
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
async def windows_hot_reload_lifespan_hack():
|
|
@@ -50,11 +51,11 @@ def pydantic_v1_patch():
|
|
|
50
51
|
]
|
|
51
52
|
originals = {module: sys.modules.get(module) for module in patched_modules}
|
|
52
53
|
try:
|
|
53
|
-
import pydantic.v1
|
|
54
|
+
import pydantic.v1
|
|
54
55
|
|
|
55
|
-
sys.modules["pydantic.fields"] = pydantic.v1.fields #
|
|
56
|
-
sys.modules["pydantic.main"] = pydantic.v1.main #
|
|
57
|
-
sys.modules["pydantic.errors"] = pydantic.v1.errors #
|
|
56
|
+
sys.modules["pydantic.fields"] = pydantic.v1.fields # pyright: ignore [reportAttributeAccessIssue]
|
|
57
|
+
sys.modules["pydantic.main"] = pydantic.v1.main # pyright: ignore [reportAttributeAccessIssue]
|
|
58
|
+
sys.modules["pydantic.errors"] = pydantic.v1.errors # pyright: ignore [reportAttributeAccessIssue]
|
|
58
59
|
sys.modules["pydantic"] = pydantic.v1
|
|
59
60
|
yield
|
|
60
61
|
except (ImportError, AttributeError):
|
|
@@ -74,7 +75,7 @@ with pydantic_v1_patch():
|
|
|
74
75
|
import sqlmodel as sqlmodel
|
|
75
76
|
|
|
76
77
|
|
|
77
|
-
def sqlmodel_field_has_primary_key(field) -> bool:
|
|
78
|
+
def sqlmodel_field_has_primary_key(field: Any) -> bool:
|
|
78
79
|
"""Determines if a field is a priamary.
|
|
79
80
|
|
|
80
81
|
Args:
|
reflex/utils/console.py
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import contextlib
|
|
6
|
+
import inspect
|
|
7
|
+
import shutil
|
|
8
|
+
import time
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from types import FrameType
|
|
6
11
|
|
|
7
12
|
from rich.console import Console
|
|
8
13
|
from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
|
|
@@ -14,7 +19,7 @@ from reflex.constants import LogLevel
|
|
|
14
19
|
_console = Console()
|
|
15
20
|
|
|
16
21
|
# The current log level.
|
|
17
|
-
_LOG_LEVEL = LogLevel.
|
|
22
|
+
_LOG_LEVEL = LogLevel.INFO
|
|
18
23
|
|
|
19
24
|
# Deprecated features who's warning has been printed.
|
|
20
25
|
_EMITTED_DEPRECATION_WARNINGS = set()
|
|
@@ -48,24 +53,13 @@ def set_log_level(log_level: LogLevel):
|
|
|
48
53
|
log_level: The log level to set.
|
|
49
54
|
|
|
50
55
|
Raises:
|
|
51
|
-
|
|
56
|
+
TypeError: If the log level is a string.
|
|
52
57
|
"""
|
|
53
58
|
if not isinstance(log_level, LogLevel):
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
reason="use reflex.constants.LogLevel enum instead",
|
|
57
|
-
deprecation_version="0.6.6",
|
|
58
|
-
removal_version="0.7.0",
|
|
59
|
+
raise TypeError(
|
|
60
|
+
f"log_level must be a LogLevel enum value, got {log_level} of type {type(log_level)} instead."
|
|
59
61
|
)
|
|
60
|
-
try:
|
|
61
|
-
log_level = getattr(LogLevel, log_level.upper())
|
|
62
|
-
except AttributeError as ae:
|
|
63
|
-
raise ValueError(f"Invalid log level: {log_level}") from ae
|
|
64
|
-
|
|
65
62
|
global _LOG_LEVEL
|
|
66
|
-
if log_level != _LOG_LEVEL:
|
|
67
|
-
# Set the loglevel persistently for subprocesses
|
|
68
|
-
os.environ["LOGLEVEL"] = log_level.value
|
|
69
63
|
_LOG_LEVEL = log_level
|
|
70
64
|
|
|
71
65
|
|
|
@@ -193,6 +187,33 @@ def warn(msg: str, dedupe: bool = False, **kwargs):
|
|
|
193
187
|
print(f"[orange1]Warning: {msg}[/orange1]", **kwargs)
|
|
194
188
|
|
|
195
189
|
|
|
190
|
+
def _get_first_non_framework_frame() -> FrameType | None:
|
|
191
|
+
import click
|
|
192
|
+
import typer
|
|
193
|
+
import typing_extensions
|
|
194
|
+
|
|
195
|
+
import reflex as rx
|
|
196
|
+
|
|
197
|
+
# Exclude utility modules that should never be the source of deprecated reflex usage.
|
|
198
|
+
exclude_modules = [click, rx, typer, typing_extensions]
|
|
199
|
+
exclude_roots = [
|
|
200
|
+
p.parent.resolve()
|
|
201
|
+
if (p := Path(m.__file__)).name == "__init__.py" # pyright: ignore [reportArgumentType]
|
|
202
|
+
else p.resolve()
|
|
203
|
+
for m in exclude_modules
|
|
204
|
+
]
|
|
205
|
+
# Specifically exclude the reflex cli module.
|
|
206
|
+
if reflex_bin := shutil.which(b"reflex"):
|
|
207
|
+
exclude_roots.append(Path(reflex_bin.decode()))
|
|
208
|
+
|
|
209
|
+
frame = inspect.currentframe()
|
|
210
|
+
while frame := frame and frame.f_back:
|
|
211
|
+
frame_path = Path(inspect.getfile(frame)).resolve()
|
|
212
|
+
if not any(frame_path.is_relative_to(root) for root in exclude_roots):
|
|
213
|
+
break
|
|
214
|
+
return frame
|
|
215
|
+
|
|
216
|
+
|
|
196
217
|
def deprecate(
|
|
197
218
|
feature_name: str,
|
|
198
219
|
reason: str,
|
|
@@ -211,15 +232,27 @@ def deprecate(
|
|
|
211
232
|
dedupe: If True, suppress multiple console logs of deprecation message.
|
|
212
233
|
kwargs: Keyword arguments to pass to the print function.
|
|
213
234
|
"""
|
|
214
|
-
|
|
235
|
+
dedupe_key = feature_name
|
|
236
|
+
loc = ""
|
|
237
|
+
|
|
238
|
+
# See if we can find where the deprecation exists in "user code"
|
|
239
|
+
origin_frame = _get_first_non_framework_frame()
|
|
240
|
+
if origin_frame is not None:
|
|
241
|
+
filename = Path(origin_frame.f_code.co_filename)
|
|
242
|
+
if filename.is_relative_to(Path.cwd()):
|
|
243
|
+
filename = filename.relative_to(Path.cwd())
|
|
244
|
+
loc = f"{filename}:{origin_frame.f_lineno}"
|
|
245
|
+
dedupe_key = f"{dedupe_key} {loc}"
|
|
246
|
+
|
|
247
|
+
if dedupe_key not in _EMITTED_DEPRECATION_WARNINGS:
|
|
215
248
|
msg = (
|
|
216
249
|
f"{feature_name} has been deprecated in version {deprecation_version} {reason.rstrip('.')}. It will be completely "
|
|
217
|
-
f"removed in {removal_version}"
|
|
250
|
+
f"removed in {removal_version}. ({loc})"
|
|
218
251
|
)
|
|
219
252
|
if _LOG_LEVEL <= LogLevel.WARNING:
|
|
220
253
|
print(f"[yellow]DeprecationWarning: {msg}[/yellow]", **kwargs)
|
|
221
254
|
if dedupe:
|
|
222
|
-
_EMITTED_DEPRECATION_WARNINGS.add(
|
|
255
|
+
_EMITTED_DEPRECATION_WARNINGS.add(dedupe_key)
|
|
223
256
|
|
|
224
257
|
|
|
225
258
|
def error(msg: str, dedupe: bool = False, **kwargs):
|
|
@@ -244,7 +277,7 @@ def ask(
|
|
|
244
277
|
choices: list[str] | None = None,
|
|
245
278
|
default: str | None = None,
|
|
246
279
|
show_choices: bool = True,
|
|
247
|
-
) -> str:
|
|
280
|
+
) -> str | None:
|
|
248
281
|
"""Takes a prompt question and optionally a list of choices
|
|
249
282
|
and returns the user input.
|
|
250
283
|
|
|
@@ -259,7 +292,7 @@ def ask(
|
|
|
259
292
|
"""
|
|
260
293
|
return Prompt.ask(
|
|
261
294
|
question, choices=choices, default=default, show_choices=show_choices
|
|
262
|
-
)
|
|
295
|
+
)
|
|
263
296
|
|
|
264
297
|
|
|
265
298
|
def progress():
|
|
@@ -286,3 +319,20 @@ def status(*args, **kwargs):
|
|
|
286
319
|
A new status.
|
|
287
320
|
"""
|
|
288
321
|
return _console.status(*args, **kwargs)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@contextlib.contextmanager
|
|
325
|
+
def timing(msg: str):
|
|
326
|
+
"""Create a context manager to time a block of code.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
msg: The message to display.
|
|
330
|
+
|
|
331
|
+
Yields:
|
|
332
|
+
None.
|
|
333
|
+
"""
|
|
334
|
+
start = time.time()
|
|
335
|
+
try:
|
|
336
|
+
yield
|
|
337
|
+
finally:
|
|
338
|
+
debug(f"[white]\\[timing] {msg}: {time.time() - start:.2f}s[/white]")
|
reflex/utils/exceptions.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Custom Exceptions."""
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class ReflexError(Exception):
|
|
@@ -11,7 +11,7 @@ class ConfigError(ReflexError):
|
|
|
11
11
|
"""Custom exception for config related errors."""
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class
|
|
14
|
+
class InvalidStateManagerModeError(ReflexError, ValueError):
|
|
15
15
|
"""Raised when an invalid state manager mode is provided."""
|
|
16
16
|
|
|
17
17
|
|
|
@@ -31,6 +31,22 @@ class ComponentTypeError(ReflexError, TypeError):
|
|
|
31
31
|
"""Custom TypeError for component related errors."""
|
|
32
32
|
|
|
33
33
|
|
|
34
|
+
class ChildrenTypeError(ComponentTypeError):
|
|
35
|
+
"""Raised when the children prop of a component is not a valid type."""
|
|
36
|
+
|
|
37
|
+
def __init__(self, component: str, child: Any):
|
|
38
|
+
"""Initialize the exception.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
component: The name of the component.
|
|
42
|
+
child: The child that caused the error.
|
|
43
|
+
"""
|
|
44
|
+
super().__init__(
|
|
45
|
+
f"Component {component} received child {child} of type {type(child)}. "
|
|
46
|
+
"Accepted types are other components, state vars, or primitive Python types (dict excluded)."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
34
50
|
class EventHandlerTypeError(ReflexError, TypeError):
|
|
35
51
|
"""Custom TypeError for event handler related errors."""
|
|
36
52
|
|
|
@@ -59,6 +75,47 @@ class VarAttributeError(ReflexError, AttributeError):
|
|
|
59
75
|
"""Custom AttributeError for var related errors."""
|
|
60
76
|
|
|
61
77
|
|
|
78
|
+
class UntypedVarError(ReflexError, TypeError):
|
|
79
|
+
"""Custom TypeError for untyped var errors."""
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class UntypedComputedVarError(ReflexError, TypeError):
|
|
83
|
+
"""Custom TypeError for untyped computed var errors."""
|
|
84
|
+
|
|
85
|
+
def __init__(self, var_name: str):
|
|
86
|
+
"""Initialize the UntypedComputedVarError.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
var_name: The name of the computed var.
|
|
90
|
+
"""
|
|
91
|
+
super().__init__(f"Computed var '{var_name}' must have a type annotation.")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class ComputedVarSignatureError(ReflexError, TypeError):
|
|
95
|
+
"""Custom TypeError for computed var signature errors."""
|
|
96
|
+
|
|
97
|
+
def __init__(self, var_name: str, signature: str):
|
|
98
|
+
"""Initialize the ComputedVarSignatureError.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
var_name: The name of the var.
|
|
102
|
+
signature: The invalid signature.
|
|
103
|
+
"""
|
|
104
|
+
super().__init__(f"Computed var `{var_name}{signature}` cannot take arguments.")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class MissingAnnotationError(ReflexError, TypeError):
|
|
108
|
+
"""Custom TypeError for missing annotations."""
|
|
109
|
+
|
|
110
|
+
def __init__(self, var_name: str):
|
|
111
|
+
"""Initialize the MissingAnnotationError.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
var_name: The name of the var.
|
|
115
|
+
"""
|
|
116
|
+
super().__init__(f"Var '{var_name}' must have a type annotation.")
|
|
117
|
+
|
|
118
|
+
|
|
62
119
|
class UploadValueError(ReflexError, ValueError):
|
|
63
120
|
"""Custom ValueError for upload related errors."""
|
|
64
121
|
|
|
@@ -95,43 +152,43 @@ class MatchTypeError(ReflexError, TypeError):
|
|
|
95
152
|
"""Raised when the return types of match cases are different."""
|
|
96
153
|
|
|
97
154
|
|
|
98
|
-
class
|
|
155
|
+
class EventHandlerArgTypeMismatchError(ReflexError, TypeError):
|
|
99
156
|
"""Raised when the annotations of args accepted by an EventHandler differs from the spec of the event trigger."""
|
|
100
157
|
|
|
101
158
|
|
|
102
|
-
class
|
|
159
|
+
class EventFnArgMismatchError(ReflexError, TypeError):
|
|
103
160
|
"""Raised when the number of args required by an event handler is more than provided by the event trigger."""
|
|
104
161
|
|
|
105
162
|
|
|
106
|
-
class
|
|
163
|
+
class DynamicRouteArgShadowsStateVarError(ReflexError, NameError):
|
|
107
164
|
"""Raised when a dynamic route arg shadows a state var."""
|
|
108
165
|
|
|
109
166
|
|
|
110
|
-
class
|
|
167
|
+
class ComputedVarShadowsStateVarError(ReflexError, NameError):
|
|
111
168
|
"""Raised when a computed var shadows a state var."""
|
|
112
169
|
|
|
113
170
|
|
|
114
|
-
class
|
|
171
|
+
class ComputedVarShadowsBaseVarsError(ReflexError, NameError):
|
|
115
172
|
"""Raised when a computed var shadows a base var."""
|
|
116
173
|
|
|
117
174
|
|
|
118
|
-
class
|
|
175
|
+
class EventHandlerShadowsBuiltInStateMethodError(ReflexError, NameError):
|
|
119
176
|
"""Raised when an event handler shadows a built-in state method."""
|
|
120
177
|
|
|
121
178
|
|
|
122
|
-
class
|
|
179
|
+
class GeneratedCodeHasNoFunctionDefsError(ReflexError):
|
|
123
180
|
"""Raised when refactored code generated with flexgen has no functions defined."""
|
|
124
181
|
|
|
125
182
|
|
|
126
|
-
class
|
|
183
|
+
class PrimitiveUnserializableToJSONError(ReflexError, ValueError):
|
|
127
184
|
"""Raised when a primitive type is unserializable to JSON. Usually with NaN and Infinity."""
|
|
128
185
|
|
|
129
186
|
|
|
130
|
-
class
|
|
187
|
+
class InvalidLifespanTaskTypeError(ReflexError, TypeError):
|
|
131
188
|
"""Raised when an invalid task type is registered as a lifespan task."""
|
|
132
189
|
|
|
133
190
|
|
|
134
|
-
class
|
|
191
|
+
class DynamicComponentMissingLibraryError(ReflexError, ValueError):
|
|
135
192
|
"""Raised when a dynamic component is missing a library."""
|
|
136
193
|
|
|
137
194
|
|
|
@@ -147,7 +204,7 @@ class EnvironmentVarValueError(ReflexError, ValueError):
|
|
|
147
204
|
"""Raised when an environment variable is set to an invalid value."""
|
|
148
205
|
|
|
149
206
|
|
|
150
|
-
class
|
|
207
|
+
class DynamicComponentInvalidSignatureError(ReflexError, TypeError):
|
|
151
208
|
"""Raised when a dynamic component has an invalid signature."""
|
|
152
209
|
|
|
153
210
|
|
|
@@ -163,26 +220,32 @@ class StateSerializationError(ReflexError):
|
|
|
163
220
|
"""Raised when the state cannot be serialized."""
|
|
164
221
|
|
|
165
222
|
|
|
223
|
+
class StateMismatchError(ReflexError, ValueError):
|
|
224
|
+
"""Raised when the state retrieved does not match the expected state."""
|
|
225
|
+
|
|
226
|
+
|
|
166
227
|
class SystemPackageMissingError(ReflexError):
|
|
167
228
|
"""Raised when a system package is missing."""
|
|
168
229
|
|
|
230
|
+
def __init__(self, package: str):
|
|
231
|
+
"""Initialize the SystemPackageMissingError.
|
|
169
232
|
|
|
170
|
-
|
|
171
|
-
|
|
233
|
+
Args:
|
|
234
|
+
package: The missing package.
|
|
235
|
+
"""
|
|
236
|
+
from reflex.constants import IS_MACOS
|
|
172
237
|
|
|
173
|
-
|
|
174
|
-
|
|
238
|
+
extra = (
|
|
239
|
+
f" You can do so by running 'brew install {package}'." if IS_MACOS else ""
|
|
240
|
+
)
|
|
241
|
+
super().__init__(
|
|
242
|
+
f"System package '{package}' is missing."
|
|
243
|
+
f" Please install it through your system package manager.{extra}"
|
|
244
|
+
)
|
|
175
245
|
|
|
176
|
-
Raises:
|
|
177
|
-
SystemPackageMissingError: The raised exception.
|
|
178
|
-
"""
|
|
179
|
-
from reflex.constants import IS_MACOS
|
|
180
246
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
" Please install it through your system package manager."
|
|
184
|
-
+ (f" You can do so by running 'brew install {package}'." if IS_MACOS else "")
|
|
185
|
-
)
|
|
247
|
+
class EventDeserializationError(ReflexError, ValueError):
|
|
248
|
+
"""Raised when an event cannot be deserialized."""
|
|
186
249
|
|
|
187
250
|
|
|
188
251
|
class InvalidLockWarningThresholdError(ReflexError):
|