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
reflex/utils/redir.py CHANGED
@@ -10,6 +10,18 @@ from .. import constants
10
10
  from . import console
11
11
 
12
12
 
13
+ def open_browser(target_url: str) -> None:
14
+ """Open a browser window to target_url.
15
+
16
+ Args:
17
+ target_url: The URL to open in the browser.
18
+ """
19
+ if not webbrowser.open(target_url):
20
+ console.warn(
21
+ f"Unable to automatically open the browser. Please navigate to {target_url} in your browser."
22
+ )
23
+
24
+
13
25
  def open_browser_and_wait(
14
26
  target_url: str, poll_url: str, interval: int = 2
15
27
  ) -> httpx.Response:
@@ -23,10 +35,7 @@ def open_browser_and_wait(
23
35
  Returns:
24
36
  The response from the poll_url.
25
37
  """
26
- if not webbrowser.open(target_url):
27
- console.warn(
28
- f"Unable to automatically open the browser. Please navigate to {target_url} in your browser."
29
- )
38
+ open_browser(target_url)
30
39
  console.info("[b]Complete the workflow in the browser to continue.[/b]")
31
40
  while True:
32
41
  try:
@@ -263,7 +263,58 @@ def serialize_base(value: Base) -> dict:
263
263
  Returns:
264
264
  The serialized Base.
265
265
  """
266
- return {k: v for k, v in value.dict().items() if not callable(v)}
266
+ from reflex.vars.base import Var
267
+
268
+ return {
269
+ k: v for k, v in value.dict().items() if isinstance(v, Var) or not callable(v)
270
+ }
271
+
272
+
273
+ try:
274
+ from pydantic.v1 import BaseModel as BaseModelV1
275
+
276
+ @serializer(to=dict)
277
+ def serialize_base_model_v1(model: BaseModelV1) -> dict:
278
+ """Serialize a pydantic v1 BaseModel instance.
279
+
280
+ Args:
281
+ model: The BaseModel to serialize.
282
+
283
+ Returns:
284
+ The serialized BaseModel.
285
+ """
286
+ return model.dict()
287
+
288
+ from pydantic import BaseModel as BaseModelV2
289
+
290
+ if BaseModelV1 is not BaseModelV2:
291
+
292
+ @serializer(to=dict)
293
+ def serialize_base_model_v2(model: BaseModelV2) -> dict:
294
+ """Serialize a pydantic v2 BaseModel instance.
295
+
296
+ Args:
297
+ model: The BaseModel to serialize.
298
+
299
+ Returns:
300
+ The serialized BaseModel.
301
+ """
302
+ return model.model_dump()
303
+ except ImportError:
304
+ # Older pydantic v1 import
305
+ from pydantic import BaseModel as BaseModelV1
306
+
307
+ @serializer(to=dict)
308
+ def serialize_base_model_v1(model: BaseModelV1) -> dict:
309
+ """Serialize a pydantic v1 BaseModel instance.
310
+
311
+ Args:
312
+ model: The BaseModel to serialize.
313
+
314
+ Returns:
315
+ The serialized BaseModel.
316
+ """
317
+ return model.dict()
267
318
 
268
319
 
269
320
  @serializer
reflex/utils/telemetry.py CHANGED
@@ -51,7 +51,8 @@ def get_python_version() -> str:
51
51
  Returns:
52
52
  The Python version.
53
53
  """
54
- return platform.python_version()
54
+ # Remove the "+" from the version string in case user is using a pre-release version.
55
+ return platform.python_version().rstrip("+")
55
56
 
56
57
 
57
58
  def get_reflex_version() -> str:
reflex/utils/types.py CHANGED
@@ -14,9 +14,11 @@ from typing import (
14
14
  Callable,
15
15
  ClassVar,
16
16
  Dict,
17
+ FrozenSet,
17
18
  Iterable,
18
19
  List,
19
20
  Literal,
21
+ Mapping,
20
22
  Optional,
21
23
  Sequence,
22
24
  Tuple,
@@ -29,6 +31,7 @@ from typing import (
29
31
  from typing import get_origin as get_origin_og
30
32
 
31
33
  import sqlalchemy
34
+ from typing_extensions import is_typeddict
32
35
 
33
36
  import reflex
34
37
  from reflex.components.core.breakpoints import Breakpoints
@@ -494,6 +497,14 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None)
494
497
  if isinstance(instance, Breakpoints):
495
498
  return _breakpoints_satisfies_typing(cls_check, instance)
496
499
 
500
+ if isinstance(cls_check_base, tuple):
501
+ cls_check_base = tuple(
502
+ cls_check_one if not is_typeddict(cls_check_one) else dict
503
+ for cls_check_one in cls_check_base
504
+ )
505
+ if is_typeddict(cls_check_base):
506
+ cls_check_base = dict
507
+
497
508
  # Check if the types match.
498
509
  try:
499
510
  return cls_check_base == Any or issubclass(cls_base, cls_check_base)
@@ -503,6 +514,36 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None)
503
514
  raise TypeError(f"Invalid type for issubclass: {cls_base}") from te
504
515
 
505
516
 
517
+ def does_obj_satisfy_typed_dict(obj: Any, cls: GenericType) -> bool:
518
+ """Check if an object satisfies a typed dict.
519
+
520
+ Args:
521
+ obj: The object to check.
522
+ cls: The typed dict to check against.
523
+
524
+ Returns:
525
+ Whether the object satisfies the typed dict.
526
+ """
527
+ if not isinstance(obj, Mapping):
528
+ return False
529
+
530
+ key_names_to_values = get_type_hints(cls)
531
+ required_keys: FrozenSet[str] = getattr(cls, "__required_keys__", frozenset())
532
+
533
+ if not all(
534
+ isinstance(key, str)
535
+ and key in key_names_to_values
536
+ and _isinstance(value, key_names_to_values[key])
537
+ for key, value in obj.items()
538
+ ):
539
+ return False
540
+
541
+ # TODO in 3.14: Implement https://peps.python.org/pep-0728/ if it's approved
542
+
543
+ # required keys are all present
544
+ return required_keys.issubset(required_keys)
545
+
546
+
506
547
  def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
507
548
  """Check if an object is an instance of a class.
508
549
 
@@ -529,6 +570,16 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
529
570
  origin = get_origin(cls)
530
571
 
531
572
  if origin is None:
573
+ # cls is a typed dict
574
+ if is_typeddict(cls):
575
+ if nested:
576
+ return does_obj_satisfy_typed_dict(obj, cls)
577
+ return isinstance(obj, dict)
578
+
579
+ # cls is a float
580
+ if cls is float:
581
+ return isinstance(obj, (float, int))
582
+
532
583
  # cls is a simple class
533
584
  return isinstance(obj, cls)
534
585
 
@@ -553,7 +604,7 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
553
604
  and len(obj) == len(args)
554
605
  and all(_isinstance(item, arg) for item, arg in zip(obj, args))
555
606
  )
556
- if origin is dict:
607
+ if origin in (dict, Breakpoints):
557
608
  return isinstance(obj, dict) and all(
558
609
  _isinstance(key, args[0]) and _isinstance(value, args[1])
559
610
  for key, value in obj.items()
reflex/vars/base.py CHANGED
@@ -361,21 +361,29 @@ class Var(Generic[VAR_TYPE]):
361
361
  return False
362
362
 
363
363
  def __init_subclass__(
364
- cls, python_types: Tuple[GenericType, ...] | GenericType = types.Unset, **kwargs
364
+ cls,
365
+ python_types: Tuple[GenericType, ...] | GenericType = types.Unset(),
366
+ default_type: GenericType = types.Unset(),
367
+ **kwargs,
365
368
  ):
366
369
  """Initialize the subclass.
367
370
 
368
371
  Args:
369
372
  python_types: The python types that the var represents.
373
+ default_type: The default type of the var. Defaults to the first python type.
370
374
  **kwargs: Additional keyword arguments.
371
375
  """
372
376
  super().__init_subclass__(**kwargs)
373
377
 
374
- if python_types is not types.Unset:
378
+ if python_types or default_type:
375
379
  python_types = (
376
- python_types if isinstance(python_types, tuple) else (python_types,)
380
+ (python_types if isinstance(python_types, tuple) else (python_types,))
381
+ if python_types
382
+ else ()
377
383
  )
378
384
 
385
+ default_type = default_type or (python_types[0] if python_types else Any)
386
+
379
387
  @dataclasses.dataclass(
380
388
  eq=False,
381
389
  frozen=True,
@@ -388,7 +396,7 @@ class Var(Generic[VAR_TYPE]):
388
396
  default=Var(_js_expr="null", _var_type=None),
389
397
  )
390
398
 
391
- _default_var_type: ClassVar[GenericType] = python_types[0]
399
+ _default_var_type: ClassVar[GenericType] = default_type
392
400
 
393
401
  ToVarOperation.__name__ = f'To{cls.__name__.removesuffix("Var")}Operation'
394
402
 
@@ -588,6 +596,12 @@ class Var(Generic[VAR_TYPE]):
588
596
  output: type[list] | type[tuple] | type[set],
589
597
  ) -> ArrayVar: ...
590
598
 
599
+ @overload
600
+ def to(
601
+ self,
602
+ output: type[dict],
603
+ ) -> ObjectVar[dict]: ...
604
+
591
605
  @overload
592
606
  def to(
593
607
  self, output: Type[ObjectVar], var_type: Type[VAR_INSIDE]
reflex/vars/function.py CHANGED
@@ -4,32 +4,177 @@ from __future__ import annotations
4
4
 
5
5
  import dataclasses
6
6
  import sys
7
- from typing import Any, Callable, Optional, Sequence, Tuple, Type, Union
7
+ from typing import Any, Callable, Optional, Sequence, Tuple, Type, Union, overload
8
+
9
+ from typing_extensions import Concatenate, Generic, ParamSpec, Protocol, TypeVar
8
10
 
9
11
  from reflex.utils import format
10
12
  from reflex.utils.types import GenericType
11
13
 
12
14
  from .base import CachedVarOperation, LiteralVar, Var, VarData, cached_property_no_lock
13
15
 
16
+ P = ParamSpec("P")
17
+ V1 = TypeVar("V1")
18
+ V2 = TypeVar("V2")
19
+ V3 = TypeVar("V3")
20
+ V4 = TypeVar("V4")
21
+ V5 = TypeVar("V5")
22
+ V6 = TypeVar("V6")
23
+ R = TypeVar("R")
24
+
25
+
26
+ class ReflexCallable(Protocol[P, R]):
27
+ """Protocol for a callable."""
28
+
29
+ __call__: Callable[P, R]
30
+
14
31
 
15
- class FunctionVar(Var[Callable], python_types=Callable):
32
+ CALLABLE_TYPE = TypeVar("CALLABLE_TYPE", bound=ReflexCallable, infer_variance=True)
33
+ OTHER_CALLABLE_TYPE = TypeVar(
34
+ "OTHER_CALLABLE_TYPE", bound=ReflexCallable, infer_variance=True
35
+ )
36
+
37
+
38
+ class FunctionVar(Var[CALLABLE_TYPE], default_type=ReflexCallable[Any, Any]):
16
39
  """Base class for immutable function vars."""
17
40
 
18
- def __call__(self, *args: Var | Any) -> ArgsFunctionOperation:
19
- """Call the function with the given arguments.
41
+ @overload
42
+ def partial(self) -> FunctionVar[CALLABLE_TYPE]: ...
43
+
44
+ @overload
45
+ def partial(
46
+ self: FunctionVar[ReflexCallable[Concatenate[V1, P], R]],
47
+ arg1: Union[V1, Var[V1]],
48
+ ) -> FunctionVar[ReflexCallable[P, R]]: ...
49
+
50
+ @overload
51
+ def partial(
52
+ self: FunctionVar[ReflexCallable[Concatenate[V1, V2, P], R]],
53
+ arg1: Union[V1, Var[V1]],
54
+ arg2: Union[V2, Var[V2]],
55
+ ) -> FunctionVar[ReflexCallable[P, R]]: ...
56
+
57
+ @overload
58
+ def partial(
59
+ self: FunctionVar[ReflexCallable[Concatenate[V1, V2, V3, P], R]],
60
+ arg1: Union[V1, Var[V1]],
61
+ arg2: Union[V2, Var[V2]],
62
+ arg3: Union[V3, Var[V3]],
63
+ ) -> FunctionVar[ReflexCallable[P, R]]: ...
64
+
65
+ @overload
66
+ def partial(
67
+ self: FunctionVar[ReflexCallable[Concatenate[V1, V2, V3, V4, P], R]],
68
+ arg1: Union[V1, Var[V1]],
69
+ arg2: Union[V2, Var[V2]],
70
+ arg3: Union[V3, Var[V3]],
71
+ arg4: Union[V4, Var[V4]],
72
+ ) -> FunctionVar[ReflexCallable[P, R]]: ...
73
+
74
+ @overload
75
+ def partial(
76
+ self: FunctionVar[ReflexCallable[Concatenate[V1, V2, V3, V4, V5, P], R]],
77
+ arg1: Union[V1, Var[V1]],
78
+ arg2: Union[V2, Var[V2]],
79
+ arg3: Union[V3, Var[V3]],
80
+ arg4: Union[V4, Var[V4]],
81
+ arg5: Union[V5, Var[V5]],
82
+ ) -> FunctionVar[ReflexCallable[P, R]]: ...
83
+
84
+ @overload
85
+ def partial(
86
+ self: FunctionVar[ReflexCallable[Concatenate[V1, V2, V3, V4, V5, V6, P], R]],
87
+ arg1: Union[V1, Var[V1]],
88
+ arg2: Union[V2, Var[V2]],
89
+ arg3: Union[V3, Var[V3]],
90
+ arg4: Union[V4, Var[V4]],
91
+ arg5: Union[V5, Var[V5]],
92
+ arg6: Union[V6, Var[V6]],
93
+ ) -> FunctionVar[ReflexCallable[P, R]]: ...
94
+
95
+ @overload
96
+ def partial(
97
+ self: FunctionVar[ReflexCallable[P, R]], *args: Var | Any
98
+ ) -> FunctionVar[ReflexCallable[P, R]]: ...
99
+
100
+ @overload
101
+ def partial(self, *args: Var | Any) -> FunctionVar: ...
102
+
103
+ def partial(self, *args: Var | Any) -> FunctionVar: # type: ignore
104
+ """Partially apply the function with the given arguments.
20
105
 
21
106
  Args:
22
- *args: The arguments to call the function with.
107
+ *args: The arguments to partially apply the function with.
23
108
 
24
109
  Returns:
25
- The function call operation.
110
+ The partially applied function.
26
111
  """
112
+ if not args:
113
+ return ArgsFunctionOperation.create((), self)
27
114
  return ArgsFunctionOperation.create(
28
115
  ("...args",),
29
116
  VarOperationCall.create(self, *args, Var(_js_expr="...args")),
30
117
  )
31
118
 
32
- def call(self, *args: Var | Any) -> VarOperationCall:
119
+ @overload
120
+ def call(
121
+ self: FunctionVar[ReflexCallable[[V1], R]], arg1: Union[V1, Var[V1]]
122
+ ) -> VarOperationCall[[V1], R]: ...
123
+
124
+ @overload
125
+ def call(
126
+ self: FunctionVar[ReflexCallable[[V1, V2], R]],
127
+ arg1: Union[V1, Var[V1]],
128
+ arg2: Union[V2, Var[V2]],
129
+ ) -> VarOperationCall[[V1, V2], R]: ...
130
+
131
+ @overload
132
+ def call(
133
+ self: FunctionVar[ReflexCallable[[V1, V2, V3], R]],
134
+ arg1: Union[V1, Var[V1]],
135
+ arg2: Union[V2, Var[V2]],
136
+ arg3: Union[V3, Var[V3]],
137
+ ) -> VarOperationCall[[V1, V2, V3], R]: ...
138
+
139
+ @overload
140
+ def call(
141
+ self: FunctionVar[ReflexCallable[[V1, V2, V3, V4], R]],
142
+ arg1: Union[V1, Var[V1]],
143
+ arg2: Union[V2, Var[V2]],
144
+ arg3: Union[V3, Var[V3]],
145
+ arg4: Union[V4, Var[V4]],
146
+ ) -> VarOperationCall[[V1, V2, V3, V4], R]: ...
147
+
148
+ @overload
149
+ def call(
150
+ self: FunctionVar[ReflexCallable[[V1, V2, V3, V4, V5], R]],
151
+ arg1: Union[V1, Var[V1]],
152
+ arg2: Union[V2, Var[V2]],
153
+ arg3: Union[V3, Var[V3]],
154
+ arg4: Union[V4, Var[V4]],
155
+ arg5: Union[V5, Var[V5]],
156
+ ) -> VarOperationCall[[V1, V2, V3, V4, V5], R]: ...
157
+
158
+ @overload
159
+ def call(
160
+ self: FunctionVar[ReflexCallable[[V1, V2, V3, V4, V5, V6], R]],
161
+ arg1: Union[V1, Var[V1]],
162
+ arg2: Union[V2, Var[V2]],
163
+ arg3: Union[V3, Var[V3]],
164
+ arg4: Union[V4, Var[V4]],
165
+ arg5: Union[V5, Var[V5]],
166
+ arg6: Union[V6, Var[V6]],
167
+ ) -> VarOperationCall[[V1, V2, V3, V4, V5, V6], R]: ...
168
+
169
+ @overload
170
+ def call(
171
+ self: FunctionVar[ReflexCallable[P, R]], *args: Var | Any
172
+ ) -> VarOperationCall[P, R]: ...
173
+
174
+ @overload
175
+ def call(self, *args: Var | Any) -> Var: ...
176
+
177
+ def call(self, *args: Var | Any) -> Var: # type: ignore
33
178
  """Call the function with the given arguments.
34
179
 
35
180
  Args:
@@ -38,19 +183,29 @@ class FunctionVar(Var[Callable], python_types=Callable):
38
183
  Returns:
39
184
  The function call operation.
40
185
  """
41
- return VarOperationCall.create(self, *args)
186
+ return VarOperationCall.create(self, *args).guess_type()
187
+
188
+ __call__ = call
189
+
190
+
191
+ class BuilderFunctionVar(
192
+ FunctionVar[CALLABLE_TYPE], default_type=ReflexCallable[Any, Any]
193
+ ):
194
+ """Base class for immutable function vars with the builder pattern."""
195
+
196
+ __call__ = FunctionVar.partial
42
197
 
43
198
 
44
- class FunctionStringVar(FunctionVar):
199
+ class FunctionStringVar(FunctionVar[CALLABLE_TYPE]):
45
200
  """Base class for immutable function vars from a string."""
46
201
 
47
202
  @classmethod
48
203
  def create(
49
204
  cls,
50
205
  func: str,
51
- _var_type: Type[Callable] = Callable,
206
+ _var_type: Type[OTHER_CALLABLE_TYPE] = ReflexCallable[Any, Any],
52
207
  _var_data: VarData | None = None,
53
- ) -> FunctionStringVar:
208
+ ) -> FunctionStringVar[OTHER_CALLABLE_TYPE]:
54
209
  """Create a new function var from a string.
55
210
 
56
211
  Args:
@@ -60,7 +215,7 @@ class FunctionStringVar(FunctionVar):
60
215
  Returns:
61
216
  The function var.
62
217
  """
63
- return cls(
218
+ return FunctionStringVar(
64
219
  _js_expr=func,
65
220
  _var_type=_var_type,
66
221
  _var_data=_var_data,
@@ -72,10 +227,10 @@ class FunctionStringVar(FunctionVar):
72
227
  frozen=True,
73
228
  **{"slots": True} if sys.version_info >= (3, 10) else {},
74
229
  )
75
- class VarOperationCall(CachedVarOperation, Var):
230
+ class VarOperationCall(Generic[P, R], CachedVarOperation, Var[R]):
76
231
  """Base class for immutable vars that are the result of a function call."""
77
232
 
78
- _func: Optional[FunctionVar] = dataclasses.field(default=None)
233
+ _func: Optional[FunctionVar[ReflexCallable[P, R]]] = dataclasses.field(default=None)
79
234
  _args: Tuple[Union[Var, Any], ...] = dataclasses.field(default_factory=tuple)
80
235
 
81
236
  @cached_property_no_lock
@@ -103,7 +258,7 @@ class VarOperationCall(CachedVarOperation, Var):
103
258
  @classmethod
104
259
  def create(
105
260
  cls,
106
- func: FunctionVar,
261
+ func: FunctionVar[ReflexCallable[P, R]],
107
262
  *args: Var | Any,
108
263
  _var_type: GenericType = Any,
109
264
  _var_data: VarData | None = None,
@@ -118,9 +273,15 @@ class VarOperationCall(CachedVarOperation, Var):
118
273
  Returns:
119
274
  The function call var.
120
275
  """
276
+ function_return_type = (
277
+ func._var_type.__args__[1]
278
+ if getattr(func._var_type, "__args__", None)
279
+ else Any
280
+ )
281
+ var_type = _var_type if _var_type is not Any else function_return_type
121
282
  return cls(
122
283
  _js_expr="",
123
- _var_type=_var_type,
284
+ _var_type=var_type,
124
285
  _var_data=_var_data,
125
286
  _func=func,
126
287
  _args=args,
@@ -157,6 +318,33 @@ class FunctionArgs:
157
318
  rest: Optional[str] = None
158
319
 
159
320
 
321
+ def format_args_function_operation(
322
+ args: FunctionArgs, return_expr: Var | Any, explicit_return: bool
323
+ ) -> str:
324
+ """Format an args function operation.
325
+
326
+ Args:
327
+ args: The function arguments.
328
+ return_expr: The return expression.
329
+ explicit_return: Whether to use explicit return syntax.
330
+
331
+ Returns:
332
+ The formatted args function operation.
333
+ """
334
+ arg_names_str = ", ".join(
335
+ [arg if isinstance(arg, str) else arg.to_javascript() for arg in args.args]
336
+ ) + (f", ...{args.rest}" if args.rest else "")
337
+
338
+ return_expr_str = str(LiteralVar.create(return_expr))
339
+
340
+ # Wrap return expression in curly braces if explicit return syntax is used.
341
+ return_expr_str_wrapped = (
342
+ format.wrap(return_expr_str, "{", "}") if explicit_return else return_expr_str
343
+ )
344
+
345
+ return f"(({arg_names_str}) => {return_expr_str_wrapped})"
346
+
347
+
160
348
  @dataclasses.dataclass(
161
349
  eq=False,
162
350
  frozen=True,
@@ -176,24 +364,10 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
176
364
  Returns:
177
365
  The name of the var.
178
366
  """
179
- arg_names_str = ", ".join(
180
- [
181
- arg if isinstance(arg, str) else arg.to_javascript()
182
- for arg in self._args.args
183
- ]
184
- ) + (f", ...{self._args.rest}" if self._args.rest else "")
185
-
186
- return_expr_str = str(LiteralVar.create(self._return_expr))
187
-
188
- # Wrap return expression in curly braces if explicit return syntax is used.
189
- return_expr_str_wrapped = (
190
- format.wrap(return_expr_str, "{", "}")
191
- if self._explicit_return
192
- else return_expr_str
367
+ return format_args_function_operation(
368
+ self._args, self._return_expr, self._explicit_return
193
369
  )
194
370
 
195
- return f"(({arg_names_str}) => {return_expr_str_wrapped})"
196
-
197
371
  @classmethod
198
372
  def create(
199
373
  cls,
@@ -203,7 +377,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
203
377
  explicit_return: bool = False,
204
378
  _var_type: GenericType = Callable,
205
379
  _var_data: VarData | None = None,
206
- ) -> ArgsFunctionOperation:
380
+ ):
207
381
  """Create a new function var.
208
382
 
209
383
  Args:
@@ -226,8 +400,80 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
226
400
  )
227
401
 
228
402
 
229
- JSON_STRINGIFY = FunctionStringVar.create("JSON.stringify")
230
- ARRAY_ISARRAY = FunctionStringVar.create("Array.isArray")
231
- PROTOTYPE_TO_STRING = FunctionStringVar.create(
232
- "((__to_string) => __to_string.toString())"
403
+ @dataclasses.dataclass(
404
+ eq=False,
405
+ frozen=True,
406
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
233
407
  )
408
+ class ArgsFunctionOperationBuilder(CachedVarOperation, BuilderFunctionVar):
409
+ """Base class for immutable function defined via arguments and return expression with the builder pattern."""
410
+
411
+ _args: FunctionArgs = dataclasses.field(default_factory=FunctionArgs)
412
+ _return_expr: Union[Var, Any] = dataclasses.field(default=None)
413
+ _explicit_return: bool = dataclasses.field(default=False)
414
+
415
+ @cached_property_no_lock
416
+ def _cached_var_name(self) -> str:
417
+ """The name of the var.
418
+
419
+ Returns:
420
+ The name of the var.
421
+ """
422
+ return format_args_function_operation(
423
+ self._args, self._return_expr, self._explicit_return
424
+ )
425
+
426
+ @classmethod
427
+ def create(
428
+ cls,
429
+ args_names: Sequence[Union[str, DestructuredArg]],
430
+ return_expr: Var | Any,
431
+ rest: str | None = None,
432
+ explicit_return: bool = False,
433
+ _var_type: GenericType = Callable,
434
+ _var_data: VarData | None = None,
435
+ ):
436
+ """Create a new function var.
437
+
438
+ Args:
439
+ args_names: The names of the arguments.
440
+ return_expr: The return expression of the function.
441
+ rest: The name of the rest argument.
442
+ explicit_return: Whether to use explicit return syntax.
443
+ _var_data: Additional hooks and imports associated with the Var.
444
+
445
+ Returns:
446
+ The function var.
447
+ """
448
+ return cls(
449
+ _js_expr="",
450
+ _var_type=_var_type,
451
+ _var_data=_var_data,
452
+ _args=FunctionArgs(args=tuple(args_names), rest=rest),
453
+ _return_expr=return_expr,
454
+ _explicit_return=explicit_return,
455
+ )
456
+
457
+
458
+ if python_version := sys.version_info[:2] >= (3, 10):
459
+ JSON_STRINGIFY = FunctionStringVar.create(
460
+ "JSON.stringify", _var_type=ReflexCallable[[Any], str]
461
+ )
462
+ ARRAY_ISARRAY = FunctionStringVar.create(
463
+ "Array.isArray", _var_type=ReflexCallable[[Any], bool]
464
+ )
465
+ PROTOTYPE_TO_STRING = FunctionStringVar.create(
466
+ "((__to_string) => __to_string.toString())",
467
+ _var_type=ReflexCallable[[Any], str],
468
+ )
469
+ else:
470
+ JSON_STRINGIFY = FunctionStringVar.create(
471
+ "JSON.stringify", _var_type=ReflexCallable[Any, str]
472
+ )
473
+ ARRAY_ISARRAY = FunctionStringVar.create(
474
+ "Array.isArray", _var_type=ReflexCallable[Any, bool]
475
+ )
476
+ PROTOTYPE_TO_STRING = FunctionStringVar.create(
477
+ "((__to_string) => __to_string.toString())",
478
+ _var_type=ReflexCallable[Any, str],
479
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reflex
3
- Version: 0.6.5a3
3
+ Version: 0.6.6a1
4
4
  Summary: Web apps in pure Python.
5
5
  Home-page: https://reflex.dev
6
6
  License: Apache-2.0
@@ -33,7 +33,7 @@ Requires-Dist: python-multipart (>=0.0.5,<0.1)
33
33
  Requires-Dist: python-socketio (>=5.7.0,<6.0)
34
34
  Requires-Dist: redis (>=4.3.5,<6.0)
35
35
  Requires-Dist: reflex-chakra (>=0.6.0)
36
- Requires-Dist: reflex-hosting-cli (>=0.1.15,<2.0)
36
+ Requires-Dist: reflex-hosting-cli (>=0.1.17,<2.0)
37
37
  Requires-Dist: rich (>=13.0.0,<14.0)
38
38
  Requires-Dist: setuptools (>=75.0)
39
39
  Requires-Dist: sqlmodel (>=0.0.14,<0.1)
@@ -41,6 +41,7 @@ Requires-Dist: starlette-admin (>=0.11.0,<1.0)
41
41
  Requires-Dist: tomlkit (>=0.12.4,<1.0)
42
42
  Requires-Dist: twine (>=4.0.0,<6.0)
43
43
  Requires-Dist: typer (>=0.4.2,<1.0)
44
+ Requires-Dist: typing_extensions (>=4.6.0)
44
45
  Requires-Dist: uvicorn (>=0.20.0)
45
46
  Requires-Dist: wheel (>=0.42.0,<1.0)
46
47
  Requires-Dist: wrapt (>=1.11.0,<2.0) ; python_version < "3.11"