reflex 0.6.1a2__py3-none-any.whl → 0.6.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +6 -8
- reflex/.templates/web/utils/state.js +17 -5
- reflex/app.py +3 -14
- reflex/compiler/compiler.py +25 -1
- reflex/compiler/utils.py +4 -5
- reflex/components/component.py +32 -18
- reflex/components/dynamic.py +39 -9
- reflex/components/el/elements/media.py +89 -0
- reflex/components/el/elements/media.pyi +480 -0
- reflex/config.py +3 -2
- reflex/constants/base.py +22 -12
- reflex/constants/config.py +3 -4
- reflex/constants/custom_components.py +4 -3
- reflex/constants/installer.py +14 -15
- reflex/custom_components/custom_components.py +32 -41
- reflex/event.py +199 -4
- reflex/istate/data.py +126 -0
- reflex/model.py +2 -3
- reflex/reflex.py +5 -14
- reflex/state.py +127 -164
- reflex/utils/build.py +21 -16
- reflex/utils/compat.py +25 -4
- reflex/utils/exceptions.py +12 -0
- reflex/utils/exec.py +2 -2
- reflex/utils/format.py +1 -13
- reflex/utils/path_ops.py +3 -3
- reflex/utils/prerequisites.py +49 -88
- reflex/utils/processes.py +2 -2
- reflex/vars/base.py +48 -37
- {reflex-0.6.1a2.dist-info → reflex-0.6.2.dist-info}/METADATA +1 -2
- {reflex-0.6.1a2.dist-info → reflex-0.6.2.dist-info}/RECORD +34 -33
- {reflex-0.6.1a2.dist-info → reflex-0.6.2.dist-info}/LICENSE +0 -0
- {reflex-0.6.1a2.dist-info → reflex-0.6.2.dist-info}/WHEEL +0 -0
- {reflex-0.6.1a2.dist-info → reflex-0.6.2.dist-info}/entry_points.txt +0 -0
reflex/constants/installer.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import os
|
|
6
5
|
import platform
|
|
7
6
|
from types import SimpleNamespace
|
|
8
7
|
|
|
@@ -40,11 +39,10 @@ class Bun(SimpleNamespace):
|
|
|
40
39
|
# Min Bun Version
|
|
41
40
|
MIN_VERSION = "0.7.0"
|
|
42
41
|
# The directory to store the bun.
|
|
43
|
-
ROOT_PATH =
|
|
42
|
+
ROOT_PATH = Reflex.DIR / "bun"
|
|
44
43
|
# Default bun path.
|
|
45
|
-
DEFAULT_PATH =
|
|
46
|
-
|
|
47
|
-
)
|
|
44
|
+
DEFAULT_PATH = ROOT_PATH / "bin" / ("bun" if not IS_WINDOWS else "bun.exe")
|
|
45
|
+
|
|
48
46
|
# URL to bun install script.
|
|
49
47
|
INSTALL_URL = "https://bun.sh/install"
|
|
50
48
|
# URL to windows install script.
|
|
@@ -65,10 +63,10 @@ class Fnm(SimpleNamespace):
|
|
|
65
63
|
# The FNM version.
|
|
66
64
|
VERSION = "1.35.1"
|
|
67
65
|
# The directory to store fnm.
|
|
68
|
-
DIR =
|
|
66
|
+
DIR = Reflex.DIR / "fnm"
|
|
69
67
|
FILENAME = get_fnm_name()
|
|
70
68
|
# The fnm executable binary.
|
|
71
|
-
EXE =
|
|
69
|
+
EXE = DIR / ("fnm.exe" if IS_WINDOWS else "fnm")
|
|
72
70
|
|
|
73
71
|
# The URL to the fnm release binary
|
|
74
72
|
INSTALL_URL = (
|
|
@@ -86,18 +84,19 @@ class Node(SimpleNamespace):
|
|
|
86
84
|
MIN_VERSION = "18.17.0"
|
|
87
85
|
|
|
88
86
|
# The node bin path.
|
|
89
|
-
BIN_PATH =
|
|
90
|
-
Fnm.DIR
|
|
91
|
-
"node-versions"
|
|
92
|
-
f"v{VERSION}"
|
|
93
|
-
"installation"
|
|
94
|
-
"bin" if not IS_WINDOWS else ""
|
|
87
|
+
BIN_PATH = (
|
|
88
|
+
Fnm.DIR
|
|
89
|
+
/ "node-versions"
|
|
90
|
+
/ f"v{VERSION}"
|
|
91
|
+
/ "installation"
|
|
92
|
+
/ ("bin" if not IS_WINDOWS else "")
|
|
95
93
|
)
|
|
94
|
+
|
|
96
95
|
# The default path where node is installed.
|
|
97
|
-
PATH =
|
|
96
|
+
PATH = BIN_PATH / ("node.exe" if IS_WINDOWS else "node")
|
|
98
97
|
|
|
99
98
|
# The default path where npm is installed.
|
|
100
|
-
NPM_PATH =
|
|
99
|
+
NPM_PATH = BIN_PATH / "npm"
|
|
101
100
|
|
|
102
101
|
# The environment variable to use the system installed node.
|
|
103
102
|
USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_NODE"
|
|
@@ -36,7 +36,7 @@ POST_CUSTOM_COMPONENTS_GALLERY_TIMEOUT = 15
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
@contextmanager
|
|
39
|
-
def set_directory(working_directory: str):
|
|
39
|
+
def set_directory(working_directory: str | Path):
|
|
40
40
|
"""Context manager that sets the working directory.
|
|
41
41
|
|
|
42
42
|
Args:
|
|
@@ -45,7 +45,8 @@ def set_directory(working_directory: str):
|
|
|
45
45
|
Yields:
|
|
46
46
|
Yield to the caller to perform operations in the working directory.
|
|
47
47
|
"""
|
|
48
|
-
current_directory =
|
|
48
|
+
current_directory = Path.cwd()
|
|
49
|
+
working_directory = Path(working_directory)
|
|
49
50
|
try:
|
|
50
51
|
os.chdir(working_directory)
|
|
51
52
|
yield
|
|
@@ -62,14 +63,14 @@ def _create_package_config(module_name: str, package_name: str):
|
|
|
62
63
|
"""
|
|
63
64
|
from reflex.compiler import templates
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
66
|
+
pyproject = Path(CustomComponents.PYPROJECT_TOML)
|
|
67
|
+
pyproject.write_text(
|
|
68
|
+
templates.CUSTOM_COMPONENTS_PYPROJECT_TOML.render(
|
|
69
|
+
module_name=module_name,
|
|
70
|
+
package_name=package_name,
|
|
71
|
+
reflex_version=constants.Reflex.VERSION,
|
|
72
72
|
)
|
|
73
|
+
)
|
|
73
74
|
|
|
74
75
|
|
|
75
76
|
def _get_package_config(exit_on_fail: bool = True) -> dict:
|
|
@@ -84,11 +85,11 @@ def _get_package_config(exit_on_fail: bool = True) -> dict:
|
|
|
84
85
|
Raises:
|
|
85
86
|
Exit: If the pyproject.toml file is not found.
|
|
86
87
|
"""
|
|
88
|
+
pyproject = Path(CustomComponents.PYPROJECT_TOML)
|
|
87
89
|
try:
|
|
88
|
-
|
|
89
|
-
return dict(tomlkit.load(f))
|
|
90
|
+
return dict(tomlkit.loads(pyproject.read_bytes()))
|
|
90
91
|
except (OSError, TOMLKitError) as ex:
|
|
91
|
-
console.error(f"Unable to read from pyproject
|
|
92
|
+
console.error(f"Unable to read from {pyproject} due to {ex}")
|
|
92
93
|
if exit_on_fail:
|
|
93
94
|
raise typer.Exit(code=1) from ex
|
|
94
95
|
raise
|
|
@@ -103,17 +104,17 @@ def _create_readme(module_name: str, package_name: str):
|
|
|
103
104
|
"""
|
|
104
105
|
from reflex.compiler import templates
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
107
|
+
readme = Path(CustomComponents.PACKAGE_README)
|
|
108
|
+
readme.write_text(
|
|
109
|
+
templates.CUSTOM_COMPONENTS_README.render(
|
|
110
|
+
module_name=module_name,
|
|
111
|
+
package_name=package_name,
|
|
112
112
|
)
|
|
113
|
+
)
|
|
113
114
|
|
|
114
115
|
|
|
115
116
|
def _write_source_and_init_py(
|
|
116
|
-
custom_component_src_dir:
|
|
117
|
+
custom_component_src_dir: Path,
|
|
117
118
|
component_class_name: str,
|
|
118
119
|
module_name: str,
|
|
119
120
|
):
|
|
@@ -126,27 +127,17 @@ def _write_source_and_init_py(
|
|
|
126
127
|
"""
|
|
127
128
|
from reflex.compiler import templates
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
),
|
|
134
|
-
"w",
|
|
135
|
-
) as f:
|
|
136
|
-
f.write(
|
|
137
|
-
templates.CUSTOM_COMPONENTS_SOURCE.render(
|
|
138
|
-
component_class_name=component_class_name, module_name=module_name
|
|
139
|
-
)
|
|
130
|
+
module_path = custom_component_src_dir / f"{module_name}.py"
|
|
131
|
+
module_path.write_text(
|
|
132
|
+
templates.CUSTOM_COMPONENTS_SOURCE.render(
|
|
133
|
+
component_class_name=component_class_name, module_name=module_name
|
|
140
134
|
)
|
|
135
|
+
)
|
|
141
136
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
),
|
|
147
|
-
"w",
|
|
148
|
-
) as f:
|
|
149
|
-
f.write(templates.CUSTOM_COMPONENTS_INIT_FILE.render(module_name=module_name))
|
|
137
|
+
init_path = custom_component_src_dir / CustomComponents.INIT_FILE
|
|
138
|
+
init_path.write_text(
|
|
139
|
+
templates.CUSTOM_COMPONENTS_INIT_FILE.render(module_name=module_name)
|
|
140
|
+
)
|
|
150
141
|
|
|
151
142
|
|
|
152
143
|
def _populate_demo_app(name_variants: NameVariants):
|
|
@@ -192,7 +183,7 @@ def _get_default_library_name_parts() -> list[str]:
|
|
|
192
183
|
Returns:
|
|
193
184
|
The parts of default library name.
|
|
194
185
|
"""
|
|
195
|
-
current_dir_name =
|
|
186
|
+
current_dir_name = Path.cwd().name
|
|
196
187
|
|
|
197
188
|
cleaned_dir_name = re.sub("[^0-9a-zA-Z-_]+", "", current_dir_name).lower()
|
|
198
189
|
parts = [part for part in re.split("-|_", cleaned_dir_name) if part]
|
|
@@ -269,7 +260,7 @@ def _validate_library_name(library_name: str | None) -> NameVariants:
|
|
|
269
260
|
# Module name is the snake case.
|
|
270
261
|
module_name = "_".join(name_parts)
|
|
271
262
|
|
|
272
|
-
custom_component_module_dir = f"reflex_{module_name}"
|
|
263
|
+
custom_component_module_dir = Path(f"reflex_{module_name}")
|
|
273
264
|
console.debug(f"Custom component source directory: {custom_component_module_dir}")
|
|
274
265
|
|
|
275
266
|
# Use the same name for the directory and the app.
|
|
@@ -345,7 +336,7 @@ def init(
|
|
|
345
336
|
|
|
346
337
|
console.set_log_level(loglevel)
|
|
347
338
|
|
|
348
|
-
if
|
|
339
|
+
if CustomComponents.PYPROJECT_TOML.exists():
|
|
349
340
|
console.error(f"A {CustomComponents.PYPROJECT_TOML} already exists. Aborting.")
|
|
350
341
|
typer.Exit(code=1)
|
|
351
342
|
|
reflex/event.py
CHANGED
|
@@ -4,16 +4,19 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import dataclasses
|
|
6
6
|
import inspect
|
|
7
|
+
import sys
|
|
7
8
|
import types
|
|
8
9
|
import urllib.parse
|
|
9
10
|
from base64 import b64encode
|
|
10
11
|
from typing import (
|
|
11
12
|
Any,
|
|
12
13
|
Callable,
|
|
14
|
+
ClassVar,
|
|
13
15
|
Dict,
|
|
14
16
|
List,
|
|
15
17
|
Optional,
|
|
16
18
|
Tuple,
|
|
19
|
+
Type,
|
|
17
20
|
Union,
|
|
18
21
|
get_type_hints,
|
|
19
22
|
)
|
|
@@ -25,8 +28,15 @@ from reflex.utils import format
|
|
|
25
28
|
from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
|
|
26
29
|
from reflex.utils.types import ArgsSpec, GenericType
|
|
27
30
|
from reflex.vars import VarData
|
|
28
|
-
from reflex.vars.base import
|
|
29
|
-
|
|
31
|
+
from reflex.vars.base import (
|
|
32
|
+
CachedVarOperation,
|
|
33
|
+
LiteralNoneVar,
|
|
34
|
+
LiteralVar,
|
|
35
|
+
ToOperation,
|
|
36
|
+
Var,
|
|
37
|
+
cached_property_no_lock,
|
|
38
|
+
)
|
|
39
|
+
from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar, FunctionVar
|
|
30
40
|
from reflex.vars.object import ObjectVar
|
|
31
41
|
|
|
32
42
|
try:
|
|
@@ -375,7 +385,7 @@ class CallableEventSpec(EventSpec):
|
|
|
375
385
|
class EventChain(EventActionsMixin):
|
|
376
386
|
"""Container for a chain of events that will be executed in order."""
|
|
377
387
|
|
|
378
|
-
events: List[EventSpec] = dataclasses.field(default_factory=list)
|
|
388
|
+
events: List[Union[EventSpec, EventVar]] = dataclasses.field(default_factory=list)
|
|
379
389
|
|
|
380
390
|
args_spec: Optional[Callable] = dataclasses.field(default=None)
|
|
381
391
|
|
|
@@ -478,7 +488,7 @@ class FileUpload:
|
|
|
478
488
|
if isinstance(events, Var):
|
|
479
489
|
raise ValueError(f"{on_upload_progress} cannot return a var {events}.")
|
|
480
490
|
on_upload_progress_chain = EventChain(
|
|
481
|
-
events=events,
|
|
491
|
+
events=[*events],
|
|
482
492
|
args_spec=self.on_upload_progress_args_spec,
|
|
483
493
|
)
|
|
484
494
|
formatted_chain = str(format.format_prop(on_upload_progress_chain))
|
|
@@ -839,6 +849,16 @@ def call_script(
|
|
|
839
849
|
),
|
|
840
850
|
),
|
|
841
851
|
}
|
|
852
|
+
if isinstance(javascript_code, str):
|
|
853
|
+
# When there is VarData, include it and eval the JS code inline on the client.
|
|
854
|
+
javascript_code, original_code = (
|
|
855
|
+
LiteralVar.create(javascript_code),
|
|
856
|
+
javascript_code,
|
|
857
|
+
)
|
|
858
|
+
if not javascript_code._get_all_var_data():
|
|
859
|
+
# Without VarData, cast to string and eval the code in the event loop.
|
|
860
|
+
javascript_code = str(Var(_js_expr=original_code))
|
|
861
|
+
|
|
842
862
|
return server_side(
|
|
843
863
|
"_call_script",
|
|
844
864
|
get_fn_signature(call_script),
|
|
@@ -1126,3 +1146,178 @@ def get_fn_signature(fn: Callable) -> inspect.Signature:
|
|
|
1126
1146
|
"state", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=Any
|
|
1127
1147
|
)
|
|
1128
1148
|
return signature.replace(parameters=(new_param, *signature.parameters.values()))
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
class EventVar(ObjectVar):
|
|
1152
|
+
"""Base class for event vars."""
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
@dataclasses.dataclass(
|
|
1156
|
+
eq=False,
|
|
1157
|
+
frozen=True,
|
|
1158
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1159
|
+
)
|
|
1160
|
+
class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar):
|
|
1161
|
+
"""A literal event var."""
|
|
1162
|
+
|
|
1163
|
+
_var_value: EventSpec = dataclasses.field(default=None) # type: ignore
|
|
1164
|
+
|
|
1165
|
+
def __hash__(self) -> int:
|
|
1166
|
+
"""Get the hash of the var.
|
|
1167
|
+
|
|
1168
|
+
Returns:
|
|
1169
|
+
The hash of the var.
|
|
1170
|
+
"""
|
|
1171
|
+
return hash((self.__class__.__name__, self._js_expr))
|
|
1172
|
+
|
|
1173
|
+
@cached_property_no_lock
|
|
1174
|
+
def _cached_var_name(self) -> str:
|
|
1175
|
+
"""The name of the var.
|
|
1176
|
+
|
|
1177
|
+
Returns:
|
|
1178
|
+
The name of the var.
|
|
1179
|
+
"""
|
|
1180
|
+
return str(
|
|
1181
|
+
FunctionStringVar("Event").call(
|
|
1182
|
+
# event handler name
|
|
1183
|
+
".".join(
|
|
1184
|
+
filter(
|
|
1185
|
+
None,
|
|
1186
|
+
format.get_event_handler_parts(self._var_value.handler),
|
|
1187
|
+
)
|
|
1188
|
+
),
|
|
1189
|
+
# event handler args
|
|
1190
|
+
{str(name): value for name, value in self._var_value.args},
|
|
1191
|
+
# event actions
|
|
1192
|
+
self._var_value.event_actions,
|
|
1193
|
+
# client handler name
|
|
1194
|
+
*(
|
|
1195
|
+
[self._var_value.client_handler_name]
|
|
1196
|
+
if self._var_value.client_handler_name
|
|
1197
|
+
else []
|
|
1198
|
+
),
|
|
1199
|
+
)
|
|
1200
|
+
)
|
|
1201
|
+
|
|
1202
|
+
@classmethod
|
|
1203
|
+
def create(
|
|
1204
|
+
cls,
|
|
1205
|
+
value: EventSpec,
|
|
1206
|
+
_var_data: VarData | None = None,
|
|
1207
|
+
) -> LiteralEventVar:
|
|
1208
|
+
"""Create a new LiteralEventVar instance.
|
|
1209
|
+
|
|
1210
|
+
Args:
|
|
1211
|
+
value: The value of the var.
|
|
1212
|
+
_var_data: The data of the var.
|
|
1213
|
+
|
|
1214
|
+
Returns:
|
|
1215
|
+
The created LiteralEventVar instance.
|
|
1216
|
+
"""
|
|
1217
|
+
return cls(
|
|
1218
|
+
_js_expr="",
|
|
1219
|
+
_var_type=EventSpec,
|
|
1220
|
+
_var_data=_var_data,
|
|
1221
|
+
_var_value=value,
|
|
1222
|
+
)
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
class EventChainVar(FunctionVar):
|
|
1226
|
+
"""Base class for event chain vars."""
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
@dataclasses.dataclass(
|
|
1230
|
+
eq=False,
|
|
1231
|
+
frozen=True,
|
|
1232
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1233
|
+
)
|
|
1234
|
+
class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar):
|
|
1235
|
+
"""A literal event chain var."""
|
|
1236
|
+
|
|
1237
|
+
_var_value: EventChain = dataclasses.field(default=None) # type: ignore
|
|
1238
|
+
|
|
1239
|
+
def __hash__(self) -> int:
|
|
1240
|
+
"""Get the hash of the var.
|
|
1241
|
+
|
|
1242
|
+
Returns:
|
|
1243
|
+
The hash of the var.
|
|
1244
|
+
"""
|
|
1245
|
+
return hash((self.__class__.__name__, self._js_expr))
|
|
1246
|
+
|
|
1247
|
+
@cached_property_no_lock
|
|
1248
|
+
def _cached_var_name(self) -> str:
|
|
1249
|
+
"""The name of the var.
|
|
1250
|
+
|
|
1251
|
+
Returns:
|
|
1252
|
+
The name of the var.
|
|
1253
|
+
"""
|
|
1254
|
+
sig = inspect.signature(self._var_value.args_spec) # type: ignore
|
|
1255
|
+
if sig.parameters:
|
|
1256
|
+
arg_def = tuple((f"_{p}" for p in sig.parameters))
|
|
1257
|
+
arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
|
|
1258
|
+
else:
|
|
1259
|
+
# add a default argument for addEvents if none were specified in value.args_spec
|
|
1260
|
+
# used to trigger the preventDefault() on the event.
|
|
1261
|
+
arg_def = ("...args",)
|
|
1262
|
+
arg_def_expr = Var(_js_expr="args")
|
|
1263
|
+
|
|
1264
|
+
return str(
|
|
1265
|
+
ArgsFunctionOperation.create(
|
|
1266
|
+
arg_def,
|
|
1267
|
+
FunctionStringVar.create("addEvents").call(
|
|
1268
|
+
LiteralVar.create(
|
|
1269
|
+
[LiteralVar.create(event) for event in self._var_value.events]
|
|
1270
|
+
),
|
|
1271
|
+
arg_def_expr,
|
|
1272
|
+
self._var_value.event_actions,
|
|
1273
|
+
),
|
|
1274
|
+
)
|
|
1275
|
+
)
|
|
1276
|
+
|
|
1277
|
+
@classmethod
|
|
1278
|
+
def create(
|
|
1279
|
+
cls,
|
|
1280
|
+
value: EventChain,
|
|
1281
|
+
_var_data: VarData | None = None,
|
|
1282
|
+
) -> LiteralEventChainVar:
|
|
1283
|
+
"""Create a new LiteralEventChainVar instance.
|
|
1284
|
+
|
|
1285
|
+
Args:
|
|
1286
|
+
value: The value of the var.
|
|
1287
|
+
_var_data: The data of the var.
|
|
1288
|
+
|
|
1289
|
+
Returns:
|
|
1290
|
+
The created LiteralEventChainVar instance.
|
|
1291
|
+
"""
|
|
1292
|
+
return cls(
|
|
1293
|
+
_js_expr="",
|
|
1294
|
+
_var_type=EventChain,
|
|
1295
|
+
_var_data=_var_data,
|
|
1296
|
+
_var_value=value,
|
|
1297
|
+
)
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
@dataclasses.dataclass(
|
|
1301
|
+
eq=False,
|
|
1302
|
+
frozen=True,
|
|
1303
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1304
|
+
)
|
|
1305
|
+
class ToEventVarOperation(ToOperation, EventVar):
|
|
1306
|
+
"""Result of a cast to an event var."""
|
|
1307
|
+
|
|
1308
|
+
_original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
|
|
1309
|
+
|
|
1310
|
+
_default_var_type: ClassVar[Type] = EventSpec
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
@dataclasses.dataclass(
|
|
1314
|
+
eq=False,
|
|
1315
|
+
frozen=True,
|
|
1316
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1317
|
+
)
|
|
1318
|
+
class ToEventChainVarOperation(ToOperation, EventChainVar):
|
|
1319
|
+
"""Result of a cast to an event chain var."""
|
|
1320
|
+
|
|
1321
|
+
_original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
|
|
1322
|
+
|
|
1323
|
+
_default_var_type: ClassVar[Type] = EventChain
|
reflex/istate/data.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""This module contains the dataclasses representing the router object."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from reflex import constants
|
|
7
|
+
from reflex.utils import format
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclasses.dataclass(frozen=True)
|
|
11
|
+
class HeaderData:
|
|
12
|
+
"""An object containing headers data."""
|
|
13
|
+
|
|
14
|
+
host: str = ""
|
|
15
|
+
origin: str = ""
|
|
16
|
+
upgrade: str = ""
|
|
17
|
+
connection: str = ""
|
|
18
|
+
cookie: str = ""
|
|
19
|
+
pragma: str = ""
|
|
20
|
+
cache_control: str = ""
|
|
21
|
+
user_agent: str = ""
|
|
22
|
+
sec_websocket_version: str = ""
|
|
23
|
+
sec_websocket_key: str = ""
|
|
24
|
+
sec_websocket_extensions: str = ""
|
|
25
|
+
accept_encoding: str = ""
|
|
26
|
+
accept_language: str = ""
|
|
27
|
+
|
|
28
|
+
def __init__(self, router_data: Optional[dict] = None):
|
|
29
|
+
"""Initalize the HeaderData object based on router_data.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
router_data: the router_data dict.
|
|
33
|
+
"""
|
|
34
|
+
if router_data:
|
|
35
|
+
for k, v in router_data.get(constants.RouteVar.HEADERS, {}).items():
|
|
36
|
+
object.__setattr__(self, format.to_snake_case(k), v)
|
|
37
|
+
else:
|
|
38
|
+
for k in dataclasses.fields(self):
|
|
39
|
+
object.__setattr__(self, k.name, "")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclasses.dataclass(frozen=True)
|
|
43
|
+
class PageData:
|
|
44
|
+
"""An object containing page data."""
|
|
45
|
+
|
|
46
|
+
host: str = "" # repeated with self.headers.origin (remove or keep the duplicate?)
|
|
47
|
+
path: str = ""
|
|
48
|
+
raw_path: str = ""
|
|
49
|
+
full_path: str = ""
|
|
50
|
+
full_raw_path: str = ""
|
|
51
|
+
params: dict = dataclasses.field(default_factory=dict)
|
|
52
|
+
|
|
53
|
+
def __init__(self, router_data: Optional[dict] = None):
|
|
54
|
+
"""Initalize the PageData object based on router_data.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
router_data: the router_data dict.
|
|
58
|
+
"""
|
|
59
|
+
if router_data:
|
|
60
|
+
object.__setattr__(
|
|
61
|
+
self,
|
|
62
|
+
"host",
|
|
63
|
+
router_data.get(constants.RouteVar.HEADERS, {}).get("origin", ""),
|
|
64
|
+
)
|
|
65
|
+
object.__setattr__(
|
|
66
|
+
self, "path", router_data.get(constants.RouteVar.PATH, "")
|
|
67
|
+
)
|
|
68
|
+
object.__setattr__(
|
|
69
|
+
self, "raw_path", router_data.get(constants.RouteVar.ORIGIN, "")
|
|
70
|
+
)
|
|
71
|
+
object.__setattr__(self, "full_path", f"{self.host}{self.path}")
|
|
72
|
+
object.__setattr__(self, "full_raw_path", f"{self.host}{self.raw_path}")
|
|
73
|
+
object.__setattr__(
|
|
74
|
+
self, "params", router_data.get(constants.RouteVar.QUERY, {})
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
object.__setattr__(self, "host", "")
|
|
78
|
+
object.__setattr__(self, "path", "")
|
|
79
|
+
object.__setattr__(self, "raw_path", "")
|
|
80
|
+
object.__setattr__(self, "full_path", "")
|
|
81
|
+
object.__setattr__(self, "full_raw_path", "")
|
|
82
|
+
object.__setattr__(self, "params", {})
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclasses.dataclass(frozen=True, init=False)
|
|
86
|
+
class SessionData:
|
|
87
|
+
"""An object containing session data."""
|
|
88
|
+
|
|
89
|
+
client_token: str = ""
|
|
90
|
+
client_ip: str = ""
|
|
91
|
+
session_id: str = ""
|
|
92
|
+
|
|
93
|
+
def __init__(self, router_data: Optional[dict] = None):
|
|
94
|
+
"""Initalize the SessionData object based on router_data.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
router_data: the router_data dict.
|
|
98
|
+
"""
|
|
99
|
+
if router_data:
|
|
100
|
+
client_token = router_data.get(constants.RouteVar.CLIENT_TOKEN, "")
|
|
101
|
+
client_ip = router_data.get(constants.RouteVar.CLIENT_IP, "")
|
|
102
|
+
session_id = router_data.get(constants.RouteVar.SESSION_ID, "")
|
|
103
|
+
else:
|
|
104
|
+
client_token = client_ip = session_id = ""
|
|
105
|
+
object.__setattr__(self, "client_token", client_token)
|
|
106
|
+
object.__setattr__(self, "client_ip", client_ip)
|
|
107
|
+
object.__setattr__(self, "session_id", session_id)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclasses.dataclass(frozen=True, init=False)
|
|
111
|
+
class RouterData:
|
|
112
|
+
"""An object containing RouterData."""
|
|
113
|
+
|
|
114
|
+
session: SessionData = dataclasses.field(default_factory=SessionData)
|
|
115
|
+
headers: HeaderData = dataclasses.field(default_factory=HeaderData)
|
|
116
|
+
page: PageData = dataclasses.field(default_factory=PageData)
|
|
117
|
+
|
|
118
|
+
def __init__(self, router_data: Optional[dict] = None):
|
|
119
|
+
"""Initialize the RouterData object.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
router_data: the router_data dict.
|
|
123
|
+
"""
|
|
124
|
+
object.__setattr__(self, "session", SessionData(router_data))
|
|
125
|
+
object.__setattr__(self, "headers", HeaderData(router_data))
|
|
126
|
+
object.__setattr__(self, "page", PageData(router_data))
|
reflex/model.py
CHANGED
|
@@ -22,7 +22,7 @@ from reflex import constants
|
|
|
22
22
|
from reflex.base import Base
|
|
23
23
|
from reflex.config import get_config
|
|
24
24
|
from reflex.utils import console
|
|
25
|
-
from reflex.utils.compat import sqlmodel
|
|
25
|
+
from reflex.utils.compat import sqlmodel, sqlmodel_field_has_primary_key
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def get_engine(url: str | None = None) -> sqlalchemy.engine.Engine:
|
|
@@ -166,8 +166,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|
|
166
166
|
non_default_primary_key_fields = [
|
|
167
167
|
field_name
|
|
168
168
|
for field_name, field in cls.__fields__.items()
|
|
169
|
-
if field_name != "id"
|
|
170
|
-
and getattr(field.field_info, "primary_key", None) is True
|
|
169
|
+
if field_name != "id" and sqlmodel_field_has_primary_key(field)
|
|
171
170
|
]
|
|
172
171
|
if non_default_primary_key_fields:
|
|
173
172
|
cls.__fields__.pop("id", None)
|
reflex/reflex.py
CHANGED
|
@@ -15,7 +15,6 @@ from reflex_cli.utils import dependency
|
|
|
15
15
|
|
|
16
16
|
from reflex import constants
|
|
17
17
|
from reflex.config import get_config
|
|
18
|
-
from reflex.constants.base import LogLevel
|
|
19
18
|
from reflex.custom_components.custom_components import custom_components_cli
|
|
20
19
|
from reflex.state import reset_disk_state_manager
|
|
21
20
|
from reflex.utils import console, redir, telemetry
|
|
@@ -115,9 +114,6 @@ def _init(
|
|
|
115
114
|
app_name, generation_hash=generation_hash
|
|
116
115
|
)
|
|
117
116
|
|
|
118
|
-
# Migrate Pynecone projects to Reflex.
|
|
119
|
-
prerequisites.migrate_to_reflex()
|
|
120
|
-
|
|
121
117
|
# Initialize the .gitignore.
|
|
122
118
|
prerequisites.initialize_gitignore()
|
|
123
119
|
|
|
@@ -247,11 +243,6 @@ def _run(
|
|
|
247
243
|
setup_frontend(Path.cwd())
|
|
248
244
|
commands.append((frontend_cmd, Path.cwd(), frontend_port, backend))
|
|
249
245
|
|
|
250
|
-
# If no loglevel is specified, set the subprocesses loglevel to WARNING.
|
|
251
|
-
subprocesses_loglevel = (
|
|
252
|
-
loglevel if loglevel != LogLevel.DEFAULT else LogLevel.WARNING
|
|
253
|
-
)
|
|
254
|
-
|
|
255
246
|
# In prod mode, run the backend on a separate thread.
|
|
256
247
|
if backend and env == constants.Env.PROD:
|
|
257
248
|
commands.append(
|
|
@@ -259,7 +250,7 @@ def _run(
|
|
|
259
250
|
backend_cmd,
|
|
260
251
|
backend_host,
|
|
261
252
|
backend_port,
|
|
262
|
-
|
|
253
|
+
loglevel.subprocess_level(),
|
|
263
254
|
frontend,
|
|
264
255
|
)
|
|
265
256
|
)
|
|
@@ -269,7 +260,7 @@ def _run(
|
|
|
269
260
|
# In dev mode, run the backend on the main thread.
|
|
270
261
|
if backend and env == constants.Env.DEV:
|
|
271
262
|
backend_cmd(
|
|
272
|
-
backend_host, int(backend_port),
|
|
263
|
+
backend_host, int(backend_port), loglevel.subprocess_level(), frontend
|
|
273
264
|
)
|
|
274
265
|
# The windows uvicorn bug workaround
|
|
275
266
|
# https://github.com/reflex-dev/reflex/issues/2335
|
|
@@ -342,7 +333,7 @@ def export(
|
|
|
342
333
|
backend=backend,
|
|
343
334
|
zip_dest_dir=zip_dest_dir,
|
|
344
335
|
upload_db_file=upload_db_file,
|
|
345
|
-
loglevel=loglevel,
|
|
336
|
+
loglevel=loglevel.subprocess_level(),
|
|
346
337
|
)
|
|
347
338
|
|
|
348
339
|
|
|
@@ -577,7 +568,7 @@ def deploy(
|
|
|
577
568
|
frontend=frontend,
|
|
578
569
|
backend=backend,
|
|
579
570
|
zipping=zipping,
|
|
580
|
-
loglevel=loglevel,
|
|
571
|
+
loglevel=loglevel.subprocess_level(),
|
|
581
572
|
upload_db_file=upload_db_file,
|
|
582
573
|
),
|
|
583
574
|
key=key,
|
|
@@ -591,7 +582,7 @@ def deploy(
|
|
|
591
582
|
interactive=interactive,
|
|
592
583
|
with_metrics=with_metrics,
|
|
593
584
|
with_tracing=with_tracing,
|
|
594
|
-
loglevel=loglevel.
|
|
585
|
+
loglevel=loglevel.subprocess_level(),
|
|
595
586
|
)
|
|
596
587
|
|
|
597
588
|
|