reflex 0.5.5a2__py3-none-any.whl → 0.5.6__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/web/pages/_app.js.jinja2 +0 -1
- reflex/.templates/jinja/web/utils/context.js.jinja2 +2 -0
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +20 -2
- reflex/.templates/web/utils/helpers/paste.js +59 -0
- reflex/__init__.py +9 -1
- reflex/__init__.pyi +89 -87
- reflex/app.py +64 -126
- reflex/app_mixins/__init__.py +5 -0
- reflex/app_mixins/lifespan.py +57 -0
- reflex/app_mixins/middleware.py +93 -0
- reflex/app_mixins/mixin.py +14 -0
- reflex/compiler/compiler.py +6 -1
- reflex/components/__init__.pyi +0 -2
- reflex/components/base/__init__.pyi +1 -3
- reflex/components/base/app_wrap.pyi +21 -22
- reflex/components/base/body.pyi +21 -20
- reflex/components/base/document.pyi +85 -85
- reflex/components/base/fragment.pyi +21 -20
- reflex/components/base/head.pyi +37 -36
- reflex/components/base/link.pyi +37 -37
- reflex/components/base/meta.pyi +69 -70
- reflex/components/base/script.py +6 -2
- reflex/components/base/script.pyi +31 -27
- reflex/components/chakra/base.pyi +54 -56
- reflex/components/chakra/datadisplay/badge.pyi +21 -21
- reflex/components/chakra/datadisplay/code.pyi +21 -20
- reflex/components/chakra/datadisplay/divider.pyi +21 -22
- reflex/components/chakra/datadisplay/keyboard_key.pyi +21 -20
- reflex/components/chakra/datadisplay/list.pyi +69 -71
- reflex/components/chakra/datadisplay/stat.pyi +101 -102
- reflex/components/chakra/datadisplay/table.pyi +149 -153
- reflex/components/chakra/datadisplay/tag.pyi +85 -89
- reflex/components/chakra/disclosure/accordion.pyi +87 -93
- reflex/components/chakra/disclosure/tabs.pyi +85 -90
- reflex/components/chakra/disclosure/transition.pyi +104 -105
- reflex/components/chakra/disclosure/visuallyhidden.pyi +21 -20
- reflex/components/chakra/feedback/alert.pyi +69 -70
- reflex/components/chakra/feedback/circularprogress.pyi +38 -40
- reflex/components/chakra/feedback/progress.pyi +22 -23
- reflex/components/chakra/feedback/skeleton.pyi +53 -53
- reflex/components/chakra/feedback/spinner.pyi +21 -21
- reflex/components/chakra/forms/button.pyi +37 -42
- reflex/components/chakra/forms/checkbox.pyi +38 -39
- reflex/components/chakra/forms/colormodeswitch.pyi +72 -71
- reflex/components/chakra/forms/date_picker.pyi +24 -24
- reflex/components/chakra/forms/date_time_picker.pyi +24 -24
- reflex/components/chakra/forms/editable.pyi +73 -74
- reflex/components/chakra/forms/email.pyi +24 -24
- reflex/components/chakra/forms/form.pyi +112 -141
- reflex/components/chakra/forms/iconbutton.pyi +21 -22
- reflex/components/chakra/forms/input.pyi +104 -111
- reflex/components/chakra/forms/numberinput.pyi +87 -91
- reflex/components/chakra/forms/password.pyi +24 -24
- reflex/components/chakra/forms/pininput.pyi +39 -45
- reflex/components/chakra/forms/radio.pyi +38 -43
- reflex/components/chakra/forms/rangeslider.pyi +72 -76
- reflex/components/chakra/forms/select.pyi +39 -44
- reflex/components/chakra/forms/slider.pyi +88 -91
- reflex/components/chakra/forms/switch.pyi +22 -23
- reflex/components/chakra/forms/textarea.pyi +24 -27
- reflex/components/chakra/forms/time_picker.pyi +24 -24
- reflex/components/chakra/layout/aspect_ratio.pyi +21 -21
- reflex/components/chakra/layout/box.pyi +21 -22
- reflex/components/chakra/layout/card.pyi +69 -73
- reflex/components/chakra/layout/center.pyi +53 -52
- reflex/components/chakra/layout/container.pyi +21 -21
- reflex/components/chakra/layout/flex.pyi +23 -26
- reflex/components/chakra/layout/grid.pyi +53 -54
- reflex/components/chakra/layout/spacer.pyi +21 -20
- reflex/components/chakra/layout/stack.pyi +62 -60
- reflex/components/chakra/layout/wrap.pyi +37 -38
- reflex/components/chakra/media/avatar.pyi +54 -55
- reflex/components/chakra/media/icon.pyi +37 -38
- reflex/components/chakra/media/image.pyi +24 -26
- reflex/components/chakra/navigation/breadcrumb.pyi +69 -71
- reflex/components/chakra/navigation/link.pyi +20 -21
- reflex/components/chakra/navigation/linkoverlay.pyi +37 -37
- reflex/components/chakra/navigation/stepper.pyi +149 -151
- reflex/components/chakra/overlay/alertdialog.pyi +121 -124
- reflex/components/chakra/overlay/drawer.pyi +121 -126
- reflex/components/chakra/overlay/menu.pyi +135 -141
- reflex/components/chakra/overlay/modal.pyi +121 -124
- reflex/components/chakra/overlay/popover.pyi +151 -156
- reflex/components/chakra/overlay/tooltip.pyi +23 -24
- reflex/components/chakra/typography/heading.pyi +21 -21
- reflex/components/chakra/typography/highlight.pyi +21 -23
- reflex/components/chakra/typography/span.pyi +21 -21
- reflex/components/chakra/typography/text.pyi +21 -21
- reflex/components/component.py +6 -2
- reflex/components/core/__init__.py +2 -0
- reflex/components/core/__init__.pyi +9 -7
- reflex/components/core/banner.pyi +118 -146
- reflex/components/core/breakpoints.py +95 -0
- reflex/components/core/client_side_routing.pyi +37 -39
- reflex/components/core/clipboard.py +95 -0
- reflex/components/core/clipboard.pyi +102 -0
- reflex/components/core/debounce.pyi +23 -28
- reflex/components/core/foreach.py +3 -2
- reflex/components/core/html.pyi +38 -55
- reflex/components/core/upload.py +1 -1
- reflex/components/core/upload.pyi +74 -91
- reflex/components/datadisplay/__init__.pyi +2 -3
- reflex/components/datadisplay/code.py +3 -3
- reflex/components/datadisplay/code.pyi +22 -31
- reflex/components/datadisplay/dataeditor.pyi +41 -45
- reflex/components/el/__init__.pyi +131 -135
- reflex/components/el/element.pyi +21 -20
- reflex/components/el/elements/__init__.pyi +131 -132
- reflex/components/el/elements/base.pyi +38 -55
- reflex/components/el/elements/forms.pyi +558 -878
- reflex/components/el/elements/inline.pyi +941 -1403
- reflex/components/el/elements/media.pyi +645 -994
- reflex/components/el/elements/metadata.pyi +186 -268
- reflex/components/el/elements/other.pyi +239 -353
- reflex/components/el/elements/scripts.pyi +113 -171
- reflex/components/el/elements/sectioning.pyi +500 -739
- reflex/components/el/elements/tables.pyi +355 -551
- reflex/components/el/elements/typography.pyi +510 -760
- reflex/components/gridjs/datatable.pyi +38 -42
- reflex/components/lucide/icon.pyi +37 -38
- reflex/components/markdown/markdown.pyi +23 -36
- reflex/components/moment/moment.pyi +23 -25
- reflex/components/next/base.pyi +21 -20
- reflex/components/next/image.pyi +25 -27
- reflex/components/next/link.pyi +21 -21
- reflex/components/next/video.pyi +22 -22
- reflex/components/plotly/plotly.pyi +42 -45
- reflex/components/radix/__init__.pyi +26 -30
- reflex/components/radix/primitives/__init__.pyi +0 -2
- reflex/components/radix/primitives/accordion.pyi +119 -127
- reflex/components/radix/primitives/base.pyi +37 -40
- reflex/components/radix/primitives/drawer.pyi +175 -179
- reflex/components/radix/primitives/form.pyi +250 -336
- reflex/components/radix/primitives/progress.pyi +92 -96
- reflex/components/radix/primitives/slider.pyi +87 -89
- reflex/components/radix/themes/__init__.pyi +0 -2
- reflex/components/radix/themes/base.pyi +118 -121
- reflex/components/radix/themes/color_mode.pyi +103 -117
- reflex/components/radix/themes/components/__init__.pyi +12 -14
- reflex/components/radix/themes/components/alert_dialog.py +2 -1
- reflex/components/radix/themes/components/alert_dialog.pyi +150 -157
- reflex/components/radix/themes/components/aspect_ratio.pyi +22 -22
- reflex/components/radix/themes/components/avatar.py +2 -1
- reflex/components/radix/themes/components/avatar.pyi +32 -23
- reflex/components/radix/themes/components/badge.py +2 -1
- reflex/components/radix/themes/components/badge.pyi +50 -57
- reflex/components/radix/themes/components/button.py +2 -1
- reflex/components/radix/themes/components/button.pyi +60 -79
- reflex/components/radix/themes/components/callout.py +2 -1
- reflex/components/radix/themes/components/callout.pyi +201 -258
- reflex/components/radix/themes/components/card.py +2 -1
- reflex/components/radix/themes/components/card.pyi +48 -56
- reflex/components/radix/themes/components/checkbox.py +2 -1
- reflex/components/radix/themes/components/checkbox.pyi +68 -62
- reflex/components/radix/themes/components/checkbox_cards.py +8 -3
- reflex/components/radix/themes/components/checkbox_cards.pyi +87 -44
- reflex/components/radix/themes/components/checkbox_group.py +2 -1
- reflex/components/radix/themes/components/checkbox_group.pyi +49 -40
- reflex/components/radix/themes/components/context_menu.py +2 -1
- reflex/components/radix/themes/components/context_menu.pyi +153 -147
- reflex/components/radix/themes/components/data_list.py +8 -7
- reflex/components/radix/themes/components/data_list.pyi +116 -78
- reflex/components/radix/themes/components/dialog.py +2 -1
- reflex/components/radix/themes/components/dialog.pyi +154 -161
- reflex/components/radix/themes/components/dropdown_menu.py +2 -1
- reflex/components/radix/themes/components/dropdown_menu.pyi +169 -163
- reflex/components/radix/themes/components/hover_card.py +2 -1
- reflex/components/radix/themes/components/hover_card.pyi +97 -107
- reflex/components/radix/themes/components/icon_button.py +2 -1
- reflex/components/radix/themes/components/icon_button.pyi +59 -82
- reflex/components/radix/themes/components/inset.py +10 -9
- reflex/components/radix/themes/components/inset.pyi +109 -61
- reflex/components/radix/themes/components/popover.py +2 -1
- reflex/components/radix/themes/components/popover.pyi +105 -112
- reflex/components/radix/themes/components/progress.py +2 -1
- reflex/components/radix/themes/components/progress.pyi +32 -24
- reflex/components/radix/themes/components/radio.py +2 -1
- reflex/components/radix/themes/components/radio.pyi +32 -23
- reflex/components/radix/themes/components/radio_cards.py +51 -3
- reflex/components/radix/themes/components/radio_cards.pyi +120 -44
- reflex/components/radix/themes/components/radio_group.py +5 -2
- reflex/components/radix/themes/components/radio_group.pyi +82 -77
- reflex/components/radix/themes/components/scroll_area.pyi +21 -21
- reflex/components/radix/themes/components/segmented_control.py +2 -1
- reflex/components/radix/themes/components/segmented_control.pyi +52 -46
- reflex/components/radix/themes/components/select.py +2 -1
- reflex/components/radix/themes/components/select.pyi +188 -164
- reflex/components/radix/themes/components/separator.py +5 -2
- reflex/components/radix/themes/components/separator.pyi +40 -24
- reflex/components/radix/themes/components/skeleton.py +7 -6
- reflex/components/radix/themes/components/skeleton.pyi +40 -26
- reflex/components/radix/themes/components/slider.py +2 -1
- reflex/components/radix/themes/components/slider.pyi +40 -31
- reflex/components/radix/themes/components/spinner.py +2 -1
- reflex/components/radix/themes/components/spinner.pyi +31 -22
- reflex/components/radix/themes/components/switch.py +2 -1
- reflex/components/radix/themes/components/switch.pyi +33 -25
- reflex/components/radix/themes/components/table.py +2 -1
- reflex/components/radix/themes/components/table.pyi +265 -404
- reflex/components/radix/themes/components/tabs.py +14 -1
- reflex/components/radix/themes/components/tabs.pyi +113 -92
- reflex/components/radix/themes/components/text_area.py +3 -2
- reflex/components/radix/themes/components/text_area.pyi +64 -66
- reflex/components/radix/themes/components/text_field.py +2 -1
- reflex/components/radix/themes/components/text_field.pyi +116 -140
- reflex/components/radix/themes/components/tooltip.pyi +32 -37
- reflex/components/radix/themes/layout/__init__.pyi +4 -7
- reflex/components/radix/themes/layout/base.py +10 -9
- reflex/components/radix/themes/layout/base.pyi +121 -31
- reflex/components/radix/themes/layout/box.pyi +39 -53
- reflex/components/radix/themes/layout/center.pyi +89 -58
- reflex/components/radix/themes/layout/container.py +4 -1
- reflex/components/radix/themes/layout/container.pyi +51 -58
- reflex/components/radix/themes/layout/flex.py +6 -5
- reflex/components/radix/themes/layout/flex.pyi +91 -61
- reflex/components/radix/themes/layout/grid.py +9 -8
- reflex/components/radix/themes/layout/grid.pyi +116 -64
- reflex/components/radix/themes/layout/list.pyi +173 -233
- reflex/components/radix/themes/layout/section.py +4 -1
- reflex/components/radix/themes/layout/section.pyi +50 -57
- reflex/components/radix/themes/layout/spacer.pyi +89 -58
- reflex/components/radix/themes/layout/stack.pyi +160 -160
- reflex/components/radix/themes/typography/__init__.pyi +0 -2
- reflex/components/radix/themes/typography/blockquote.py +3 -2
- reflex/components/radix/themes/typography/blockquote.pyi +58 -59
- reflex/components/radix/themes/typography/code.py +3 -2
- reflex/components/radix/themes/typography/code.pyi +57 -58
- reflex/components/radix/themes/typography/heading.py +5 -4
- reflex/components/radix/themes/typography/heading.pyi +71 -60
- reflex/components/radix/themes/typography/link.py +4 -3
- reflex/components/radix/themes/typography/link.pyi +74 -82
- reflex/components/radix/themes/typography/text.py +5 -4
- reflex/components/radix/themes/typography/text.pyi +330 -364
- reflex/components/react_player/audio.pyi +37 -36
- reflex/components/react_player/react_player.pyi +37 -38
- reflex/components/react_player/video.pyi +37 -36
- reflex/components/recharts/__init__.pyi +41 -42
- reflex/components/recharts/cartesian.pyi +384 -400
- reflex/components/recharts/charts.pyi +224 -231
- reflex/components/recharts/general.pyi +89 -96
- reflex/components/recharts/polar.pyi +97 -104
- reflex/components/recharts/recharts.pyi +37 -37
- reflex/components/sonner/toast.pyi +22 -27
- reflex/components/suneditor/editor.pyi +53 -58
- reflex/config.py +6 -0
- reflex/constants/event.py +1 -0
- reflex/experimental/layout.pyi +140 -194
- reflex/model.py +14 -2
- reflex/state.py +55 -45
- reflex/style.py +24 -13
- reflex/utils/codespaces.py +94 -0
- reflex/utils/compat.py +21 -0
- reflex/utils/exceptions.py +4 -0
- reflex/utils/format.py +25 -4
- reflex/utils/prerequisites.py +0 -13
- reflex/utils/pyi_generator.py +88 -61
- reflex/utils/types.py +83 -5
- reflex/vars.py +62 -5
- reflex/vars.pyi +23 -11
- {reflex-0.5.5a2.dist-info → reflex-0.5.6.dist-info}/METADATA +4 -5
- {reflex-0.5.5a2.dist-info → reflex-0.5.6.dist-info}/RECORD +264 -255
- {reflex-0.5.5a2.dist-info → reflex-0.5.6.dist-info}/LICENSE +0 -0
- {reflex-0.5.5a2.dist-info → reflex-0.5.6.dist-info}/WHEEL +0 -0
- {reflex-0.5.5a2.dist-info → reflex-0.5.6.dist-info}/entry_points.txt +0 -0
reflex/state.py
CHANGED
|
@@ -40,6 +40,7 @@ from redis.exceptions import ResponseError
|
|
|
40
40
|
|
|
41
41
|
from reflex import constants
|
|
42
42
|
from reflex.base import Base
|
|
43
|
+
from reflex.config import get_config
|
|
43
44
|
from reflex.event import (
|
|
44
45
|
BACKGROUND_TASK_MARKER,
|
|
45
46
|
Event,
|
|
@@ -197,16 +198,6 @@ def _no_chain_background_task(
|
|
|
197
198
|
raise TypeError(f"{fn} is marked as a background task, but is not async.")
|
|
198
199
|
|
|
199
200
|
|
|
200
|
-
RESERVED_BACKEND_VAR_NAMES = {
|
|
201
|
-
"_backend_vars",
|
|
202
|
-
"_computed_var_dependencies",
|
|
203
|
-
"_substate_var_dependencies",
|
|
204
|
-
"_always_dirty_computed_vars",
|
|
205
|
-
"_always_dirty_substates",
|
|
206
|
-
"_was_touched",
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
201
|
def _substate_key(
|
|
211
202
|
token: str,
|
|
212
203
|
state_cls_or_name: BaseState | Type[BaseState] | str | list[str],
|
|
@@ -313,10 +304,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
313
304
|
# Vars inherited by the parent state.
|
|
314
305
|
inherited_vars: ClassVar[Dict[str, Var]] = {}
|
|
315
306
|
|
|
316
|
-
# Backend vars that are never sent to the client.
|
|
307
|
+
# Backend base vars that are never sent to the client.
|
|
317
308
|
backend_vars: ClassVar[Dict[str, Any]] = {}
|
|
318
309
|
|
|
319
|
-
# Backend vars inherited
|
|
310
|
+
# Backend base vars inherited
|
|
320
311
|
inherited_backend_vars: ClassVar[Dict[str, Any]] = {}
|
|
321
312
|
|
|
322
313
|
# The event handlers.
|
|
@@ -352,7 +343,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
352
343
|
# The routing path that triggered the state
|
|
353
344
|
router_data: Dict[str, Any] = {}
|
|
354
345
|
|
|
355
|
-
# Per-instance copy of backend variable values
|
|
346
|
+
# Per-instance copy of backend base variable values
|
|
356
347
|
_backend_vars: Dict[str, Any] = {}
|
|
357
348
|
|
|
358
349
|
# The router data for the current page
|
|
@@ -409,11 +400,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
409
400
|
|
|
410
401
|
# Create a fresh copy of the backend variables for this instance
|
|
411
402
|
self._backend_vars = copy.deepcopy(
|
|
412
|
-
{
|
|
413
|
-
name: item
|
|
414
|
-
for name, item in self.backend_vars.items()
|
|
415
|
-
if name not in self.computed_vars
|
|
416
|
-
}
|
|
403
|
+
{name: item for name, item in self.backend_vars.items()}
|
|
417
404
|
)
|
|
418
405
|
|
|
419
406
|
def __repr__(self) -> str:
|
|
@@ -500,25 +487,12 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
500
487
|
new_backend_vars = {
|
|
501
488
|
name: value
|
|
502
489
|
for name, value in cls.__dict__.items()
|
|
503
|
-
if types.
|
|
504
|
-
and name not in RESERVED_BACKEND_VAR_NAMES
|
|
505
|
-
and name not in cls.inherited_backend_vars
|
|
506
|
-
and not isinstance(value, FunctionType)
|
|
507
|
-
and not isinstance(value, ComputedVar)
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
# Get backend computed vars
|
|
511
|
-
backend_computed_vars = {
|
|
512
|
-
v._var_name: v._var_set_state(cls)
|
|
513
|
-
for v in computed_vars
|
|
514
|
-
if types.is_backend_variable(v._var_name, cls)
|
|
515
|
-
and v._var_name not in cls.inherited_backend_vars
|
|
490
|
+
if types.is_backend_base_variable(name, cls)
|
|
516
491
|
}
|
|
517
492
|
|
|
518
493
|
cls.backend_vars = {
|
|
519
494
|
**cls.inherited_backend_vars,
|
|
520
495
|
**new_backend_vars,
|
|
521
|
-
**backend_computed_vars,
|
|
522
496
|
}
|
|
523
497
|
|
|
524
498
|
# Set the base and computed vars.
|
|
@@ -560,6 +534,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
560
534
|
cls.computed_vars[newcv._var_name] = newcv
|
|
561
535
|
cls.vars[newcv._var_name] = newcv
|
|
562
536
|
continue
|
|
537
|
+
if types.is_backend_base_variable(name, mixin):
|
|
538
|
+
cls.backend_vars[name] = copy.deepcopy(value)
|
|
539
|
+
continue
|
|
563
540
|
if events.get(name) is not None:
|
|
564
541
|
continue
|
|
565
542
|
if not cls._item_is_event_handler(name, value):
|
|
@@ -743,7 +720,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
743
720
|
"dirty_substates",
|
|
744
721
|
"router_data",
|
|
745
722
|
}
|
|
746
|
-
| RESERVED_BACKEND_VAR_NAMES
|
|
723
|
+
| types.RESERVED_BACKEND_VAR_NAMES
|
|
747
724
|
)
|
|
748
725
|
|
|
749
726
|
@classmethod
|
|
@@ -1096,10 +1073,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1096
1073
|
setattr(self.parent_state, name, value)
|
|
1097
1074
|
return
|
|
1098
1075
|
|
|
1099
|
-
if
|
|
1100
|
-
types.is_backend_variable(name, self.__class__)
|
|
1101
|
-
and name not in RESERVED_BACKEND_VAR_NAMES
|
|
1102
|
-
):
|
|
1076
|
+
if name in self.backend_vars:
|
|
1103
1077
|
self._backend_vars.__setitem__(name, value)
|
|
1104
1078
|
self.dirty_vars.add(name)
|
|
1105
1079
|
self._mark_dirty()
|
|
@@ -1550,11 +1524,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1550
1524
|
if self.computed_vars[cvar].needs_update(instance=self)
|
|
1551
1525
|
)
|
|
1552
1526
|
|
|
1553
|
-
def _dirty_computed_vars(
|
|
1527
|
+
def _dirty_computed_vars(
|
|
1528
|
+
self, from_vars: set[str] | None = None, include_backend: bool = True
|
|
1529
|
+
) -> set[str]:
|
|
1554
1530
|
"""Determine ComputedVars that need to be recalculated based on the given vars.
|
|
1555
1531
|
|
|
1556
1532
|
Args:
|
|
1557
1533
|
from_vars: find ComputedVar that depend on this set of vars. If unspecified, will use the dirty_vars.
|
|
1534
|
+
include_backend: whether to include backend vars in the calculation.
|
|
1558
1535
|
|
|
1559
1536
|
Returns:
|
|
1560
1537
|
Set of computed vars to include in the delta.
|
|
@@ -1563,6 +1540,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1563
1540
|
cvar
|
|
1564
1541
|
for dirty_var in from_vars or self.dirty_vars
|
|
1565
1542
|
for cvar in self._computed_var_dependencies[dirty_var]
|
|
1543
|
+
if include_backend or not self.computed_vars[cvar]._backend
|
|
1566
1544
|
)
|
|
1567
1545
|
|
|
1568
1546
|
@classmethod
|
|
@@ -1598,19 +1576,23 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1598
1576
|
self.dirty_vars.update(self._always_dirty_computed_vars)
|
|
1599
1577
|
self._mark_dirty()
|
|
1600
1578
|
|
|
1579
|
+
frontend_computed_vars: set[str] = {
|
|
1580
|
+
name for name, cv in self.computed_vars.items() if not cv._backend
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1601
1583
|
# Return the dirty vars for this instance, any cached/dependent computed vars,
|
|
1602
1584
|
# and always dirty computed vars (cache=False)
|
|
1603
1585
|
delta_vars = (
|
|
1604
1586
|
self.dirty_vars.intersection(self.base_vars)
|
|
1605
|
-
.union(self.dirty_vars.intersection(
|
|
1606
|
-
.union(self._dirty_computed_vars())
|
|
1587
|
+
.union(self.dirty_vars.intersection(frontend_computed_vars))
|
|
1588
|
+
.union(self._dirty_computed_vars(include_backend=False))
|
|
1607
1589
|
.union(self._always_dirty_computed_vars)
|
|
1608
1590
|
)
|
|
1609
1591
|
|
|
1610
1592
|
subdelta = {
|
|
1611
1593
|
prop: getattr(self, prop)
|
|
1612
1594
|
for prop in delta_vars
|
|
1613
|
-
if not types.
|
|
1595
|
+
if not types.is_backend_base_variable(prop, type(self))
|
|
1614
1596
|
}
|
|
1615
1597
|
if len(subdelta) > 0:
|
|
1616
1598
|
delta[self.get_full_name()] = subdelta
|
|
@@ -1739,12 +1721,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1739
1721
|
else self.get_value(getattr(self, prop_name))
|
|
1740
1722
|
)
|
|
1741
1723
|
for prop_name, cv in self.computed_vars.items()
|
|
1724
|
+
if not cv._backend
|
|
1742
1725
|
}
|
|
1743
1726
|
elif include_computed:
|
|
1744
1727
|
computed_vars = {
|
|
1745
1728
|
# Include the computed vars.
|
|
1746
1729
|
prop_name: self.get_value(getattr(self, prop_name))
|
|
1747
|
-
for prop_name in self.computed_vars
|
|
1730
|
+
for prop_name, cv in self.computed_vars.items()
|
|
1731
|
+
if not cv._backend
|
|
1748
1732
|
}
|
|
1749
1733
|
else:
|
|
1750
1734
|
computed_vars = {}
|
|
@@ -1757,6 +1741,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1757
1741
|
for v in self.substates.values()
|
|
1758
1742
|
]:
|
|
1759
1743
|
d.update(substate_d)
|
|
1744
|
+
|
|
1760
1745
|
return d
|
|
1761
1746
|
|
|
1762
1747
|
async def __aenter__(self) -> BaseState:
|
|
@@ -2202,7 +2187,14 @@ class StateManager(Base, ABC):
|
|
|
2202
2187
|
"""
|
|
2203
2188
|
redis = prerequisites.get_redis()
|
|
2204
2189
|
if redis is not None:
|
|
2205
|
-
|
|
2190
|
+
# make sure expiration values are obtained only from the config object on creation
|
|
2191
|
+
config = get_config()
|
|
2192
|
+
return StateManagerRedis(
|
|
2193
|
+
state=state,
|
|
2194
|
+
redis=redis,
|
|
2195
|
+
token_expiration=config.redis_token_expiration,
|
|
2196
|
+
lock_expiration=config.redis_lock_expiration,
|
|
2197
|
+
)
|
|
2206
2198
|
return StateManagerMemory(state=state)
|
|
2207
2199
|
|
|
2208
2200
|
@abstractmethod
|
|
@@ -2326,6 +2318,24 @@ def _dill_reduce_state(pickler, obj):
|
|
|
2326
2318
|
dill.Pickler.dispatch[type](pickler, obj)
|
|
2327
2319
|
|
|
2328
2320
|
|
|
2321
|
+
def _default_lock_expiration() -> int:
|
|
2322
|
+
"""Get the default lock expiration time.
|
|
2323
|
+
|
|
2324
|
+
Returns:
|
|
2325
|
+
The default lock expiration time.
|
|
2326
|
+
"""
|
|
2327
|
+
return get_config().redis_lock_expiration
|
|
2328
|
+
|
|
2329
|
+
|
|
2330
|
+
def _default_token_expiration() -> int:
|
|
2331
|
+
"""Get the default token expiration time.
|
|
2332
|
+
|
|
2333
|
+
Returns:
|
|
2334
|
+
The default token expiration time.
|
|
2335
|
+
"""
|
|
2336
|
+
return get_config().redis_token_expiration
|
|
2337
|
+
|
|
2338
|
+
|
|
2329
2339
|
class StateManagerRedis(StateManager):
|
|
2330
2340
|
"""A state manager that stores states in redis."""
|
|
2331
2341
|
|
|
@@ -2333,10 +2343,10 @@ class StateManagerRedis(StateManager):
|
|
|
2333
2343
|
redis: Redis
|
|
2334
2344
|
|
|
2335
2345
|
# The token expiration time (s).
|
|
2336
|
-
token_expiration: int =
|
|
2346
|
+
token_expiration: int = pydantic.Field(default_factory=_default_token_expiration)
|
|
2337
2347
|
|
|
2338
2348
|
# The maximum time to hold a lock (ms).
|
|
2339
|
-
lock_expiration: int =
|
|
2349
|
+
lock_expiration: int = pydantic.Field(default_factory=_default_lock_expiration)
|
|
2340
2350
|
|
|
2341
2351
|
# The keyspace subscription string when redis is waiting for lock to be released
|
|
2342
2352
|
_redis_notify_keyspace_events: str = (
|
reflex/style.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from typing import Any, Literal, Tuple, Type
|
|
6
6
|
|
|
7
7
|
from reflex import constants
|
|
8
|
+
from reflex.components.core.breakpoints import Breakpoints, breakpoints_values
|
|
8
9
|
from reflex.event import EventChain
|
|
9
10
|
from reflex.utils import format
|
|
10
11
|
from reflex.utils.imports import ImportVar
|
|
@@ -86,8 +87,6 @@ toggle_color_mode = _color_mode_var(
|
|
|
86
87
|
_var_type=EventChain,
|
|
87
88
|
)
|
|
88
89
|
|
|
89
|
-
breakpoints = ["0", "30em", "48em", "62em", "80em", "96em"]
|
|
90
|
-
|
|
91
90
|
STYLE_PROP_SHORTHAND_MAPPING = {
|
|
92
91
|
"paddingX": ("paddingInlineStart", "paddingInlineEnd"),
|
|
93
92
|
"paddingY": ("paddingTop", "paddingBottom"),
|
|
@@ -100,16 +99,16 @@ STYLE_PROP_SHORTHAND_MAPPING = {
|
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
|
|
103
|
-
def media_query(
|
|
102
|
+
def media_query(breakpoint_expr: str):
|
|
104
103
|
"""Create a media query selector.
|
|
105
104
|
|
|
106
105
|
Args:
|
|
107
|
-
|
|
106
|
+
breakpoint_expr: The CSS expression representing the breakpoint.
|
|
108
107
|
|
|
109
108
|
Returns:
|
|
110
109
|
The media query selector used as a key in emotion css dict.
|
|
111
110
|
"""
|
|
112
|
-
return f"@media screen and (min-width: {
|
|
111
|
+
return f"@media screen and (min-width: {breakpoint_expr})"
|
|
113
112
|
|
|
114
113
|
|
|
115
114
|
def convert_item(style_item: str | Var) -> tuple[str, VarData | None]:
|
|
@@ -189,6 +188,10 @@ def convert(style_dict):
|
|
|
189
188
|
update_out_dict(return_val, keys)
|
|
190
189
|
# Combine all the collected VarData instances.
|
|
191
190
|
var_data = VarData.merge(var_data, new_var_data)
|
|
191
|
+
|
|
192
|
+
if isinstance(style_dict, Breakpoints):
|
|
193
|
+
out = Breakpoints(out).factorize()
|
|
194
|
+
|
|
192
195
|
return out, var_data
|
|
193
196
|
|
|
194
197
|
|
|
@@ -295,14 +298,22 @@ def format_as_emotion(style_dict: dict[str, Any]) -> Style | None:
|
|
|
295
298
|
|
|
296
299
|
for orig_key, value in style_dict.items():
|
|
297
300
|
key = _format_emotion_style_pseudo_selector(orig_key)
|
|
298
|
-
if isinstance(value, list):
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
301
|
+
if isinstance(value, (Breakpoints, list)):
|
|
302
|
+
if isinstance(value, Breakpoints):
|
|
303
|
+
mbps = {
|
|
304
|
+
media_query(bp): (
|
|
305
|
+
bp_value if isinstance(bp_value, dict) else {key: bp_value}
|
|
306
|
+
)
|
|
307
|
+
for bp, bp_value in value.items()
|
|
308
|
+
}
|
|
309
|
+
else:
|
|
310
|
+
# Apply media queries from responsive value list.
|
|
311
|
+
mbps = {
|
|
312
|
+
media_query([0, *breakpoints_values][bp]): (
|
|
313
|
+
bp_value if isinstance(bp_value, dict) else {key: bp_value}
|
|
314
|
+
)
|
|
315
|
+
for bp, bp_value in enumerate(value)
|
|
316
|
+
}
|
|
306
317
|
if key.startswith("&:"):
|
|
307
318
|
emotion_style[key] = mbps
|
|
308
319
|
else:
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Utilities for working with Github Codespaces."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from fastapi.responses import HTMLResponse
|
|
8
|
+
|
|
9
|
+
from reflex.components.base.script import Script
|
|
10
|
+
from reflex.components.component import Component
|
|
11
|
+
from reflex.components.core.banner import has_connection_errors
|
|
12
|
+
from reflex.components.core.cond import cond
|
|
13
|
+
from reflex.constants import Endpoint
|
|
14
|
+
|
|
15
|
+
redirect_script = """
|
|
16
|
+
const thisUrl = new URL(window.location.href);
|
|
17
|
+
const params = new URLSearchParams(thisUrl.search)
|
|
18
|
+
|
|
19
|
+
function doRedirect(url) {
|
|
20
|
+
if (!window.sessionStorage.getItem("authenticated_github_codespaces")) {
|
|
21
|
+
const a = document.createElement("a");
|
|
22
|
+
if (params.has("redirect_to")) {
|
|
23
|
+
a.href = params.get("redirect_to")
|
|
24
|
+
} else if (!window.location.href.startsWith(url)) {
|
|
25
|
+
a.href = url + `?redirect_to=${window.location.href}`
|
|
26
|
+
} else {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
a.hidden = true;
|
|
30
|
+
a.click();
|
|
31
|
+
a.remove();
|
|
32
|
+
window.sessionStorage.setItem("authenticated_github_codespaces", "true")
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
doRedirect("%s")
|
|
36
|
+
""" % Endpoint.AUTH_CODESPACE.get_url()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def codespaces_port_forwarding_domain() -> str | None:
|
|
40
|
+
"""Get the domain for port forwarding in Github Codespaces.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The domain for port forwarding in Github Codespaces, or None if not running in Codespaces.
|
|
44
|
+
"""
|
|
45
|
+
GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN = os.getenv(
|
|
46
|
+
"GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN"
|
|
47
|
+
)
|
|
48
|
+
return GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def is_running_in_codespaces() -> bool:
|
|
52
|
+
"""Check if the app is running in Github Codespaces.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
True if running in Github Codespaces, False otherwise.
|
|
56
|
+
"""
|
|
57
|
+
return codespaces_port_forwarding_domain() is not None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def codespaces_auto_redirect() -> list[Component]:
|
|
61
|
+
"""Get the components for automatically redirecting back to the app after authenticating a codespace port forward.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
A list containing the conditional redirect component, or empty list.
|
|
65
|
+
"""
|
|
66
|
+
if is_running_in_codespaces():
|
|
67
|
+
return [cond(has_connection_errors, Script.create(redirect_script))]
|
|
68
|
+
return []
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async def auth_codespace() -> HTMLResponse:
|
|
72
|
+
"""Page automatically redirecting back to the app after authenticating a codespace port forward.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
An HTML response with an embedded script to redirect back to the app.
|
|
76
|
+
"""
|
|
77
|
+
return HTMLResponse(
|
|
78
|
+
"""
|
|
79
|
+
<html>
|
|
80
|
+
<head>
|
|
81
|
+
<title>Reflex Github Codespace Forward Successfully Authenticated</title>
|
|
82
|
+
</head>
|
|
83
|
+
<body>
|
|
84
|
+
<center>
|
|
85
|
+
<h2>Successfully Authenticated</h2>
|
|
86
|
+
</center>
|
|
87
|
+
<script language="javascript">
|
|
88
|
+
%s
|
|
89
|
+
</script>
|
|
90
|
+
</body>
|
|
91
|
+
</html>
|
|
92
|
+
"""
|
|
93
|
+
% redirect_script
|
|
94
|
+
)
|
reflex/utils/compat.py
CHANGED
|
@@ -4,6 +4,27 @@ import contextlib
|
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
async def windows_hot_reload_lifespan_hack():
|
|
8
|
+
"""[REF-3164] A hack to fix hot reload on Windows.
|
|
9
|
+
|
|
10
|
+
Uvicorn has an issue stopping itself on Windows after detecting changes in
|
|
11
|
+
the filesystem.
|
|
12
|
+
|
|
13
|
+
This workaround repeatedly prints and flushes null characters to stderr,
|
|
14
|
+
which seems to allow the uvicorn server to exit when the CTRL-C signal is
|
|
15
|
+
sent from the reloader process.
|
|
16
|
+
|
|
17
|
+
Don't ask me why this works, I discovered it by accident - masenf.
|
|
18
|
+
"""
|
|
19
|
+
import asyncio
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
while True:
|
|
23
|
+
sys.stderr.write("\0")
|
|
24
|
+
sys.stderr.flush()
|
|
25
|
+
await asyncio.sleep(0.5)
|
|
26
|
+
|
|
27
|
+
|
|
7
28
|
@contextlib.contextmanager
|
|
8
29
|
def pydantic_v1_patch():
|
|
9
30
|
"""A context manager that patches the Pydantic module to mimic v1 behaviour.
|
reflex/utils/exceptions.py
CHANGED
|
@@ -61,6 +61,10 @@ class VarOperationTypeError(ReflexError, TypeError):
|
|
|
61
61
|
"""Custom TypeError for when unsupported operations are performed on vars."""
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
class VarDependencyError(ReflexError, ValueError):
|
|
65
|
+
"""Custom ValueError for when a var depends on a non-existent var."""
|
|
66
|
+
|
|
67
|
+
|
|
64
68
|
class InvalidStylePropError(ReflexError, TypeError):
|
|
65
69
|
"""Custom Type Error when style props have invalid values."""
|
|
66
70
|
|
reflex/utils/format.py
CHANGED
|
@@ -210,10 +210,31 @@ def _escape_js_string(string: str) -> str:
|
|
|
210
210
|
Returns:
|
|
211
211
|
The escaped string.
|
|
212
212
|
"""
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
|
|
214
|
+
# TODO: we may need to re-vist this logic after new Var API is implemented.
|
|
215
|
+
def escape_outside_segments(segment):
|
|
216
|
+
"""Escape backticks in segments outside of `${}`.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
segment: The part of the string to escape.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
The escaped or unescaped segment.
|
|
223
|
+
"""
|
|
224
|
+
if segment.startswith("${") and segment.endswith("}"):
|
|
225
|
+
# Return the `${}` segment unchanged
|
|
226
|
+
return segment
|
|
227
|
+
else:
|
|
228
|
+
# Escape backticks in the segment
|
|
229
|
+
segment = segment.replace(r"\`", "`")
|
|
230
|
+
segment = segment.replace("`", r"\`")
|
|
231
|
+
return segment
|
|
232
|
+
|
|
233
|
+
# Split the string into parts, keeping the `${}` segments
|
|
234
|
+
parts = re.split(r"(\$\{.*?\})", string)
|
|
235
|
+
escaped_parts = [escape_outside_segments(part) for part in parts]
|
|
236
|
+
escaped_string = "".join(escaped_parts)
|
|
237
|
+
return escaped_string
|
|
217
238
|
|
|
218
239
|
|
|
219
240
|
def _wrap_js_string(string: str) -> str:
|
reflex/utils/prerequisites.py
CHANGED
|
@@ -949,22 +949,9 @@ def needs_reinit(frontend: bool = True) -> bool:
|
|
|
949
949
|
return True
|
|
950
950
|
|
|
951
951
|
if constants.IS_WINDOWS:
|
|
952
|
-
import uvicorn
|
|
953
|
-
|
|
954
|
-
uvi_ver = uvicorn.__version__
|
|
955
952
|
console.warn(
|
|
956
953
|
"""Windows Subsystem for Linux (WSL) is recommended for improving initial install times."""
|
|
957
954
|
)
|
|
958
|
-
if sys.version_info >= (3, 12):
|
|
959
|
-
console.warn(
|
|
960
|
-
"Python 3.12 on Windows has known issues with hot reload (reflex-dev/reflex#3536). "
|
|
961
|
-
"Python 3.11 is recommended with this release of Reflex."
|
|
962
|
-
)
|
|
963
|
-
|
|
964
|
-
if sys.version_info < (3, 12) and uvi_ver != "0.20.0":
|
|
965
|
-
console.warn(
|
|
966
|
-
f"""On Python < 3.12, `uvicorn==0.20.0` is recommended for improved hot reload times. Found {uvi_ver} instead."""
|
|
967
|
-
)
|
|
968
955
|
|
|
969
956
|
if windows_check_onedrive_in_path():
|
|
970
957
|
console.warn(
|