reflex 0.8.7a1__py3-none-any.whl → 0.8.8a2__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 +5 -5
- reflex/app.py +15 -7
- reflex/app_mixins/lifespan.py +8 -2
- reflex/compiler/compiler.py +14 -14
- reflex/compiler/templates.py +629 -102
- reflex/compiler/utils.py +30 -21
- reflex/components/base/bare.py +17 -0
- reflex/components/component.py +38 -34
- reflex/components/core/cond.py +6 -12
- reflex/components/core/foreach.py +1 -1
- reflex/components/core/match.py +83 -60
- reflex/components/dynamic.py +3 -3
- reflex/components/el/elements/forms.py +31 -14
- reflex/components/el/elements/forms.pyi +0 -5
- reflex/components/lucide/icon.py +2 -1
- reflex/components/lucide/icon.pyi +2 -1
- reflex/components/markdown/markdown.py +2 -2
- reflex/components/radix/primitives/accordion.py +1 -1
- reflex/components/radix/primitives/drawer.py +10 -22
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/tags/cond_tag.py +14 -5
- reflex/components/tags/iter_tag.py +0 -26
- reflex/components/tags/match_tag.py +15 -6
- reflex/components/tags/tag.py +3 -6
- reflex/components/tags/tagless.py +14 -0
- reflex/constants/base.py +0 -2
- reflex/constants/compiler.py +1 -1
- reflex/constants/installer.py +4 -4
- reflex/custom_components/custom_components.py +202 -15
- reflex/event.py +1 -1
- reflex/experimental/client_state.py +1 -1
- reflex/istate/manager.py +2 -1
- reflex/plugins/shared_tailwind.py +87 -62
- reflex/plugins/tailwind_v3.py +2 -2
- reflex/plugins/tailwind_v4.py +4 -4
- reflex/state.py +5 -1
- reflex/utils/format.py +3 -4
- reflex/utils/frontend_skeleton.py +2 -2
- reflex/utils/imports.py +18 -0
- reflex/utils/pyi_generator.py +10 -2
- reflex/utils/telemetry.py +4 -1
- reflex/utils/templates.py +1 -6
- {reflex-0.8.7a1.dist-info → reflex-0.8.8a2.dist-info}/METADATA +3 -4
- {reflex-0.8.7a1.dist-info → reflex-0.8.8a2.dist-info}/RECORD +48 -70
- reflex/.templates/jinja/app/rxconfig.py.jinja2 +0 -9
- reflex/.templates/jinja/custom_components/README.md.jinja2 +0 -9
- reflex/.templates/jinja/custom_components/__init__.py.jinja2 +0 -1
- reflex/.templates/jinja/custom_components/demo_app.py.jinja2 +0 -39
- reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +0 -25
- reflex/.templates/jinja/custom_components/src.py.jinja2 +0 -57
- reflex/.templates/jinja/web/package.json.jinja2 +0 -27
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +0 -62
- reflex/.templates/jinja/web/pages/_document.js.jinja2 +0 -9
- reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -21
- reflex/.templates/jinja/web/pages/component.js.jinja2 +0 -2
- reflex/.templates/jinja/web/pages/custom_component.js.jinja2 +0 -22
- reflex/.templates/jinja/web/pages/index.js.jinja2 +0 -18
- reflex/.templates/jinja/web/pages/macros.js.jinja2 +0 -38
- reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +0 -15
- reflex/.templates/jinja/web/pages/stateful_components.js.jinja2 +0 -5
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +0 -93
- reflex/.templates/jinja/web/styles/styles.css.jinja2 +0 -6
- reflex/.templates/jinja/web/utils/context.js.jinja2 +0 -129
- reflex/.templates/jinja/web/utils/theme.js.jinja2 +0 -1
- reflex/.templates/jinja/web/vite.config.js.jinja2 +0 -74
- reflex/components/core/client_side_routing.pyi +0 -68
- {reflex-0.8.7a1.dist-info → reflex-0.8.8a2.dist-info}/WHEEL +0 -0
- {reflex-0.8.7a1.dist-info → reflex-0.8.8a2.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.7a1.dist-info → reflex-0.8.8a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -415,7 +415,7 @@ export const applyRestEvent = async (event, socket, navigate, params) => {
|
|
|
415
415
|
if (event.payload.files === undefined || event.payload.files.length === 0) {
|
|
416
416
|
// Submit the event over the websocket to trigger the event handler.
|
|
417
417
|
return await applyEvent(
|
|
418
|
-
|
|
418
|
+
ReflexEvent(event.name, { files: [] }),
|
|
419
419
|
socket,
|
|
420
420
|
navigate,
|
|
421
421
|
params,
|
|
@@ -775,7 +775,7 @@ export const uploadFiles = async (
|
|
|
775
775
|
* @param {string} handler The client handler to process event.
|
|
776
776
|
* @returns The event object.
|
|
777
777
|
*/
|
|
778
|
-
export const
|
|
778
|
+
export const ReflexEvent = (
|
|
779
779
|
name,
|
|
780
780
|
payload = {},
|
|
781
781
|
event_actions = {},
|
|
@@ -987,7 +987,7 @@ export const useEventLoop = (
|
|
|
987
987
|
|
|
988
988
|
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
|
989
989
|
addEvents([
|
|
990
|
-
|
|
990
|
+
ReflexEvent(`${exception_state_name}.handle_frontend_exception`, {
|
|
991
991
|
info: error.name + ": " + error.message + "\n" + error.stack,
|
|
992
992
|
component_stack: "",
|
|
993
993
|
}),
|
|
@@ -999,7 +999,7 @@ export const useEventLoop = (
|
|
|
999
999
|
//https://github.com/mknichel/javascript-errors?tab=readme-ov-file#promise-rejection-events
|
|
1000
1000
|
window.onunhandledrejection = function (event) {
|
|
1001
1001
|
addEvents([
|
|
1002
|
-
|
|
1002
|
+
ReflexEvent(`${exception_state_name}.handle_frontend_exception`, {
|
|
1003
1003
|
info:
|
|
1004
1004
|
event.reason?.name +
|
|
1005
1005
|
": " +
|
|
@@ -1072,7 +1072,7 @@ export const useEventLoop = (
|
|
|
1072
1072
|
if (storage_to_state_map[e.key]) {
|
|
1073
1073
|
const vars = {};
|
|
1074
1074
|
vars[storage_to_state_map[e.key]] = e.newValue;
|
|
1075
|
-
const event =
|
|
1075
|
+
const event = ReflexEvent(
|
|
1076
1076
|
`${state_name}.reflex___state____update_vars_internal_state.update_vars_internal`,
|
|
1077
1077
|
{ vars: vars },
|
|
1078
1078
|
);
|
reflex/app.py
CHANGED
|
@@ -12,6 +12,7 @@ import inspect
|
|
|
12
12
|
import io
|
|
13
13
|
import json
|
|
14
14
|
import sys
|
|
15
|
+
import time
|
|
15
16
|
import traceback
|
|
16
17
|
import urllib.parse
|
|
17
18
|
from collections.abc import (
|
|
@@ -1310,9 +1311,9 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
1310
1311
|
self.head_components,
|
|
1311
1312
|
html_lang=self.html_lang,
|
|
1312
1313
|
html_custom_attrs=(
|
|
1313
|
-
{"suppressHydrationWarning":
|
|
1314
|
+
{"suppressHydrationWarning": True, **self.html_custom_attrs}
|
|
1314
1315
|
if self.html_custom_attrs
|
|
1315
|
-
else {"suppressHydrationWarning":
|
|
1316
|
+
else {"suppressHydrationWarning": True}
|
|
1316
1317
|
),
|
|
1317
1318
|
)
|
|
1318
1319
|
)
|
|
@@ -1582,7 +1583,10 @@ class App(MiddlewareMixin, LifespanMixin):
|
|
|
1582
1583
|
sid=state.router.session.session_id,
|
|
1583
1584
|
)
|
|
1584
1585
|
|
|
1585
|
-
task = asyncio.create_task(
|
|
1586
|
+
task = asyncio.create_task(
|
|
1587
|
+
_coro(),
|
|
1588
|
+
name=f"reflex_background_task|{event.name}|{time.time()}|{event.token}",
|
|
1589
|
+
)
|
|
1586
1590
|
self._background_tasks.add(task)
|
|
1587
1591
|
# Clean up task from background_tasks set when complete.
|
|
1588
1592
|
task.add_done_callback(self._background_tasks.discard)
|
|
@@ -1727,7 +1731,8 @@ async def process(
|
|
|
1727
1731
|
"reload",
|
|
1728
1732
|
data=event,
|
|
1729
1733
|
to=sid,
|
|
1730
|
-
)
|
|
1734
|
+
),
|
|
1735
|
+
name=f"reflex_emit_reload|{event.name}|{time.time()}|{event.token}",
|
|
1731
1736
|
)
|
|
1732
1737
|
return
|
|
1733
1738
|
# re-assign only when the value is different
|
|
@@ -2028,7 +2033,8 @@ class EventNamespace(AsyncNamespace):
|
|
|
2028
2033
|
if disconnect_token:
|
|
2029
2034
|
# Use async cleanup through token manager
|
|
2030
2035
|
task = asyncio.create_task(
|
|
2031
|
-
self._token_manager.disconnect_token(disconnect_token, sid)
|
|
2036
|
+
self._token_manager.disconnect_token(disconnect_token, sid),
|
|
2037
|
+
name=f"reflex_disconnect_token|{disconnect_token}|{time.time()}",
|
|
2032
2038
|
)
|
|
2033
2039
|
# Don't await to avoid blocking disconnect, but handle potential errors
|
|
2034
2040
|
task.add_done_callback(
|
|
@@ -2047,12 +2053,14 @@ class EventNamespace(AsyncNamespace):
|
|
|
2047
2053
|
# If the sid is None, we are not connected to a client. Prevent sending
|
|
2048
2054
|
# updates to all clients.
|
|
2049
2055
|
return
|
|
2050
|
-
|
|
2056
|
+
token = self.sid_to_token.get(sid)
|
|
2057
|
+
if token is None:
|
|
2051
2058
|
console.warn(f"Attempting to send delta to disconnected websocket {sid}")
|
|
2052
2059
|
return
|
|
2053
2060
|
# Creating a task prevents the update from being blocked behind other coroutines.
|
|
2054
2061
|
await asyncio.create_task(
|
|
2055
|
-
self.emit(str(constants.SocketEvent.EVENT), update, to=sid)
|
|
2062
|
+
self.emit(str(constants.SocketEvent.EVENT), update, to=sid),
|
|
2063
|
+
name=f"reflex_emit_event|{token}|{sid}|{time.time()}",
|
|
2056
2064
|
)
|
|
2057
2065
|
|
|
2058
2066
|
async def on_event(self, sid: str, data: Any):
|
reflex/app_mixins/lifespan.py
CHANGED
|
@@ -7,6 +7,7 @@ import contextlib
|
|
|
7
7
|
import dataclasses
|
|
8
8
|
import functools
|
|
9
9
|
import inspect
|
|
10
|
+
import time
|
|
10
11
|
from collections.abc import Callable, Coroutine
|
|
11
12
|
|
|
12
13
|
from starlette.applications import Starlette
|
|
@@ -36,6 +37,7 @@ class LifespanMixin(AppMixin):
|
|
|
36
37
|
if isinstance(task, asyncio.Task):
|
|
37
38
|
running_tasks.append(task)
|
|
38
39
|
else:
|
|
40
|
+
task_name = task.__name__
|
|
39
41
|
signature = inspect.signature(task)
|
|
40
42
|
if "app" in signature.parameters:
|
|
41
43
|
task = functools.partial(task, app=app)
|
|
@@ -44,7 +46,10 @@ class LifespanMixin(AppMixin):
|
|
|
44
46
|
await stack.enter_async_context(_t)
|
|
45
47
|
console.debug(run_msg.format(type="asynccontextmanager"))
|
|
46
48
|
elif isinstance(_t, Coroutine):
|
|
47
|
-
task_ = asyncio.create_task(
|
|
49
|
+
task_ = asyncio.create_task(
|
|
50
|
+
_t,
|
|
51
|
+
name=f"reflex_lifespan_task|{task_name}|{time.time()}",
|
|
52
|
+
)
|
|
48
53
|
task_.add_done_callback(lambda t: t.result())
|
|
49
54
|
running_tasks.append(task_)
|
|
50
55
|
console.debug(run_msg.format(type="coroutine"))
|
|
@@ -70,9 +75,10 @@ class LifespanMixin(AppMixin):
|
|
|
70
75
|
msg = f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
|
|
71
76
|
raise InvalidLifespanTaskTypeError(msg)
|
|
72
77
|
|
|
78
|
+
task_name = task.__name__ # pyright: ignore [reportAttributeAccessIssue]
|
|
73
79
|
if task_kwargs:
|
|
74
80
|
original_task = task
|
|
75
81
|
task = functools.partial(task, **task_kwargs) # pyright: ignore [reportArgumentType]
|
|
76
82
|
functools.update_wrapper(task, original_task) # pyright: ignore [reportArgumentType]
|
|
77
83
|
self.lifespan_tasks.add(task)
|
|
78
|
-
console.debug(f"Registered lifespan task: {
|
|
84
|
+
console.debug(f"Registered lifespan task: {task_name}")
|
reflex/compiler/compiler.py
CHANGED
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
from collections.abc import Callable, Iterable, Sequence
|
|
7
7
|
from inspect import getmodule
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
10
|
|
|
11
11
|
from reflex import constants
|
|
12
12
|
from reflex.compiler import templates, utils
|
|
@@ -53,7 +53,7 @@ def _compile_document_root(root: Component) -> str:
|
|
|
53
53
|
"""
|
|
54
54
|
document_root_imports = root._get_all_imports()
|
|
55
55
|
_apply_common_imports(document_root_imports)
|
|
56
|
-
return templates.
|
|
56
|
+
return templates.document_root_template(
|
|
57
57
|
imports=utils.compile_imports(document_root_imports),
|
|
58
58
|
document=root.render(),
|
|
59
59
|
)
|
|
@@ -93,7 +93,7 @@ def _compile_app(app_root: Component) -> str:
|
|
|
93
93
|
app_root_imports = app_root._get_all_imports()
|
|
94
94
|
_apply_common_imports(app_root_imports)
|
|
95
95
|
|
|
96
|
-
return templates.
|
|
96
|
+
return templates.app_root_template(
|
|
97
97
|
imports=utils.compile_imports(app_root_imports),
|
|
98
98
|
custom_codes=app_root._get_all_custom_code(),
|
|
99
99
|
hooks=app_root._get_all_hooks(),
|
|
@@ -112,7 +112,7 @@ def _compile_theme(theme: str) -> str:
|
|
|
112
112
|
Returns:
|
|
113
113
|
The compiled theme.
|
|
114
114
|
"""
|
|
115
|
-
return templates.
|
|
115
|
+
return templates.theme_template(theme=theme)
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
def _compile_contexts(state: type[BaseState] | None, theme: Component | None) -> str:
|
|
@@ -130,17 +130,17 @@ def _compile_contexts(state: type[BaseState] | None, theme: Component | None) ->
|
|
|
130
130
|
appearance = LiteralVar.create(SYSTEM_COLOR_MODE)
|
|
131
131
|
|
|
132
132
|
return (
|
|
133
|
-
templates.
|
|
133
|
+
templates.context_template(
|
|
134
134
|
initial_state=utils.compile_state(state),
|
|
135
135
|
state_name=state.get_name(),
|
|
136
136
|
client_storage=utils.compile_client_storage(state),
|
|
137
137
|
is_dev_mode=not is_prod_mode(),
|
|
138
|
-
default_color_mode=appearance,
|
|
138
|
+
default_color_mode=str(appearance),
|
|
139
139
|
)
|
|
140
140
|
if state
|
|
141
|
-
else templates.
|
|
141
|
+
else templates.context_template(
|
|
142
142
|
is_dev_mode=not is_prod_mode(),
|
|
143
|
-
default_color_mode=appearance,
|
|
143
|
+
default_color_mode=str(appearance),
|
|
144
144
|
)
|
|
145
145
|
)
|
|
146
146
|
|
|
@@ -159,7 +159,7 @@ def _compile_page(component: BaseComponent) -> str:
|
|
|
159
159
|
imports = utils.compile_imports(imports)
|
|
160
160
|
|
|
161
161
|
# Compile the code to render the component.
|
|
162
|
-
return templates.
|
|
162
|
+
return templates.page_template(
|
|
163
163
|
imports=imports,
|
|
164
164
|
dynamic_imports=component._get_all_dynamic_imports(),
|
|
165
165
|
custom_codes=component._get_all_custom_code(),
|
|
@@ -321,7 +321,7 @@ def _compile_root_stylesheet(stylesheets: list[str], reset_style: bool = True) -
|
|
|
321
321
|
'The `libsass` package is required to compile sass/scss stylesheet files. Run `pip install "libsass>=0.23.0"`.'
|
|
322
322
|
)
|
|
323
323
|
|
|
324
|
-
return templates.
|
|
324
|
+
return templates.styles_template(stylesheets=sheets)
|
|
325
325
|
|
|
326
326
|
|
|
327
327
|
def _compile_component(component: Component | StatefulComponent) -> str:
|
|
@@ -333,7 +333,7 @@ def _compile_component(component: Component | StatefulComponent) -> str:
|
|
|
333
333
|
Returns:
|
|
334
334
|
The compiled component.
|
|
335
335
|
"""
|
|
336
|
-
return templates.
|
|
336
|
+
return templates.component_template(component=component)
|
|
337
337
|
|
|
338
338
|
|
|
339
339
|
def _compile_components(
|
|
@@ -376,7 +376,7 @@ def _compile_components(
|
|
|
376
376
|
|
|
377
377
|
# Compile the components page.
|
|
378
378
|
return (
|
|
379
|
-
templates.
|
|
379
|
+
templates.custom_component_template(
|
|
380
380
|
imports=utils.compile_imports(imports),
|
|
381
381
|
components=component_renders,
|
|
382
382
|
dynamic_imports=dynamic_imports,
|
|
@@ -456,7 +456,7 @@ def _compile_stateful_components(
|
|
|
456
456
|
if rendered_components:
|
|
457
457
|
_apply_common_imports(all_imports)
|
|
458
458
|
|
|
459
|
-
return templates.
|
|
459
|
+
return templates.stateful_components_template(
|
|
460
460
|
imports=utils.compile_imports(all_imports),
|
|
461
461
|
memoized_code="\n".join(rendered_components),
|
|
462
462
|
)
|
|
@@ -465,7 +465,7 @@ def _compile_stateful_components(
|
|
|
465
465
|
def compile_document_root(
|
|
466
466
|
head_components: list[Component],
|
|
467
467
|
html_lang: str | None = None,
|
|
468
|
-
html_custom_attrs: dict[str, Var |
|
|
468
|
+
html_custom_attrs: dict[str, Var | Any] | None = None,
|
|
469
469
|
) -> tuple[str, str]:
|
|
470
470
|
"""Compile the document root.
|
|
471
471
|
|