reflex 0.6.8a1__py3-none-any.whl → 0.7.0a1__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/custom_components/pyproject.toml.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
- reflex/.templates/web/utils/state.js +65 -36
- reflex/__init__.py +4 -17
- reflex/__init__.pyi +1 -2
- reflex/app.py +244 -115
- reflex/app_mixins/lifespan.py +9 -9
- reflex/app_mixins/middleware.py +6 -6
- reflex/app_module_for_backend.py +3 -7
- reflex/base.py +7 -7
- reflex/compiler/compiler.py +8 -0
- reflex/compiler/utils.py +35 -6
- reflex/components/base/bare.py +1 -1
- reflex/components/base/error_boundary.py +2 -1
- reflex/components/base/error_boundary.pyi +2 -1
- reflex/components/base/meta.py +2 -2
- reflex/components/base/strict_mode.py +10 -0
- reflex/components/base/strict_mode.pyi +57 -0
- reflex/components/component.py +38 -77
- reflex/components/core/banner.py +83 -4
- reflex/components/core/banner.pyi +86 -0
- reflex/components/core/breakpoints.py +3 -1
- reflex/components/core/client_side_routing.py +1 -1
- reflex/components/core/client_side_routing.pyi +1 -1
- reflex/components/core/cond.py +9 -10
- reflex/components/core/debounce.py +1 -1
- reflex/components/core/foreach.py +23 -3
- reflex/components/core/html.py +1 -1
- reflex/components/core/match.py +5 -5
- reflex/components/core/sticky.py +160 -0
- reflex/components/core/sticky.pyi +449 -0
- reflex/components/core/upload.py +2 -2
- reflex/components/datadisplay/code.py +5 -14
- reflex/components/datadisplay/dataeditor.py +7 -4
- reflex/components/datadisplay/logo.py +13 -8
- reflex/components/datadisplay/shiki_code_block.py +14 -9
- reflex/components/dynamic.py +22 -3
- reflex/components/el/constants/reflex.py +1 -1
- reflex/components/el/element.py +1 -1
- reflex/components/el/elements/forms.py +4 -4
- reflex/components/el/elements/forms.pyi +4 -4
- reflex/components/lucide/icon.py +46 -8
- reflex/components/lucide/icon.pyi +54 -0
- reflex/components/markdown/markdown.py +10 -8
- reflex/components/moment/moment.py +2 -2
- reflex/components/next/image.py +16 -4
- reflex/components/next/image.pyi +4 -2
- reflex/components/next/link.py +1 -1
- reflex/components/plotly/plotly.py +5 -5
- reflex/components/props.py +3 -3
- reflex/components/radix/__init__.pyi +1 -1
- reflex/components/radix/primitives/accordion.py +9 -5
- reflex/components/radix/primitives/accordion.pyi +3 -1
- reflex/components/radix/primitives/drawer.py +5 -2
- reflex/components/radix/primitives/drawer.pyi +4 -4
- reflex/components/radix/primitives/form.pyi +6 -6
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/themes/color_mode.py +11 -9
- reflex/components/radix/themes/components/alert_dialog.py +3 -0
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +1 -1
- reflex/components/radix/themes/components/context_menu.py +5 -0
- reflex/components/radix/themes/components/dialog.py +3 -0
- reflex/components/radix/themes/components/dropdown_menu.py +5 -0
- reflex/components/radix/themes/components/hover_card.py +3 -0
- reflex/components/radix/themes/components/icon_button.py +2 -2
- reflex/components/radix/themes/components/icon_button.pyi +1 -0
- reflex/components/radix/themes/components/popover.py +3 -0
- reflex/components/radix/themes/components/radio_cards.py +2 -0
- reflex/components/radix/themes/components/radio_group.py +1 -1
- reflex/components/radix/themes/components/select.py +3 -0
- reflex/components/radix/themes/components/tabs.py +3 -0
- reflex/components/radix/themes/components/text_area.py +12 -0
- reflex/components/radix/themes/components/text_area.pyi +2 -0
- reflex/components/radix/themes/components/text_field.py +1 -1
- reflex/components/radix/themes/components/tooltip.py +3 -1
- reflex/components/radix/themes/components/tooltip.pyi +1 -0
- reflex/components/radix/themes/layout/__init__.pyi +1 -1
- reflex/components/radix/themes/layout/list.py +2 -2
- reflex/components/radix/themes/layout/stack.py +2 -2
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/text.py +2 -2
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/recharts/__init__.py +2 -0
- reflex/components/recharts/__init__.pyi +2 -0
- reflex/components/recharts/charts.py +15 -15
- reflex/components/recharts/general.py +19 -4
- reflex/components/recharts/general.pyi +55 -4
- reflex/components/recharts/polar.py +2 -2
- reflex/components/recharts/recharts.py +4 -4
- reflex/components/sonner/toast.py +15 -13
- reflex/components/sonner/toast.pyi +6 -6
- reflex/components/suneditor/editor.py +6 -4
- reflex/components/suneditor/editor.pyi +2 -2
- reflex/components/tags/iter_tag.py +3 -3
- reflex/components/tags/tag.py +25 -3
- reflex/config.py +48 -20
- reflex/constants/__init__.py +1 -0
- reflex/constants/base.py +4 -1
- reflex/constants/compiler.py +5 -2
- reflex/constants/config.py +8 -1
- reflex/constants/installer.py +9 -9
- reflex/constants/style.py +1 -1
- reflex/custom_components/custom_components.py +9 -7
- reflex/event.py +137 -163
- reflex/experimental/__init__.py +19 -11
- reflex/experimental/client_state.py +53 -28
- reflex/experimental/hooks.py +5 -5
- reflex/experimental/layout.py +8 -5
- reflex/experimental/layout.pyi +1 -1
- reflex/experimental/misc.py +3 -3
- reflex/istate/wrappers.py +1 -1
- reflex/middleware/hydrate_middleware.py +2 -2
- reflex/model.py +11 -6
- reflex/page.py +3 -3
- reflex/reflex.py +90 -19
- reflex/route.py +1 -1
- reflex/state.py +358 -401
- reflex/style.py +27 -3
- reflex/testing.py +34 -39
- reflex/utils/build.py +6 -2
- reflex/utils/codespaces.py +1 -4
- reflex/utils/compat.py +6 -5
- reflex/utils/console.py +52 -21
- reflex/utils/exceptions.py +76 -26
- reflex/utils/exec.py +69 -74
- reflex/utils/export.py +6 -1
- reflex/utils/format.py +7 -39
- reflex/utils/imports.py +2 -2
- reflex/utils/lazy_loader.py +7 -1
- reflex/utils/path_ops.py +28 -14
- reflex/utils/prerequisites.py +324 -65
- reflex/utils/processes.py +45 -32
- reflex/utils/pyi_generator.py +30 -25
- reflex/utils/registry.py +4 -4
- reflex/utils/serializers.py +1 -1
- reflex/utils/telemetry.py +5 -4
- reflex/utils/types.py +42 -18
- reflex/vars/base.py +650 -333
- reflex/vars/datetime.py +6 -7
- reflex/vars/dep_tracking.py +344 -0
- reflex/vars/function.py +11 -5
- reflex/vars/number.py +31 -43
- reflex/vars/object.py +63 -62
- reflex/vars/sequence.py +79 -67
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/METADATA +7 -10
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/RECORD +153 -150
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/WHEEL +1 -1
- reflex/experimental/assets.py +0 -37
- reflex/proxy.py +0 -119
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/LICENSE +0 -0
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/entry_points.txt +0 -0
reflex/utils/processes.py
CHANGED
|
@@ -15,12 +15,14 @@ from typing import Callable, Generator, List, Optional, Tuple, Union
|
|
|
15
15
|
import psutil
|
|
16
16
|
import typer
|
|
17
17
|
from redis.exceptions import RedisError
|
|
18
|
+
from rich.progress import Progress
|
|
18
19
|
|
|
19
20
|
from reflex import constants
|
|
21
|
+
from reflex.config import environment
|
|
20
22
|
from reflex.utils import console, path_ops, prerequisites
|
|
21
23
|
|
|
22
24
|
|
|
23
|
-
def kill(pid):
|
|
25
|
+
def kill(pid: int):
|
|
24
26
|
"""Kill a process.
|
|
25
27
|
|
|
26
28
|
Args:
|
|
@@ -48,7 +50,7 @@ def get_num_workers() -> int:
|
|
|
48
50
|
return (os.cpu_count() or 1) * 2 + 1
|
|
49
51
|
|
|
50
52
|
|
|
51
|
-
def get_process_on_port(port) -> Optional[psutil.Process]:
|
|
53
|
+
def get_process_on_port(port: int) -> Optional[psutil.Process]:
|
|
52
54
|
"""Get the process on the given port.
|
|
53
55
|
|
|
54
56
|
Args:
|
|
@@ -62,7 +64,7 @@ def get_process_on_port(port) -> Optional[psutil.Process]:
|
|
|
62
64
|
psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess
|
|
63
65
|
):
|
|
64
66
|
if importlib.metadata.version("psutil") >= "6.0.0":
|
|
65
|
-
conns = proc.net_connections(kind="inet")
|
|
67
|
+
conns = proc.net_connections(kind="inet")
|
|
66
68
|
else:
|
|
67
69
|
conns = proc.connections(kind="inet")
|
|
68
70
|
for conn in conns:
|
|
@@ -71,7 +73,7 @@ def get_process_on_port(port) -> Optional[psutil.Process]:
|
|
|
71
73
|
return None
|
|
72
74
|
|
|
73
75
|
|
|
74
|
-
def is_process_on_port(port) -> bool:
|
|
76
|
+
def is_process_on_port(port: int) -> bool:
|
|
75
77
|
"""Check if a process is running on the given port.
|
|
76
78
|
|
|
77
79
|
Args:
|
|
@@ -83,7 +85,7 @@ def is_process_on_port(port) -> bool:
|
|
|
83
85
|
return get_process_on_port(port) is not None
|
|
84
86
|
|
|
85
87
|
|
|
86
|
-
def kill_process_on_port(port):
|
|
88
|
+
def kill_process_on_port(port: int):
|
|
87
89
|
"""Kill the process on the given port.
|
|
88
90
|
|
|
89
91
|
Args:
|
|
@@ -91,10 +93,10 @@ def kill_process_on_port(port):
|
|
|
91
93
|
"""
|
|
92
94
|
if get_process_on_port(port) is not None:
|
|
93
95
|
with contextlib.suppress(psutil.AccessDenied):
|
|
94
|
-
get_process_on_port(port).kill() #
|
|
96
|
+
get_process_on_port(port).kill() # pyright: ignore [reportOptionalMemberAccess]
|
|
95
97
|
|
|
96
98
|
|
|
97
|
-
def change_port(port:
|
|
99
|
+
def change_port(port: int, _type: str) -> int:
|
|
98
100
|
"""Change the port.
|
|
99
101
|
|
|
100
102
|
Args:
|
|
@@ -105,7 +107,7 @@ def change_port(port: str, _type: str) -> str:
|
|
|
105
107
|
The new port.
|
|
106
108
|
|
|
107
109
|
"""
|
|
108
|
-
new_port =
|
|
110
|
+
new_port = port + 1
|
|
109
111
|
if is_process_on_port(new_port):
|
|
110
112
|
return change_port(new_port, _type)
|
|
111
113
|
console.info(
|
|
@@ -114,7 +116,7 @@ def change_port(port: str, _type: str) -> str:
|
|
|
114
116
|
return new_port
|
|
115
117
|
|
|
116
118
|
|
|
117
|
-
def handle_port(service_name: str, port:
|
|
119
|
+
def handle_port(service_name: str, port: int, default_port: int) -> int:
|
|
118
120
|
"""Change port if the specified port is in use and is not explicitly specified as a CLI arg or config arg.
|
|
119
121
|
otherwise tell the user the port is in use and exit the app.
|
|
120
122
|
|
|
@@ -133,7 +135,7 @@ def handle_port(service_name: str, port: str, default_port: str) -> str:
|
|
|
133
135
|
Exit:when the port is in use.
|
|
134
136
|
"""
|
|
135
137
|
if is_process_on_port(port):
|
|
136
|
-
if
|
|
138
|
+
if port == int(default_port):
|
|
137
139
|
return change_port(port, service_name)
|
|
138
140
|
else:
|
|
139
141
|
console.error(f"{service_name.capitalize()} port: {port} is already in use")
|
|
@@ -141,7 +143,12 @@ def handle_port(service_name: str, port: str, default_port: str) -> str:
|
|
|
141
143
|
return port
|
|
142
144
|
|
|
143
145
|
|
|
144
|
-
def new_process(
|
|
146
|
+
def new_process(
|
|
147
|
+
args: str | list[str] | list[str | None] | list[str | Path | None],
|
|
148
|
+
run: bool = False,
|
|
149
|
+
show_logs: bool = False,
|
|
150
|
+
**kwargs,
|
|
151
|
+
):
|
|
145
152
|
"""Wrapper over subprocess.Popen to unify the launch of child processes.
|
|
146
153
|
|
|
147
154
|
Args:
|
|
@@ -156,24 +163,30 @@ def new_process(args, run: bool = False, show_logs: bool = False, **kwargs):
|
|
|
156
163
|
Raises:
|
|
157
164
|
Exit: When attempting to run a command with a None value.
|
|
158
165
|
"""
|
|
159
|
-
|
|
160
|
-
if
|
|
161
|
-
console.warn(
|
|
162
|
-
"The path to the Node binary could not be found. Please ensure that Node is properly "
|
|
163
|
-
"installed and added to your system's PATH environment variable or try running "
|
|
164
|
-
"`reflex init` again."
|
|
165
|
-
)
|
|
166
|
-
if None in args:
|
|
166
|
+
# Check for invalid command first.
|
|
167
|
+
if isinstance(args, list) and None in args:
|
|
167
168
|
console.error(f"Invalid command: {args}")
|
|
168
169
|
raise typer.Exit(1)
|
|
169
|
-
|
|
170
|
+
|
|
171
|
+
path_env: str = os.environ.get("PATH", "")
|
|
172
|
+
|
|
173
|
+
# Add node_bin_path to the PATH environment variable.
|
|
174
|
+
if not environment.REFLEX_BACKEND_ONLY.get():
|
|
175
|
+
node_bin_path = str(path_ops.get_node_bin_path())
|
|
176
|
+
if not node_bin_path and not prerequisites.CURRENTLY_INSTALLING_NODE:
|
|
177
|
+
console.warn(
|
|
178
|
+
"The path to the Node binary could not be found. Please ensure that Node is properly "
|
|
179
|
+
"installed and added to your system's PATH environment variable or try running "
|
|
180
|
+
"`reflex init` again."
|
|
181
|
+
)
|
|
182
|
+
path_env = os.pathsep.join([node_bin_path, path_env])
|
|
183
|
+
|
|
170
184
|
env: dict[str, str] = {
|
|
171
185
|
**os.environ,
|
|
172
|
-
"PATH":
|
|
173
|
-
[node_bin_path if node_bin_path else "", os.environ["PATH"]]
|
|
174
|
-
), # type: ignore
|
|
186
|
+
"PATH": path_env,
|
|
175
187
|
**kwargs.pop("env", {}),
|
|
176
188
|
}
|
|
189
|
+
|
|
177
190
|
kwargs = {
|
|
178
191
|
"env": env,
|
|
179
192
|
"stderr": None if show_logs else subprocess.STDOUT,
|
|
@@ -185,7 +198,7 @@ def new_process(args, run: bool = False, show_logs: bool = False, **kwargs):
|
|
|
185
198
|
}
|
|
186
199
|
console.debug(f"Running command: {args}")
|
|
187
200
|
fn = subprocess.run if run else subprocess.Popen
|
|
188
|
-
return fn(args, **kwargs)
|
|
201
|
+
return fn(args, **kwargs) # pyright: ignore [reportCallIssue, reportArgumentType]
|
|
189
202
|
|
|
190
203
|
|
|
191
204
|
@contextlib.contextmanager
|
|
@@ -206,14 +219,14 @@ def run_concurrently_context(
|
|
|
206
219
|
return
|
|
207
220
|
|
|
208
221
|
# Convert the functions to tuples.
|
|
209
|
-
fns = [fn if isinstance(fn, tuple) else (fn,) for fn in fns] #
|
|
222
|
+
fns = [fn if isinstance(fn, tuple) else (fn,) for fn in fns] # pyright: ignore [reportAssignmentType]
|
|
210
223
|
|
|
211
224
|
# Run the functions concurrently.
|
|
212
225
|
executor = None
|
|
213
226
|
try:
|
|
214
227
|
executor = futures.ThreadPoolExecutor(max_workers=len(fns))
|
|
215
228
|
# Submit the tasks.
|
|
216
|
-
tasks = [executor.submit(*fn) for fn in fns] #
|
|
229
|
+
tasks = [executor.submit(*fn) for fn in fns] # pyright: ignore [reportArgumentType]
|
|
217
230
|
|
|
218
231
|
# Yield control back to the main thread while tasks are running.
|
|
219
232
|
yield tasks
|
|
@@ -241,7 +254,7 @@ def run_concurrently(*fns: Union[Callable, Tuple]) -> None:
|
|
|
241
254
|
def stream_logs(
|
|
242
255
|
message: str,
|
|
243
256
|
process: subprocess.Popen,
|
|
244
|
-
progress=None,
|
|
257
|
+
progress: Progress | None = None,
|
|
245
258
|
suppress_errors: bool = False,
|
|
246
259
|
analytics_enabled: bool = False,
|
|
247
260
|
):
|
|
@@ -361,7 +374,7 @@ def get_command_with_loglevel(command: list[str]) -> list[str]:
|
|
|
361
374
|
The updated command list
|
|
362
375
|
"""
|
|
363
376
|
npm_path = path_ops.get_npm_path()
|
|
364
|
-
npm_path = str(
|
|
377
|
+
npm_path = str(npm_path) if npm_path else None
|
|
365
378
|
|
|
366
379
|
if command[0] == npm_path:
|
|
367
380
|
return [*command, "--loglevel", "silly"]
|
|
@@ -369,10 +382,10 @@ def get_command_with_loglevel(command: list[str]) -> list[str]:
|
|
|
369
382
|
|
|
370
383
|
|
|
371
384
|
def run_process_with_fallback(
|
|
372
|
-
args,
|
|
385
|
+
args: list[str],
|
|
373
386
|
*,
|
|
374
|
-
show_status_message,
|
|
375
|
-
fallback=None,
|
|
387
|
+
show_status_message: str,
|
|
388
|
+
fallback: str | list | None = None,
|
|
376
389
|
analytics_enabled: bool = False,
|
|
377
390
|
**kwargs,
|
|
378
391
|
):
|
|
@@ -411,7 +424,7 @@ def run_process_with_fallback(
|
|
|
411
424
|
)
|
|
412
425
|
|
|
413
426
|
|
|
414
|
-
def execute_command_and_return_output(command) -> str | None:
|
|
427
|
+
def execute_command_and_return_output(command: str) -> str | None:
|
|
415
428
|
"""Execute a command and return the output.
|
|
416
429
|
|
|
417
430
|
Args:
|
reflex/utils/pyi_generator.py
CHANGED
|
@@ -83,7 +83,7 @@ DEFAULT_IMPORTS = {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
def _walk_files(path):
|
|
86
|
+
def _walk_files(path: str | Path):
|
|
87
87
|
"""Walk all files in a path.
|
|
88
88
|
This can be replaced with Path.walk() in python3.12.
|
|
89
89
|
|
|
@@ -114,7 +114,9 @@ def _relative_to_pwd(path: Path) -> Path:
|
|
|
114
114
|
return path
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
def _get_type_hint(
|
|
117
|
+
def _get_type_hint(
|
|
118
|
+
value: Any, type_hint_globals: dict, is_optional: bool = True
|
|
119
|
+
) -> str:
|
|
118
120
|
"""Resolve the type hint for value.
|
|
119
121
|
|
|
120
122
|
Args:
|
|
@@ -229,7 +231,7 @@ def _generate_imports(
|
|
|
229
231
|
"""
|
|
230
232
|
return [
|
|
231
233
|
*[
|
|
232
|
-
ast.ImportFrom(module=name, names=[ast.alias(name=val) for val in values])
|
|
234
|
+
ast.ImportFrom(module=name, names=[ast.alias(name=val) for val in values]) # pyright: ignore [reportCallIssue]
|
|
233
235
|
for name, values in DEFAULT_IMPORTS.items()
|
|
234
236
|
],
|
|
235
237
|
ast.Import([ast.alias("reflex")]),
|
|
@@ -367,7 +369,7 @@ def _extract_class_props_as_ast_nodes(
|
|
|
367
369
|
# Try to get default from pydantic field definition.
|
|
368
370
|
default = target_class.__fields__[name].default
|
|
369
371
|
if isinstance(default, Var):
|
|
370
|
-
default = default._decode()
|
|
372
|
+
default = default._decode()
|
|
371
373
|
|
|
372
374
|
kwargs.append(
|
|
373
375
|
(
|
|
@@ -383,7 +385,7 @@ def _extract_class_props_as_ast_nodes(
|
|
|
383
385
|
return kwargs
|
|
384
386
|
|
|
385
387
|
|
|
386
|
-
def type_to_ast(typ, cls: type) -> ast.AST:
|
|
388
|
+
def type_to_ast(typ: Any, cls: type) -> ast.AST:
|
|
387
389
|
"""Converts any type annotation into its AST representation.
|
|
388
390
|
Handles nested generic types, unions, etc.
|
|
389
391
|
|
|
@@ -434,14 +436,16 @@ def type_to_ast(typ, cls: type) -> ast.AST:
|
|
|
434
436
|
if len(arg_nodes) == 1:
|
|
435
437
|
slice_value = arg_nodes[0]
|
|
436
438
|
else:
|
|
437
|
-
slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
|
|
439
|
+
slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load()) # pyright: ignore [reportArgumentType]
|
|
438
440
|
|
|
439
441
|
return ast.Subscript(
|
|
440
|
-
value=ast.Name(id=base_name),
|
|
442
|
+
value=ast.Name(id=base_name),
|
|
443
|
+
slice=ast.Index(value=slice_value), # pyright: ignore [reportArgumentType]
|
|
444
|
+
ctx=ast.Load(),
|
|
441
445
|
)
|
|
442
446
|
|
|
443
447
|
|
|
444
|
-
def _get_parent_imports(func):
|
|
448
|
+
def _get_parent_imports(func: Callable):
|
|
445
449
|
_imports = {"reflex.vars": ["Var"]}
|
|
446
450
|
for type_hint in inspect.get_annotations(func).values():
|
|
447
451
|
try:
|
|
@@ -575,7 +579,7 @@ def _generate_component_create_functiondef(
|
|
|
575
579
|
arg=trigger,
|
|
576
580
|
annotation=ast.Subscript(
|
|
577
581
|
ast.Name("Optional"),
|
|
578
|
-
ast.Index( #
|
|
582
|
+
ast.Index( # pyright: ignore [reportArgumentType]
|
|
579
583
|
value=ast.Name(
|
|
580
584
|
id=ast.unparse(
|
|
581
585
|
figure_out_return_type(
|
|
@@ -618,10 +622,10 @@ def _generate_component_create_functiondef(
|
|
|
618
622
|
defaults=[],
|
|
619
623
|
)
|
|
620
624
|
|
|
621
|
-
definition = ast.FunctionDef(
|
|
625
|
+
definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
|
|
622
626
|
name="create",
|
|
623
627
|
args=create_args,
|
|
624
|
-
body=[
|
|
628
|
+
body=[ # pyright: ignore [reportArgumentType]
|
|
625
629
|
ast.Expr(
|
|
626
630
|
value=ast.Constant(
|
|
627
631
|
value=_generate_docstrings(
|
|
@@ -630,7 +634,7 @@ def _generate_component_create_functiondef(
|
|
|
630
634
|
),
|
|
631
635
|
),
|
|
632
636
|
ast.Expr(
|
|
633
|
-
value=ast.Ellipsis
|
|
637
|
+
value=ast.Constant(value=Ellipsis),
|
|
634
638
|
),
|
|
635
639
|
],
|
|
636
640
|
decorator_list=[
|
|
@@ -641,7 +645,7 @@ def _generate_component_create_functiondef(
|
|
|
641
645
|
else [ast.Name(id="classmethod")]
|
|
642
646
|
),
|
|
643
647
|
],
|
|
644
|
-
lineno=node.lineno if node is not None else None,
|
|
648
|
+
lineno=node.lineno if node is not None else None, # pyright: ignore [reportArgumentType]
|
|
645
649
|
returns=ast.Constant(value=clz.__name__),
|
|
646
650
|
)
|
|
647
651
|
return definition
|
|
@@ -680,7 +684,7 @@ def _generate_staticmethod_call_functiondef(
|
|
|
680
684
|
else []
|
|
681
685
|
),
|
|
682
686
|
)
|
|
683
|
-
definition = ast.FunctionDef(
|
|
687
|
+
definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
|
|
684
688
|
name="__call__",
|
|
685
689
|
args=call_args,
|
|
686
690
|
body=[
|
|
@@ -690,11 +694,12 @@ def _generate_staticmethod_call_functiondef(
|
|
|
690
694
|
),
|
|
691
695
|
],
|
|
692
696
|
decorator_list=[ast.Name(id="staticmethod")],
|
|
693
|
-
lineno=node.lineno if node is not None else None,
|
|
697
|
+
lineno=node.lineno if node is not None else None, # pyright: ignore [reportArgumentType]
|
|
694
698
|
returns=ast.Constant(
|
|
695
699
|
value=_get_type_hint(
|
|
696
700
|
typing.get_type_hints(clz.__call__).get("return", None),
|
|
697
701
|
type_hint_globals,
|
|
702
|
+
is_optional=False,
|
|
698
703
|
)
|
|
699
704
|
),
|
|
700
705
|
)
|
|
@@ -726,17 +731,17 @@ def _generate_namespace_call_functiondef(
|
|
|
726
731
|
clz = classes[clz_name]
|
|
727
732
|
|
|
728
733
|
if not hasattr(clz.__call__, "__self__"):
|
|
729
|
-
return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals) #
|
|
734
|
+
return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals) # pyright: ignore [reportArgumentType]
|
|
730
735
|
|
|
731
736
|
# Determine which class is wrapped by the namespace __call__ method
|
|
732
737
|
component_clz = clz.__call__.__self__
|
|
733
738
|
|
|
734
|
-
if clz.__call__.__func__.__name__ != "create":
|
|
739
|
+
if clz.__call__.__func__.__name__ != "create": # pyright: ignore [reportFunctionMemberAccess]
|
|
735
740
|
return None
|
|
736
741
|
|
|
737
742
|
definition = _generate_component_create_functiondef(
|
|
738
743
|
node=None,
|
|
739
|
-
clz=component_clz, #
|
|
744
|
+
clz=component_clz, # pyright: ignore [reportArgumentType]
|
|
740
745
|
type_hint_globals=type_hint_globals,
|
|
741
746
|
)
|
|
742
747
|
definition.name = "__call__"
|
|
@@ -816,7 +821,7 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
816
821
|
The modified Module node.
|
|
817
822
|
"""
|
|
818
823
|
self.generic_visit(node)
|
|
819
|
-
return self._remove_docstring(node) #
|
|
824
|
+
return self._remove_docstring(node) # pyright: ignore [reportReturnType]
|
|
820
825
|
|
|
821
826
|
def visit_Import(
|
|
822
827
|
self, node: ast.Import | ast.ImportFrom
|
|
@@ -914,7 +919,7 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
914
919
|
node.body.append(call_definition)
|
|
915
920
|
if not node.body:
|
|
916
921
|
# We should never return an empty body.
|
|
917
|
-
node.body.append(ast.Expr(value=ast.Ellipsis
|
|
922
|
+
node.body.append(ast.Expr(value=ast.Constant(value=Ellipsis)))
|
|
918
923
|
self.current_class = None
|
|
919
924
|
return node
|
|
920
925
|
|
|
@@ -941,9 +946,9 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
941
946
|
if node.name.startswith("_") and node.name != "__call__":
|
|
942
947
|
return None # remove private methods
|
|
943
948
|
|
|
944
|
-
if node.body[-1] != ast.Expr(value=ast.Ellipsis
|
|
949
|
+
if node.body[-1] != ast.Expr(value=ast.Constant(value=Ellipsis)):
|
|
945
950
|
# Blank out the function body for public functions.
|
|
946
|
-
node.body = [ast.Expr(value=ast.Ellipsis
|
|
951
|
+
node.body = [ast.Expr(value=ast.Constant(value=Ellipsis))]
|
|
947
952
|
return node
|
|
948
953
|
|
|
949
954
|
def visit_Assign(self, node: ast.Assign) -> ast.Assign | None:
|
|
@@ -1050,7 +1055,7 @@ class PyiGenerator:
|
|
|
1050
1055
|
pyi_path.write_text(pyi_content)
|
|
1051
1056
|
logger.info(f"Wrote {relpath}")
|
|
1052
1057
|
|
|
1053
|
-
def _get_init_lazy_imports(self, mod, new_tree):
|
|
1058
|
+
def _get_init_lazy_imports(self, mod: tuple | ModuleType, new_tree: ast.AST):
|
|
1054
1059
|
# retrieve the _SUBMODULES and _SUBMOD_ATTRS from an init file if present.
|
|
1055
1060
|
sub_mods = getattr(mod, "_SUBMODULES", None)
|
|
1056
1061
|
sub_mod_attrs = getattr(mod, "_SUBMOD_ATTRS", None)
|
|
@@ -1077,7 +1082,7 @@ class PyiGenerator:
|
|
|
1077
1082
|
+ (
|
|
1078
1083
|
" # type: ignore"
|
|
1079
1084
|
if mod in pyright_ignore_imports
|
|
1080
|
-
else " # noqa" # ignore ruff formatting here for cases like rx.list.
|
|
1085
|
+
else " # noqa: F401" # ignore ruff formatting here for cases like rx.list.
|
|
1081
1086
|
if isinstance(mod, tuple)
|
|
1082
1087
|
else ""
|
|
1083
1088
|
)
|
|
@@ -1136,7 +1141,7 @@ class PyiGenerator:
|
|
|
1136
1141
|
if pyi_path:
|
|
1137
1142
|
self.written_files.append(pyi_path)
|
|
1138
1143
|
|
|
1139
|
-
def scan_all(self, targets, changed_files: list[Path] | None = None):
|
|
1144
|
+
def scan_all(self, targets: list, changed_files: list[Path] | None = None):
|
|
1140
1145
|
"""Scan all targets for class inheriting Component and generate the .pyi files.
|
|
1141
1146
|
|
|
1142
1147
|
Args:
|
reflex/utils/registry.py
CHANGED
|
@@ -22,15 +22,15 @@ def latency(registry: str) -> int:
|
|
|
22
22
|
return 10_000_000
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def average_latency(registry, attempts: int = 3) -> int:
|
|
25
|
+
def average_latency(registry: str, attempts: int = 3) -> int:
|
|
26
26
|
"""Get the average latency of a registry.
|
|
27
27
|
|
|
28
28
|
Args:
|
|
29
|
-
registry
|
|
30
|
-
attempts
|
|
29
|
+
registry: The URL of the registry.
|
|
30
|
+
attempts: The number of attempts to make. Defaults to 10.
|
|
31
31
|
|
|
32
32
|
Returns:
|
|
33
|
-
|
|
33
|
+
The average latency of the registry in microseconds.
|
|
34
34
|
"""
|
|
35
35
|
return sum(latency(registry) for _ in range(attempts)) // attempts
|
|
36
36
|
|
reflex/utils/serializers.py
CHANGED
|
@@ -476,7 +476,7 @@ try:
|
|
|
476
476
|
base64_image = base64.b64encode(image_bytes).decode("utf-8")
|
|
477
477
|
try:
|
|
478
478
|
# Newer method to get the mime type, but does not always work.
|
|
479
|
-
mime_type = image.get_format_mimetype() #
|
|
479
|
+
mime_type = image.get_format_mimetype() # pyright: ignore [reportAttributeAccessIssue]
|
|
480
480
|
except AttributeError:
|
|
481
481
|
try:
|
|
482
482
|
# Fallback method
|
reflex/utils/telemetry.py
CHANGED
|
@@ -122,7 +122,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
|
|
|
122
122
|
return {}
|
|
123
123
|
|
|
124
124
|
if UTC is None:
|
|
125
|
-
# for python 3.
|
|
125
|
+
# for python 3.10
|
|
126
126
|
stamp = datetime.utcnow().isoformat()
|
|
127
127
|
else:
|
|
128
128
|
# for python 3.11 & 3.12
|
|
@@ -156,12 +156,13 @@ def _prepare_event(event: str, **kwargs) -> dict:
|
|
|
156
156
|
def _send_event(event_data: dict) -> bool:
|
|
157
157
|
try:
|
|
158
158
|
httpx.post(POSTHOG_API_URL, json=event_data)
|
|
159
|
-
return True
|
|
160
159
|
except Exception:
|
|
161
160
|
return False
|
|
161
|
+
else:
|
|
162
|
+
return True
|
|
162
163
|
|
|
163
164
|
|
|
164
|
-
def _send(event, telemetry_enabled, **kwargs):
|
|
165
|
+
def _send(event: str, telemetry_enabled: bool | None, **kwargs):
|
|
165
166
|
from reflex.config import get_config
|
|
166
167
|
|
|
167
168
|
# Get the telemetry_enabled from the config if it is not specified.
|
|
@@ -188,7 +189,7 @@ def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
|
|
|
188
189
|
kwargs: Additional data to send with the event.
|
|
189
190
|
"""
|
|
190
191
|
|
|
191
|
-
async def async_send(event, telemetry_enabled, **kwargs):
|
|
192
|
+
async def async_send(event: str, telemetry_enabled: bool | None, **kwargs):
|
|
192
193
|
return _send(event, telemetry_enabled, **kwargs)
|
|
193
194
|
|
|
194
195
|
try:
|
reflex/utils/types.py
CHANGED
|
@@ -24,7 +24,7 @@ from typing import (
|
|
|
24
24
|
Tuple,
|
|
25
25
|
Type,
|
|
26
26
|
Union,
|
|
27
|
-
_GenericAlias, #
|
|
27
|
+
_GenericAlias, # pyright: ignore [reportAttributeAccessIssue]
|
|
28
28
|
get_args,
|
|
29
29
|
get_type_hints,
|
|
30
30
|
)
|
|
@@ -39,7 +39,9 @@ from reflex.components.core.breakpoints import Breakpoints
|
|
|
39
39
|
try:
|
|
40
40
|
from pydantic.v1.fields import ModelField
|
|
41
41
|
except ModuleNotFoundError:
|
|
42
|
-
from pydantic.fields import
|
|
42
|
+
from pydantic.fields import (
|
|
43
|
+
ModelField, # pyright: ignore [reportAttributeAccessIssue]
|
|
44
|
+
)
|
|
43
45
|
|
|
44
46
|
from sqlalchemy.ext.associationproxy import AssociationProxyInstance
|
|
45
47
|
from sqlalchemy.ext.hybrid import hybrid_property
|
|
@@ -70,13 +72,15 @@ GenericAliasTypes = [_GenericAlias]
|
|
|
70
72
|
|
|
71
73
|
with contextlib.suppress(ImportError):
|
|
72
74
|
# For newer versions of Python.
|
|
73
|
-
from types import GenericAlias
|
|
75
|
+
from types import GenericAlias
|
|
74
76
|
|
|
75
77
|
GenericAliasTypes.append(GenericAlias)
|
|
76
78
|
|
|
77
79
|
with contextlib.suppress(ImportError):
|
|
78
80
|
# For older versions of Python.
|
|
79
|
-
from typing import
|
|
81
|
+
from typing import (
|
|
82
|
+
_SpecialGenericAlias, # pyright: ignore [reportAttributeAccessIssue]
|
|
83
|
+
)
|
|
80
84
|
|
|
81
85
|
GenericAliasTypes.append(_SpecialGenericAlias)
|
|
82
86
|
|
|
@@ -153,7 +157,7 @@ class Unset:
|
|
|
153
157
|
|
|
154
158
|
|
|
155
159
|
@lru_cache()
|
|
156
|
-
def get_origin(tp):
|
|
160
|
+
def get_origin(tp: Any):
|
|
157
161
|
"""Get the origin of a class.
|
|
158
162
|
|
|
159
163
|
Args:
|
|
@@ -175,7 +179,7 @@ def is_generic_alias(cls: GenericType) -> bool:
|
|
|
175
179
|
Returns:
|
|
176
180
|
Whether the class is a generic alias.
|
|
177
181
|
"""
|
|
178
|
-
return isinstance(cls, GenericAliasTypes)
|
|
182
|
+
return isinstance(cls, GenericAliasTypes) # pyright: ignore [reportArgumentType]
|
|
179
183
|
|
|
180
184
|
|
|
181
185
|
def unionize(*args: GenericType) -> Type:
|
|
@@ -188,14 +192,14 @@ def unionize(*args: GenericType) -> Type:
|
|
|
188
192
|
The unionized types.
|
|
189
193
|
"""
|
|
190
194
|
if not args:
|
|
191
|
-
return Any
|
|
195
|
+
return Any # pyright: ignore [reportReturnType]
|
|
192
196
|
if len(args) == 1:
|
|
193
197
|
return args[0]
|
|
194
198
|
# We are bisecting the args list here to avoid hitting the recursion limit
|
|
195
199
|
# In Python versions >= 3.11, we can simply do `return Union[*args]`
|
|
196
200
|
midpoint = len(args) // 2
|
|
197
201
|
first_half, second_half = args[:midpoint], args[midpoint:]
|
|
198
|
-
return Union[unionize(*first_half), unionize(*second_half)]
|
|
202
|
+
return Union[unionize(*first_half), unionize(*second_half)] # pyright: ignore [reportReturnType]
|
|
199
203
|
|
|
200
204
|
|
|
201
205
|
def is_none(cls: GenericType) -> bool:
|
|
@@ -236,7 +240,7 @@ def is_literal(cls: GenericType) -> bool:
|
|
|
236
240
|
return get_origin(cls) is Literal
|
|
237
241
|
|
|
238
242
|
|
|
239
|
-
def has_args(cls) -> bool:
|
|
243
|
+
def has_args(cls: Type) -> bool:
|
|
240
244
|
"""Check if the class has generic parameters.
|
|
241
245
|
|
|
242
246
|
Args:
|
|
@@ -351,13 +355,13 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
|
|
|
351
355
|
if type_ is not None:
|
|
352
356
|
if hasattr(column_type, "item_type"):
|
|
353
357
|
try:
|
|
354
|
-
item_type = column_type.item_type.python_type #
|
|
358
|
+
item_type = column_type.item_type.python_type # pyright: ignore [reportAttributeAccessIssue]
|
|
355
359
|
except NotImplementedError:
|
|
356
360
|
item_type = None
|
|
357
361
|
if item_type is not None:
|
|
358
362
|
if type_ in PrimitiveToAnnotation:
|
|
359
|
-
type_ = PrimitiveToAnnotation[type_]
|
|
360
|
-
type_ = type_[item_type] #
|
|
363
|
+
type_ = PrimitiveToAnnotation[type_]
|
|
364
|
+
type_ = type_[item_type] # pyright: ignore [reportIndexIssue]
|
|
361
365
|
if column.nullable:
|
|
362
366
|
type_ = Optional[type_]
|
|
363
367
|
return type_
|
|
@@ -432,7 +436,7 @@ def get_base_class(cls: GenericType) -> Type:
|
|
|
432
436
|
return type(get_args(cls)[0])
|
|
433
437
|
|
|
434
438
|
if is_union(cls):
|
|
435
|
-
return tuple(get_base_class(arg) for arg in get_args(cls))
|
|
439
|
+
return tuple(get_base_class(arg) for arg in get_args(cls)) # pyright: ignore [reportReturnType]
|
|
436
440
|
|
|
437
441
|
return get_base_class(cls.__origin__) if is_generic_alias(cls) else cls
|
|
438
442
|
|
|
@@ -605,7 +609,9 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
|
|
|
605
609
|
return (
|
|
606
610
|
isinstance(obj, tuple)
|
|
607
611
|
and len(obj) == len(args)
|
|
608
|
-
and all(
|
|
612
|
+
and all(
|
|
613
|
+
_isinstance(item, arg) for item, arg in zip(obj, args, strict=True)
|
|
614
|
+
)
|
|
609
615
|
)
|
|
610
616
|
if origin in (dict, Breakpoints):
|
|
611
617
|
return isinstance(obj, dict) and all(
|
|
@@ -747,7 +753,7 @@ def check_prop_in_allowed_types(prop: Any, allowed_types: Iterable) -> bool:
|
|
|
747
753
|
return type_ in allowed_types
|
|
748
754
|
|
|
749
755
|
|
|
750
|
-
def is_encoded_fstring(value) -> bool:
|
|
756
|
+
def is_encoded_fstring(value: Any) -> bool:
|
|
751
757
|
"""Check if a value is an encoded Var f-string.
|
|
752
758
|
|
|
753
759
|
Args:
|
|
@@ -790,7 +796,7 @@ def validate_literal(key: str, value: Any, expected_type: Type, comp_name: str):
|
|
|
790
796
|
)
|
|
791
797
|
|
|
792
798
|
|
|
793
|
-
def validate_parameter_literals(func):
|
|
799
|
+
def validate_parameter_literals(func: Callable):
|
|
794
800
|
"""Decorator to check that the arguments passed to a function
|
|
795
801
|
correspond to the correct function parameter if it (the parameter)
|
|
796
802
|
is a literal type.
|
|
@@ -808,7 +814,7 @@ def validate_parameter_literals(func):
|
|
|
808
814
|
annotations = {param[0]: param[1].annotation for param in func_params}
|
|
809
815
|
|
|
810
816
|
# validate args
|
|
811
|
-
for param, arg in zip(annotations, args):
|
|
817
|
+
for param, arg in zip(annotations, args, strict=False):
|
|
812
818
|
if annotations[param] is inspect.Parameter.empty:
|
|
813
819
|
continue
|
|
814
820
|
validate_literal(param, arg, annotations[param], func.__name__)
|
|
@@ -829,6 +835,22 @@ StateBases = get_base_class(StateVar)
|
|
|
829
835
|
StateIterBases = get_base_class(StateIterVar)
|
|
830
836
|
|
|
831
837
|
|
|
838
|
+
def safe_issubclass(cls: Type, cls_check: Type | Tuple[Type, ...]):
|
|
839
|
+
"""Check if a class is a subclass of another class. Returns False if internal error occurs.
|
|
840
|
+
|
|
841
|
+
Args:
|
|
842
|
+
cls: The class to check.
|
|
843
|
+
cls_check: The class to check against.
|
|
844
|
+
|
|
845
|
+
Returns:
|
|
846
|
+
Whether the class is a subclass of the other class.
|
|
847
|
+
"""
|
|
848
|
+
try:
|
|
849
|
+
return issubclass(cls, cls_check)
|
|
850
|
+
except TypeError:
|
|
851
|
+
return False
|
|
852
|
+
|
|
853
|
+
|
|
832
854
|
def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> bool:
|
|
833
855
|
"""Check if a type hint is a subclass of another type hint.
|
|
834
856
|
|
|
@@ -890,6 +912,8 @@ def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> boo
|
|
|
890
912
|
# It also ignores when the length of the arguments is different
|
|
891
913
|
return all(
|
|
892
914
|
typehint_issubclass(provided_arg, accepted_arg)
|
|
893
|
-
for provided_arg, accepted_arg in zip(
|
|
915
|
+
for provided_arg, accepted_arg in zip(
|
|
916
|
+
provided_args, accepted_args, strict=False
|
|
917
|
+
)
|
|
894
918
|
if accepted_arg is not Any
|
|
895
919
|
)
|