reflex 0.5.0a3__py3-none-any.whl → 0.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

Files changed (42) hide show
  1. reflex/.templates/web/utils/state.js +7 -2
  2. reflex/app.py +68 -50
  3. reflex/app_module_for_backend.py +3 -0
  4. reflex/base.py +5 -2
  5. reflex/components/component.py +49 -13
  6. reflex/components/core/__init__.py +7 -1
  7. reflex/components/core/banner.py +79 -6
  8. reflex/components/core/banner.pyi +130 -0
  9. reflex/components/core/cond.py +10 -4
  10. reflex/components/core/debounce.py +2 -4
  11. reflex/components/core/foreach.py +11 -0
  12. reflex/components/core/upload.py +9 -10
  13. reflex/components/el/elements/forms.py +12 -6
  14. reflex/components/el/elements/media.py +19 -0
  15. reflex/components/el/elements/media.pyi +3 -1
  16. reflex/components/gridjs/datatable.py +4 -2
  17. reflex/components/props.py +30 -0
  18. reflex/components/radix/themes/components/tabs.py +1 -1
  19. reflex/components/sonner/toast.py +102 -35
  20. reflex/components/sonner/toast.pyi +27 -14
  21. reflex/config.py +5 -3
  22. reflex/constants/compiler.py +3 -3
  23. reflex/constants/installer.py +1 -1
  24. reflex/event.py +38 -24
  25. reflex/experimental/__init__.py +4 -0
  26. reflex/experimental/client_state.py +198 -0
  27. reflex/state.py +59 -21
  28. reflex/style.py +3 -3
  29. reflex/testing.py +28 -9
  30. reflex/utils/exceptions.py +64 -8
  31. reflex/utils/format.py +73 -2
  32. reflex/utils/prerequisites.py +68 -23
  33. reflex/utils/processes.py +34 -4
  34. reflex/utils/telemetry.py +42 -16
  35. reflex/utils/types.py +16 -0
  36. reflex/vars.py +104 -61
  37. reflex/vars.pyi +7 -6
  38. {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/METADATA +1 -1
  39. {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/RECORD +42 -40
  40. {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/LICENSE +0 -0
  41. {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/WHEEL +0 -0
  42. {reflex-0.5.0a3.dist-info → reflex-0.5.1.dist-info}/entry_points.txt +0 -0
reflex/utils/processes.py CHANGED
@@ -211,6 +211,7 @@ def stream_logs(
211
211
  process: subprocess.Popen,
212
212
  progress=None,
213
213
  suppress_errors: bool = False,
214
+ analytics_enabled: bool = False,
214
215
  ):
215
216
  """Stream the logs for a process.
216
217
 
@@ -219,6 +220,7 @@ def stream_logs(
219
220
  process: The process.
220
221
  progress: The ongoing progress bar if one is being used.
221
222
  suppress_errors: If True, do not exit if errors are encountered (for fallback).
223
+ analytics_enabled: Whether analytics are enabled for this command.
222
224
 
223
225
  Yields:
224
226
  The lines of the process output.
@@ -226,6 +228,8 @@ def stream_logs(
226
228
  Raises:
227
229
  Exit: If the process failed.
228
230
  """
231
+ from reflex.utils import telemetry
232
+
229
233
  # Store the tail of the logs.
230
234
  logs = collections.deque(maxlen=512)
231
235
  with process:
@@ -246,6 +250,8 @@ def stream_logs(
246
250
  console.error(f"{message} failed with exit code {process.returncode}")
247
251
  for line in logs:
248
252
  console.error(line, end="")
253
+ if analytics_enabled:
254
+ telemetry.send("error", context=message)
249
255
  console.error("Run with [bold]--loglevel debug [/bold] for the full log.")
250
256
  raise typer.Exit(1)
251
257
 
@@ -261,16 +267,27 @@ def show_logs(message: str, process: subprocess.Popen):
261
267
  pass
262
268
 
263
269
 
264
- def show_status(message: str, process: subprocess.Popen, suppress_errors: bool = False):
270
+ def show_status(
271
+ message: str,
272
+ process: subprocess.Popen,
273
+ suppress_errors: bool = False,
274
+ analytics_enabled: bool = False,
275
+ ):
265
276
  """Show the status of a process.
266
277
 
267
278
  Args:
268
279
  message: The initial message to display.
269
280
  process: The process.
270
281
  suppress_errors: If True, do not exit if errors are encountered (for fallback).
282
+ analytics_enabled: Whether analytics are enabled for this command.
271
283
  """
272
284
  with console.status(message) as status:
273
- for line in stream_logs(message, process, suppress_errors=suppress_errors):
285
+ for line in stream_logs(
286
+ message,
287
+ process,
288
+ suppress_errors=suppress_errors,
289
+ analytics_enabled=analytics_enabled,
290
+ ):
274
291
  status.update(f"{message} {line}")
275
292
 
276
293
 
@@ -319,19 +336,31 @@ def get_command_with_loglevel(command: list[str]) -> list[str]:
319
336
  return command
320
337
 
321
338
 
322
- def run_process_with_fallback(args, *, show_status_message, fallback=None, **kwargs):
339
+ def run_process_with_fallback(
340
+ args,
341
+ *,
342
+ show_status_message,
343
+ fallback=None,
344
+ analytics_enabled: bool = False,
345
+ **kwargs,
346
+ ):
323
347
  """Run subprocess and retry using fallback command if initial command fails.
324
348
 
325
349
  Args:
326
350
  args: A string, or a sequence of program arguments.
327
351
  show_status_message: The status message to be displayed in the console.
328
352
  fallback: The fallback command to run.
353
+ analytics_enabled: Whether analytics are enabled for this command.
329
354
  kwargs: Kwargs to pass to new_process function.
330
355
  """
331
356
  process = new_process(get_command_with_loglevel(args), **kwargs)
332
357
  if fallback is None:
333
358
  # No fallback given, or this _is_ the fallback command.
334
- show_status(show_status_message, process)
359
+ show_status(
360
+ show_status_message,
361
+ process,
362
+ analytics_enabled=analytics_enabled,
363
+ )
335
364
  else:
336
365
  # Suppress errors for initial command, because we will try to fallback
337
366
  show_status(show_status_message, process, suppress_errors=True)
@@ -345,6 +374,7 @@ def run_process_with_fallback(args, *, show_status_message, fallback=None, **kwa
345
374
  fallback_args,
346
375
  show_status_message=show_status_message,
347
376
  fallback=None,
377
+ analytics_enabled=analytics_enabled,
348
378
  **kwargs,
349
379
  )
350
380
 
reflex/utils/telemetry.py CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import asyncio
5
6
  import multiprocessing
6
7
  import platform
8
+ import warnings
7
9
 
8
10
  try:
9
11
  from datetime import UTC, datetime
@@ -126,6 +128,10 @@ def _prepare_event(event: str, **kwargs) -> dict:
126
128
 
127
129
  cpuinfo = get_cpu_info()
128
130
 
131
+ additional_keys = ["template", "context", "detail"]
132
+ additional_fields = {
133
+ key: value for key in additional_keys if (value := kwargs.get(key)) is not None
134
+ }
129
135
  return {
130
136
  "api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb",
131
137
  "event": event,
@@ -139,11 +145,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
139
145
  "cpu_count": get_cpu_count(),
140
146
  "memory": get_memory(),
141
147
  "cpu_info": dict(cpuinfo) if cpuinfo else {},
142
- **(
143
- {"template": template}
144
- if (template := kwargs.get("template")) is not None
145
- else {}
146
- ),
148
+ **additional_fields,
147
149
  },
148
150
  "timestamp": stamp,
149
151
  }
@@ -157,17 +159,7 @@ def _send_event(event_data: dict) -> bool:
157
159
  return False
158
160
 
159
161
 
160
- def send(event: str, telemetry_enabled: bool | None = None, **kwargs) -> bool:
161
- """Send anonymous telemetry for Reflex.
162
-
163
- Args:
164
- event: The event name.
165
- telemetry_enabled: Whether to send the telemetry (If None, get from config).
166
- kwargs: Additional data to send with the event.
167
-
168
- Returns:
169
- Whether the telemetry was sent successfully.
170
- """
162
+ def _send(event, telemetry_enabled, **kwargs):
171
163
  from reflex.config import get_config
172
164
 
173
165
  # Get the telemetry_enabled from the config if it is not specified.
@@ -182,3 +174,37 @@ def send(event: str, telemetry_enabled: bool | None = None, **kwargs) -> bool:
182
174
  if not event_data:
183
175
  return False
184
176
  return _send_event(event_data)
177
+
178
+
179
+ def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
180
+ """Send anonymous telemetry for Reflex.
181
+
182
+ Args:
183
+ event: The event name.
184
+ telemetry_enabled: Whether to send the telemetry (If None, get from config).
185
+ kwargs: Additional data to send with the event.
186
+ """
187
+
188
+ async def async_send(event, telemetry_enabled, **kwargs):
189
+ return _send(event, telemetry_enabled, **kwargs)
190
+
191
+ try:
192
+ # Within an event loop context, send the event asynchronously.
193
+ asyncio.create_task(async_send(event, telemetry_enabled, **kwargs))
194
+ except RuntimeError:
195
+ # If there is no event loop, send the event synchronously.
196
+ warnings.filterwarnings("ignore", category=RuntimeWarning)
197
+ _send(event, telemetry_enabled, **kwargs)
198
+
199
+
200
+ def send_error(error: Exception, context: str):
201
+ """Send an error event.
202
+
203
+ Args:
204
+ error: The error to send.
205
+ context: The context of the error (e.g. "frontend" or "backend")
206
+
207
+ Returns:
208
+ Whether the telemetry was sent successfully.
209
+ """
210
+ return send("error", detail=type(error).__name__, context=context)
reflex/utils/types.py CHANGED
@@ -44,6 +44,22 @@ from reflex import constants
44
44
  from reflex.base import Base
45
45
  from reflex.utils import console, serializers
46
46
 
47
+ if sys.version_info >= (3, 12):
48
+ from typing import override
49
+ else:
50
+
51
+ def override(func: Callable) -> Callable:
52
+ """Fallback for @override decorator.
53
+
54
+ Args:
55
+ func: The function to decorate.
56
+
57
+ Returns:
58
+ The unmodified function.
59
+ """
60
+ return func
61
+
62
+
47
63
  # Potential GenericAlias types for isinstance checks.
48
64
  GenericAliasTypes = [_GenericAlias]
49
65