reflex 0.7.4a0__py3-none-any.whl → 0.7.4a2__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/web/components/reflex/radix_themes_color_mode_provider.js +9 -1
- reflex/app.py +20 -2
- reflex/base.py +3 -3
- reflex/compiler/compiler.py +7 -4
- reflex/components/component.py +6 -3
- reflex/components/core/client_side_routing.py +3 -3
- reflex/components/core/cond.py +20 -12
- reflex/components/dynamic.py +2 -4
- reflex/components/lucide/icon.py +20 -27
- reflex/config.py +18 -18
- reflex/custom_components/custom_components.py +8 -3
- reflex/reflex.py +22 -4
- reflex/state.py +1 -0
- reflex/utils/exec.py +146 -64
- reflex/utils/prerequisites.py +93 -3
- reflex/utils/processes.py +51 -19
- reflex/vars/base.py +2 -38
- reflex/vars/datetime.py +10 -34
- reflex/vars/number.py +16 -112
- reflex/vars/sequence.py +99 -108
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a2.dist-info}/METADATA +4 -2
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a2.dist-info}/RECORD +25 -26
- reflex/app_module_for_backend.py +0 -33
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a2.dist-info}/WHEEL +0 -0
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a2.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useTheme } from "next-themes";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
2
|
+
import { useRef, useEffect, useState } from "react";
|
|
3
3
|
import {
|
|
4
4
|
ColorModeContext,
|
|
5
5
|
defaultColorMode,
|
|
@@ -13,6 +13,14 @@ export default function RadixThemesColorModeProvider({ children }) {
|
|
|
13
13
|
const [resolvedColorMode, setResolvedColorMode] = useState(
|
|
14
14
|
defaultColorMode === "dark" ? "dark" : "light",
|
|
15
15
|
);
|
|
16
|
+
const firstUpdate = useRef(true);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (firstUpdate.current) {
|
|
19
|
+
firstUpdate.current = false;
|
|
20
|
+
setRawColorMode(theme);
|
|
21
|
+
setResolvedColorMode(resolvedTheme);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
16
24
|
|
|
17
25
|
useEffect(() => {
|
|
18
26
|
if (isDevMode) {
|
reflex/app.py
CHANGED
|
@@ -576,6 +576,22 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
576
576
|
"""
|
|
577
577
|
if not self.api:
|
|
578
578
|
raise ValueError("The app has not been initialized.")
|
|
579
|
+
|
|
580
|
+
# For py3.9 compatibility when redis is used, we MUST add any decorator pages
|
|
581
|
+
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
|
582
|
+
self._apply_decorated_pages()
|
|
583
|
+
|
|
584
|
+
compile_future = concurrent.futures.ThreadPoolExecutor(max_workers=1).submit(
|
|
585
|
+
self._compile
|
|
586
|
+
)
|
|
587
|
+
compile_future.add_done_callback(
|
|
588
|
+
# Force background compile errors to print eagerly
|
|
589
|
+
lambda f: f.result()
|
|
590
|
+
)
|
|
591
|
+
# Wait for the compile to finish in prod mode to ensure all optional endpoints are mounted.
|
|
592
|
+
if is_prod_mode():
|
|
593
|
+
compile_future.result()
|
|
594
|
+
|
|
579
595
|
return self.api
|
|
580
596
|
|
|
581
597
|
def _add_default_endpoints(self):
|
|
@@ -952,7 +968,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
952
968
|
# Check the nocompile file.
|
|
953
969
|
if nocompile.exists():
|
|
954
970
|
# Delete the nocompile file
|
|
955
|
-
nocompile.unlink()
|
|
971
|
+
nocompile.unlink(missing_ok=True)
|
|
956
972
|
return False
|
|
957
973
|
|
|
958
974
|
# By default, compile the app.
|
|
@@ -1242,7 +1258,9 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
1242
1258
|
compiler.compile_document_root(
|
|
1243
1259
|
self.head_components,
|
|
1244
1260
|
html_lang=self.html_lang,
|
|
1245
|
-
html_custom_attrs=
|
|
1261
|
+
html_custom_attrs=(
|
|
1262
|
+
{**self.html_custom_attrs} if self.html_custom_attrs else {}
|
|
1263
|
+
),
|
|
1246
1264
|
)
|
|
1247
1265
|
)
|
|
1248
1266
|
|
reflex/base.py
CHANGED
|
@@ -38,7 +38,7 @@ def validate_field_name(bases: list[Type["BaseModel"]], field_name: str) -> None
|
|
|
38
38
|
|
|
39
39
|
# monkeypatch pydantic validate_field_name method to skip validating
|
|
40
40
|
# shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
|
|
41
|
-
pydantic_main.validate_field_name = validate_field_name # pyright: ignore [
|
|
41
|
+
pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPrivateImportUsage]
|
|
42
42
|
|
|
43
43
|
if TYPE_CHECKING:
|
|
44
44
|
from reflex.vars import Var
|
|
@@ -107,7 +107,7 @@ class Base(BaseModel):
|
|
|
107
107
|
default_value: The default value of the field
|
|
108
108
|
"""
|
|
109
109
|
var_name = var._var_field_name
|
|
110
|
-
new_field = ModelField.infer(
|
|
110
|
+
new_field = ModelField.infer(
|
|
111
111
|
name=var_name,
|
|
112
112
|
value=default_value,
|
|
113
113
|
annotation=var._var_type,
|
|
@@ -128,5 +128,5 @@ class Base(BaseModel):
|
|
|
128
128
|
if isinstance(key, str):
|
|
129
129
|
# Seems like this function signature was wrong all along?
|
|
130
130
|
# If the user wants a field that we know of, get it and pass it off to _get_value
|
|
131
|
-
return getattr(self, key
|
|
131
|
+
return getattr(self, key)
|
|
132
132
|
return key
|
reflex/compiler/compiler.py
CHANGED
|
@@ -20,6 +20,7 @@ from reflex.config import environment, get_config
|
|
|
20
20
|
from reflex.state import BaseState
|
|
21
21
|
from reflex.style import SYSTEM_COLOR_MODE
|
|
22
22
|
from reflex.utils import console, path_ops
|
|
23
|
+
from reflex.utils.exceptions import ReflexError
|
|
23
24
|
from reflex.utils.exec import is_prod_mode
|
|
24
25
|
from reflex.utils.imports import ImportVar
|
|
25
26
|
from reflex.utils.prerequisites import get_web_dir
|
|
@@ -368,13 +369,11 @@ def _compile_stateful_components(
|
|
|
368
369
|
|
|
369
370
|
# Include dynamic imports in the shared component.
|
|
370
371
|
if dynamic_imports := component._get_all_dynamic_imports():
|
|
371
|
-
rendered_components.update(
|
|
372
|
-
{dynamic_import: None for dynamic_import in dynamic_imports}
|
|
373
|
-
)
|
|
372
|
+
rendered_components.update(dict.fromkeys(dynamic_imports))
|
|
374
373
|
|
|
375
374
|
# Include custom code in the shared component.
|
|
376
375
|
rendered_components.update(
|
|
377
|
-
|
|
376
|
+
dict.fromkeys(component._get_all_custom_code()),
|
|
378
377
|
)
|
|
379
378
|
|
|
380
379
|
# Include all imports in the shared component.
|
|
@@ -653,6 +652,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
|
|
|
653
652
|
):
|
|
654
653
|
return converted
|
|
655
654
|
except KeyError as e:
|
|
655
|
+
if isinstance(e, ReflexError):
|
|
656
|
+
raise
|
|
656
657
|
key = e.args[0] if e.args else None
|
|
657
658
|
if key is not None and isinstance(key, Var):
|
|
658
659
|
raise TypeError(
|
|
@@ -660,6 +661,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
|
|
|
660
661
|
).with_traceback(e.__traceback__) from None
|
|
661
662
|
raise
|
|
662
663
|
except TypeError as e:
|
|
664
|
+
if isinstance(e, ReflexError):
|
|
665
|
+
raise
|
|
663
666
|
message = e.args[0] if e.args else None
|
|
664
667
|
if message and isinstance(message, str):
|
|
665
668
|
if message.endswith("has no len()") and (
|
reflex/components/component.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import contextlib
|
|
5
6
|
import copy
|
|
6
7
|
import dataclasses
|
|
7
8
|
import functools
|
|
@@ -1974,13 +1975,15 @@ class NoSSRComponent(Component):
|
|
|
1974
1975
|
# Do NOT import the main library/tag statically.
|
|
1975
1976
|
import_name = self._get_import_name()
|
|
1976
1977
|
if import_name is not None:
|
|
1977
|
-
|
|
1978
|
+
with contextlib.suppress(ValueError):
|
|
1979
|
+
_imports[import_name].remove(self.import_var)
|
|
1980
|
+
_imports[import_name].append(
|
|
1978
1981
|
imports.ImportVar(
|
|
1979
1982
|
tag=None,
|
|
1980
1983
|
render=False,
|
|
1981
1984
|
transpile=self._should_transpile(self.library),
|
|
1982
|
-
)
|
|
1983
|
-
|
|
1985
|
+
)
|
|
1986
|
+
)
|
|
1984
1987
|
|
|
1985
1988
|
return imports.merge_imports(
|
|
1986
1989
|
dynamic_import,
|
|
@@ -53,9 +53,9 @@ def wait_for_client_redirect(component: Component) -> Component:
|
|
|
53
53
|
The conditionally rendered component.
|
|
54
54
|
"""
|
|
55
55
|
return cond(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
route_not_found,
|
|
57
|
+
component,
|
|
58
|
+
ClientSideRouting.create(),
|
|
59
59
|
)
|
|
60
60
|
|
|
61
61
|
|
reflex/components/core/cond.py
CHANGED
|
@@ -31,7 +31,7 @@ class Cond(MemoizationLeaf):
|
|
|
31
31
|
cls,
|
|
32
32
|
cond: Var,
|
|
33
33
|
comp1: BaseComponent,
|
|
34
|
-
comp2: BaseComponent |
|
|
34
|
+
comp2: BaseComponent | types.Unset = types.Unset(),
|
|
35
35
|
) -> Component:
|
|
36
36
|
"""Create a conditional component.
|
|
37
37
|
|
|
@@ -44,10 +44,14 @@ class Cond(MemoizationLeaf):
|
|
|
44
44
|
The conditional component.
|
|
45
45
|
"""
|
|
46
46
|
# Wrap everything in fragments.
|
|
47
|
-
if type(comp1)
|
|
47
|
+
if type(comp1) is not Fragment:
|
|
48
48
|
comp1 = Fragment.create(comp1)
|
|
49
|
-
if comp2
|
|
50
|
-
comp2 =
|
|
49
|
+
if isinstance(comp2, types.Unset) or type(comp2) is not Fragment:
|
|
50
|
+
comp2 = (
|
|
51
|
+
Fragment.create(comp2)
|
|
52
|
+
if not isinstance(comp2, types.Unset)
|
|
53
|
+
else Fragment.create()
|
|
54
|
+
)
|
|
51
55
|
return Fragment.create(
|
|
52
56
|
cls._create(
|
|
53
57
|
children=[comp1, comp2],
|
|
@@ -96,18 +100,22 @@ class Cond(MemoizationLeaf):
|
|
|
96
100
|
|
|
97
101
|
|
|
98
102
|
@overload
|
|
99
|
-
def cond(condition: Any, c1: Component, c2: Any) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
103
|
+
def cond(condition: Any, c1: Component, c2: Any, /) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@overload
|
|
107
|
+
def cond(condition: Any, c1: Component, /) -> Component: ...
|
|
100
108
|
|
|
101
109
|
|
|
102
110
|
@overload
|
|
103
|
-
def cond(condition: Any, c1: Component) -> Component: ...
|
|
111
|
+
def cond(condition: Any, c1: Any, c2: Component, /) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
104
112
|
|
|
105
113
|
|
|
106
114
|
@overload
|
|
107
|
-
def cond(condition: Any, c1: Any, c2: Any) -> Var: ...
|
|
115
|
+
def cond(condition: Any, c1: Any, c2: Any, /) -> Var: ...
|
|
108
116
|
|
|
109
117
|
|
|
110
|
-
def cond(condition: Any, c1: Any, c2: Any =
|
|
118
|
+
def cond(condition: Any, c1: Any, c2: Any = types.Unset(), /) -> Component | Var:
|
|
111
119
|
"""Create a conditional component or Prop.
|
|
112
120
|
|
|
113
121
|
Args:
|
|
@@ -128,15 +136,15 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
|
|
|
128
136
|
|
|
129
137
|
# If the first component is a component, create a Cond component.
|
|
130
138
|
if isinstance(c1, BaseComponent):
|
|
131
|
-
if c2
|
|
132
|
-
|
|
139
|
+
if not isinstance(c2, types.Unset) and not isinstance(c2, BaseComponent):
|
|
140
|
+
return Cond.create(cond_var.bool(), c1, Fragment.create(c2))
|
|
133
141
|
return Cond.create(cond_var.bool(), c1, c2)
|
|
134
142
|
|
|
135
143
|
# Otherwise, create a conditional Var.
|
|
136
144
|
# Check that the second argument is valid.
|
|
137
145
|
if isinstance(c2, BaseComponent):
|
|
138
|
-
|
|
139
|
-
if c2
|
|
146
|
+
return Cond.create(cond_var.bool(), Fragment.create(c1), c2)
|
|
147
|
+
if isinstance(c2, types.Unset):
|
|
140
148
|
raise ValueError("For conditional vars, the second argument must be set.")
|
|
141
149
|
|
|
142
150
|
# convert the truth and false cond parts into vars so the _var_data can be obtained.
|
reflex/components/dynamic.py
CHANGED
|
@@ -72,13 +72,11 @@ def load_dynamic_serializer():
|
|
|
72
72
|
rendered_components = {}
|
|
73
73
|
# Include dynamic imports in the shared component.
|
|
74
74
|
if dynamic_imports := component._get_all_dynamic_imports():
|
|
75
|
-
rendered_components.update(
|
|
76
|
-
{dynamic_import: None for dynamic_import in dynamic_imports}
|
|
77
|
-
)
|
|
75
|
+
rendered_components.update(dict.fromkeys(dynamic_imports))
|
|
78
76
|
|
|
79
77
|
# Include custom code in the shared component.
|
|
80
78
|
rendered_components.update(
|
|
81
|
-
|
|
79
|
+
dict.fromkeys(component._get_all_custom_code()),
|
|
82
80
|
)
|
|
83
81
|
|
|
84
82
|
rendered_components[
|
reflex/components/lucide/icon.py
CHANGED
|
@@ -53,42 +53,35 @@ class Icon(LucideIconComponent):
|
|
|
53
53
|
if "tag" not in props:
|
|
54
54
|
raise AttributeError("Missing 'tag' keyword-argument for Icon")
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
if isinstance(
|
|
58
|
-
if isinstance(
|
|
59
|
-
tag =
|
|
56
|
+
tag_var: Var | LiteralVar = Var.create(props.pop("tag"))
|
|
57
|
+
if isinstance(tag_var, LiteralVar):
|
|
58
|
+
if isinstance(tag_var, LiteralStringVar):
|
|
59
|
+
tag = format.to_snake_case(tag_var._var_value.lower())
|
|
60
60
|
else:
|
|
61
|
-
raise TypeError(f"Icon name must be a string, got {type(
|
|
62
|
-
elif isinstance(
|
|
63
|
-
tag_stringified =
|
|
61
|
+
raise TypeError(f"Icon name must be a string, got {type(tag_var)}")
|
|
62
|
+
elif isinstance(tag_var, Var):
|
|
63
|
+
tag_stringified = tag_var.guess_type()
|
|
64
64
|
if not isinstance(tag_stringified, StringVar):
|
|
65
|
-
raise TypeError(f"Icon name must be a string, got {
|
|
65
|
+
raise TypeError(f"Icon name must be a string, got {tag_var._var_type}")
|
|
66
66
|
return DynamicIcon.create(name=tag_stringified.replace("_", "-"), **props)
|
|
67
67
|
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
tag, s
|
|
77
|
-
),
|
|
78
|
-
reverse=True,
|
|
79
|
-
)
|
|
80
|
-
else:
|
|
81
|
-
icons_sorted = LUCIDE_ICON_LIST
|
|
68
|
+
if tag not in LUCIDE_ICON_LIST:
|
|
69
|
+
icons_sorted = sorted(
|
|
70
|
+
LUCIDE_ICON_LIST,
|
|
71
|
+
key=lambda s, tag=tag: format.length_of_largest_common_substring(
|
|
72
|
+
tag, s
|
|
73
|
+
),
|
|
74
|
+
reverse=True,
|
|
75
|
+
)
|
|
82
76
|
console.warn(
|
|
83
77
|
f"Invalid icon tag: {tag}. Please use one of the following: {', '.join(icons_sorted[0:10])}, ..."
|
|
84
78
|
"\nSee full list at https://reflex.dev/docs/library/data-display/icon/#icons-list. Using 'circle-help' icon instead."
|
|
85
79
|
)
|
|
86
|
-
tag = "
|
|
80
|
+
tag = "circle_help"
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
props["tag"] = format.to_title_case(format.to_snake_case(tag)) + "Icon"
|
|
82
|
+
props["tag"] = LUCIDE_ICON_MAPPING_OVERRIDE.get(
|
|
83
|
+
tag, format.to_title_case(tag) + "Icon"
|
|
84
|
+
)
|
|
92
85
|
props["alias"] = f"Lucide{props['tag']}"
|
|
93
86
|
props.setdefault("color", "var(--current-color)")
|
|
94
87
|
return super().create(**props)
|
reflex/config.py
CHANGED
|
@@ -30,7 +30,6 @@ from typing import (
|
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
import pydantic.v1 as pydantic
|
|
33
|
-
from reflex_cli.constants.hosting import Hosting
|
|
34
33
|
|
|
35
34
|
from reflex import constants
|
|
36
35
|
from reflex.base import Base
|
|
@@ -45,7 +44,7 @@ from reflex.utils.types import (
|
|
|
45
44
|
)
|
|
46
45
|
|
|
47
46
|
try:
|
|
48
|
-
from dotenv import load_dotenv
|
|
47
|
+
from dotenv import load_dotenv
|
|
49
48
|
except ImportError:
|
|
50
49
|
load_dotenv = None
|
|
51
50
|
|
|
@@ -602,7 +601,7 @@ class EnvironmentVariables:
|
|
|
602
601
|
# The npm registry to use.
|
|
603
602
|
NPM_CONFIG_REGISTRY: EnvVar[str | None] = env_var(None)
|
|
604
603
|
|
|
605
|
-
# Whether to use Granian for the backend.
|
|
604
|
+
# Whether to use Granian for the backend. By default, the backend uses Uvicorn if available.
|
|
606
605
|
REFLEX_USE_GRANIAN: EnvVar[bool] = env_var(False)
|
|
607
606
|
|
|
608
607
|
# The username to use for authentication on python package repository. Username and password must both be provided.
|
|
@@ -807,8 +806,8 @@ class Config(Base):
|
|
|
807
806
|
# Tailwind config.
|
|
808
807
|
tailwind: dict[str, Any] | None = {"plugins": ["@tailwindcss/typography"]}
|
|
809
808
|
|
|
810
|
-
# Timeout when launching the gunicorn server.
|
|
811
|
-
timeout: int =
|
|
809
|
+
# DEPRECATED. Timeout when launching the gunicorn server.
|
|
810
|
+
timeout: int | None = None
|
|
812
811
|
|
|
813
812
|
# Whether to enable or disable nextJS gzip compression.
|
|
814
813
|
next_compression: bool = True
|
|
@@ -819,22 +818,17 @@ class Config(Base):
|
|
|
819
818
|
# Additional frontend packages to install.
|
|
820
819
|
frontend_packages: list[str] = []
|
|
821
820
|
|
|
822
|
-
# The
|
|
823
|
-
cp_backend_url: str = Hosting.HOSTING_SERVICE
|
|
824
|
-
# The hosting service frontend URL.
|
|
825
|
-
cp_web_url: str = Hosting.HOSTING_SERVICE_UI
|
|
826
|
-
|
|
827
|
-
# The worker class used in production mode
|
|
821
|
+
# DEPRECATED. The worker class used in production mode
|
|
828
822
|
gunicorn_worker_class: str = "uvicorn.workers.UvicornH11Worker"
|
|
829
823
|
|
|
830
|
-
# Number of gunicorn workers from user
|
|
824
|
+
# DEPRECATED. Number of gunicorn workers from user
|
|
831
825
|
gunicorn_workers: int | None = None
|
|
832
826
|
|
|
833
|
-
# Number of requests before a worker is restarted; set to 0 to disable
|
|
834
|
-
gunicorn_max_requests: int =
|
|
827
|
+
# DEPRECATED. Number of requests before a worker is restarted; set to 0 to disable
|
|
828
|
+
gunicorn_max_requests: int | None = None
|
|
835
829
|
|
|
836
|
-
# Variance limit for max requests; gunicorn only
|
|
837
|
-
gunicorn_max_requests_jitter: int =
|
|
830
|
+
# DEPRECATED. Variance limit for max requests; gunicorn only
|
|
831
|
+
gunicorn_max_requests_jitter: int | None = None
|
|
838
832
|
|
|
839
833
|
# Indicate which type of state manager to use
|
|
840
834
|
state_manager_mode: constants.StateManagerMode = constants.StateManagerMode.DISK
|
|
@@ -938,8 +932,14 @@ class Config(Base):
|
|
|
938
932
|
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0.1"`."""
|
|
939
933
|
)
|
|
940
934
|
else:
|
|
941
|
-
# load env
|
|
942
|
-
|
|
935
|
+
# load env files in reverse order if they exist
|
|
936
|
+
for env_file_path in [
|
|
937
|
+
Path(p)
|
|
938
|
+
for s in reversed(env_file.split(os.pathsep))
|
|
939
|
+
if (p := s.strip())
|
|
940
|
+
]:
|
|
941
|
+
if env_file_path.exists():
|
|
942
|
+
load_dotenv(env_file_path, override=True)
|
|
943
943
|
|
|
944
944
|
updated_values = {}
|
|
945
945
|
# Iterate over the fields.
|
|
@@ -826,12 +826,19 @@ def _collect_details_for_gallery():
|
|
|
826
826
|
Raises:
|
|
827
827
|
Exit: If pyproject.toml file is ill-formed or the request to the backend services fails.
|
|
828
828
|
"""
|
|
829
|
+
import reflex_cli.constants
|
|
829
830
|
from reflex_cli.utils import hosting
|
|
830
831
|
|
|
831
832
|
console.rule("[bold]Authentication with Reflex Services")
|
|
832
833
|
console.print("First let's log in to Reflex backend services.")
|
|
833
834
|
access_token, _ = hosting.authenticated_token()
|
|
834
835
|
|
|
836
|
+
if not access_token:
|
|
837
|
+
console.error(
|
|
838
|
+
"Unable to authenticate with Reflex backend services. Make sure you are logged in."
|
|
839
|
+
)
|
|
840
|
+
raise typer.Exit(code=1)
|
|
841
|
+
|
|
835
842
|
console.rule("[bold]Custom Component Information")
|
|
836
843
|
params = {}
|
|
837
844
|
package_name = None
|
|
@@ -845,10 +852,8 @@ def _collect_details_for_gallery():
|
|
|
845
852
|
console.print(f"[ Custom component package name ] : {package_name}")
|
|
846
853
|
params["package_name"] = package_name
|
|
847
854
|
|
|
848
|
-
config = get_config()
|
|
849
|
-
|
|
850
855
|
post_custom_components_gallery_endpoint = (
|
|
851
|
-
f"{
|
|
856
|
+
f"{reflex_cli.constants.Hosting.HOSTING_SERVICE}/custom-components/gallery"
|
|
852
857
|
)
|
|
853
858
|
|
|
854
859
|
# Check the backend services if the user is allowed to update information of this package is already shared.
|
reflex/reflex.py
CHANGED
|
@@ -7,13 +7,14 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
import typer
|
|
9
9
|
import typer.core
|
|
10
|
-
from reflex_cli.v2.deployments import
|
|
10
|
+
from reflex_cli.v2.deployments import hosting_cli
|
|
11
11
|
|
|
12
12
|
from reflex import constants
|
|
13
13
|
from reflex.config import environment, get_config
|
|
14
14
|
from reflex.custom_components.custom_components import custom_components_cli
|
|
15
15
|
from reflex.state import reset_disk_state_manager
|
|
16
16
|
from reflex.utils import console, redir, telemetry
|
|
17
|
+
from reflex.utils.exec import should_use_granian
|
|
17
18
|
|
|
18
19
|
# Disable typer+rich integration for help panels
|
|
19
20
|
typer.core.rich = None # pyright: ignore [reportPrivateImportUsage]
|
|
@@ -203,9 +204,23 @@ def _run(
|
|
|
203
204
|
|
|
204
205
|
prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
# Get the app module.
|
|
208
|
+
app_task = prerequisites.compile_or_validate_app
|
|
209
|
+
args = (frontend,)
|
|
210
|
+
|
|
211
|
+
# Granian fails if the app is already imported.
|
|
212
|
+
if should_use_granian():
|
|
213
|
+
import concurrent.futures
|
|
214
|
+
|
|
215
|
+
compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
|
|
216
|
+
app_task,
|
|
217
|
+
*args,
|
|
218
|
+
)
|
|
219
|
+
validation_result = compile_future.result()
|
|
220
|
+
else:
|
|
221
|
+
validation_result = app_task(*args)
|
|
222
|
+
if not validation_result:
|
|
223
|
+
raise typer.Exit(1)
|
|
209
224
|
|
|
210
225
|
# Warn if schema is not up to date.
|
|
211
226
|
prerequisites.check_schema_up_to_date()
|
|
@@ -386,6 +401,7 @@ def export(
|
|
|
386
401
|
def login(loglevel: constants.LogLevel | None = typer.Option(None)):
|
|
387
402
|
"""Authenticate with experimental Reflex hosting service."""
|
|
388
403
|
from reflex_cli.v2 import cli as hosting_cli
|
|
404
|
+
from reflex_cli.v2.deployments import check_version
|
|
389
405
|
|
|
390
406
|
loglevel = loglevel or get_config().loglevel
|
|
391
407
|
|
|
@@ -407,6 +423,7 @@ def logout(
|
|
|
407
423
|
):
|
|
408
424
|
"""Log out of access to Reflex hosting service."""
|
|
409
425
|
from reflex_cli.v2.cli import logout
|
|
426
|
+
from reflex_cli.v2.deployments import check_version
|
|
410
427
|
|
|
411
428
|
check_version()
|
|
412
429
|
|
|
@@ -567,6 +584,7 @@ def deploy(
|
|
|
567
584
|
from reflex_cli.constants.base import LogLevel as HostingLogLevel
|
|
568
585
|
from reflex_cli.utils import dependency
|
|
569
586
|
from reflex_cli.v2 import cli as hosting_cli
|
|
587
|
+
from reflex_cli.v2.deployments import check_version
|
|
570
588
|
|
|
571
589
|
from reflex.utils import export as export_utils
|
|
572
590
|
from reflex.utils import prerequisites
|
reflex/state.py
CHANGED
|
@@ -1671,6 +1671,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1671
1671
|
|
|
1672
1672
|
raise TypeError(
|
|
1673
1673
|
f"Your handler {handler.fn.__qualname__} must only return/yield: None, Events or other EventHandlers referenced by their class (i.e. using `type(self)` or other class references)."
|
|
1674
|
+
f" Returned events of types {', '.join(map(str, map(type, events)))!s}."
|
|
1674
1675
|
)
|
|
1675
1676
|
|
|
1676
1677
|
async def _as_state_update(
|