reflex 0.6.6.post3__py3-none-any.whl → 0.6.7__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/stateful_component.js.jinja2 +5 -1
- reflex/.templates/web/utils/state.js +36 -28
- reflex/__init__.py +1 -1
- reflex/__init__.pyi +1 -0
- reflex/app.py +41 -16
- reflex/assets.py +2 -2
- reflex/base.py +8 -7
- reflex/compiler/templates.py +1 -0
- reflex/compiler/utils.py +2 -3
- reflex/components/base/bare.py +2 -2
- reflex/components/component.py +54 -29
- reflex/components/core/banner.py +2 -2
- reflex/components/core/banner.pyi +1 -1
- reflex/components/core/client_side_routing.py +2 -2
- reflex/components/core/client_side_routing.pyi +1 -1
- reflex/components/core/clipboard.py +11 -9
- reflex/components/core/clipboard.pyi +1 -1
- reflex/components/core/cond.py +3 -3
- reflex/components/core/foreach.py +1 -1
- reflex/components/core/html.pyi +1 -1
- reflex/components/core/upload.py +8 -8
- reflex/components/datadisplay/code.py +5 -5
- reflex/components/datadisplay/dataeditor.py +8 -28
- reflex/components/datadisplay/dataeditor.pyi +1 -1
- reflex/components/datadisplay/shiki_code_block.py +7 -7
- reflex/components/dynamic.py +2 -2
- reflex/components/el/elements/__init__.py +1 -1
- reflex/components/el/elements/__init__.pyi +1 -1
- reflex/components/el/elements/base.py +2 -2
- reflex/components/el/elements/base.pyi +1 -1
- reflex/components/el/elements/forms.py +40 -10
- reflex/components/el/elements/forms.pyi +17 -15
- reflex/components/el/elements/inline.py +1 -1
- reflex/components/el/elements/inline.pyi +28 -28
- reflex/components/el/elements/media.py +1 -4
- reflex/components/el/elements/media.pyi +25 -26
- reflex/components/el/elements/metadata.py +6 -6
- reflex/components/el/elements/metadata.pyi +4 -4
- reflex/components/el/elements/other.py +17 -9
- reflex/components/el/elements/other.pyi +7 -7
- reflex/components/el/elements/scripts.py +1 -2
- reflex/components/el/elements/scripts.pyi +3 -3
- reflex/components/el/elements/sectioning.py +16 -16
- reflex/components/el/elements/sectioning.pyi +15 -15
- reflex/components/el/elements/tables.py +1 -1
- reflex/components/el/elements/tables.pyi +10 -10
- reflex/components/el/elements/typography.py +1 -1
- reflex/components/el/elements/typography.pyi +15 -15
- reflex/components/markdown/markdown.py +3 -3
- reflex/components/next/image.py +1 -1
- reflex/components/next/image.pyi +1 -1
- reflex/components/plotly/plotly.py +2 -2
- reflex/components/radix/primitives/accordion.py +2 -1
- reflex/components/radix/primitives/form.pyi +3 -3
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/themes/base.py +4 -10
- reflex/components/radix/themes/color_mode.pyi +2 -2
- reflex/components/radix/themes/components/alert_dialog.pyi +1 -1
- reflex/components/radix/themes/components/badge.pyi +1 -1
- reflex/components/radix/themes/components/button.pyi +1 -1
- reflex/components/radix/themes/components/callout.pyi +5 -5
- reflex/components/radix/themes/components/card.pyi +1 -1
- reflex/components/radix/themes/components/checkbox.pyi +3 -3
- reflex/components/radix/themes/components/context_menu.py +11 -0
- reflex/components/radix/themes/components/context_menu.pyi +155 -0
- reflex/components/radix/themes/components/dialog.pyi +1 -1
- reflex/components/radix/themes/components/hover_card.pyi +1 -1
- reflex/components/radix/themes/components/icon_button.py +1 -1
- reflex/components/radix/themes/components/icon_button.pyi +1 -1
- reflex/components/radix/themes/components/inset.pyi +1 -1
- reflex/components/radix/themes/components/popover.pyi +1 -1
- reflex/components/radix/themes/components/radio_group.py +2 -4
- reflex/components/radix/themes/components/radio_group.pyi +1 -1
- reflex/components/radix/themes/components/select.pyi +3 -3
- reflex/components/radix/themes/components/slider.pyi +1 -1
- reflex/components/radix/themes/components/switch.pyi +1 -1
- reflex/components/radix/themes/components/table.pyi +7 -7
- reflex/components/radix/themes/components/tabs.pyi +2 -2
- reflex/components/radix/themes/components/text_area.py +3 -0
- reflex/components/radix/themes/components/text_area.pyi +3 -1
- reflex/components/radix/themes/components/text_field.py +16 -1
- reflex/components/radix/themes/components/text_field.pyi +105 -17
- reflex/components/radix/themes/layout/box.pyi +1 -1
- reflex/components/radix/themes/layout/center.pyi +1 -1
- reflex/components/radix/themes/layout/flex.pyi +1 -1
- reflex/components/radix/themes/layout/grid.pyi +1 -1
- reflex/components/radix/themes/layout/list.py +0 -4
- reflex/components/radix/themes/layout/list.pyi +3 -8
- reflex/components/radix/themes/layout/section.pyi +1 -1
- reflex/components/radix/themes/layout/spacer.pyi +1 -1
- reflex/components/radix/themes/layout/stack.pyi +3 -3
- reflex/components/radix/themes/typography/blockquote.pyi +1 -1
- reflex/components/radix/themes/typography/code.pyi +1 -1
- reflex/components/radix/themes/typography/heading.pyi +1 -1
- reflex/components/radix/themes/typography/link.py +5 -1
- reflex/components/radix/themes/typography/link.pyi +1 -1
- reflex/components/radix/themes/typography/text.pyi +7 -7
- reflex/components/recharts/cartesian.py +1 -1
- reflex/components/recharts/charts.py +4 -4
- reflex/components/recharts/polar.py +1 -1
- reflex/components/recharts/polar.pyi +1 -1
- reflex/components/sonner/toast.py +4 -7
- reflex/components/suneditor/editor.py +6 -6
- reflex/components/suneditor/editor.pyi +6 -6
- reflex/config.py +25 -10
- reflex/constants/compiler.py +6 -0
- reflex/constants/config.py +2 -0
- reflex/constants/custom_components.py +1 -1
- reflex/constants/route.py +1 -1
- reflex/custom_components/custom_components.py +21 -21
- reflex/event.py +57 -22
- reflex/experimental/client_state.py +2 -1
- reflex/experimental/layout.py +0 -6
- reflex/model.py +125 -9
- reflex/reflex.py +5 -6
- reflex/state.py +200 -88
- reflex/style.py +1 -4
- reflex/testing.py +10 -11
- reflex/utils/build.py +1 -1
- reflex/utils/console.py +75 -6
- reflex/utils/exceptions.py +12 -0
- reflex/utils/exec.py +10 -10
- reflex/utils/export.py +1 -2
- reflex/utils/format.py +11 -8
- reflex/utils/path_ops.py +2 -2
- reflex/utils/prerequisites.py +31 -28
- reflex/utils/processes.py +4 -4
- reflex/utils/pyi_generator.py +12 -11
- reflex/utils/types.py +6 -3
- reflex/vars/__init__.py +1 -0
- reflex/vars/base.py +75 -38
- reflex/vars/datetime.py +222 -0
- reflex/vars/function.py +3 -3
- reflex/vars/number.py +3 -3
- reflex/vars/object.py +5 -5
- reflex/vars/sequence.py +7 -7
- {reflex-0.6.6.post3.dist-info → reflex-0.6.7.dist-info}/METADATA +2 -2
- {reflex-0.6.6.post3.dist-info → reflex-0.6.7.dist-info}/RECORD +141 -140
- {reflex-0.6.6.post3.dist-info → reflex-0.6.7.dist-info}/LICENSE +0 -0
- {reflex-0.6.6.post3.dist-info → reflex-0.6.7.dist-info}/WHEEL +0 -0
- {reflex-0.6.6.post3.dist-info → reflex-0.6.7.dist-info}/entry_points.txt +0 -0
|
@@ -264,7 +264,7 @@ class Text(elements.Span, RadixThemesComponent, MarkdownComponentMap):
|
|
|
264
264
|
trim: Removes the leading trim space: "normal" | "start" | "end" | "both"
|
|
265
265
|
color_scheme: Overrides the accent color inherited from the Theme.
|
|
266
266
|
high_contrast: Whether to render the text with higher contrast color
|
|
267
|
-
access_key:
|
|
267
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
268
268
|
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
269
269
|
content_editable: Indicates whether the element's content is editable.
|
|
270
270
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
@@ -521,7 +521,7 @@ class Span(Text):
|
|
|
521
521
|
trim: Removes the leading trim space: "normal" | "start" | "end" | "both"
|
|
522
522
|
color_scheme: Overrides the accent color inherited from the Theme.
|
|
523
523
|
high_contrast: Whether to render the text with higher contrast color
|
|
524
|
-
access_key:
|
|
524
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
525
525
|
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
526
526
|
content_editable: Indicates whether the element's content is editable.
|
|
527
527
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
@@ -610,7 +610,7 @@ class Em(elements.Em, RadixThemesComponent):
|
|
|
610
610
|
|
|
611
611
|
Args:
|
|
612
612
|
*children: Child components.
|
|
613
|
-
access_key:
|
|
613
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
614
614
|
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
615
615
|
content_editable: Indicates whether the element's content is editable.
|
|
616
616
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
@@ -706,7 +706,7 @@ class Kbd(elements.Kbd, RadixThemesComponent):
|
|
|
706
706
|
Args:
|
|
707
707
|
*children: Child components.
|
|
708
708
|
size: Text size: "1" - "9"
|
|
709
|
-
access_key:
|
|
709
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
710
710
|
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
711
711
|
content_editable: Indicates whether the element's content is editable.
|
|
712
712
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
@@ -797,7 +797,7 @@ class Quote(elements.Q, RadixThemesComponent):
|
|
|
797
797
|
Args:
|
|
798
798
|
*children: Child components.
|
|
799
799
|
cite: Specifies the source URL of the quote.
|
|
800
|
-
access_key:
|
|
800
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
801
801
|
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
802
802
|
content_editable: Indicates whether the element's content is editable.
|
|
803
803
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
@@ -886,7 +886,7 @@ class Strong(elements.Strong, RadixThemesComponent):
|
|
|
886
886
|
|
|
887
887
|
Args:
|
|
888
888
|
*children: Child components.
|
|
889
|
-
access_key:
|
|
889
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
890
890
|
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
891
891
|
content_editable: Indicates whether the element's content is editable.
|
|
892
892
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
@@ -1147,7 +1147,7 @@ class TextNamespace(ComponentNamespace):
|
|
|
1147
1147
|
trim: Removes the leading trim space: "normal" | "start" | "end" | "both"
|
|
1148
1148
|
color_scheme: Overrides the accent color inherited from the Theme.
|
|
1149
1149
|
high_contrast: Whether to render the text with higher contrast color
|
|
1150
|
-
access_key:
|
|
1150
|
+
access_key: Provides a hint for generating a keyboard shortcut for the current element.
|
|
1151
1151
|
auto_capitalize: Controls whether and how text input is automatically capitalized as it is entered/edited by the user.
|
|
1152
1152
|
content_editable: Indicates whether the element's content is editable.
|
|
1153
1153
|
context_menu: Defines the ID of a <menu> element which will serve as the element's context menu.
|
|
@@ -416,7 +416,7 @@ class Bar(Cartesian):
|
|
|
416
416
|
radius: Var[Union[int, List[int]]]
|
|
417
417
|
|
|
418
418
|
# The active bar is shown when a user enters a bar chart and this chart has tooltip. If set to false, no active bar will be drawn. If set to true, active bar will be drawn with the props calculated internally. If passed an object, active bar will be drawn, and the internally calculated props will be merged with the key value pairs of the passed object.
|
|
419
|
-
# active_bar: Var[Union[bool, Dict[str, Any]]]
|
|
419
|
+
# active_bar: Var[Union[bool, Dict[str, Any]]] #noqa: ERA001
|
|
420
420
|
|
|
421
421
|
# Valid children components
|
|
422
422
|
_valid_children: List[str] = ["Cell", "LabelList", "ErrorBar"]
|
|
@@ -84,10 +84,10 @@ class ChartBase(RechartsCharts):
|
|
|
84
84
|
cls._ensure_valid_dimension("width", width)
|
|
85
85
|
cls._ensure_valid_dimension("height", height)
|
|
86
86
|
|
|
87
|
-
dim_props =
|
|
88
|
-
width
|
|
89
|
-
height
|
|
90
|
-
|
|
87
|
+
dim_props = {
|
|
88
|
+
"width": width or "100%",
|
|
89
|
+
"height": height or "100%",
|
|
90
|
+
}
|
|
91
91
|
# Provide min dimensions so the graph always appears, even if the outer container is zero-size.
|
|
92
92
|
if width is None:
|
|
93
93
|
dim_props["min_width"] = 200
|
|
@@ -136,7 +136,7 @@ class Radar(Recharts):
|
|
|
136
136
|
# Fill color. Default: rx.color("accent", 3)
|
|
137
137
|
fill: Var[str] = LiteralVar.create(Color("accent", 3))
|
|
138
138
|
|
|
139
|
-
# opacity. Default: 0.6
|
|
139
|
+
# The opacity to fill the chart. Default: 0.6
|
|
140
140
|
fill_opacity: Var[float] = LiteralVar.create(0.6)
|
|
141
141
|
|
|
142
142
|
# The type of icon in legend. If set to 'none', no legend item will be rendered. Default: "rect"
|
|
@@ -204,7 +204,7 @@ class Radar(Recharts):
|
|
|
204
204
|
dot: If false set, dots will not be drawn. Default: True
|
|
205
205
|
stroke: Stoke color. Default: rx.color("accent", 9)
|
|
206
206
|
fill: Fill color. Default: rx.color("accent", 3)
|
|
207
|
-
fill_opacity: opacity. Default: 0.6
|
|
207
|
+
fill_opacity: The opacity to fill the chart. Default: 0.6
|
|
208
208
|
legend_type: The type of icon in legend. If set to 'none', no legend item will be rendered. Default: "rect"
|
|
209
209
|
label: If false set, labels will not be drawn. Default: True
|
|
210
210
|
is_animation_active: If set false, animation of polygon will be disabled. Default: True in CSR, and False in SSR
|
|
@@ -64,7 +64,7 @@ def _toast_callback_signature(toast: Var) -> list[Var]:
|
|
|
64
64
|
"""
|
|
65
65
|
return [
|
|
66
66
|
Var(
|
|
67
|
-
_js_expr=f"(() => {{let {{action, cancel, onDismiss, onAutoClose, ...rest}} = {
|
|
67
|
+
_js_expr=f"(() => {{let {{action, cancel, onDismiss, onAutoClose, ...rest}} = {toast!s}; return rest}})()"
|
|
68
68
|
)
|
|
69
69
|
]
|
|
70
70
|
|
|
@@ -98,7 +98,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
|
|
|
98
98
|
|
|
99
99
|
# TODO: fix serialization of icons for toast? (might not be possible yet)
|
|
100
100
|
# Icon displayed in front of toast's text, aligned vertically.
|
|
101
|
-
# icon: Optional[Icon] = None
|
|
101
|
+
# icon: Optional[Icon] = None # noqa: ERA001
|
|
102
102
|
|
|
103
103
|
# TODO: fix implementation for action / cancel buttons
|
|
104
104
|
# Renders a primary button, clicking it will close the toast.
|
|
@@ -338,7 +338,7 @@ class Toaster(Component):
|
|
|
338
338
|
dismiss_var_data = None
|
|
339
339
|
|
|
340
340
|
if isinstance(id, Var):
|
|
341
|
-
dismiss = f"{toast_ref}.dismiss({
|
|
341
|
+
dismiss = f"{toast_ref}.dismiss({id!s})"
|
|
342
342
|
dismiss_var_data = id._get_all_var_data()
|
|
343
343
|
elif isinstance(id, str):
|
|
344
344
|
dismiss = f"{toast_ref}.dismiss('{id}')"
|
|
@@ -364,9 +364,7 @@ class Toaster(Component):
|
|
|
364
364
|
return super().create(*children, **props)
|
|
365
365
|
|
|
366
366
|
|
|
367
|
-
# TODO: figure out why loading toast stay open forever
|
|
368
|
-
# def toast_loading(message: str, **kwargs):
|
|
369
|
-
# return _toast(message, level="loading", **kwargs)
|
|
367
|
+
# TODO: figure out why loading toast stay open forever when using level="loading" in toast()
|
|
370
368
|
|
|
371
369
|
|
|
372
370
|
class ToastNamespace(ComponentNamespace):
|
|
@@ -379,7 +377,6 @@ class ToastNamespace(ComponentNamespace):
|
|
|
379
377
|
error = staticmethod(Toaster.toast_error)
|
|
380
378
|
success = staticmethod(Toaster.toast_success)
|
|
381
379
|
dismiss = staticmethod(Toaster.toast_dismiss)
|
|
382
|
-
# loading = staticmethod(toast_loading)
|
|
383
380
|
__call__ = staticmethod(Toaster.send_toast)
|
|
384
381
|
|
|
385
382
|
|
|
@@ -116,7 +116,7 @@ class Editor(NoSSRComponent):
|
|
|
116
116
|
# Please refer to the library docs for this.
|
|
117
117
|
# options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" |
|
|
118
118
|
# "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it"
|
|
119
|
-
# default
|
|
119
|
+
# default: "en".
|
|
120
120
|
lang: Var[
|
|
121
121
|
Union[
|
|
122
122
|
Literal[
|
|
@@ -172,7 +172,7 @@ class Editor(NoSSRComponent):
|
|
|
172
172
|
set_options: Var[Dict]
|
|
173
173
|
|
|
174
174
|
# Whether all SunEditor plugins should be loaded.
|
|
175
|
-
# default: True
|
|
175
|
+
# default: True.
|
|
176
176
|
set_all_plugins: Var[bool]
|
|
177
177
|
|
|
178
178
|
# Set the content of the editor.
|
|
@@ -191,19 +191,19 @@ class Editor(NoSSRComponent):
|
|
|
191
191
|
set_default_style: Var[str]
|
|
192
192
|
|
|
193
193
|
# Disable the editor
|
|
194
|
-
# default: False
|
|
194
|
+
# default: False.
|
|
195
195
|
disable: Var[bool]
|
|
196
196
|
|
|
197
197
|
# Hide the editor
|
|
198
|
-
# default: False
|
|
198
|
+
# default: False.
|
|
199
199
|
hide: Var[bool]
|
|
200
200
|
|
|
201
201
|
# Hide the editor toolbar
|
|
202
|
-
# default: False
|
|
202
|
+
# default: False.
|
|
203
203
|
hide_toolbar: Var[bool]
|
|
204
204
|
|
|
205
205
|
# Disable the editor toolbar
|
|
206
|
-
# default: False
|
|
206
|
+
# default: False.
|
|
207
207
|
disable_toolbar: Var[bool]
|
|
208
208
|
|
|
209
209
|
# Fired when the editor content changes.
|
|
@@ -172,7 +172,7 @@ class Editor(NoSSRComponent):
|
|
|
172
172
|
|
|
173
173
|
Args:
|
|
174
174
|
set_options(Optional[EditorOptions]): Configuration object to further configure the instance.
|
|
175
|
-
lang: Language of the editor. Alternatively to a string, a dict of your language can be passed to this prop. Please refer to the library docs for this. options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" default
|
|
175
|
+
lang: Language of the editor. Alternatively to a string, a dict of your language can be passed to this prop. Please refer to the library docs for this. options: "en" | "da" | "de" | "es" | "fr" | "ja" | "ko" | "pt_br" | "ru" | "zh_cn" | "ro" | "pl" | "ckb" | "lv" | "se" | "ua" | "he" | "it" default: "en".
|
|
176
176
|
name: This is used to set the HTML form name of the editor. This means on HTML form submission, it will be submitted together with contents of the editor by the name provided.
|
|
177
177
|
default_value: Sets the default value of the editor. This is useful if you don't want the on_change method to be called on render. If you want the on_change method to be called on render please use the set_contents prop
|
|
178
178
|
width: Sets the width of the editor. px and percentage values are accepted, eg width="100%" or width="500px" default: 100%
|
|
@@ -180,14 +180,14 @@ class Editor(NoSSRComponent):
|
|
|
180
180
|
placeholder: Sets the placeholder of the editor.
|
|
181
181
|
auto_focus: Should the editor receive focus when initialized?
|
|
182
182
|
set_options: Pass an EditorOptions instance to modify the behaviour of Editor even more.
|
|
183
|
-
set_all_plugins: Whether all SunEditor plugins should be loaded. default: True
|
|
183
|
+
set_all_plugins: Whether all SunEditor plugins should be loaded. default: True.
|
|
184
184
|
set_contents: Set the content of the editor. Note: To set the initial contents of the editor without calling the on_change event, please use the default_value prop. set_contents is used to set the contents of the editor programmatically. You must be aware that, when the set_contents's prop changes, the on_change event is triggered.
|
|
185
185
|
append_contents: Append editor content
|
|
186
186
|
set_default_style: Sets the default style of the editor's edit area
|
|
187
|
-
disable: Disable the editor default: False
|
|
188
|
-
hide: Hide the editor default: False
|
|
189
|
-
hide_toolbar: Hide the editor toolbar default: False
|
|
190
|
-
disable_toolbar: Disable the editor toolbar default: False
|
|
187
|
+
disable: Disable the editor default: False.
|
|
188
|
+
hide: Hide the editor default: False.
|
|
189
|
+
hide_toolbar: Hide the editor toolbar default: False.
|
|
190
|
+
disable_toolbar: Disable the editor toolbar default: False.
|
|
191
191
|
on_change: Fired when the editor content changes.
|
|
192
192
|
on_input: Fired when the something is inputted in the editor.
|
|
193
193
|
on_blur: Fired when the editor loses focus.
|
reflex/config.py
CHANGED
|
@@ -82,7 +82,7 @@ class DBConfig(Base):
|
|
|
82
82
|
)
|
|
83
83
|
|
|
84
84
|
@classmethod
|
|
85
|
-
def
|
|
85
|
+
def postgresql_psycopg(
|
|
86
86
|
cls,
|
|
87
87
|
database: str,
|
|
88
88
|
username: str,
|
|
@@ -90,7 +90,7 @@ class DBConfig(Base):
|
|
|
90
90
|
host: str | None = None,
|
|
91
91
|
port: int | None = 5432,
|
|
92
92
|
) -> DBConfig:
|
|
93
|
-
"""Create an instance with postgresql+
|
|
93
|
+
"""Create an instance with postgresql+psycopg engine.
|
|
94
94
|
|
|
95
95
|
Args:
|
|
96
96
|
database: Database name.
|
|
@@ -103,7 +103,7 @@ class DBConfig(Base):
|
|
|
103
103
|
DBConfig instance.
|
|
104
104
|
"""
|
|
105
105
|
return cls(
|
|
106
|
-
engine="postgresql+
|
|
106
|
+
engine="postgresql+psycopg",
|
|
107
107
|
username=username,
|
|
108
108
|
password=password,
|
|
109
109
|
host=host,
|
|
@@ -512,6 +512,9 @@ class EnvironmentVariables:
|
|
|
512
512
|
# Whether to print the SQL queries if the log level is INFO or lower.
|
|
513
513
|
SQLALCHEMY_ECHO: EnvVar[bool] = env_var(False)
|
|
514
514
|
|
|
515
|
+
# Whether to check db connections before using them.
|
|
516
|
+
SQLALCHEMY_POOL_PRE_PING: EnvVar[bool] = env_var(True)
|
|
517
|
+
|
|
515
518
|
# Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration.
|
|
516
519
|
REFLEX_IGNORE_REDIS_CONFIG_ERROR: EnvVar[bool] = env_var(False)
|
|
517
520
|
|
|
@@ -568,6 +571,10 @@ class EnvironmentVariables:
|
|
|
568
571
|
environment = EnvironmentVariables()
|
|
569
572
|
|
|
570
573
|
|
|
574
|
+
# These vars are not logged because they may contain sensitive information.
|
|
575
|
+
_sensitive_env_vars = {"DB_URL", "ASYNC_DB_URL", "REDIS_URL"}
|
|
576
|
+
|
|
577
|
+
|
|
571
578
|
class Config(Base):
|
|
572
579
|
"""The config defines runtime settings for the app.
|
|
573
580
|
|
|
@@ -621,6 +628,9 @@ class Config(Base):
|
|
|
621
628
|
# The database url used by rx.Model.
|
|
622
629
|
db_url: Optional[str] = "sqlite:///reflex.db"
|
|
623
630
|
|
|
631
|
+
# The async database url used by rx.Model.
|
|
632
|
+
async_db_url: Optional[str] = None
|
|
633
|
+
|
|
624
634
|
# The redis url
|
|
625
635
|
redis_url: Optional[str] = None
|
|
626
636
|
|
|
@@ -674,6 +684,9 @@ class Config(Base):
|
|
|
674
684
|
# Maximum expiration lock time for redis state manager
|
|
675
685
|
redis_lock_expiration: int = constants.Expiration.LOCK
|
|
676
686
|
|
|
687
|
+
# Maximum lock time before warning for redis state manager.
|
|
688
|
+
redis_lock_warning_threshold: int = constants.Expiration.LOCK_WARNING_THRESHOLD
|
|
689
|
+
|
|
677
690
|
# Token expiration time for redis state manager
|
|
678
691
|
redis_token_expiration: int = constants.Expiration.TOKEN
|
|
679
692
|
|
|
@@ -748,18 +761,20 @@ class Config(Base):
|
|
|
748
761
|
|
|
749
762
|
# If the env var is set, override the config value.
|
|
750
763
|
if env_var is not None:
|
|
751
|
-
if key.upper() != "DB_URL":
|
|
752
|
-
console.info(
|
|
753
|
-
f"Overriding config value {key} with env var {key.upper()}={env_var}",
|
|
754
|
-
dedupe=True,
|
|
755
|
-
)
|
|
756
|
-
|
|
757
764
|
# Interpret the value.
|
|
758
765
|
value = interpret_env_var_value(env_var, field.outer_type_, field.name)
|
|
759
766
|
|
|
760
767
|
# Set the value.
|
|
761
768
|
updated_values[key] = value
|
|
762
769
|
|
|
770
|
+
if key.upper() in _sensitive_env_vars:
|
|
771
|
+
env_var = "***"
|
|
772
|
+
|
|
773
|
+
console.info(
|
|
774
|
+
f"Overriding config value {key} with env var {key.upper()}={env_var}",
|
|
775
|
+
dedupe=True,
|
|
776
|
+
)
|
|
777
|
+
|
|
763
778
|
return updated_values
|
|
764
779
|
|
|
765
780
|
def get_event_namespace(self) -> str:
|
|
@@ -858,7 +873,7 @@ def get_config(reload: bool = False) -> Config:
|
|
|
858
873
|
with _config_lock:
|
|
859
874
|
sys_path = sys.path.copy()
|
|
860
875
|
sys.path.clear()
|
|
861
|
-
sys.path.append(
|
|
876
|
+
sys.path.append(str(Path.cwd()))
|
|
862
877
|
try:
|
|
863
878
|
# Try to import the module with only the current directory in the path.
|
|
864
879
|
return _get_config()
|
reflex/constants/compiler.py
CHANGED
|
@@ -132,6 +132,12 @@ class Hooks(SimpleNamespace):
|
|
|
132
132
|
}
|
|
133
133
|
})"""
|
|
134
134
|
|
|
135
|
+
class HookPosition(enum.Enum):
|
|
136
|
+
"""The position of the hook in the component."""
|
|
137
|
+
|
|
138
|
+
PRE_TRIGGER = "pre_trigger"
|
|
139
|
+
POST_TRIGGER = "post_trigger"
|
|
140
|
+
|
|
135
141
|
|
|
136
142
|
class MemoizationDisposition(enum.Enum):
|
|
137
143
|
"""The conditions under which a component should be memoized."""
|
reflex/constants/config.py
CHANGED
|
@@ -10,7 +10,7 @@ class CustomComponents(SimpleNamespace):
|
|
|
10
10
|
"""Constants for the custom components."""
|
|
11
11
|
|
|
12
12
|
# The name of the custom components source directory.
|
|
13
|
-
SRC_DIR = "custom_components"
|
|
13
|
+
SRC_DIR = Path("custom_components")
|
|
14
14
|
# The name of the custom components pyproject.toml file.
|
|
15
15
|
PYPROJECT_TOML = Path("pyproject.toml")
|
|
16
16
|
# The name of the custom components package README file.
|
reflex/constants/route.py
CHANGED
|
@@ -31,7 +31,7 @@ class RouteVar(SimpleNamespace):
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
# This subset of router_data is included in chained on_load events.
|
|
34
|
-
ROUTER_DATA_INCLUDE =
|
|
34
|
+
ROUTER_DATA_INCLUDE = {RouteVar.PATH, RouteVar.ORIGIN, RouteVar.QUERY}
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class RouteRegex(SimpleNamespace):
|
|
@@ -150,27 +150,27 @@ def _populate_demo_app(name_variants: NameVariants):
|
|
|
150
150
|
from reflex.compiler import templates
|
|
151
151
|
from reflex.reflex import _init
|
|
152
152
|
|
|
153
|
-
demo_app_dir = name_variants.demo_app_dir
|
|
153
|
+
demo_app_dir = Path(name_variants.demo_app_dir)
|
|
154
154
|
demo_app_name = name_variants.demo_app_name
|
|
155
155
|
|
|
156
|
-
console.info(f"Creating app for testing: {demo_app_dir}")
|
|
156
|
+
console.info(f"Creating app for testing: {demo_app_dir!s}")
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
demo_app_dir.mkdir(exist_ok=True)
|
|
159
159
|
|
|
160
160
|
with set_directory(demo_app_dir):
|
|
161
161
|
# We start with the blank template as basis.
|
|
162
162
|
_init(name=demo_app_name, template=constants.Templates.DEFAULT)
|
|
163
163
|
# Then overwrite the app source file with the one we want for testing custom components.
|
|
164
164
|
# This source file is rendered using jinja template file.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
165
|
+
demo_file = Path(f"{demo_app_name}/{demo_app_name}.py")
|
|
166
|
+
demo_file.write_text(
|
|
167
|
+
templates.CUSTOM_COMPONENTS_DEMO_APP.render(
|
|
168
|
+
custom_component_module_dir=name_variants.custom_component_module_dir,
|
|
169
|
+
module_name=name_variants.module_name,
|
|
171
170
|
)
|
|
171
|
+
)
|
|
172
172
|
# Append the custom component package to the requirements.txt file.
|
|
173
|
-
with
|
|
173
|
+
with Path(f"{constants.RequirementsTxt.FILE}").open(mode="a") as f:
|
|
174
174
|
f.write(f"{name_variants.package_name}\n")
|
|
175
175
|
|
|
176
176
|
|
|
@@ -296,13 +296,14 @@ def _populate_custom_component_project(name_variants: NameVariants):
|
|
|
296
296
|
)
|
|
297
297
|
|
|
298
298
|
console.info(
|
|
299
|
-
f"Initializing the component directory: {CustomComponents.SRC_DIR
|
|
299
|
+
f"Initializing the component directory: {CustomComponents.SRC_DIR / name_variants.custom_component_module_dir}"
|
|
300
300
|
)
|
|
301
|
-
|
|
301
|
+
CustomComponents.SRC_DIR.mkdir(exist_ok=True)
|
|
302
302
|
with set_directory(CustomComponents.SRC_DIR):
|
|
303
|
-
|
|
303
|
+
module_dir = Path(name_variants.custom_component_module_dir)
|
|
304
|
+
module_dir.mkdir(exist_ok=True, parents=True)
|
|
304
305
|
_write_source_and_init_py(
|
|
305
|
-
custom_component_src_dir=
|
|
306
|
+
custom_component_src_dir=module_dir,
|
|
306
307
|
component_class_name=name_variants.component_class_name,
|
|
307
308
|
module_name=name_variants.module_name,
|
|
308
309
|
)
|
|
@@ -814,7 +815,7 @@ def _validate_project_info():
|
|
|
814
815
|
)
|
|
815
816
|
pyproject_toml["project"] = project
|
|
816
817
|
try:
|
|
817
|
-
with
|
|
818
|
+
with CustomComponents.PYPROJECT_TOML.open("w") as f:
|
|
818
819
|
tomlkit.dump(pyproject_toml, f)
|
|
819
820
|
except (OSError, TOMLKitError) as ex:
|
|
820
821
|
console.error(f"Unable to write to pyproject.toml due to {ex}")
|
|
@@ -922,16 +923,15 @@ def _validate_url_with_protocol_prefix(url: str | None) -> bool:
|
|
|
922
923
|
def _get_file_from_prompt_in_loop() -> Tuple[bytes, str] | None:
|
|
923
924
|
image_file = file_extension = None
|
|
924
925
|
while image_file is None:
|
|
925
|
-
image_filepath =
|
|
926
|
-
"Upload a preview image of your demo app (enter to skip)"
|
|
926
|
+
image_filepath = Path(
|
|
927
|
+
console.ask("Upload a preview image of your demo app (enter to skip)")
|
|
927
928
|
)
|
|
928
929
|
if not image_filepath:
|
|
929
930
|
break
|
|
930
|
-
file_extension = image_filepath.
|
|
931
|
+
file_extension = image_filepath.suffix
|
|
931
932
|
try:
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
return image_file, file_extension
|
|
933
|
+
image_file = image_filepath.read_bytes()
|
|
934
|
+
return image_file, file_extension
|
|
935
935
|
except OSError as ose:
|
|
936
936
|
console.error(f"Unable to read the {file_extension} file due to {ose}")
|
|
937
937
|
raise typer.Exit(code=1) from ose
|
reflex/event.py
CHANGED
|
@@ -25,6 +25,7 @@ from typing import (
|
|
|
25
25
|
overload,
|
|
26
26
|
)
|
|
27
27
|
|
|
28
|
+
import typing_extensions
|
|
28
29
|
from typing_extensions import (
|
|
29
30
|
Concatenate,
|
|
30
31
|
ParamSpec,
|
|
@@ -296,7 +297,7 @@ class EventSpec(EventActionsMixin):
|
|
|
296
297
|
handler: EventHandler,
|
|
297
298
|
event_actions: Dict[str, Union[bool, int]] | None = None,
|
|
298
299
|
client_handler_name: str = "",
|
|
299
|
-
args: Tuple[Tuple[Var, Var], ...] =
|
|
300
|
+
args: Tuple[Tuple[Var, Var], ...] = (),
|
|
300
301
|
):
|
|
301
302
|
"""Initialize an EventSpec.
|
|
302
303
|
|
|
@@ -311,7 +312,7 @@ class EventSpec(EventActionsMixin):
|
|
|
311
312
|
object.__setattr__(self, "event_actions", event_actions)
|
|
312
313
|
object.__setattr__(self, "handler", handler)
|
|
313
314
|
object.__setattr__(self, "client_handler_name", client_handler_name)
|
|
314
|
-
object.__setattr__(self, "args", args or
|
|
315
|
+
object.__setattr__(self, "args", args or ())
|
|
315
316
|
|
|
316
317
|
def with_args(self, args: Tuple[Tuple[Var, Var], ...]) -> EventSpec:
|
|
317
318
|
"""Copy the event spec, with updated args.
|
|
@@ -349,13 +350,14 @@ class EventSpec(EventActionsMixin):
|
|
|
349
350
|
|
|
350
351
|
# Construct the payload.
|
|
351
352
|
values = []
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
353
|
+
arg = None
|
|
354
|
+
try:
|
|
355
|
+
for arg in args:
|
|
356
|
+
values.append(LiteralVar.create(value=arg)) # noqa: PERF401
|
|
357
|
+
except TypeError as e:
|
|
358
|
+
raise EventHandlerTypeError(
|
|
359
|
+
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
|
360
|
+
) from e
|
|
359
361
|
new_payload = tuple(zip(fn_args, values))
|
|
360
362
|
return self.with_args(self.args + new_payload)
|
|
361
363
|
|
|
@@ -447,7 +449,7 @@ class JavascriptHTMLInputElement:
|
|
|
447
449
|
class JavascriptInputEvent:
|
|
448
450
|
"""Interface for a Javascript InputEvent https://developer.mozilla.org/en-US/docs/Web/API/InputEvent."""
|
|
449
451
|
|
|
450
|
-
target: JavascriptHTMLInputElement = JavascriptHTMLInputElement()
|
|
452
|
+
target: JavascriptHTMLInputElement = JavascriptHTMLInputElement() # noqa: RUF009
|
|
451
453
|
|
|
452
454
|
|
|
453
455
|
@dataclasses.dataclass(
|
|
@@ -513,7 +515,7 @@ def no_args_event_spec() -> Tuple[()]:
|
|
|
513
515
|
Returns:
|
|
514
516
|
An empty tuple.
|
|
515
517
|
"""
|
|
516
|
-
return
|
|
518
|
+
return () # type: ignore
|
|
517
519
|
|
|
518
520
|
|
|
519
521
|
# These chains can be used for their side effects when no other events are desired.
|
|
@@ -714,26 +716,61 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
|
|
|
714
716
|
)
|
|
715
717
|
|
|
716
718
|
|
|
719
|
+
@overload
|
|
720
|
+
def redirect(
|
|
721
|
+
path: str | Var[str],
|
|
722
|
+
is_external: Optional[bool] = None,
|
|
723
|
+
replace: bool = False,
|
|
724
|
+
) -> EventSpec: ...
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
@overload
|
|
728
|
+
@typing_extensions.deprecated("`external` is deprecated use `is_external` instead")
|
|
729
|
+
def redirect(
|
|
730
|
+
path: str | Var[str],
|
|
731
|
+
is_external: Optional[bool] = None,
|
|
732
|
+
replace: bool = False,
|
|
733
|
+
external: Optional[bool] = None,
|
|
734
|
+
) -> EventSpec: ...
|
|
735
|
+
|
|
736
|
+
|
|
717
737
|
def redirect(
|
|
718
738
|
path: str | Var[str],
|
|
719
|
-
|
|
720
|
-
replace:
|
|
739
|
+
is_external: Optional[bool] = None,
|
|
740
|
+
replace: bool = False,
|
|
741
|
+
external: Optional[bool] = None,
|
|
721
742
|
) -> EventSpec:
|
|
722
743
|
"""Redirect to a new path.
|
|
723
744
|
|
|
724
745
|
Args:
|
|
725
746
|
path: The path to redirect to.
|
|
726
|
-
|
|
747
|
+
is_external: Whether to open in new tab or not.
|
|
727
748
|
replace: If True, the current page will not create a new history entry.
|
|
749
|
+
external(Deprecated): Whether to open in new tab or not.
|
|
728
750
|
|
|
729
751
|
Returns:
|
|
730
752
|
An event to redirect to the path.
|
|
731
753
|
"""
|
|
754
|
+
if external is not None:
|
|
755
|
+
console.deprecate(
|
|
756
|
+
"The `external` prop in `rx.redirect`",
|
|
757
|
+
"use `is_external` instead.",
|
|
758
|
+
"0.6.6",
|
|
759
|
+
"0.7.0",
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
# is_external should take precedence over external.
|
|
763
|
+
is_external = (
|
|
764
|
+
(False if external is None else external)
|
|
765
|
+
if is_external is None
|
|
766
|
+
else is_external
|
|
767
|
+
)
|
|
768
|
+
|
|
732
769
|
return server_side(
|
|
733
770
|
"_redirect",
|
|
734
771
|
get_fn_signature(redirect),
|
|
735
772
|
path=path,
|
|
736
|
-
external=
|
|
773
|
+
external=is_external,
|
|
737
774
|
replace=replace,
|
|
738
775
|
)
|
|
739
776
|
|
|
@@ -1101,9 +1138,7 @@ def run_script(
|
|
|
1101
1138
|
Var(javascript_code) if isinstance(javascript_code, str) else javascript_code
|
|
1102
1139
|
)
|
|
1103
1140
|
|
|
1104
|
-
return call_function(
|
|
1105
|
-
ArgsFunctionOperation.create(tuple(), javascript_code), callback
|
|
1106
|
-
)
|
|
1141
|
+
return call_function(ArgsFunctionOperation.create((), javascript_code), callback)
|
|
1107
1142
|
|
|
1108
1143
|
|
|
1109
1144
|
def get_event(state, event):
|
|
@@ -1222,7 +1257,7 @@ def call_event_handler(
|
|
|
1222
1257
|
except TypeError:
|
|
1223
1258
|
# TODO: In 0.7.0, remove this block and raise the exception
|
|
1224
1259
|
# raise TypeError(
|
|
1225
|
-
# f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_handler.fn.__qualname__} provided for {key}."
|
|
1260
|
+
# f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_handler.fn.__qualname__} provided for {key}." # noqa: ERA001
|
|
1226
1261
|
# ) from e
|
|
1227
1262
|
console.warn(
|
|
1228
1263
|
f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_callback.fn.__qualname__} provided for {key}."
|
|
@@ -1455,7 +1490,7 @@ def get_handler_args(
|
|
|
1455
1490
|
"""
|
|
1456
1491
|
args = inspect.getfullargspec(event_spec.handler.fn).args
|
|
1457
1492
|
|
|
1458
|
-
return event_spec.args if len(args) > 1 else
|
|
1493
|
+
return event_spec.args if len(args) > 1 else ()
|
|
1459
1494
|
|
|
1460
1495
|
|
|
1461
1496
|
def fix_events(
|
|
@@ -1556,7 +1591,7 @@ class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
|
|
|
1556
1591
|
Returns:
|
|
1557
1592
|
The hash of the var.
|
|
1558
1593
|
"""
|
|
1559
|
-
return hash((self.
|
|
1594
|
+
return hash((type(self).__name__, self._js_expr))
|
|
1560
1595
|
|
|
1561
1596
|
@classmethod
|
|
1562
1597
|
def create(
|
|
@@ -1620,7 +1655,7 @@ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainV
|
|
|
1620
1655
|
Returns:
|
|
1621
1656
|
The hash of the var.
|
|
1622
1657
|
"""
|
|
1623
|
-
return hash((self.
|
|
1658
|
+
return hash((type(self).__name__, self._js_expr))
|
|
1624
1659
|
|
|
1625
1660
|
@classmethod
|
|
1626
1661
|
def create(
|
|
@@ -106,7 +106,7 @@ class ClientStateVar(Var):
|
|
|
106
106
|
default_var = default
|
|
107
107
|
setter_name = f"set{var_name.capitalize()}"
|
|
108
108
|
hooks = {
|
|
109
|
-
f"const [{var_name}, {setter_name}] = useState({
|
|
109
|
+
f"const [{var_name}, {setter_name}] = useState({default_var!s})": None,
|
|
110
110
|
}
|
|
111
111
|
imports = {
|
|
112
112
|
"react": [ImportVar(tag="useState")],
|
|
@@ -242,4 +242,5 @@ class ClientStateVar(Var):
|
|
|
242
242
|
"""
|
|
243
243
|
if not self._global_ref:
|
|
244
244
|
raise ValueError("ClientStateVar must be global to push the value.")
|
|
245
|
+
value = Var.create(value)
|
|
245
246
|
return run_script(f"{_client_state_ref(self._setter_name)}({value})")
|