reflex 0.7.0a5__py3-none-any.whl → 0.7.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/jinja/web/package.json.jinja2 +7 -1
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +3 -1
- reflex/__init__.py +1 -0
- reflex/__init__.pyi +1 -0
- reflex/app.py +268 -85
- reflex/base.py +4 -10
- reflex/compiler/compiler.py +46 -12
- reflex/compiler/templates.py +1 -2
- reflex/compiler/utils.py +23 -14
- reflex/components/base/bare.py +109 -16
- reflex/components/component.py +179 -124
- reflex/components/core/__init__.py +1 -0
- reflex/components/core/__init__.pyi +1 -0
- reflex/components/core/auto_scroll.py +114 -0
- reflex/components/core/auto_scroll.pyi +284 -0
- reflex/components/core/banner.py +40 -9
- reflex/components/core/banner.pyi +400 -87
- reflex/components/core/breakpoints.py +1 -1
- reflex/components/core/cond.py +0 -8
- reflex/components/core/foreach.py +12 -2
- reflex/components/core/html.pyi +200 -19
- reflex/components/core/match.py +4 -4
- reflex/components/core/sticky.pyi +874 -90
- reflex/components/core/upload.py +3 -5
- reflex/components/core/upload.pyi +2 -4
- reflex/components/datadisplay/code.py +36 -10
- reflex/components/datadisplay/code.pyi +1 -1
- reflex/components/datadisplay/dataeditor.py +1 -3
- reflex/components/datadisplay/dataeditor.pyi +1 -3
- reflex/components/el/elements/base.py +95 -17
- reflex/components/el/elements/base.pyi +278 -19
- reflex/components/el/elements/forms.py +124 -102
- reflex/components/el/elements/forms.pyi +2787 -365
- reflex/components/el/elements/inline.py +24 -15
- reflex/components/el/elements/inline.pyi +5655 -546
- reflex/components/el/elements/media.py +79 -95
- reflex/components/el/elements/media.pyi +5167 -565
- reflex/components/el/elements/metadata.py +19 -17
- reflex/components/el/elements/metadata.pyi +841 -89
- reflex/components/el/elements/other.py +3 -5
- reflex/components/el/elements/other.pyi +1404 -137
- reflex/components/el/elements/scripts.py +10 -13
- reflex/components/el/elements/scripts.pyi +634 -65
- reflex/components/el/elements/sectioning.pyi +3001 -286
- reflex/components/el/elements/tables.py +14 -35
- reflex/components/el/elements/tables.pyi +2029 -218
- reflex/components/el/elements/typography.py +10 -13
- reflex/components/el/elements/typography.pyi +3014 -297
- reflex/components/lucide/icon.py +22 -6
- reflex/components/markdown/markdown.py +30 -10
- reflex/components/markdown/markdown.pyi +3 -2
- reflex/components/plotly/plotly.py +1 -3
- reflex/components/plotly/plotly.pyi +1 -3
- reflex/components/radix/primitives/form.pyi +624 -93
- reflex/components/radix/themes/color_mode.py +1 -1
- reflex/components/radix/themes/color_mode.pyi +213 -31
- reflex/components/radix/themes/components/alert_dialog.pyi +199 -18
- reflex/components/radix/themes/components/badge.pyi +199 -18
- reflex/components/radix/themes/components/button.pyi +213 -31
- reflex/components/radix/themes/components/callout.pyi +1000 -95
- reflex/components/radix/themes/components/card.pyi +199 -18
- reflex/components/radix/themes/components/context_menu.py +79 -1
- reflex/components/radix/themes/components/context_menu.pyi +320 -1
- reflex/components/radix/themes/components/dialog.pyi +199 -18
- reflex/components/radix/themes/components/hover_card.pyi +199 -18
- reflex/components/radix/themes/components/icon_button.pyi +213 -31
- reflex/components/radix/themes/components/inset.pyi +199 -18
- reflex/components/radix/themes/components/popover.pyi +199 -18
- reflex/components/radix/themes/components/table.pyi +1437 -154
- reflex/components/radix/themes/components/text_area.py +2 -2
- reflex/components/radix/themes/components/text_area.pyi +201 -20
- reflex/components/radix/themes/components/text_field.py +1 -1
- reflex/components/radix/themes/components/text_field.pyi +444 -88
- reflex/components/radix/themes/layout/box.pyi +200 -19
- reflex/components/radix/themes/layout/center.pyi +199 -18
- reflex/components/radix/themes/layout/container.pyi +199 -18
- reflex/components/radix/themes/layout/flex.pyi +199 -18
- reflex/components/radix/themes/layout/grid.pyi +199 -18
- reflex/components/radix/themes/layout/list.pyi +604 -57
- reflex/components/radix/themes/layout/section.pyi +199 -18
- reflex/components/radix/themes/layout/spacer.pyi +199 -18
- reflex/components/radix/themes/layout/stack.pyi +597 -54
- reflex/components/radix/themes/typography/blockquote.pyi +200 -19
- reflex/components/radix/themes/typography/code.pyi +199 -18
- reflex/components/radix/themes/typography/heading.pyi +199 -18
- reflex/components/radix/themes/typography/link.pyi +238 -28
- reflex/components/radix/themes/typography/text.pyi +1394 -127
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/react_player/react_player.pyi +1 -3
- reflex/components/sonner/toast.py +41 -12
- reflex/components/sonner/toast.pyi +20 -6
- reflex/components/tags/iter_tag.py +4 -0
- reflex/components/tags/tag.py +3 -3
- reflex/config.py +187 -28
- reflex/constants/__init__.py +2 -0
- reflex/constants/base.py +6 -0
- reflex/constants/compiler.py +9 -0
- reflex/constants/event.py +1 -0
- reflex/constants/installer.py +8 -5
- reflex/constants/utils.py +1 -3
- reflex/event.py +7 -16
- reflex/experimental/layout.pyi +597 -54
- reflex/py.typed +0 -0
- reflex/reflex.py +30 -41
- reflex/state.py +49 -44
- reflex/style.py +15 -22
- reflex/testing.py +2 -0
- reflex/utils/build.py +12 -0
- reflex/utils/console.py +4 -0
- reflex/utils/decorator.py +25 -0
- reflex/utils/exec.py +92 -34
- reflex/utils/format.py +35 -6
- reflex/utils/path_ops.py +16 -1
- reflex/utils/prerequisites.py +25 -33
- reflex/utils/processes.py +12 -13
- reflex/utils/serializers.py +20 -43
- reflex/utils/telemetry.py +4 -15
- reflex/utils/types.py +36 -66
- reflex/vars/base.py +53 -76
- reflex/vars/function.py +17 -5
- reflex/vars/number.py +1 -1
- reflex/vars/sequence.py +80 -4
- {reflex-0.7.0a5.dist-info → reflex-0.7.1.dist-info}/METADATA +4 -5
- {reflex-0.7.0a5.dist-info → reflex-0.7.1.dist-info}/RECORD +127 -123
- {reflex-0.7.0a5.dist-info → reflex-0.7.1.dist-info}/LICENSE +0 -0
- {reflex-0.7.0a5.dist-info → reflex-0.7.1.dist-info}/WHEEL +0 -0
- {reflex-0.7.0a5.dist-info → reflex-0.7.1.dist-info}/entry_points.txt +0 -0
reflex/py.typed
ADDED
|
File without changes
|
reflex/reflex.py
CHANGED
|
@@ -20,13 +20,8 @@ from reflex.utils import console, telemetry
|
|
|
20
20
|
typer.core.rich = None # pyright: ignore [reportPrivateImportUsage]
|
|
21
21
|
|
|
22
22
|
# Create the app.
|
|
23
|
-
|
|
24
|
-
cli = typer.Typer(add_completion=False, pretty_exceptions_enable=False)
|
|
25
|
-
except TypeError:
|
|
26
|
-
# Fallback for older typer versions.
|
|
27
|
-
cli = typer.Typer(add_completion=False)
|
|
23
|
+
cli = typer.Typer(add_completion=False, pretty_exceptions_enable=False)
|
|
28
24
|
|
|
29
|
-
SHOW_BUILT_WITH_REFLEX_INFO = "https://reflex.dev/docs/hosting/reflex-branding/"
|
|
30
25
|
|
|
31
26
|
# Get the config.
|
|
32
27
|
config = get_config()
|
|
@@ -127,8 +122,8 @@ def _run(
|
|
|
127
122
|
env: constants.Env = constants.Env.DEV,
|
|
128
123
|
frontend: bool = True,
|
|
129
124
|
backend: bool = True,
|
|
130
|
-
frontend_port: int =
|
|
131
|
-
backend_port: int =
|
|
125
|
+
frontend_port: int | None = None,
|
|
126
|
+
backend_port: int | None = None,
|
|
132
127
|
backend_host: str = config.backend_host,
|
|
133
128
|
loglevel: constants.LogLevel = config.loglevel,
|
|
134
129
|
):
|
|
@@ -158,17 +153,28 @@ def _run(
|
|
|
158
153
|
|
|
159
154
|
# Find the next available open port if applicable.
|
|
160
155
|
if frontend:
|
|
156
|
+
auto_increment_frontend = not bool(frontend_port or config.frontend_port)
|
|
161
157
|
frontend_port = processes.handle_port(
|
|
162
158
|
"frontend",
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
(
|
|
160
|
+
frontend_port
|
|
161
|
+
or config.frontend_port
|
|
162
|
+
or constants.DefaultPorts.FRONTEND_PORT
|
|
163
|
+
),
|
|
164
|
+
auto_increment=auto_increment_frontend,
|
|
165
165
|
)
|
|
166
166
|
|
|
167
167
|
if backend:
|
|
168
|
+
auto_increment_backend = not bool(backend_port or config.backend_port)
|
|
169
|
+
|
|
168
170
|
backend_port = processes.handle_port(
|
|
169
171
|
"backend",
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
(
|
|
173
|
+
backend_port
|
|
174
|
+
or config.backend_port
|
|
175
|
+
or constants.DefaultPorts.BACKEND_PORT
|
|
176
|
+
),
|
|
177
|
+
auto_increment=auto_increment_backend,
|
|
172
178
|
)
|
|
173
179
|
|
|
174
180
|
# Apply the new ports to the config.
|
|
@@ -185,15 +191,6 @@ def _run(
|
|
|
185
191
|
prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
|
|
186
192
|
|
|
187
193
|
if frontend:
|
|
188
|
-
if not config.show_built_with_reflex:
|
|
189
|
-
# The sticky badge may be disabled at runtime for team/enterprise tiers.
|
|
190
|
-
prerequisites.check_config_option_in_tier(
|
|
191
|
-
option_name="show_built_with_reflex",
|
|
192
|
-
allowed_tiers=["team", "enterprise"],
|
|
193
|
-
fallback_value=True,
|
|
194
|
-
help_link=SHOW_BUILT_WITH_REFLEX_INFO,
|
|
195
|
-
)
|
|
196
|
-
|
|
197
194
|
# Get the app module.
|
|
198
195
|
prerequisites.get_compiled_app()
|
|
199
196
|
|
|
@@ -246,7 +243,7 @@ def _run(
|
|
|
246
243
|
# Start the frontend and backend.
|
|
247
244
|
with processes.run_concurrently_context(*commands):
|
|
248
245
|
# In dev mode, run the backend on the main thread.
|
|
249
|
-
if backend and env == constants.Env.DEV:
|
|
246
|
+
if backend and backend_port and env == constants.Env.DEV:
|
|
250
247
|
backend_cmd(
|
|
251
248
|
backend_host, int(backend_port), loglevel.subprocess_level(), frontend
|
|
252
249
|
)
|
|
@@ -275,10 +272,14 @@ def run(
|
|
|
275
272
|
envvar=environment.REFLEX_BACKEND_ONLY.name,
|
|
276
273
|
),
|
|
277
274
|
frontend_port: int = typer.Option(
|
|
278
|
-
config.frontend_port,
|
|
275
|
+
config.frontend_port,
|
|
276
|
+
help="Specify a different frontend port.",
|
|
277
|
+
envvar=environment.REFLEX_FRONTEND_PORT.name,
|
|
279
278
|
),
|
|
280
279
|
backend_port: int = typer.Option(
|
|
281
|
-
config.backend_port,
|
|
280
|
+
config.backend_port,
|
|
281
|
+
help="Specify a different backend port.",
|
|
282
|
+
envvar=environment.REFLEX_BACKEND_PORT.name,
|
|
282
283
|
),
|
|
283
284
|
backend_host: str = typer.Option(
|
|
284
285
|
config.backend_host, help="Specify the backend host."
|
|
@@ -291,6 +292,8 @@ def run(
|
|
|
291
292
|
if frontend and backend:
|
|
292
293
|
console.error("Cannot use both --frontend-only and --backend-only options.")
|
|
293
294
|
raise typer.Exit(1)
|
|
295
|
+
|
|
296
|
+
environment.REFLEX_COMPILE_CONTEXT.set(constants.CompileContext.RUN)
|
|
294
297
|
environment.REFLEX_BACKEND_ONLY.set(backend)
|
|
295
298
|
environment.REFLEX_FRONTEND_ONLY.set(frontend)
|
|
296
299
|
|
|
@@ -337,20 +340,13 @@ def export(
|
|
|
337
340
|
from reflex.utils import export as export_utils
|
|
338
341
|
from reflex.utils import prerequisites
|
|
339
342
|
|
|
343
|
+
environment.REFLEX_COMPILE_CONTEXT.set(constants.CompileContext.EXPORT)
|
|
344
|
+
|
|
340
345
|
frontend, backend = prerequisites.check_running_mode(frontend, backend)
|
|
341
346
|
|
|
342
347
|
if prerequisites.needs_reinit(frontend=frontend or not backend):
|
|
343
348
|
_init(name=config.app_name, loglevel=loglevel)
|
|
344
349
|
|
|
345
|
-
if frontend and not config.show_built_with_reflex:
|
|
346
|
-
# The sticky badge may be disabled on export for team/enterprise tiers.
|
|
347
|
-
prerequisites.check_config_option_in_tier(
|
|
348
|
-
option_name="show_built_with_reflex",
|
|
349
|
-
allowed_tiers=["team", "enterprise"],
|
|
350
|
-
fallback_value=False,
|
|
351
|
-
help_link=SHOW_BUILT_WITH_REFLEX_INFO,
|
|
352
|
-
)
|
|
353
|
-
|
|
354
350
|
export_utils.export(
|
|
355
351
|
zipping=zipping,
|
|
356
352
|
frontend=frontend,
|
|
@@ -545,14 +541,7 @@ def deploy(
|
|
|
545
541
|
|
|
546
542
|
check_version()
|
|
547
543
|
|
|
548
|
-
|
|
549
|
-
# The sticky badge may be disabled on deploy for pro/team/enterprise tiers.
|
|
550
|
-
prerequisites.check_config_option_in_tier(
|
|
551
|
-
option_name="show_built_with_reflex",
|
|
552
|
-
allowed_tiers=["pro", "team", "enterprise"],
|
|
553
|
-
fallback_value=True,
|
|
554
|
-
help_link=SHOW_BUILT_WITH_REFLEX_INFO,
|
|
555
|
-
)
|
|
544
|
+
environment.REFLEX_COMPILE_CONTEXT.set(constants.CompileContext.DEPLOY)
|
|
556
545
|
|
|
557
546
|
# Set the log level.
|
|
558
547
|
console.set_log_level(loglevel)
|
reflex/state.py
CHANGED
|
@@ -40,50 +40,22 @@ from typing import (
|
|
|
40
40
|
get_type_hints,
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
from sqlalchemy.orm import DeclarativeBase
|
|
45
|
-
from typing_extensions import Self
|
|
46
|
-
|
|
47
|
-
from reflex import event
|
|
48
|
-
from reflex.config import PerformanceMode, get_config
|
|
49
|
-
from reflex.istate.data import RouterData
|
|
50
|
-
from reflex.istate.storage import ClientStorageBase
|
|
51
|
-
from reflex.model import Model
|
|
52
|
-
from reflex.vars.base import (
|
|
53
|
-
ComputedVar,
|
|
54
|
-
DynamicRouteVar,
|
|
55
|
-
Var,
|
|
56
|
-
computed_var,
|
|
57
|
-
dispatch,
|
|
58
|
-
get_unique_variable_name,
|
|
59
|
-
is_computed_var,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
try:
|
|
63
|
-
import pydantic.v1 as pydantic
|
|
64
|
-
except ModuleNotFoundError:
|
|
65
|
-
import pydantic
|
|
66
|
-
|
|
67
|
-
from pydantic import BaseModel as BaseModelV2
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
from pydantic.v1 import BaseModel as BaseModelV1
|
|
71
|
-
except ModuleNotFoundError:
|
|
72
|
-
BaseModelV1 = BaseModelV2
|
|
73
|
-
|
|
74
|
-
try:
|
|
75
|
-
from pydantic.v1 import validator
|
|
76
|
-
except ModuleNotFoundError:
|
|
77
|
-
from pydantic import validator
|
|
78
|
-
|
|
43
|
+
import pydantic.v1 as pydantic
|
|
79
44
|
import wrapt
|
|
45
|
+
from pydantic import BaseModel as BaseModelV2
|
|
46
|
+
from pydantic.v1 import BaseModel as BaseModelV1
|
|
47
|
+
from pydantic.v1 import validator
|
|
48
|
+
from pydantic.v1.fields import ModelField
|
|
80
49
|
from redis.asyncio import Redis
|
|
50
|
+
from redis.asyncio.client import PubSub
|
|
81
51
|
from redis.exceptions import ResponseError
|
|
52
|
+
from sqlalchemy.orm import DeclarativeBase
|
|
53
|
+
from typing_extensions import Self
|
|
82
54
|
|
|
83
55
|
import reflex.istate.dynamic
|
|
84
|
-
from reflex import constants
|
|
56
|
+
from reflex import constants, event
|
|
85
57
|
from reflex.base import Base
|
|
86
|
-
from reflex.config import environment
|
|
58
|
+
from reflex.config import PerformanceMode, environment, get_config
|
|
87
59
|
from reflex.event import (
|
|
88
60
|
BACKGROUND_TASK_MARKER,
|
|
89
61
|
Event,
|
|
@@ -91,6 +63,9 @@ from reflex.event import (
|
|
|
91
63
|
EventSpec,
|
|
92
64
|
fix_events,
|
|
93
65
|
)
|
|
66
|
+
from reflex.istate.data import RouterData
|
|
67
|
+
from reflex.istate.storage import ClientStorageBase
|
|
68
|
+
from reflex.model import Model
|
|
94
69
|
from reflex.utils import console, format, path_ops, prerequisites, types
|
|
95
70
|
from reflex.utils.exceptions import (
|
|
96
71
|
ComputedVarShadowsBaseVarsError,
|
|
@@ -121,6 +96,15 @@ from reflex.utils.types import (
|
|
|
121
96
|
value_inside_optional,
|
|
122
97
|
)
|
|
123
98
|
from reflex.vars import VarData
|
|
99
|
+
from reflex.vars.base import (
|
|
100
|
+
ComputedVar,
|
|
101
|
+
DynamicRouteVar,
|
|
102
|
+
Var,
|
|
103
|
+
computed_var,
|
|
104
|
+
dispatch,
|
|
105
|
+
get_unique_variable_name,
|
|
106
|
+
is_computed_var,
|
|
107
|
+
)
|
|
124
108
|
|
|
125
109
|
if TYPE_CHECKING:
|
|
126
110
|
from reflex.components.component import Component
|
|
@@ -289,10 +273,6 @@ class EventHandlerSetVar(EventHandler):
|
|
|
289
273
|
return super().__call__(*args)
|
|
290
274
|
|
|
291
275
|
|
|
292
|
-
if TYPE_CHECKING:
|
|
293
|
-
from pydantic.v1.fields import ModelField
|
|
294
|
-
|
|
295
|
-
|
|
296
276
|
def _unwrap_field_type(type_: Type) -> Type:
|
|
297
277
|
"""Unwrap rx.Field type annotations.
|
|
298
278
|
|
|
@@ -347,6 +327,9 @@ async def _resolve_delta(delta: Delta) -> Delta:
|
|
|
347
327
|
return delta
|
|
348
328
|
|
|
349
329
|
|
|
330
|
+
all_base_state_classes: dict[str, None] = {}
|
|
331
|
+
|
|
332
|
+
|
|
350
333
|
class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
351
334
|
"""The state of the app."""
|
|
352
335
|
|
|
@@ -644,6 +627,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
644
627
|
cls._var_dependencies = {}
|
|
645
628
|
cls._init_var_dependency_dicts()
|
|
646
629
|
|
|
630
|
+
all_base_state_classes[cls.get_full_name()] = None
|
|
631
|
+
|
|
647
632
|
@staticmethod
|
|
648
633
|
def _copy_fn(fn: Callable) -> Callable:
|
|
649
634
|
"""Copy a function. Used to copy ComputedVars and EventHandlers from mixins.
|
|
@@ -1742,6 +1727,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1742
1727
|
|
|
1743
1728
|
Yields:
|
|
1744
1729
|
StateUpdate object
|
|
1730
|
+
|
|
1731
|
+
Raises:
|
|
1732
|
+
ValueError: If a string value is received for an int or float type and cannot be converted.
|
|
1745
1733
|
"""
|
|
1746
1734
|
from reflex.utils import telemetry
|
|
1747
1735
|
|
|
@@ -1779,12 +1767,25 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1779
1767
|
hinted_args, (Base, BaseModelV1, BaseModelV2)
|
|
1780
1768
|
):
|
|
1781
1769
|
payload[arg] = hinted_args(**value)
|
|
1782
|
-
|
|
1770
|
+
elif isinstance(value, list) and (hinted_args is set or hinted_args is Set):
|
|
1783
1771
|
payload[arg] = set(value)
|
|
1784
|
-
|
|
1772
|
+
elif isinstance(value, list) and (
|
|
1785
1773
|
hinted_args is tuple or hinted_args is Tuple
|
|
1786
1774
|
):
|
|
1787
1775
|
payload[arg] = tuple(value)
|
|
1776
|
+
elif isinstance(value, str) and (
|
|
1777
|
+
hinted_args is int or hinted_args is float
|
|
1778
|
+
):
|
|
1779
|
+
try:
|
|
1780
|
+
payload[arg] = hinted_args(value)
|
|
1781
|
+
except ValueError:
|
|
1782
|
+
raise ValueError(
|
|
1783
|
+
f"Received a string value ({value}) for {arg} but expected a {hinted_args}"
|
|
1784
|
+
) from None
|
|
1785
|
+
else:
|
|
1786
|
+
console.warn(
|
|
1787
|
+
f"Received a string value ({value}) for {arg} but expected a {hinted_args}. A simple conversion was successful."
|
|
1788
|
+
)
|
|
1788
1789
|
|
|
1789
1790
|
# Wrap the function in a try/except block.
|
|
1790
1791
|
try:
|
|
@@ -2459,6 +2460,8 @@ class ComponentState(State, mixin=True):
|
|
|
2459
2460
|
Returns:
|
|
2460
2461
|
A new instance of the Component with an independent copy of the State.
|
|
2461
2462
|
"""
|
|
2463
|
+
from reflex.compiler.compiler import into_component
|
|
2464
|
+
|
|
2462
2465
|
cls._per_component_state_instance_count += 1
|
|
2463
2466
|
state_cls_name = f"{cls.__name__}_n{cls._per_component_state_instance_count}"
|
|
2464
2467
|
component_state = type(
|
|
@@ -2470,6 +2473,7 @@ class ComponentState(State, mixin=True):
|
|
|
2470
2473
|
# Save a reference to the dynamic state for pickle/unpickle.
|
|
2471
2474
|
setattr(reflex.istate.dynamic, state_cls_name, component_state)
|
|
2472
2475
|
component = component_state.get_component(*children, **props)
|
|
2476
|
+
component = into_component(component)
|
|
2473
2477
|
component.State = component_state
|
|
2474
2478
|
return component
|
|
2475
2479
|
|
|
@@ -4088,6 +4092,7 @@ def reload_state_module(
|
|
|
4088
4092
|
for subclass in tuple(state.class_subclasses):
|
|
4089
4093
|
reload_state_module(module=module, state=subclass)
|
|
4090
4094
|
if subclass.__module__ == module and module is not None:
|
|
4095
|
+
all_base_state_classes.pop(subclass.get_full_name(), None)
|
|
4091
4096
|
state.class_subclasses.remove(subclass)
|
|
4092
4097
|
state._always_dirty_substates.discard(subclass.get_name())
|
|
4093
4098
|
state._var_dependencies = {}
|
reflex/style.py
CHANGED
|
@@ -6,13 +6,13 @@ from typing import Any, Literal, Tuple, Type
|
|
|
6
6
|
|
|
7
7
|
from reflex import constants
|
|
8
8
|
from reflex.components.core.breakpoints import Breakpoints, breakpoints_values
|
|
9
|
-
from reflex.event import EventChain, EventHandler
|
|
9
|
+
from reflex.event import EventChain, EventHandler, EventSpec, run_script
|
|
10
10
|
from reflex.utils import format
|
|
11
11
|
from reflex.utils.exceptions import ReflexError
|
|
12
12
|
from reflex.utils.imports import ImportVar
|
|
13
13
|
from reflex.utils.types import get_origin
|
|
14
14
|
from reflex.vars import VarData
|
|
15
|
-
from reflex.vars.base import
|
|
15
|
+
from reflex.vars.base import LiteralVar, Var
|
|
16
16
|
from reflex.vars.function import FunctionVar
|
|
17
17
|
from reflex.vars.object import ObjectVar
|
|
18
18
|
|
|
@@ -48,11 +48,10 @@ def _color_mode_var(_js_expr: str, _var_type: Type = str) -> Var:
|
|
|
48
48
|
).guess_type()
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
@CallableVar
|
|
52
51
|
def set_color_mode(
|
|
53
|
-
new_color_mode: LiteralColorMode | Var[LiteralColorMode]
|
|
54
|
-
) ->
|
|
55
|
-
"""Create an
|
|
52
|
+
new_color_mode: LiteralColorMode | Var[LiteralColorMode],
|
|
53
|
+
) -> EventSpec:
|
|
54
|
+
"""Create an EventSpec Var that sets the color mode to a specific value.
|
|
56
55
|
|
|
57
56
|
Note: `set_color_mode` is not a real event and cannot be triggered from a
|
|
58
57
|
backend event handler.
|
|
@@ -61,24 +60,15 @@ def set_color_mode(
|
|
|
61
60
|
new_color_mode: The color mode to set.
|
|
62
61
|
|
|
63
62
|
Returns:
|
|
64
|
-
The
|
|
63
|
+
The EventSpec Var that can be passed to an event trigger.
|
|
65
64
|
"""
|
|
66
65
|
base_setter = _color_mode_var(
|
|
67
66
|
_js_expr=constants.ColorMode.SET,
|
|
68
|
-
|
|
69
|
-
)
|
|
70
|
-
if new_color_mode is None:
|
|
71
|
-
return base_setter
|
|
72
|
-
|
|
73
|
-
if not isinstance(new_color_mode, Var):
|
|
74
|
-
new_color_mode = LiteralVar.create(new_color_mode)
|
|
67
|
+
).to(FunctionVar)
|
|
75
68
|
|
|
76
|
-
return
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
base_setter._get_all_var_data(), new_color_mode._get_all_var_data()
|
|
80
|
-
),
|
|
81
|
-
).to(FunctionVar, EventChain)
|
|
69
|
+
return run_script(
|
|
70
|
+
base_setter.call(new_color_mode),
|
|
71
|
+
)
|
|
82
72
|
|
|
83
73
|
|
|
84
74
|
# Var resolves to the current color mode for the app ("light", "dark" or "system")
|
|
@@ -191,11 +181,12 @@ def convert(
|
|
|
191
181
|
for key, value in style_dict.items():
|
|
192
182
|
keys = (
|
|
193
183
|
format_style_key(key)
|
|
194
|
-
if not isinstance(value, (dict, ObjectVar))
|
|
184
|
+
if not isinstance(value, (dict, ObjectVar, list))
|
|
195
185
|
or (
|
|
196
186
|
isinstance(value, Breakpoints)
|
|
197
187
|
and all(not isinstance(v, dict) for v in value.values())
|
|
198
188
|
)
|
|
189
|
+
or (isinstance(value, list) and all(not isinstance(v, dict) for v in value))
|
|
199
190
|
or (
|
|
200
191
|
isinstance(value, ObjectVar)
|
|
201
192
|
and not issubclass(get_origin(value._var_type) or value._var_type, dict)
|
|
@@ -237,7 +228,9 @@ def format_style_key(key: str) -> Tuple[str, ...]:
|
|
|
237
228
|
Returns:
|
|
238
229
|
Tuple of css style names corresponding to the key provided.
|
|
239
230
|
"""
|
|
240
|
-
key
|
|
231
|
+
if key.startswith("--"):
|
|
232
|
+
return (key,)
|
|
233
|
+
key = format.to_camel_case(key)
|
|
241
234
|
return STYLE_PROP_SHORTHAND_MAPPING.get(key, (key,))
|
|
242
235
|
|
|
243
236
|
|
reflex/testing.py
CHANGED
|
@@ -43,6 +43,7 @@ import reflex.utils.exec
|
|
|
43
43
|
import reflex.utils.format
|
|
44
44
|
import reflex.utils.prerequisites
|
|
45
45
|
import reflex.utils.processes
|
|
46
|
+
from reflex.components.component import CustomComponent
|
|
46
47
|
from reflex.config import environment
|
|
47
48
|
from reflex.state import (
|
|
48
49
|
BaseState,
|
|
@@ -254,6 +255,7 @@ class AppHarness:
|
|
|
254
255
|
# disable telemetry reporting for tests
|
|
255
256
|
|
|
256
257
|
os.environ["TELEMETRY_ENABLED"] = "false"
|
|
258
|
+
CustomComponent.create().get_component.cache_clear()
|
|
257
259
|
self.app_path.mkdir(parents=True, exist_ok=True)
|
|
258
260
|
if self.app_source is not None:
|
|
259
261
|
app_globals = self._get_globals_from_signature(self.app_source)
|
reflex/utils/build.py
CHANGED
|
@@ -60,6 +60,7 @@ def _zip(
|
|
|
60
60
|
dirs_to_exclude: set[str] | None = None,
|
|
61
61
|
files_to_exclude: set[str] | None = None,
|
|
62
62
|
top_level_dirs_to_exclude: set[str] | None = None,
|
|
63
|
+
globs_to_include: list[str] | None = None,
|
|
63
64
|
) -> None:
|
|
64
65
|
"""Zip utility function.
|
|
65
66
|
|
|
@@ -72,6 +73,7 @@ def _zip(
|
|
|
72
73
|
dirs_to_exclude: The directories to exclude.
|
|
73
74
|
files_to_exclude: The files to exclude.
|
|
74
75
|
top_level_dirs_to_exclude: The top level directory names immediately under root_dir to exclude. Do not exclude folders by these names further in the sub-directories.
|
|
76
|
+
globs_to_include: Apply these globs from the root_dir and always include them in the zip.
|
|
75
77
|
|
|
76
78
|
"""
|
|
77
79
|
target = Path(target)
|
|
@@ -103,6 +105,13 @@ def _zip(
|
|
|
103
105
|
files_to_zip += [
|
|
104
106
|
str(root / file) for file in files if file not in files_to_exclude
|
|
105
107
|
]
|
|
108
|
+
if globs_to_include:
|
|
109
|
+
for glob in globs_to_include:
|
|
110
|
+
files_to_zip += [
|
|
111
|
+
str(file)
|
|
112
|
+
for file in root_dir.glob(glob)
|
|
113
|
+
if file.name not in files_to_exclude
|
|
114
|
+
]
|
|
106
115
|
|
|
107
116
|
# Create a progress bar for zipping the component.
|
|
108
117
|
progress = Progress(
|
|
@@ -160,6 +169,9 @@ def zip_app(
|
|
|
160
169
|
top_level_dirs_to_exclude={"assets"},
|
|
161
170
|
exclude_venv_dirs=True,
|
|
162
171
|
upload_db_file=upload_db_file,
|
|
172
|
+
globs_to_include=[
|
|
173
|
+
str(Path(constants.Dirs.WEB) / constants.Dirs.BACKEND / "*")
|
|
174
|
+
],
|
|
163
175
|
)
|
|
164
176
|
|
|
165
177
|
|
reflex/utils/console.py
CHANGED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import inspect
|
|
7
|
+
import os
|
|
7
8
|
import shutil
|
|
8
9
|
import time
|
|
9
10
|
from pathlib import Path
|
|
@@ -60,6 +61,9 @@ def set_log_level(log_level: LogLevel):
|
|
|
60
61
|
f"log_level must be a LogLevel enum value, got {log_level} of type {type(log_level)} instead."
|
|
61
62
|
)
|
|
62
63
|
global _LOG_LEVEL
|
|
64
|
+
if log_level != _LOG_LEVEL:
|
|
65
|
+
# Set the loglevel persistenly for subprocesses.
|
|
66
|
+
os.environ["LOGLEVEL"] = log_level.value
|
|
63
67
|
_LOG_LEVEL = log_level
|
|
64
68
|
|
|
65
69
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Decorator utilities."""
|
|
2
|
+
|
|
3
|
+
from typing import Callable, TypeVar
|
|
4
|
+
|
|
5
|
+
T = TypeVar("T")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def once(f: Callable[[], T]) -> Callable[[], T]:
|
|
9
|
+
"""A decorator that calls the function once and caches the result.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
f: The function to call.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
A function that calls the function once and caches the result.
|
|
16
|
+
"""
|
|
17
|
+
unset = object()
|
|
18
|
+
value: object | T = unset
|
|
19
|
+
|
|
20
|
+
def wrapper() -> T:
|
|
21
|
+
nonlocal value
|
|
22
|
+
value = f() if value is unset else value
|
|
23
|
+
return value # pyright: ignore[reportReturnType]
|
|
24
|
+
|
|
25
|
+
return wrapper
|