reflex 0.8.0a6__py3-none-any.whl → 0.8.1__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/utils/state.js +18 -1
- reflex/.templates/web/vite-plugin-safari-cachebust.js +160 -0
- reflex/.templates/web/vite.config.js +28 -6
- reflex/app.py +1 -1
- reflex/components/__init__.py +1 -0
- reflex/components/__init__.pyi +2 -0
- reflex/components/component.py +53 -1
- reflex/components/core/banner.py +3 -13
- reflex/components/core/upload.py +5 -5
- reflex/components/core/upload.pyi +2 -2
- reflex/components/el/__init__.py +7 -1
- reflex/components/el/__init__.pyi +2 -1
- reflex/components/radix/primitives/accordion.py +10 -29
- reflex/components/radix/primitives/accordion.pyi +7 -1
- reflex/components/radix/themes/typography/link.py +1 -30
- reflex/components/radix/themes/typography/link.pyi +1 -304
- reflex/components/react_router/__init__.py +5 -0
- reflex/components/react_router/dom.py +69 -0
- reflex/components/react_router/dom.pyi +321 -0
- reflex/components/recharts/recharts.py +2 -2
- reflex/config.py +7 -36
- reflex/constants/compiler.py +1 -1
- reflex/constants/installer.py +2 -2
- reflex/environment.py +116 -0
- reflex/event.py +18 -1
- reflex/istate/data.py +142 -69
- reflex/plugins/tailwind_v4.py +2 -2
- reflex/state.py +3 -3
- reflex/utils/exec.py +35 -8
- reflex/utils/lazy_loader.py +7 -1
- reflex/utils/misc.py +1 -2
- reflex/utils/processes.py +27 -3
- reflex/utils/pyi_generator.py +17 -2
- {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/METADATA +3 -3
- {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/RECORD +38 -34
- {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/WHEEL +0 -0
- {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.0a6.dist-info → reflex-0.8.1.dist-info}/licenses/LICENSE +0 -0
reflex/istate/data.py
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
from collections.abc import Mapping
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
from urllib.parse import _NetlocResultMixinStr, urlsplit
|
|
5
7
|
|
|
6
8
|
from reflex import constants
|
|
7
|
-
from reflex.utils import format
|
|
9
|
+
from reflex.utils import console, format
|
|
8
10
|
from reflex.utils.serializers import serializer
|
|
9
11
|
|
|
10
12
|
|
|
@@ -45,36 +47,40 @@ class _HeaderData:
|
|
|
45
47
|
)
|
|
46
48
|
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
_HEADER_DATA_FIELDS = frozenset(
|
|
51
|
+
[field.name for field in dataclasses.fields(_HeaderData)]
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclasses.dataclass(frozen=True)
|
|
49
56
|
class HeaderData(_HeaderData):
|
|
50
57
|
"""An object containing headers data."""
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_router_data(cls, router_data: dict) -> "HeaderData":
|
|
61
|
+
"""Create a HeaderData object from the given router_data.
|
|
54
62
|
|
|
55
63
|
Args:
|
|
56
64
|
router_data: the router_data dict.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
A HeaderData object initialized with the provided router_data.
|
|
57
68
|
"""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
).items()
|
|
74
|
-
if v
|
|
75
|
-
}
|
|
76
|
-
),
|
|
77
|
-
)
|
|
69
|
+
return cls(
|
|
70
|
+
**{
|
|
71
|
+
snake_case_key: v
|
|
72
|
+
for k, v in router_data.get(constants.RouteVar.HEADERS, {}).items()
|
|
73
|
+
if v
|
|
74
|
+
and (snake_case_key := format.to_snake_case(k)) in _HEADER_DATA_FIELDS
|
|
75
|
+
},
|
|
76
|
+
raw_headers=_FrozenDictStrStr(
|
|
77
|
+
**{
|
|
78
|
+
k: v
|
|
79
|
+
for k, v in router_data.get(constants.RouteVar.HEADERS, {}).items()
|
|
80
|
+
if v
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
)
|
|
78
84
|
|
|
79
85
|
|
|
80
86
|
@serializer(to=dict)
|
|
@@ -90,6 +96,35 @@ def serialize_frozen_dict_str_str(obj: _FrozenDictStrStr) -> dict:
|
|
|
90
96
|
return dict(obj._data)
|
|
91
97
|
|
|
92
98
|
|
|
99
|
+
class ReflexURL(str, _NetlocResultMixinStr):
|
|
100
|
+
"""A class representing a URL split result."""
|
|
101
|
+
|
|
102
|
+
if TYPE_CHECKING:
|
|
103
|
+
scheme: str
|
|
104
|
+
netloc: str
|
|
105
|
+
path: str
|
|
106
|
+
query: str
|
|
107
|
+
fragment: str
|
|
108
|
+
|
|
109
|
+
def __new__(cls, url: str):
|
|
110
|
+
"""Create a new ReflexURL instance.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
url: the URL to split.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
A new ReflexURL instance.
|
|
117
|
+
"""
|
|
118
|
+
(scheme, netloc, path, query, fragment) = urlsplit(url)
|
|
119
|
+
obj = super().__new__(cls, url)
|
|
120
|
+
object.__setattr__(obj, "scheme", scheme)
|
|
121
|
+
object.__setattr__(obj, "netloc", netloc)
|
|
122
|
+
object.__setattr__(obj, "path", path)
|
|
123
|
+
object.__setattr__(obj, "query", query)
|
|
124
|
+
object.__setattr__(obj, "fragment", fragment)
|
|
125
|
+
return obj
|
|
126
|
+
|
|
127
|
+
|
|
93
128
|
@dataclasses.dataclass(frozen=True)
|
|
94
129
|
class PageData:
|
|
95
130
|
"""An object containing page data."""
|
|
@@ -101,39 +136,30 @@ class PageData:
|
|
|
101
136
|
full_raw_path: str = ""
|
|
102
137
|
params: dict = dataclasses.field(default_factory=dict)
|
|
103
138
|
|
|
104
|
-
|
|
105
|
-
|
|
139
|
+
@classmethod
|
|
140
|
+
def from_router_data(cls, router_data: dict) -> "PageData":
|
|
141
|
+
"""Create a PageData object from the given router_data.
|
|
106
142
|
|
|
107
143
|
Args:
|
|
108
144
|
router_data: the router_data dict.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
A PageData object initialized with the provided router_data.
|
|
109
148
|
"""
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
object.__setattr__(self, "full_path", f"{self.host}{self.path}")
|
|
123
|
-
object.__setattr__(self, "full_raw_path", f"{self.host}{self.raw_path}")
|
|
124
|
-
object.__setattr__(
|
|
125
|
-
self, "params", router_data.get(constants.RouteVar.QUERY, {})
|
|
126
|
-
)
|
|
127
|
-
else:
|
|
128
|
-
object.__setattr__(self, "host", "")
|
|
129
|
-
object.__setattr__(self, "path", "")
|
|
130
|
-
object.__setattr__(self, "raw_path", "")
|
|
131
|
-
object.__setattr__(self, "full_path", "")
|
|
132
|
-
object.__setattr__(self, "full_raw_path", "")
|
|
133
|
-
object.__setattr__(self, "params", {})
|
|
149
|
+
host = router_data.get(constants.RouteVar.HEADERS, {}).get("origin", "")
|
|
150
|
+
path = router_data.get(constants.RouteVar.PATH, "")
|
|
151
|
+
raw_path = router_data.get(constants.RouteVar.ORIGIN, "")
|
|
152
|
+
return cls(
|
|
153
|
+
host=host,
|
|
154
|
+
path=path,
|
|
155
|
+
raw_path=raw_path,
|
|
156
|
+
full_path=f"{host}{path}",
|
|
157
|
+
full_raw_path=f"{host}{raw_path}",
|
|
158
|
+
params=router_data.get(constants.RouteVar.QUERY, {}),
|
|
159
|
+
)
|
|
134
160
|
|
|
135
161
|
|
|
136
|
-
@dataclasses.dataclass(frozen=True
|
|
162
|
+
@dataclasses.dataclass(frozen=True)
|
|
137
163
|
class SessionData:
|
|
138
164
|
"""An object containing session data."""
|
|
139
165
|
|
|
@@ -141,37 +167,84 @@ class SessionData:
|
|
|
141
167
|
client_ip: str = ""
|
|
142
168
|
session_id: str = ""
|
|
143
169
|
|
|
144
|
-
|
|
145
|
-
|
|
170
|
+
@classmethod
|
|
171
|
+
def from_router_data(cls, router_data: dict) -> "SessionData":
|
|
172
|
+
"""Create a SessionData object from the given router_data.
|
|
146
173
|
|
|
147
174
|
Args:
|
|
148
175
|
router_data: the router_data dict.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
A SessionData object initialized with the provided router_data.
|
|
149
179
|
"""
|
|
150
|
-
|
|
151
|
-
client_token
|
|
152
|
-
client_ip
|
|
153
|
-
session_id
|
|
154
|
-
|
|
155
|
-
client_token = client_ip = session_id = ""
|
|
156
|
-
object.__setattr__(self, "client_token", client_token)
|
|
157
|
-
object.__setattr__(self, "client_ip", client_ip)
|
|
158
|
-
object.__setattr__(self, "session_id", session_id)
|
|
180
|
+
return cls(
|
|
181
|
+
client_token=router_data.get(constants.RouteVar.CLIENT_TOKEN, ""),
|
|
182
|
+
client_ip=router_data.get(constants.RouteVar.CLIENT_IP, ""),
|
|
183
|
+
session_id=router_data.get(constants.RouteVar.SESSION_ID, ""),
|
|
184
|
+
)
|
|
159
185
|
|
|
160
186
|
|
|
161
|
-
@dataclasses.dataclass(frozen=True
|
|
187
|
+
@dataclasses.dataclass(frozen=True)
|
|
162
188
|
class RouterData:
|
|
163
189
|
"""An object containing RouterData."""
|
|
164
190
|
|
|
165
191
|
session: SessionData = dataclasses.field(default_factory=SessionData)
|
|
166
192
|
headers: HeaderData = dataclasses.field(default_factory=HeaderData)
|
|
167
|
-
|
|
193
|
+
_page: PageData = dataclasses.field(default_factory=PageData)
|
|
194
|
+
url: ReflexURL = dataclasses.field(default=ReflexURL(""))
|
|
195
|
+
route_id: str = ""
|
|
168
196
|
|
|
169
|
-
|
|
170
|
-
|
|
197
|
+
@property
|
|
198
|
+
def page(self) -> PageData:
|
|
199
|
+
"""Get the page data.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
The PageData object.
|
|
203
|
+
"""
|
|
204
|
+
console.deprecate(
|
|
205
|
+
"RouterData.page",
|
|
206
|
+
"Use RouterData.url instead",
|
|
207
|
+
deprecation_version="0.8.1",
|
|
208
|
+
removal_version="0.9.0",
|
|
209
|
+
)
|
|
210
|
+
return self._page
|
|
211
|
+
|
|
212
|
+
@classmethod
|
|
213
|
+
def from_router_data(cls, router_data: dict) -> "RouterData":
|
|
214
|
+
"""Create a RouterData object from the given router_data.
|
|
171
215
|
|
|
172
216
|
Args:
|
|
173
217
|
router_data: the router_data dict.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
A RouterData object initialized with the provided router_data.
|
|
174
221
|
"""
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
222
|
+
return cls(
|
|
223
|
+
session=SessionData.from_router_data(router_data),
|
|
224
|
+
headers=HeaderData.from_router_data(router_data),
|
|
225
|
+
_page=PageData.from_router_data(router_data),
|
|
226
|
+
url=ReflexURL(
|
|
227
|
+
router_data.get(constants.RouteVar.HEADERS, {}).get("origin", "")
|
|
228
|
+
+ router_data.get(constants.RouteVar.ORIGIN, "")
|
|
229
|
+
),
|
|
230
|
+
route_id=router_data.get(constants.RouteVar.PATH, ""),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@serializer(to=dict)
|
|
235
|
+
def serialize_router_data(obj: RouterData) -> dict:
|
|
236
|
+
"""Serialize a RouterData object to a dict.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
obj: the RouterData object.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
A dict representation of the RouterData object.
|
|
243
|
+
"""
|
|
244
|
+
return {
|
|
245
|
+
"session": obj.session,
|
|
246
|
+
"headers": obj.headers,
|
|
247
|
+
"page": obj._page,
|
|
248
|
+
"url": obj.url,
|
|
249
|
+
"route_id": obj.route_id,
|
|
250
|
+
}
|
reflex/plugins/tailwind_v4.py
CHANGED
|
@@ -17,7 +17,7 @@ class Constants(SimpleNamespace):
|
|
|
17
17
|
"""Tailwind constants."""
|
|
18
18
|
|
|
19
19
|
# The Tailwindcss version
|
|
20
|
-
VERSION = "tailwindcss@4.1.
|
|
20
|
+
VERSION = "tailwindcss@4.1.11"
|
|
21
21
|
# The Tailwind config.
|
|
22
22
|
CONFIG = "tailwind.config.js"
|
|
23
23
|
# Default Tailwind content paths
|
|
@@ -156,7 +156,7 @@ class TailwindV4Plugin(TailwindPlugin):
|
|
|
156
156
|
return [
|
|
157
157
|
*super().get_frontend_development_dependencies(**context),
|
|
158
158
|
Constants.VERSION,
|
|
159
|
-
"@tailwindcss/postcss@4.1.
|
|
159
|
+
"@tailwindcss/postcss@4.1.11",
|
|
160
160
|
]
|
|
161
161
|
|
|
162
162
|
def pre_compile(self, **context):
|
reflex/state.py
CHANGED
|
@@ -1204,7 +1204,7 @@ class BaseState(EvenMoreBasicBaseState):
|
|
|
1204
1204
|
|
|
1205
1205
|
def argsingle_factory(param: str):
|
|
1206
1206
|
def inner_func(self: BaseState) -> str:
|
|
1207
|
-
return self.router.
|
|
1207
|
+
return self.router._page.params.get(param, "")
|
|
1208
1208
|
|
|
1209
1209
|
inner_func.__name__ = param
|
|
1210
1210
|
|
|
@@ -1212,7 +1212,7 @@ class BaseState(EvenMoreBasicBaseState):
|
|
|
1212
1212
|
|
|
1213
1213
|
def arglist_factory(param: str):
|
|
1214
1214
|
def inner_func(self: BaseState) -> list[str]:
|
|
1215
|
-
return self.router.
|
|
1215
|
+
return self.router._page.params.get(param, [])
|
|
1216
1216
|
|
|
1217
1217
|
inner_func.__name__ = param
|
|
1218
1218
|
|
|
@@ -2466,7 +2466,7 @@ class OnLoadInternalState(State):
|
|
|
2466
2466
|
"""
|
|
2467
2467
|
# Do not app._compile()! It should be already compiled by now.
|
|
2468
2468
|
load_events = prerequisites.get_and_validate_app().app.get_load_events(
|
|
2469
|
-
self.router.
|
|
2469
|
+
self.router._page.path
|
|
2470
2470
|
)
|
|
2471
2471
|
if not load_events:
|
|
2472
2472
|
self.is_hydrated = True
|
reflex/utils/exec.py
CHANGED
|
@@ -519,9 +519,11 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel):
|
|
|
519
519
|
|
|
520
520
|
from granian.constants import Interfaces
|
|
521
521
|
from granian.log import LogLevels
|
|
522
|
-
from granian.server import
|
|
522
|
+
from granian.server import Server as Granian
|
|
523
523
|
|
|
524
|
-
|
|
524
|
+
from reflex.environment import _paths_from_environment
|
|
525
|
+
|
|
526
|
+
granian_app = Granian(
|
|
525
527
|
target=get_app_instance_from_file(),
|
|
526
528
|
factory=True,
|
|
527
529
|
address=host,
|
|
@@ -533,8 +535,11 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel):
|
|
|
533
535
|
reload_ignore_worker_failure=True,
|
|
534
536
|
reload_ignore_patterns=HOTRELOAD_IGNORE_PATTERNS,
|
|
535
537
|
reload_tick=100,
|
|
538
|
+
env_files=_paths_from_environment() or None,
|
|
536
539
|
workers_kill_timeout=2,
|
|
537
|
-
)
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
granian_app.serve()
|
|
538
543
|
|
|
539
544
|
|
|
540
545
|
def run_backend_prod(
|
|
@@ -568,15 +573,37 @@ def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
|
568
573
|
port: The app port
|
|
569
574
|
loglevel: The log level.
|
|
570
575
|
"""
|
|
576
|
+
import os
|
|
577
|
+
import shlex
|
|
578
|
+
|
|
571
579
|
from reflex.utils import processes
|
|
572
580
|
|
|
573
581
|
app_module = get_app_instance()
|
|
574
582
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
583
|
+
if constants.IS_WINDOWS:
|
|
584
|
+
command = [
|
|
585
|
+
"uvicorn",
|
|
586
|
+
*("--host", host),
|
|
587
|
+
*("--port", str(port)),
|
|
588
|
+
"--factory",
|
|
589
|
+
app_module,
|
|
590
|
+
]
|
|
591
|
+
else:
|
|
592
|
+
# Parse GUNICORN_CMD_ARGS for user overrides
|
|
593
|
+
env_args = []
|
|
594
|
+
if gunicorn_cmd_args := os.environ.get("GUNICORN_CMD_ARGS", ""):
|
|
595
|
+
env_args = shlex.split(gunicorn_cmd_args)
|
|
596
|
+
|
|
597
|
+
# Our default args, then env args (env args win on conflicts)
|
|
598
|
+
command = [
|
|
599
|
+
"gunicorn",
|
|
600
|
+
"--preload",
|
|
601
|
+
"--worker-class",
|
|
602
|
+
"uvicorn.workers.UvicornH11Worker",
|
|
603
|
+
*("--bind", f"{host}:{port}"),
|
|
604
|
+
*env_args,
|
|
605
|
+
f"{app_module}()",
|
|
606
|
+
]
|
|
580
607
|
|
|
581
608
|
command += [
|
|
582
609
|
*("--log-level", loglevel.value),
|
reflex/utils/lazy_loader.py
CHANGED
|
@@ -27,6 +27,7 @@ def attach(
|
|
|
27
27
|
package_name: str,
|
|
28
28
|
submodules: set[str] | None = None,
|
|
29
29
|
submod_attrs: dict[str, list[str]] | None = None,
|
|
30
|
+
**extra_mappings,
|
|
30
31
|
):
|
|
31
32
|
"""Replaces a package's __getattr__, __dir__, and __all__ attributes using lazy.attach.
|
|
32
33
|
The lazy loader __getattr__ doesn't support tuples as list values. We needed to add
|
|
@@ -39,6 +40,7 @@ def attach(
|
|
|
39
40
|
submodules : List of submodules to attach.
|
|
40
41
|
submod_attrs : Dictionary of submodule -> list of attributes / functions.
|
|
41
42
|
These attributes are imported as they are used.
|
|
43
|
+
extra_mappings: Additional mappings to resolve lazily.
|
|
42
44
|
|
|
43
45
|
Returns:
|
|
44
46
|
__getattr__, __dir__, __all__
|
|
@@ -60,9 +62,13 @@ def attach(
|
|
|
60
62
|
attr: mod for mod, attrs in submod_attrs.items() for attr in attrs
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
__all__ = sorted(submodules | attr_to_modules.keys())
|
|
65
|
+
__all__ = sorted([*(submodules | attr_to_modules.keys()), *(extra_mappings or [])])
|
|
64
66
|
|
|
65
67
|
def __getattr__(name: str): # noqa: N807
|
|
68
|
+
if name in extra_mappings:
|
|
69
|
+
submod_path, attr = extra_mappings[name].rsplit(".", 1)
|
|
70
|
+
submod = importlib.import_module(submod_path)
|
|
71
|
+
return getattr(submod, attr)
|
|
66
72
|
if name in submodules:
|
|
67
73
|
return importlib.import_module(f"{package_name}.{name}")
|
|
68
74
|
if name in attr_to_modules:
|
reflex/utils/misc.py
CHANGED
|
@@ -31,14 +31,13 @@ def get_module_path(module_name: str) -> Path | None:
|
|
|
31
31
|
for i, part in enumerate(parts):
|
|
32
32
|
potential_file = current_path / (part + ".py")
|
|
33
33
|
potential_dir = current_path / part
|
|
34
|
-
potential_init = current_path / part / "__init__.py"
|
|
35
34
|
|
|
36
35
|
if potential_file.is_file():
|
|
37
36
|
# We encountered a file, but we can't continue deeper
|
|
38
37
|
if i == len(parts) - 1:
|
|
39
38
|
return potential_file
|
|
40
39
|
return None # Can't continue deeper
|
|
41
|
-
if potential_dir.is_dir()
|
|
40
|
+
if potential_dir.is_dir():
|
|
42
41
|
# It's a package, so we can continue deeper
|
|
43
42
|
current_path = potential_dir
|
|
44
43
|
else:
|
reflex/utils/processes.py
CHANGED
|
@@ -15,6 +15,7 @@ from pathlib import Path
|
|
|
15
15
|
from typing import Any, Literal, overload
|
|
16
16
|
|
|
17
17
|
import click
|
|
18
|
+
import rich.markup
|
|
18
19
|
from redis.exceptions import RedisError
|
|
19
20
|
from rich.progress import Progress
|
|
20
21
|
|
|
@@ -52,6 +53,26 @@ def get_num_workers() -> int:
|
|
|
52
53
|
return (os.cpu_count() or 1) * 2 + 1
|
|
53
54
|
|
|
54
55
|
|
|
56
|
+
def _is_address_responsive(
|
|
57
|
+
address_family: socket.AddressFamily | int, address: str, port: int
|
|
58
|
+
) -> bool:
|
|
59
|
+
"""Check if a given address and port are responsive.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
address_family: The address family (e.g., socket.AF_INET or socket.AF_INET6).
|
|
63
|
+
address: The address to check.
|
|
64
|
+
port: The port to check.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Whether the address and port are responsive.
|
|
68
|
+
"""
|
|
69
|
+
try:
|
|
70
|
+
with closing(socket.socket(address_family, socket.SOCK_STREAM)) as sock:
|
|
71
|
+
return sock.connect_ex((address, port)) == 0
|
|
72
|
+
except OSError:
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
55
76
|
def is_process_on_port(port: int) -> bool:
|
|
56
77
|
"""Check if a process is running on the given port.
|
|
57
78
|
|
|
@@ -61,8 +82,11 @@ def is_process_on_port(port: int) -> bool:
|
|
|
61
82
|
Returns:
|
|
62
83
|
Whether a process is running on the given port.
|
|
63
84
|
"""
|
|
64
|
-
|
|
65
|
-
|
|
85
|
+
return _is_address_responsive( # Test IPv4 localhost (127.0.0.1)
|
|
86
|
+
socket.AF_INET, "127.0.0.1", port
|
|
87
|
+
) or _is_address_responsive(
|
|
88
|
+
socket.AF_INET6, "::1", port
|
|
89
|
+
) # Test IPv6 localhost (::1)
|
|
66
90
|
|
|
67
91
|
|
|
68
92
|
def change_port(port: int, _type: str) -> int:
|
|
@@ -273,7 +297,7 @@ def stream_logs(
|
|
|
273
297
|
return
|
|
274
298
|
try:
|
|
275
299
|
for line in process.stdout:
|
|
276
|
-
console.debug(line, end="", progress=progress)
|
|
300
|
+
console.debug(rich.markup.escape(line), end="", progress=progress)
|
|
277
301
|
logs.append(line)
|
|
278
302
|
yield line
|
|
279
303
|
except ValueError:
|
reflex/utils/pyi_generator.py
CHANGED
|
@@ -1108,11 +1108,13 @@ class PyiGenerator:
|
|
|
1108
1108
|
sub_mod_attrs: dict[str, list[str | tuple[str, str]]] | None = getattr(
|
|
1109
1109
|
mod, "_SUBMOD_ATTRS", None
|
|
1110
1110
|
)
|
|
1111
|
+
extra_mappings: dict[str, str] | None = getattr(mod, "_EXTRA_MAPPINGS", None)
|
|
1111
1112
|
|
|
1112
|
-
if not sub_mods and not sub_mod_attrs:
|
|
1113
|
+
if not sub_mods and not sub_mod_attrs and not extra_mappings:
|
|
1113
1114
|
return None
|
|
1114
1115
|
sub_mods_imports = []
|
|
1115
1116
|
sub_mod_attrs_imports = []
|
|
1117
|
+
extra_mappings_imports = []
|
|
1116
1118
|
|
|
1117
1119
|
if sub_mods:
|
|
1118
1120
|
sub_mods_imports = [f"from . import {mod}" for mod in sorted(sub_mods)]
|
|
@@ -1140,7 +1142,20 @@ class PyiGenerator:
|
|
|
1140
1142
|
]
|
|
1141
1143
|
sub_mod_attrs_imports.append("")
|
|
1142
1144
|
|
|
1143
|
-
|
|
1145
|
+
if extra_mappings:
|
|
1146
|
+
for alias, import_path in extra_mappings.items():
|
|
1147
|
+
module_name, import_name = import_path.rsplit(".", 1)
|
|
1148
|
+
extra_mappings_imports.append(
|
|
1149
|
+
f"from {module_name} import {import_name} as {alias}"
|
|
1150
|
+
)
|
|
1151
|
+
|
|
1152
|
+
text = (
|
|
1153
|
+
"\n"
|
|
1154
|
+
+ "\n".join(
|
|
1155
|
+
[*sub_mods_imports, *sub_mod_attrs_imports, *extra_mappings_imports]
|
|
1156
|
+
)
|
|
1157
|
+
+ "\n"
|
|
1158
|
+
)
|
|
1144
1159
|
text += ast.unparse(new_tree) + "\n\n"
|
|
1145
1160
|
text += f"__all__ = {getattr(mod, '__all__', [])!r}\n"
|
|
1146
1161
|
return text
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reflex
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1
|
|
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
|
|
@@ -21,7 +21,7 @@ Requires-Python: <4.0,>=3.10
|
|
|
21
21
|
Requires-Dist: alembic<2.0,>=1.15.2
|
|
22
22
|
Requires-Dist: click>=8.2
|
|
23
23
|
Requires-Dist: fastapi>=0.115.0
|
|
24
|
-
Requires-Dist: granian[reload]>=2.
|
|
24
|
+
Requires-Dist: granian[reload]>=2.4.0
|
|
25
25
|
Requires-Dist: httpx<1.0,>=0.28.0
|
|
26
26
|
Requires-Dist: jinja2<4.0,>=3.1.2
|
|
27
27
|
Requires-Dist: packaging<26,>=24.2
|
|
@@ -31,7 +31,7 @@ Requires-Dist: pydantic<3.0,>=1.10.21
|
|
|
31
31
|
Requires-Dist: python-multipart<1.0,>=0.0.20
|
|
32
32
|
Requires-Dist: python-socketio<6.0,>=5.12.0
|
|
33
33
|
Requires-Dist: redis<7.0,>=5.2.1
|
|
34
|
-
Requires-Dist: reflex-hosting-cli>=0.1.
|
|
34
|
+
Requires-Dist: reflex-hosting-cli>=0.1.51
|
|
35
35
|
Requires-Dist: rich<15,>=13
|
|
36
36
|
Requires-Dist: sqlmodel<0.1,>=0.0.24
|
|
37
37
|
Requires-Dist: typing-extensions>=4.13.0
|