reflex 0.8.8a1__py3-none-any.whl → 0.8.9__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 (38) hide show
  1. reflex/.templates/web/utils/state.js +5 -5
  2. reflex/app.py +17 -7
  3. reflex/compiler/compiler.py +2 -2
  4. reflex/compiler/templates.py +23 -7
  5. reflex/compiler/utils.py +8 -5
  6. reflex/components/component.py +69 -80
  7. reflex/components/core/sticky.pyi +3 -0
  8. reflex/components/el/elements/media.py +518 -0
  9. reflex/components/el/elements/media.pyi +5869 -5
  10. reflex/components/lucide/icon.py +4 -1
  11. reflex/components/lucide/icon.pyi +4 -1
  12. reflex/components/radix/primitives/drawer.py +9 -21
  13. reflex/components/radix/primitives/drawer.pyi +4 -0
  14. reflex/config.py +34 -7
  15. reflex/constants/compiler.py +1 -1
  16. reflex/constants/installer.py +4 -4
  17. reflex/environment.py +8 -3
  18. reflex/event.py +1 -1
  19. reflex/istate/data.py +15 -0
  20. reflex/plugins/sitemap.py +3 -6
  21. reflex/reflex.py +8 -2
  22. reflex/state.py +46 -6
  23. reflex/testing.py +1 -1
  24. reflex/utils/console.py +67 -7
  25. reflex/utils/format.py +1 -1
  26. reflex/utils/frontend_skeleton.py +6 -1
  27. reflex/utils/imports.py +1 -1
  28. reflex/utils/prerequisites.py +3 -1
  29. reflex/utils/pyi_generator.py +2 -2
  30. reflex/utils/serializers.py +4 -4
  31. reflex/utils/types.py +11 -10
  32. reflex/vars/base.py +24 -17
  33. reflex/vars/object.py +4 -2
  34. {reflex-0.8.8a1.dist-info → reflex-0.8.9.dist-info}/METADATA +1 -1
  35. {reflex-0.8.8a1.dist-info → reflex-0.8.9.dist-info}/RECORD +38 -38
  36. {reflex-0.8.8a1.dist-info → reflex-0.8.9.dist-info}/WHEEL +0 -0
  37. {reflex-0.8.8a1.dist-info → reflex-0.8.9.dist-info}/entry_points.txt +0 -0
  38. {reflex-0.8.8a1.dist-info → reflex-0.8.9.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,7 @@ from reflex.utils.imports import ImportVar
6
6
  from reflex.vars.base import LiteralVar, Var
7
7
  from reflex.vars.sequence import LiteralStringVar, StringVar
8
8
 
9
- LUCIDE_LIBRARY = "lucide-react@0.540.0"
9
+ LUCIDE_LIBRARY = "lucide-react@0.541.0"
10
10
 
11
11
 
12
12
  class LucideIconComponent(Component):
@@ -453,6 +453,7 @@ LUCIDE_ICON_LIST = [
453
453
  "chevrons_up_down",
454
454
  "chevrons_up",
455
455
  "chrome",
456
+ "chromium",
456
457
  "church",
457
458
  "cigarette_off",
458
459
  "cigarette",
@@ -1198,11 +1199,13 @@ LUCIDE_ICON_LIST = [
1198
1199
  "panel_left_close",
1199
1200
  "panel_left_dashed",
1200
1201
  "panel_left_open",
1202
+ "panel_left_right_dashed",
1201
1203
  "panel_left",
1202
1204
  "panel_right_close",
1203
1205
  "panel_right_dashed",
1204
1206
  "panel_right_open",
1205
1207
  "panel_right",
1208
+ "panel_top_bottom_dashed",
1206
1209
  "panel_top_close",
1207
1210
  "panel_top_dashed",
1208
1211
  "panel_top_open",
@@ -11,7 +11,7 @@ from reflex.components.core.breakpoints import Breakpoints
11
11
  from reflex.event import EventType, PointerEventInfo
12
12
  from reflex.vars.base import Var
13
13
 
14
- LUCIDE_LIBRARY = "lucide-react@0.540.0"
14
+ LUCIDE_LIBRARY = "lucide-react@0.541.0"
15
15
 
16
16
  class LucideIconComponent(Component):
17
17
  @classmethod
@@ -518,6 +518,7 @@ LUCIDE_ICON_LIST = [
518
518
  "chevrons_up_down",
519
519
  "chevrons_up",
520
520
  "chrome",
521
+ "chromium",
521
522
  "church",
522
523
  "cigarette_off",
523
524
  "cigarette",
@@ -1263,11 +1264,13 @@ LUCIDE_ICON_LIST = [
1263
1264
  "panel_left_close",
1264
1265
  "panel_left_dashed",
1265
1266
  "panel_left_open",
1267
+ "panel_left_right_dashed",
1266
1268
  "panel_left",
1267
1269
  "panel_right_close",
1268
1270
  "panel_right_dashed",
1269
1271
  "panel_right_open",
1270
1272
  "panel_right",
1273
+ "panel_top_bottom_dashed",
1271
1274
  "panel_top_close",
1272
1275
  "panel_top_dashed",
1273
1276
  "panel_top_open",
@@ -124,13 +124,13 @@ class DrawerContent(DrawerComponent):
124
124
  alias = "Vaul" + tag
125
125
 
126
126
  # Style set partially based on the source code at https://ui.shadcn.com/docs/components/drawer
127
- def _get_style(self) -> dict:
127
+ def add_style(self) -> dict:
128
128
  """Get the style for the component.
129
129
 
130
130
  Returns:
131
131
  The dictionary of the component style as value and the style notation as key.
132
132
  """
133
- base_style = {
133
+ return {
134
134
  "left": "0",
135
135
  "right": "0",
136
136
  "bottom": "0",
@@ -139,9 +139,6 @@ class DrawerContent(DrawerComponent):
139
139
  "z_index": 50,
140
140
  "display": "flex",
141
141
  }
142
- style = self.style or {}
143
- base_style.update(style)
144
- return {"css": base_style}
145
142
 
146
143
  # Fired when the drawer content is opened.
147
144
  on_open_auto_focus: EventHandler[no_args_event_spec]
@@ -186,13 +183,13 @@ class DrawerOverlay(DrawerComponent):
186
183
  alias = "Vaul" + tag
187
184
 
188
185
  # Style set based on the source code at https://ui.shadcn.com/docs/components/drawer
189
- def _get_style(self) -> dict:
186
+ def add_style(self) -> dict:
190
187
  """Get the style for the component.
191
188
 
192
189
  Returns:
193
190
  The dictionary of the component style as value and the style notation as key.
194
191
  """
195
- base_style = {
192
+ return {
196
193
  "position": "fixed",
197
194
  "left": "0",
198
195
  "right": "0",
@@ -201,9 +198,6 @@ class DrawerOverlay(DrawerComponent):
201
198
  "z_index": 50,
202
199
  "background": "rgba(0, 0, 0, 0.5)",
203
200
  }
204
- style = self.style or {}
205
- base_style.update(style)
206
- return {"css": base_style}
207
201
 
208
202
 
209
203
  class DrawerClose(DrawerTrigger):
@@ -222,21 +216,18 @@ class DrawerTitle(DrawerComponent):
222
216
  alias = "Vaul" + tag
223
217
 
224
218
  # Style set based on the source code at https://ui.shadcn.com/docs/components/drawer
225
- def _get_style(self) -> dict:
219
+ def add_style(self) -> dict:
226
220
  """Get the style for the component.
227
221
 
228
222
  Returns:
229
223
  The dictionary of the component style as value and the style notation as key.
230
224
  """
231
- base_style = {
225
+ return {
232
226
  "font-size": "1.125rem",
233
227
  "font-weight": "600",
234
- "line-weight": "1",
228
+ "line-height": "1",
235
229
  "letter-spacing": "-0.05em",
236
230
  }
237
- style = self.style or {}
238
- base_style.update(style)
239
- return {"css": base_style}
240
231
 
241
232
 
242
233
  class DrawerDescription(DrawerComponent):
@@ -247,18 +238,15 @@ class DrawerDescription(DrawerComponent):
247
238
  alias = "Vaul" + tag
248
239
 
249
240
  # Style set based on the source code at https://ui.shadcn.com/docs/components/drawer
250
- def _get_style(self) -> dict:
241
+ def add_style(self) -> dict:
251
242
  """Get the style for the component.
252
243
 
253
244
  Returns:
254
245
  The dictionary of the component style as value and the style notation as key.
255
246
  """
256
- base_style = {
247
+ return {
257
248
  "font-size": "0.875rem",
258
249
  }
259
- style = self.style or {}
260
- base_style.update(style)
261
- return {"css": base_style}
262
250
 
263
251
 
264
252
  class DrawerHandle(DrawerComponent):
@@ -249,6 +249,7 @@ class DrawerPortal(DrawerComponent):
249
249
  """
250
250
 
251
251
  class DrawerContent(DrawerComponent):
252
+ def add_style(self) -> dict: ...
252
253
  @classmethod
253
254
  def create(
254
255
  cls,
@@ -309,6 +310,7 @@ class DrawerContent(DrawerComponent):
309
310
  """
310
311
 
311
312
  class DrawerOverlay(DrawerComponent):
313
+ def add_style(self) -> dict: ...
312
314
  @classmethod
313
315
  def create(
314
316
  cls,
@@ -411,6 +413,7 @@ class DrawerClose(DrawerTrigger):
411
413
  """
412
414
 
413
415
  class DrawerTitle(DrawerComponent):
416
+ def add_style(self) -> dict: ...
414
417
  @classmethod
415
418
  def create(
416
419
  cls,
@@ -462,6 +465,7 @@ class DrawerTitle(DrawerComponent):
462
465
  """
463
466
 
464
467
  class DrawerDescription(DrawerComponent):
468
+ def add_style(self) -> dict: ...
465
469
  @classmethod
466
470
  def create(
467
471
  cls,
reflex/config.py CHANGED
@@ -237,7 +237,7 @@ class BaseConfig:
237
237
  env_file: str | None = None
238
238
 
239
239
  # Whether to automatically create setters for state base vars
240
- state_auto_setters: bool = True
240
+ state_auto_setters: bool | None = None
241
241
 
242
242
  # Whether to display the sticky "Built with Reflex" badge on all pages.
243
243
  show_built_with_reflex: bool | None = None
@@ -267,9 +267,12 @@ _PLUGINS_ENABLED_BY_DEFAULT = [
267
267
 
268
268
  @dataclasses.dataclass(kw_only=True, init=False)
269
269
  class Config(BaseConfig):
270
- """The config defines runtime settings for the app.
270
+ """Configuration class for Reflex applications.
271
271
 
272
- By default, the config is defined in an `rxconfig.py` file in the root of the app.
272
+ The config defines runtime settings for your app including server ports, database connections,
273
+ frontend packages, and deployment settings.
274
+
275
+ By default, the config is defined in an `rxconfig.py` file in the root of your app:
273
276
 
274
277
  ```python
275
278
  # rxconfig.py
@@ -277,14 +280,38 @@ class Config(BaseConfig):
277
280
 
278
281
  config = rx.Config(
279
282
  app_name="myapp",
280
- api_url="http://localhost:8000",
283
+ # Server configuration
284
+ frontend_port=3000,
285
+ backend_port=8000,
286
+ # Database
287
+ db_url="postgresql://user:pass@localhost:5432/mydb",
288
+ # Additional frontend packages
289
+ frontend_packages=["react-icons"],
290
+ # CORS settings for production
291
+ cors_allowed_origins=["https://mydomain.com"],
281
292
  )
282
293
  ```
283
294
 
284
- Every config value can be overridden by an environment variable with the same name in uppercase and a REFLEX_ prefix.
285
- For example, `db_url` can be overridden by setting the `REFLEX_DB_URL` environment variable.
295
+ ## Environment Variable Overrides
296
+
297
+ Any config value can be overridden by setting an environment variable with the `REFLEX_`
298
+ prefix and the parameter name in uppercase:
299
+
300
+ ```bash
301
+ REFLEX_DB_URL="postgresql://user:pass@localhost/db" reflex run
302
+ REFLEX_FRONTEND_PORT=3001 reflex run
303
+ ```
304
+
305
+ ## Key Configuration Areas
306
+
307
+ - **App Settings**: `app_name`, `loglevel`, `telemetry_enabled`
308
+ - **Server**: `frontend_port`, `backend_port`, `api_url`, `cors_allowed_origins`
309
+ - **Database**: `db_url`, `async_db_url`, `redis_url`
310
+ - **Frontend**: `frontend_packages`, `react_strict_mode`
311
+ - **State Management**: `state_manager_mode`, `state_auto_setters`
312
+ - **Plugins**: `plugins`, `disable_plugins`
286
313
 
287
- See the [configuration](https://reflex.dev/docs/getting-started/configuration/) docs for more info.
314
+ See the [configuration docs](https://reflex.dev/docs/advanced-onboarding/configuration) for complete details on all available options.
288
315
  """
289
316
 
290
317
  # Track whether the app name has already been validated for this Config instance.
@@ -64,7 +64,7 @@ class CompileVars(SimpleNamespace):
64
64
  # The name of the var storing any connection error.
65
65
  CONNECT_ERROR = "connectErrors"
66
66
  # The name of the function for converting a dict to an event.
67
- TO_EVENT = "Event"
67
+ TO_EVENT = "ReflexEvent"
68
68
  # The name of the internal on_load event.
69
69
  ON_LOAD_INTERNAL = "reflex___state____on_load_internal_state.on_load_internal"
70
70
  # The name of the internal event to update generic state vars.
@@ -14,7 +14,7 @@ class Bun(SimpleNamespace):
14
14
  """Bun constants."""
15
15
 
16
16
  # The Bun version.
17
- VERSION = "1.2.20"
17
+ VERSION = "1.2.21"
18
18
 
19
19
  # Min Bun Version
20
20
  MIN_VERSION = "1.2.17"
@@ -75,7 +75,7 @@ fetch-retries=0
75
75
 
76
76
 
77
77
  def _determine_react_router_version() -> str:
78
- default_version = "7.8.1"
78
+ default_version = "7.8.2"
79
79
  if (version := os.getenv("REACT_ROUTER_VERSION")) and version != default_version:
80
80
  from reflex.utils import console
81
81
 
@@ -143,11 +143,11 @@ class PackageJson(SimpleNamespace):
143
143
  "postcss-import": "16.1.1",
144
144
  "@react-router/dev": _react_router_version,
145
145
  "@react-router/fs-routes": _react_router_version,
146
- "vite": "npm:rolldown-vite@7.1.3",
146
+ "vite": "npm:rolldown-vite@7.1.5",
147
147
  }
148
148
  OVERRIDES = {
149
149
  # This should always match the `react` version in DEPENDENCIES for recharts compatibility.
150
150
  "react-is": _react_version,
151
151
  "cookie": "1.0.2",
152
- "vite": "npm:rolldown-vite@7.1.3",
152
+ "vite": "npm:rolldown-vite@7.1.5",
153
153
  }
reflex/environment.py CHANGED
@@ -6,7 +6,6 @@ import concurrent.futures
6
6
  import dataclasses
7
7
  import enum
8
8
  import importlib
9
- import inspect
10
9
  import multiprocessing
11
10
  import os
12
11
  import platform
@@ -159,7 +158,7 @@ def interpret_plugin_env(value: str, field_name: str) -> Plugin:
159
158
  msg = f"Failed to get plugin class {plugin_name!r} from module {import_path!r} for {field_name}: {e}"
160
159
  raise EnvironmentVarValueError(msg) from e
161
160
 
162
- if not inspect.isclass(plugin_class) or not issubclass(plugin_class, Plugin):
161
+ if not isinstance(plugin_class, type) or not issubclass(plugin_class, Plugin):
163
162
  msg = f"Invalid plugin class: {plugin_name!r} for {field_name}. Must be a subclass of Plugin."
164
163
  raise EnvironmentVarValueError(msg)
165
164
 
@@ -236,7 +235,7 @@ def interpret_env_var_value(
236
235
  )
237
236
  for i, v in enumerate(value.split(":"))
238
237
  ]
239
- if inspect.isclass(field_type) and issubclass(field_type, enum.Enum):
238
+ if isinstance(field_type, type) and issubclass(field_type, enum.Enum):
240
239
  return interpret_enum_env(value, field_type, field_name)
241
240
 
242
241
  msg = f"Invalid type for environment variable {field_name}: {field_type}. This is probably an issue in Reflex."
@@ -640,6 +639,12 @@ class EnvironmentVariables:
640
639
  # Enable full logging of debug messages to reflex user directory.
641
640
  REFLEX_ENABLE_FULL_LOGGING: EnvVar[bool] = env_var(False)
642
641
 
642
+ # Whether to enable hot module replacement
643
+ VITE_HMR: EnvVar[bool] = env_var(True)
644
+
645
+ # Whether to force a full reload on changes.
646
+ VITE_FORCE_FULL_RELOAD: EnvVar[bool] = env_var(False)
647
+
643
648
 
644
649
  environment = EnvironmentVariables()
645
650
 
reflex/event.py CHANGED
@@ -1930,7 +1930,7 @@ class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
1930
1930
  _var_type=EventSpec,
1931
1931
  _var_data=_var_data,
1932
1932
  _var_value=value,
1933
- _func=FunctionStringVar("Event"),
1933
+ _func=FunctionStringVar("ReflexEvent"),
1934
1934
  _args=(
1935
1935
  # event handler name
1936
1936
  ".".join(
reflex/istate/data.py CHANGED
@@ -83,6 +83,11 @@ class HeaderData(_HeaderData):
83
83
  )
84
84
 
85
85
 
86
+ @serializer(to=dict)
87
+ def _serialize_header_data(obj: HeaderData) -> dict:
88
+ return {k.name: getattr(obj, k.name) for k in dataclasses.fields(obj)}
89
+
90
+
86
91
  @serializer(to=dict)
87
92
  def serialize_frozen_dict_str_str(obj: _FrozenDictStrStr) -> dict:
88
93
  """Serialize a _FrozenDictStrStr object to a dict.
@@ -165,6 +170,11 @@ class PageData:
165
170
  )
166
171
 
167
172
 
173
+ @serializer(to=dict)
174
+ def _serialize_page_data(obj: PageData) -> dict:
175
+ return dataclasses.asdict(obj)
176
+
177
+
168
178
  @dataclasses.dataclass(frozen=True)
169
179
  class SessionData:
170
180
  """An object containing session data."""
@@ -190,6 +200,11 @@ class SessionData:
190
200
  )
191
201
 
192
202
 
203
+ @serializer(to=dict)
204
+ def _serialize_session_data(obj: SessionData) -> dict:
205
+ return dataclasses.asdict(obj)
206
+
207
+
193
208
  @dataclasses.dataclass(frozen=True)
194
209
  class RouterData:
195
210
  """An object containing RouterData."""
reflex/plugins/sitemap.py CHANGED
@@ -5,8 +5,7 @@ from collections.abc import Sequence
5
5
  from pathlib import Path
6
6
  from types import SimpleNamespace
7
7
  from typing import TYPE_CHECKING, Literal, TypedDict
8
- from xml.dom import minidom
9
- from xml.etree.ElementTree import Element, SubElement, tostring
8
+ from xml.etree.ElementTree import Element, SubElement, indent, tostring
10
9
 
11
10
  from typing_extensions import NotRequired
12
11
 
@@ -104,10 +103,8 @@ def generate_xml(links: Sequence[SitemapLink]) -> str:
104
103
  if (priority := link.get("priority")) is not None:
105
104
  priority_element = SubElement(url, "priority")
106
105
  priority_element.text = str(priority)
107
-
108
- rough_string = tostring(urlset, "utf-8")
109
- reparsed = minidom.parseString(rough_string)
110
- return reparsed.toprettyxml(indent=" ")
106
+ indent(urlset, " ")
107
+ return tostring(urlset, encoding="utf-8", xml_declaration=True).decode("utf-8")
111
108
 
112
109
 
113
110
  def is_route_dynamic(route: str) -> bool:
reflex/reflex.py CHANGED
@@ -360,7 +360,13 @@ def run(
360
360
  default=False,
361
361
  help="Run the command without making any changes.",
362
362
  )
363
- def compile(dry: bool):
363
+ @click.option(
364
+ "--rich/--no-rich",
365
+ default=True,
366
+ is_flag=True,
367
+ help="Whether to use rich progress bars.",
368
+ )
369
+ def compile(dry: bool, rich: bool):
364
370
  """Compile the app in the current directory."""
365
371
  import time
366
372
 
@@ -371,7 +377,7 @@ def compile(dry: bool):
371
377
  _init(name=get_config().app_name)
372
378
  get_config(reload=True)
373
379
  starting_time = time.monotonic()
374
- prerequisites.get_compiled_app(dry_run=dry)
380
+ prerequisites.get_compiled_app(dry_run=dry, use_rich=rich)
375
381
  elapsed_time = time.monotonic() - starting_time
376
382
  console.success(f"App compiled successfully in {elapsed_time:.3f} seconds.")
377
383
 
reflex/state.py CHANGED
@@ -225,8 +225,20 @@ class EventHandlerSetVar(EventHandler):
225
225
  EventHandlerValueError: If the given Var name is not a str
226
226
  NotImplementedError: If the setter for the given Var is async
227
227
  """
228
+ from reflex.config import get_config
228
229
  from reflex.utils.exceptions import EventHandlerValueError
229
230
 
231
+ config = get_config()
232
+ if config.state_auto_setters is None:
233
+ console.deprecate(
234
+ feature_name="state_auto_setters defaulting to True",
235
+ reason="The default value will be changed to False in a future release. Set state_auto_setters explicitly or define setters explicitly. "
236
+ f"Used {self.state_cls.__name__}.setvar without defining it.",
237
+ deprecation_version="0.8.9",
238
+ removal_version="0.9.0",
239
+ dedupe=True,
240
+ )
241
+
230
242
  if args:
231
243
  if not isinstance(args[0], str):
232
244
  msg = f"Var name must be passed as a string, got {args[0]!r}"
@@ -1036,7 +1048,7 @@ class BaseState(EvenMoreBasicBaseState):
1036
1048
  )
1037
1049
  raise VarTypeError(msg)
1038
1050
  cls._set_var(name, prop)
1039
- if cls.is_user_defined() and get_config().state_auto_setters:
1051
+ if cls.is_user_defined() and get_config().state_auto_setters is not False:
1040
1052
  cls._create_setter(name, prop)
1041
1053
  cls._set_default_value(name, prop)
1042
1054
 
@@ -1096,11 +1108,14 @@ class BaseState(EvenMoreBasicBaseState):
1096
1108
  setattr(cls, name, prop)
1097
1109
 
1098
1110
  @classmethod
1099
- def _create_event_handler(cls, fn: Any):
1111
+ def _create_event_handler(
1112
+ cls, fn: Any, event_handler_cls: type[EventHandler] = EventHandler
1113
+ ):
1100
1114
  """Create an event handler for the given function.
1101
1115
 
1102
1116
  Args:
1103
1117
  fn: The function to create an event handler for.
1118
+ event_handler_cls: The event handler class to use.
1104
1119
 
1105
1120
  Returns:
1106
1121
  The event handler.
@@ -1108,7 +1123,7 @@ class BaseState(EvenMoreBasicBaseState):
1108
1123
  # Check if function has stored event_actions from decorator
1109
1124
  event_actions = getattr(fn, "_rx_event_actions", {})
1110
1125
 
1111
- return EventHandler(
1126
+ return event_handler_cls(
1112
1127
  fn=fn, state_full_name=cls.get_full_name(), event_actions=event_actions
1113
1128
  )
1114
1129
 
@@ -1125,9 +1140,34 @@ class BaseState(EvenMoreBasicBaseState):
1125
1140
  name: The name of the var.
1126
1141
  prop: The var to create a setter for.
1127
1142
  """
1143
+ from reflex.config import get_config
1144
+
1145
+ config = get_config()
1146
+ _create_event_handler_kwargs = {}
1147
+
1148
+ if config.state_auto_setters is None:
1149
+
1150
+ class EventHandlerDeprecatedSetter(EventHandler):
1151
+ def __call__(self, *args, **kwargs):
1152
+ console.deprecate(
1153
+ feature_name="state_auto_setters defaulting to True",
1154
+ reason="The default value will be changed to False in a future release. Set state_auto_setters explicitly or define setters explicitly. "
1155
+ f"Used {setter_name} in {cls.__name__} without defining it.",
1156
+ deprecation_version="0.8.9",
1157
+ removal_version="0.9.0",
1158
+ dedupe=True,
1159
+ )
1160
+ return super().__call__(*args, **kwargs)
1161
+
1162
+ _create_event_handler_kwargs["event_handler_cls"] = (
1163
+ EventHandlerDeprecatedSetter
1164
+ )
1165
+
1128
1166
  setter_name = Var._get_setter_name_for_name(name)
1129
1167
  if setter_name not in cls.__dict__:
1130
- event_handler = cls._create_event_handler(prop._get_setter(name))
1168
+ event_handler = cls._create_event_handler(
1169
+ prop._get_setter(name), **_create_event_handler_kwargs
1170
+ )
1131
1171
  cls.event_handlers[setter_name] = event_handler
1132
1172
  setattr(cls, setter_name, event_handler)
1133
1173
 
@@ -1810,7 +1850,7 @@ class BaseState(EvenMoreBasicBaseState):
1810
1850
  hinted_args = value_inside_optional(hinted_args)
1811
1851
  if (
1812
1852
  isinstance(value, dict)
1813
- and inspect.isclass(hinted_args)
1853
+ and isinstance(hinted_args, type)
1814
1854
  and not types.is_generic_alias(hinted_args) # py3.10
1815
1855
  ):
1816
1856
  if issubclass(hinted_args, Model):
@@ -2341,7 +2381,7 @@ def _serialize_type(type_: Any) -> str:
2341
2381
  Returns:
2342
2382
  The serialized type.
2343
2383
  """
2344
- if not inspect.isclass(type_):
2384
+ if not isinstance(type_, type):
2345
2385
  return f"{type_}"
2346
2386
  return f"{type_.__module__}.{type_.__qualname__}"
2347
2387
 
reflex/testing.py CHANGED
@@ -472,7 +472,7 @@ class AppHarness:
472
472
  Returns:
473
473
  The rendered app global code.
474
474
  """
475
- if not inspect.isclass(value) and not inspect.isfunction(value):
475
+ if not isinstance(value, type) and not inspect.isfunction(value):
476
476
  return f"{key} = {value!r}"
477
477
  return inspect.getsource(value)
478
478
 
reflex/utils/console.py CHANGED
@@ -7,12 +7,13 @@ import datetime
7
7
  import inspect
8
8
  import os
9
9
  import shutil
10
+ import sys
10
11
  import time
11
12
  from pathlib import Path
12
13
  from types import FrameType
13
14
 
14
15
  from rich.console import Console
15
- from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
16
+ from rich.progress import MofNCompleteColumn, Progress, TaskID, TimeElapsedColumn
16
17
  from rich.prompt import Prompt
17
18
 
18
19
  from reflex.constants import LogLevel
@@ -244,23 +245,38 @@ def warn(msg: str, *, dedupe: bool = False, **kwargs):
244
245
  print_to_log_file(f"[orange1]Warning: {msg}[/orange1]", **kwargs)
245
246
 
246
247
 
247
- def _get_first_non_framework_frame() -> FrameType | None:
248
+ @once
249
+ def _exclude_paths_from_frame_info() -> list[Path]:
250
+ import importlib.util
251
+
248
252
  import click
253
+ import granian
254
+ import socketio
249
255
  import typing_extensions
250
256
 
251
257
  import reflex as rx
252
258
 
253
259
  # Exclude utility modules that should never be the source of deprecated reflex usage.
254
- exclude_modules = [click, rx, typing_extensions]
260
+ exclude_modules = [click, rx, typing_extensions, socketio, granian]
261
+ modules_paths = [file for m in exclude_modules if (file := m.__file__)] + [
262
+ spec.origin
263
+ for m in [*sys.builtin_module_names, *sys.stdlib_module_names]
264
+ if (spec := importlib.util.find_spec(m)) and spec.origin
265
+ ]
255
266
  exclude_roots = [
256
267
  p.parent.resolve() if (p := Path(file)).name == "__init__.py" else p.resolve()
257
- for m in exclude_modules
258
- if (file := m.__file__)
268
+ for file in modules_paths
259
269
  ]
260
270
  # Specifically exclude the reflex cli module.
261
271
  if reflex_bin := shutil.which(b"reflex"):
262
272
  exclude_roots.append(Path(reflex_bin.decode()))
263
273
 
274
+ return exclude_roots
275
+
276
+
277
+ def _get_first_non_framework_frame() -> FrameType | None:
278
+ exclude_roots = _exclude_paths_from_frame_info()
279
+
264
280
  frame = inspect.currentframe()
265
281
  while frame := frame and frame.f_back:
266
282
  frame_path = Path(inspect.getfile(frame)).resolve()
@@ -297,13 +313,13 @@ def deprecate(
297
313
  filename = Path(origin_frame.f_code.co_filename)
298
314
  if filename.is_relative_to(Path.cwd()):
299
315
  filename = filename.relative_to(Path.cwd())
300
- loc = f"{filename}:{origin_frame.f_lineno}"
316
+ loc = f" ({filename}:{origin_frame.f_lineno})"
301
317
  dedupe_key = f"{dedupe_key} {loc}"
302
318
 
303
319
  if dedupe_key not in _EMITTED_DEPRECATION_WARNINGS:
304
320
  msg = (
305
321
  f"{feature_name} has been deprecated in version {deprecation_version}. {reason.rstrip('.').lstrip('. ')}. It will be completely "
306
- f"removed in {removal_version}. ({loc})"
322
+ f"removed in {removal_version}.{loc}"
307
323
  )
308
324
  if _LOG_LEVEL <= LogLevel.WARNING:
309
325
  print(f"[yellow]DeprecationWarning: {msg}[/yellow]", **kwargs)
@@ -395,3 +411,47 @@ def timing(msg: str):
395
411
  yield
396
412
  finally:
397
413
  debug(f"[white]\\[timing] {msg}: {time.time() - start:.2f}s[/white]")
414
+
415
+
416
+ class PoorProgress:
417
+ """A poor man's progress bar."""
418
+
419
+ def __init__(self):
420
+ """Initialize the progress bar."""
421
+ super().__init__()
422
+ self.tasks = {}
423
+ self.progress = 0
424
+ self.total = 0
425
+
426
+ def add_task(self, task: str, total: int):
427
+ """Add a task to the progress bar.
428
+
429
+ Args:
430
+ task: The task name.
431
+ total: The total number of steps for the task.
432
+
433
+ Returns:
434
+ The task ID.
435
+ """
436
+ self.total += total
437
+ task_id = TaskID(len(self.tasks))
438
+ self.tasks[task_id] = {"total": total, "current": 0}
439
+ return task_id
440
+
441
+ def advance(self, task: TaskID, advance: int = 1):
442
+ """Advance the progress of a task.
443
+
444
+ Args:
445
+ task: The task ID.
446
+ advance: The number of steps to advance.
447
+ """
448
+ if task in self.tasks:
449
+ self.tasks[task]["current"] += advance
450
+ self.progress += advance
451
+ _console.print(f"Progress: {self.progress}/{self.total}")
452
+
453
+ def start(self):
454
+ """Start the progress bar."""
455
+
456
+ def stop(self):
457
+ """Stop the progress bar."""