reflex 0.6.4a3__py3-none-any.whl → 0.6.5a1__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.
- reflex/.templates/jinja/web/pages/custom_component.js.jinja2 +0 -14
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -8
- reflex/.templates/web/components/shiki/code.js +16 -11
- reflex/.templates/web/utils/state.js +29 -21
- reflex/__init__.py +4 -0
- reflex/__init__.pyi +4 -0
- reflex/app.py +148 -154
- reflex/app_mixins/lifespan.py +5 -1
- reflex/app_mixins/middleware.py +3 -1
- reflex/app_mixins/mixin.py +3 -2
- reflex/base.py +2 -4
- reflex/compiler/compiler.py +111 -37
- reflex/components/base/app_wrap.pyi +17 -17
- reflex/components/base/bare.py +72 -3
- reflex/components/base/body.pyi +17 -17
- reflex/components/base/document.pyi +81 -81
- reflex/components/base/error_boundary.pyi +25 -18
- reflex/components/base/fragment.pyi +17 -17
- reflex/components/base/head.pyi +33 -33
- reflex/components/base/link.pyi +33 -33
- reflex/components/base/meta.pyi +65 -65
- reflex/components/base/script.py +4 -4
- reflex/components/base/script.pyi +23 -20
- reflex/components/component.py +250 -31
- reflex/components/core/banner.py +1 -1
- reflex/components/core/banner.pyi +81 -81
- reflex/components/core/client_side_routing.pyi +33 -33
- reflex/components/core/clipboard.py +2 -2
- reflex/components/core/clipboard.pyi +24 -18
- reflex/components/core/debounce.py +2 -2
- reflex/components/core/debounce.pyi +18 -18
- reflex/components/core/html.pyi +17 -17
- reflex/components/core/upload.py +82 -28
- reflex/components/core/upload.pyi +77 -72
- reflex/components/datadisplay/code.py +55 -40
- reflex/components/datadisplay/code.pyi +46 -44
- reflex/components/datadisplay/dataeditor.py +21 -20
- reflex/components/datadisplay/dataeditor.pyi +103 -35
- reflex/components/datadisplay/shiki_code_block.py +60 -27
- reflex/components/datadisplay/shiki_code_block.pyi +86 -65
- reflex/components/dynamic.py +9 -5
- reflex/components/el/element.pyi +17 -17
- reflex/components/el/elements/base.pyi +17 -17
- reflex/components/el/elements/forms.py +12 -3
- reflex/components/el/elements/forms.pyi +293 -233
- reflex/components/el/elements/inline.pyi +449 -449
- reflex/components/el/elements/media.pyi +401 -401
- reflex/components/el/elements/metadata.pyi +97 -97
- reflex/components/el/elements/other.pyi +113 -113
- reflex/components/el/elements/scripts.pyi +49 -49
- reflex/components/el/elements/sectioning.pyi +241 -241
- reflex/components/el/elements/tables.pyi +161 -161
- reflex/components/el/elements/typography.pyi +241 -241
- reflex/components/gridjs/datatable.pyi +33 -33
- reflex/components/lucide/icon.py +1 -1
- reflex/components/lucide/icon.pyi +33 -33
- reflex/components/markdown/markdown.py +180 -49
- reflex/components/markdown/markdown.pyi +36 -19
- reflex/components/moment/moment.py +17 -21
- reflex/components/moment/moment.pyi +26 -21
- reflex/components/next/base.pyi +17 -17
- reflex/components/next/image.py +3 -3
- reflex/components/next/image.pyi +21 -19
- reflex/components/next/link.pyi +17 -17
- reflex/components/next/video.pyi +17 -17
- reflex/components/plotly/plotly.py +79 -78
- reflex/components/plotly/plotly.pyi +91 -41
- reflex/components/props.py +34 -0
- reflex/components/radix/primitives/accordion.py +15 -8
- reflex/components/radix/primitives/accordion.pyi +121 -118
- reflex/components/radix/primitives/base.pyi +33 -33
- reflex/components/radix/primitives/drawer.py +41 -20
- reflex/components/radix/primitives/drawer.pyi +279 -190
- reflex/components/radix/primitives/form.py +2 -2
- reflex/components/radix/primitives/form.pyi +200 -167
- reflex/components/radix/primitives/progress.pyi +81 -81
- reflex/components/radix/primitives/slider.pyi +89 -83
- reflex/components/radix/themes/base.py +27 -1
- reflex/components/radix/themes/base.pyi +286 -113
- reflex/components/radix/themes/color_mode.py +17 -9
- reflex/components/radix/themes/color_mode.pyi +68 -56
- reflex/components/radix/themes/components/alert_dialog.py +8 -5
- reflex/components/radix/themes/components/alert_dialog.pyi +125 -117
- reflex/components/radix/themes/components/aspect_ratio.pyi +17 -17
- reflex/components/radix/themes/components/avatar.py +1 -5
- reflex/components/radix/themes/components/avatar.pyi +17 -17
- reflex/components/radix/themes/components/badge.py +1 -5
- reflex/components/radix/themes/components/badge.pyi +17 -17
- reflex/components/radix/themes/components/button.pyi +18 -21
- reflex/components/radix/themes/components/callout.py +1 -4
- reflex/components/radix/themes/components/callout.pyi +81 -81
- reflex/components/radix/themes/components/card.py +1 -3
- reflex/components/radix/themes/components/card.pyi +17 -17
- reflex/components/radix/themes/components/checkbox.py +4 -8
- reflex/components/radix/themes/components/checkbox.pyi +61 -52
- reflex/components/radix/themes/components/checkbox_cards.pyi +33 -33
- reflex/components/radix/themes/components/checkbox_group.pyi +33 -33
- reflex/components/radix/themes/components/context_menu.py +121 -28
- reflex/components/radix/themes/components/context_menu.pyi +250 -147
- reflex/components/radix/themes/components/data_list.pyi +65 -65
- reflex/components/radix/themes/components/dialog.py +11 -11
- reflex/components/radix/themes/components/dialog.pyi +135 -120
- reflex/components/radix/themes/components/dropdown_menu.py +14 -25
- reflex/components/radix/themes/components/dropdown_menu.pyi +157 -145
- reflex/components/radix/themes/components/hover_card.py +19 -7
- reflex/components/radix/themes/components/hover_card.pyi +102 -67
- reflex/components/radix/themes/components/icon_button.pyi +18 -21
- reflex/components/radix/themes/components/inset.py +1 -3
- reflex/components/radix/themes/components/inset.pyi +17 -17
- reflex/components/radix/themes/components/popover.py +22 -13
- reflex/components/radix/themes/components/popover.pyi +98 -72
- reflex/components/radix/themes/components/progress.pyi +17 -17
- reflex/components/radix/themes/components/radio.pyi +17 -17
- reflex/components/radix/themes/components/radio_cards.py +2 -2
- reflex/components/radix/themes/components/radio_cards.pyi +37 -34
- reflex/components/radix/themes/components/radio_group.py +3 -7
- reflex/components/radix/themes/components/radio_group.pyi +69 -66
- reflex/components/radix/themes/components/scroll_area.py +1 -3
- reflex/components/radix/themes/components/scroll_area.pyi +17 -17
- reflex/components/radix/themes/components/segmented_control.pyi +37 -34
- reflex/components/radix/themes/components/select.py +7 -11
- reflex/components/radix/themes/components/select.pyi +175 -154
- reflex/components/radix/themes/components/separator.py +1 -4
- reflex/components/radix/themes/components/separator.pyi +17 -17
- reflex/components/radix/themes/components/skeleton.pyi +17 -17
- reflex/components/radix/themes/components/slider.py +12 -21
- reflex/components/radix/themes/components/slider.pyi +47 -25
- reflex/components/radix/themes/components/spinner.py +1 -4
- reflex/components/radix/themes/components/spinner.pyi +17 -17
- reflex/components/radix/themes/components/switch.py +3 -6
- reflex/components/radix/themes/components/switch.pyi +21 -18
- reflex/components/radix/themes/components/table.py +21 -5
- reflex/components/radix/themes/components/table.pyi +392 -116
- reflex/components/radix/themes/components/tabs.py +3 -6
- reflex/components/radix/themes/components/tabs.pyi +89 -83
- reflex/components/radix/themes/components/text_area.py +1 -5
- reflex/components/radix/themes/components/text_area.pyi +43 -20
- reflex/components/radix/themes/components/text_field.py +1 -5
- reflex/components/radix/themes/components/text_field.pyi +101 -55
- reflex/components/radix/themes/components/tooltip.py +5 -7
- reflex/components/radix/themes/components/tooltip.pyi +25 -22
- reflex/components/radix/themes/layout/base.py +2 -27
- reflex/components/radix/themes/layout/base.pyi +82 -82
- reflex/components/radix/themes/layout/box.pyi +17 -17
- reflex/components/radix/themes/layout/center.pyi +17 -17
- reflex/components/radix/themes/layout/container.pyi +17 -17
- reflex/components/radix/themes/layout/flex.py +1 -6
- reflex/components/radix/themes/layout/flex.pyi +17 -17
- reflex/components/radix/themes/layout/grid.py +1 -6
- reflex/components/radix/themes/layout/grid.pyi +17 -17
- reflex/components/radix/themes/layout/list.py +20 -15
- reflex/components/radix/themes/layout/list.pyi +175 -92
- reflex/components/radix/themes/layout/section.pyi +17 -17
- reflex/components/radix/themes/layout/spacer.pyi +17 -17
- reflex/components/radix/themes/layout/stack.py +6 -6
- reflex/components/radix/themes/layout/stack.pyi +91 -62
- reflex/components/radix/themes/typography/blockquote.py +2 -8
- reflex/components/radix/themes/typography/blockquote.pyi +17 -17
- reflex/components/radix/themes/typography/code.py +4 -10
- reflex/components/radix/themes/typography/code.pyi +19 -18
- reflex/components/radix/themes/typography/heading.py +4 -11
- reflex/components/radix/themes/typography/heading.pyi +19 -18
- reflex/components/radix/themes/typography/link.py +4 -10
- reflex/components/radix/themes/typography/link.pyi +19 -18
- reflex/components/radix/themes/typography/text.py +4 -11
- reflex/components/radix/themes/typography/text.pyi +115 -114
- reflex/components/react_player/audio.pyi +58 -33
- reflex/components/react_player/react_player.py +17 -17
- reflex/components/react_player/react_player.pyi +55 -33
- reflex/components/react_player/video.pyi +58 -33
- reflex/components/recharts/cartesian.py +45 -45
- reflex/components/recharts/cartesian.pyi +389 -304
- reflex/components/recharts/charts.py +22 -22
- reflex/components/recharts/charts.pyi +226 -179
- reflex/components/recharts/general.py +26 -27
- reflex/components/recharts/general.pyi +106 -99
- reflex/components/recharts/polar.py +33 -33
- reflex/components/recharts/polar.pyi +70 -64
- reflex/components/recharts/recharts.pyi +33 -33
- reflex/components/sonner/toast.py +9 -36
- reflex/components/sonner/toast.pyi +20 -24
- reflex/components/suneditor/editor.py +8 -8
- reflex/components/suneditor/editor.pyi +50 -25
- reflex/components/tags/iter_tag.py +1 -10
- reflex/components/tags/tag.py +1 -4
- reflex/config.py +198 -35
- reflex/constants/__init__.py +4 -16
- reflex/constants/base.py +7 -14
- reflex/constants/colors.py +0 -1
- reflex/constants/installer.py +12 -7
- reflex/constants/state.py +4 -0
- reflex/custom_components/custom_components.py +6 -6
- reflex/event.py +486 -241
- reflex/experimental/client_state.py +9 -9
- reflex/experimental/layout.py +2 -2
- reflex/experimental/layout.pyi +95 -87
- reflex/experimental/misc.py +1 -1
- reflex/istate/__init__.py +1 -0
- reflex/istate/proxy.py +33 -0
- reflex/istate/wrappers.py +27 -0
- reflex/model.py +7 -7
- reflex/page.py +2 -1
- reflex/reflex.py +142 -8
- reflex/state.py +127 -46
- reflex/testing.py +9 -7
- reflex/utils/console.py +0 -1
- reflex/utils/exceptions.py +31 -3
- reflex/utils/exec.py +33 -14
- reflex/utils/format.py +15 -12
- reflex/utils/net.py +1 -1
- reflex/utils/path_ops.py +2 -2
- reflex/utils/prerequisites.py +82 -46
- reflex/utils/pyi_generator.py +63 -20
- reflex/utils/registry.py +1 -1
- reflex/utils/serializers.py +75 -36
- reflex/utils/telemetry.py +3 -2
- reflex/utils/types.py +125 -10
- reflex/vars/base.py +131 -119
- reflex/vars/function.py +59 -12
- reflex/vars/number.py +3 -1
- reflex/vars/object.py +30 -24
- reflex/vars/sequence.py +7 -7
- {reflex-0.6.4a3.dist-info → reflex-0.6.5a1.dist-info}/METADATA +3 -3
- reflex-0.6.5a1.dist-info/RECORD +394 -0
- reflex-0.6.4a3.dist-info/RECORD +0 -391
- {reflex-0.6.4a3.dist-info → reflex-0.6.5a1.dist-info}/LICENSE +0 -0
- {reflex-0.6.4a3.dist-info → reflex-0.6.5a1.dist-info}/WHEEL +0 -0
- {reflex-0.6.4a3.dist-info → reflex-0.6.5a1.dist-info}/entry_points.txt +0 -0
reflex/utils/exec.py
CHANGED
|
@@ -184,7 +184,7 @@ def should_use_granian():
|
|
|
184
184
|
Returns:
|
|
185
185
|
True if Granian should be used.
|
|
186
186
|
"""
|
|
187
|
-
return environment.REFLEX_USE_GRANIAN
|
|
187
|
+
return environment.REFLEX_USE_GRANIAN.get()
|
|
188
188
|
|
|
189
189
|
|
|
190
190
|
def get_app_module():
|
|
@@ -369,7 +369,9 @@ def run_uvicorn_backend_prod(host, port, loglevel):
|
|
|
369
369
|
command,
|
|
370
370
|
run=True,
|
|
371
371
|
show_logs=True,
|
|
372
|
-
env={
|
|
372
|
+
env={
|
|
373
|
+
environment.REFLEX_SKIP_COMPILE.name: "true"
|
|
374
|
+
}, # skip compile for prod backend
|
|
373
375
|
)
|
|
374
376
|
|
|
375
377
|
|
|
@@ -405,7 +407,7 @@ def run_granian_backend_prod(host, port, loglevel):
|
|
|
405
407
|
run=True,
|
|
406
408
|
show_logs=True,
|
|
407
409
|
env={
|
|
408
|
-
|
|
410
|
+
environment.REFLEX_SKIP_COMPILE.name: "true"
|
|
409
411
|
}, # skip compile for prod backend
|
|
410
412
|
)
|
|
411
413
|
except ImportError:
|
|
@@ -427,7 +429,7 @@ def output_system_info():
|
|
|
427
429
|
except Exception:
|
|
428
430
|
config_file = None
|
|
429
431
|
|
|
430
|
-
console.rule(
|
|
432
|
+
console.rule("System Info")
|
|
431
433
|
console.debug(f"Config file: {config_file!r}")
|
|
432
434
|
console.debug(f"Config: {config}")
|
|
433
435
|
|
|
@@ -467,9 +469,11 @@ def output_system_info():
|
|
|
467
469
|
console.debug(f"{dep}")
|
|
468
470
|
|
|
469
471
|
console.debug(
|
|
470
|
-
f"Using package installer at: {prerequisites.get_install_package_manager()}" # type: ignore
|
|
472
|
+
f"Using package installer at: {prerequisites.get_install_package_manager(on_failure_return_none=True)}" # type: ignore
|
|
471
473
|
)
|
|
472
|
-
console.debug(
|
|
474
|
+
console.debug(
|
|
475
|
+
f"Using package executer at: {prerequisites.get_package_manager(on_failure_return_none=True)}"
|
|
476
|
+
) # type: ignore
|
|
473
477
|
if system != "Windows":
|
|
474
478
|
console.debug(f"Unzip path: {path_ops.which('unzip')}")
|
|
475
479
|
|
|
@@ -489,11 +493,8 @@ def is_prod_mode() -> bool:
|
|
|
489
493
|
Returns:
|
|
490
494
|
True if the app is running in production mode or False if running in dev mode.
|
|
491
495
|
"""
|
|
492
|
-
current_mode =
|
|
493
|
-
|
|
494
|
-
constants.Env.DEV.value,
|
|
495
|
-
)
|
|
496
|
-
return current_mode == constants.Env.PROD.value
|
|
496
|
+
current_mode = environment.REFLEX_ENV_MODE.get()
|
|
497
|
+
return current_mode == constants.Env.PROD
|
|
497
498
|
|
|
498
499
|
|
|
499
500
|
def is_frontend_only() -> bool:
|
|
@@ -502,7 +503,13 @@ def is_frontend_only() -> bool:
|
|
|
502
503
|
Returns:
|
|
503
504
|
True if the app is running in frontend-only mode.
|
|
504
505
|
"""
|
|
505
|
-
|
|
506
|
+
console.deprecate(
|
|
507
|
+
"is_frontend_only() is deprecated and will be removed in a future release.",
|
|
508
|
+
reason="Use `environment.REFLEX_FRONTEND_ONLY.get()` instead.",
|
|
509
|
+
deprecation_version="0.6.5",
|
|
510
|
+
removal_version="0.7.0",
|
|
511
|
+
)
|
|
512
|
+
return environment.REFLEX_FRONTEND_ONLY.get()
|
|
506
513
|
|
|
507
514
|
|
|
508
515
|
def is_backend_only() -> bool:
|
|
@@ -511,7 +518,13 @@ def is_backend_only() -> bool:
|
|
|
511
518
|
Returns:
|
|
512
519
|
True if the app is running in backend-only mode.
|
|
513
520
|
"""
|
|
514
|
-
|
|
521
|
+
console.deprecate(
|
|
522
|
+
"is_backend_only() is deprecated and will be removed in a future release.",
|
|
523
|
+
reason="Use `environment.REFLEX_BACKEND_ONLY.get()` instead.",
|
|
524
|
+
deprecation_version="0.6.5",
|
|
525
|
+
removal_version="0.7.0",
|
|
526
|
+
)
|
|
527
|
+
return environment.REFLEX_BACKEND_ONLY.get()
|
|
515
528
|
|
|
516
529
|
|
|
517
530
|
def should_skip_compile() -> bool:
|
|
@@ -520,4 +533,10 @@ def should_skip_compile() -> bool:
|
|
|
520
533
|
Returns:
|
|
521
534
|
True if the app should skip compile.
|
|
522
535
|
"""
|
|
523
|
-
|
|
536
|
+
console.deprecate(
|
|
537
|
+
"should_skip_compile() is deprecated and will be removed in a future release.",
|
|
538
|
+
reason="Use `environment.REFLEX_SKIP_COMPILE.get()` instead.",
|
|
539
|
+
deprecation_version="0.6.5",
|
|
540
|
+
removal_version="0.7.0",
|
|
541
|
+
)
|
|
542
|
+
return environment.REFLEX_SKIP_COMPILE.get()
|
reflex/utils/format.py
CHANGED
|
@@ -6,15 +6,16 @@ import inspect
|
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
8
|
import re
|
|
9
|
-
from typing import TYPE_CHECKING, Any,
|
|
9
|
+
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
|
10
10
|
|
|
11
11
|
from reflex import constants
|
|
12
|
+
from reflex.constants.state import FRONTEND_EVENT_STATE
|
|
12
13
|
from reflex.utils import exceptions
|
|
13
14
|
from reflex.utils.console import deprecate
|
|
14
15
|
|
|
15
16
|
if TYPE_CHECKING:
|
|
16
17
|
from reflex.components.component import ComponentStyle
|
|
17
|
-
from reflex.event import ArgsSpec, EventChain, EventHandler, EventSpec
|
|
18
|
+
from reflex.event import ArgsSpec, EventChain, EventHandler, EventSpec, EventType
|
|
18
19
|
|
|
19
20
|
WRAP_MAP = {
|
|
20
21
|
"{": "}",
|
|
@@ -197,8 +198,16 @@ def make_default_page_title(app_name: str, route: str) -> str:
|
|
|
197
198
|
Returns:
|
|
198
199
|
The default page title.
|
|
199
200
|
"""
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
route_parts = [
|
|
202
|
+
part
|
|
203
|
+
for part in route.split("/")
|
|
204
|
+
if part and not (part.startswith("[") and part.endswith("]"))
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
title = constants.DefaultPage.TITLE.format(
|
|
208
|
+
app_name, route_parts[-1] if route_parts else constants.PageNames.INDEX_ROUTE
|
|
209
|
+
)
|
|
210
|
+
return to_title_case(title)
|
|
202
211
|
|
|
203
212
|
|
|
204
213
|
def _escape_js_string(string: str) -> str:
|
|
@@ -431,7 +440,7 @@ def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]:
|
|
|
431
440
|
|
|
432
441
|
from reflex.state import State
|
|
433
442
|
|
|
434
|
-
if state_full_name ==
|
|
443
|
+
if state_full_name == FRONTEND_EVENT_STATE and name not in State.__dict__:
|
|
435
444
|
return ("", to_snake_case(handler.fn.__qualname__))
|
|
436
445
|
|
|
437
446
|
return (state_full_name, name)
|
|
@@ -525,13 +534,7 @@ def format_event_chain(
|
|
|
525
534
|
|
|
526
535
|
|
|
527
536
|
def format_queue_events(
|
|
528
|
-
events:
|
|
529
|
-
EventSpec
|
|
530
|
-
| EventHandler
|
|
531
|
-
| Callable
|
|
532
|
-
| List[EventSpec | EventHandler | Callable]
|
|
533
|
-
| None
|
|
534
|
-
) = None,
|
|
537
|
+
events: EventType | None = None,
|
|
535
538
|
args_spec: Optional[ArgsSpec] = None,
|
|
536
539
|
) -> Var[EventChain]:
|
|
537
540
|
"""Format a list of event handler / event spec as a javascript callback.
|
reflex/utils/net.py
CHANGED
reflex/utils/path_ops.py
CHANGED
|
@@ -136,7 +136,7 @@ def use_system_node() -> bool:
|
|
|
136
136
|
Returns:
|
|
137
137
|
Whether the system node should be used.
|
|
138
138
|
"""
|
|
139
|
-
return environment.REFLEX_USE_SYSTEM_NODE
|
|
139
|
+
return environment.REFLEX_USE_SYSTEM_NODE.get()
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
def use_system_bun() -> bool:
|
|
@@ -145,7 +145,7 @@ def use_system_bun() -> bool:
|
|
|
145
145
|
Returns:
|
|
146
146
|
Whether the system bun should be used.
|
|
147
147
|
"""
|
|
148
|
-
return environment.REFLEX_USE_SYSTEM_BUN
|
|
148
|
+
return environment.REFLEX_USE_SYSTEM_BUN.get()
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
def get_node_bin_path() -> Path | None:
|
reflex/utils/prerequisites.py
CHANGED
|
@@ -35,7 +35,10 @@ from reflex import constants, model
|
|
|
35
35
|
from reflex.compiler import templates
|
|
36
36
|
from reflex.config import Config, environment, get_config
|
|
37
37
|
from reflex.utils import console, net, path_ops, processes
|
|
38
|
-
from reflex.utils.exceptions import
|
|
38
|
+
from reflex.utils.exceptions import (
|
|
39
|
+
GeneratedCodeHasNoFunctionDefs,
|
|
40
|
+
raise_system_package_missing_error,
|
|
41
|
+
)
|
|
39
42
|
from reflex.utils.format import format_library_name
|
|
40
43
|
from reflex.utils.registry import _get_npm_registry
|
|
41
44
|
|
|
@@ -69,7 +72,7 @@ def get_web_dir() -> Path:
|
|
|
69
72
|
Returns:
|
|
70
73
|
The working directory.
|
|
71
74
|
"""
|
|
72
|
-
return environment.REFLEX_WEB_WORKDIR
|
|
75
|
+
return environment.REFLEX_WEB_WORKDIR.get()
|
|
73
76
|
|
|
74
77
|
|
|
75
78
|
def _python_version_check():
|
|
@@ -204,10 +207,13 @@ def get_bun_version() -> version.Version | None:
|
|
|
204
207
|
return None
|
|
205
208
|
|
|
206
209
|
|
|
207
|
-
def get_install_package_manager() -> str | None:
|
|
210
|
+
def get_install_package_manager(on_failure_return_none: bool = False) -> str | None:
|
|
208
211
|
"""Get the package manager executable for installation.
|
|
209
212
|
Currently, bun is used for installation only.
|
|
210
213
|
|
|
214
|
+
Args:
|
|
215
|
+
on_failure_return_none: Whether to return None on failure.
|
|
216
|
+
|
|
211
217
|
Returns:
|
|
212
218
|
The path to the package manager.
|
|
213
219
|
"""
|
|
@@ -217,21 +223,29 @@ def get_install_package_manager() -> str | None:
|
|
|
217
223
|
or windows_check_onedrive_in_path()
|
|
218
224
|
or windows_npm_escape_hatch()
|
|
219
225
|
):
|
|
220
|
-
return get_package_manager()
|
|
226
|
+
return get_package_manager(on_failure_return_none)
|
|
221
227
|
return str(get_config().bun_path)
|
|
222
228
|
|
|
223
229
|
|
|
224
|
-
def get_package_manager() -> str | None:
|
|
230
|
+
def get_package_manager(on_failure_return_none: bool = False) -> str | None:
|
|
225
231
|
"""Get the package manager executable for running app.
|
|
226
232
|
Currently on unix systems, npm is used for running the app only.
|
|
227
233
|
|
|
234
|
+
Args:
|
|
235
|
+
on_failure_return_none: Whether to return None on failure.
|
|
236
|
+
|
|
228
237
|
Returns:
|
|
229
238
|
The path to the package manager.
|
|
239
|
+
|
|
240
|
+
Raises:
|
|
241
|
+
FileNotFoundError: If the package manager is not found.
|
|
230
242
|
"""
|
|
231
243
|
npm_path = path_ops.get_npm_path()
|
|
232
244
|
if npm_path is not None:
|
|
233
|
-
|
|
234
|
-
|
|
245
|
+
return str(Path(npm_path).resolve())
|
|
246
|
+
if on_failure_return_none:
|
|
247
|
+
return None
|
|
248
|
+
raise FileNotFoundError("NPM not found. You may need to run `reflex init`.")
|
|
235
249
|
|
|
236
250
|
|
|
237
251
|
def windows_check_onedrive_in_path() -> bool:
|
|
@@ -249,7 +263,7 @@ def windows_npm_escape_hatch() -> bool:
|
|
|
249
263
|
Returns:
|
|
250
264
|
If the user has set REFLEX_USE_NPM.
|
|
251
265
|
"""
|
|
252
|
-
return environment.REFLEX_USE_NPM
|
|
266
|
+
return environment.REFLEX_USE_NPM.get()
|
|
253
267
|
|
|
254
268
|
|
|
255
269
|
def get_app(reload: bool = False) -> ModuleType:
|
|
@@ -267,7 +281,7 @@ def get_app(reload: bool = False) -> ModuleType:
|
|
|
267
281
|
from reflex.utils import telemetry
|
|
268
282
|
|
|
269
283
|
try:
|
|
270
|
-
|
|
284
|
+
environment.RELOAD_CONFIG.set(reload)
|
|
271
285
|
config = get_config()
|
|
272
286
|
if not config.app_name:
|
|
273
287
|
raise RuntimeError(
|
|
@@ -430,7 +444,7 @@ def create_config(app_name: str):
|
|
|
430
444
|
|
|
431
445
|
def initialize_gitignore(
|
|
432
446
|
gitignore_file: Path = constants.GitIgnore.FILE,
|
|
433
|
-
files_to_ignore: set[str] = constants.GitIgnore.DEFAULTS,
|
|
447
|
+
files_to_ignore: set[str] | list[str] = constants.GitIgnore.DEFAULTS,
|
|
434
448
|
):
|
|
435
449
|
"""Initialize the template .gitignore file.
|
|
436
450
|
|
|
@@ -439,23 +453,20 @@ def initialize_gitignore(
|
|
|
439
453
|
files_to_ignore: The files to add to the .gitignore file.
|
|
440
454
|
"""
|
|
441
455
|
# Combine with the current ignored files.
|
|
442
|
-
current_ignore:
|
|
456
|
+
current_ignore: list[str] = []
|
|
443
457
|
if gitignore_file.exists():
|
|
444
|
-
current_ignore
|
|
445
|
-
line.strip() for line in gitignore_file.read_text().splitlines()
|
|
446
|
-
)
|
|
458
|
+
current_ignore = [ln.strip() for ln in gitignore_file.read_text().splitlines()]
|
|
447
459
|
|
|
448
460
|
if files_to_ignore == current_ignore:
|
|
449
461
|
console.debug(f"{gitignore_file} already up to date.")
|
|
450
462
|
return
|
|
451
|
-
files_to_ignore
|
|
463
|
+
files_to_ignore = [ln for ln in files_to_ignore if ln not in current_ignore]
|
|
464
|
+
files_to_ignore += current_ignore
|
|
452
465
|
|
|
453
466
|
# Write files to the .gitignore file.
|
|
454
467
|
gitignore_file.touch(exist_ok=True)
|
|
455
468
|
console.debug(f"Creating {gitignore_file}")
|
|
456
|
-
gitignore_file.write_text(
|
|
457
|
-
"\n".join(sorted(files_to_ignore)) + "\n",
|
|
458
|
-
)
|
|
469
|
+
gitignore_file.write_text("\n".join(files_to_ignore) + "\n")
|
|
459
470
|
|
|
460
471
|
|
|
461
472
|
def initialize_requirements_txt():
|
|
@@ -587,6 +598,8 @@ def initialize_web_directory():
|
|
|
587
598
|
|
|
588
599
|
initialize_package_json()
|
|
589
600
|
|
|
601
|
+
initialize_bun_config()
|
|
602
|
+
|
|
590
603
|
path_ops.mkdir(get_web_dir() / constants.Dirs.PUBLIC)
|
|
591
604
|
|
|
592
605
|
update_next_config()
|
|
@@ -611,17 +624,21 @@ def _compile_package_json():
|
|
|
611
624
|
def initialize_package_json():
|
|
612
625
|
"""Render and write in .web the package.json file."""
|
|
613
626
|
output_path = get_web_dir() / constants.PackageJson.PATH
|
|
614
|
-
|
|
615
|
-
|
|
627
|
+
output_path.write_text(_compile_package_json())
|
|
628
|
+
|
|
616
629
|
|
|
617
|
-
|
|
630
|
+
def initialize_bun_config():
|
|
631
|
+
"""Initialize the bun config file."""
|
|
618
632
|
bun_config_path = get_web_dir() / constants.Bun.CONFIG_PATH
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
633
|
+
|
|
634
|
+
if (custom_bunfig := Path(constants.Bun.CONFIG_PATH)).exists():
|
|
635
|
+
bunfig_content = custom_bunfig.read_text()
|
|
636
|
+
console.info(f"Copying custom bunfig.toml inside {get_web_dir()} folder")
|
|
637
|
+
else:
|
|
638
|
+
best_registry = _get_npm_registry()
|
|
639
|
+
bunfig_content = constants.Bun.DEFAULT_CONFIG.format(registry=best_registry)
|
|
640
|
+
|
|
641
|
+
bun_config_path.write_text(bunfig_content)
|
|
625
642
|
|
|
626
643
|
|
|
627
644
|
def init_reflex_json(project_hash: int | None):
|
|
@@ -677,6 +694,7 @@ def _update_next_config(
|
|
|
677
694
|
"compress": config.next_compression,
|
|
678
695
|
"reactStrictMode": config.react_strict_mode,
|
|
679
696
|
"trailingSlash": True,
|
|
697
|
+
"staticPageGenerationTimeout": config.static_page_generation_timeout,
|
|
680
698
|
}
|
|
681
699
|
if transpile_packages:
|
|
682
700
|
next_config["transpilePackages"] = list(
|
|
@@ -811,11 +829,7 @@ def install_node():
|
|
|
811
829
|
|
|
812
830
|
|
|
813
831
|
def install_bun():
|
|
814
|
-
"""Install bun onto the user's system.
|
|
815
|
-
|
|
816
|
-
Raises:
|
|
817
|
-
FileNotFoundError: If required packages are not found.
|
|
818
|
-
"""
|
|
832
|
+
"""Install bun onto the user's system."""
|
|
819
833
|
win_supported = is_windows_bun_supported()
|
|
820
834
|
one_drive_in_path = windows_check_onedrive_in_path()
|
|
821
835
|
if constants.IS_WINDOWS and not win_supported or one_drive_in_path:
|
|
@@ -854,7 +868,7 @@ def install_bun():
|
|
|
854
868
|
else:
|
|
855
869
|
unzip_path = path_ops.which("unzip")
|
|
856
870
|
if unzip_path is None:
|
|
857
|
-
|
|
871
|
+
raise_system_package_missing_error("unzip")
|
|
858
872
|
|
|
859
873
|
# Run the bun install script.
|
|
860
874
|
download_and_run(
|
|
@@ -919,20 +933,39 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
919
933
|
packages: A list of package names to be installed.
|
|
920
934
|
config: The config object.
|
|
921
935
|
|
|
936
|
+
Raises:
|
|
937
|
+
FileNotFoundError: If the package manager is not found.
|
|
938
|
+
|
|
922
939
|
Example:
|
|
923
940
|
>>> install_frontend_packages(["react", "react-dom"], get_config())
|
|
924
941
|
"""
|
|
925
942
|
# unsupported archs(arm and 32bit machines) will use npm anyway. so we dont have to run npm twice
|
|
926
943
|
fallback_command = (
|
|
927
|
-
get_package_manager()
|
|
928
|
-
if
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
944
|
+
get_package_manager(on_failure_return_none=True)
|
|
945
|
+
if (
|
|
946
|
+
not constants.IS_WINDOWS
|
|
947
|
+
or constants.IS_WINDOWS
|
|
948
|
+
and is_windows_bun_supported()
|
|
949
|
+
and not windows_check_onedrive_in_path()
|
|
950
|
+
)
|
|
932
951
|
else None
|
|
933
952
|
)
|
|
953
|
+
|
|
954
|
+
install_package_manager = (
|
|
955
|
+
get_install_package_manager(on_failure_return_none=True) or fallback_command
|
|
956
|
+
)
|
|
957
|
+
|
|
958
|
+
if install_package_manager is None:
|
|
959
|
+
raise FileNotFoundError(
|
|
960
|
+
"Could not find a package manager to install frontend packages. You may need to run `reflex init`."
|
|
961
|
+
)
|
|
962
|
+
|
|
963
|
+
fallback_command = (
|
|
964
|
+
fallback_command if fallback_command is not install_package_manager else None
|
|
965
|
+
)
|
|
966
|
+
|
|
934
967
|
processes.run_process_with_fallback(
|
|
935
|
-
[
|
|
968
|
+
[install_package_manager, "install"], # type: ignore
|
|
936
969
|
fallback=fallback_command,
|
|
937
970
|
analytics_enabled=True,
|
|
938
971
|
show_status_message="Installing base frontend packages",
|
|
@@ -943,7 +976,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
943
976
|
if config.tailwind is not None:
|
|
944
977
|
processes.run_process_with_fallback(
|
|
945
978
|
[
|
|
946
|
-
|
|
979
|
+
install_package_manager,
|
|
947
980
|
"add",
|
|
948
981
|
"-d",
|
|
949
982
|
constants.Tailwind.VERSION,
|
|
@@ -959,7 +992,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
959
992
|
# Install custom packages defined in frontend_packages
|
|
960
993
|
if len(packages) > 0:
|
|
961
994
|
processes.run_process_with_fallback(
|
|
962
|
-
[
|
|
995
|
+
[install_package_manager, "add", *packages],
|
|
963
996
|
fallback=fallback_command,
|
|
964
997
|
analytics_enabled=True,
|
|
965
998
|
show_status_message="Installing frontend packages from config and components",
|
|
@@ -991,7 +1024,7 @@ def needs_reinit(frontend: bool = True) -> bool:
|
|
|
991
1024
|
return False
|
|
992
1025
|
|
|
993
1026
|
# Make sure the .reflex directory exists.
|
|
994
|
-
if not environment.REFLEX_DIR.exists():
|
|
1027
|
+
if not environment.REFLEX_DIR.get().exists():
|
|
995
1028
|
return True
|
|
996
1029
|
|
|
997
1030
|
# Make sure the .web directory exists in frontend mode.
|
|
@@ -1096,7 +1129,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
|
|
|
1096
1129
|
"""
|
|
1097
1130
|
try:
|
|
1098
1131
|
initialize_reflex_user_directory()
|
|
1099
|
-
installation_id_file = environment.REFLEX_DIR / "installation_id"
|
|
1132
|
+
installation_id_file = environment.REFLEX_DIR.get() / "installation_id"
|
|
1100
1133
|
|
|
1101
1134
|
installation_id = None
|
|
1102
1135
|
if installation_id_file.exists():
|
|
@@ -1121,7 +1154,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
|
|
|
1121
1154
|
def initialize_reflex_user_directory():
|
|
1122
1155
|
"""Initialize the reflex user directory."""
|
|
1123
1156
|
# Create the reflex directory.
|
|
1124
|
-
path_ops.mkdir(environment.REFLEX_DIR)
|
|
1157
|
+
path_ops.mkdir(environment.REFLEX_DIR.get())
|
|
1125
1158
|
|
|
1126
1159
|
|
|
1127
1160
|
def initialize_frontend_dependencies():
|
|
@@ -1144,7 +1177,10 @@ def check_db_initialized() -> bool:
|
|
|
1144
1177
|
Returns:
|
|
1145
1178
|
True if alembic is initialized (or if database is not used).
|
|
1146
1179
|
"""
|
|
1147
|
-
if
|
|
1180
|
+
if (
|
|
1181
|
+
get_config().db_url is not None
|
|
1182
|
+
and not environment.ALEMBIC_CONFIG.get().exists()
|
|
1183
|
+
):
|
|
1148
1184
|
console.error(
|
|
1149
1185
|
"Database is not initialized. Run [bold]reflex db init[/bold] first."
|
|
1150
1186
|
)
|
|
@@ -1154,7 +1190,7 @@ def check_db_initialized() -> bool:
|
|
|
1154
1190
|
|
|
1155
1191
|
def check_schema_up_to_date():
|
|
1156
1192
|
"""Check if the sqlmodel metadata matches the current database schema."""
|
|
1157
|
-
if get_config().db_url is None or not environment.ALEMBIC_CONFIG.exists():
|
|
1193
|
+
if get_config().db_url is None or not environment.ALEMBIC_CONFIG.get().exists():
|
|
1158
1194
|
return
|
|
1159
1195
|
with model.Model.get_db_engine().connect() as connection:
|
|
1160
1196
|
try:
|
reflex/utils/pyi_generator.py
CHANGED
|
@@ -16,7 +16,7 @@ from itertools import chain
|
|
|
16
16
|
from multiprocessing import Pool, cpu_count
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from types import ModuleType, SimpleNamespace
|
|
19
|
-
from typing import Any, Callable, Iterable, Type, get_args, get_origin
|
|
19
|
+
from typing import Any, Callable, Iterable, Sequence, Type, get_args, get_origin
|
|
20
20
|
|
|
21
21
|
from reflex.components.component import Component
|
|
22
22
|
from reflex.utils import types as rx_types
|
|
@@ -70,7 +70,14 @@ DEFAULT_TYPING_IMPORTS = {
|
|
|
70
70
|
DEFAULT_IMPORTS = {
|
|
71
71
|
"typing": sorted(DEFAULT_TYPING_IMPORTS),
|
|
72
72
|
"reflex.components.core.breakpoints": ["Breakpoints"],
|
|
73
|
-
"reflex.event": [
|
|
73
|
+
"reflex.event": [
|
|
74
|
+
"EventChain",
|
|
75
|
+
"EventHandler",
|
|
76
|
+
"EventSpec",
|
|
77
|
+
"EventType",
|
|
78
|
+
"BASE_STATE",
|
|
79
|
+
"KeyInputInfo",
|
|
80
|
+
],
|
|
74
81
|
"reflex.style": ["Style"],
|
|
75
82
|
"reflex.vars.base": ["Var"],
|
|
76
83
|
}
|
|
@@ -490,7 +497,7 @@ def _generate_component_create_functiondef(
|
|
|
490
497
|
|
|
491
498
|
def figure_out_return_type(annotation: Any):
|
|
492
499
|
if inspect.isclass(annotation) and issubclass(annotation, inspect._empty):
|
|
493
|
-
return ast.Name(id="
|
|
500
|
+
return ast.Name(id="EventType[..., BASE_STATE]")
|
|
494
501
|
|
|
495
502
|
if not isinstance(annotation, str) and get_origin(annotation) is tuple:
|
|
496
503
|
arguments = get_args(annotation)
|
|
@@ -503,26 +510,24 @@ def _generate_component_create_functiondef(
|
|
|
503
510
|
# Convert each argument type to its AST representation
|
|
504
511
|
type_args = [type_to_ast(arg, cls=clz) for arg in arguments_without_var]
|
|
505
512
|
|
|
506
|
-
#
|
|
507
|
-
|
|
513
|
+
# Get all prefixes of the type arguments
|
|
514
|
+
all_count_args_type = [
|
|
515
|
+
ast.Name(
|
|
516
|
+
f"EventType[[{', '.join([ast.unparse(arg) for arg in type_args[:i]])}], BASE_STATE]"
|
|
517
|
+
)
|
|
518
|
+
for i in range(len(type_args) + 1)
|
|
519
|
+
]
|
|
508
520
|
|
|
509
521
|
# Create EventType using the joined string
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
# Wrap in Optional
|
|
513
|
-
optional_type = ast.Subscript(
|
|
514
|
-
value=ast.Name(id="Optional"),
|
|
515
|
-
slice=ast.Index(value=event_type),
|
|
516
|
-
ctx=ast.Load(),
|
|
522
|
+
return ast.Name(
|
|
523
|
+
id=f"Union[{', '.join(map(ast.unparse, all_count_args_type))}]"
|
|
517
524
|
)
|
|
518
525
|
|
|
519
|
-
return ast.Name(id=ast.unparse(optional_type))
|
|
520
|
-
|
|
521
526
|
if isinstance(annotation, str) and annotation.startswith("Tuple["):
|
|
522
527
|
inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]")
|
|
523
528
|
|
|
524
529
|
if inside_of_tuple == "()":
|
|
525
|
-
return ast.Name(id="
|
|
530
|
+
return ast.Name(id="EventType[[], BASE_STATE]")
|
|
526
531
|
|
|
527
532
|
arguments = [""]
|
|
528
533
|
|
|
@@ -548,10 +553,17 @@ def _generate_component_create_functiondef(
|
|
|
548
553
|
for argument in arguments
|
|
549
554
|
]
|
|
550
555
|
|
|
556
|
+
all_count_args_type = [
|
|
557
|
+
ast.Name(
|
|
558
|
+
f"EventType[[{', '.join(arguments_without_var[:i])}], BASE_STATE]"
|
|
559
|
+
)
|
|
560
|
+
for i in range(len(arguments) + 1)
|
|
561
|
+
]
|
|
562
|
+
|
|
551
563
|
return ast.Name(
|
|
552
|
-
id=f"
|
|
564
|
+
id=f"Union[{', '.join(map(ast.unparse, all_count_args_type))}]"
|
|
553
565
|
)
|
|
554
|
-
return ast.Name(id="
|
|
566
|
+
return ast.Name(id="EventType[..., BASE_STATE]")
|
|
555
567
|
|
|
556
568
|
event_triggers = clz().get_event_triggers()
|
|
557
569
|
|
|
@@ -560,14 +572,40 @@ def _generate_component_create_functiondef(
|
|
|
560
572
|
(
|
|
561
573
|
ast.arg(
|
|
562
574
|
arg=trigger,
|
|
563
|
-
annotation=
|
|
564
|
-
|
|
575
|
+
annotation=ast.Subscript(
|
|
576
|
+
ast.Name("Optional"),
|
|
577
|
+
ast.Index( # type: ignore
|
|
578
|
+
value=ast.Name(
|
|
579
|
+
id=ast.unparse(
|
|
580
|
+
figure_out_return_type(
|
|
581
|
+
inspect.signature(event_specs).return_annotation
|
|
582
|
+
)
|
|
583
|
+
if not isinstance(
|
|
584
|
+
event_specs := event_triggers[trigger], Sequence
|
|
585
|
+
)
|
|
586
|
+
else ast.Subscript(
|
|
587
|
+
ast.Name("Union"),
|
|
588
|
+
ast.Tuple(
|
|
589
|
+
[
|
|
590
|
+
figure_out_return_type(
|
|
591
|
+
inspect.signature(
|
|
592
|
+
event_spec
|
|
593
|
+
).return_annotation
|
|
594
|
+
)
|
|
595
|
+
for event_spec in event_specs
|
|
596
|
+
]
|
|
597
|
+
),
|
|
598
|
+
)
|
|
599
|
+
)
|
|
600
|
+
)
|
|
601
|
+
),
|
|
565
602
|
),
|
|
566
603
|
),
|
|
567
604
|
ast.Constant(value=None),
|
|
568
605
|
)
|
|
569
606
|
for trigger in sorted(event_triggers)
|
|
570
607
|
)
|
|
608
|
+
|
|
571
609
|
logger.debug(f"Generated {clz.__name__}.create method with {len(kwargs)} kwargs")
|
|
572
610
|
create_args = ast.arguments(
|
|
573
611
|
args=[ast.arg(arg="cls")],
|
|
@@ -578,12 +616,17 @@ def _generate_component_create_functiondef(
|
|
|
578
616
|
kwarg=ast.arg(arg="props"),
|
|
579
617
|
defaults=[],
|
|
580
618
|
)
|
|
619
|
+
|
|
581
620
|
definition = ast.FunctionDef(
|
|
582
621
|
name="create",
|
|
583
622
|
args=create_args,
|
|
584
623
|
body=[
|
|
585
624
|
ast.Expr(
|
|
586
|
-
value=ast.Constant(
|
|
625
|
+
value=ast.Constant(
|
|
626
|
+
value=_generate_docstrings(
|
|
627
|
+
all_classes, [*all_props, *event_triggers]
|
|
628
|
+
)
|
|
629
|
+
),
|
|
587
630
|
),
|
|
588
631
|
ast.Expr(
|
|
589
632
|
value=ast.Ellipsis(),
|
reflex/utils/registry.py
CHANGED