reflex 0.5.4a3__py3-none-any.whl → 0.5.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/apps/demo/code/demo.py +1 -0
- reflex/.templates/apps/demo/code/pages/__init__.py +1 -0
- reflex/.templates/apps/demo/code/pages/datatable.py +1 -0
- reflex/.templates/apps/demo/code/pages/forms.py +1 -0
- reflex/.templates/apps/demo/code/pages/graphing.py +1 -0
- reflex/.templates/apps/demo/code/pages/home.py +1 -0
- reflex/.templates/apps/demo/code/styles.py +1 -0
- reflex/.templates/apps/demo/code/webui/components/loading_icon.py +1 -8
- reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +27 -12
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +19 -5
- reflex/.templates/web/utils/state.js +73 -7
- reflex/__init__.py +3 -0
- reflex/__init__.pyi +3 -0
- reflex/admin.py +1 -0
- reflex/app.py +8 -6
- reflex/app_module_for_backend.py +2 -1
- reflex/base.py +4 -4
- reflex/compiler/compiler.py +4 -3
- reflex/compiler/templates.py +2 -0
- reflex/compiler/utils.py +58 -35
- reflex/components/__init__.py +1 -0
- reflex/components/base/__init__.py +1 -0
- reflex/components/base/app_wrap.py +1 -0
- reflex/components/base/fragment.py +1 -0
- reflex/components/base/link.py +0 -1
- reflex/components/base/script.py +11 -15
- reflex/components/base/script.pyi +1 -2
- reflex/components/chakra/base.py +15 -13
- reflex/components/chakra/base.pyi +3 -1
- reflex/components/chakra/datadisplay/code.py +1 -0
- reflex/components/chakra/datadisplay/divider.py +1 -0
- reflex/components/chakra/datadisplay/table.py +1 -0
- reflex/components/chakra/datadisplay/table.pyi +3 -0
- reflex/components/chakra/datadisplay/tag.py +1 -0
- reflex/components/chakra/disclosure/transition.py +1 -0
- reflex/components/chakra/feedback/circularprogress.py +1 -0
- reflex/components/chakra/forms/button.py +1 -0
- reflex/components/chakra/forms/checkbox.py +4 -13
- reflex/components/chakra/forms/checkbox.pyi +1 -3
- reflex/components/chakra/forms/colormodeswitch.py +1 -0
- reflex/components/chakra/forms/editable.py +13 -16
- reflex/components/chakra/forms/editable.pyi +1 -3
- reflex/components/chakra/forms/form.py +1 -0
- reflex/components/chakra/forms/input.py +22 -21
- reflex/components/chakra/forms/input.pyi +4 -4
- reflex/components/chakra/forms/multiselect.py +1 -0
- reflex/components/chakra/forms/numberinput.py +3 -12
- reflex/components/chakra/forms/numberinput.pyi +1 -3
- reflex/components/chakra/forms/pininput.py +8 -14
- reflex/components/chakra/forms/pininput.pyi +2 -3
- reflex/components/chakra/forms/radio.py +4 -13
- reflex/components/chakra/forms/radio.pyi +2 -3
- reflex/components/chakra/forms/rangeslider.py +10 -13
- reflex/components/chakra/forms/rangeslider.pyi +2 -3
- reflex/components/chakra/forms/select.py +4 -12
- reflex/components/chakra/forms/select.pyi +2 -3
- reflex/components/chakra/forms/slider.py +10 -13
- reflex/components/chakra/forms/slider.pyi +2 -3
- reflex/components/chakra/forms/switch.py +4 -13
- reflex/components/chakra/forms/switch.pyi +1 -3
- reflex/components/chakra/forms/textarea.py +16 -17
- reflex/components/chakra/forms/textarea.pyi +1 -3
- reflex/components/chakra/media/avatar.py +4 -12
- reflex/components/chakra/media/avatar.pyi +1 -2
- reflex/components/chakra/media/icon.py +1 -0
- reflex/components/chakra/media/image.py +7 -11
- reflex/components/chakra/media/image.pyi +2 -2
- reflex/components/chakra/navigation/link.py +8 -4
- reflex/components/chakra/navigation/link.pyi +2 -1
- reflex/components/chakra/overlay/alertdialog.py +12 -14
- reflex/components/chakra/overlay/alertdialog.pyi +1 -2
- reflex/components/chakra/overlay/drawer.py +12 -14
- reflex/components/chakra/overlay/drawer.pyi +1 -2
- reflex/components/chakra/overlay/menu.py +7 -11
- reflex/components/chakra/overlay/menu.pyi +2 -2
- reflex/components/chakra/overlay/modal.py +13 -13
- reflex/components/chakra/overlay/modal.pyi +2 -2
- reflex/components/chakra/overlay/popover.py +6 -12
- reflex/components/chakra/overlay/popover.pyi +1 -2
- reflex/components/chakra/overlay/tooltip.py +7 -13
- reflex/components/chakra/overlay/tooltip.pyi +1 -2
- reflex/components/chakra/typography/heading.py +0 -1
- reflex/components/chakra/typography/span.py +1 -0
- reflex/components/chakra/typography/text.py +1 -0
- reflex/components/component.py +70 -43
- reflex/components/core/__init__.py +1 -0
- reflex/components/core/banner.py +27 -24
- reflex/components/core/banner.pyi +6 -2
- reflex/components/core/client_side_routing.py +1 -0
- reflex/components/core/cond.py +19 -17
- reflex/components/core/debounce.py +4 -11
- reflex/components/core/debounce.pyi +1 -1
- reflex/components/core/foreach.py +1 -0
- reflex/components/core/html.py +1 -0
- reflex/components/core/match.py +9 -6
- reflex/components/core/upload.py +26 -25
- reflex/components/core/upload.pyi +3 -4
- reflex/components/datadisplay/__init__.py +1 -0
- reflex/components/datadisplay/code.py +27 -23
- reflex/components/datadisplay/code.pyi +4 -2
- reflex/components/datadisplay/dataeditor.py +73 -80
- reflex/components/datadisplay/dataeditor.pyi +52 -4
- reflex/components/datadisplay/logo.py +1 -0
- reflex/components/el/__init__.py +1 -0
- reflex/components/el/__init__.pyi +8 -0
- reflex/components/el/element.py +0 -1
- reflex/components/el/elements/__init__.py +5 -0
- reflex/components/el/elements/__init__.pyi +12 -1
- reflex/components/el/elements/base.py +1 -0
- reflex/components/el/elements/forms.py +44 -61
- reflex/components/el/elements/forms.pyi +4 -6
- reflex/components/el/elements/inline.py +1 -0
- reflex/components/el/elements/media.py +53 -0
- reflex/components/el/elements/media.pyi +428 -0
- reflex/components/el/elements/metadata.py +11 -0
- reflex/components/el/elements/metadata.pyi +80 -0
- reflex/components/el/elements/other.py +1 -0
- reflex/components/el/elements/scripts.py +1 -0
- reflex/components/el/elements/tables.py +1 -0
- reflex/components/el/elements/typography.py +1 -0
- reflex/components/gridjs/datatable.py +9 -6
- reflex/components/gridjs/datatable.pyi +4 -1
- reflex/components/markdown/markdown.py +36 -41
- reflex/components/markdown/markdown.pyi +4 -3
- reflex/components/media/icon.py +1 -0
- reflex/components/moment/moment.py +11 -17
- reflex/components/moment/moment.pyi +4 -3
- reflex/components/next/base.py +1 -0
- reflex/components/next/image.py +6 -11
- reflex/components/next/image.pyi +2 -2
- reflex/components/plotly/plotly.py +1 -0
- reflex/components/props.py +1 -0
- reflex/components/radix/__init__.py +1 -0
- reflex/components/radix/primitives/__init__.py +1 -0
- reflex/components/radix/primitives/accordion.py +7 -15
- reflex/components/radix/primitives/accordion.pyi +7 -4
- reflex/components/radix/primitives/base.py +1 -0
- reflex/components/radix/primitives/drawer.py +17 -27
- reflex/components/radix/primitives/drawer.pyi +2 -4
- reflex/components/radix/primitives/form.py +4 -12
- reflex/components/radix/primitives/form.pyi +2 -3
- reflex/components/radix/primitives/slider.py +6 -11
- reflex/components/radix/primitives/slider.pyi +2 -2
- reflex/components/radix/themes/__init__.py +1 -0
- reflex/components/radix/themes/base.py +3 -3
- reflex/components/radix/themes/base.pyi +3 -2
- reflex/components/radix/themes/color_mode.py +31 -2
- reflex/components/radix/themes/color_mode.pyi +10 -1
- reflex/components/radix/themes/components/__init__.py +1 -0
- reflex/components/radix/themes/components/alert_dialog.py +13 -24
- reflex/components/radix/themes/components/alert_dialog.pyi +2 -4
- reflex/components/radix/themes/components/aspect_ratio.py +1 -0
- reflex/components/radix/themes/components/card.py +1 -0
- reflex/components/radix/themes/components/checkbox.py +6 -22
- reflex/components/radix/themes/components/checkbox.pyi +2 -4
- reflex/components/radix/themes/components/checkbox_group.py +15 -3
- reflex/components/radix/themes/components/checkbox_group.pyi +10 -2
- reflex/components/radix/themes/components/context_menu.py +29 -38
- reflex/components/radix/themes/components/context_menu.pyi +2 -5
- reflex/components/radix/themes/components/dialog.py +18 -26
- reflex/components/radix/themes/components/dialog.pyi +2 -4
- reflex/components/radix/themes/components/dropdown_menu.py +32 -57
- reflex/components/radix/themes/components/dropdown_menu.pyi +2 -7
- reflex/components/radix/themes/components/hover_card.py +5 -12
- reflex/components/radix/themes/components/hover_card.pyi +2 -3
- reflex/components/radix/themes/components/icon_button.py +1 -0
- reflex/components/radix/themes/components/icon_button.pyi +1 -0
- reflex/components/radix/themes/components/inset.py +1 -0
- reflex/components/radix/themes/components/popover.py +22 -27
- reflex/components/radix/themes/components/popover.pyi +2 -4
- reflex/components/radix/themes/components/radio_group.py +25 -17
- reflex/components/radix/themes/components/radio_group.pyi +2 -3
- reflex/components/radix/themes/components/scroll_area.py +1 -0
- reflex/components/radix/themes/components/segmented_control.py +18 -5
- reflex/components/radix/themes/components/segmented_control.pyi +16 -7
- reflex/components/radix/themes/components/select.py +13 -23
- reflex/components/radix/themes/components/select.pyi +1 -4
- reflex/components/radix/themes/components/separator.py +1 -0
- reflex/components/radix/themes/components/slider.py +7 -12
- reflex/components/radix/themes/components/slider.pyi +2 -3
- reflex/components/radix/themes/components/switch.py +5 -12
- reflex/components/radix/themes/components/switch.pyi +2 -3
- reflex/components/radix/themes/components/table.py +1 -0
- reflex/components/radix/themes/components/tabs.py +4 -11
- reflex/components/radix/themes/components/tabs.pyi +2 -2
- reflex/components/radix/themes/components/text_area.py +19 -18
- reflex/components/radix/themes/components/text_area.pyi +2 -3
- reflex/components/radix/themes/components/text_field.py +19 -18
- reflex/components/radix/themes/components/text_field.pyi +3 -3
- reflex/components/radix/themes/components/tooltip.py +10 -13
- reflex/components/radix/themes/components/tooltip.pyi +2 -3
- reflex/components/radix/themes/layout/__init__.py +1 -0
- reflex/components/radix/themes/layout/box.py +1 -0
- reflex/components/radix/themes/layout/container.py +1 -0
- reflex/components/radix/themes/layout/list.py +1 -0
- reflex/components/radix/themes/layout/list.pyi +1 -0
- reflex/components/radix/themes/layout/section.py +1 -0
- reflex/components/radix/themes/typography/__init__.py +1 -0
- reflex/components/radix/themes/typography/base.py +1 -0
- reflex/components/radix/themes/typography/blockquote.py +1 -0
- reflex/components/radix/themes/typography/code.py +1 -0
- reflex/components/radix/themes/typography/heading.py +1 -0
- reflex/components/radix/themes/typography/link.py +8 -3
- reflex/components/radix/themes/typography/link.pyi +2 -1
- reflex/components/react_player/audio.py +1 -0
- reflex/components/react_player/audio.pyi +48 -0
- reflex/components/react_player/react_player.py +49 -0
- reflex/components/react_player/react_player.pyi +49 -0
- reflex/components/react_player/video.py +1 -0
- reflex/components/react_player/video.pyi +48 -0
- reflex/components/recharts/__init__.py +1 -0
- reflex/components/recharts/cartesian.py +264 -74
- reflex/components/recharts/cartesian.pyi +573 -58
- reflex/components/recharts/charts.py +68 -78
- reflex/components/recharts/charts.pyi +373 -156
- reflex/components/recharts/general.py +52 -20
- reflex/components/recharts/general.pyi +52 -6
- reflex/components/recharts/polar.py +30 -18
- reflex/components/recharts/polar.pyi +66 -5
- reflex/components/recharts/recharts.py +5 -3
- reflex/components/recharts/recharts.pyi +2 -1
- reflex/components/sonner/toast.py +2 -2
- reflex/components/sonner/toast.pyi +1 -1
- reflex/components/suneditor/editor.py +39 -26
- reflex/components/suneditor/editor.pyi +4 -4
- reflex/components/tags/iter_tag.py +1 -0
- reflex/constants/__init__.py +3 -2
- reflex/constants/base.py +20 -21
- reflex/constants/compiler.py +3 -1
- reflex/constants/config.py +1 -0
- reflex/constants/event.py +1 -0
- reflex/constants/installer.py +3 -2
- reflex/constants/style.py +2 -8
- reflex/event.py +36 -6
- reflex/experimental/assets.py +1 -0
- reflex/experimental/client_state.py +9 -3
- reflex/experimental/hooks.py +1 -0
- reflex/experimental/misc.py +12 -3
- reflex/middleware/hydrate_middleware.py +1 -0
- reflex/middleware/middleware.py +1 -0
- reflex/state.py +38 -1
- reflex/style.py +67 -20
- reflex/testing.py +6 -2
- reflex/utils/build.py +76 -72
- reflex/utils/exec.py +17 -9
- reflex/utils/export.py +13 -9
- reflex/utils/imports.py +34 -5
- reflex/utils/lazy_loader.py +1 -0
- reflex/utils/path_ops.py +39 -33
- reflex/utils/prerequisites.py +38 -29
- reflex/utils/processes.py +1 -1
- reflex/utils/serializers.py +3 -6
- reflex/utils/watch.py +3 -1
- reflex/vars.py +26 -10
- reflex/vars.pyi +3 -3
- {reflex-0.5.4a3.dist-info → reflex-0.5.5.dist-info}/METADATA +3 -3
- {reflex-0.5.4a3.dist-info → reflex-0.5.5.dist-info}/RECORD +260 -260
- {reflex-0.5.4a3.dist-info → reflex-0.5.5.dist-info}/LICENSE +0 -0
- {reflex-0.5.4a3.dist-info → reflex-0.5.5.dist-info}/WHEEL +0 -0
- {reflex-0.5.4a3.dist-info → reflex-0.5.5.dist-info}/entry_points.txt +0 -0
reflex/utils/build.py
CHANGED
|
@@ -18,7 +18,7 @@ from reflex.utils import console, path_ops, prerequisites, processes
|
|
|
18
18
|
def set_env_json():
|
|
19
19
|
"""Write the upload url to a REFLEX_JSON."""
|
|
20
20
|
path_ops.update_json_file(
|
|
21
|
-
constants.Dirs.ENV_JSON,
|
|
21
|
+
str(prerequisites.get_web_dir() / constants.Dirs.ENV_JSON),
|
|
22
22
|
{endpoint.name: endpoint.get_url() for endpoint in constants.Endpoint},
|
|
23
23
|
)
|
|
24
24
|
|
|
@@ -55,8 +55,8 @@ def generate_sitemap_config(deploy_url: str, export=False):
|
|
|
55
55
|
|
|
56
56
|
config = json.dumps(config)
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
sitemap = prerequisites.get_web_dir() / constants.Next.SITEMAP_CONFIG_FILE
|
|
59
|
+
sitemap.write_text(templates.SITEMAP_CONFIG(config=config))
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def _zip(
|
|
@@ -129,85 +129,89 @@ def _zip(
|
|
|
129
129
|
zipf.write(file, os.path.relpath(file, root_dir))
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
def
|
|
133
|
-
backend: bool = True,
|
|
132
|
+
def zip_app(
|
|
134
133
|
frontend: bool = True,
|
|
135
|
-
|
|
134
|
+
backend: bool = True,
|
|
136
135
|
zip_dest_dir: str = os.getcwd(),
|
|
137
|
-
deploy_url: str | None = None,
|
|
138
136
|
upload_db_file: bool = False,
|
|
139
137
|
):
|
|
140
|
-
"""
|
|
138
|
+
"""Zip up the app.
|
|
141
139
|
|
|
142
140
|
Args:
|
|
143
|
-
backend: Whether to zip up the backend app.
|
|
144
141
|
frontend: Whether to zip up the frontend app.
|
|
145
|
-
|
|
146
|
-
zip_dest_dir: The
|
|
147
|
-
|
|
148
|
-
upload_db_file: Whether to include local sqlite db files from the backend zip.
|
|
142
|
+
backend: Whether to zip up the backend app.
|
|
143
|
+
zip_dest_dir: The directory to export the zip file to.
|
|
144
|
+
upload_db_file: Whether to upload the database file.
|
|
149
145
|
"""
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
command = "export"
|
|
146
|
+
files_to_exclude = {
|
|
147
|
+
constants.ComponentName.FRONTEND.zip(),
|
|
148
|
+
constants.ComponentName.BACKEND.zip(),
|
|
149
|
+
}
|
|
155
150
|
|
|
156
151
|
if frontend:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
"Collecting build traces",
|
|
165
|
-
]
|
|
152
|
+
_zip(
|
|
153
|
+
component_name=constants.ComponentName.FRONTEND,
|
|
154
|
+
target=os.path.join(zip_dest_dir, constants.ComponentName.FRONTEND.zip()),
|
|
155
|
+
root_dir=str(prerequisites.get_web_dir() / constants.Dirs.STATIC),
|
|
156
|
+
files_to_exclude=files_to_exclude,
|
|
157
|
+
exclude_venv_dirs=False,
|
|
158
|
+
)
|
|
166
159
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
160
|
+
if backend:
|
|
161
|
+
_zip(
|
|
162
|
+
component_name=constants.ComponentName.BACKEND,
|
|
163
|
+
target=os.path.join(zip_dest_dir, constants.ComponentName.BACKEND.zip()),
|
|
164
|
+
root_dir=".",
|
|
165
|
+
dirs_to_exclude={"__pycache__"},
|
|
166
|
+
files_to_exclude=files_to_exclude,
|
|
167
|
+
top_level_dirs_to_exclude={"assets"},
|
|
168
|
+
exclude_venv_dirs=True,
|
|
169
|
+
upload_db_file=upload_db_file,
|
|
170
|
+
)
|
|
171
171
|
|
|
172
|
-
checkpoints.extend(["Loading next-sitemap", "Generation completed"])
|
|
173
172
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
173
|
+
def build(
|
|
174
|
+
deploy_url: str | None = None,
|
|
175
|
+
for_export: bool = False,
|
|
176
|
+
):
|
|
177
|
+
"""Build the app for deployment.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
deploy_url: The deployment URL.
|
|
181
|
+
for_export: Whether the build is for export.
|
|
182
|
+
"""
|
|
183
|
+
wdir = prerequisites.get_web_dir()
|
|
184
|
+
|
|
185
|
+
# Clean the static directory if it exists.
|
|
186
|
+
path_ops.rm(str(wdir / constants.Dirs.STATIC))
|
|
187
|
+
|
|
188
|
+
# The export command to run.
|
|
189
|
+
command = "export"
|
|
190
|
+
|
|
191
|
+
checkpoints = [
|
|
192
|
+
"Linting and checking ",
|
|
193
|
+
"Creating an optimized production build",
|
|
194
|
+
"Route (pages)",
|
|
195
|
+
"prerendered as static HTML",
|
|
196
|
+
"Collecting page data",
|
|
197
|
+
"Finalizing page optimization",
|
|
198
|
+
"Collecting build traces",
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
# Generate a sitemap if a deploy URL is provided.
|
|
202
|
+
if deploy_url is not None:
|
|
203
|
+
generate_sitemap_config(deploy_url, export=for_export)
|
|
204
|
+
command = "export-sitemap"
|
|
205
|
+
|
|
206
|
+
checkpoints.extend(["Loading next-sitemap", "Generation completed"])
|
|
207
|
+
|
|
208
|
+
# Start the subprocess with the progress bar.
|
|
209
|
+
process = processes.new_process(
|
|
210
|
+
[prerequisites.get_package_manager(), "run", command],
|
|
211
|
+
cwd=wdir,
|
|
212
|
+
shell=constants.IS_WINDOWS,
|
|
213
|
+
)
|
|
214
|
+
processes.show_progress("Creating Production Build", process, checkpoints)
|
|
211
215
|
|
|
212
216
|
|
|
213
217
|
def setup_frontend(
|
|
@@ -226,7 +230,7 @@ def setup_frontend(
|
|
|
226
230
|
# Copy asset files to public folder.
|
|
227
231
|
path_ops.cp(
|
|
228
232
|
src=str(root / constants.Dirs.APP_ASSETS),
|
|
229
|
-
dest=str(root / constants.Dirs.
|
|
233
|
+
dest=str(root / prerequisites.get_web_dir() / constants.Dirs.PUBLIC),
|
|
230
234
|
)
|
|
231
235
|
|
|
232
236
|
# Set the environment variables in client (env.json).
|
|
@@ -242,7 +246,7 @@ def setup_frontend(
|
|
|
242
246
|
"telemetry",
|
|
243
247
|
"disable",
|
|
244
248
|
],
|
|
245
|
-
cwd=
|
|
249
|
+
cwd=prerequisites.get_web_dir(),
|
|
246
250
|
stdout=subprocess.DEVNULL,
|
|
247
251
|
shell=constants.IS_WINDOWS,
|
|
248
252
|
)
|
|
@@ -259,7 +263,7 @@ def setup_frontend_prod(
|
|
|
259
263
|
disable_telemetry: Whether to disable the Next telemetry.
|
|
260
264
|
"""
|
|
261
265
|
setup_frontend(root, disable_telemetry)
|
|
262
|
-
|
|
266
|
+
build(deploy_url=get_config().deploy_url)
|
|
263
267
|
|
|
264
268
|
|
|
265
269
|
def _looks_like_venv_dir(dir_to_check: str) -> bool:
|
reflex/utils/exec.py
CHANGED
|
@@ -17,6 +17,7 @@ import psutil
|
|
|
17
17
|
from reflex import constants
|
|
18
18
|
from reflex.config import get_config
|
|
19
19
|
from reflex.utils import console, path_ops
|
|
20
|
+
from reflex.utils.prerequisites import get_web_dir
|
|
20
21
|
from reflex.utils.watch import AssetFolderWatch
|
|
21
22
|
|
|
22
23
|
# For uvicorn windows bug fix (#2335)
|
|
@@ -82,8 +83,8 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
|
|
82
83
|
"""
|
|
83
84
|
from reflex.utils import processes
|
|
84
85
|
|
|
85
|
-
json_file_path =
|
|
86
|
-
last_hash = detect_package_change(json_file_path)
|
|
86
|
+
json_file_path = get_web_dir() / constants.PackageJson.PATH
|
|
87
|
+
last_hash = detect_package_change(str(json_file_path))
|
|
87
88
|
process = None
|
|
88
89
|
first_run = True
|
|
89
90
|
|
|
@@ -94,7 +95,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
|
|
94
95
|
kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore
|
|
95
96
|
process = processes.new_process(
|
|
96
97
|
run_command,
|
|
97
|
-
cwd=
|
|
98
|
+
cwd=get_web_dir(),
|
|
98
99
|
shell=constants.IS_WINDOWS,
|
|
99
100
|
**kwargs,
|
|
100
101
|
)
|
|
@@ -108,7 +109,14 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
|
|
108
109
|
url = match.group(1)
|
|
109
110
|
if get_config().frontend_path != "":
|
|
110
111
|
url = urljoin(url, get_config().frontend_path)
|
|
111
|
-
|
|
112
|
+
|
|
113
|
+
console.print(
|
|
114
|
+
f"App running at: [bold green]{url}[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
|
|
115
|
+
)
|
|
116
|
+
if backend_present:
|
|
117
|
+
console.print(
|
|
118
|
+
f"Backend running at: [bold green]http://0.0.0.0:{get_config().backend_port}[/bold green]"
|
|
119
|
+
)
|
|
112
120
|
first_run = False
|
|
113
121
|
else:
|
|
114
122
|
console.print("New packages detected: Updating app...")
|
|
@@ -121,7 +129,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
|
|
121
129
|
"`REFLEX_USE_NPM=1 reflex init`\n"
|
|
122
130
|
"`REFLEX_USE_NPM=1 reflex run`"
|
|
123
131
|
)
|
|
124
|
-
new_hash = detect_package_change(json_file_path)
|
|
132
|
+
new_hash = detect_package_change(str(json_file_path))
|
|
125
133
|
if new_hash != last_hash:
|
|
126
134
|
last_hash = new_hash
|
|
127
135
|
kill(process.pid)
|
|
@@ -194,10 +202,10 @@ def run_backend(
|
|
|
194
202
|
config = get_config()
|
|
195
203
|
app_module = f"reflex.app_module_for_backend:{constants.CompileVars.APP}"
|
|
196
204
|
|
|
205
|
+
web_dir = get_web_dir()
|
|
197
206
|
# Create a .nocompile file to skip compile for backend.
|
|
198
|
-
if
|
|
199
|
-
|
|
200
|
-
pass
|
|
207
|
+
if web_dir.exists():
|
|
208
|
+
(web_dir / constants.NOCOMPILE_FILE).touch()
|
|
201
209
|
|
|
202
210
|
# Run the backend in development mode.
|
|
203
211
|
uvicorn.run(
|
|
@@ -207,7 +215,7 @@ def run_backend(
|
|
|
207
215
|
log_level=loglevel.value,
|
|
208
216
|
reload=True,
|
|
209
217
|
reload_dirs=[config.app_name],
|
|
210
|
-
reload_excludes=[
|
|
218
|
+
reload_excludes=[str(web_dir)],
|
|
211
219
|
)
|
|
212
220
|
|
|
213
221
|
|
reflex/utils/export.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Export utilities."""
|
|
2
|
+
|
|
2
3
|
import os
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Optional
|
|
@@ -55,15 +56,18 @@ def export(
|
|
|
55
56
|
# Set up .web directory and install frontend dependencies.
|
|
56
57
|
build.setup_frontend(Path.cwd())
|
|
57
58
|
|
|
58
|
-
#
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
# Build the static app.
|
|
60
|
+
if frontend:
|
|
61
|
+
build.build(deploy_url=config.deploy_url, for_export=True)
|
|
62
|
+
|
|
63
|
+
# Zip up the app.
|
|
64
|
+
if zipping:
|
|
65
|
+
build.zip_app(
|
|
66
|
+
frontend=frontend,
|
|
67
|
+
backend=backend,
|
|
68
|
+
zip_dest_dir=zip_dest_dir,
|
|
69
|
+
upload_db_file=upload_db_file,
|
|
70
|
+
)
|
|
67
71
|
|
|
68
72
|
# Post a telemetry event.
|
|
69
73
|
telemetry.send("export")
|
reflex/utils/imports.py
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from collections import defaultdict
|
|
6
|
-
from typing import Dict, List, Optional
|
|
6
|
+
from typing import Dict, List, Optional, Union
|
|
7
7
|
|
|
8
8
|
from reflex.base import Base
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def merge_imports(*imports) ->
|
|
11
|
+
def merge_imports(*imports: ImportDict | ParsedImportDict) -> ParsedImportDict:
|
|
12
12
|
"""Merge multiple import dicts together.
|
|
13
13
|
|
|
14
14
|
Args:
|
|
@@ -24,7 +24,31 @@ def merge_imports(*imports) -> ImportDict:
|
|
|
24
24
|
return all_imports
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def
|
|
27
|
+
def parse_imports(imports: ImportDict | ParsedImportDict) -> ParsedImportDict:
|
|
28
|
+
"""Parse the import dict into a standard format.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
imports: The import dict to parse.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
The parsed import dict.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def _make_list(value: ImportTypes) -> list[str | ImportVar] | list[ImportVar]:
|
|
38
|
+
if isinstance(value, (str, ImportVar)):
|
|
39
|
+
return [value]
|
|
40
|
+
return value
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
package: [
|
|
44
|
+
ImportVar(tag=tag) if isinstance(tag, str) else tag
|
|
45
|
+
for tag in _make_list(maybe_tags)
|
|
46
|
+
]
|
|
47
|
+
for package, maybe_tags in imports.items()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def collapse_imports(imports: ParsedImportDict) -> ParsedImportDict:
|
|
28
52
|
"""Remove all duplicate ImportVar within an ImportDict.
|
|
29
53
|
|
|
30
54
|
Args:
|
|
@@ -33,7 +57,10 @@ def collapse_imports(imports: ImportDict) -> ImportDict:
|
|
|
33
57
|
Returns:
|
|
34
58
|
The collapsed import dict.
|
|
35
59
|
"""
|
|
36
|
-
return {
|
|
60
|
+
return {
|
|
61
|
+
lib: list(set(import_vars)) if isinstance(import_vars, list) else import_vars
|
|
62
|
+
for lib, import_vars in imports.items()
|
|
63
|
+
}
|
|
37
64
|
|
|
38
65
|
|
|
39
66
|
class ImportVar(Base):
|
|
@@ -90,4 +117,6 @@ class ImportVar(Base):
|
|
|
90
117
|
)
|
|
91
118
|
|
|
92
119
|
|
|
93
|
-
|
|
120
|
+
ImportTypes = Union[str, ImportVar, List[Union[str, ImportVar]], List[ImportVar]]
|
|
121
|
+
ImportDict = Dict[str, ImportTypes]
|
|
122
|
+
ParsedImportDict = Dict[str, List[ImportVar]]
|
reflex/utils/lazy_loader.py
CHANGED
reflex/utils/path_ops.py
CHANGED
|
@@ -14,19 +14,20 @@ from reflex import constants
|
|
|
14
14
|
join = os.linesep.join
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def rm(path: str):
|
|
17
|
+
def rm(path: str | Path):
|
|
18
18
|
"""Remove a file or directory.
|
|
19
19
|
|
|
20
20
|
Args:
|
|
21
21
|
path: The path to the file or directory.
|
|
22
22
|
"""
|
|
23
|
-
|
|
23
|
+
path = Path(path)
|
|
24
|
+
if path.is_dir():
|
|
24
25
|
shutil.rmtree(path)
|
|
25
|
-
elif
|
|
26
|
-
|
|
26
|
+
elif path.is_file():
|
|
27
|
+
path.unlink()
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
def cp(src: str, dest: str, overwrite: bool = True) -> bool:
|
|
30
|
+
def cp(src: str | Path, dest: str | Path, overwrite: bool = True) -> bool:
|
|
30
31
|
"""Copy a file or directory.
|
|
31
32
|
|
|
32
33
|
Args:
|
|
@@ -37,11 +38,12 @@ def cp(src: str, dest: str, overwrite: bool = True) -> bool:
|
|
|
37
38
|
Returns:
|
|
38
39
|
Whether the copy was successful.
|
|
39
40
|
"""
|
|
41
|
+
src, dest = Path(src), Path(dest)
|
|
40
42
|
if src == dest:
|
|
41
43
|
return False
|
|
42
|
-
if not overwrite and
|
|
44
|
+
if not overwrite and dest.exists():
|
|
43
45
|
return False
|
|
44
|
-
if
|
|
46
|
+
if src.is_dir():
|
|
45
47
|
rm(dest)
|
|
46
48
|
shutil.copytree(src, dest)
|
|
47
49
|
else:
|
|
@@ -49,7 +51,7 @@ def cp(src: str, dest: str, overwrite: bool = True) -> bool:
|
|
|
49
51
|
return True
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
def mv(src: str, dest: str, overwrite: bool = True) -> bool:
|
|
54
|
+
def mv(src: str | Path, dest: str | Path, overwrite: bool = True) -> bool:
|
|
53
55
|
"""Move a file or directory.
|
|
54
56
|
|
|
55
57
|
Args:
|
|
@@ -60,25 +62,26 @@ def mv(src: str, dest: str, overwrite: bool = True) -> bool:
|
|
|
60
62
|
Returns:
|
|
61
63
|
Whether the move was successful.
|
|
62
64
|
"""
|
|
65
|
+
src, dest = Path(src), Path(dest)
|
|
63
66
|
if src == dest:
|
|
64
67
|
return False
|
|
65
|
-
if not overwrite and
|
|
68
|
+
if not overwrite and dest.exists():
|
|
66
69
|
return False
|
|
67
70
|
rm(dest)
|
|
68
71
|
shutil.move(src, dest)
|
|
69
72
|
return True
|
|
70
73
|
|
|
71
74
|
|
|
72
|
-
def mkdir(path: str):
|
|
75
|
+
def mkdir(path: str | Path):
|
|
73
76
|
"""Create a directory.
|
|
74
77
|
|
|
75
78
|
Args:
|
|
76
79
|
path: The path to the directory.
|
|
77
80
|
"""
|
|
78
|
-
|
|
81
|
+
Path(path).mkdir(parents=True, exist_ok=True)
|
|
79
82
|
|
|
80
83
|
|
|
81
|
-
def ln(src: str, dest: str, overwrite: bool = False) -> bool:
|
|
84
|
+
def ln(src: str | Path, dest: str | Path, overwrite: bool = False) -> bool:
|
|
82
85
|
"""Create a symbolic link.
|
|
83
86
|
|
|
84
87
|
Args:
|
|
@@ -89,19 +92,20 @@ def ln(src: str, dest: str, overwrite: bool = False) -> bool:
|
|
|
89
92
|
Returns:
|
|
90
93
|
Whether the link was successful.
|
|
91
94
|
"""
|
|
95
|
+
src, dest = Path(src), Path(dest)
|
|
92
96
|
if src == dest:
|
|
93
97
|
return False
|
|
94
|
-
if not overwrite and (
|
|
98
|
+
if not overwrite and (dest.exists() or dest.is_symlink()):
|
|
95
99
|
return False
|
|
96
|
-
if
|
|
100
|
+
if src.is_dir():
|
|
97
101
|
rm(dest)
|
|
98
|
-
|
|
102
|
+
src.symlink_to(dest, target_is_directory=True)
|
|
99
103
|
else:
|
|
100
|
-
|
|
104
|
+
src.symlink_to(dest)
|
|
101
105
|
return True
|
|
102
106
|
|
|
103
107
|
|
|
104
|
-
def which(program: str) -> str | None:
|
|
108
|
+
def which(program: str | Path) -> str | Path | None:
|
|
105
109
|
"""Find the path to an executable.
|
|
106
110
|
|
|
107
111
|
Args:
|
|
@@ -110,7 +114,7 @@ def which(program: str) -> str | None:
|
|
|
110
114
|
Returns:
|
|
111
115
|
The path to the executable.
|
|
112
116
|
"""
|
|
113
|
-
return shutil.which(program)
|
|
117
|
+
return shutil.which(str(program))
|
|
114
118
|
|
|
115
119
|
|
|
116
120
|
def get_node_bin_path() -> str | None:
|
|
@@ -119,10 +123,11 @@ def get_node_bin_path() -> str | None:
|
|
|
119
123
|
Returns:
|
|
120
124
|
The path to the node bin folder.
|
|
121
125
|
"""
|
|
122
|
-
|
|
126
|
+
bin_path = Path(constants.Node.BIN_PATH)
|
|
127
|
+
if not bin_path.exists():
|
|
123
128
|
str_path = which("node")
|
|
124
129
|
return str(Path(str_path).parent.resolve()) if str_path else str_path
|
|
125
|
-
return str(
|
|
130
|
+
return str(bin_path.resolve())
|
|
126
131
|
|
|
127
132
|
|
|
128
133
|
def get_node_path() -> str | None:
|
|
@@ -131,9 +136,10 @@ def get_node_path() -> str | None:
|
|
|
131
136
|
Returns:
|
|
132
137
|
The path to the node binary file.
|
|
133
138
|
"""
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
node_path = Path(constants.Node.PATH)
|
|
140
|
+
if not node_path.exists():
|
|
141
|
+
return str(which("node"))
|
|
142
|
+
return str(node_path)
|
|
137
143
|
|
|
138
144
|
|
|
139
145
|
def get_npm_path() -> str | None:
|
|
@@ -142,12 +148,13 @@ def get_npm_path() -> str | None:
|
|
|
142
148
|
Returns:
|
|
143
149
|
The path to the npm binary file.
|
|
144
150
|
"""
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
151
|
+
npm_path = Path(constants.Node.NPM_PATH)
|
|
152
|
+
if not npm_path.exists():
|
|
153
|
+
return str(which("npm"))
|
|
154
|
+
return str(npm_path)
|
|
148
155
|
|
|
149
156
|
|
|
150
|
-
def update_json_file(file_path: str, update_dict: dict[str, int | str]):
|
|
157
|
+
def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
|
|
151
158
|
"""Update the contents of a json file.
|
|
152
159
|
|
|
153
160
|
Args:
|
|
@@ -176,7 +183,7 @@ def update_json_file(file_path: str, update_dict: dict[str, int | str]):
|
|
|
176
183
|
json.dump(json_object, f, ensure_ascii=False)
|
|
177
184
|
|
|
178
185
|
|
|
179
|
-
def find_replace(directory: str, find: str, replace: str):
|
|
186
|
+
def find_replace(directory: str | Path, find: str, replace: str):
|
|
180
187
|
"""Recursively find and replace text in files in a directory.
|
|
181
188
|
|
|
182
189
|
Args:
|
|
@@ -184,11 +191,10 @@ def find_replace(directory: str, find: str, replace: str):
|
|
|
184
191
|
find: The text to find.
|
|
185
192
|
replace: The text to replace.
|
|
186
193
|
"""
|
|
194
|
+
directory = Path(directory)
|
|
187
195
|
for root, _dirs, files in os.walk(directory):
|
|
188
196
|
for file in files:
|
|
189
|
-
filepath =
|
|
190
|
-
|
|
191
|
-
text = f.read()
|
|
197
|
+
filepath = Path(root, file)
|
|
198
|
+
text = filepath.read_text(encoding="utf-8")
|
|
192
199
|
text = re.sub(find, replace, text)
|
|
193
|
-
|
|
194
|
-
f.write(text)
|
|
200
|
+
filepath.write_text(text)
|