reflex 0.8.2a1__py3-none-any.whl → 0.8.3a2__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 (37) hide show
  1. reflex/.templates/web/utils/state.js +7 -2
  2. reflex/__init__.py +1 -0
  3. reflex/__init__.pyi +2 -0
  4. reflex/app.py +8 -11
  5. reflex/compiler/compiler.py +10 -38
  6. reflex/components/base/error_boundary.py +6 -5
  7. reflex/components/core/__init__.py +1 -0
  8. reflex/components/core/__init__.pyi +3 -0
  9. reflex/components/core/window_events.py +104 -0
  10. reflex/components/core/window_events.pyi +84 -0
  11. reflex/components/el/__init__.pyi +4 -0
  12. reflex/components/el/elements/__init__.py +1 -0
  13. reflex/components/el/elements/__init__.pyi +5 -0
  14. reflex/components/el/elements/forms.py +4 -2
  15. reflex/components/el/elements/typography.py +7 -0
  16. reflex/components/el/elements/typography.pyi +246 -0
  17. reflex/components/lucide/icon.py +303 -292
  18. reflex/components/lucide/icon.pyi +303 -292
  19. reflex/components/recharts/recharts.py +2 -2
  20. reflex/components/sonner/toast.py +1 -1
  21. reflex/config.py +3 -3
  22. reflex/constants/installer.py +2 -1
  23. reflex/environment.py +3 -0
  24. reflex/event.py +69 -8
  25. reflex/model.py +55 -0
  26. reflex/reflex.py +33 -0
  27. reflex/state.py +9 -4
  28. reflex/testing.py +180 -288
  29. reflex/utils/console.py +17 -0
  30. reflex/utils/exec.py +22 -5
  31. reflex/utils/processes.py +28 -38
  32. reflex/utils/types.py +1 -1
  33. {reflex-0.8.2a1.dist-info → reflex-0.8.3a2.dist-info}/METADATA +1 -1
  34. {reflex-0.8.2a1.dist-info → reflex-0.8.3a2.dist-info}/RECORD +37 -35
  35. {reflex-0.8.2a1.dist-info → reflex-0.8.3a2.dist-info}/WHEEL +0 -0
  36. {reflex-0.8.2a1.dist-info → reflex-0.8.3a2.dist-info}/entry_points.txt +0 -0
  37. {reflex-0.8.2a1.dist-info → reflex-0.8.3a2.dist-info}/licenses/LICENSE +0 -0
@@ -8,7 +8,7 @@ from reflex.components.component import Component, MemoizationLeaf, NoSSRCompone
8
8
  class Recharts(Component):
9
9
  """A component that wraps a recharts lib."""
10
10
 
11
- library = "recharts@3.0.2"
11
+ library = "recharts@3.1.0"
12
12
 
13
13
  def _get_style(self) -> dict:
14
14
  return {"wrapperStyle": self.style}
@@ -17,7 +17,7 @@ class Recharts(Component):
17
17
  class RechartsCharts(NoSSRComponent, MemoizationLeaf):
18
18
  """A component that wraps a recharts lib."""
19
19
 
20
- library = "recharts@3.0.2"
20
+ library = "recharts@3.1.0"
21
21
 
22
22
 
23
23
  LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]
@@ -171,7 +171,7 @@ class ToastProps(NoExtrasAllowedProps):
171
171
  class Toaster(Component):
172
172
  """A Toaster Component for displaying toast notifications."""
173
173
 
174
- library: str | None = "sonner@2.0.5"
174
+ library: str | None = "sonner@2.0.6"
175
175
 
176
176
  tag = "Toaster"
177
177
 
reflex/config.py CHANGED
@@ -294,14 +294,14 @@ class Config(BaseConfig):
294
294
  if env_loglevel or self.loglevel != LogLevel.DEFAULT:
295
295
  console.set_log_level(env_loglevel or self.loglevel)
296
296
 
297
- # Add builtin plugins if not disabled.
298
- self._add_builtin_plugins()
299
-
300
297
  # Update the config from environment variables.
301
298
  env_kwargs = self.update_from_env()
302
299
  for key, env_value in env_kwargs.items():
303
300
  setattr(self, key, env_value)
304
301
 
302
+ # Add builtin plugins if not disabled.
303
+ self._add_builtin_plugins()
304
+
305
305
  # Update default URLs if ports were set
306
306
  kwargs.update(env_kwargs)
307
307
  self._non_default_attributes = set(kwargs.keys())
@@ -143,10 +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
- "rolldown-vite": "7.0.8",
146
+ "rolldown-vite": "7.0.9",
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
+ "rollup": "4.44.2",
152
153
  }
reflex/environment.py CHANGED
@@ -650,6 +650,9 @@ class EnvironmentVariables:
650
650
  # Enable full logging of debug messages to reflex user directory.
651
651
  REFLEX_ENABLE_FULL_LOGGING: EnvVar[bool] = env_var(False)
652
652
 
653
+ # The path to the reflex errors log file. If not set, no separate error log will be used.
654
+ REFLEX_ERROR_LOG_FILE: EnvVar[Path | None] = env_var(None)
655
+
653
656
 
654
657
  environment = EnvironmentVariables()
655
658
 
reflex/event.py CHANGED
@@ -109,7 +109,7 @@ class EventActionsMixin:
109
109
  """
110
110
  return dataclasses.replace(
111
111
  self,
112
- event_actions={"stopPropagation": True, **self.event_actions},
112
+ event_actions={**self.event_actions, "stopPropagation": True},
113
113
  )
114
114
 
115
115
  @property
@@ -121,7 +121,7 @@ class EventActionsMixin:
121
121
  """
122
122
  return dataclasses.replace(
123
123
  self,
124
- event_actions={"preventDefault": True, **self.event_actions},
124
+ event_actions={**self.event_actions, "preventDefault": True},
125
125
  )
126
126
 
127
127
  def throttle(self, limit_ms: int) -> Self:
@@ -135,7 +135,7 @@ class EventActionsMixin:
135
135
  """
136
136
  return dataclasses.replace(
137
137
  self,
138
- event_actions={"throttle": limit_ms, **self.event_actions},
138
+ event_actions={**self.event_actions, "throttle": limit_ms},
139
139
  )
140
140
 
141
141
  def debounce(self, delay_ms: int) -> Self:
@@ -149,7 +149,7 @@ class EventActionsMixin:
149
149
  """
150
150
  return dataclasses.replace(
151
151
  self,
152
- event_actions={"debounce": delay_ms, **self.event_actions},
152
+ event_actions={**self.event_actions, "debounce": delay_ms},
153
153
  )
154
154
 
155
155
  @property
@@ -161,7 +161,7 @@ class EventActionsMixin:
161
161
  """
162
162
  return dataclasses.replace(
163
163
  self,
164
- event_actions={"temporal": True, **self.event_actions},
164
+ event_actions={**self.event_actions, "temporal": True},
165
165
  )
166
166
 
167
167
 
@@ -1269,7 +1269,7 @@ def call_script(
1269
1269
  Returns:
1270
1270
  EventSpec: An event that will execute the client side javascript.
1271
1271
  """
1272
- callback_kwargs = {}
1272
+ callback_kwargs = {"callback": None}
1273
1273
  if callback is not None:
1274
1274
  callback_kwargs = {
1275
1275
  "callback": str(
@@ -2211,7 +2211,15 @@ class EventNamespace:
2211
2211
 
2212
2212
  @overload
2213
2213
  def __new__(
2214
- cls, func: None = None, *, background: bool | None = None
2214
+ cls,
2215
+ func: None = None,
2216
+ *,
2217
+ background: bool | None = None,
2218
+ stop_propagation: bool | None = None,
2219
+ prevent_default: bool | None = None,
2220
+ throttle: int | None = None,
2221
+ debounce: int | None = None,
2222
+ temporal: bool | None = None,
2215
2223
  ) -> Callable[
2216
2224
  [Callable[[BASE_STATE, Unpack[P]], Any]], EventCallback[Unpack[P]] # pyright: ignore [reportInvalidTypeVarUse]
2217
2225
  ]: ...
@@ -2222,6 +2230,11 @@ class EventNamespace:
2222
2230
  func: Callable[[BASE_STATE, Unpack[P]], Any],
2223
2231
  *,
2224
2232
  background: bool | None = None,
2233
+ stop_propagation: bool | None = None,
2234
+ prevent_default: bool | None = None,
2235
+ throttle: int | None = None,
2236
+ debounce: int | None = None,
2237
+ temporal: bool | None = None,
2225
2238
  ) -> EventCallback[Unpack[P]]: ...
2226
2239
 
2227
2240
  def __new__(
@@ -2229,6 +2242,11 @@ class EventNamespace:
2229
2242
  func: Callable[[BASE_STATE, Unpack[P]], Any] | None = None,
2230
2243
  *,
2231
2244
  background: bool | None = None,
2245
+ stop_propagation: bool | None = None,
2246
+ prevent_default: bool | None = None,
2247
+ throttle: int | None = None,
2248
+ debounce: int | None = None,
2249
+ temporal: bool | None = None,
2232
2250
  ) -> (
2233
2251
  EventCallback[Unpack[P]]
2234
2252
  | Callable[[Callable[[BASE_STATE, Unpack[P]], Any]], EventCallback[Unpack[P]]]
@@ -2238,6 +2256,11 @@ class EventNamespace:
2238
2256
  Args:
2239
2257
  func: The function to wrap.
2240
2258
  background: Whether the event should be run in the background. Defaults to False.
2259
+ stop_propagation: Whether to stop the event from bubbling up the DOM tree.
2260
+ prevent_default: Whether to prevent the default behavior of the event.
2261
+ throttle: Throttle the event handler to limit calls (in milliseconds).
2262
+ debounce: Debounce the event handler to delay calls (in milliseconds).
2263
+ temporal: Whether the event should be dropped when the backend is down.
2241
2264
 
2242
2265
  Raises:
2243
2266
  TypeError: If background is True and the function is not a coroutine or async generator. # noqa: DAR402
@@ -2246,6 +2269,30 @@ class EventNamespace:
2246
2269
  The wrapped function.
2247
2270
  """
2248
2271
 
2272
+ def _build_event_actions():
2273
+ """Build event_actions dict from decorator parameters.
2274
+
2275
+ Returns:
2276
+ Dict of event actions to apply, or empty dict if none specified.
2277
+ """
2278
+ if not any(
2279
+ [stop_propagation, prevent_default, throttle, debounce, temporal]
2280
+ ):
2281
+ return {}
2282
+
2283
+ event_actions = {}
2284
+ if stop_propagation is not None:
2285
+ event_actions["stopPropagation"] = stop_propagation
2286
+ if prevent_default is not None:
2287
+ event_actions["preventDefault"] = prevent_default
2288
+ if throttle is not None:
2289
+ event_actions["throttle"] = throttle
2290
+ if debounce is not None:
2291
+ event_actions["debounce"] = debounce
2292
+ if temporal is not None:
2293
+ event_actions["temporal"] = temporal
2294
+ return event_actions
2295
+
2249
2296
  def wrapper(
2250
2297
  func: Callable[[BASE_STATE, Unpack[P]], T],
2251
2298
  ) -> EventCallback[Unpack[P]]:
@@ -2281,8 +2328,22 @@ class EventNamespace:
2281
2328
  object.__setattr__(func, "__name__", name)
2282
2329
  object.__setattr__(func, "__qualname__", name)
2283
2330
  state_cls._add_event_handler(name, func)
2284
- return getattr(state_cls, name)
2331
+ event_callback = getattr(state_cls, name)
2332
+
2333
+ # Apply decorator event actions
2334
+ event_actions = _build_event_actions()
2335
+ if event_actions:
2336
+ # Create new EventCallback with updated event_actions
2337
+ event_callback = dataclasses.replace(
2338
+ event_callback, event_actions=event_actions
2339
+ )
2340
+
2341
+ return event_callback
2285
2342
 
2343
+ # Store decorator event actions on the function for later processing
2344
+ event_actions = _build_event_actions()
2345
+ if event_actions:
2346
+ func._rx_event_actions = event_actions # pyright: ignore [reportFunctionMemberAccess]
2286
2347
  return func # pyright: ignore [reportReturnType]
2287
2348
 
2288
2349
  if func is not None:
reflex/model.py CHANGED
@@ -19,6 +19,7 @@ import sqlalchemy.exc
19
19
  import sqlalchemy.ext.asyncio
20
20
  import sqlalchemy.orm
21
21
  from alembic.runtime.migration import MigrationContext
22
+ from alembic.script.base import Script
22
23
 
23
24
  from reflex.base import Base
24
25
  from reflex.config import get_config
@@ -34,6 +35,41 @@ _AsyncSessionLocal: dict[str | None, sqlalchemy.ext.asyncio.async_sessionmaker]
34
35
  from sqlmodel.ext.asyncio.session import AsyncSession # noqa: E402
35
36
 
36
37
 
38
+ def format_revision(
39
+ rev: Script,
40
+ current_rev: str | None,
41
+ current_reached_ref: list[bool],
42
+ ) -> str:
43
+ """Format a single revision for display.
44
+
45
+ Args:
46
+ rev: The alembic script object
47
+ current_rev: The currently applied revision ID
48
+ current_reached_ref: Mutable reference to track if we've reached current revision
49
+
50
+ Returns:
51
+ Formatted string for display
52
+ """
53
+ current = rev.revision
54
+ message = rev.doc
55
+
56
+ # Determine if this migration is applied
57
+ if current_rev is None:
58
+ is_applied = False
59
+ elif current == current_rev:
60
+ is_applied = True
61
+ current_reached_ref[0] = True
62
+ else:
63
+ is_applied = not current_reached_ref[0]
64
+
65
+ # Show checkmark or X with colors
66
+ status_icon = "[green]✓[/green]" if is_applied else "[red]✗[/red]"
67
+ head_marker = " (head)" if rev.is_head else ""
68
+
69
+ # Format output with message
70
+ return f" [{status_icon}] {current}{head_marker}, {message}"
71
+
72
+
37
73
  def _safe_db_url_for_logging(url: str) -> str:
38
74
  """Remove username and password from the database URL for logging.
39
75
 
@@ -361,6 +397,25 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
361
397
  directory=str(environment.ALEMBIC_CONFIG.get().parent / "alembic"),
362
398
  )
363
399
 
400
+ @classmethod
401
+ def get_migration_history(cls):
402
+ """Get migration history with current database state.
403
+
404
+ Returns:
405
+ tuple: (current_revision, revisions_list) where revisions_list is in chronological order
406
+ """
407
+ # Get current revision from database
408
+ with cls.get_db_engine().connect() as connection:
409
+ context = MigrationContext.configure(connection)
410
+ current_rev = context.get_current_revision()
411
+
412
+ # Get all revisions from base to head
413
+ _, script_dir = cls._alembic_config()
414
+ revisions = list(script_dir.walk_revisions())
415
+ revisions.reverse() # Reverse to get chronological order (base first)
416
+
417
+ return current_rev, revisions
418
+
364
419
  @classmethod
365
420
  def alembic_autogenerate(
366
421
  cls,
reflex/reflex.py CHANGED
@@ -540,6 +540,39 @@ def migrate():
540
540
  prerequisites.check_schema_up_to_date()
541
541
 
542
542
 
543
+ @db_cli.command()
544
+ def status():
545
+ """Check the status of the database schema."""
546
+ from reflex.model import Model, format_revision
547
+ from reflex.utils import prerequisites
548
+
549
+ prerequisites.get_app()
550
+ if not prerequisites.check_db_initialized():
551
+ console.info(
552
+ "Database is not initialized. Run [bold]reflex db init[/bold] to initialize."
553
+ )
554
+ return
555
+
556
+ # Run alembic check command and display output
557
+ import reflex.config
558
+
559
+ config = reflex.config.get_config()
560
+ console.print(f"[bold]\\[{config.db_url}][/bold]")
561
+
562
+ # Get migration history using Model method
563
+ current_rev, revisions = Model.get_migration_history()
564
+ if current_rev is None and not revisions:
565
+ return
566
+
567
+ current_reached_ref = [current_rev is None]
568
+
569
+ # Show migration history in chronological order
570
+ console.print("<base>")
571
+ for rev in revisions:
572
+ # Format and print the revision
573
+ console.print(format_revision(rev, current_rev, current_reached_ref))
574
+
575
+
543
576
  @db_cli.command()
544
577
  @click.option(
545
578
  "--message",
reflex/state.py CHANGED
@@ -1100,7 +1100,12 @@ class BaseState(EvenMoreBasicBaseState):
1100
1100
  Returns:
1101
1101
  The event handler.
1102
1102
  """
1103
- return EventHandler(fn=fn, state_full_name=cls.get_full_name())
1103
+ # Check if function has stored event_actions from decorator
1104
+ event_actions = getattr(fn, "_rx_event_actions", {})
1105
+
1106
+ return EventHandler(
1107
+ fn=fn, state_full_name=cls.get_full_name(), event_actions=event_actions
1108
+ )
1104
1109
 
1105
1110
  @classmethod
1106
1111
  def _create_setvar(cls):
@@ -2412,19 +2417,19 @@ class FrontendEventExceptionState(State):
2412
2417
  """Substate for handling frontend exceptions."""
2413
2418
 
2414
2419
  @event
2415
- def handle_frontend_exception(self, stack: str, component_stack: str) -> None:
2420
+ def handle_frontend_exception(self, info: str, component_stack: str) -> None:
2416
2421
  """Handle frontend exceptions.
2417
2422
 
2418
2423
  If a frontend exception handler is provided, it will be called.
2419
2424
  Otherwise, the default frontend exception handler will be called.
2420
2425
 
2421
2426
  Args:
2422
- stack: The stack trace of the exception.
2427
+ info: The exception information.
2423
2428
  component_stack: The stack trace of the component where the exception occurred.
2424
2429
 
2425
2430
  """
2426
2431
  prerequisites.get_and_validate_app().app.frontend_exception_handler(
2427
- Exception(stack)
2432
+ Exception(info)
2428
2433
  )
2429
2434
 
2430
2435