reflex 0.7.8__py3-none-any.whl → 0.7.9__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/tailwind.config.js.jinja2 +65 -31
- reflex/.templates/web/utils/state.js +11 -1
- reflex/app.py +191 -87
- reflex/app_mixins/lifespan.py +2 -2
- reflex/compiler/compiler.py +31 -4
- reflex/components/component.py +39 -57
- reflex/components/core/upload.py +8 -0
- reflex/components/dynamic.py +9 -1
- reflex/components/markdown/markdown.py +0 -21
- reflex/components/radix/primitives/accordion.py +1 -1
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/themes/color_mode.py +1 -1
- reflex/components/radix/themes/color_mode.pyi +1 -1
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/sonner/toast.py +1 -1
- reflex/config.py +4 -7
- reflex/constants/base.py +21 -0
- reflex/constants/installer.py +6 -6
- reflex/custom_components/custom_components.py +67 -64
- reflex/event.py +2 -0
- reflex/page.py +8 -0
- reflex/reflex.py +277 -265
- reflex/testing.py +30 -24
- reflex/utils/codespaces.py +6 -2
- reflex/utils/console.py +4 -3
- reflex/utils/exec.py +60 -24
- reflex/utils/format.py +17 -2
- reflex/utils/prerequisites.py +43 -30
- reflex/utils/processes.py +6 -6
- reflex/utils/types.py +11 -6
- reflex/vars/base.py +19 -1
- {reflex-0.7.8.dist-info → reflex-0.7.9.dist-info}/METADATA +6 -9
- {reflex-0.7.8.dist-info → reflex-0.7.9.dist-info}/RECORD +38 -38
- {reflex-0.7.8.dist-info → reflex-0.7.9.dist-info}/WHEEL +0 -0
- {reflex-0.7.8.dist-info → reflex-0.7.9.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.8.dist-info → reflex-0.7.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -9,17 +9,46 @@ import sys
|
|
|
9
9
|
from collections import namedtuple
|
|
10
10
|
from contextlib import contextmanager
|
|
11
11
|
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
12
13
|
|
|
14
|
+
import click
|
|
13
15
|
import httpx
|
|
14
|
-
import typer
|
|
15
16
|
|
|
16
17
|
from reflex import constants
|
|
17
|
-
from reflex.config import get_config
|
|
18
18
|
from reflex.constants import CustomComponents
|
|
19
19
|
from reflex.utils import console
|
|
20
20
|
|
|
21
|
-
custom_components_cli = typer.Typer()
|
|
22
21
|
|
|
22
|
+
def set_loglevel(ctx: Any, self: Any, value: str | None):
|
|
23
|
+
"""Set the log level.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
ctx: The click context.
|
|
27
|
+
self: The click command.
|
|
28
|
+
value: The log level to set.
|
|
29
|
+
"""
|
|
30
|
+
if value is not None:
|
|
31
|
+
loglevel = constants.LogLevel.from_string(value)
|
|
32
|
+
console.set_log_level(loglevel)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@click.group
|
|
36
|
+
def custom_components_cli():
|
|
37
|
+
"""CLI for creating custom components."""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
loglevel_option = click.option(
|
|
42
|
+
"--loglevel",
|
|
43
|
+
type=click.Choice(
|
|
44
|
+
[loglevel.value for loglevel in constants.LogLevel],
|
|
45
|
+
case_sensitive=False,
|
|
46
|
+
),
|
|
47
|
+
callback=set_loglevel,
|
|
48
|
+
is_eager=True,
|
|
49
|
+
expose_value=False,
|
|
50
|
+
help="The log level to use.",
|
|
51
|
+
)
|
|
23
52
|
|
|
24
53
|
POST_CUSTOM_COMPONENTS_GALLERY_TIMEOUT = 15
|
|
25
54
|
|
|
@@ -163,13 +192,13 @@ def _get_default_library_name_parts() -> list[str]:
|
|
|
163
192
|
console.error(
|
|
164
193
|
f"Based on current directory name {current_dir_name}, the library name is {constants.Reflex.MODULE_NAME}. This package already exists. Please use --library-name to specify a different name."
|
|
165
194
|
)
|
|
166
|
-
raise
|
|
195
|
+
raise click.exceptions.Exit(code=1)
|
|
167
196
|
if not parts:
|
|
168
197
|
# The folder likely has a name not suitable for python paths.
|
|
169
198
|
console.error(
|
|
170
199
|
f"Could not find a valid library name based on the current directory: got {current_dir_name}."
|
|
171
200
|
)
|
|
172
|
-
raise
|
|
201
|
+
raise click.exceptions.Exit(code=1)
|
|
173
202
|
return parts
|
|
174
203
|
|
|
175
204
|
|
|
@@ -205,7 +234,7 @@ def _validate_library_name(library_name: str | None) -> NameVariants:
|
|
|
205
234
|
console.error(
|
|
206
235
|
f"Please use only alphanumeric characters or dashes: got {library_name}"
|
|
207
236
|
)
|
|
208
|
-
raise
|
|
237
|
+
raise click.exceptions.Exit(code=1)
|
|
209
238
|
|
|
210
239
|
# If not specified, use the current directory name to form the module name.
|
|
211
240
|
name_parts = (
|
|
@@ -277,36 +306,35 @@ def _populate_custom_component_project(name_variants: NameVariants):
|
|
|
277
306
|
|
|
278
307
|
|
|
279
308
|
@custom_components_cli.command(name="init")
|
|
309
|
+
@click.option(
|
|
310
|
+
"--library-name",
|
|
311
|
+
default=None,
|
|
312
|
+
help="The name of your library. On PyPI, package will be published as `reflex-{library-name}`.",
|
|
313
|
+
)
|
|
314
|
+
@click.option(
|
|
315
|
+
"--install/--no-install",
|
|
316
|
+
default=True,
|
|
317
|
+
help="Whether to install package from this local custom component in editable mode.",
|
|
318
|
+
)
|
|
319
|
+
@loglevel_option
|
|
280
320
|
def init(
|
|
281
|
-
library_name: str | None
|
|
282
|
-
|
|
283
|
-
help="The name of your library. On PyPI, package will be published as `reflex-{library-name}`.",
|
|
284
|
-
),
|
|
285
|
-
install: bool = typer.Option(
|
|
286
|
-
True,
|
|
287
|
-
help="Whether to install package from this local custom component in editable mode.",
|
|
288
|
-
),
|
|
289
|
-
loglevel: constants.LogLevel | None = typer.Option(
|
|
290
|
-
None, help="The log level to use."
|
|
291
|
-
),
|
|
321
|
+
library_name: str | None,
|
|
322
|
+
install: bool,
|
|
292
323
|
):
|
|
293
324
|
"""Initialize a custom component.
|
|
294
325
|
|
|
295
326
|
Args:
|
|
296
327
|
library_name: The name of the library.
|
|
297
328
|
install: Whether to install package from this local custom component in editable mode.
|
|
298
|
-
loglevel: The log level to use.
|
|
299
329
|
|
|
300
330
|
Raises:
|
|
301
331
|
Exit: If the pyproject.toml already exists.
|
|
302
332
|
"""
|
|
303
333
|
from reflex.utils import exec, prerequisites
|
|
304
334
|
|
|
305
|
-
console.set_log_level(loglevel or get_config().loglevel)
|
|
306
|
-
|
|
307
335
|
if CustomComponents.PYPROJECT_TOML.exists():
|
|
308
336
|
console.error(f"A {CustomComponents.PYPROJECT_TOML} already exists. Aborting.")
|
|
309
|
-
|
|
337
|
+
click.exceptions.Exit(code=1)
|
|
310
338
|
|
|
311
339
|
# Show system info.
|
|
312
340
|
exec.output_system_info()
|
|
@@ -331,7 +359,7 @@ def init(
|
|
|
331
359
|
if _pip_install_on_demand(package_name=".", install_args=["-e"]):
|
|
332
360
|
console.info(f"Package {package_name} installed!")
|
|
333
361
|
else:
|
|
334
|
-
raise
|
|
362
|
+
raise click.exceptions.Exit(code=1)
|
|
335
363
|
|
|
336
364
|
console.print("[bold]Custom component initialized successfully!")
|
|
337
365
|
console.rule("[bold]Project Summary")
|
|
@@ -424,21 +452,13 @@ def _run_build():
|
|
|
424
452
|
if _run_commands_in_subprocess(cmds):
|
|
425
453
|
console.info("Custom component built successfully!")
|
|
426
454
|
else:
|
|
427
|
-
raise
|
|
455
|
+
raise click.exceptions.Exit(code=1)
|
|
428
456
|
|
|
429
457
|
|
|
430
458
|
@custom_components_cli.command(name="build")
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
),
|
|
435
|
-
):
|
|
436
|
-
"""Build a custom component. Must be run from the project root directory where the pyproject.toml is.
|
|
437
|
-
|
|
438
|
-
Args:
|
|
439
|
-
loglevel: The log level to use.
|
|
440
|
-
"""
|
|
441
|
-
console.set_log_level(loglevel or get_config().loglevel)
|
|
459
|
+
@loglevel_option
|
|
460
|
+
def build():
|
|
461
|
+
"""Build a custom component. Must be run from the project root directory where the pyproject.toml is."""
|
|
442
462
|
_run_build()
|
|
443
463
|
|
|
444
464
|
|
|
@@ -453,7 +473,7 @@ def publish():
|
|
|
453
473
|
"The publish command is deprecated. You can use `reflex component build` followed by `twine upload` or a similar publishing command to publish your custom component."
|
|
454
474
|
"\nIf you want to share your custom component with the Reflex community, please use `reflex component share`."
|
|
455
475
|
)
|
|
456
|
-
raise
|
|
476
|
+
raise click.exceptions.Exit(code=1)
|
|
457
477
|
|
|
458
478
|
|
|
459
479
|
def _collect_details_for_gallery():
|
|
@@ -472,7 +492,7 @@ def _collect_details_for_gallery():
|
|
|
472
492
|
console.error(
|
|
473
493
|
"Unable to authenticate with Reflex backend services. Make sure you are logged in."
|
|
474
494
|
)
|
|
475
|
-
raise
|
|
495
|
+
raise click.exceptions.Exit(code=1)
|
|
476
496
|
|
|
477
497
|
console.rule("[bold]Custom Component Information")
|
|
478
498
|
params = {}
|
|
@@ -502,11 +522,11 @@ def _collect_details_for_gallery():
|
|
|
502
522
|
console.error(
|
|
503
523
|
f"{package_name} is owned by another user. Unable to update the information for it."
|
|
504
524
|
)
|
|
505
|
-
raise
|
|
525
|
+
raise click.exceptions.Exit(code=1)
|
|
506
526
|
response.raise_for_status()
|
|
507
527
|
except httpx.HTTPError as he:
|
|
508
528
|
console.error(f"Unable to complete request due to {he}.")
|
|
509
|
-
raise
|
|
529
|
+
raise click.exceptions.Exit(code=1) from he
|
|
510
530
|
|
|
511
531
|
files = []
|
|
512
532
|
if (image_file_and_extension := _get_file_from_prompt_in_loop()) is not None:
|
|
@@ -541,7 +561,7 @@ def _collect_details_for_gallery():
|
|
|
541
561
|
|
|
542
562
|
except httpx.HTTPError as he:
|
|
543
563
|
console.error(f"Unable to complete request due to {he}.")
|
|
544
|
-
raise
|
|
564
|
+
raise click.exceptions.Exit(code=1) from he
|
|
545
565
|
|
|
546
566
|
console.info("Custom component information successfully shared!")
|
|
547
567
|
|
|
@@ -577,7 +597,7 @@ def _get_file_from_prompt_in_loop() -> tuple[bytes, str] | None:
|
|
|
577
597
|
image_file = image_file_path.read_bytes()
|
|
578
598
|
except OSError as ose:
|
|
579
599
|
console.error(f"Unable to read the {file_extension} file due to {ose}")
|
|
580
|
-
raise
|
|
600
|
+
raise click.exceptions.Exit(code=1) from ose
|
|
581
601
|
else:
|
|
582
602
|
return image_file, file_extension
|
|
583
603
|
|
|
@@ -586,38 +606,21 @@ def _get_file_from_prompt_in_loop() -> tuple[bytes, str] | None:
|
|
|
586
606
|
|
|
587
607
|
|
|
588
608
|
@custom_components_cli.command(name="share")
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
),
|
|
593
|
-
):
|
|
594
|
-
"""Collect more details on the published package for gallery.
|
|
595
|
-
|
|
596
|
-
Args:
|
|
597
|
-
loglevel: The log level to use.
|
|
598
|
-
"""
|
|
599
|
-
console.set_log_level(loglevel or get_config().loglevel)
|
|
600
|
-
|
|
609
|
+
@loglevel_option
|
|
610
|
+
def share_more_detail():
|
|
611
|
+
"""Collect more details on the published package for gallery."""
|
|
601
612
|
_collect_details_for_gallery()
|
|
602
613
|
|
|
603
614
|
|
|
604
|
-
@custom_components_cli.command()
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
None, help="The log level to use."
|
|
608
|
-
),
|
|
609
|
-
):
|
|
615
|
+
@custom_components_cli.command(name="install")
|
|
616
|
+
@loglevel_option
|
|
617
|
+
def install():
|
|
610
618
|
"""Install package from this local custom component in editable mode.
|
|
611
619
|
|
|
612
|
-
Args:
|
|
613
|
-
loglevel: The log level to use.
|
|
614
|
-
|
|
615
620
|
Raises:
|
|
616
621
|
Exit: If unable to install the current directory in editable mode.
|
|
617
622
|
"""
|
|
618
|
-
console.set_log_level(loglevel or get_config().loglevel)
|
|
619
|
-
|
|
620
623
|
if _pip_install_on_demand(package_name=".", install_args=["-e"]):
|
|
621
624
|
console.info("Package installed successfully!")
|
|
622
625
|
else:
|
|
623
|
-
raise
|
|
626
|
+
raise click.exceptions.Exit(code=1)
|
reflex/event.py
CHANGED
|
@@ -2064,6 +2064,8 @@ class EventNamespace:
|
|
|
2064
2064
|
"Background task must be async function or generator."
|
|
2065
2065
|
)
|
|
2066
2066
|
setattr(func, BACKGROUND_TASK_MARKER, True)
|
|
2067
|
+
if getattr(func, "__name__", "").startswith("_"):
|
|
2068
|
+
raise ValueError("Event handlers cannot be private.")
|
|
2067
2069
|
return func # pyright: ignore [reportReturnType]
|
|
2068
2070
|
|
|
2069
2071
|
if func is not None:
|
reflex/page.py
CHANGED
|
@@ -8,6 +8,7 @@ from typing import Any
|
|
|
8
8
|
|
|
9
9
|
from reflex.config import get_config
|
|
10
10
|
from reflex.event import EventType
|
|
11
|
+
from reflex.utils import console
|
|
11
12
|
|
|
12
13
|
DECORATED_PAGES: dict[str, list] = defaultdict(list)
|
|
13
14
|
|
|
@@ -76,6 +77,13 @@ def get_decorated_pages(omit_implicit_routes: bool = True) -> list[dict[str, Any
|
|
|
76
77
|
Returns:
|
|
77
78
|
The decorated pages.
|
|
78
79
|
"""
|
|
80
|
+
console.deprecate(
|
|
81
|
+
"get_decorated_pages",
|
|
82
|
+
reason="This function is deprecated and will be removed in a future version.",
|
|
83
|
+
deprecation_version="0.7.9",
|
|
84
|
+
removal_version="0.8.0",
|
|
85
|
+
dedupe=True,
|
|
86
|
+
)
|
|
79
87
|
return sorted(
|
|
80
88
|
[
|
|
81
89
|
page_data
|