reflex 0.7.1a4__py3-none-any.whl → 0.7.2a2__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/utils/context.js.jinja2 +8 -8
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +3 -3
- reflex/.templates/web/utils/state.js +18 -18
- reflex/admin.py +1 -2
- reflex/app.py +46 -49
- reflex/app_mixins/lifespan.py +2 -2
- reflex/app_mixins/middleware.py +1 -2
- reflex/assets.py +1 -2
- reflex/base.py +2 -2
- reflex/compiler/compiler.py +51 -16
- reflex/compiler/utils.py +4 -13
- reflex/components/base/app_wrap.pyi +7 -7
- reflex/components/base/bare.py +3 -3
- reflex/components/base/body.pyi +7 -7
- reflex/components/base/document.py +1 -3
- reflex/components/base/document.pyi +32 -32
- reflex/components/base/error_boundary.py +2 -4
- reflex/components/base/error_boundary.pyi +11 -13
- reflex/components/base/fragment.pyi +7 -7
- reflex/components/base/head.pyi +13 -13
- reflex/components/base/link.pyi +22 -22
- reflex/components/base/meta.py +5 -7
- reflex/components/base/meta.pyi +40 -40
- reflex/components/base/script.pyi +11 -14
- reflex/components/base/strict_mode.pyi +7 -7
- reflex/components/component.py +188 -113
- reflex/components/core/auto_scroll.py +8 -1
- reflex/components/core/auto_scroll.pyi +183 -210
- reflex/components/core/banner.py +2 -4
- reflex/components/core/banner.pyi +390 -444
- reflex/components/core/breakpoints.py +5 -5
- reflex/components/core/client_side_routing.pyi +14 -14
- reflex/components/core/clipboard.py +4 -4
- reflex/components/core/clipboard.pyi +12 -14
- reflex/components/core/cond.py +17 -25
- reflex/components/core/debounce.py +3 -3
- reflex/components/core/debounce.pyi +14 -14
- reflex/components/core/foreach.py +7 -2
- reflex/components/core/html.py +1 -3
- reflex/components/core/html.pyi +184 -213
- reflex/components/core/match.py +15 -19
- reflex/components/core/sticky.pyi +930 -1078
- reflex/components/core/upload.py +4 -4
- reflex/components/core/upload.pyi +62 -62
- reflex/components/datadisplay/code.py +6 -6
- reflex/components/datadisplay/code.pyi +1159 -1165
- reflex/components/datadisplay/dataeditor.py +49 -49
- reflex/components/datadisplay/dataeditor.pyi +95 -123
- reflex/components/datadisplay/logo.py +1 -3
- reflex/components/datadisplay/shiki_code_block.py +8 -10
- reflex/components/datadisplay/shiki_code_block.pyi +1678 -1720
- reflex/components/el/element.pyi +7 -7
- reflex/components/el/elements/base.pyi +183 -210
- reflex/components/el/elements/forms.py +24 -24
- reflex/components/el/elements/forms.pyi +2572 -2934
- reflex/components/el/elements/inline.py +4 -4
- reflex/components/el/elements/inline.pyi +5191 -5953
- reflex/components/el/elements/media.py +47 -47
- reflex/components/el/elements/media.pyi +4802 -5500
- reflex/components/el/elements/metadata.py +1 -3
- reflex/components/el/elements/metadata.pyi +782 -896
- reflex/components/el/elements/other.pyi +1278 -1467
- reflex/components/el/elements/scripts.pyi +580 -667
- reflex/components/el/elements/sectioning.pyi +2761 -3166
- reflex/components/el/elements/tables.pyi +1840 -2119
- reflex/components/el/elements/typography.pyi +2772 -3179
- reflex/components/gridjs/datatable.py +7 -7
- reflex/components/gridjs/datatable.pyi +19 -19
- reflex/components/lucide/icon.pyi +21 -21
- reflex/components/markdown/markdown.py +2 -2
- reflex/components/markdown/markdown.pyi +9 -9
- reflex/components/moment/moment.py +11 -12
- reflex/components/moment/moment.pyi +44 -47
- reflex/components/next/base.pyi +7 -7
- reflex/components/next/image.py +3 -3
- reflex/components/next/image.pyi +19 -21
- reflex/components/next/link.pyi +9 -9
- reflex/components/next/video.py +1 -3
- reflex/components/next/video.pyi +9 -9
- reflex/components/plotly/plotly.py +22 -45
- reflex/components/plotly/plotly.pyi +164 -164
- reflex/components/radix/primitives/accordion.py +14 -14
- reflex/components/radix/primitives/accordion.pyi +439 -487
- reflex/components/radix/primitives/base.py +1 -3
- reflex/components/radix/primitives/base.pyi +15 -15
- reflex/components/radix/primitives/drawer.py +3 -3
- reflex/components/radix/primitives/drawer.pyi +110 -116
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/form.pyi +668 -752
- reflex/components/radix/primitives/progress.py +6 -6
- reflex/components/radix/primitives/progress.pyi +225 -243
- reflex/components/radix/primitives/slider.py +6 -6
- reflex/components/radix/primitives/slider.pyi +52 -55
- reflex/components/radix/themes/base.py +3 -6
- reflex/components/radix/themes/base.pyi +197 -303
- reflex/components/radix/themes/color_mode.py +5 -5
- reflex/components/radix/themes/color_mode.pyi +366 -436
- reflex/components/radix/themes/components/alert_dialog.pyi +229 -262
- reflex/components/radix/themes/components/aspect_ratio.py +1 -3
- reflex/components/radix/themes/components/aspect_ratio.pyi +8 -8
- reflex/components/radix/themes/components/avatar.pyi +79 -94
- reflex/components/radix/themes/components/badge.pyi +252 -295
- reflex/components/radix/themes/components/button.pyi +269 -314
- reflex/components/radix/themes/components/callout.py +2 -2
- reflex/components/radix/themes/components/callout.pyi +1116 -1290
- reflex/components/radix/themes/components/card.pyi +194 -229
- reflex/components/radix/themes/components/checkbox.pyi +243 -278
- reflex/components/radix/themes/components/checkbox_cards.py +3 -7
- reflex/components/radix/themes/components/checkbox_cards.pyi +101 -135
- reflex/components/radix/themes/components/checkbox_group.py +2 -2
- reflex/components/radix/themes/components/checkbox_group.pyi +83 -96
- reflex/components/radix/themes/components/context_menu.py +18 -15
- reflex/components/radix/themes/components/context_menu.pyi +408 -458
- reflex/components/radix/themes/components/data_list.pyi +122 -147
- reflex/components/radix/themes/components/dialog.pyi +231 -264
- reflex/components/radix/themes/components/dropdown_menu.py +16 -13
- reflex/components/radix/themes/components/dropdown_menu.pyi +223 -246
- reflex/components/radix/themes/components/hover_card.py +2 -2
- reflex/components/radix/themes/components/hover_card.pyi +237 -282
- reflex/components/radix/themes/components/icon_button.pyi +269 -314
- reflex/components/radix/themes/components/inset.py +8 -8
- reflex/components/radix/themes/components/inset.pyi +232 -292
- reflex/components/radix/themes/components/popover.py +2 -2
- reflex/components/radix/themes/components/popover.pyi +229 -271
- reflex/components/radix/themes/components/progress.pyi +80 -96
- reflex/components/radix/themes/components/radio.pyi +73 -86
- reflex/components/radix/themes/components/radio_cards.py +4 -8
- reflex/components/radix/themes/components/radio_cards.pyi +117 -154
- reflex/components/radix/themes/components/radio_group.py +3 -3
- reflex/components/radix/themes/components/radio_group.pyi +250 -291
- reflex/components/radix/themes/components/scroll_area.pyi +14 -20
- reflex/components/radix/themes/components/segmented_control.py +6 -6
- reflex/components/radix/themes/components/segmented_control.pyi +89 -108
- reflex/components/radix/themes/components/select.py +7 -7
- reflex/components/radix/themes/components/select.pyi +376 -444
- reflex/components/radix/themes/components/separator.pyi +79 -93
- reflex/components/radix/themes/components/skeleton.pyi +32 -26
- reflex/components/radix/themes/components/slider.py +8 -8
- reflex/components/radix/themes/components/slider.pyi +99 -122
- reflex/components/radix/themes/components/spinner.pyi +12 -19
- reflex/components/radix/themes/components/switch.pyi +84 -99
- reflex/components/radix/themes/components/table.py +9 -9
- reflex/components/radix/themes/components/table.pyi +1440 -1794
- reflex/components/radix/themes/components/tabs.py +4 -4
- reflex/components/radix/themes/components/tabs.pyi +120 -132
- reflex/components/radix/themes/components/text_area.pyi +281 -331
- reflex/components/radix/themes/components/text_field.py +2 -2
- reflex/components/radix/themes/components/text_field.pyi +639 -734
- reflex/components/radix/themes/components/tooltip.py +6 -6
- reflex/components/radix/themes/components/tooltip.pyi +34 -43
- reflex/components/radix/themes/layout/base.pyi +85 -182
- reflex/components/radix/themes/layout/box.pyi +183 -210
- reflex/components/radix/themes/layout/center.pyi +225 -286
- reflex/components/radix/themes/layout/container.pyi +191 -224
- reflex/components/radix/themes/layout/flex.py +2 -2
- reflex/components/radix/themes/layout/flex.pyi +225 -286
- reflex/components/radix/themes/layout/grid.py +2 -2
- reflex/components/radix/themes/layout/grid.pyi +245 -315
- reflex/components/radix/themes/layout/list.py +2 -2
- reflex/components/radix/themes/layout/list.pyi +712 -815
- reflex/components/radix/themes/layout/section.pyi +187 -221
- reflex/components/radix/themes/layout/spacer.pyi +225 -286
- reflex/components/radix/themes/layout/stack.pyi +625 -768
- reflex/components/radix/themes/typography/blockquote.pyi +257 -299
- reflex/components/radix/themes/typography/code.pyi +259 -304
- reflex/components/radix/themes/typography/heading.pyi +272 -324
- reflex/components/radix/themes/typography/link.pyi +302 -358
- reflex/components/radix/themes/typography/text.pyi +1669 -1945
- reflex/components/react_player/audio.pyi +20 -22
- reflex/components/react_player/react_player.pyi +19 -19
- reflex/components/react_player/video.pyi +20 -22
- reflex/components/recharts/cartesian.py +100 -97
- reflex/components/recharts/cartesian.pyi +891 -1007
- reflex/components/recharts/charts.py +42 -42
- reflex/components/recharts/charts.pyi +212 -249
- reflex/components/recharts/general.py +22 -21
- reflex/components/recharts/general.pyi +198 -223
- reflex/components/recharts/polar.py +42 -45
- reflex/components/recharts/polar.pyi +254 -288
- reflex/components/recharts/recharts.pyi +13 -13
- reflex/components/sonner/toast.py +20 -20
- reflex/components/sonner/toast.pyi +58 -61
- reflex/components/suneditor/editor.py +9 -9
- reflex/components/suneditor/editor.pyi +78 -83
- reflex/components/tags/cond_tag.py +2 -2
- reflex/components/tags/iter_tag.py +10 -14
- reflex/components/tags/match_tag.py +2 -2
- reflex/components/tags/tag.py +10 -10
- reflex/config.py +36 -35
- reflex/constants/__init__.py +56 -53
- reflex/custom_components/custom_components.py +6 -7
- reflex/event.py +38 -42
- reflex/experimental/client_state.py +2 -4
- reflex/experimental/layout.py +2 -2
- reflex/experimental/layout.pyi +579 -663
- reflex/istate/data.py +4 -5
- reflex/middleware/hydrate_middleware.py +2 -2
- reflex/middleware/middleware.py +2 -2
- reflex/model.py +3 -5
- reflex/page.py +2 -2
- reflex/reflex.py +9 -10
- reflex/state.py +77 -49
- reflex/style.py +9 -3
- reflex/testing.py +21 -24
- reflex/utils/console.py +1 -1
- reflex/utils/decorator.py +26 -1
- reflex/utils/exec.py +6 -11
- reflex/utils/export.py +2 -3
- reflex/utils/format.py +4 -4
- reflex/utils/imports.py +12 -12
- reflex/utils/prerequisites.py +35 -84
- reflex/utils/processes.py +5 -5
- reflex/utils/pyi_generator.py +33 -22
- reflex/utils/serializers.py +60 -15
- reflex/utils/types.py +237 -56
- reflex/vars/base.py +122 -72
- reflex/vars/datetime.py +2 -2
- reflex/vars/function.py +52 -55
- reflex/vars/number.py +59 -5
- reflex/vars/object.py +57 -26
- reflex/vars/sequence.py +983 -958
- {reflex-0.7.1a4.dist-info → reflex-0.7.2a2.dist-info}/METADATA +3 -6
- reflex-0.7.2a2.dist-info/RECORD +405 -0
- {reflex-0.7.1a4.dist-info → reflex-0.7.2a2.dist-info}/WHEEL +1 -1
- reflex-0.7.1a4.dist-info/RECORD +0 -405
- {reflex-0.7.1a4.dist-info → reflex-0.7.2a2.dist-info}/LICENSE +0 -0
- {reflex-0.7.1a4.dist-info → reflex-0.7.2a2.dist-info}/entry_points.txt +0 -0
reflex/istate/data.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""This module contains the dataclasses representing the router object."""
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
from typing import Optional
|
|
5
4
|
|
|
6
5
|
from reflex import constants
|
|
7
6
|
from reflex.utils import format
|
|
@@ -25,7 +24,7 @@ class HeaderData:
|
|
|
25
24
|
accept_encoding: str = ""
|
|
26
25
|
accept_language: str = ""
|
|
27
26
|
|
|
28
|
-
def __init__(self, router_data:
|
|
27
|
+
def __init__(self, router_data: dict | None = None):
|
|
29
28
|
"""Initialize the HeaderData object based on router_data.
|
|
30
29
|
|
|
31
30
|
Args:
|
|
@@ -50,7 +49,7 @@ class PageData:
|
|
|
50
49
|
full_raw_path: str = ""
|
|
51
50
|
params: dict = dataclasses.field(default_factory=dict)
|
|
52
51
|
|
|
53
|
-
def __init__(self, router_data:
|
|
52
|
+
def __init__(self, router_data: dict | None = None):
|
|
54
53
|
"""Initialize the PageData object based on router_data.
|
|
55
54
|
|
|
56
55
|
Args:
|
|
@@ -90,7 +89,7 @@ class SessionData:
|
|
|
90
89
|
client_ip: str = ""
|
|
91
90
|
session_id: str = ""
|
|
92
91
|
|
|
93
|
-
def __init__(self, router_data:
|
|
92
|
+
def __init__(self, router_data: dict | None = None):
|
|
94
93
|
"""Initialize the SessionData object based on router_data.
|
|
95
94
|
|
|
96
95
|
Args:
|
|
@@ -115,7 +114,7 @@ class RouterData:
|
|
|
115
114
|
headers: HeaderData = dataclasses.field(default_factory=HeaderData)
|
|
116
115
|
page: PageData = dataclasses.field(default_factory=PageData)
|
|
117
116
|
|
|
118
|
-
def __init__(self, router_data:
|
|
117
|
+
def __init__(self, router_data: dict | None = None):
|
|
119
118
|
"""Initialize the RouterData object.
|
|
120
119
|
|
|
121
120
|
Args:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import dataclasses
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from reflex import constants
|
|
9
9
|
from reflex.event import Event, get_hydrate_event
|
|
@@ -20,7 +20,7 @@ class HydrateMiddleware(Middleware):
|
|
|
20
20
|
|
|
21
21
|
async def preprocess(
|
|
22
22
|
self, app: App, state: BaseState, event: Event
|
|
23
|
-
) ->
|
|
23
|
+
) -> StateUpdate | None:
|
|
24
24
|
"""Preprocess the event.
|
|
25
25
|
|
|
26
26
|
Args:
|
reflex/middleware/middleware.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
8
|
from reflex.event import Event
|
|
9
9
|
from reflex.state import BaseState, StateUpdate
|
|
@@ -18,7 +18,7 @@ class Middleware(ABC):
|
|
|
18
18
|
@abstractmethod
|
|
19
19
|
async def preprocess(
|
|
20
20
|
self, app: App, state: BaseState, event: Event
|
|
21
|
-
) ->
|
|
21
|
+
) -> StateUpdate | None:
|
|
22
22
|
"""Preprocess the event.
|
|
23
23
|
|
|
24
24
|
Args:
|
reflex/model.py
CHANGED
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import re
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from contextlib import suppress
|
|
8
|
-
from typing import Any, ClassVar,
|
|
8
|
+
from typing import Any, ClassVar, Type
|
|
9
9
|
|
|
10
10
|
import alembic.autogenerate
|
|
11
11
|
import alembic.command
|
|
@@ -161,9 +161,7 @@ async def get_db_status() -> dict[str, bool]:
|
|
|
161
161
|
return {"db": status}
|
|
162
162
|
|
|
163
163
|
|
|
164
|
-
SQLModelOrSqlAlchemy =
|
|
165
|
-
Type[sqlmodel.SQLModel], Type[sqlalchemy.orm.DeclarativeBase]
|
|
166
|
-
]
|
|
164
|
+
SQLModelOrSqlAlchemy = Type[sqlmodel.SQLModel] | Type[sqlalchemy.orm.DeclarativeBase]
|
|
167
165
|
|
|
168
166
|
|
|
169
167
|
class ModelRegistry:
|
|
@@ -247,7 +245,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|
|
247
245
|
"""Base class to define a table in the database."""
|
|
248
246
|
|
|
249
247
|
# The primary key for the table.
|
|
250
|
-
id:
|
|
248
|
+
id: int | None = sqlmodel.Field(default=None, primary_key=True)
|
|
251
249
|
|
|
252
250
|
def __init_subclass__(cls):
|
|
253
251
|
"""Drop the default primary key field if any primary key field is defined."""
|
reflex/page.py
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from collections import defaultdict
|
|
6
|
-
from typing import Any, Callable,
|
|
6
|
+
from typing import Any, Callable, List
|
|
7
7
|
|
|
8
8
|
from reflex.config import get_config
|
|
9
9
|
from reflex.event import EventType
|
|
10
10
|
|
|
11
|
-
DECORATED_PAGES:
|
|
11
|
+
DECORATED_PAGES: dict[str, List] = defaultdict(list)
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def page(
|
reflex/reflex.py
CHANGED
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import atexit
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import List, Optional
|
|
8
7
|
|
|
9
8
|
import typer
|
|
10
9
|
import typer.core
|
|
@@ -477,23 +476,23 @@ def deploy(
|
|
|
477
476
|
"--app-id",
|
|
478
477
|
help="The ID of the App to deploy over.",
|
|
479
478
|
),
|
|
480
|
-
regions:
|
|
479
|
+
regions: list[str] = typer.Option(
|
|
481
480
|
[],
|
|
482
481
|
"-r",
|
|
483
482
|
"--region",
|
|
484
483
|
help="The regions to deploy to. `reflex cloud regions` For multiple envs, repeat this option, e.g. --region sjc --region iad",
|
|
485
484
|
),
|
|
486
|
-
envs:
|
|
485
|
+
envs: list[str] = typer.Option(
|
|
487
486
|
[],
|
|
488
487
|
"--env",
|
|
489
488
|
help="The environment variables to set: <key>=<value>. For multiple envs, repeat this option, e.g. --env k1=v2 --env k2=v2.",
|
|
490
489
|
),
|
|
491
|
-
vmtype:
|
|
490
|
+
vmtype: str | None = typer.Option(
|
|
492
491
|
None,
|
|
493
492
|
"--vmtype",
|
|
494
493
|
help="Vm type id. Run `reflex cloud vmtypes` to get options.",
|
|
495
494
|
),
|
|
496
|
-
hostname:
|
|
495
|
+
hostname: str | None = typer.Option(
|
|
497
496
|
None,
|
|
498
497
|
"--hostname",
|
|
499
498
|
help="The hostname of the frontend.",
|
|
@@ -502,7 +501,7 @@ def deploy(
|
|
|
502
501
|
True,
|
|
503
502
|
help="Whether to list configuration options and ask for confirmation.",
|
|
504
503
|
),
|
|
505
|
-
envfile:
|
|
504
|
+
envfile: str | None = typer.Option(
|
|
506
505
|
None,
|
|
507
506
|
"--envfile",
|
|
508
507
|
help="The path to an env file to use. Will override any envs set manually.",
|
|
@@ -510,22 +509,22 @@ def deploy(
|
|
|
510
509
|
loglevel: constants.LogLevel = typer.Option(
|
|
511
510
|
config.loglevel, help="The log level to use."
|
|
512
511
|
),
|
|
513
|
-
project:
|
|
512
|
+
project: str | None = typer.Option(
|
|
514
513
|
None,
|
|
515
514
|
"--project",
|
|
516
515
|
help="project id to deploy to",
|
|
517
516
|
),
|
|
518
|
-
project_name:
|
|
517
|
+
project_name: str | None = typer.Option(
|
|
519
518
|
None,
|
|
520
519
|
"--project-name",
|
|
521
520
|
help="The name of the project to deploy to.",
|
|
522
521
|
),
|
|
523
|
-
token:
|
|
522
|
+
token: str | None = typer.Option(
|
|
524
523
|
None,
|
|
525
524
|
"--token",
|
|
526
525
|
help="token to use for auth",
|
|
527
526
|
),
|
|
528
|
-
config_path:
|
|
527
|
+
config_path: str | None = typer.Option(
|
|
529
528
|
None,
|
|
530
529
|
"--config",
|
|
531
530
|
help="path to the config file",
|
reflex/state.py
CHANGED
|
@@ -14,6 +14,7 @@ import sys
|
|
|
14
14
|
import time
|
|
15
15
|
import typing
|
|
16
16
|
import uuid
|
|
17
|
+
import warnings
|
|
17
18
|
from abc import ABC, abstractmethod
|
|
18
19
|
from hashlib import md5
|
|
19
20
|
from pathlib import Path
|
|
@@ -26,7 +27,6 @@ from typing import (
|
|
|
26
27
|
Callable,
|
|
27
28
|
ClassVar,
|
|
28
29
|
Dict,
|
|
29
|
-
List,
|
|
30
30
|
Optional,
|
|
31
31
|
Sequence,
|
|
32
32
|
Set,
|
|
@@ -34,7 +34,6 @@ from typing import (
|
|
|
34
34
|
Tuple,
|
|
35
35
|
Type,
|
|
36
36
|
TypeVar,
|
|
37
|
-
Union,
|
|
38
37
|
cast,
|
|
39
38
|
get_args,
|
|
40
39
|
get_type_hints,
|
|
@@ -90,9 +89,9 @@ from reflex.utils.serializers import serializer
|
|
|
90
89
|
from reflex.utils.types import (
|
|
91
90
|
_isinstance,
|
|
92
91
|
get_origin,
|
|
93
|
-
is_optional,
|
|
94
92
|
is_union,
|
|
95
93
|
override,
|
|
94
|
+
true_type_for_pydantic_field,
|
|
96
95
|
value_inside_optional,
|
|
97
96
|
)
|
|
98
97
|
from reflex.vars import VarData
|
|
@@ -110,7 +109,7 @@ if TYPE_CHECKING:
|
|
|
110
109
|
from reflex.components.component import Component
|
|
111
110
|
|
|
112
111
|
|
|
113
|
-
Delta =
|
|
112
|
+
Delta = dict[str, Any]
|
|
114
113
|
var = computed_var
|
|
115
114
|
|
|
116
115
|
|
|
@@ -118,7 +117,7 @@ if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF:
|
|
|
118
117
|
# If the state is this large, it's considered a performance issue.
|
|
119
118
|
TOO_LARGE_SERIALIZED_STATE = environment.REFLEX_STATE_SIZE_LIMIT.get() * 1024
|
|
120
119
|
# Only warn about each state class size once.
|
|
121
|
-
_WARNED_ABOUT_STATE_SIZE:
|
|
120
|
+
_WARNED_ABOUT_STATE_SIZE: set[str] = set()
|
|
122
121
|
|
|
123
122
|
# Errors caught during pickling of state
|
|
124
123
|
HANDLED_PICKLE_ERRORS = (
|
|
@@ -273,7 +272,11 @@ class EventHandlerSetVar(EventHandler):
|
|
|
273
272
|
return super().__call__(*args)
|
|
274
273
|
|
|
275
274
|
|
|
276
|
-
|
|
275
|
+
if TYPE_CHECKING:
|
|
276
|
+
from pydantic.v1.fields import ModelField
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _unwrap_field_type(type_: types.GenericType) -> Type:
|
|
277
280
|
"""Unwrap rx.Field type annotations.
|
|
278
281
|
|
|
279
282
|
Args:
|
|
@@ -304,7 +307,7 @@ def get_var_for_field(cls: Type[BaseState], f: ModelField):
|
|
|
304
307
|
return dispatch(
|
|
305
308
|
field_name=field_name,
|
|
306
309
|
var_data=VarData.from_state(cls, f.name),
|
|
307
|
-
result_var_type=_unwrap_field_type(f
|
|
310
|
+
result_var_type=_unwrap_field_type(true_type_for_pydantic_field(f)),
|
|
308
311
|
)
|
|
309
312
|
|
|
310
313
|
|
|
@@ -355,31 +358,31 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
355
358
|
event_handlers: ClassVar[Dict[str, EventHandler]] = {}
|
|
356
359
|
|
|
357
360
|
# A set of subclassses of this class.
|
|
358
|
-
class_subclasses: ClassVar[
|
|
361
|
+
class_subclasses: ClassVar[set[Type[BaseState]]] = set()
|
|
359
362
|
|
|
360
363
|
# Mapping of var name to set of (state_full_name, var_name) that depend on it.
|
|
361
|
-
_var_dependencies: ClassVar[Dict[str,
|
|
364
|
+
_var_dependencies: ClassVar[Dict[str, set[tuple[str, str]]]] = {}
|
|
362
365
|
|
|
363
366
|
# Set of vars which always need to be recomputed
|
|
364
|
-
_always_dirty_computed_vars: ClassVar[
|
|
367
|
+
_always_dirty_computed_vars: ClassVar[set[str]] = set()
|
|
365
368
|
|
|
366
369
|
# Set of substates which always need to be recomputed
|
|
367
|
-
_always_dirty_substates: ClassVar[
|
|
370
|
+
_always_dirty_substates: ClassVar[set[str]] = set()
|
|
368
371
|
|
|
369
372
|
# Set of states which might need to be recomputed if vars in this state change.
|
|
370
|
-
_potentially_dirty_states: ClassVar[
|
|
373
|
+
_potentially_dirty_states: ClassVar[set[str]] = set()
|
|
371
374
|
|
|
372
375
|
# The parent state.
|
|
373
|
-
parent_state:
|
|
376
|
+
parent_state: BaseState | None = None
|
|
374
377
|
|
|
375
378
|
# The substates of the state.
|
|
376
379
|
substates: Dict[str, BaseState] = {}
|
|
377
380
|
|
|
378
381
|
# The set of dirty vars.
|
|
379
|
-
dirty_vars:
|
|
382
|
+
dirty_vars: set[str] = set()
|
|
380
383
|
|
|
381
384
|
# The set of dirty substates.
|
|
382
|
-
dirty_substates:
|
|
385
|
+
dirty_substates: set[str] = set()
|
|
383
386
|
|
|
384
387
|
# The routing path that triggered the state
|
|
385
388
|
router_data: Dict[str, Any] = {}
|
|
@@ -670,9 +673,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
670
673
|
)
|
|
671
674
|
|
|
672
675
|
@classmethod
|
|
673
|
-
def _evaluate(
|
|
674
|
-
cls, f: Callable[[Self], Any], of_type: Union[type, None] = None
|
|
675
|
-
) -> Var:
|
|
676
|
+
def _evaluate(cls, f: Callable[[Self], Any], of_type: type | None = None) -> Var:
|
|
676
677
|
"""Evaluate a function to a ComputedVar. Experimental.
|
|
677
678
|
|
|
678
679
|
Args:
|
|
@@ -695,7 +696,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
695
696
|
def computed_var_func(state: Self):
|
|
696
697
|
result = f(state)
|
|
697
698
|
|
|
698
|
-
if not _isinstance(result, of_type):
|
|
699
|
+
if not _isinstance(result, of_type, nested=1, treat_var_as_type=False):
|
|
699
700
|
console.warn(
|
|
700
701
|
f"Inline ComputedVar {f} expected type {of_type}, got {type(result)}. "
|
|
701
702
|
"You can specify expected type with `of_type` argument."
|
|
@@ -712,7 +713,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
712
713
|
return getattr(cls, unique_var_name)
|
|
713
714
|
|
|
714
715
|
@classmethod
|
|
715
|
-
def _mixins(cls) ->
|
|
716
|
+
def _mixins(cls) -> list[Type]:
|
|
716
717
|
"""Get the mixin classes of the state.
|
|
717
718
|
|
|
718
719
|
Returns:
|
|
@@ -1199,7 +1200,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1199
1200
|
return inner_func
|
|
1200
1201
|
|
|
1201
1202
|
def arglist_factory(param: str):
|
|
1202
|
-
def inner_func(self: BaseState) ->
|
|
1203
|
+
def inner_func(self: BaseState) -> list[str]:
|
|
1203
1204
|
return self.router.page.params.get(param, [])
|
|
1204
1205
|
|
|
1205
1206
|
return inner_func
|
|
@@ -1353,10 +1354,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1353
1354
|
|
|
1354
1355
|
if name in fields:
|
|
1355
1356
|
field = fields[name]
|
|
1356
|
-
field_type = _unwrap_field_type(field
|
|
1357
|
-
if
|
|
1358
|
-
field_type = Union[field_type, None]
|
|
1359
|
-
if not _isinstance(value, field_type):
|
|
1357
|
+
field_type = _unwrap_field_type(true_type_for_pydantic_field(field))
|
|
1358
|
+
if not _isinstance(value, field_type, nested=1, treat_var_as_type=False):
|
|
1360
1359
|
console.error(
|
|
1361
1360
|
f"Expected field '{type(self).__name__}.{name}' to receive type '{field_type}',"
|
|
1362
1361
|
f" but got '{value}' of type '{type(value)}'."
|
|
@@ -1645,14 +1644,26 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1645
1644
|
|
|
1646
1645
|
if events is None or _is_valid_type(events):
|
|
1647
1646
|
return events
|
|
1647
|
+
|
|
1648
|
+
if not isinstance(events, Sequence):
|
|
1649
|
+
events = [events]
|
|
1650
|
+
|
|
1648
1651
|
try:
|
|
1649
1652
|
if all(_is_valid_type(e) for e in events):
|
|
1650
1653
|
return events
|
|
1651
1654
|
except TypeError:
|
|
1652
1655
|
pass
|
|
1653
1656
|
|
|
1657
|
+
coroutines = [e for e in events if asyncio.iscoroutine(e)]
|
|
1658
|
+
|
|
1659
|
+
for coroutine in coroutines:
|
|
1660
|
+
coroutine_name = coroutine.__qualname__
|
|
1661
|
+
warnings.filterwarnings(
|
|
1662
|
+
"ignore", message=f"coroutine '{coroutine_name}' was never awaited"
|
|
1663
|
+
)
|
|
1664
|
+
|
|
1654
1665
|
raise TypeError(
|
|
1655
|
-
f"Your handler {handler.fn.__qualname__} must only return/yield: None, Events or other EventHandlers referenced by their class (
|
|
1666
|
+
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)."
|
|
1656
1667
|
)
|
|
1657
1668
|
|
|
1658
1669
|
async def _as_state_update(
|
|
@@ -1702,7 +1713,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1702
1713
|
return StateUpdate()
|
|
1703
1714
|
|
|
1704
1715
|
event_specs_correct_type = cast(
|
|
1705
|
-
|
|
1716
|
+
list[EventSpec | EventHandler] | None,
|
|
1706
1717
|
[event_specs] if isinstance(event_specs, EventSpec) else event_specs,
|
|
1707
1718
|
)
|
|
1708
1719
|
fixed_events = fix_events(
|
|
@@ -1911,7 +1922,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
1911
1922
|
self.dirty_vars.intersection(frontend_computed_vars)
|
|
1912
1923
|
)
|
|
1913
1924
|
|
|
1914
|
-
subdelta:
|
|
1925
|
+
subdelta: dict[str, Any] = {
|
|
1915
1926
|
prop: self.get_value(prop)
|
|
1916
1927
|
for prop in delta_vars
|
|
1917
1928
|
if not types.is_backend_base_variable(prop, type(self))
|
|
@@ -2150,7 +2161,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|
|
2150
2161
|
|
|
2151
2162
|
def _field_tuple(
|
|
2152
2163
|
field_name: str,
|
|
2153
|
-
) ->
|
|
2164
|
+
) -> tuple[str, str, Any, bool | None, Any]:
|
|
2154
2165
|
model_field = cls.__fields__[field_name]
|
|
2155
2166
|
return (
|
|
2156
2167
|
field_name,
|
|
@@ -2357,7 +2368,7 @@ class OnLoadInternalState(State):
|
|
|
2357
2368
|
self.is_hydrated = False
|
|
2358
2369
|
return [
|
|
2359
2370
|
*fix_events(
|
|
2360
|
-
cast(list[
|
|
2371
|
+
cast(list[EventSpec | EventHandler], load_events),
|
|
2361
2372
|
self.router.session.client_token,
|
|
2362
2373
|
router_data=self.router_data,
|
|
2363
2374
|
),
|
|
@@ -2760,7 +2771,7 @@ class StateUpdate:
|
|
|
2760
2771
|
delta: Delta = dataclasses.field(default_factory=dict)
|
|
2761
2772
|
|
|
2762
2773
|
# Events to be added to the event queue.
|
|
2763
|
-
events:
|
|
2774
|
+
events: list[Event] = dataclasses.field(default_factory=list)
|
|
2764
2775
|
|
|
2765
2776
|
# Whether this is the final state update for the event.
|
|
2766
2777
|
final: bool = True
|
|
@@ -2855,13 +2866,13 @@ class StateManagerMemory(StateManager):
|
|
|
2855
2866
|
"""A state manager that stores states in memory."""
|
|
2856
2867
|
|
|
2857
2868
|
# The mapping of client ids to states.
|
|
2858
|
-
states:
|
|
2869
|
+
states: dict[str, BaseState] = {}
|
|
2859
2870
|
|
|
2860
2871
|
# The mutex ensures the dict of mutexes is updated exclusively
|
|
2861
2872
|
_state_manager_lock = asyncio.Lock()
|
|
2862
2873
|
|
|
2863
2874
|
# The dict of mutexes for each client
|
|
2864
|
-
_states_locks:
|
|
2875
|
+
_states_locks: dict[str, asyncio.Lock] = pydantic.PrivateAttr({})
|
|
2865
2876
|
|
|
2866
2877
|
class Config: # pyright: ignore [reportIncompatibleVariableOverride]
|
|
2867
2878
|
"""The Pydantic config."""
|
|
@@ -2970,13 +2981,13 @@ class StateManagerDisk(StateManager):
|
|
|
2970
2981
|
"""A state manager that stores states in memory."""
|
|
2971
2982
|
|
|
2972
2983
|
# The mapping of client ids to states.
|
|
2973
|
-
states:
|
|
2984
|
+
states: dict[str, BaseState] = {}
|
|
2974
2985
|
|
|
2975
2986
|
# The mutex ensures the dict of mutexes is updated exclusively
|
|
2976
2987
|
_state_manager_lock = asyncio.Lock()
|
|
2977
2988
|
|
|
2978
2989
|
# The dict of mutexes for each client
|
|
2979
|
-
_states_locks:
|
|
2990
|
+
_states_locks: dict[str, asyncio.Lock] = pydantic.PrivateAttr({})
|
|
2980
2991
|
|
|
2981
2992
|
# The token expiration time (s).
|
|
2982
2993
|
token_expiration: int = pydantic.Field(default_factory=_default_token_expiration)
|
|
@@ -3205,7 +3216,7 @@ class StateManagerRedis(StateManager):
|
|
|
3205
3216
|
default_factory=_default_lock_warning_threshold
|
|
3206
3217
|
)
|
|
3207
3218
|
|
|
3208
|
-
# The keyspace subscription string when redis is waiting for lock to be released
|
|
3219
|
+
# The keyspace subscription string when redis is waiting for lock to be released.
|
|
3209
3220
|
_redis_notify_keyspace_events: str = (
|
|
3210
3221
|
"K" # Enable keyspace notifications (target a particular key)
|
|
3211
3222
|
"g" # For generic commands (DEL, EXPIRE, etc)
|
|
@@ -3213,14 +3224,20 @@ class StateManagerRedis(StateManager):
|
|
|
3213
3224
|
"e" # For evicted events (i.e. maxmemory exceeded)
|
|
3214
3225
|
)
|
|
3215
3226
|
|
|
3216
|
-
# These events indicate that a lock is no longer held
|
|
3217
|
-
_redis_keyspace_lock_release_events:
|
|
3227
|
+
# These events indicate that a lock is no longer held.
|
|
3228
|
+
_redis_keyspace_lock_release_events: set[bytes] = {
|
|
3218
3229
|
b"del",
|
|
3219
3230
|
b"expire",
|
|
3220
3231
|
b"expired",
|
|
3221
3232
|
b"evicted",
|
|
3222
3233
|
}
|
|
3223
3234
|
|
|
3235
|
+
# Whether keyspace notifications have been enabled.
|
|
3236
|
+
_redis_notify_keyspace_events_enabled: bool = False
|
|
3237
|
+
|
|
3238
|
+
# The logical database number used by the redis client.
|
|
3239
|
+
_redis_db: int = 0
|
|
3240
|
+
|
|
3224
3241
|
def _get_required_state_classes(
|
|
3225
3242
|
self,
|
|
3226
3243
|
target_state_cls: Type[BaseState],
|
|
@@ -3553,20 +3570,17 @@ class StateManagerRedis(StateManager):
|
|
|
3553
3570
|
return
|
|
3554
3571
|
await self._get_pubsub_message(pubsub, timeout=remaining)
|
|
3555
3572
|
|
|
3556
|
-
async def
|
|
3557
|
-
"""
|
|
3558
|
-
|
|
3559
|
-
Coroutine will not return until the lock is obtained.
|
|
3560
|
-
|
|
3561
|
-
Args:
|
|
3562
|
-
lock_key: The redis key for the lock.
|
|
3563
|
-
lock_id: The ID of the lock.
|
|
3573
|
+
async def _enable_keyspace_notifications(self):
|
|
3574
|
+
"""Enable keyspace notifications for the redis server.
|
|
3564
3575
|
|
|
3565
3576
|
Raises:
|
|
3566
3577
|
ResponseError: when the keyspace config cannot be set.
|
|
3567
3578
|
"""
|
|
3568
|
-
|
|
3569
|
-
|
|
3579
|
+
if self._redis_notify_keyspace_events_enabled:
|
|
3580
|
+
return
|
|
3581
|
+
# Find out which logical database index is being used.
|
|
3582
|
+
self._redis_db = self.redis.get_connection_kwargs().get("db", self._redis_db)
|
|
3583
|
+
|
|
3570
3584
|
try:
|
|
3571
3585
|
await self.redis.config_set(
|
|
3572
3586
|
"notify-keyspace-events",
|
|
@@ -3576,6 +3590,20 @@ class StateManagerRedis(StateManager):
|
|
|
3576
3590
|
# Some redis servers only allow out-of-band configuration, so ignore errors here.
|
|
3577
3591
|
if not environment.REFLEX_IGNORE_REDIS_CONFIG_ERROR.get():
|
|
3578
3592
|
raise
|
|
3593
|
+
self._redis_notify_keyspace_events_enabled = True
|
|
3594
|
+
|
|
3595
|
+
async def _wait_lock(self, lock_key: bytes, lock_id: bytes) -> None:
|
|
3596
|
+
"""Wait for a redis lock to be released via pubsub.
|
|
3597
|
+
|
|
3598
|
+
Coroutine will not return until the lock is obtained.
|
|
3599
|
+
|
|
3600
|
+
Args:
|
|
3601
|
+
lock_key: The redis key for the lock.
|
|
3602
|
+
lock_id: The ID of the lock.
|
|
3603
|
+
"""
|
|
3604
|
+
# Enable keyspace notifications for the lock key, so we know when it is available.
|
|
3605
|
+
await self._enable_keyspace_notifications()
|
|
3606
|
+
lock_key_channel = f"__keyspace@{self._redis_db}__:{lock_key.decode()}"
|
|
3579
3607
|
async with self.redis.pubsub() as pubsub:
|
|
3580
3608
|
await pubsub.psubscribe(lock_key_channel)
|
|
3581
3609
|
# wait for the lock to be released
|
|
@@ -3687,7 +3715,7 @@ class MutableProxy(wrapt.ObjectProxy):
|
|
|
3687
3715
|
)
|
|
3688
3716
|
|
|
3689
3717
|
# Dynamically generated classes for tracking dataclass mutations.
|
|
3690
|
-
__dataclass_proxies__:
|
|
3718
|
+
__dataclass_proxies__: dict[type, type] = {}
|
|
3691
3719
|
|
|
3692
3720
|
def __new__(cls, wrapped: Any, *args, **kwargs) -> MutableProxy:
|
|
3693
3721
|
"""Create a proxy instance for a mutable object that tracks changes.
|
reflex/style.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Any, Literal,
|
|
5
|
+
from typing import Any, Literal, Type
|
|
6
6
|
|
|
7
7
|
from reflex import constants
|
|
8
8
|
from reflex.components.core.breakpoints import Breakpoints, breakpoints_values
|
|
@@ -218,7 +218,7 @@ def convert(
|
|
|
218
218
|
return out, var_data
|
|
219
219
|
|
|
220
220
|
|
|
221
|
-
def format_style_key(key: str) ->
|
|
221
|
+
def format_style_key(key: str) -> tuple[str, ...]:
|
|
222
222
|
"""Convert style keys to camel case and convert shorthand
|
|
223
223
|
styles names to their corresponding css names.
|
|
224
224
|
|
|
@@ -234,6 +234,9 @@ def format_style_key(key: str) -> Tuple[str, ...]:
|
|
|
234
234
|
return STYLE_PROP_SHORTHAND_MAPPING.get(key, (key,))
|
|
235
235
|
|
|
236
236
|
|
|
237
|
+
EMPTY_VAR_DATA = VarData()
|
|
238
|
+
|
|
239
|
+
|
|
237
240
|
class Style(dict):
|
|
238
241
|
"""A style dictionary."""
|
|
239
242
|
|
|
@@ -248,7 +251,10 @@ class Style(dict):
|
|
|
248
251
|
style_dict.update(kwargs)
|
|
249
252
|
else:
|
|
250
253
|
style_dict = kwargs
|
|
251
|
-
|
|
254
|
+
if style_dict:
|
|
255
|
+
style_dict, self._var_data = convert(style_dict)
|
|
256
|
+
else:
|
|
257
|
+
self._var_data = EMPTY_VAR_DATA
|
|
252
258
|
super().__init__(style_dict)
|
|
253
259
|
|
|
254
260
|
def update(self, style_dict: dict | None, **kwargs):
|