reflex 0.6.5a3__py3-none-any.whl → 0.6.6a1__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 (48) hide show
  1. reflex/.templates/web/utils/state.js +15 -1
  2. reflex/__init__.py +3 -1
  3. reflex/__init__.pyi +3 -0
  4. reflex/app.py +4 -2
  5. reflex/assets.py +95 -0
  6. reflex/base.py +2 -2
  7. reflex/components/base/error_boundary.py +99 -36
  8. reflex/components/base/error_boundary.pyi +3 -4
  9. reflex/components/component.py +29 -7
  10. reflex/components/core/cond.py +8 -0
  11. reflex/components/datadisplay/code.py +1 -1
  12. reflex/components/datadisplay/logo.py +26 -13
  13. reflex/components/el/__init__.pyi +2 -0
  14. reflex/components/el/elements/__init__.py +1 -0
  15. reflex/components/el/elements/__init__.pyi +3 -0
  16. reflex/components/el/elements/forms.py +1 -0
  17. reflex/components/el/elements/forms.pyi +1 -0
  18. reflex/components/moment/moment.py +4 -3
  19. reflex/components/moment/moment.pyi +12 -2
  20. reflex/components/radix/primitives/drawer.py +5 -23
  21. reflex/components/radix/themes/base.py +3 -0
  22. reflex/components/radix/themes/components/segmented_control.py +3 -1
  23. reflex/components/radix/themes/components/segmented_control.pyi +7 -2
  24. reflex/components/radix/themes/components/text_field.py +3 -0
  25. reflex/components/radix/themes/components/text_field.pyi +4 -0
  26. reflex/components/sonner/toast.py +23 -12
  27. reflex/components/sonner/toast.pyi +6 -6
  28. reflex/config.py +60 -9
  29. reflex/constants/base.py +12 -0
  30. reflex/constants/installer.py +3 -3
  31. reflex/constants/style.py +1 -1
  32. reflex/event.py +22 -5
  33. reflex/experimental/assets.py +14 -36
  34. reflex/reflex.py +15 -34
  35. reflex/state.py +81 -23
  36. reflex/utils/exceptions.py +4 -0
  37. reflex/utils/prerequisites.py +174 -40
  38. reflex/utils/redir.py +13 -4
  39. reflex/utils/serializers.py +52 -1
  40. reflex/utils/telemetry.py +2 -1
  41. reflex/utils/types.py +52 -1
  42. reflex/vars/base.py +18 -4
  43. reflex/vars/function.py +283 -37
  44. {reflex-0.6.5a3.dist-info → reflex-0.6.6a1.dist-info}/METADATA +3 -2
  45. {reflex-0.6.5a3.dist-info → reflex-0.6.6a1.dist-info}/RECORD +48 -47
  46. {reflex-0.6.5a3.dist-info → reflex-0.6.6a1.dist-info}/LICENSE +0 -0
  47. {reflex-0.6.5a3.dist-info → reflex-0.6.6a1.dist-info}/WHEEL +0 -0
  48. {reflex-0.6.5a3.dist-info → reflex-0.6.6a1.dist-info}/entry_points.txt +0 -0
@@ -4,6 +4,7 @@
4
4
  # This file was generated by `reflex/utils/pyi_generator.py`!
5
5
  # ------------------------------------------------------
6
6
  import dataclasses
7
+ from datetime import date, datetime, time, timedelta
7
8
  from typing import Any, Dict, Optional, Union, overload
8
9
 
9
10
  from reflex.components.component import NoSSRComponent
@@ -20,7 +21,7 @@ class MomentDelta:
20
21
  weeks: Optional[int]
21
22
  days: Optional[int]
22
23
  hours: Optional[int]
23
- minutess: Optional[int]
24
+ minutes: Optional[int]
24
25
  seconds: Optional[int]
25
26
  milliseconds: Optional[int]
26
27
 
@@ -46,7 +47,16 @@ class Moment(NoSSRComponent):
46
47
  decimal: Optional[Union[Var[bool], bool]] = None,
47
48
  unit: Optional[Union[Var[str], str]] = None,
48
49
  duration: Optional[Union[Var[str], str]] = None,
49
- date: Optional[Union[Var[str], str]] = None,
50
+ date: Optional[
51
+ Union[
52
+ Var[Union[date, datetime, str, time, timedelta]],
53
+ date,
54
+ datetime,
55
+ str,
56
+ time,
57
+ timedelta,
58
+ ]
59
+ ] = None,
50
60
  duration_from_now: Optional[Union[Var[bool], bool]] = None,
51
61
  unix: Optional[Union[Var[bool], bool]] = None,
52
62
  local: Optional[Union[Var[bool], bool]] = None,
@@ -11,7 +11,6 @@ from reflex.components.radix.primitives.base import RadixPrimitiveComponent
11
11
  from reflex.components.radix.themes.base import Theme
12
12
  from reflex.components.radix.themes.layout.flex import Flex
13
13
  from reflex.event import EventHandler, no_args_event_spec, passthrough_event_spec
14
- from reflex.utils import console
15
14
  from reflex.vars.base import Var
16
15
 
17
16
 
@@ -140,19 +139,19 @@ class DrawerContent(DrawerComponent):
140
139
  base_style.update(style)
141
140
  return {"css": base_style}
142
141
 
143
- # Fired when the drawer content is opened. Deprecated.
142
+ # Fired when the drawer content is opened.
144
143
  on_open_auto_focus: EventHandler[no_args_event_spec]
145
144
 
146
- # Fired when the drawer content is closed. Deprecated.
145
+ # Fired when the drawer content is closed.
147
146
  on_close_auto_focus: EventHandler[no_args_event_spec]
148
147
 
149
- # Fired when the escape key is pressed. Deprecated.
148
+ # Fired when the escape key is pressed.
150
149
  on_escape_key_down: EventHandler[no_args_event_spec]
151
150
 
152
- # Fired when the pointer is down outside the drawer content. Deprecated.
151
+ # Fired when the pointer is down outside the drawer content.
153
152
  on_pointer_down_outside: EventHandler[no_args_event_spec]
154
153
 
155
- # Fired when interacting outside the drawer content. Deprecated.
154
+ # Fired when interacting outside the drawer content.
156
155
  on_interact_outside: EventHandler[no_args_event_spec]
157
156
 
158
157
  @classmethod
@@ -170,23 +169,6 @@ class DrawerContent(DrawerComponent):
170
169
  Returns:
171
170
  The drawer content.
172
171
  """
173
- deprecated_properties = [
174
- "on_open_auto_focus",
175
- "on_close_auto_focus",
176
- "on_escape_key_down",
177
- "on_pointer_down_outside",
178
- "on_interact_outside",
179
- ]
180
-
181
- for prop in deprecated_properties:
182
- if prop in props:
183
- console.deprecate(
184
- feature_name="drawer content events",
185
- reason=f"The `{prop}` event is deprecated and will be removed in 0.7.0.",
186
- deprecation_version="0.6.3",
187
- removal_version="0.7.0",
188
- )
189
-
190
172
  comp = super().create(*children, **props)
191
173
 
192
174
  return Theme.create(comp)
@@ -112,6 +112,9 @@ class RadixThemesComponent(Component):
112
112
 
113
113
  library = "@radix-ui/themes@^3.0.0"
114
114
 
115
+ # Temporary pin < 3.1.5 until radix-ui/themes#627 is resolved.
116
+ library = library + " && <3.1.5"
117
+
115
118
  # "Fake" prop color_scheme is used to avoid shadowing CSS prop "color".
116
119
  _rename_props: Dict[str, str] = {"colorScheme": "color"}
117
120
 
@@ -12,7 +12,9 @@ from reflex.vars.base import Var
12
12
  from ..base import LiteralAccentColor, RadixThemesComponent
13
13
 
14
14
 
15
- def on_value_change(value: Var[str | List[str]]) -> Tuple[Var[str | List[str]]]:
15
+ def on_value_change(
16
+ value: Var[Union[str, List[str]]],
17
+ ) -> Tuple[Var[Union[str, List[str]]]]:
16
18
  """Handle the on_value_change event.
17
19
 
18
20
  Args:
@@ -13,7 +13,9 @@ from reflex.vars.base import Var
13
13
 
14
14
  from ..base import RadixThemesComponent
15
15
 
16
- def on_value_change(value: Var[str | List[str]]) -> Tuple[Var[str | List[str]]]: ...
16
+ def on_value_change(
17
+ value: Var[Union[str, List[str]]],
18
+ ) -> Tuple[Var[Union[str, List[str]]]]: ...
17
19
 
18
20
  class SegmentedControlRoot(RadixThemesComponent):
19
21
  @overload
@@ -118,7 +120,10 @@ class SegmentedControlRoot(RadixThemesComponent):
118
120
  custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
119
121
  on_blur: Optional[EventType[[], BASE_STATE]] = None,
120
122
  on_change: Optional[
121
- Union[EventType[[], BASE_STATE], EventType[[str | List[str]], BASE_STATE]]
123
+ Union[
124
+ EventType[[], BASE_STATE],
125
+ EventType[[Union[str, List[str]]], BASE_STATE],
126
+ ]
122
127
  ] = None,
123
128
  on_click: Optional[EventType[[], BASE_STATE]] = None,
124
129
  on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
@@ -67,6 +67,9 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
67
67
  # Value of the input
68
68
  value: Var[Union[str, int, float]]
69
69
 
70
+ # References a datalist for suggested options
71
+ list: Var[Union[str, int, bool]]
72
+
70
73
  # Fired when the value of the textarea changes.
71
74
  on_change: EventHandler[input_event]
72
75
 
@@ -119,6 +119,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
119
119
  required: Optional[Union[Var[bool], bool]] = None,
120
120
  type: Optional[Union[Var[str], str]] = None,
121
121
  value: Optional[Union[Var[Union[float, int, str]], float, int, str]] = None,
122
+ list: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
122
123
  access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
123
124
  auto_capitalize: Optional[
124
125
  Union[Var[Union[bool, int, str]], bool, int, str]
@@ -206,6 +207,7 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
206
207
  required: Indicates that the input is required
207
208
  type: Specifies the type of input
208
209
  value: Value of the input
210
+ list: References a datalist for suggested options
209
211
  on_change: Fired when the value of the textarea changes.
210
212
  on_focus: Fired when the textarea is focused.
211
213
  on_blur: Fired when the textarea is blurred.
@@ -454,6 +456,7 @@ class TextField(ComponentNamespace):
454
456
  required: Optional[Union[Var[bool], bool]] = None,
455
457
  type: Optional[Union[Var[str], str]] = None,
456
458
  value: Optional[Union[Var[Union[float, int, str]], float, int, str]] = None,
459
+ list: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
457
460
  access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
458
461
  auto_capitalize: Optional[
459
462
  Union[Var[Union[bool, int, str]], bool, int, str]
@@ -541,6 +544,7 @@ class TextField(ComponentNamespace):
541
544
  required: Indicates that the input is required
542
545
  type: Specifies the type of input
543
546
  value: Value of the input
547
+ list: References a datalist for suggested options
544
548
  on_change: Fired when the value of the textarea changes.
545
549
  on_focus: Fired when the textarea is focused.
546
550
  on_blur: Fired when the textarea is blurred.
@@ -15,6 +15,8 @@ from reflex.utils.imports import ImportVar
15
15
  from reflex.utils.serializers import serializer
16
16
  from reflex.vars import VarData
17
17
  from reflex.vars.base import LiteralVar, Var
18
+ from reflex.vars.function import FunctionVar
19
+ from reflex.vars.object import ObjectVar
18
20
 
19
21
  LiteralPosition = Literal[
20
22
  "top-left",
@@ -232,7 +234,9 @@ class Toaster(Component):
232
234
  return [hook]
233
235
 
234
236
  @staticmethod
235
- def send_toast(message: str = "", level: str | None = None, **props) -> EventSpec:
237
+ def send_toast(
238
+ message: str | Var = "", level: str | None = None, **props
239
+ ) -> EventSpec:
236
240
  """Send a toast message.
237
241
 
238
242
  Args:
@@ -250,20 +254,27 @@ class Toaster(Component):
250
254
  raise ValueError(
251
255
  "Toaster component must be created before sending a toast. (use `rx.toast.provider()`)"
252
256
  )
253
- toast_command = f"{toast_ref}.{level}" if level is not None else toast_ref
254
- if message == "" and ("title" not in props or "description" not in props):
257
+
258
+ toast_command = (
259
+ ObjectVar.__getattr__(toast_ref.to(dict), level) if level else toast_ref
260
+ ).to(FunctionVar)
261
+
262
+ if isinstance(message, Var):
263
+ props.setdefault("title", message)
264
+ message = ""
265
+ elif message == "" and "title" not in props and "description" not in props:
255
266
  raise ValueError("Toast message or title or description must be provided.")
267
+
256
268
  if props:
257
- args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # type: ignore
258
- toast = f"{toast_command}(`{message}`, {str(args)})"
269
+ args = LiteralVar.create(ToastProps(component_name="rx.toast", **props)) # pyright: ignore [reportCallIssue, reportGeneralTypeIssues]
270
+ toast = toast_command.call(message, args)
259
271
  else:
260
- toast = f"{toast_command}(`{message}`)"
272
+ toast = toast_command.call(message)
261
273
 
262
- toast_action = Var(_js_expr=toast)
263
- return run_script(toast_action)
274
+ return run_script(toast)
264
275
 
265
276
  @staticmethod
266
- def toast_info(message: str = "", **kwargs):
277
+ def toast_info(message: str | Var = "", **kwargs):
267
278
  """Display an info toast message.
268
279
 
269
280
  Args:
@@ -276,7 +287,7 @@ class Toaster(Component):
276
287
  return Toaster.send_toast(message, level="info", **kwargs)
277
288
 
278
289
  @staticmethod
279
- def toast_warning(message: str = "", **kwargs):
290
+ def toast_warning(message: str | Var = "", **kwargs):
280
291
  """Display a warning toast message.
281
292
 
282
293
  Args:
@@ -289,7 +300,7 @@ class Toaster(Component):
289
300
  return Toaster.send_toast(message, level="warning", **kwargs)
290
301
 
291
302
  @staticmethod
292
- def toast_error(message: str = "", **kwargs):
303
+ def toast_error(message: str | Var = "", **kwargs):
293
304
  """Display an error toast message.
294
305
 
295
306
  Args:
@@ -302,7 +313,7 @@ class Toaster(Component):
302
313
  return Toaster.send_toast(message, level="error", **kwargs)
303
314
 
304
315
  @staticmethod
305
- def toast_success(message: str = "", **kwargs):
316
+ def toast_success(message: str | Var = "", **kwargs):
306
317
  """Display a success toast message.
307
318
 
308
319
  Args:
@@ -59,16 +59,16 @@ class Toaster(Component):
59
59
  def add_hooks(self) -> list[Var | str]: ...
60
60
  @staticmethod
61
61
  def send_toast(
62
- message: str = "", level: str | None = None, **props
62
+ message: str | Var = "", level: str | None = None, **props
63
63
  ) -> EventSpec: ...
64
64
  @staticmethod
65
- def toast_info(message: str = "", **kwargs): ...
65
+ def toast_info(message: str | Var = "", **kwargs): ...
66
66
  @staticmethod
67
- def toast_warning(message: str = "", **kwargs): ...
67
+ def toast_warning(message: str | Var = "", **kwargs): ...
68
68
  @staticmethod
69
- def toast_error(message: str = "", **kwargs): ...
69
+ def toast_error(message: str | Var = "", **kwargs): ...
70
70
  @staticmethod
71
- def toast_success(message: str = "", **kwargs): ...
71
+ def toast_success(message: str | Var = "", **kwargs): ...
72
72
  @staticmethod
73
73
  def toast_dismiss(id: Var | str | None = None): ...
74
74
  @overload
@@ -176,7 +176,7 @@ class ToastNamespace(ComponentNamespace):
176
176
 
177
177
  @staticmethod
178
178
  def __call__(
179
- message: str = "", level: Optional[str] = None, **props
179
+ message: Union[str, Var] = "", level: Optional[str] = None, **props
180
180
  ) -> "Optional[EventSpec]":
181
181
  """Send a toast message.
182
182
 
reflex/config.py CHANGED
@@ -8,7 +8,9 @@ import importlib
8
8
  import inspect
9
9
  import os
10
10
  import sys
11
+ import threading
11
12
  import urllib.parse
13
+ from importlib.util import find_spec
12
14
  from pathlib import Path
13
15
  from typing import (
14
16
  TYPE_CHECKING,
@@ -452,6 +454,14 @@ class PathExistsFlag:
452
454
  ExistingPath = Annotated[Path, PathExistsFlag]
453
455
 
454
456
 
457
+ class PerformanceMode(enum.Enum):
458
+ """Performance mode for the app."""
459
+
460
+ WARN = "warn"
461
+ RAISE = "raise"
462
+ OFF = "off"
463
+
464
+
455
465
  class EnvironmentVariables:
456
466
  """Environment variables class to instantiate environment variables."""
457
467
 
@@ -545,6 +555,15 @@ class EnvironmentVariables:
545
555
  # Where to save screenshots when tests fail.
546
556
  SCREENSHOT_DIR: EnvVar[Optional[Path]] = env_var(None)
547
557
 
558
+ # Whether to check for outdated package versions.
559
+ REFLEX_CHECK_LATEST_VERSION: EnvVar[bool] = env_var(True)
560
+
561
+ # In which performance mode to run the app.
562
+ REFLEX_PERF_MODE: EnvVar[Optional[PerformanceMode]] = env_var(PerformanceMode.WARN)
563
+
564
+ # The maximum size of the reflex state in kilobytes.
565
+ REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
566
+
548
567
 
549
568
  environment = EnvironmentVariables()
550
569
 
@@ -798,24 +817,56 @@ class Config(Base):
798
817
  self._replace_defaults(**kwargs)
799
818
 
800
819
 
801
- def get_config(reload: bool = False) -> Config:
820
+ def _get_config() -> Config:
802
821
  """Get the app config.
803
822
 
804
- Args:
805
- reload: Re-import the rxconfig module from disk
806
-
807
823
  Returns:
808
824
  The app config.
809
825
  """
810
- sys.path.insert(0, os.getcwd())
811
826
  # only import the module if it exists. If a module spec exists then
812
827
  # the module exists.
813
- spec = importlib.util.find_spec(constants.Config.MODULE) # type: ignore
828
+ spec = find_spec(constants.Config.MODULE)
814
829
  if not spec:
815
830
  # we need this condition to ensure that a ModuleNotFound error is not thrown when
816
- # running unit/integration tests.
831
+ # running unit/integration tests or during `reflex init`.
817
832
  return Config(app_name="")
818
833
  rxconfig = importlib.import_module(constants.Config.MODULE)
819
- if reload:
820
- importlib.reload(rxconfig)
821
834
  return rxconfig.config
835
+
836
+
837
+ # Protect sys.path from concurrent modification
838
+ _config_lock = threading.RLock()
839
+
840
+
841
+ def get_config(reload: bool = False) -> Config:
842
+ """Get the app config.
843
+
844
+ Args:
845
+ reload: Re-import the rxconfig module from disk
846
+
847
+ Returns:
848
+ The app config.
849
+ """
850
+ cached_rxconfig = sys.modules.get(constants.Config.MODULE, None)
851
+ if cached_rxconfig is not None:
852
+ if reload:
853
+ # Remove any cached module when `reload` is requested.
854
+ del sys.modules[constants.Config.MODULE]
855
+ else:
856
+ return cached_rxconfig.config
857
+
858
+ with _config_lock:
859
+ sys_path = sys.path.copy()
860
+ sys.path.clear()
861
+ sys.path.append(os.getcwd())
862
+ try:
863
+ # Try to import the module with only the current directory in the path.
864
+ return _get_config()
865
+ except Exception:
866
+ # If the module import fails, try to import with the original sys.path.
867
+ sys.path.extend(sys_path)
868
+ return _get_config()
869
+ finally:
870
+ # Restore the original sys.path.
871
+ sys.path.clear()
872
+ sys.path.extend(sys_path)
reflex/constants/base.py CHANGED
@@ -97,6 +97,18 @@ class Templates(SimpleNamespace):
97
97
  # The default template
98
98
  DEFAULT = "blank"
99
99
 
100
+ # The AI template
101
+ AI = "ai"
102
+
103
+ # The option for the user to choose a remote template.
104
+ CHOOSE_TEMPLATES = "choose-templates"
105
+
106
+ # The URL to find reflex templates.
107
+ REFLEX_TEMPLATES_URL = "https://reflex.dev/templates"
108
+
109
+ # Demo url for the default template.
110
+ DEFAULT_TEMPLATE_URL = "https://blank-template.reflex.run"
111
+
100
112
  # The reflex.build frontend host
101
113
  REFLEX_BUILD_FRONTEND = "https://flexgen.reflex.run"
102
114
 
@@ -184,15 +184,15 @@ class PackageJson(SimpleNamespace):
184
184
  "json5": "2.2.3",
185
185
  "next": "14.2.16",
186
186
  "next-sitemap": "4.2.3",
187
- "next-themes": "0.3.0",
187
+ "next-themes": "0.4.3",
188
188
  "react": "18.3.1",
189
189
  "react-dom": "18.3.1",
190
190
  "react-focus-lock": "2.13.2",
191
191
  "socket.io-client": "4.8.1",
192
- "universal-cookie": "7.2.1",
192
+ "universal-cookie": "7.2.2",
193
193
  }
194
194
  DEV_DEPENDENCIES = {
195
195
  "autoprefixer": "10.4.20",
196
- "postcss": "8.4.47",
196
+ "postcss": "8.4.49",
197
197
  "postcss-import": "16.1.0",
198
198
  }
reflex/constants/style.py CHANGED
@@ -7,7 +7,7 @@ class Tailwind(SimpleNamespace):
7
7
  """Tailwind constants."""
8
8
 
9
9
  # The Tailwindcss version
10
- VERSION = "tailwindcss@3.4.14"
10
+ VERSION = "tailwindcss@3.4.15"
11
11
  # The Tailwind config.
12
12
  CONFIG = "tailwind.config.js"
13
13
  # Default Tailwind content paths
reflex/event.py CHANGED
@@ -45,6 +45,8 @@ from reflex.vars import VarData
45
45
  from reflex.vars.base import LiteralVar, Var
46
46
  from reflex.vars.function import (
47
47
  ArgsFunctionOperation,
48
+ ArgsFunctionOperationBuilder,
49
+ BuilderFunctionVar,
48
50
  FunctionArgs,
49
51
  FunctionStringVar,
50
52
  FunctionVar,
@@ -179,6 +181,18 @@ class EventActionsMixin:
179
181
  event_actions={"debounce": delay_ms, **self.event_actions},
180
182
  )
181
183
 
184
+ @property
185
+ def temporal(self):
186
+ """Do not queue the event if the backend is down.
187
+
188
+ Returns:
189
+ New EventHandler-like with temporal set to True.
190
+ """
191
+ return dataclasses.replace(
192
+ self,
193
+ event_actions={"temporal": True, **self.event_actions},
194
+ )
195
+
182
196
 
183
197
  @dataclasses.dataclass(
184
198
  init=True,
@@ -797,8 +811,7 @@ def scroll_to(elem_id: str, align_to_top: bool | Var[bool] = True) -> EventSpec:
797
811
  get_element_by_id = FunctionStringVar.create("document.getElementById")
798
812
 
799
813
  return run_script(
800
- get_element_by_id(elem_id)
801
- .call(elem_id)
814
+ get_element_by_id.call(elem_id)
802
815
  .to(ObjectVar)
803
816
  .scrollIntoView.to(FunctionVar)
804
817
  .call(align_to_top),
@@ -899,7 +912,7 @@ def remove_session_storage(key: str) -> EventSpec:
899
912
  )
900
913
 
901
914
 
902
- def set_clipboard(content: str) -> EventSpec:
915
+ def set_clipboard(content: Union[str, Var[str]]) -> EventSpec:
903
916
  """Set the text in content in the clipboard.
904
917
 
905
918
  Args:
@@ -1345,6 +1358,10 @@ def check_fn_match_arg_spec(
1345
1358
  EventFnArgMismatch: Raised if the number of mandatory arguments do not match
1346
1359
  """
1347
1360
  user_args = inspect.getfullargspec(user_func).args
1361
+ # Drop the first argument if it's a bound method
1362
+ if inspect.ismethod(user_func) and user_func.__self__ is not None:
1363
+ user_args = user_args[1:]
1364
+
1348
1365
  user_default_args = inspect.getfullargspec(user_func).defaults
1349
1366
  number_of_user_args = len(user_args) - number_of_bound_args
1350
1367
  number_of_user_default_args = len(user_default_args) if user_default_args else 0
@@ -1580,7 +1597,7 @@ class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
1580
1597
  )
1581
1598
 
1582
1599
 
1583
- class EventChainVar(FunctionVar, python_types=EventChain):
1600
+ class EventChainVar(BuilderFunctionVar, python_types=EventChain):
1584
1601
  """Base class for event chain vars."""
1585
1602
 
1586
1603
 
@@ -1592,7 +1609,7 @@ class EventChainVar(FunctionVar, python_types=EventChain):
1592
1609
  # Note: LiteralVar is second in the inheritance list allowing it act like a
1593
1610
  # CachedVarOperation (ArgsFunctionOperation) and get the _js_expr from the
1594
1611
  # _cached_var_name property.
1595
- class LiteralEventChainVar(ArgsFunctionOperation, LiteralVar, EventChainVar):
1612
+ class LiteralEventChainVar(ArgsFunctionOperationBuilder, LiteralVar, EventChainVar):
1596
1613
  """A literal event chain var."""
1597
1614
 
1598
1615
  _var_value: EventChain = dataclasses.field(default=None) # type: ignore
@@ -1,14 +1,15 @@
1
1
  """Helper functions for adding assets to the app."""
2
2
 
3
- import inspect
4
- from pathlib import Path
5
3
  from typing import Optional
6
4
 
7
- from reflex import constants
5
+ from reflex import assets
6
+ from reflex.utils import console
8
7
 
9
8
 
10
9
  def asset(relative_filename: str, subfolder: Optional[str] = None) -> str:
11
- """Add an asset to the app.
10
+ """DEPRECATED: use `rx.asset` with `shared=True` instead.
11
+
12
+ Add an asset to the app.
12
13
  Place the file next to your including python file.
13
14
  Copies the file to the app's external assets directory.
14
15
 
@@ -22,38 +23,15 @@ def asset(relative_filename: str, subfolder: Optional[str] = None) -> str:
22
23
  relative_filename: The relative filename of the asset.
23
24
  subfolder: The directory to place the asset in.
24
25
 
25
- Raises:
26
- FileNotFoundError: If the file does not exist.
27
- ValueError: If the module is None.
28
-
29
26
  Returns:
30
27
  The relative URL to the copied asset.
31
28
  """
32
- # Determine the file by which the asset is exposed.
33
- calling_file = inspect.stack()[1].filename
34
- module = inspect.getmodule(inspect.stack()[1][0])
35
- if module is None:
36
- raise ValueError("Module is None")
37
- caller_module_path = module.__name__.replace(".", "/")
38
-
39
- subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path
40
-
41
- src_file = Path(calling_file).parent / relative_filename
42
-
43
- assets = constants.Dirs.APP_ASSETS
44
- external = constants.Dirs.EXTERNAL_APP_ASSETS
45
-
46
- if not src_file.exists():
47
- raise FileNotFoundError(f"File not found: {src_file}")
48
-
49
- # Create the asset folder in the currently compiling app.
50
- asset_folder = Path.cwd() / assets / external / subfolder
51
- asset_folder.mkdir(parents=True, exist_ok=True)
52
-
53
- dst_file = asset_folder / relative_filename
54
-
55
- if not dst_file.exists():
56
- dst_file.symlink_to(src_file)
57
-
58
- asset_url = f"/{external}/{subfolder}/{relative_filename}"
59
- return asset_url
29
+ console.deprecate(
30
+ feature_name="rx._x.asset",
31
+ reason="Use `rx.asset` with `shared=True` instead of `rx._x.asset`.",
32
+ deprecation_version="0.6.6",
33
+ removal_version="0.7.0",
34
+ )
35
+ return assets.asset(
36
+ relative_filename, shared=True, subfolder=subfolder, _stack_level=2
37
+ )