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.

Files changed (227) hide show
  1. reflex/.templates/jinja/web/utils/context.js.jinja2 +8 -8
  2. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +3 -3
  3. reflex/.templates/web/utils/state.js +18 -18
  4. reflex/admin.py +1 -2
  5. reflex/app.py +46 -49
  6. reflex/app_mixins/lifespan.py +2 -2
  7. reflex/app_mixins/middleware.py +1 -2
  8. reflex/assets.py +1 -2
  9. reflex/base.py +2 -2
  10. reflex/compiler/compiler.py +51 -16
  11. reflex/compiler/utils.py +4 -13
  12. reflex/components/base/app_wrap.pyi +7 -7
  13. reflex/components/base/bare.py +3 -3
  14. reflex/components/base/body.pyi +7 -7
  15. reflex/components/base/document.py +1 -3
  16. reflex/components/base/document.pyi +32 -32
  17. reflex/components/base/error_boundary.py +2 -4
  18. reflex/components/base/error_boundary.pyi +11 -13
  19. reflex/components/base/fragment.pyi +7 -7
  20. reflex/components/base/head.pyi +13 -13
  21. reflex/components/base/link.pyi +22 -22
  22. reflex/components/base/meta.py +5 -7
  23. reflex/components/base/meta.pyi +40 -40
  24. reflex/components/base/script.pyi +11 -14
  25. reflex/components/base/strict_mode.pyi +7 -7
  26. reflex/components/component.py +188 -113
  27. reflex/components/core/auto_scroll.py +8 -1
  28. reflex/components/core/auto_scroll.pyi +183 -210
  29. reflex/components/core/banner.py +2 -4
  30. reflex/components/core/banner.pyi +390 -444
  31. reflex/components/core/breakpoints.py +5 -5
  32. reflex/components/core/client_side_routing.pyi +14 -14
  33. reflex/components/core/clipboard.py +4 -4
  34. reflex/components/core/clipboard.pyi +12 -14
  35. reflex/components/core/cond.py +17 -25
  36. reflex/components/core/debounce.py +3 -3
  37. reflex/components/core/debounce.pyi +14 -14
  38. reflex/components/core/foreach.py +7 -2
  39. reflex/components/core/html.py +1 -3
  40. reflex/components/core/html.pyi +184 -213
  41. reflex/components/core/match.py +15 -19
  42. reflex/components/core/sticky.pyi +930 -1078
  43. reflex/components/core/upload.py +4 -4
  44. reflex/components/core/upload.pyi +62 -62
  45. reflex/components/datadisplay/code.py +6 -6
  46. reflex/components/datadisplay/code.pyi +1159 -1165
  47. reflex/components/datadisplay/dataeditor.py +49 -49
  48. reflex/components/datadisplay/dataeditor.pyi +95 -123
  49. reflex/components/datadisplay/logo.py +1 -3
  50. reflex/components/datadisplay/shiki_code_block.py +8 -10
  51. reflex/components/datadisplay/shiki_code_block.pyi +1678 -1720
  52. reflex/components/el/element.pyi +7 -7
  53. reflex/components/el/elements/base.pyi +183 -210
  54. reflex/components/el/elements/forms.py +24 -24
  55. reflex/components/el/elements/forms.pyi +2572 -2934
  56. reflex/components/el/elements/inline.py +4 -4
  57. reflex/components/el/elements/inline.pyi +5191 -5953
  58. reflex/components/el/elements/media.py +47 -47
  59. reflex/components/el/elements/media.pyi +4802 -5500
  60. reflex/components/el/elements/metadata.py +1 -3
  61. reflex/components/el/elements/metadata.pyi +782 -896
  62. reflex/components/el/elements/other.pyi +1278 -1467
  63. reflex/components/el/elements/scripts.pyi +580 -667
  64. reflex/components/el/elements/sectioning.pyi +2761 -3166
  65. reflex/components/el/elements/tables.pyi +1840 -2119
  66. reflex/components/el/elements/typography.pyi +2772 -3179
  67. reflex/components/gridjs/datatable.py +7 -7
  68. reflex/components/gridjs/datatable.pyi +19 -19
  69. reflex/components/lucide/icon.pyi +21 -21
  70. reflex/components/markdown/markdown.py +2 -2
  71. reflex/components/markdown/markdown.pyi +9 -9
  72. reflex/components/moment/moment.py +11 -12
  73. reflex/components/moment/moment.pyi +44 -47
  74. reflex/components/next/base.pyi +7 -7
  75. reflex/components/next/image.py +3 -3
  76. reflex/components/next/image.pyi +19 -21
  77. reflex/components/next/link.pyi +9 -9
  78. reflex/components/next/video.py +1 -3
  79. reflex/components/next/video.pyi +9 -9
  80. reflex/components/plotly/plotly.py +22 -45
  81. reflex/components/plotly/plotly.pyi +164 -164
  82. reflex/components/radix/primitives/accordion.py +14 -14
  83. reflex/components/radix/primitives/accordion.pyi +439 -487
  84. reflex/components/radix/primitives/base.py +1 -3
  85. reflex/components/radix/primitives/base.pyi +15 -15
  86. reflex/components/radix/primitives/drawer.py +3 -3
  87. reflex/components/radix/primitives/drawer.pyi +110 -116
  88. reflex/components/radix/primitives/form.py +1 -1
  89. reflex/components/radix/primitives/form.pyi +668 -752
  90. reflex/components/radix/primitives/progress.py +6 -6
  91. reflex/components/radix/primitives/progress.pyi +225 -243
  92. reflex/components/radix/primitives/slider.py +6 -6
  93. reflex/components/radix/primitives/slider.pyi +52 -55
  94. reflex/components/radix/themes/base.py +3 -6
  95. reflex/components/radix/themes/base.pyi +197 -303
  96. reflex/components/radix/themes/color_mode.py +5 -5
  97. reflex/components/radix/themes/color_mode.pyi +366 -436
  98. reflex/components/radix/themes/components/alert_dialog.pyi +229 -262
  99. reflex/components/radix/themes/components/aspect_ratio.py +1 -3
  100. reflex/components/radix/themes/components/aspect_ratio.pyi +8 -8
  101. reflex/components/radix/themes/components/avatar.pyi +79 -94
  102. reflex/components/radix/themes/components/badge.pyi +252 -295
  103. reflex/components/radix/themes/components/button.pyi +269 -314
  104. reflex/components/radix/themes/components/callout.py +2 -2
  105. reflex/components/radix/themes/components/callout.pyi +1116 -1290
  106. reflex/components/radix/themes/components/card.pyi +194 -229
  107. reflex/components/radix/themes/components/checkbox.pyi +243 -278
  108. reflex/components/radix/themes/components/checkbox_cards.py +3 -7
  109. reflex/components/radix/themes/components/checkbox_cards.pyi +101 -135
  110. reflex/components/radix/themes/components/checkbox_group.py +2 -2
  111. reflex/components/radix/themes/components/checkbox_group.pyi +83 -96
  112. reflex/components/radix/themes/components/context_menu.py +18 -15
  113. reflex/components/radix/themes/components/context_menu.pyi +408 -458
  114. reflex/components/radix/themes/components/data_list.pyi +122 -147
  115. reflex/components/radix/themes/components/dialog.pyi +231 -264
  116. reflex/components/radix/themes/components/dropdown_menu.py +16 -13
  117. reflex/components/radix/themes/components/dropdown_menu.pyi +223 -246
  118. reflex/components/radix/themes/components/hover_card.py +2 -2
  119. reflex/components/radix/themes/components/hover_card.pyi +237 -282
  120. reflex/components/radix/themes/components/icon_button.pyi +269 -314
  121. reflex/components/radix/themes/components/inset.py +8 -8
  122. reflex/components/radix/themes/components/inset.pyi +232 -292
  123. reflex/components/radix/themes/components/popover.py +2 -2
  124. reflex/components/radix/themes/components/popover.pyi +229 -271
  125. reflex/components/radix/themes/components/progress.pyi +80 -96
  126. reflex/components/radix/themes/components/radio.pyi +73 -86
  127. reflex/components/radix/themes/components/radio_cards.py +4 -8
  128. reflex/components/radix/themes/components/radio_cards.pyi +117 -154
  129. reflex/components/radix/themes/components/radio_group.py +3 -3
  130. reflex/components/radix/themes/components/radio_group.pyi +250 -291
  131. reflex/components/radix/themes/components/scroll_area.pyi +14 -20
  132. reflex/components/radix/themes/components/segmented_control.py +6 -6
  133. reflex/components/radix/themes/components/segmented_control.pyi +89 -108
  134. reflex/components/radix/themes/components/select.py +7 -7
  135. reflex/components/radix/themes/components/select.pyi +376 -444
  136. reflex/components/radix/themes/components/separator.pyi +79 -93
  137. reflex/components/radix/themes/components/skeleton.pyi +32 -26
  138. reflex/components/radix/themes/components/slider.py +8 -8
  139. reflex/components/radix/themes/components/slider.pyi +99 -122
  140. reflex/components/radix/themes/components/spinner.pyi +12 -19
  141. reflex/components/radix/themes/components/switch.pyi +84 -99
  142. reflex/components/radix/themes/components/table.py +9 -9
  143. reflex/components/radix/themes/components/table.pyi +1440 -1794
  144. reflex/components/radix/themes/components/tabs.py +4 -4
  145. reflex/components/radix/themes/components/tabs.pyi +120 -132
  146. reflex/components/radix/themes/components/text_area.pyi +281 -331
  147. reflex/components/radix/themes/components/text_field.py +2 -2
  148. reflex/components/radix/themes/components/text_field.pyi +639 -734
  149. reflex/components/radix/themes/components/tooltip.py +6 -6
  150. reflex/components/radix/themes/components/tooltip.pyi +34 -43
  151. reflex/components/radix/themes/layout/base.pyi +85 -182
  152. reflex/components/radix/themes/layout/box.pyi +183 -210
  153. reflex/components/radix/themes/layout/center.pyi +225 -286
  154. reflex/components/radix/themes/layout/container.pyi +191 -224
  155. reflex/components/radix/themes/layout/flex.py +2 -2
  156. reflex/components/radix/themes/layout/flex.pyi +225 -286
  157. reflex/components/radix/themes/layout/grid.py +2 -2
  158. reflex/components/radix/themes/layout/grid.pyi +245 -315
  159. reflex/components/radix/themes/layout/list.py +2 -2
  160. reflex/components/radix/themes/layout/list.pyi +712 -815
  161. reflex/components/radix/themes/layout/section.pyi +187 -221
  162. reflex/components/radix/themes/layout/spacer.pyi +225 -286
  163. reflex/components/radix/themes/layout/stack.pyi +625 -768
  164. reflex/components/radix/themes/typography/blockquote.pyi +257 -299
  165. reflex/components/radix/themes/typography/code.pyi +259 -304
  166. reflex/components/radix/themes/typography/heading.pyi +272 -324
  167. reflex/components/radix/themes/typography/link.pyi +302 -358
  168. reflex/components/radix/themes/typography/text.pyi +1669 -1945
  169. reflex/components/react_player/audio.pyi +20 -22
  170. reflex/components/react_player/react_player.pyi +19 -19
  171. reflex/components/react_player/video.pyi +20 -22
  172. reflex/components/recharts/cartesian.py +100 -97
  173. reflex/components/recharts/cartesian.pyi +891 -1007
  174. reflex/components/recharts/charts.py +42 -42
  175. reflex/components/recharts/charts.pyi +212 -249
  176. reflex/components/recharts/general.py +22 -21
  177. reflex/components/recharts/general.pyi +198 -223
  178. reflex/components/recharts/polar.py +42 -45
  179. reflex/components/recharts/polar.pyi +254 -288
  180. reflex/components/recharts/recharts.pyi +13 -13
  181. reflex/components/sonner/toast.py +20 -20
  182. reflex/components/sonner/toast.pyi +58 -61
  183. reflex/components/suneditor/editor.py +9 -9
  184. reflex/components/suneditor/editor.pyi +78 -83
  185. reflex/components/tags/cond_tag.py +2 -2
  186. reflex/components/tags/iter_tag.py +10 -14
  187. reflex/components/tags/match_tag.py +2 -2
  188. reflex/components/tags/tag.py +10 -10
  189. reflex/config.py +36 -35
  190. reflex/constants/__init__.py +56 -53
  191. reflex/custom_components/custom_components.py +6 -7
  192. reflex/event.py +38 -42
  193. reflex/experimental/client_state.py +2 -4
  194. reflex/experimental/layout.py +2 -2
  195. reflex/experimental/layout.pyi +579 -663
  196. reflex/istate/data.py +4 -5
  197. reflex/middleware/hydrate_middleware.py +2 -2
  198. reflex/middleware/middleware.py +2 -2
  199. reflex/model.py +3 -5
  200. reflex/page.py +2 -2
  201. reflex/reflex.py +9 -10
  202. reflex/state.py +77 -49
  203. reflex/style.py +9 -3
  204. reflex/testing.py +21 -24
  205. reflex/utils/console.py +1 -1
  206. reflex/utils/decorator.py +26 -1
  207. reflex/utils/exec.py +6 -11
  208. reflex/utils/export.py +2 -3
  209. reflex/utils/format.py +4 -4
  210. reflex/utils/imports.py +12 -12
  211. reflex/utils/prerequisites.py +35 -84
  212. reflex/utils/processes.py +5 -5
  213. reflex/utils/pyi_generator.py +33 -22
  214. reflex/utils/serializers.py +60 -15
  215. reflex/utils/types.py +237 -56
  216. reflex/vars/base.py +122 -72
  217. reflex/vars/datetime.py +2 -2
  218. reflex/vars/function.py +52 -55
  219. reflex/vars/number.py +59 -5
  220. reflex/vars/object.py +57 -26
  221. reflex/vars/sequence.py +983 -958
  222. {reflex-0.7.1a4.dist-info → reflex-0.7.2a2.dist-info}/METADATA +3 -6
  223. reflex-0.7.2a2.dist-info/RECORD +405 -0
  224. {reflex-0.7.1a4.dist-info → reflex-0.7.2a2.dist-info}/WHEEL +1 -1
  225. reflex-0.7.1a4.dist-info/RECORD +0 -405
  226. {reflex-0.7.1a4.dist-info → reflex-0.7.2a2.dist-info}/LICENSE +0 -0
  227. {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: Optional[dict] = None):
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: Optional[dict] = None):
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: Optional[dict] = None):
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: Optional[dict] = None):
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, Optional
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
- ) -> Optional[StateUpdate]:
23
+ ) -> StateUpdate | None:
24
24
  """Preprocess the event.
25
25
 
26
26
  Args:
@@ -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, Optional
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
- ) -> Optional[StateUpdate]:
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, Optional, Type, Union
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 = Union[
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: Optional[int] = sqlmodel.Field(default=None, primary_key=True)
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, Dict, List
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: Dict[str, List] = defaultdict(list)
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: List[str] = typer.Option(
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: List[str] = typer.Option(
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: Optional[str] = typer.Option(
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: Optional[str] = typer.Option(
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: Optional[str] = typer.Option(
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: Optional[str] = typer.Option(
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: Optional[str] = typer.Option(
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: Optional[str] = typer.Option(
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: Optional[str] = typer.Option(
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 = Dict[str, Any]
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: Set[str] = set()
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
- def _unwrap_field_type(type_: Type) -> Type:
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.outer_type_),
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[Set[Type[BaseState]]] = set()
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, Set[Tuple[str, 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[Set[str]] = set()
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[Set[str]] = set()
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[Set[str]] = set()
373
+ _potentially_dirty_states: ClassVar[set[str]] = set()
371
374
 
372
375
  # The parent state.
373
- parent_state: Optional[BaseState] = None
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: Set[str] = set()
382
+ dirty_vars: set[str] = set()
380
383
 
381
384
  # The set of dirty substates.
382
- dirty_substates: Set[str] = set()
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) -> List[Type]:
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) -> List[str]:
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.outer_type_)
1357
- if field.allow_none and not is_optional(field_type):
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 (not using `self`)"
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
- Union[List[Union[EventSpec, EventHandler]], None],
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: Dict[str, Any] = {
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
- ) -> Tuple[str, str, Any, Union[bool, None], Any]:
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[Union[EventSpec, EventHandler]], load_events),
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: List[Event] = dataclasses.field(default_factory=list)
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: Dict[str, BaseState] = {}
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: Dict[str, asyncio.Lock] = pydantic.PrivateAttr({})
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: Dict[str, BaseState] = {}
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: Dict[str, asyncio.Lock] = pydantic.PrivateAttr({})
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: Set[bytes] = {
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 _wait_lock(self, lock_key: bytes, lock_id: bytes) -> None:
3557
- """Wait for a redis lock to be released via pubsub.
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
- lock_key_channel = f"__keyspace@0__:{lock_key.decode()}"
3569
- # Enable keyspace notifications for the lock key, so we know when it is available.
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__: Dict[type, type] = {}
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, Tuple, Type
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) -> Tuple[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
- style_dict, self._var_data = convert(style_dict or {})
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):