reflex 0.7.4a0__py3-none-any.whl → 0.7.4a1__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/app.py +16 -0
- reflex/compiler/compiler.py +2 -4
- reflex/components/core/client_side_routing.py +3 -3
- reflex/components/core/cond.py +20 -12
- reflex/components/dynamic.py +2 -4
- reflex/components/lucide/icon.py +20 -27
- reflex/config.py +17 -17
- reflex/custom_components/custom_components.py +8 -3
- reflex/reflex.py +18 -4
- reflex/state.py +1 -0
- reflex/utils/exec.py +136 -60
- reflex/utils/prerequisites.py +20 -1
- reflex/utils/processes.py +4 -4
- reflex/vars/base.py +2 -3
- reflex/vars/sequence.py +84 -0
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a1.dist-info}/METADATA +3 -3
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a1.dist-info}/RECORD +20 -21
- reflex/app_module_for_backend.py +0 -33
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a1.dist-info}/WHEEL +0 -0
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.4a0.dist-info → reflex-0.7.4a1.dist-info}/licenses/LICENSE +0 -0
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):
|
reflex/compiler/compiler.py
CHANGED
|
@@ -368,13 +368,11 @@ def _compile_stateful_components(
|
|
|
368
368
|
|
|
369
369
|
# Include dynamic imports in the shared component.
|
|
370
370
|
if dynamic_imports := component._get_all_dynamic_imports():
|
|
371
|
-
rendered_components.update(
|
|
372
|
-
{dynamic_import: None for dynamic_import in dynamic_imports}
|
|
373
|
-
)
|
|
371
|
+
rendered_components.update(dict.fromkeys(dynamic_imports))
|
|
374
372
|
|
|
375
373
|
# Include custom code in the shared component.
|
|
376
374
|
rendered_components.update(
|
|
377
|
-
|
|
375
|
+
dict.fromkeys(component._get_all_custom_code()),
|
|
378
376
|
)
|
|
379
377
|
|
|
380
378
|
# Include all imports in the shared component.
|
|
@@ -53,9 +53,9 @@ def wait_for_client_redirect(component: Component) -> Component:
|
|
|
53
53
|
The conditionally rendered component.
|
|
54
54
|
"""
|
|
55
55
|
return cond(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
route_not_found,
|
|
57
|
+
component,
|
|
58
|
+
ClientSideRouting.create(),
|
|
59
59
|
)
|
|
60
60
|
|
|
61
61
|
|
reflex/components/core/cond.py
CHANGED
|
@@ -31,7 +31,7 @@ class Cond(MemoizationLeaf):
|
|
|
31
31
|
cls,
|
|
32
32
|
cond: Var,
|
|
33
33
|
comp1: BaseComponent,
|
|
34
|
-
comp2: BaseComponent |
|
|
34
|
+
comp2: BaseComponent | types.Unset = types.Unset(),
|
|
35
35
|
) -> Component:
|
|
36
36
|
"""Create a conditional component.
|
|
37
37
|
|
|
@@ -44,10 +44,14 @@ class Cond(MemoizationLeaf):
|
|
|
44
44
|
The conditional component.
|
|
45
45
|
"""
|
|
46
46
|
# Wrap everything in fragments.
|
|
47
|
-
if type(comp1)
|
|
47
|
+
if type(comp1) is not Fragment:
|
|
48
48
|
comp1 = Fragment.create(comp1)
|
|
49
|
-
if comp2
|
|
50
|
-
comp2 =
|
|
49
|
+
if isinstance(comp2, types.Unset) or type(comp2) is not Fragment:
|
|
50
|
+
comp2 = (
|
|
51
|
+
Fragment.create(comp2)
|
|
52
|
+
if not isinstance(comp2, types.Unset)
|
|
53
|
+
else Fragment.create()
|
|
54
|
+
)
|
|
51
55
|
return Fragment.create(
|
|
52
56
|
cls._create(
|
|
53
57
|
children=[comp1, comp2],
|
|
@@ -96,18 +100,22 @@ class Cond(MemoizationLeaf):
|
|
|
96
100
|
|
|
97
101
|
|
|
98
102
|
@overload
|
|
99
|
-
def cond(condition: Any, c1: Component, c2: Any) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
103
|
+
def cond(condition: Any, c1: Component, c2: Any, /) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@overload
|
|
107
|
+
def cond(condition: Any, c1: Component, /) -> Component: ...
|
|
100
108
|
|
|
101
109
|
|
|
102
110
|
@overload
|
|
103
|
-
def cond(condition: Any, c1: Component) -> Component: ...
|
|
111
|
+
def cond(condition: Any, c1: Any, c2: Component, /) -> Component: ... # pyright: ignore [reportOverlappingOverload]
|
|
104
112
|
|
|
105
113
|
|
|
106
114
|
@overload
|
|
107
|
-
def cond(condition: Any, c1: Any, c2: Any) -> Var: ...
|
|
115
|
+
def cond(condition: Any, c1: Any, c2: Any, /) -> Var: ...
|
|
108
116
|
|
|
109
117
|
|
|
110
|
-
def cond(condition: Any, c1: Any, c2: Any =
|
|
118
|
+
def cond(condition: Any, c1: Any, c2: Any = types.Unset(), /) -> Component | Var:
|
|
111
119
|
"""Create a conditional component or Prop.
|
|
112
120
|
|
|
113
121
|
Args:
|
|
@@ -128,15 +136,15 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
|
|
|
128
136
|
|
|
129
137
|
# If the first component is a component, create a Cond component.
|
|
130
138
|
if isinstance(c1, BaseComponent):
|
|
131
|
-
if c2
|
|
132
|
-
|
|
139
|
+
if not isinstance(c2, types.Unset) and not isinstance(c2, BaseComponent):
|
|
140
|
+
return Cond.create(cond_var.bool(), c1, Fragment.create(c2))
|
|
133
141
|
return Cond.create(cond_var.bool(), c1, c2)
|
|
134
142
|
|
|
135
143
|
# Otherwise, create a conditional Var.
|
|
136
144
|
# Check that the second argument is valid.
|
|
137
145
|
if isinstance(c2, BaseComponent):
|
|
138
|
-
|
|
139
|
-
if c2
|
|
146
|
+
return Cond.create(cond_var.bool(), Fragment.create(c1), c2)
|
|
147
|
+
if isinstance(c2, types.Unset):
|
|
140
148
|
raise ValueError("For conditional vars, the second argument must be set.")
|
|
141
149
|
|
|
142
150
|
# convert the truth and false cond parts into vars so the _var_data can be obtained.
|
reflex/components/dynamic.py
CHANGED
|
@@ -72,13 +72,11 @@ def load_dynamic_serializer():
|
|
|
72
72
|
rendered_components = {}
|
|
73
73
|
# Include dynamic imports in the shared component.
|
|
74
74
|
if dynamic_imports := component._get_all_dynamic_imports():
|
|
75
|
-
rendered_components.update(
|
|
76
|
-
{dynamic_import: None for dynamic_import in dynamic_imports}
|
|
77
|
-
)
|
|
75
|
+
rendered_components.update(dict.fromkeys(dynamic_imports))
|
|
78
76
|
|
|
79
77
|
# Include custom code in the shared component.
|
|
80
78
|
rendered_components.update(
|
|
81
|
-
|
|
79
|
+
dict.fromkeys(component._get_all_custom_code()),
|
|
82
80
|
)
|
|
83
81
|
|
|
84
82
|
rendered_components[
|
reflex/components/lucide/icon.py
CHANGED
|
@@ -53,42 +53,35 @@ class Icon(LucideIconComponent):
|
|
|
53
53
|
if "tag" not in props:
|
|
54
54
|
raise AttributeError("Missing 'tag' keyword-argument for Icon")
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
if isinstance(
|
|
58
|
-
if isinstance(
|
|
59
|
-
tag =
|
|
56
|
+
tag_var: Var | LiteralVar = Var.create(props.pop("tag"))
|
|
57
|
+
if isinstance(tag_var, LiteralVar):
|
|
58
|
+
if isinstance(tag_var, LiteralStringVar):
|
|
59
|
+
tag = format.to_snake_case(tag_var._var_value.lower())
|
|
60
60
|
else:
|
|
61
|
-
raise TypeError(f"Icon name must be a string, got {type(
|
|
62
|
-
elif isinstance(
|
|
63
|
-
tag_stringified =
|
|
61
|
+
raise TypeError(f"Icon name must be a string, got {type(tag_var)}")
|
|
62
|
+
elif isinstance(tag_var, Var):
|
|
63
|
+
tag_stringified = tag_var.guess_type()
|
|
64
64
|
if not isinstance(tag_stringified, StringVar):
|
|
65
|
-
raise TypeError(f"Icon name must be a string, got {
|
|
65
|
+
raise TypeError(f"Icon name must be a string, got {tag_var._var_type}")
|
|
66
66
|
return DynamicIcon.create(name=tag_stringified.replace("_", "-"), **props)
|
|
67
67
|
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
tag, s
|
|
77
|
-
),
|
|
78
|
-
reverse=True,
|
|
79
|
-
)
|
|
80
|
-
else:
|
|
81
|
-
icons_sorted = LUCIDE_ICON_LIST
|
|
68
|
+
if tag not in LUCIDE_ICON_LIST:
|
|
69
|
+
icons_sorted = sorted(
|
|
70
|
+
LUCIDE_ICON_LIST,
|
|
71
|
+
key=lambda s, tag=tag: format.length_of_largest_common_substring(
|
|
72
|
+
tag, s
|
|
73
|
+
),
|
|
74
|
+
reverse=True,
|
|
75
|
+
)
|
|
82
76
|
console.warn(
|
|
83
77
|
f"Invalid icon tag: {tag}. Please use one of the following: {', '.join(icons_sorted[0:10])}, ..."
|
|
84
78
|
"\nSee full list at https://reflex.dev/docs/library/data-display/icon/#icons-list. Using 'circle-help' icon instead."
|
|
85
79
|
)
|
|
86
|
-
tag = "
|
|
80
|
+
tag = "circle_help"
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
props["tag"] = format.to_title_case(format.to_snake_case(tag)) + "Icon"
|
|
82
|
+
props["tag"] = LUCIDE_ICON_MAPPING_OVERRIDE.get(
|
|
83
|
+
tag, format.to_title_case(tag) + "Icon"
|
|
84
|
+
)
|
|
92
85
|
props["alias"] = f"Lucide{props['tag']}"
|
|
93
86
|
props.setdefault("color", "var(--current-color)")
|
|
94
87
|
return super().create(**props)
|
reflex/config.py
CHANGED
|
@@ -30,7 +30,6 @@ from typing import (
|
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
import pydantic.v1 as pydantic
|
|
33
|
-
from reflex_cli.constants.hosting import Hosting
|
|
34
33
|
|
|
35
34
|
from reflex import constants
|
|
36
35
|
from reflex.base import Base
|
|
@@ -602,7 +601,7 @@ class EnvironmentVariables:
|
|
|
602
601
|
# The npm registry to use.
|
|
603
602
|
NPM_CONFIG_REGISTRY: EnvVar[str | None] = env_var(None)
|
|
604
603
|
|
|
605
|
-
# Whether to use Granian for the backend.
|
|
604
|
+
# Whether to use Granian for the backend. By default, the backend uses Uvicorn if available.
|
|
606
605
|
REFLEX_USE_GRANIAN: EnvVar[bool] = env_var(False)
|
|
607
606
|
|
|
608
607
|
# The username to use for authentication on python package repository. Username and password must both be provided.
|
|
@@ -807,8 +806,8 @@ class Config(Base):
|
|
|
807
806
|
# Tailwind config.
|
|
808
807
|
tailwind: dict[str, Any] | None = {"plugins": ["@tailwindcss/typography"]}
|
|
809
808
|
|
|
810
|
-
# Timeout when launching the gunicorn server.
|
|
811
|
-
timeout: int =
|
|
809
|
+
# DEPRECATED. Timeout when launching the gunicorn server.
|
|
810
|
+
timeout: int | None = None
|
|
812
811
|
|
|
813
812
|
# Whether to enable or disable nextJS gzip compression.
|
|
814
813
|
next_compression: bool = True
|
|
@@ -819,22 +818,17 @@ class Config(Base):
|
|
|
819
818
|
# Additional frontend packages to install.
|
|
820
819
|
frontend_packages: list[str] = []
|
|
821
820
|
|
|
822
|
-
# The
|
|
823
|
-
cp_backend_url: str = Hosting.HOSTING_SERVICE
|
|
824
|
-
# The hosting service frontend URL.
|
|
825
|
-
cp_web_url: str = Hosting.HOSTING_SERVICE_UI
|
|
826
|
-
|
|
827
|
-
# The worker class used in production mode
|
|
821
|
+
# DEPRECATED. The worker class used in production mode
|
|
828
822
|
gunicorn_worker_class: str = "uvicorn.workers.UvicornH11Worker"
|
|
829
823
|
|
|
830
|
-
# Number of gunicorn workers from user
|
|
824
|
+
# DEPRECATED. Number of gunicorn workers from user
|
|
831
825
|
gunicorn_workers: int | None = None
|
|
832
826
|
|
|
833
|
-
# Number of requests before a worker is restarted; set to 0 to disable
|
|
834
|
-
gunicorn_max_requests: int =
|
|
827
|
+
# DEPRECATED. Number of requests before a worker is restarted; set to 0 to disable
|
|
828
|
+
gunicorn_max_requests: int | None = None
|
|
835
829
|
|
|
836
|
-
# Variance limit for max requests; gunicorn only
|
|
837
|
-
gunicorn_max_requests_jitter: int =
|
|
830
|
+
# DEPRECATED. Variance limit for max requests; gunicorn only
|
|
831
|
+
gunicorn_max_requests_jitter: int | None = None
|
|
838
832
|
|
|
839
833
|
# Indicate which type of state manager to use
|
|
840
834
|
state_manager_mode: constants.StateManagerMode = constants.StateManagerMode.DISK
|
|
@@ -938,8 +932,14 @@ class Config(Base):
|
|
|
938
932
|
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0.1"`."""
|
|
939
933
|
)
|
|
940
934
|
else:
|
|
941
|
-
# load env
|
|
942
|
-
|
|
935
|
+
# load env files in reverse order if they exist
|
|
936
|
+
for env_file_path in [
|
|
937
|
+
Path(p)
|
|
938
|
+
for s in reversed(env_file.split(os.pathsep))
|
|
939
|
+
if (p := s.strip())
|
|
940
|
+
]:
|
|
941
|
+
if env_file_path.exists():
|
|
942
|
+
load_dotenv(env_file_path, override=True)
|
|
943
943
|
|
|
944
944
|
updated_values = {}
|
|
945
945
|
# Iterate over the fields.
|
|
@@ -826,12 +826,19 @@ def _collect_details_for_gallery():
|
|
|
826
826
|
Raises:
|
|
827
827
|
Exit: If pyproject.toml file is ill-formed or the request to the backend services fails.
|
|
828
828
|
"""
|
|
829
|
+
import reflex_cli.constants
|
|
829
830
|
from reflex_cli.utils import hosting
|
|
830
831
|
|
|
831
832
|
console.rule("[bold]Authentication with Reflex Services")
|
|
832
833
|
console.print("First let's log in to Reflex backend services.")
|
|
833
834
|
access_token, _ = hosting.authenticated_token()
|
|
834
835
|
|
|
836
|
+
if not access_token:
|
|
837
|
+
console.error(
|
|
838
|
+
"Unable to authenticate with Reflex backend services. Make sure you are logged in."
|
|
839
|
+
)
|
|
840
|
+
raise typer.Exit(code=1)
|
|
841
|
+
|
|
835
842
|
console.rule("[bold]Custom Component Information")
|
|
836
843
|
params = {}
|
|
837
844
|
package_name = None
|
|
@@ -845,10 +852,8 @@ def _collect_details_for_gallery():
|
|
|
845
852
|
console.print(f"[ Custom component package name ] : {package_name}")
|
|
846
853
|
params["package_name"] = package_name
|
|
847
854
|
|
|
848
|
-
config = get_config()
|
|
849
|
-
|
|
850
855
|
post_custom_components_gallery_endpoint = (
|
|
851
|
-
f"{
|
|
856
|
+
f"{reflex_cli.constants.Hosting.HOSTING_SERVICE}/custom-components/gallery"
|
|
852
857
|
)
|
|
853
858
|
|
|
854
859
|
# Check the backend services if the user is allowed to update information of this package is already shared.
|
reflex/reflex.py
CHANGED
|
@@ -7,13 +7,14 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
import typer
|
|
9
9
|
import typer.core
|
|
10
|
-
from reflex_cli.v2.deployments import
|
|
10
|
+
from reflex_cli.v2.deployments import hosting_cli
|
|
11
11
|
|
|
12
12
|
from reflex import constants
|
|
13
13
|
from reflex.config import environment, get_config
|
|
14
14
|
from reflex.custom_components.custom_components import custom_components_cli
|
|
15
15
|
from reflex.state import reset_disk_state_manager
|
|
16
16
|
from reflex.utils import console, redir, telemetry
|
|
17
|
+
from reflex.utils.exec import should_use_granian
|
|
17
18
|
|
|
18
19
|
# Disable typer+rich integration for help panels
|
|
19
20
|
typer.core.rich = None # pyright: ignore [reportPrivateImportUsage]
|
|
@@ -203,9 +204,19 @@ def _run(
|
|
|
203
204
|
|
|
204
205
|
prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
|
|
205
206
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
# Get the app module.
|
|
208
|
+
app_task = prerequisites.compile_app if frontend else prerequisites.validate_app
|
|
209
|
+
|
|
210
|
+
# Granian fails if the app is already imported.
|
|
211
|
+
if should_use_granian():
|
|
212
|
+
import concurrent.futures
|
|
213
|
+
|
|
214
|
+
compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
|
|
215
|
+
app_task
|
|
216
|
+
)
|
|
217
|
+
compile_future.result()
|
|
218
|
+
else:
|
|
219
|
+
app_task()
|
|
209
220
|
|
|
210
221
|
# Warn if schema is not up to date.
|
|
211
222
|
prerequisites.check_schema_up_to_date()
|
|
@@ -386,6 +397,7 @@ def export(
|
|
|
386
397
|
def login(loglevel: constants.LogLevel | None = typer.Option(None)):
|
|
387
398
|
"""Authenticate with experimental Reflex hosting service."""
|
|
388
399
|
from reflex_cli.v2 import cli as hosting_cli
|
|
400
|
+
from reflex_cli.v2.deployments import check_version
|
|
389
401
|
|
|
390
402
|
loglevel = loglevel or get_config().loglevel
|
|
391
403
|
|
|
@@ -407,6 +419,7 @@ def logout(
|
|
|
407
419
|
):
|
|
408
420
|
"""Log out of access to Reflex hosting service."""
|
|
409
421
|
from reflex_cli.v2.cli import logout
|
|
422
|
+
from reflex_cli.v2.deployments import check_version
|
|
410
423
|
|
|
411
424
|
check_version()
|
|
412
425
|
|
|
@@ -567,6 +580,7 @@ def deploy(
|
|
|
567
580
|
from reflex_cli.constants.base import LogLevel as HostingLogLevel
|
|
568
581
|
from reflex_cli.utils import dependency
|
|
569
582
|
from reflex_cli.v2 import cli as hosting_cli
|
|
583
|
+
from reflex_cli.v2.deployments import check_version
|
|
570
584
|
|
|
571
585
|
from reflex.utils import export as export_utils
|
|
572
586
|
from reflex.utils import prerequisites
|
reflex/state.py
CHANGED
|
@@ -1671,6 +1671,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1671
1671
|
|
|
1672
1672
|
raise TypeError(
|
|
1673
1673
|
f"Your handler {handler.fn.__qualname__} must only return/yield: None, Events or other EventHandlers referenced by their class (i.e. using `type(self)` or other class references)."
|
|
1674
|
+
f" Returned events of types {', '.join(map(str, map(type, events)))!s}."
|
|
1674
1675
|
)
|
|
1675
1676
|
|
|
1676
1677
|
async def _as_state_update(
|
reflex/utils/exec.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import hashlib
|
|
6
|
+
import importlib.util
|
|
6
7
|
import json
|
|
7
8
|
import os
|
|
8
9
|
import platform
|
|
@@ -19,6 +20,7 @@ from reflex import constants
|
|
|
19
20
|
from reflex.config import environment, get_config
|
|
20
21
|
from reflex.constants.base import LogLevel
|
|
21
22
|
from reflex.utils import console, path_ops
|
|
23
|
+
from reflex.utils.decorator import once
|
|
22
24
|
from reflex.utils.prerequisites import get_web_dir
|
|
23
25
|
|
|
24
26
|
# For uvicorn windows bug fix (#2335)
|
|
@@ -185,13 +187,28 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
|
|
|
185
187
|
)
|
|
186
188
|
|
|
187
189
|
|
|
190
|
+
@once
|
|
191
|
+
def _warn_user_about_uvicorn():
|
|
192
|
+
console.warn(
|
|
193
|
+
"Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default."
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
188
197
|
def should_use_granian():
|
|
189
198
|
"""Whether to use Granian for backend.
|
|
190
199
|
|
|
191
200
|
Returns:
|
|
192
201
|
True if Granian should be used.
|
|
193
202
|
"""
|
|
194
|
-
|
|
203
|
+
if environment.REFLEX_USE_GRANIAN.get():
|
|
204
|
+
return True
|
|
205
|
+
if (
|
|
206
|
+
importlib.util.find_spec("uvicorn") is None
|
|
207
|
+
or importlib.util.find_spec("gunicorn") is None
|
|
208
|
+
):
|
|
209
|
+
return True
|
|
210
|
+
_warn_user_about_uvicorn()
|
|
211
|
+
return False
|
|
195
212
|
|
|
196
213
|
|
|
197
214
|
def get_app_module():
|
|
@@ -200,22 +217,9 @@ def get_app_module():
|
|
|
200
217
|
Returns:
|
|
201
218
|
The app module for the backend.
|
|
202
219
|
"""
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def get_granian_target():
|
|
207
|
-
"""Get the Granian target for the backend.
|
|
208
|
-
|
|
209
|
-
Returns:
|
|
210
|
-
The Granian target for the backend.
|
|
211
|
-
"""
|
|
212
|
-
import reflex
|
|
213
|
-
|
|
214
|
-
app_module_path = Path(reflex.__file__).parent / "app_module_for_backend.py"
|
|
220
|
+
config = get_config()
|
|
215
221
|
|
|
216
|
-
return
|
|
217
|
-
f"{app_module_path!s}:{constants.CompileVars.APP}.{constants.CompileVars.API}"
|
|
218
|
-
)
|
|
222
|
+
return f"{config.module}:{constants.CompileVars.APP}"
|
|
219
223
|
|
|
220
224
|
|
|
221
225
|
def run_backend(
|
|
@@ -317,7 +321,8 @@ def run_uvicorn_backend(host: str, port: int, loglevel: LogLevel):
|
|
|
317
321
|
import uvicorn
|
|
318
322
|
|
|
319
323
|
uvicorn.run(
|
|
320
|
-
app=f"{get_app_module()}
|
|
324
|
+
app=f"{get_app_module()}",
|
|
325
|
+
factory=True,
|
|
321
326
|
host=host,
|
|
322
327
|
port=port,
|
|
323
328
|
log_level=loglevel.value,
|
|
@@ -335,31 +340,37 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel):
|
|
|
335
340
|
loglevel: The log level.
|
|
336
341
|
"""
|
|
337
342
|
console.debug("Using Granian for backend")
|
|
338
|
-
try:
|
|
339
|
-
from granian.constants import Interfaces
|
|
340
|
-
from granian.log import LogLevels
|
|
341
|
-
from granian.server import Server as Granian
|
|
342
|
-
|
|
343
|
-
Granian(
|
|
344
|
-
target=get_granian_target(),
|
|
345
|
-
address=host,
|
|
346
|
-
port=port,
|
|
347
|
-
interface=Interfaces.ASGI,
|
|
348
|
-
log_level=LogLevels(loglevel.value),
|
|
349
|
-
reload=True,
|
|
350
|
-
reload_paths=get_reload_paths(),
|
|
351
|
-
).serve()
|
|
352
|
-
except ImportError:
|
|
353
|
-
console.error(
|
|
354
|
-
'InstallError: REFLEX_USE_GRANIAN is set but `granian` is not installed. (run `pip install "granian[reload]>=1.6.0"`)'
|
|
355
|
-
)
|
|
356
|
-
os._exit(1)
|
|
357
343
|
|
|
344
|
+
from granian.constants import Interfaces
|
|
345
|
+
from granian.log import LogLevels
|
|
346
|
+
from granian.server import MPServer as Granian
|
|
358
347
|
|
|
348
|
+
Granian(
|
|
349
|
+
target=get_app_module(),
|
|
350
|
+
factory=True,
|
|
351
|
+
address=host,
|
|
352
|
+
port=port,
|
|
353
|
+
interface=Interfaces.ASGI,
|
|
354
|
+
log_level=LogLevels(loglevel.value),
|
|
355
|
+
reload=True,
|
|
356
|
+
reload_paths=get_reload_paths(),
|
|
357
|
+
).serve()
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
@once
|
|
359
361
|
def _get_backend_workers():
|
|
360
362
|
from reflex.utils import processes
|
|
361
363
|
|
|
362
364
|
config = get_config()
|
|
365
|
+
|
|
366
|
+
if config.gunicorn_workers is not None:
|
|
367
|
+
console.deprecate(
|
|
368
|
+
"config.gunicorn_workers",
|
|
369
|
+
reason="If you're using Granian, use GRANIAN_WORKERS instead.",
|
|
370
|
+
deprecation_version="0.7.4",
|
|
371
|
+
removal_version="0.8.0",
|
|
372
|
+
)
|
|
373
|
+
|
|
363
374
|
return (
|
|
364
375
|
processes.get_num_workers()
|
|
365
376
|
if not config.gunicorn_workers
|
|
@@ -367,6 +378,51 @@ def _get_backend_workers():
|
|
|
367
378
|
)
|
|
368
379
|
|
|
369
380
|
|
|
381
|
+
@once
|
|
382
|
+
def _get_backend_timeout():
|
|
383
|
+
config = get_config()
|
|
384
|
+
|
|
385
|
+
if config.timeout is not None:
|
|
386
|
+
console.deprecate(
|
|
387
|
+
"config.timeout",
|
|
388
|
+
reason="If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
|
|
389
|
+
deprecation_version="0.7.4",
|
|
390
|
+
removal_version="0.8.0",
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
return config.timeout
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
@once
|
|
397
|
+
def _get_backend_max_requests():
|
|
398
|
+
config = get_config()
|
|
399
|
+
|
|
400
|
+
if config.gunicorn_max_requests is not None:
|
|
401
|
+
console.deprecate(
|
|
402
|
+
"config.gunicorn_max_requests",
|
|
403
|
+
reason="",
|
|
404
|
+
deprecation_version="0.7.4",
|
|
405
|
+
removal_version="0.8.0",
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
return config.gunicorn_max_requests
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@once
|
|
412
|
+
def _get_backend_max_requests_jitter():
|
|
413
|
+
config = get_config()
|
|
414
|
+
|
|
415
|
+
if config.gunicorn_max_requests_jitter is not None:
|
|
416
|
+
console.deprecate(
|
|
417
|
+
"config.gunicorn_max_requests_jitter",
|
|
418
|
+
reason="",
|
|
419
|
+
deprecation_version="0.7.4",
|
|
420
|
+
removal_version="0.8.0",
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
return config.gunicorn_max_requests_jitter
|
|
424
|
+
|
|
425
|
+
|
|
370
426
|
def run_backend_prod(
|
|
371
427
|
host: str,
|
|
372
428
|
port: int,
|
|
@@ -408,17 +464,25 @@ def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
|
408
464
|
[
|
|
409
465
|
"uvicorn",
|
|
410
466
|
*(
|
|
411
|
-
|
|
467
|
+
(
|
|
412
468
|
"--limit-max-requests",
|
|
413
|
-
str(
|
|
414
|
-
|
|
415
|
-
if
|
|
416
|
-
|
|
469
|
+
str(max_requessts),
|
|
470
|
+
)
|
|
471
|
+
if (
|
|
472
|
+
(max_requessts := _get_backend_max_requests()) is not None
|
|
473
|
+
and max_requessts > 0
|
|
474
|
+
)
|
|
475
|
+
else ()
|
|
476
|
+
),
|
|
477
|
+
*(
|
|
478
|
+
("--timeout-keep-alive", str(timeout))
|
|
479
|
+
if (timeout := _get_backend_timeout()) is not None
|
|
480
|
+
else ()
|
|
417
481
|
),
|
|
418
|
-
*("--timeout-keep-alive", str(config.timeout)),
|
|
419
482
|
*("--host", host),
|
|
420
483
|
*("--port", str(port)),
|
|
421
484
|
*("--workers", str(_get_backend_workers())),
|
|
485
|
+
"--factory",
|
|
422
486
|
app_module,
|
|
423
487
|
]
|
|
424
488
|
if constants.IS_WINDOWS
|
|
@@ -426,17 +490,34 @@ def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
|
426
490
|
"gunicorn",
|
|
427
491
|
*("--worker-class", config.gunicorn_worker_class),
|
|
428
492
|
*(
|
|
429
|
-
|
|
493
|
+
(
|
|
430
494
|
"--max-requests",
|
|
431
|
-
str(
|
|
495
|
+
str(max_requessts),
|
|
496
|
+
)
|
|
497
|
+
if (
|
|
498
|
+
(max_requessts := _get_backend_max_requests()) is not None
|
|
499
|
+
and max_requessts > 0
|
|
500
|
+
)
|
|
501
|
+
else ()
|
|
502
|
+
),
|
|
503
|
+
*(
|
|
504
|
+
(
|
|
432
505
|
"--max-requests-jitter",
|
|
433
|
-
str(
|
|
434
|
-
|
|
435
|
-
if
|
|
436
|
-
|
|
506
|
+
str(max_requessts_jitter),
|
|
507
|
+
)
|
|
508
|
+
if (
|
|
509
|
+
(max_requessts_jitter := _get_backend_max_requests_jitter())
|
|
510
|
+
is not None
|
|
511
|
+
and max_requessts_jitter > 0
|
|
512
|
+
)
|
|
513
|
+
else ()
|
|
437
514
|
),
|
|
438
515
|
"--preload",
|
|
439
|
-
*(
|
|
516
|
+
*(
|
|
517
|
+
("--timeout", str(timeout))
|
|
518
|
+
if (timeout := _get_backend_timeout()) is not None
|
|
519
|
+
else ()
|
|
520
|
+
),
|
|
440
521
|
*("--bind", f"{host}:{port}"),
|
|
441
522
|
*("--threads", str(_get_backend_workers())),
|
|
442
523
|
f"{app_module}()",
|
|
@@ -472,17 +553,12 @@ def run_granian_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
|
472
553
|
|
|
473
554
|
command = [
|
|
474
555
|
"granian",
|
|
475
|
-
"--workers",
|
|
476
|
-
|
|
477
|
-
"--
|
|
478
|
-
"
|
|
479
|
-
"--
|
|
480
|
-
|
|
481
|
-
"--port",
|
|
482
|
-
str(port),
|
|
483
|
-
"--interface",
|
|
484
|
-
str(Interfaces.ASGI),
|
|
485
|
-
get_granian_target(),
|
|
556
|
+
*("--workers", str(_get_backend_workers())),
|
|
557
|
+
*("--log-level", "critical"),
|
|
558
|
+
*("--host", host),
|
|
559
|
+
*("--port", str(port)),
|
|
560
|
+
*("--interface", str(Interfaces.ASGI)),
|
|
561
|
+
*("--factory", get_app_module()),
|
|
486
562
|
]
|
|
487
563
|
processes.new_process(
|
|
488
564
|
command,
|
reflex/utils/prerequisites.py
CHANGED
|
@@ -412,6 +412,15 @@ def get_and_validate_app(reload: bool = False) -> AppInfo:
|
|
|
412
412
|
return AppInfo(app=app, module=app_module)
|
|
413
413
|
|
|
414
414
|
|
|
415
|
+
def validate_app(reload: bool = False) -> None:
|
|
416
|
+
"""Validate the app instance based on the default config.
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
reload: Re-import the app module from disk
|
|
420
|
+
"""
|
|
421
|
+
get_and_validate_app(reload=reload)
|
|
422
|
+
|
|
423
|
+
|
|
415
424
|
def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
|
|
416
425
|
"""Get the app module based on the default config after first compiling it.
|
|
417
426
|
|
|
@@ -430,6 +439,16 @@ def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
|
|
|
430
439
|
return app_module
|
|
431
440
|
|
|
432
441
|
|
|
442
|
+
def compile_app(reload: bool = False, export: bool = False) -> None:
|
|
443
|
+
"""Compile the app module based on the default config.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
reload: Re-import the app module from disk
|
|
447
|
+
export: Compile the app for export
|
|
448
|
+
"""
|
|
449
|
+
get_compiled_app(reload=reload, export=export)
|
|
450
|
+
|
|
451
|
+
|
|
433
452
|
def get_redis() -> Redis | None:
|
|
434
453
|
"""Get the asynchronous redis client.
|
|
435
454
|
|
|
@@ -1542,7 +1561,7 @@ def create_config_init_app_from_remote_template(app_name: str, template_url: str
|
|
|
1542
1561
|
console.error(f"Failed to unzip the template: {uze}")
|
|
1543
1562
|
raise typer.Exit(1) from uze
|
|
1544
1563
|
|
|
1545
|
-
if len(subdirs :=
|
|
1564
|
+
if len(subdirs := list(unzip_dir.iterdir())) != 1:
|
|
1546
1565
|
console.error(f"Expected one directory in the zip, found {subdirs}")
|
|
1547
1566
|
raise typer.Exit(1)
|
|
1548
1567
|
|
reflex/utils/processes.py
CHANGED
|
@@ -10,7 +10,7 @@ import signal
|
|
|
10
10
|
import subprocess
|
|
11
11
|
from concurrent import futures
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import Callable, Generator, Sequence, Tuple
|
|
13
|
+
from typing import Any, Callable, Generator, Sequence, Tuple
|
|
14
14
|
|
|
15
15
|
import psutil
|
|
16
16
|
import typer
|
|
@@ -197,7 +197,7 @@ def new_process(
|
|
|
197
197
|
|
|
198
198
|
@contextlib.contextmanager
|
|
199
199
|
def run_concurrently_context(
|
|
200
|
-
*fns: Callable |
|
|
200
|
+
*fns: Callable[..., Any] | tuple[Callable[..., Any], ...],
|
|
201
201
|
) -> Generator[list[futures.Future], None, None]:
|
|
202
202
|
"""Run functions concurrently in a thread pool.
|
|
203
203
|
|
|
@@ -213,14 +213,14 @@ def run_concurrently_context(
|
|
|
213
213
|
return
|
|
214
214
|
|
|
215
215
|
# Convert the functions to tuples.
|
|
216
|
-
fns =
|
|
216
|
+
fns = tuple(fn if isinstance(fn, tuple) else (fn,) for fn in fns)
|
|
217
217
|
|
|
218
218
|
# Run the functions concurrently.
|
|
219
219
|
executor = None
|
|
220
220
|
try:
|
|
221
221
|
executor = futures.ThreadPoolExecutor(max_workers=len(fns))
|
|
222
222
|
# Submit the tasks.
|
|
223
|
-
tasks = [executor.submit(*fn) for fn in fns]
|
|
223
|
+
tasks = [executor.submit(*fn) for fn in fns]
|
|
224
224
|
|
|
225
225
|
# Yield control back to the main thread while tasks are running.
|
|
226
226
|
yield tasks
|
reflex/vars/base.py
CHANGED
|
@@ -160,7 +160,7 @@ class VarData:
|
|
|
160
160
|
if isinstance(hooks, str):
|
|
161
161
|
hooks = [hooks]
|
|
162
162
|
if not isinstance(hooks, dict):
|
|
163
|
-
hooks =
|
|
163
|
+
hooks = dict.fromkeys(hooks or [])
|
|
164
164
|
immutable_imports: ImmutableParsedImportDict = tuple(
|
|
165
165
|
(k, tuple(v)) for k, v in parse_imports(imports or {}).items()
|
|
166
166
|
)
|
|
@@ -1791,8 +1791,7 @@ class cached_property: # noqa: N801
|
|
|
1791
1791
|
if original_del is not None:
|
|
1792
1792
|
original_del(this)
|
|
1793
1793
|
return
|
|
1794
|
-
|
|
1795
|
-
del GLOBAL_CACHE[unique_id]
|
|
1794
|
+
GLOBAL_CACHE.pop(unique_id, None)
|
|
1796
1795
|
|
|
1797
1796
|
if original_del is not None:
|
|
1798
1797
|
original_del(this)
|
reflex/vars/sequence.py
CHANGED
|
@@ -1683,6 +1683,8 @@ def _determine_value_of_array_index(
|
|
|
1683
1683
|
if t is not type(None)
|
|
1684
1684
|
]
|
|
1685
1685
|
)
|
|
1686
|
+
if origin_var_type is range:
|
|
1687
|
+
return int
|
|
1686
1688
|
if origin_var_type in [
|
|
1687
1689
|
Sequence,
|
|
1688
1690
|
Iterable,
|
|
@@ -1974,3 +1976,85 @@ class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
|
|
|
1974
1976
|
):
|
|
1975
1977
|
raise TypeError("Color is not a valid color.")
|
|
1976
1978
|
return f"var(--{color}-{'a' if alpha else ''}{shade})"
|
|
1979
|
+
|
|
1980
|
+
|
|
1981
|
+
class RangeVar(ArrayVar[Sequence[int]], python_types=range):
|
|
1982
|
+
"""Base class for immutable range vars."""
|
|
1983
|
+
|
|
1984
|
+
|
|
1985
|
+
@dataclasses.dataclass(
|
|
1986
|
+
eq=False,
|
|
1987
|
+
frozen=True,
|
|
1988
|
+
slots=True,
|
|
1989
|
+
)
|
|
1990
|
+
class LiteralRangeVar(CachedVarOperation, LiteralVar, RangeVar):
|
|
1991
|
+
"""Base class for immutable literal range vars."""
|
|
1992
|
+
|
|
1993
|
+
_var_value: range = dataclasses.field(default_factory=lambda: range(0))
|
|
1994
|
+
|
|
1995
|
+
@classmethod
|
|
1996
|
+
def create(
|
|
1997
|
+
cls,
|
|
1998
|
+
value: range,
|
|
1999
|
+
_var_type: Type[range] | None = None,
|
|
2000
|
+
_var_data: VarData | None = None,
|
|
2001
|
+
) -> RangeVar:
|
|
2002
|
+
"""Create a var from a string value.
|
|
2003
|
+
|
|
2004
|
+
Args:
|
|
2005
|
+
value: The value to create the var from.
|
|
2006
|
+
_var_type: The type of the var.
|
|
2007
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
2008
|
+
|
|
2009
|
+
Returns:
|
|
2010
|
+
The var.
|
|
2011
|
+
"""
|
|
2012
|
+
return cls(
|
|
2013
|
+
_js_expr="",
|
|
2014
|
+
_var_type=_var_type or range,
|
|
2015
|
+
_var_data=_var_data,
|
|
2016
|
+
_var_value=value,
|
|
2017
|
+
)
|
|
2018
|
+
|
|
2019
|
+
def __hash__(self) -> int:
|
|
2020
|
+
"""Get the hash of the var.
|
|
2021
|
+
|
|
2022
|
+
Returns:
|
|
2023
|
+
The hash of the var.
|
|
2024
|
+
"""
|
|
2025
|
+
return hash(
|
|
2026
|
+
(
|
|
2027
|
+
self.__class__.__name__,
|
|
2028
|
+
self._var_value.start,
|
|
2029
|
+
self._var_value.stop,
|
|
2030
|
+
self._var_value.step,
|
|
2031
|
+
)
|
|
2032
|
+
)
|
|
2033
|
+
|
|
2034
|
+
@cached_property_no_lock
|
|
2035
|
+
def _cached_var_name(self) -> str:
|
|
2036
|
+
"""The name of the var.
|
|
2037
|
+
|
|
2038
|
+
Returns:
|
|
2039
|
+
The name of the var.
|
|
2040
|
+
"""
|
|
2041
|
+
return f"Array.from({{ length: Math.ceil(({self._var_value.stop!s} - {self._var_value.start!s}) / {self._var_value.step!s}) }}, (_, i) => {self._var_value.start!s} + i * {self._var_value.step!s})"
|
|
2042
|
+
|
|
2043
|
+
@cached_property_no_lock
|
|
2044
|
+
def _cached_get_all_var_data(self) -> VarData | None:
|
|
2045
|
+
"""Get all the var data.
|
|
2046
|
+
|
|
2047
|
+
Returns:
|
|
2048
|
+
The var data.
|
|
2049
|
+
"""
|
|
2050
|
+
return self._var_data
|
|
2051
|
+
|
|
2052
|
+
def json(self) -> str:
|
|
2053
|
+
"""Get the JSON representation of the var.
|
|
2054
|
+
|
|
2055
|
+
Returns:
|
|
2056
|
+
The JSON representation of the var.
|
|
2057
|
+
"""
|
|
2058
|
+
return json.dumps(
|
|
2059
|
+
list(self._var_value),
|
|
2060
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reflex
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4a1
|
|
4
4
|
Summary: Web apps in pure Python.
|
|
5
5
|
Project-URL: homepage, https://reflex.dev
|
|
6
6
|
Project-URL: repository, https://github.com/reflex-dev/reflex
|
|
@@ -23,7 +23,7 @@ Requires-Dist: build<2.0,>=1.0.3
|
|
|
23
23
|
Requires-Dist: charset-normalizer<4.0,>=3.3.2
|
|
24
24
|
Requires-Dist: distro<2.0,>=1.8.0; platform_system == 'Linux'
|
|
25
25
|
Requires-Dist: fastapi!=0.111.0,!=0.111.1,>=0.96.0
|
|
26
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: granian[reload]>=2.0.0
|
|
27
27
|
Requires-Dist: httpx<1.0,>=0.25.1
|
|
28
28
|
Requires-Dist: jinja2<4.0,>=3.1.2
|
|
29
29
|
Requires-Dist: lazy-loader>=0.4
|
|
@@ -44,7 +44,6 @@ Requires-Dist: tomlkit<1.0,>=0.12.4
|
|
|
44
44
|
Requires-Dist: twine<7.0,>=4.0.0
|
|
45
45
|
Requires-Dist: typer<1.0,>=0.15.1
|
|
46
46
|
Requires-Dist: typing-extensions>=4.6.0
|
|
47
|
-
Requires-Dist: uvicorn>=0.20.0
|
|
48
47
|
Requires-Dist: wheel<1.0,>=0.42.0
|
|
49
48
|
Requires-Dist: wrapt<2.0,>=1.17.0
|
|
50
49
|
Description-Content-Type: text/markdown
|
|
@@ -60,6 +59,7 @@ Description-Content-Type: text/markdown
|
|
|
60
59
|
[](https://badge.fury.io/py/reflex)
|
|
61
60
|

|
|
62
61
|
[](https://reflex.dev/docs/getting-started/introduction)
|
|
62
|
+
[](https://pepy.tech/projects/reflex)
|
|
63
63
|
[](https://discord.gg/T5WSbC2YtQ)
|
|
64
64
|
|
|
65
65
|
</div>
|
|
@@ -2,18 +2,17 @@ reflex/__init__.py,sha256=64HB9b6MKesl3Yv6aZMsozdMKKpgnxirKk-aeN45UYY,10341
|
|
|
2
2
|
reflex/__init__.pyi,sha256=j4ZkO-mKKw5dFBhJVbaOg7AlncO-JCckV2cHENPiLG0,11303
|
|
3
3
|
reflex/__main__.py,sha256=6cVrGEyT3j3tEvlEVUatpaYfbB5EF3UVY-6vc_Z7-hw,108
|
|
4
4
|
reflex/admin.py,sha256=wu_vYqB0rU2njYBJSI0XZgVEkAFVZNQNUkUUXrlFbZc,343
|
|
5
|
-
reflex/app.py,sha256=
|
|
6
|
-
reflex/app_module_for_backend.py,sha256=iuEYcJNRai59vReNUIZgixtYlFHYcYp_LNFB9DPQnKs,1134
|
|
5
|
+
reflex/app.py,sha256=JCh2PGvwfTpYSfZJeMRANGT-6NdWw718gAFWX-hOq_U,69385
|
|
7
6
|
reflex/assets.py,sha256=PLTKAMYPKMZq8eWXKX8uco6NZ9IiPGWal0bOPLUmU7k,3364
|
|
8
7
|
reflex/base.py,sha256=T1sY7SJJOpTsOveEiFxp-K39EoIQtRLgqdFZhsdM0DE,3976
|
|
9
|
-
reflex/config.py,sha256=
|
|
8
|
+
reflex/config.py,sha256=LWl45MJv-fh4fMr-cpQWffO0HgQU-UiMEeqiqJC_Gto,35100
|
|
10
9
|
reflex/event.py,sha256=EX-9X-c8gIudZjRDG8qSrVAbegcaGkYXxLLRWg-7IOA,60758
|
|
11
10
|
reflex/model.py,sha256=k6qCweATPW1YRB_qcHwa5X35btJmtIlB4zEQ63FaW3w,17527
|
|
12
11
|
reflex/page.py,sha256=qEt8n5EtawSywCzdsiaNQJWhC8ie-vg8ig0JGuVavPI,2386
|
|
13
12
|
reflex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
reflex/reflex.py,sha256=
|
|
13
|
+
reflex/reflex.py,sha256=BM9oQ4VaobBa__BLgf38DJ2BYhTdobTRDZCpaZkOBHk,20920
|
|
15
14
|
reflex/route.py,sha256=nn_hJwtQdjiqH_dHXfqMGWKllnyPQZTSR-KWdHDhoOs,4210
|
|
16
|
-
reflex/state.py,sha256=
|
|
15
|
+
reflex/state.py,sha256=XBryDsRkXVLxYYiU_TL2B_riU7FySJsg3aU0ywUSWJs,141886
|
|
17
16
|
reflex/style.py,sha256=dilXPn8de80NzsXT53GPJrmjELC5nPYIlCgongyq1zM,13145
|
|
18
17
|
reflex/testing.py,sha256=IpjUHBNOJDAQtu6HnazfWIacEO5cIJvyHlCr6dYpr38,35585
|
|
19
18
|
reflex/.templates/apps/blank/assets/favicon.ico,sha256=baxxgDAQ2V4-G5Q4S2yK5uUJTUGkv-AOWBQ0xd6myUo,4286
|
|
@@ -59,13 +58,13 @@ reflex/app_mixins/lifespan.py,sha256=fwtaa9NnyENdDa8_RUHUsT8L9qnZKxcpL-mEGLTGldo
|
|
|
59
58
|
reflex/app_mixins/middleware.py,sha256=_B33NZdbuI16IUPTENyfCmEfJ6OxFHm6rObl3JdIs-Y,3286
|
|
60
59
|
reflex/app_mixins/mixin.py,sha256=si0Pa0U1EtJc-a6iZntqU9B7_NrPILwrGFxk9mKHBCE,317
|
|
61
60
|
reflex/compiler/__init__.py,sha256=r8jqmDSFf09iV2lHlNhfc9XrTLjNxfDNwPYlxS4cmHE,27
|
|
62
|
-
reflex/compiler/compiler.py,sha256=
|
|
61
|
+
reflex/compiler/compiler.py,sha256=Dr7eitYfwfJlcun7v88E7FEELAnkbKp8ja4-r41_6co,25870
|
|
63
62
|
reflex/compiler/templates.py,sha256=NX3YUMVGGyDsy2JuDv-AmklMM0pKJHLPsIpdqamgqRQ,5854
|
|
64
63
|
reflex/compiler/utils.py,sha256=w8KcAXneXQxPOSei7BvAfA9MzR4jQWjDlxm8ahN1UM0,16083
|
|
65
64
|
reflex/components/__init__.py,sha256=zbIXThv1WPI0FdIGf9G9RAmGoCRoGy7nHcSZ8K5D5bA,624
|
|
66
65
|
reflex/components/__init__.pyi,sha256=qoj1zIWaitcZOGcJ6k7wuGJk_GAJCE9Xtx8CeRVrvoE,861
|
|
67
66
|
reflex/components/component.py,sha256=ksc0Vc3hgZkTEyDZksarETCrjA-pvDMnd7T11F01ecg,88766
|
|
68
|
-
reflex/components/dynamic.py,sha256=
|
|
67
|
+
reflex/components/dynamic.py,sha256=DdlFbtciytsEbVdFHm-obmE4FFkSR6x2DH0BzYI_4C4,7150
|
|
69
68
|
reflex/components/literals.py,sha256=hogLnwTJxFJODIvqihg-GD9kFZVsEBDoYzaRit56Nuk,501
|
|
70
69
|
reflex/components/props.py,sha256=8F2ZNeF16BDiTh-E4F-U_vks41BMJgmkTM7xbjGvfOA,2593
|
|
71
70
|
reflex/components/base/__init__.py,sha256=QIOxOPT87WrSE4TSHAsZ-358VzvUXAe1w8vWogQ3Uuo,730
|
|
@@ -98,12 +97,12 @@ reflex/components/core/auto_scroll.pyi,sha256=4oTNr6ixo5D0rzmIQVXGCEUpHSSa7KdrkW
|
|
|
98
97
|
reflex/components/core/banner.py,sha256=OB8HlnytknFQotVoBNsbCHxE6_3W96JCCtvxS6R3QKU,18473
|
|
99
98
|
reflex/components/core/banner.pyi,sha256=owB8dbiHh2YMeJsggCM5zQ3kpfIcGXoxTWQdscakpwQ,24586
|
|
100
99
|
reflex/components/core/breakpoints.py,sha256=fDtfDoZqJnAOnBvpp0640FCKbuMyC9dVoSf0-RE7n6Y,2756
|
|
101
|
-
reflex/components/core/client_side_routing.py,sha256=
|
|
100
|
+
reflex/components/core/client_side_routing.py,sha256=CgW29H4Kiy5V4AKdJlFT9gSWaFUfki3f3Prf9twbbqA,1881
|
|
102
101
|
reflex/components/core/client_side_routing.pyi,sha256=XODI3H05ccxhAo-_SvFJjKFxTAkWbRsA-wmTe9uBxRo,4182
|
|
103
102
|
reflex/components/core/clipboard.py,sha256=WH2pagKO0H5G7BaIT1kChRzrMV-aP5ENv1lIKbkRzJ8,3354
|
|
104
103
|
reflex/components/core/clipboard.pyi,sha256=PiCieOSgQWwN5M7uHl11_kSqUXBN8J3glred4TH-yiQ,3041
|
|
105
104
|
reflex/components/core/colors.py,sha256=-hzVGLEq3TiqroqzMi_YzGBCPXMvkNsen3pS_NzIQNk,590
|
|
106
|
-
reflex/components/core/cond.py,sha256=
|
|
105
|
+
reflex/components/core/cond.py,sha256=j5V-CGjoB6W_Ch0blQYzLuepjLqtX4vXb8e6qvEL_3I,5685
|
|
107
106
|
reflex/components/core/debounce.py,sha256=qZsnu-7xfxz3NJS4-UnA_2YQz2P8SznJyuwZz98nEwE,4961
|
|
108
107
|
reflex/components/core/debounce.pyi,sha256=QjyPCR1eVGxTdDFnFPD9Ir9QbJLk-2xU8f-hSMZHcfU,2883
|
|
109
108
|
reflex/components/core/foreach.py,sha256=s2wgxcgEBc_8PfTKolDjbRz1pgdKZCdq8tqk87t3QVQ,5827
|
|
@@ -159,7 +158,7 @@ reflex/components/gridjs/__init__.py,sha256=xJwDm1AZ70L5-t9LLqZwGUtDpijbf1KuMYDT
|
|
|
159
158
|
reflex/components/gridjs/datatable.py,sha256=Q2P2lFbPEujVa6bfetV0w4Oc81APX9YgVKGnKCvhSxY,4197
|
|
160
159
|
reflex/components/gridjs/datatable.pyi,sha256=zVZTSTTQJY5jjrCTnyah3XM6aySyhq_mbhBWnbFg6Io,4859
|
|
161
160
|
reflex/components/lucide/__init__.py,sha256=EggTK2MuQKQeOBLKW-mF0VaDK9zdWBImu1HO2dvHZbE,73
|
|
162
|
-
reflex/components/lucide/icon.py,sha256=
|
|
161
|
+
reflex/components/lucide/icon.py,sha256=lRmzrsoT2_zvC8mKAZx0b1SJW_6ebEmRjWop2ggGHwM,33600
|
|
163
162
|
reflex/components/lucide/icon.pyi,sha256=DZkrFkUSq-BT23taozAIDfPuHAF3V9AsVYwaEeOCgm0,35884
|
|
164
163
|
reflex/components/markdown/__init__.py,sha256=Dfl1At5uYoY7H4ufZU_RY2KOGQDLtj75dsZ2BTqqAns,87
|
|
165
164
|
reflex/components/markdown/markdown.py,sha256=9VoxHQNZe44pVDoT_2b897dTn7vcel7oglBF-iTu0aM,16186
|
|
@@ -352,7 +351,7 @@ reflex/constants/state.py,sha256=6Mfr7xVcAZOj5aSy7kp0W6r8oTs7K30URgGDAAFLfPQ,294
|
|
|
352
351
|
reflex/constants/style.py,sha256=EPgRYHhAlcrPUBc2HkDTdTj-Q0uDAXHlq8Sp6D35Zf4,475
|
|
353
352
|
reflex/constants/utils.py,sha256=GJhFj1uba54CDPEm70tWs8B5iS2siHgeNi--oGCjeRc,759
|
|
354
353
|
reflex/custom_components/__init__.py,sha256=R4zsvOi4dfPmHc18KEphohXnQFBPnUCb50cMR5hSLDE,36
|
|
355
|
-
reflex/custom_components/custom_components.py,sha256=
|
|
354
|
+
reflex/custom_components/custom_components.py,sha256=Ho3W97wfStsEVh6BuTEORhc3bd4UoCYzY3yB4YdVBUI,33592
|
|
356
355
|
reflex/experimental/__init__.py,sha256=bvJ6qFeO3xT3L-8IBtk4ecoi5rda3EDvblgNP60yhEo,2206
|
|
357
356
|
reflex/experimental/client_state.py,sha256=p_Toz94fNQGMbHY1WlwfQ-i_M01f1ExA9t1iokSvdLc,9880
|
|
358
357
|
reflex/experimental/hooks.py,sha256=CHYGrAE5t8riltrJmDFgJ4D2Vhmhw-y3B3MSGNlOQow,2366
|
|
@@ -375,15 +374,15 @@ reflex/utils/compat.py,sha256=aSJH_M6iomgHPQ4onQ153xh1MWqPi3HSYDzE68N6gZM,2635
|
|
|
375
374
|
reflex/utils/console.py,sha256=slDTb_5QXfSvdflFiwJauc874R2zqo8BOSh37JUhYLY,9469
|
|
376
375
|
reflex/utils/decorator.py,sha256=EYdAjPdfgFjqjYSmLlc9qzOYnoihzavG5T4tgVgzsw4,1171
|
|
377
376
|
reflex/utils/exceptions.py,sha256=Wwu7Ji2xgq521bJKtU2NgjwhmFfnG8erirEVN2h8S-g,8884
|
|
378
|
-
reflex/utils/exec.py,sha256
|
|
377
|
+
reflex/utils/exec.py,sha256=YVYsUYNKSm2uYVGRLNOhC-zQMW7NrGjLmRxmzpTnVfk,19054
|
|
379
378
|
reflex/utils/export.py,sha256=bcJA0L8lBbjij-5PU93ka2c1d_yJqrIurp5u4mN5f68,2537
|
|
380
379
|
reflex/utils/format.py,sha256=a8em_yzqp9pLTrPXRsdzFWSO1qL2x25BpJXOf9DV1t8,20638
|
|
381
380
|
reflex/utils/imports.py,sha256=-EkUt9y5U3qmImjfpsXwYh7JI9qJHd_L6X9y12EPJew,3921
|
|
382
381
|
reflex/utils/lazy_loader.py,sha256=-3DcwIqHNft2fb1ikgDYAMiEwNfbiWfrTBAf1gEVX2o,1367
|
|
383
382
|
reflex/utils/net.py,sha256=0Yd9OLK8R_px2sqnqrDkTky6hYHtG2pEDvvilOjDfjc,1219
|
|
384
383
|
reflex/utils/path_ops.py,sha256=idGxUSJRKwYLLi7ppXkq3eV6rvAytJoO-n-FuLkwl3o,7604
|
|
385
|
-
reflex/utils/prerequisites.py,sha256=
|
|
386
|
-
reflex/utils/processes.py,sha256=
|
|
384
|
+
reflex/utils/prerequisites.py,sha256=_lgbA4udXoTPgBUYaSRW3zqyHJ3jrObgS7GXrQvgf3M,61526
|
|
385
|
+
reflex/utils/processes.py,sha256=B5F8m1smqGCvvwcGBO9poqQddfNBLy7uafO0J0PDcMo,13538
|
|
387
386
|
reflex/utils/pyi_generator.py,sha256=cKdssbtAtGj2deOSDos9OF96w10qte8JM-TlfbzSdtw,41602
|
|
388
387
|
reflex/utils/redir.py,sha256=kTqY2WSouF5_ftOe5bnvPEyU3SLpg3pcysTcxFH1UxI,1505
|
|
389
388
|
reflex/utils/registry.py,sha256=6DPfYc64GodbhwdAZ113_zBsvMNdbFTIJ94qDH1N6wc,1410
|
|
@@ -391,15 +390,15 @@ reflex/utils/serializers.py,sha256=K8-erpNIjJNIKif0cDFExa9f5DEVuQUq0j5v5VH6aBI,1
|
|
|
391
390
|
reflex/utils/telemetry.py,sha256=qwJBwjdtAV-OGKgO4h-NWhgTvfC3gbduBdn1UB8Ikes,5608
|
|
392
391
|
reflex/utils/types.py,sha256=nGX44Q_Jp33wIaxf2vxANwBWe1743V2B8RRS8H9yV4c,33449
|
|
393
392
|
reflex/vars/__init__.py,sha256=2Kv6Oh9g3ISZFESjL1al8KiO7QBZUXmLKGMCBsP-DoY,1243
|
|
394
|
-
reflex/vars/base.py,sha256=
|
|
393
|
+
reflex/vars/base.py,sha256=EjerSG-V8BwXhAcB___I0jNA_0T9t81EUxff7LpjyFg,101870
|
|
395
394
|
reflex/vars/datetime.py,sha256=WOEzQF6qjMjYvCat80XxgB_4hmVNHwIIZNMBSmfu0PM,5790
|
|
396
395
|
reflex/vars/dep_tracking.py,sha256=kluvF4Pfbpdqf0GcpmYHjT1yP-D1erAzaSQP6qIxjB0,13846
|
|
397
396
|
reflex/vars/function.py,sha256=2sVnhgetPSwtor8VFtAiYJdzZ9IRNzAKdsUJG6dXQcE,14461
|
|
398
397
|
reflex/vars/number.py,sha256=hacFEtv-63tMQN-oeVDWkrLFQL4utYG-b3ahYTb8b4M,29573
|
|
399
398
|
reflex/vars/object.py,sha256=-fGqHThozjxAAuQL-wTwEItPiFI-ps53P2bKoSlW_As,17081
|
|
400
|
-
reflex/vars/sequence.py,sha256=
|
|
401
|
-
reflex-0.7.
|
|
402
|
-
reflex-0.7.
|
|
403
|
-
reflex-0.7.
|
|
404
|
-
reflex-0.7.
|
|
405
|
-
reflex-0.7.
|
|
399
|
+
reflex/vars/sequence.py,sha256=PzFF1SC6r9iONV3t3nh5GKmToCTEm4B2GL3zGcNerl4,58099
|
|
400
|
+
reflex-0.7.4a1.dist-info/METADATA,sha256=Rl6X3yhbKBHSA5mBr88GK3STyGTmV3PSfO4RN78fcyc,12153
|
|
401
|
+
reflex-0.7.4a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
402
|
+
reflex-0.7.4a1.dist-info/entry_points.txt,sha256=Rxt4dXc7MLBNt5CSHTehVPuSe9Xqow4HLX55nD9tQQ0,45
|
|
403
|
+
reflex-0.7.4a1.dist-info/licenses/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
|
|
404
|
+
reflex-0.7.4a1.dist-info/RECORD,,
|
reflex/app_module_for_backend.py
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"""Shims the real reflex app module for running backend server (uvicorn or gunicorn).
|
|
2
|
-
Only the app attribute is explicitly exposed.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
6
|
-
|
|
7
|
-
from reflex import constants
|
|
8
|
-
from reflex.utils.exec import is_prod_mode
|
|
9
|
-
from reflex.utils.prerequisites import get_and_validate_app
|
|
10
|
-
|
|
11
|
-
if constants.CompileVars.APP != "app":
|
|
12
|
-
raise AssertionError("unexpected variable name for 'app'")
|
|
13
|
-
|
|
14
|
-
app, app_module = get_and_validate_app(reload=False)
|
|
15
|
-
# For py3.9 compatibility when redis is used, we MUST add any decorator pages
|
|
16
|
-
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
|
17
|
-
app._apply_decorated_pages()
|
|
18
|
-
compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile)
|
|
19
|
-
compile_future.add_done_callback(
|
|
20
|
-
# Force background compile errors to print eagerly
|
|
21
|
-
lambda f: f.result()
|
|
22
|
-
)
|
|
23
|
-
# Wait for the compile to finish in prod mode to ensure all optional endpoints are mounted.
|
|
24
|
-
if is_prod_mode():
|
|
25
|
-
compile_future.result()
|
|
26
|
-
|
|
27
|
-
# ensure only "app" is exposed.
|
|
28
|
-
del app_module
|
|
29
|
-
del compile_future
|
|
30
|
-
del get_and_validate_app
|
|
31
|
-
del is_prod_mode
|
|
32
|
-
del constants
|
|
33
|
-
del ThreadPoolExecutor
|
|
File without changes
|
|
File without changes
|
|
File without changes
|