reflex 0.7.3a2__py3-none-any.whl → 0.7.4__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 +21 -5
- reflex/base.py +3 -3
- reflex/compiler/compiler.py +68 -8
- reflex/components/component.py +6 -3
- reflex/components/core/client_side_routing.py +3 -3
- reflex/components/core/cond.py +20 -12
- reflex/components/core/upload.py +1 -1
- reflex/components/dynamic.py +2 -4
- reflex/components/lucide/icon.py +20 -27
- reflex/components/plotly/plotly.py +9 -9
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/sonner/toast.py +1 -1
- reflex/config.py +23 -23
- reflex/constants/__init__.py +1 -2
- reflex/constants/base.py +3 -0
- reflex/constants/installer.py +8 -105
- reflex/custom_components/custom_components.py +8 -3
- reflex/reflex.py +22 -4
- reflex/state.py +9 -1
- reflex/testing.py +7 -1
- reflex/utils/build.py +3 -4
- reflex/utils/exec.py +156 -75
- reflex/utils/net.py +107 -18
- reflex/utils/path_ops.py +15 -25
- reflex/utils/prerequisites.py +225 -189
- reflex/utils/processes.py +70 -35
- reflex/utils/redir.py +3 -1
- reflex/utils/registry.py +16 -8
- 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.3a2.dist-info → reflex-0.7.4.dist-info}/METADATA +4 -2
- {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/RECORD +38 -39
- reflex/app_module_for_backend.py +0 -33
- {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/WHEEL +0 -0
- {reflex-0.7.3a2.dist-info → reflex-0.7.4.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.3a2.dist-info → reflex-0.7.4.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.
|
|
@@ -1063,7 +1079,7 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
1063
1079
|
with stateful_pages_marker.open("r") as f:
|
|
1064
1080
|
stateful_pages = json.load(f)
|
|
1065
1081
|
for route in stateful_pages:
|
|
1066
|
-
console.
|
|
1082
|
+
console.debug(f"BE Evaluating stateful page: {route}")
|
|
1067
1083
|
self._compile_page(route, save_page=False)
|
|
1068
1084
|
self._enable_state()
|
|
1069
1085
|
self._add_optional_endpoints()
|
|
@@ -1092,8 +1108,6 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
1092
1108
|
if config.react_strict_mode:
|
|
1093
1109
|
app_wrappers[(200, "StrictMode")] = StrictMode.create()
|
|
1094
1110
|
|
|
1095
|
-
should_compile = self._should_compile()
|
|
1096
|
-
|
|
1097
1111
|
if not should_compile:
|
|
1098
1112
|
with console.timing("Evaluate Pages (Backend)"):
|
|
1099
1113
|
for route in self._unevaluated_pages:
|
|
@@ -1242,7 +1256,9 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
1242
1256
|
compiler.compile_document_root(
|
|
1243
1257
|
self.head_components,
|
|
1244
1258
|
html_lang=self.html_lang,
|
|
1245
|
-
html_custom_attrs=
|
|
1259
|
+
html_custom_attrs=(
|
|
1260
|
+
{**self.html_custom_attrs} if self.html_custom_attrs else {}
|
|
1261
|
+
),
|
|
1246
1262
|
)
|
|
1247
1263
|
)
|
|
1248
1264
|
|
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
|
@@ -19,6 +19,8 @@ from reflex.components.component import (
|
|
|
19
19
|
from reflex.config import environment, get_config
|
|
20
20
|
from reflex.state import BaseState
|
|
21
21
|
from reflex.style import SYSTEM_COLOR_MODE
|
|
22
|
+
from reflex.utils import console, path_ops
|
|
23
|
+
from reflex.utils.exceptions import ReflexError
|
|
22
24
|
from reflex.utils.exec import is_prod_mode
|
|
23
25
|
from reflex.utils.imports import ImportVar
|
|
24
26
|
from reflex.utils.prerequisites import get_web_dir
|
|
@@ -190,18 +192,74 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
|
|
|
190
192
|
if get_config().tailwind is not None
|
|
191
193
|
else []
|
|
192
194
|
)
|
|
195
|
+
|
|
196
|
+
failed_to_import_sass = False
|
|
193
197
|
for stylesheet in stylesheets:
|
|
194
198
|
if not utils.is_valid_url(stylesheet):
|
|
195
199
|
# check if stylesheet provided exists.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
200
|
+
assets_app_path = Path.cwd() / constants.Dirs.APP_ASSETS
|
|
201
|
+
stylesheet_full_path = assets_app_path / stylesheet.strip("/")
|
|
202
|
+
|
|
199
203
|
if not stylesheet_full_path.exists():
|
|
200
204
|
raise FileNotFoundError(
|
|
201
205
|
f"The stylesheet file {stylesheet_full_path} does not exist."
|
|
202
206
|
)
|
|
203
|
-
|
|
207
|
+
|
|
208
|
+
if stylesheet_full_path.is_dir():
|
|
209
|
+
# NOTE: this can create an infinite loop, for example:
|
|
210
|
+
# assets/
|
|
211
|
+
# | dir_a/
|
|
212
|
+
# | | dir_c/ (symlink to "assets/dir_a")
|
|
213
|
+
# | dir_b/
|
|
214
|
+
# so to avoid the infinite loop, we don't include symbolic links
|
|
215
|
+
stylesheets += [
|
|
216
|
+
str(p.relative_to(assets_app_path))
|
|
217
|
+
for p in stylesheet_full_path.iterdir()
|
|
218
|
+
if not (p.is_symlink() and p.is_dir())
|
|
219
|
+
]
|
|
220
|
+
continue
|
|
221
|
+
|
|
222
|
+
if (
|
|
223
|
+
stylesheet_full_path.suffix[1:].lower()
|
|
224
|
+
in constants.Reflex.STYLESHEETS_SUPPORTED
|
|
225
|
+
):
|
|
226
|
+
target = (
|
|
227
|
+
Path.cwd()
|
|
228
|
+
/ constants.Dirs.WEB
|
|
229
|
+
/ constants.Dirs.STYLES
|
|
230
|
+
/ (stylesheet.rsplit(".", 1)[0].strip("/") + ".css")
|
|
231
|
+
)
|
|
232
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
233
|
+
|
|
234
|
+
if stylesheet_full_path.suffix == ".css":
|
|
235
|
+
path_ops.cp(src=stylesheet_full_path, dest=target, overwrite=True)
|
|
236
|
+
else:
|
|
237
|
+
try:
|
|
238
|
+
from sass import compile as sass_compile
|
|
239
|
+
|
|
240
|
+
target.write_text(
|
|
241
|
+
data=sass_compile(
|
|
242
|
+
filename=str(stylesheet_full_path),
|
|
243
|
+
output_style="compressed",
|
|
244
|
+
),
|
|
245
|
+
encoding="utf8",
|
|
246
|
+
)
|
|
247
|
+
except ImportError:
|
|
248
|
+
failed_to_import_sass = True
|
|
249
|
+
else:
|
|
250
|
+
raise FileNotFoundError(
|
|
251
|
+
f'The stylesheet file "{stylesheet_full_path}" is not a valid file.'
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
stylesheet = f"./{stylesheet.rsplit('.', 1)[0].strip('/')}.css"
|
|
255
|
+
|
|
204
256
|
sheets.append(stylesheet) if stylesheet not in sheets else None
|
|
257
|
+
|
|
258
|
+
if failed_to_import_sass:
|
|
259
|
+
console.error(
|
|
260
|
+
'The `libsass` package is required to compile sass/scss stylesheet files. Run `pip install "libsass>=0.23.0"`.'
|
|
261
|
+
)
|
|
262
|
+
|
|
205
263
|
return templates.STYLE.render(stylesheets=sheets)
|
|
206
264
|
|
|
207
265
|
|
|
@@ -311,13 +369,11 @@ def _compile_stateful_components(
|
|
|
311
369
|
|
|
312
370
|
# Include dynamic imports in the shared component.
|
|
313
371
|
if dynamic_imports := component._get_all_dynamic_imports():
|
|
314
|
-
rendered_components.update(
|
|
315
|
-
{dynamic_import: None for dynamic_import in dynamic_imports}
|
|
316
|
-
)
|
|
372
|
+
rendered_components.update(dict.fromkeys(dynamic_imports))
|
|
317
373
|
|
|
318
374
|
# Include custom code in the shared component.
|
|
319
375
|
rendered_components.update(
|
|
320
|
-
|
|
376
|
+
dict.fromkeys(component._get_all_custom_code()),
|
|
321
377
|
)
|
|
322
378
|
|
|
323
379
|
# Include all imports in the shared component.
|
|
@@ -596,6 +652,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
|
|
|
596
652
|
):
|
|
597
653
|
return converted
|
|
598
654
|
except KeyError as e:
|
|
655
|
+
if isinstance(e, ReflexError):
|
|
656
|
+
raise
|
|
599
657
|
key = e.args[0] if e.args else None
|
|
600
658
|
if key is not None and isinstance(key, Var):
|
|
601
659
|
raise TypeError(
|
|
@@ -603,6 +661,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
|
|
|
603
661
|
).with_traceback(e.__traceback__) from None
|
|
604
662
|
raise
|
|
605
663
|
except TypeError as e:
|
|
664
|
+
if isinstance(e, ReflexError):
|
|
665
|
+
raise
|
|
606
666
|
message = e.args[0] if e.args else None
|
|
607
667
|
if message and isinstance(message, str):
|
|
608
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/core/upload.py
CHANGED
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)
|
|
@@ -71,7 +71,7 @@ class Plotly(NoSSRComponent):
|
|
|
71
71
|
|
|
72
72
|
library = "react-plotly.js@2.6.0"
|
|
73
73
|
|
|
74
|
-
lib_dependencies: list[str] = ["plotly.js@
|
|
74
|
+
lib_dependencies: list[str] = ["plotly.js@3.0.1"]
|
|
75
75
|
|
|
76
76
|
tag = "Plot"
|
|
77
77
|
|
|
@@ -289,7 +289,7 @@ class PlotlyBasic(Plotly):
|
|
|
289
289
|
|
|
290
290
|
library = "react-plotly.js@2.6.0"
|
|
291
291
|
|
|
292
|
-
lib_dependencies: list[str] = ["plotly.js-basic-dist-min@3.0.
|
|
292
|
+
lib_dependencies: list[str] = ["plotly.js-basic-dist-min@3.0.1"]
|
|
293
293
|
|
|
294
294
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
295
295
|
"""Add imports for the plotly basic component.
|
|
@@ -315,7 +315,7 @@ class PlotlyCartesian(Plotly):
|
|
|
315
315
|
|
|
316
316
|
library = "react-plotly.js@2.6.0"
|
|
317
317
|
|
|
318
|
-
lib_dependencies: list[str] = ["plotly.js-cartesian-dist-min@3.0.
|
|
318
|
+
lib_dependencies: list[str] = ["plotly.js-cartesian-dist-min@3.0.1"]
|
|
319
319
|
|
|
320
320
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
321
321
|
"""Add imports for the plotly cartesian component.
|
|
@@ -341,7 +341,7 @@ class PlotlyGeo(Plotly):
|
|
|
341
341
|
|
|
342
342
|
library = "react-plotly.js@2.6.0"
|
|
343
343
|
|
|
344
|
-
lib_dependencies: list[str] = ["plotly.js-geo-dist-min@3.0.
|
|
344
|
+
lib_dependencies: list[str] = ["plotly.js-geo-dist-min@3.0.1"]
|
|
345
345
|
|
|
346
346
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
347
347
|
"""Add imports for the plotly geo component.
|
|
@@ -367,7 +367,7 @@ class PlotlyGl3d(Plotly):
|
|
|
367
367
|
|
|
368
368
|
library = "react-plotly.js@2.6.0"
|
|
369
369
|
|
|
370
|
-
lib_dependencies: list[str] = ["plotly.js-gl3d-dist-min@3.0.
|
|
370
|
+
lib_dependencies: list[str] = ["plotly.js-gl3d-dist-min@3.0.1"]
|
|
371
371
|
|
|
372
372
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
373
373
|
"""Add imports for the plotly 3d component.
|
|
@@ -393,7 +393,7 @@ class PlotlyGl2d(Plotly):
|
|
|
393
393
|
|
|
394
394
|
library = "react-plotly.js@2.6.0"
|
|
395
395
|
|
|
396
|
-
lib_dependencies: list[str] = ["plotly.js-gl2d-dist-min@3.0.
|
|
396
|
+
lib_dependencies: list[str] = ["plotly.js-gl2d-dist-min@3.0.1"]
|
|
397
397
|
|
|
398
398
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
399
399
|
"""Add imports for the plotly 2d component.
|
|
@@ -419,7 +419,7 @@ class PlotlyMapbox(Plotly):
|
|
|
419
419
|
|
|
420
420
|
library = "react-plotly.js@2.6.0"
|
|
421
421
|
|
|
422
|
-
lib_dependencies: list[str] = ["plotly.js-mapbox-dist-min@3.0.
|
|
422
|
+
lib_dependencies: list[str] = ["plotly.js-mapbox-dist-min@3.0.1"]
|
|
423
423
|
|
|
424
424
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
425
425
|
"""Add imports for the plotly mapbox component.
|
|
@@ -445,7 +445,7 @@ class PlotlyFinance(Plotly):
|
|
|
445
445
|
|
|
446
446
|
library = "react-plotly.js@2.6.0"
|
|
447
447
|
|
|
448
|
-
lib_dependencies: list[str] = ["plotly.js-finance-dist-min@3.0.
|
|
448
|
+
lib_dependencies: list[str] = ["plotly.js-finance-dist-min@3.0.1"]
|
|
449
449
|
|
|
450
450
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
451
451
|
"""Add imports for the plotly finance component.
|
|
@@ -471,7 +471,7 @@ class PlotlyStrict(Plotly):
|
|
|
471
471
|
|
|
472
472
|
library = "react-plotly.js@2.6.0"
|
|
473
473
|
|
|
474
|
-
lib_dependencies: list[str] = ["plotly.js-strict-dist-min@3.0.
|
|
474
|
+
lib_dependencies: list[str] = ["plotly.js-strict-dist-min@3.0.1"]
|
|
475
475
|
|
|
476
476
|
def add_imports(self) -> ImportDict | list[ImportDict]:
|
|
477
477
|
"""Add imports for the plotly strict component.
|
|
@@ -8,7 +8,7 @@ from reflex.components.component import Component, MemoizationLeaf, NoSSRCompone
|
|
|
8
8
|
class Recharts(Component):
|
|
9
9
|
"""A component that wraps a recharts lib."""
|
|
10
10
|
|
|
11
|
-
library = "recharts@2.15.
|
|
11
|
+
library = "recharts@2.15.1"
|
|
12
12
|
|
|
13
13
|
def _get_style(self) -> dict:
|
|
14
14
|
return {"wrapperStyle": self.style}
|
|
@@ -17,7 +17,7 @@ class Recharts(Component):
|
|
|
17
17
|
class RechartsCharts(NoSSRComponent, MemoizationLeaf):
|
|
18
18
|
"""A component that wraps a recharts lib."""
|
|
19
19
|
|
|
20
|
-
library = "recharts@2.15.
|
|
20
|
+
library = "recharts@2.15.1"
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]
|
|
@@ -172,7 +172,7 @@ class ToastProps(PropsBase, NoExtrasAllowedProps):
|
|
|
172
172
|
class Toaster(Component):
|
|
173
173
|
"""A Toaster Component for displaying toast notifications."""
|
|
174
174
|
|
|
175
|
-
library: str | None = "sonner@
|
|
175
|
+
library: str | None = "sonner@2.0.1"
|
|
176
176
|
|
|
177
177
|
tag = "Toaster"
|
|
178
178
|
|
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
|
|
|
@@ -596,13 +595,13 @@ class EnvironmentVariables:
|
|
|
596
595
|
constants.CompileContext.UNDEFINED, internal=True
|
|
597
596
|
)
|
|
598
597
|
|
|
599
|
-
# Whether to use npm over bun to install frontend
|
|
598
|
+
# Whether to use npm over bun to install and run the frontend.
|
|
600
599
|
REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
|
|
601
600
|
|
|
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.
|
|
@@ -614,9 +613,6 @@ class EnvironmentVariables:
|
|
|
614
613
|
# Whether to use the system installed bun. If set to false, bun will be bundled with the app.
|
|
615
614
|
REFLEX_USE_SYSTEM_BUN: EnvVar[bool] = env_var(False)
|
|
616
615
|
|
|
617
|
-
# Whether to use the system installed node and npm. If set to false, node and npm will be bundled with the app.
|
|
618
|
-
REFLEX_USE_SYSTEM_NODE: EnvVar[bool] = env_var(False)
|
|
619
|
-
|
|
620
616
|
# The working directory for the next.js commands.
|
|
621
617
|
REFLEX_WEB_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.WEB))
|
|
622
618
|
|
|
@@ -724,6 +720,9 @@ class EnvironmentVariables:
|
|
|
724
720
|
# Used by flexgen to enumerate the pages.
|
|
725
721
|
REFLEX_ADD_ALL_ROUTES_ENDPOINT: EnvVar[bool] = env_var(False)
|
|
726
722
|
|
|
723
|
+
# The address to bind the HTTP client to. You can set this to "::" to enable IPv6.
|
|
724
|
+
REFLEX_HTTP_CLIENT_BIND_ADDRESS: EnvVar[str | None] = env_var(None)
|
|
725
|
+
|
|
727
726
|
|
|
728
727
|
environment = EnvironmentVariables()
|
|
729
728
|
|
|
@@ -810,8 +809,8 @@ class Config(Base):
|
|
|
810
809
|
# Tailwind config.
|
|
811
810
|
tailwind: dict[str, Any] | None = {"plugins": ["@tailwindcss/typography"]}
|
|
812
811
|
|
|
813
|
-
# Timeout when launching the gunicorn server.
|
|
814
|
-
timeout: int =
|
|
812
|
+
# DEPRECATED. Timeout when launching the gunicorn server.
|
|
813
|
+
timeout: int | None = None
|
|
815
814
|
|
|
816
815
|
# Whether to enable or disable nextJS gzip compression.
|
|
817
816
|
next_compression: bool = True
|
|
@@ -822,22 +821,17 @@ class Config(Base):
|
|
|
822
821
|
# Additional frontend packages to install.
|
|
823
822
|
frontend_packages: list[str] = []
|
|
824
823
|
|
|
825
|
-
# The
|
|
826
|
-
cp_backend_url: str = Hosting.HOSTING_SERVICE
|
|
827
|
-
# The hosting service frontend URL.
|
|
828
|
-
cp_web_url: str = Hosting.HOSTING_SERVICE_UI
|
|
829
|
-
|
|
830
|
-
# The worker class used in production mode
|
|
824
|
+
# DEPRECATED. The worker class used in production mode
|
|
831
825
|
gunicorn_worker_class: str = "uvicorn.workers.UvicornH11Worker"
|
|
832
826
|
|
|
833
|
-
# Number of gunicorn workers from user
|
|
827
|
+
# DEPRECATED. Number of gunicorn workers from user
|
|
834
828
|
gunicorn_workers: int | None = None
|
|
835
829
|
|
|
836
|
-
# Number of requests before a worker is restarted; set to 0 to disable
|
|
837
|
-
gunicorn_max_requests: int =
|
|
830
|
+
# DEPRECATED. Number of requests before a worker is restarted; set to 0 to disable
|
|
831
|
+
gunicorn_max_requests: int | None = None
|
|
838
832
|
|
|
839
|
-
# Variance limit for max requests; gunicorn only
|
|
840
|
-
gunicorn_max_requests_jitter: int =
|
|
833
|
+
# DEPRECATED. Variance limit for max requests; gunicorn only
|
|
834
|
+
gunicorn_max_requests_jitter: int | None = None
|
|
841
835
|
|
|
842
836
|
# Indicate which type of state manager to use
|
|
843
837
|
state_manager_mode: constants.StateManagerMode = constants.StateManagerMode.DISK
|
|
@@ -941,8 +935,14 @@ class Config(Base):
|
|
|
941
935
|
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0.1"`."""
|
|
942
936
|
)
|
|
943
937
|
else:
|
|
944
|
-
# load env
|
|
945
|
-
|
|
938
|
+
# load env files in reverse order if they exist
|
|
939
|
+
for env_file_path in [
|
|
940
|
+
Path(p)
|
|
941
|
+
for s in reversed(env_file.split(os.pathsep))
|
|
942
|
+
if (p := s.strip())
|
|
943
|
+
]:
|
|
944
|
+
if env_file_path.exists():
|
|
945
|
+
load_dotenv(env_file_path, override=True)
|
|
946
946
|
|
|
947
947
|
updated_values = {}
|
|
948
948
|
# Iterate over the fields.
|
|
@@ -964,7 +964,7 @@ class Config(Base):
|
|
|
964
964
|
env_var = "***"
|
|
965
965
|
|
|
966
966
|
if value != getattr(self, key):
|
|
967
|
-
console.
|
|
967
|
+
console.debug(
|
|
968
968
|
f"Overriding config value {key} with env var {key.upper()}={env_var}",
|
|
969
969
|
dedupe=True,
|
|
970
970
|
)
|