reflex 0.5.0.post1__py3-none-any.whl → 0.5.1a1__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/web/utils/state.js +7 -2
- reflex/app.py +69 -50
- reflex/base.py +5 -2
- reflex/components/component.py +49 -13
- reflex/components/core/__init__.py +7 -1
- reflex/components/core/banner.py +79 -6
- reflex/components/core/banner.pyi +130 -0
- reflex/components/core/cond.py +1 -1
- reflex/components/core/debounce.py +2 -4
- reflex/components/core/foreach.py +11 -0
- reflex/components/core/upload.py +9 -10
- reflex/components/el/elements/forms.py +12 -6
- reflex/components/el/elements/media.py +19 -0
- reflex/components/el/elements/media.pyi +3 -1
- reflex/components/gridjs/datatable.py +4 -2
- reflex/components/props.py +30 -0
- reflex/components/radix/themes/components/tabs.py +1 -1
- reflex/components/sonner/toast.py +102 -35
- reflex/components/sonner/toast.pyi +27 -14
- reflex/config.py +5 -3
- reflex/constants/compiler.py +3 -3
- reflex/constants/installer.py +1 -1
- reflex/event.py +38 -24
- reflex/experimental/__init__.py +4 -0
- reflex/experimental/client_state.py +198 -0
- reflex/state.py +61 -21
- reflex/style.py +3 -3
- reflex/testing.py +28 -9
- reflex/utils/exceptions.py +64 -8
- reflex/utils/format.py +73 -2
- reflex/utils/prerequisites.py +28 -18
- reflex/utils/processes.py +34 -4
- reflex/utils/telemetry.py +5 -5
- reflex/utils/types.py +16 -0
- reflex/vars.py +104 -61
- reflex/vars.pyi +7 -6
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/METADATA +1 -1
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/RECORD +41 -39
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/LICENSE +0 -0
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/WHEEL +0 -0
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/entry_points.txt +0 -0
reflex/testing.py
CHANGED
|
@@ -26,6 +26,7 @@ from typing import (
|
|
|
26
26
|
AsyncIterator,
|
|
27
27
|
Callable,
|
|
28
28
|
Coroutine,
|
|
29
|
+
List,
|
|
29
30
|
Optional,
|
|
30
31
|
Type,
|
|
31
32
|
TypeVar,
|
|
@@ -513,12 +514,19 @@ class AppHarness:
|
|
|
513
514
|
raise TimeoutError("Backend is not listening.")
|
|
514
515
|
return backend.servers[0].sockets[0]
|
|
515
516
|
|
|
516
|
-
def frontend(
|
|
517
|
+
def frontend(
|
|
518
|
+
self,
|
|
519
|
+
driver_clz: Optional[Type["WebDriver"]] = None,
|
|
520
|
+
driver_kwargs: dict[str, Any] | None = None,
|
|
521
|
+
driver_option_args: List[str] | None = None,
|
|
522
|
+
) -> "WebDriver":
|
|
517
523
|
"""Get a selenium webdriver instance pointed at the app.
|
|
518
524
|
|
|
519
525
|
Args:
|
|
520
526
|
driver_clz: webdriver.Chrome (default), webdriver.Firefox, webdriver.Safari,
|
|
521
527
|
webdriver.Edge, etc
|
|
528
|
+
driver_kwargs: additional keyword arguments to pass to the webdriver constructor
|
|
529
|
+
driver_option_args: additional arguments for the webdriver options
|
|
522
530
|
|
|
523
531
|
Returns:
|
|
524
532
|
Instance of the given webdriver navigated to the frontend url of the app.
|
|
@@ -541,19 +549,30 @@ class AppHarness:
|
|
|
541
549
|
requested_driver = os.environ.get("APP_HARNESS_DRIVER", "Chrome")
|
|
542
550
|
driver_clz = getattr(webdriver, requested_driver)
|
|
543
551
|
options = getattr(webdriver, f"{requested_driver}Options")()
|
|
544
|
-
if driver_clz is webdriver.Chrome
|
|
552
|
+
if driver_clz is webdriver.Chrome:
|
|
545
553
|
options = webdriver.ChromeOptions()
|
|
546
|
-
options.add_argument("--
|
|
547
|
-
|
|
554
|
+
options.add_argument("--class=AppHarness")
|
|
555
|
+
if want_headless:
|
|
556
|
+
options.add_argument("--headless=new")
|
|
557
|
+
elif driver_clz is webdriver.Firefox:
|
|
548
558
|
options = webdriver.FirefoxOptions()
|
|
549
|
-
|
|
550
|
-
|
|
559
|
+
if want_headless:
|
|
560
|
+
options.add_argument("-headless")
|
|
561
|
+
elif driver_clz is webdriver.Edge:
|
|
551
562
|
options = webdriver.EdgeOptions()
|
|
552
|
-
|
|
553
|
-
|
|
563
|
+
if want_headless:
|
|
564
|
+
options.add_argument("headless")
|
|
565
|
+
if options is None:
|
|
566
|
+
raise RuntimeError(f"Could not determine options for {driver_clz}")
|
|
567
|
+
if args := os.environ.get("APP_HARNESS_DRIVER_ARGS"):
|
|
554
568
|
for arg in args.split(","):
|
|
555
569
|
options.add_argument(arg)
|
|
556
|
-
|
|
570
|
+
if driver_option_args is not None:
|
|
571
|
+
for arg in driver_option_args:
|
|
572
|
+
options.add_argument(arg)
|
|
573
|
+
if driver_kwargs is None:
|
|
574
|
+
driver_kwargs = {}
|
|
575
|
+
driver = driver_clz(options=options, **driver_kwargs) # type: ignore
|
|
557
576
|
driver.get(self.frontend_url)
|
|
558
577
|
self._frontends.append(driver)
|
|
559
578
|
return driver
|
reflex/utils/exceptions.py
CHANGED
|
@@ -1,21 +1,77 @@
|
|
|
1
1
|
"""Custom Exceptions."""
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class
|
|
5
|
-
"""
|
|
4
|
+
class ReflexError(Exception):
|
|
5
|
+
"""Base exception for all Reflex exceptions."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ReflexRuntimeError(ReflexError, RuntimeError):
|
|
9
|
+
"""Custom RuntimeError for Reflex."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class UploadTypeError(ReflexError, TypeError):
|
|
13
|
+
"""Custom TypeError for upload related errors."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EnvVarValueError(ReflexError, ValueError):
|
|
17
|
+
"""Custom ValueError raised when unable to convert env var to expected type."""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ComponentTypeError(ReflexError, TypeError):
|
|
21
|
+
"""Custom TypeError for component related errors."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class EventHandlerTypeError(ReflexError, TypeError):
|
|
25
|
+
"""Custom TypeError for event handler related errors."""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class EventHandlerValueError(ReflexError, ValueError):
|
|
29
|
+
"""Custom ValueError for event handler related errors."""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class StateValueError(ReflexError, ValueError):
|
|
33
|
+
"""Custom ValueError for state related errors."""
|
|
34
|
+
|
|
6
35
|
|
|
7
|
-
|
|
36
|
+
class VarNameError(ReflexError, NameError):
|
|
37
|
+
"""Custom NameError for when a state var has been shadowed by a substate var."""
|
|
8
38
|
|
|
9
39
|
|
|
10
|
-
class
|
|
40
|
+
class VarTypeError(ReflexError, TypeError):
|
|
41
|
+
"""Custom TypeError for var related errors."""
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class VarValueError(ReflexError, ValueError):
|
|
45
|
+
"""Custom ValueError for var related errors."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class VarAttributeError(ReflexError, AttributeError):
|
|
49
|
+
"""Custom AttributeError for var related errors."""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class UploadValueError(ReflexError, ValueError):
|
|
53
|
+
"""Custom ValueError for upload related errors."""
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class RouteValueError(ReflexError, ValueError):
|
|
57
|
+
"""Custom ValueError for route related errors."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class VarOperationTypeError(ReflexError, TypeError):
|
|
61
|
+
"""Custom TypeError for when unsupported operations are performed on vars."""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class InvalidStylePropError(ReflexError, TypeError):
|
|
65
|
+
"""Custom Type Error when style props have invalid values."""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ImmutableStateError(ReflexError):
|
|
11
69
|
"""Raised when a background task attempts to modify state outside of context."""
|
|
12
70
|
|
|
13
71
|
|
|
14
|
-
class LockExpiredError(
|
|
72
|
+
class LockExpiredError(ReflexError):
|
|
15
73
|
"""Raised when the state lock expires while an event is being processed."""
|
|
16
74
|
|
|
17
75
|
|
|
18
|
-
class MatchTypeError(TypeError):
|
|
76
|
+
class MatchTypeError(ReflexError, TypeError):
|
|
19
77
|
"""Raised when the return types of match cases are different."""
|
|
20
|
-
|
|
21
|
-
pass
|
reflex/utils/format.py
CHANGED
|
@@ -6,7 +6,7 @@ import inspect
|
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
8
|
import re
|
|
9
|
-
from typing import TYPE_CHECKING, Any, List, Optional, Union
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
|
|
10
10
|
|
|
11
11
|
from reflex import constants
|
|
12
12
|
from reflex.utils import exceptions, serializers, types
|
|
@@ -15,7 +15,7 @@ from reflex.vars import BaseVar, Var
|
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
from reflex.components.component import ComponentStyle
|
|
18
|
-
from reflex.event import EventChain, EventHandler, EventSpec
|
|
18
|
+
from reflex.event import ArgsSpec, EventChain, EventHandler, EventSpec
|
|
19
19
|
|
|
20
20
|
WRAP_MAP = {
|
|
21
21
|
"{": "}",
|
|
@@ -590,6 +590,77 @@ def format_event_chain(
|
|
|
590
590
|
)
|
|
591
591
|
|
|
592
592
|
|
|
593
|
+
def format_queue_events(
|
|
594
|
+
events: EventSpec
|
|
595
|
+
| EventHandler
|
|
596
|
+
| Callable
|
|
597
|
+
| List[EventSpec | EventHandler | Callable]
|
|
598
|
+
| None = None,
|
|
599
|
+
args_spec: Optional[ArgsSpec] = None,
|
|
600
|
+
) -> Var[EventChain]:
|
|
601
|
+
"""Format a list of event handler / event spec as a javascript callback.
|
|
602
|
+
|
|
603
|
+
The resulting code can be passed to interfaces that expect a callback
|
|
604
|
+
function and when triggered it will directly call queueEvents.
|
|
605
|
+
|
|
606
|
+
It is intended to be executed in the rx.call_script context, where some
|
|
607
|
+
existing API needs a callback to trigger a backend event handler.
|
|
608
|
+
|
|
609
|
+
Args:
|
|
610
|
+
events: The events to queue.
|
|
611
|
+
args_spec: The argument spec for the callback.
|
|
612
|
+
|
|
613
|
+
Returns:
|
|
614
|
+
The compiled javascript callback to queue the given events on the frontend.
|
|
615
|
+
"""
|
|
616
|
+
from reflex.event import (
|
|
617
|
+
EventChain,
|
|
618
|
+
EventHandler,
|
|
619
|
+
EventSpec,
|
|
620
|
+
call_event_fn,
|
|
621
|
+
call_event_handler,
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
if not events:
|
|
625
|
+
return Var.create_safe(
|
|
626
|
+
"() => null", _var_is_string=False, _var_is_local=False
|
|
627
|
+
).to(EventChain)
|
|
628
|
+
|
|
629
|
+
# If no spec is provided, the function will take no arguments.
|
|
630
|
+
def _default_args_spec():
|
|
631
|
+
return []
|
|
632
|
+
|
|
633
|
+
# Construct the arguments that the function accepts.
|
|
634
|
+
sig = inspect.signature(args_spec or _default_args_spec) # type: ignore
|
|
635
|
+
if sig.parameters:
|
|
636
|
+
arg_def = ",".join(f"_{p}" for p in sig.parameters)
|
|
637
|
+
arg_def = f"({arg_def})"
|
|
638
|
+
else:
|
|
639
|
+
arg_def = "()"
|
|
640
|
+
|
|
641
|
+
payloads = []
|
|
642
|
+
if not isinstance(events, list):
|
|
643
|
+
events = [events]
|
|
644
|
+
|
|
645
|
+
# Process each event/spec/lambda (similar to Component._create_event_chain).
|
|
646
|
+
for spec in events:
|
|
647
|
+
specs: list[EventSpec] = []
|
|
648
|
+
if isinstance(spec, (EventHandler, EventSpec)):
|
|
649
|
+
specs = [call_event_handler(spec, args_spec or _default_args_spec)]
|
|
650
|
+
elif isinstance(spec, type(lambda: None)):
|
|
651
|
+
specs = call_event_fn(spec, args_spec or _default_args_spec)
|
|
652
|
+
payloads.extend(format_event(s) for s in specs)
|
|
653
|
+
|
|
654
|
+
# Return the final code snippet, expecting queueEvents, processEvent, and socket to be in scope.
|
|
655
|
+
# Typically this snippet will _only_ run from within an rx.call_script eval context.
|
|
656
|
+
return Var.create_safe(
|
|
657
|
+
f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); "
|
|
658
|
+
f"processEvent({constants.CompileVars.SOCKET})}}",
|
|
659
|
+
_var_is_string=False,
|
|
660
|
+
_var_is_local=False,
|
|
661
|
+
).to(EventChain)
|
|
662
|
+
|
|
663
|
+
|
|
593
664
|
def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
|
|
594
665
|
"""Convert back query params name to python-friendly case.
|
|
595
666
|
|
reflex/utils/prerequisites.py
CHANGED
|
@@ -233,28 +233,35 @@ def get_app(reload: bool = False) -> ModuleType:
|
|
|
233
233
|
|
|
234
234
|
Raises:
|
|
235
235
|
RuntimeError: If the app name is not set in the config.
|
|
236
|
+
exceptions.ReflexError: Reflex specific errors.
|
|
236
237
|
"""
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
238
|
+
from reflex.utils import exceptions, telemetry
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
os.environ[constants.RELOAD_CONFIG] = str(reload)
|
|
242
|
+
config = get_config()
|
|
243
|
+
if not config.app_name:
|
|
244
|
+
raise RuntimeError(
|
|
245
|
+
"Cannot get the app module because `app_name` is not set in rxconfig! "
|
|
246
|
+
"If this error occurs in a reflex test case, ensure that `get_app` is mocked."
|
|
247
|
+
)
|
|
248
|
+
module = config.module
|
|
249
|
+
sys.path.insert(0, os.getcwd())
|
|
250
|
+
app = __import__(module, fromlist=(constants.CompileVars.APP,))
|
|
247
251
|
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
if reload:
|
|
253
|
+
from reflex.state import reload_state_module
|
|
250
254
|
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
# Reset rx.State subclasses to avoid conflict when reloading.
|
|
256
|
+
reload_state_module(module=module)
|
|
253
257
|
|
|
254
|
-
|
|
255
|
-
|
|
258
|
+
# Reload the app module.
|
|
259
|
+
importlib.reload(app)
|
|
256
260
|
|
|
257
|
-
|
|
261
|
+
return app
|
|
262
|
+
except exceptions.ReflexError as ex:
|
|
263
|
+
telemetry.send("error", context="frontend", detail=str(ex))
|
|
264
|
+
raise
|
|
258
265
|
|
|
259
266
|
|
|
260
267
|
def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
|
|
@@ -406,7 +413,7 @@ def initialize_gitignore(
|
|
|
406
413
|
# Write files to the .gitignore file.
|
|
407
414
|
with open(gitignore_file, "w", newline="\n") as f:
|
|
408
415
|
console.debug(f"Creating {gitignore_file}")
|
|
409
|
-
f.write(f"{(path_ops.join(sorted(files_to_ignore))).lstrip()}")
|
|
416
|
+
f.write(f"{(path_ops.join(sorted(files_to_ignore))).lstrip()}\n")
|
|
410
417
|
|
|
411
418
|
|
|
412
419
|
def initialize_requirements_txt():
|
|
@@ -879,6 +886,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
879
886
|
processes.run_process_with_fallback(
|
|
880
887
|
[get_install_package_manager(), "install"], # type: ignore
|
|
881
888
|
fallback=fallback_command,
|
|
889
|
+
analytics_enabled=True,
|
|
882
890
|
show_status_message="Installing base frontend packages",
|
|
883
891
|
cwd=constants.Dirs.WEB,
|
|
884
892
|
shell=constants.IS_WINDOWS,
|
|
@@ -894,6 +902,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
894
902
|
*((config.tailwind or {}).get("plugins", [])),
|
|
895
903
|
],
|
|
896
904
|
fallback=fallback_command,
|
|
905
|
+
analytics_enabled=True,
|
|
897
906
|
show_status_message="Installing tailwind",
|
|
898
907
|
cwd=constants.Dirs.WEB,
|
|
899
908
|
shell=constants.IS_WINDOWS,
|
|
@@ -904,6 +913,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
904
913
|
processes.run_process_with_fallback(
|
|
905
914
|
[get_install_package_manager(), "add", *packages],
|
|
906
915
|
fallback=fallback_command,
|
|
916
|
+
analytics_enabled=True,
|
|
907
917
|
show_status_message="Installing frontend packages from config and components",
|
|
908
918
|
cwd=constants.Dirs.WEB,
|
|
909
919
|
shell=constants.IS_WINDOWS,
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
@@ -126,6 +126,10 @@ def _prepare_event(event: str, **kwargs) -> dict:
|
|
|
126
126
|
|
|
127
127
|
cpuinfo = get_cpu_info()
|
|
128
128
|
|
|
129
|
+
additional_keys = ["template", "context", "detail"]
|
|
130
|
+
additional_fields = {
|
|
131
|
+
key: value for key in additional_keys if (value := kwargs.get(key)) is not None
|
|
132
|
+
}
|
|
129
133
|
return {
|
|
130
134
|
"api_key": "phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb",
|
|
131
135
|
"event": event,
|
|
@@ -139,11 +143,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
|
|
|
139
143
|
"cpu_count": get_cpu_count(),
|
|
140
144
|
"memory": get_memory(),
|
|
141
145
|
"cpu_info": dict(cpuinfo) if cpuinfo else {},
|
|
142
|
-
**
|
|
143
|
-
{"template": template}
|
|
144
|
-
if (template := kwargs.get("template")) is not None
|
|
145
|
-
else {}
|
|
146
|
-
),
|
|
146
|
+
**additional_fields,
|
|
147
147
|
},
|
|
148
148
|
"timestamp": stamp,
|
|
149
149
|
}
|
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
|
|