reflex 0.7.3a1__py3-none-any.whl → 0.7.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +9 -1
- reflex/.templates/web/utils/state.js +1 -1
- reflex/app.py +21 -5
- reflex/app_mixins/middleware.py +2 -3
- reflex/base.py +3 -3
- reflex/compiler/compiler.py +68 -8
- reflex/components/component.py +6 -3
- reflex/components/core/client_side_routing.py +3 -3
- reflex/components/core/cond.py +20 -12
- reflex/components/core/upload.py +1 -1
- reflex/components/dynamic.py +2 -4
- reflex/components/lucide/icon.py +20 -27
- reflex/components/plotly/plotly.py +9 -9
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/sonner/toast.py +1 -1
- reflex/config.py +23 -23
- reflex/constants/__init__.py +1 -2
- reflex/constants/base.py +3 -0
- reflex/constants/installer.py +8 -105
- reflex/custom_components/custom_components.py +8 -3
- reflex/reflex.py +22 -4
- reflex/state.py +9 -1
- reflex/testing.py +7 -1
- reflex/utils/build.py +3 -4
- reflex/utils/exec.py +156 -75
- reflex/utils/net.py +107 -18
- reflex/utils/path_ops.py +15 -25
- reflex/utils/prerequisites.py +225 -189
- reflex/utils/processes.py +70 -35
- reflex/utils/redir.py +3 -1
- reflex/utils/registry.py +16 -8
- reflex/vars/base.py +2 -38
- reflex/vars/datetime.py +10 -34
- reflex/vars/number.py +16 -112
- reflex/vars/sequence.py +99 -108
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/METADATA +32 -23
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/RECORD +58 -68
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/WHEEL +1 -1
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/entry_points.txt +0 -3
- benchmarks/__init__.py +0 -3
- benchmarks/benchmark_compile_times.py +0 -147
- benchmarks/benchmark_imports.py +0 -128
- benchmarks/benchmark_lighthouse.py +0 -75
- benchmarks/benchmark_package_size.py +0 -135
- benchmarks/benchmark_web_size.py +0 -106
- benchmarks/conftest.py +0 -20
- benchmarks/lighthouse.sh +0 -77
- benchmarks/utils.py +0 -74
- reflex/app_module_for_backend.py +0 -33
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/licenses/LICENSE +0 -0
reflex/config.py
CHANGED
|
@@ -30,7 +30,6 @@ from typing import (
|
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
import pydantic.v1 as pydantic
|
|
33
|
-
from reflex_cli.constants.hosting import Hosting
|
|
34
33
|
|
|
35
34
|
from reflex import constants
|
|
36
35
|
from reflex.base import Base
|
|
@@ -45,7 +44,7 @@ from reflex.utils.types import (
|
|
|
45
44
|
)
|
|
46
45
|
|
|
47
46
|
try:
|
|
48
|
-
from dotenv import load_dotenv
|
|
47
|
+
from dotenv import load_dotenv
|
|
49
48
|
except ImportError:
|
|
50
49
|
load_dotenv = None
|
|
51
50
|
|
|
@@ -596,13 +595,13 @@ class EnvironmentVariables:
|
|
|
596
595
|
constants.CompileContext.UNDEFINED, internal=True
|
|
597
596
|
)
|
|
598
597
|
|
|
599
|
-
# Whether to use npm over bun to install frontend
|
|
598
|
+
# Whether to use npm over bun to install and run the frontend.
|
|
600
599
|
REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
|
|
601
600
|
|
|
602
601
|
# The npm registry to use.
|
|
603
602
|
NPM_CONFIG_REGISTRY: EnvVar[str | None] = env_var(None)
|
|
604
603
|
|
|
605
|
-
# Whether to use Granian for the backend.
|
|
604
|
+
# Whether to use Granian for the backend. By default, the backend uses Uvicorn if available.
|
|
606
605
|
REFLEX_USE_GRANIAN: EnvVar[bool] = env_var(False)
|
|
607
606
|
|
|
608
607
|
# The username to use for authentication on python package repository. Username and password must both be provided.
|
|
@@ -614,9 +613,6 @@ class EnvironmentVariables:
|
|
|
614
613
|
# Whether to use the system installed bun. If set to false, bun will be bundled with the app.
|
|
615
614
|
REFLEX_USE_SYSTEM_BUN: EnvVar[bool] = env_var(False)
|
|
616
615
|
|
|
617
|
-
# Whether to use the system installed node and npm. If set to false, node and npm will be bundled with the app.
|
|
618
|
-
REFLEX_USE_SYSTEM_NODE: EnvVar[bool] = env_var(False)
|
|
619
|
-
|
|
620
616
|
# The working directory for the next.js commands.
|
|
621
617
|
REFLEX_WEB_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.WEB))
|
|
622
618
|
|
|
@@ -724,6 +720,9 @@ class EnvironmentVariables:
|
|
|
724
720
|
# Used by flexgen to enumerate the pages.
|
|
725
721
|
REFLEX_ADD_ALL_ROUTES_ENDPOINT: EnvVar[bool] = env_var(False)
|
|
726
722
|
|
|
723
|
+
# The address to bind the HTTP client to. You can set this to "::" to enable IPv6.
|
|
724
|
+
REFLEX_HTTP_CLIENT_BIND_ADDRESS: EnvVar[str | None] = env_var(None)
|
|
725
|
+
|
|
727
726
|
|
|
728
727
|
environment = EnvironmentVariables()
|
|
729
728
|
|
|
@@ -810,8 +809,8 @@ class Config(Base):
|
|
|
810
809
|
# Tailwind config.
|
|
811
810
|
tailwind: dict[str, Any] | None = {"plugins": ["@tailwindcss/typography"]}
|
|
812
811
|
|
|
813
|
-
# Timeout when launching the gunicorn server.
|
|
814
|
-
timeout: int =
|
|
812
|
+
# DEPRECATED. Timeout when launching the gunicorn server.
|
|
813
|
+
timeout: int | None = None
|
|
815
814
|
|
|
816
815
|
# Whether to enable or disable nextJS gzip compression.
|
|
817
816
|
next_compression: bool = True
|
|
@@ -822,22 +821,17 @@ class Config(Base):
|
|
|
822
821
|
# Additional frontend packages to install.
|
|
823
822
|
frontend_packages: list[str] = []
|
|
824
823
|
|
|
825
|
-
# The
|
|
826
|
-
cp_backend_url: str = Hosting.HOSTING_SERVICE
|
|
827
|
-
# The hosting service frontend URL.
|
|
828
|
-
cp_web_url: str = Hosting.HOSTING_SERVICE_UI
|
|
829
|
-
|
|
830
|
-
# The worker class used in production mode
|
|
824
|
+
# DEPRECATED. The worker class used in production mode
|
|
831
825
|
gunicorn_worker_class: str = "uvicorn.workers.UvicornH11Worker"
|
|
832
826
|
|
|
833
|
-
# Number of gunicorn workers from user
|
|
827
|
+
# DEPRECATED. Number of gunicorn workers from user
|
|
834
828
|
gunicorn_workers: int | None = None
|
|
835
829
|
|
|
836
|
-
# Number of requests before a worker is restarted; set to 0 to disable
|
|
837
|
-
gunicorn_max_requests: int =
|
|
830
|
+
# DEPRECATED. Number of requests before a worker is restarted; set to 0 to disable
|
|
831
|
+
gunicorn_max_requests: int | None = None
|
|
838
832
|
|
|
839
|
-
# Variance limit for max requests; gunicorn only
|
|
840
|
-
gunicorn_max_requests_jitter: int =
|
|
833
|
+
# DEPRECATED. Variance limit for max requests; gunicorn only
|
|
834
|
+
gunicorn_max_requests_jitter: int | None = None
|
|
841
835
|
|
|
842
836
|
# Indicate which type of state manager to use
|
|
843
837
|
state_manager_mode: constants.StateManagerMode = constants.StateManagerMode.DISK
|
|
@@ -941,8 +935,14 @@ class Config(Base):
|
|
|
941
935
|
"""The `python-dotenv` package is required to load environment variables from a file. Run `pip install "python-dotenv>=1.0.1"`."""
|
|
942
936
|
)
|
|
943
937
|
else:
|
|
944
|
-
# load env
|
|
945
|
-
|
|
938
|
+
# load env files in reverse order if they exist
|
|
939
|
+
for env_file_path in [
|
|
940
|
+
Path(p)
|
|
941
|
+
for s in reversed(env_file.split(os.pathsep))
|
|
942
|
+
if (p := s.strip())
|
|
943
|
+
]:
|
|
944
|
+
if env_file_path.exists():
|
|
945
|
+
load_dotenv(env_file_path, override=True)
|
|
946
946
|
|
|
947
947
|
updated_values = {}
|
|
948
948
|
# Iterate over the fields.
|
|
@@ -964,7 +964,7 @@ class Config(Base):
|
|
|
964
964
|
env_var = "***"
|
|
965
965
|
|
|
966
966
|
if value != getattr(self, key):
|
|
967
|
-
console.
|
|
967
|
+
console.debug(
|
|
968
968
|
f"Overriding config value {key} with env var {key.upper()}={env_var}",
|
|
969
969
|
dedupe=True,
|
|
970
970
|
)
|
reflex/constants/__init__.py
CHANGED
|
@@ -45,7 +45,7 @@ from .config import (
|
|
|
45
45
|
)
|
|
46
46
|
from .custom_components import CustomComponents
|
|
47
47
|
from .event import Endpoint, EventTriggers, SocketEvent
|
|
48
|
-
from .installer import Bun,
|
|
48
|
+
from .installer import Bun, Node, PackageJson
|
|
49
49
|
from .route import (
|
|
50
50
|
ROUTE_NOT_FOUND,
|
|
51
51
|
ROUTER,
|
|
@@ -94,7 +94,6 @@ __all__ = [
|
|
|
94
94
|
"EventTriggers",
|
|
95
95
|
"Expiration",
|
|
96
96
|
"Ext",
|
|
97
|
-
"Fnm",
|
|
98
97
|
"GitIgnore",
|
|
99
98
|
"Hooks",
|
|
100
99
|
"Imports",
|
reflex/constants/base.py
CHANGED
|
@@ -88,6 +88,9 @@ class Reflex(SimpleNamespace):
|
|
|
88
88
|
|
|
89
89
|
RELEASES_URL = "https://api.github.com/repos/reflex-dev/templates/releases"
|
|
90
90
|
|
|
91
|
+
# The reflex stylesheet language supported
|
|
92
|
+
STYLESHEETS_SUPPORTED = ["css", "sass", "scss"]
|
|
93
|
+
|
|
91
94
|
|
|
92
95
|
class ReflexHostingCLI(SimpleNamespace):
|
|
93
96
|
"""Base constants concerning Reflex Hosting CLI."""
|
reflex/constants/installer.py
CHANGED
|
@@ -1,46 +1,22 @@
|
|
|
1
|
-
"""File for constants related to the installation process. (Bun/
|
|
1
|
+
"""File for constants related to the installation process. (Bun/Node)."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import platform
|
|
6
|
-
from pathlib import Path
|
|
7
5
|
from types import SimpleNamespace
|
|
8
6
|
|
|
9
7
|
from .base import IS_WINDOWS
|
|
10
8
|
from .utils import classproperty
|
|
11
9
|
|
|
12
10
|
|
|
13
|
-
def get_fnm_name() -> str | None:
|
|
14
|
-
"""Get the appropriate fnm executable name based on the current platform.
|
|
15
|
-
|
|
16
|
-
Returns:
|
|
17
|
-
The fnm executable name for the current platform.
|
|
18
|
-
"""
|
|
19
|
-
platform_os = platform.system()
|
|
20
|
-
|
|
21
|
-
if platform_os == "Windows":
|
|
22
|
-
return "fnm-windows"
|
|
23
|
-
elif platform_os == "Darwin":
|
|
24
|
-
return "fnm-macos"
|
|
25
|
-
elif platform_os == "Linux":
|
|
26
|
-
machine = platform.machine()
|
|
27
|
-
if machine == "arm" or machine.startswith("armv7"):
|
|
28
|
-
return "fnm-arm32"
|
|
29
|
-
elif machine.startswith("aarch") or machine.startswith("armv8"):
|
|
30
|
-
return "fnm-arm64"
|
|
31
|
-
return "fnm-linux"
|
|
32
|
-
return None
|
|
33
|
-
|
|
34
|
-
|
|
35
11
|
# Bun config.
|
|
36
12
|
class Bun(SimpleNamespace):
|
|
37
13
|
"""Bun constants."""
|
|
38
14
|
|
|
39
15
|
# The Bun version.
|
|
40
|
-
VERSION = "1.2.
|
|
16
|
+
VERSION = "1.2.4"
|
|
41
17
|
|
|
42
18
|
# Min Bun Version
|
|
43
|
-
MIN_VERSION = "1.
|
|
19
|
+
MIN_VERSION = "1.2.4"
|
|
44
20
|
|
|
45
21
|
# URL to bun install script.
|
|
46
22
|
INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh"
|
|
@@ -81,43 +57,6 @@ registry = "{registry}"
|
|
|
81
57
|
"""
|
|
82
58
|
|
|
83
59
|
|
|
84
|
-
# FNM config.
|
|
85
|
-
class Fnm(SimpleNamespace):
|
|
86
|
-
"""FNM constants."""
|
|
87
|
-
|
|
88
|
-
# The FNM version.
|
|
89
|
-
VERSION = "1.35.1"
|
|
90
|
-
|
|
91
|
-
FILENAME = get_fnm_name()
|
|
92
|
-
|
|
93
|
-
# The URL to the fnm release binary
|
|
94
|
-
INSTALL_URL = (
|
|
95
|
-
f"https://github.com/Schniz/fnm/releases/download/v{VERSION}/{FILENAME}.zip"
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
@classproperty
|
|
99
|
-
@classmethod
|
|
100
|
-
def DIR(cls) -> Path:
|
|
101
|
-
"""The directory to store fnm.
|
|
102
|
-
|
|
103
|
-
Returns:
|
|
104
|
-
The directory to store fnm.
|
|
105
|
-
"""
|
|
106
|
-
from reflex.config import environment
|
|
107
|
-
|
|
108
|
-
return environment.REFLEX_DIR.get() / "fnm"
|
|
109
|
-
|
|
110
|
-
@classproperty
|
|
111
|
-
@classmethod
|
|
112
|
-
def EXE(cls):
|
|
113
|
-
"""The fnm executable binary.
|
|
114
|
-
|
|
115
|
-
Returns:
|
|
116
|
-
The fnm executable binary.
|
|
117
|
-
"""
|
|
118
|
-
return cls.DIR / ("fnm.exe" if IS_WINDOWS else "fnm")
|
|
119
|
-
|
|
120
|
-
|
|
121
60
|
# Node / NPM config
|
|
122
61
|
class Node(SimpleNamespace):
|
|
123
62
|
"""Node/ NPM constants."""
|
|
@@ -127,42 +66,6 @@ class Node(SimpleNamespace):
|
|
|
127
66
|
# The minimum required node version.
|
|
128
67
|
MIN_VERSION = "18.18.0"
|
|
129
68
|
|
|
130
|
-
@classproperty
|
|
131
|
-
@classmethod
|
|
132
|
-
def BIN_PATH(cls):
|
|
133
|
-
"""The node bin path.
|
|
134
|
-
|
|
135
|
-
Returns:
|
|
136
|
-
The node bin path.
|
|
137
|
-
"""
|
|
138
|
-
return (
|
|
139
|
-
Fnm.DIR
|
|
140
|
-
/ "node-versions"
|
|
141
|
-
/ f"v{cls.VERSION}"
|
|
142
|
-
/ "installation"
|
|
143
|
-
/ ("bin" if not IS_WINDOWS else "")
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
@classproperty
|
|
147
|
-
@classmethod
|
|
148
|
-
def PATH(cls):
|
|
149
|
-
"""The default path where node is installed.
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
The default path where node is installed.
|
|
153
|
-
"""
|
|
154
|
-
return cls.BIN_PATH / ("node.exe" if IS_WINDOWS else "node")
|
|
155
|
-
|
|
156
|
-
@classproperty
|
|
157
|
-
@classmethod
|
|
158
|
-
def NPM_PATH(cls):
|
|
159
|
-
"""The default path where npm is installed.
|
|
160
|
-
|
|
161
|
-
Returns:
|
|
162
|
-
The default path where npm is installed.
|
|
163
|
-
"""
|
|
164
|
-
return cls.BIN_PATH / "npm"
|
|
165
|
-
|
|
166
69
|
|
|
167
70
|
class PackageJson(SimpleNamespace):
|
|
168
71
|
"""Constants used to build the package.json file."""
|
|
@@ -179,11 +82,11 @@ class PackageJson(SimpleNamespace):
|
|
|
179
82
|
|
|
180
83
|
DEPENDENCIES = {
|
|
181
84
|
"@emotion/react": "11.14.0",
|
|
182
|
-
"axios": "1.
|
|
85
|
+
"axios": "1.8.3",
|
|
183
86
|
"json5": "2.2.3",
|
|
184
|
-
"next": "15.
|
|
87
|
+
"next": "15.0.4",
|
|
185
88
|
"next-sitemap": "4.2.3",
|
|
186
|
-
"next-themes": "0.4.
|
|
89
|
+
"next-themes": "0.4.6",
|
|
187
90
|
"react": "19.0.0",
|
|
188
91
|
"react-dom": "19.0.0",
|
|
189
92
|
"react-focus-lock": "2.13.6",
|
|
@@ -191,8 +94,8 @@ class PackageJson(SimpleNamespace):
|
|
|
191
94
|
"universal-cookie": "7.2.2",
|
|
192
95
|
}
|
|
193
96
|
DEV_DEPENDENCIES = {
|
|
194
|
-
"autoprefixer": "10.4.
|
|
195
|
-
"postcss": "8.5.
|
|
97
|
+
"autoprefixer": "10.4.21",
|
|
98
|
+
"postcss": "8.5.3",
|
|
196
99
|
"postcss-import": "16.1.0",
|
|
197
100
|
}
|
|
198
101
|
OVERRIDES = {
|
|
@@ -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,23 @@ 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_or_validate_app
|
|
209
|
+
args = (frontend,)
|
|
210
|
+
|
|
211
|
+
# Granian fails if the app is already imported.
|
|
212
|
+
if should_use_granian():
|
|
213
|
+
import concurrent.futures
|
|
214
|
+
|
|
215
|
+
compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
|
|
216
|
+
app_task,
|
|
217
|
+
*args,
|
|
218
|
+
)
|
|
219
|
+
validation_result = compile_future.result()
|
|
220
|
+
else:
|
|
221
|
+
validation_result = app_task(*args)
|
|
222
|
+
if not validation_result:
|
|
223
|
+
raise typer.Exit(1)
|
|
209
224
|
|
|
210
225
|
# Warn if schema is not up to date.
|
|
211
226
|
prerequisites.check_schema_up_to_date()
|
|
@@ -386,6 +401,7 @@ def export(
|
|
|
386
401
|
def login(loglevel: constants.LogLevel | None = typer.Option(None)):
|
|
387
402
|
"""Authenticate with experimental Reflex hosting service."""
|
|
388
403
|
from reflex_cli.v2 import cli as hosting_cli
|
|
404
|
+
from reflex_cli.v2.deployments import check_version
|
|
389
405
|
|
|
390
406
|
loglevel = loglevel or get_config().loglevel
|
|
391
407
|
|
|
@@ -407,6 +423,7 @@ def logout(
|
|
|
407
423
|
):
|
|
408
424
|
"""Log out of access to Reflex hosting service."""
|
|
409
425
|
from reflex_cli.v2.cli import logout
|
|
426
|
+
from reflex_cli.v2.deployments import check_version
|
|
410
427
|
|
|
411
428
|
check_version()
|
|
412
429
|
|
|
@@ -567,6 +584,7 @@ def deploy(
|
|
|
567
584
|
from reflex_cli.constants.base import LogLevel as HostingLogLevel
|
|
568
585
|
from reflex_cli.utils import dependency
|
|
569
586
|
from reflex_cli.v2 import cli as hosting_cli
|
|
587
|
+
from reflex_cli.v2.deployments import check_version
|
|
570
588
|
|
|
571
589
|
from reflex.utils import export as export_utils
|
|
572
590
|
from reflex.utils import prerequisites
|
reflex/state.py
CHANGED
|
@@ -905,7 +905,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
905
905
|
]
|
|
906
906
|
if len(parent_states) >= 2:
|
|
907
907
|
raise ValueError(f"Only one parent state is allowed {parent_states}.")
|
|
908
|
-
|
|
908
|
+
# The first non-mixin state in the mro is our parent.
|
|
909
|
+
for base in cls.mro()[1:]:
|
|
910
|
+
if not issubclass(base, BaseState) or base._mixin:
|
|
911
|
+
continue
|
|
912
|
+
if base is BaseState:
|
|
913
|
+
break
|
|
914
|
+
return base
|
|
915
|
+
return None # No known parent
|
|
909
916
|
|
|
910
917
|
@classmethod
|
|
911
918
|
@functools.lru_cache()
|
|
@@ -1664,6 +1671,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1664
1671
|
|
|
1665
1672
|
raise TypeError(
|
|
1666
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}."
|
|
1667
1675
|
)
|
|
1668
1676
|
|
|
1669
1677
|
async def _as_state_update(
|
reflex/testing.py
CHANGED
|
@@ -371,7 +371,13 @@ class AppHarness:
|
|
|
371
371
|
|
|
372
372
|
# Start the frontend.
|
|
373
373
|
self.frontend_process = reflex.utils.processes.new_process(
|
|
374
|
-
[
|
|
374
|
+
[
|
|
375
|
+
*reflex.utils.prerequisites.get_js_package_executor(raise_on_none=True)[
|
|
376
|
+
0
|
|
377
|
+
],
|
|
378
|
+
"run",
|
|
379
|
+
"dev",
|
|
380
|
+
],
|
|
375
381
|
cwd=self.app_path / reflex.utils.prerequisites.get_web_dir(),
|
|
376
382
|
env={"PORT": "0"},
|
|
377
383
|
**FRONTEND_POPEN_ARGS,
|
reflex/utils/build.py
CHANGED
|
@@ -212,7 +212,7 @@ def build(
|
|
|
212
212
|
|
|
213
213
|
# Start the subprocess with the progress bar.
|
|
214
214
|
process = processes.new_process(
|
|
215
|
-
[prerequisites.
|
|
215
|
+
[*prerequisites.get_js_package_executor(raise_on_none=True)[0], "run", command],
|
|
216
216
|
cwd=wdir,
|
|
217
217
|
shell=constants.IS_WINDOWS,
|
|
218
218
|
)
|
|
@@ -231,11 +231,10 @@ def setup_frontend(
|
|
|
231
231
|
"""
|
|
232
232
|
# Create the assets dir if it doesn't exist.
|
|
233
233
|
path_ops.mkdir(constants.Dirs.APP_ASSETS)
|
|
234
|
-
|
|
235
|
-
# Copy asset files to public folder.
|
|
236
234
|
path_ops.cp(
|
|
237
235
|
src=str(root / constants.Dirs.APP_ASSETS),
|
|
238
236
|
dest=str(root / prerequisites.get_web_dir() / constants.Dirs.PUBLIC),
|
|
237
|
+
ignore=tuple(f"*.{ext}" for ext in constants.Reflex.STYLESHEETS_SUPPORTED),
|
|
239
238
|
)
|
|
240
239
|
|
|
241
240
|
# Set the environment variables in client (env.json).
|
|
@@ -248,7 +247,7 @@ def setup_frontend(
|
|
|
248
247
|
if disable_telemetry:
|
|
249
248
|
processes.new_process(
|
|
250
249
|
[
|
|
251
|
-
prerequisites.
|
|
250
|
+
*prerequisites.get_js_package_executor(raise_on_none=True)[0],
|
|
252
251
|
"run",
|
|
253
252
|
"next",
|
|
254
253
|
"telemetry",
|