reflex 0.6.2a2__py3-none-any.whl → 0.6.3__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 (179) hide show
  1. reflex/__init__.py +3 -2
  2. reflex/__init__.pyi +3 -1
  3. reflex/components/base/app_wrap.pyi +17 -37
  4. reflex/components/base/body.pyi +17 -37
  5. reflex/components/base/document.pyi +77 -177
  6. reflex/components/base/error_boundary.pyi +18 -38
  7. reflex/components/base/fragment.pyi +17 -37
  8. reflex/components/base/head.pyi +32 -72
  9. reflex/components/base/link.pyi +32 -72
  10. reflex/components/base/meta.pyi +62 -142
  11. reflex/components/base/script.py +4 -4
  12. reflex/components/base/script.pyi +20 -40
  13. reflex/components/component.py +30 -19
  14. reflex/components/core/banner.pyi +77 -177
  15. reflex/components/core/client_side_routing.pyi +32 -72
  16. reflex/components/core/clipboard.py +3 -3
  17. reflex/components/core/clipboard.pyi +18 -38
  18. reflex/components/core/debounce.py +2 -2
  19. reflex/components/core/debounce.pyi +18 -38
  20. reflex/components/core/html.pyi +17 -37
  21. reflex/components/core/upload.py +4 -4
  22. reflex/components/core/upload.pyi +65 -145
  23. reflex/components/datadisplay/code.pyi +32 -72
  24. reflex/components/datadisplay/dataeditor.py +13 -13
  25. reflex/components/datadisplay/dataeditor.pyi +33 -83
  26. reflex/components/dynamic.py +6 -7
  27. reflex/components/el/__init__.pyi +1 -0
  28. reflex/components/el/element.pyi +17 -37
  29. reflex/components/el/elements/base.pyi +17 -37
  30. reflex/components/el/elements/forms.py +29 -14
  31. reflex/components/el/elements/forms.pyi +222 -504
  32. reflex/components/el/elements/inline.pyi +422 -982
  33. reflex/components/el/elements/media.pyi +377 -877
  34. reflex/components/el/elements/metadata.pyi +92 -212
  35. reflex/components/el/elements/other.pyi +107 -247
  36. reflex/components/el/elements/scripts.pyi +47 -107
  37. reflex/components/el/elements/sectioning.pyi +227 -527
  38. reflex/components/el/elements/tables.pyi +152 -352
  39. reflex/components/el/elements/typography.pyi +227 -527
  40. reflex/components/gridjs/datatable.py +2 -2
  41. reflex/components/gridjs/datatable.pyi +32 -72
  42. reflex/components/lucide/icon.pyi +32 -72
  43. reflex/components/markdown/markdown.pyi +16 -36
  44. reflex/components/moment/moment.py +2 -2
  45. reflex/components/moment/moment.pyi +18 -38
  46. reflex/components/next/base.pyi +17 -37
  47. reflex/components/next/image.py +3 -3
  48. reflex/components/next/image.pyi +19 -39
  49. reflex/components/next/link.pyi +17 -37
  50. reflex/components/next/video.pyi +17 -37
  51. reflex/components/plotly/plotly.py +1 -1
  52. reflex/components/plotly/plotly.pyi +35 -87
  53. reflex/components/radix/primitives/accordion.py +14 -2
  54. reflex/components/radix/primitives/accordion.pyi +110 -250
  55. reflex/components/radix/primitives/base.pyi +32 -72
  56. reflex/components/radix/primitives/drawer.py +30 -12
  57. reflex/components/radix/primitives/drawer.pyi +159 -373
  58. reflex/components/radix/primitives/form.py +3 -3
  59. reflex/components/radix/primitives/form.pyi +158 -364
  60. reflex/components/radix/primitives/progress.pyi +77 -177
  61. reflex/components/radix/primitives/slider.py +17 -3
  62. reflex/components/radix/primitives/slider.pyi +81 -183
  63. reflex/components/radix/themes/base.pyi +107 -247
  64. reflex/components/radix/themes/color_mode.pyi +48 -117
  65. reflex/components/radix/themes/components/alert_dialog.py +5 -5
  66. reflex/components/radix/themes/components/alert_dialog.pyi +111 -259
  67. reflex/components/radix/themes/components/aspect_ratio.pyi +17 -37
  68. reflex/components/radix/themes/components/avatar.pyi +17 -37
  69. reflex/components/radix/themes/components/badge.pyi +17 -37
  70. reflex/components/radix/themes/components/button.pyi +17 -37
  71. reflex/components/radix/themes/components/callout.pyi +77 -177
  72. reflex/components/radix/themes/components/card.pyi +17 -37
  73. reflex/components/radix/themes/components/checkbox.py +3 -3
  74. reflex/components/radix/themes/components/checkbox.pyi +50 -110
  75. reflex/components/radix/themes/components/checkbox_cards.pyi +32 -72
  76. reflex/components/radix/themes/components/checkbox_group.pyi +32 -72
  77. reflex/components/radix/themes/components/context_menu.py +11 -11
  78. reflex/components/radix/themes/components/context_menu.pyi +132 -312
  79. reflex/components/radix/themes/components/data_list.pyi +62 -142
  80. reflex/components/radix/themes/components/dialog.py +7 -7
  81. reflex/components/radix/themes/components/dialog.pyi +114 -268
  82. reflex/components/radix/themes/components/dropdown_menu.py +13 -13
  83. reflex/components/radix/themes/components/dropdown_menu.pyi +134 -316
  84. reflex/components/radix/themes/components/hover_card.py +2 -2
  85. reflex/components/radix/themes/components/hover_card.pyi +64 -148
  86. reflex/components/radix/themes/components/icon_button.pyi +17 -37
  87. reflex/components/radix/themes/components/inset.pyi +17 -37
  88. reflex/components/radix/themes/components/popover.py +8 -8
  89. reflex/components/radix/themes/components/popover.pyi +69 -163
  90. reflex/components/radix/themes/components/progress.pyi +17 -37
  91. reflex/components/radix/themes/components/radio.pyi +17 -37
  92. reflex/components/radix/themes/components/radio_cards.py +2 -2
  93. reflex/components/radix/themes/components/radio_cards.pyi +33 -75
  94. reflex/components/radix/themes/components/radio_group.py +4 -4
  95. reflex/components/radix/themes/components/radio_group.pyi +63 -143
  96. reflex/components/radix/themes/components/scroll_area.pyi +17 -37
  97. reflex/components/radix/themes/components/segmented_control.py +14 -2
  98. reflex/components/radix/themes/components/segmented_control.pyi +35 -73
  99. reflex/components/radix/themes/components/select.py +6 -5
  100. reflex/components/radix/themes/components/select.pyi +146 -338
  101. reflex/components/radix/themes/components/separator.pyi +17 -37
  102. reflex/components/radix/themes/components/skeleton.pyi +17 -37
  103. reflex/components/radix/themes/components/slider.py +19 -3
  104. reflex/components/radix/themes/components/slider.pyi +23 -41
  105. reflex/components/radix/themes/components/spinner.pyi +17 -37
  106. reflex/components/radix/themes/components/switch.py +2 -2
  107. reflex/components/radix/themes/components/switch.pyi +18 -38
  108. reflex/components/radix/themes/components/table.pyi +107 -247
  109. reflex/components/radix/themes/components/tabs.py +2 -2
  110. reflex/components/radix/themes/components/tabs.pyi +79 -179
  111. reflex/components/radix/themes/components/text_area.py +0 -16
  112. reflex/components/radix/themes/components/text_area.pyi +20 -42
  113. reflex/components/radix/themes/components/text_field.py +6 -6
  114. reflex/components/radix/themes/components/text_field.pyi +53 -117
  115. reflex/components/radix/themes/components/tooltip.py +4 -4
  116. reflex/components/radix/themes/components/tooltip.pyi +20 -46
  117. reflex/components/radix/themes/layout/base.pyi +17 -37
  118. reflex/components/radix/themes/layout/box.pyi +17 -37
  119. reflex/components/radix/themes/layout/center.pyi +17 -37
  120. reflex/components/radix/themes/layout/container.pyi +17 -37
  121. reflex/components/radix/themes/layout/flex.pyi +17 -37
  122. reflex/components/radix/themes/layout/grid.pyi +17 -37
  123. reflex/components/radix/themes/layout/list.pyi +77 -177
  124. reflex/components/radix/themes/layout/section.pyi +17 -37
  125. reflex/components/radix/themes/layout/spacer.pyi +17 -37
  126. reflex/components/radix/themes/layout/stack.pyi +47 -107
  127. reflex/components/radix/themes/typography/blockquote.pyi +17 -37
  128. reflex/components/radix/themes/typography/code.pyi +17 -37
  129. reflex/components/radix/themes/typography/heading.pyi +17 -37
  130. reflex/components/radix/themes/typography/link.pyi +17 -37
  131. reflex/components/radix/themes/typography/text.pyi +107 -247
  132. reflex/components/react_player/audio.pyi +33 -69
  133. reflex/components/react_player/react_player.py +17 -17
  134. reflex/components/react_player/react_player.pyi +33 -69
  135. reflex/components/react_player/video.pyi +33 -69
  136. reflex/components/recharts/cartesian.py +216 -186
  137. reflex/components/recharts/cartesian.pyi +623 -832
  138. reflex/components/recharts/charts.py +68 -65
  139. reflex/components/recharts/charts.pyi +213 -433
  140. reflex/components/recharts/general.py +27 -21
  141. reflex/components/recharts/general.pyi +94 -189
  142. reflex/components/recharts/polar.py +135 -97
  143. reflex/components/recharts/polar.pyi +219 -229
  144. reflex/components/recharts/recharts.py +5 -1
  145. reflex/components/recharts/recharts.pyi +37 -73
  146. reflex/components/sonner/toast.py +1 -1
  147. reflex/components/sonner/toast.pyi +17 -37
  148. reflex/components/suneditor/editor.pyi +26 -52
  149. reflex/components/tags/iter_tag.py +2 -2
  150. reflex/config.py +16 -0
  151. reflex/constants/__init__.py +2 -0
  152. reflex/constants/compiler.py +25 -0
  153. reflex/constants/installer.py +17 -16
  154. reflex/constants/state.py +11 -0
  155. reflex/constants/style.py +1 -1
  156. reflex/custom_components/custom_components.py +1 -1
  157. reflex/event.py +337 -84
  158. reflex/experimental/layout.pyi +78 -180
  159. reflex/istate/dynamic.py +3 -0
  160. reflex/state.py +197 -118
  161. reflex/style.py +5 -0
  162. reflex/testing.py +8 -5
  163. reflex/utils/compat.py +1 -3
  164. reflex/utils/exceptions.py +8 -0
  165. reflex/utils/path_ops.py +2 -2
  166. reflex/utils/prerequisites.py +2 -2
  167. reflex/utils/pyi_generator.py +44 -4
  168. reflex/utils/registry.py +17 -3
  169. reflex/utils/telemetry.py +1 -3
  170. reflex/utils/types.py +60 -16
  171. reflex/vars/__init__.py +2 -0
  172. reflex/vars/base.py +127 -72
  173. reflex/vars/object.py +5 -1
  174. reflex/vars/sequence.py +15 -3
  175. {reflex-0.6.2a2.dist-info → reflex-0.6.3.dist-info}/METADATA +3 -3
  176. {reflex-0.6.2a2.dist-info → reflex-0.6.3.dist-info}/RECORD +179 -177
  177. {reflex-0.6.2a2.dist-info → reflex-0.6.3.dist-info}/LICENSE +0 -0
  178. {reflex-0.6.2a2.dist-info → reflex-0.6.3.dist-info}/WHEEL +0 -0
  179. {reflex-0.6.2a2.dist-info → reflex-0.6.3.dist-info}/entry_points.txt +0 -0
@@ -70,7 +70,7 @@ DEFAULT_TYPING_IMPORTS = {
70
70
  DEFAULT_IMPORTS = {
71
71
  "typing": sorted(DEFAULT_TYPING_IMPORTS),
72
72
  "reflex.components.core.breakpoints": ["Breakpoints"],
73
- "reflex.event": ["EventChain", "EventHandler", "EventSpec"],
73
+ "reflex.event": ["EventChain", "EventHandler", "EventSpec", "EventType"],
74
74
  "reflex.style": ["Style"],
75
75
  "reflex.vars.base": ["Var"],
76
76
  }
@@ -427,18 +427,58 @@ def _generate_component_create_functiondef(
427
427
  all_props = [arg[0].arg for arg in prop_kwargs]
428
428
  kwargs.extend(prop_kwargs)
429
429
 
430
+ def figure_out_return_type(annotation: Any):
431
+ if inspect.isclass(annotation) and issubclass(annotation, inspect._empty):
432
+ return ast.Name(id="Optional[EventType]")
433
+ if isinstance(annotation, str) and annotation.startswith("Tuple["):
434
+ inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]")
435
+
436
+ if inside_of_tuple == "()":
437
+ return ast.Name(id="Optional[EventType[[]]]")
438
+
439
+ arguments: list[str] = [""]
440
+
441
+ bracket_count = 0
442
+
443
+ for char in inside_of_tuple:
444
+ if char == "[":
445
+ bracket_count += 1
446
+ elif char == "]":
447
+ bracket_count -= 1
448
+
449
+ if char == "," and bracket_count == 0:
450
+ arguments.append("")
451
+ else:
452
+ arguments[-1] += char
453
+
454
+ arguments = [argument.strip() for argument in arguments]
455
+
456
+ arguments_without_var = [
457
+ argument.removeprefix("Var[").removesuffix("]")
458
+ if argument.startswith("Var[")
459
+ else argument
460
+ for argument in arguments
461
+ ]
462
+
463
+ return ast.Name(
464
+ id=f"Optional[EventType[{', '.join(arguments_without_var)}]]"
465
+ )
466
+ return ast.Name(id="Optional[EventType]")
467
+
468
+ event_triggers = clz().get_event_triggers()
469
+
430
470
  # event handler kwargs
431
471
  kwargs.extend(
432
472
  (
433
473
  ast.arg(
434
474
  arg=trigger,
435
- annotation=ast.Name(
436
- id="Optional[Union[EventHandler, EventSpec, list, Callable, Var]]"
475
+ annotation=figure_out_return_type(
476
+ inspect.signature(event_triggers[trigger]).return_annotation
437
477
  ),
438
478
  ),
439
479
  ast.Constant(value=None),
440
480
  )
441
- for trigger in sorted(clz().get_event_triggers())
481
+ for trigger in sorted(event_triggers)
442
482
  )
443
483
  logger.debug(f"Generated {clz.__name__}.create method with {len(kwargs)} kwargs")
444
484
  create_args = ast.arguments(
reflex/utils/registry.py CHANGED
@@ -1,8 +1,10 @@
1
1
  """Utilities for working with registries."""
2
2
 
3
+ import os
4
+
3
5
  import httpx
4
6
 
5
- from reflex.utils import console
7
+ from reflex.utils import console, net
6
8
 
7
9
 
8
10
  def latency(registry: str) -> int:
@@ -15,7 +17,7 @@ def latency(registry: str) -> int:
15
17
  int: The latency of the registry in microseconds.
16
18
  """
17
19
  try:
18
- return httpx.get(registry).elapsed.microseconds
20
+ return net.get(registry).elapsed.microseconds
19
21
  except httpx.HTTPError:
20
22
  console.info(f"Failed to connect to {registry}.")
21
23
  return 10_000_000
@@ -34,7 +36,7 @@ def average_latency(registry, attempts: int = 3) -> int:
34
36
  return sum(latency(registry) for _ in range(attempts)) // attempts
35
37
 
36
38
 
37
- def _get_best_registry() -> str:
39
+ def get_best_registry() -> str:
38
40
  """Get the best registry based on latency.
39
41
 
40
42
  Returns:
@@ -46,3 +48,15 @@ def _get_best_registry() -> str:
46
48
  ]
47
49
 
48
50
  return min(registries, key=average_latency)
51
+
52
+
53
+ def _get_npm_registry() -> str:
54
+ """Get npm registry. If environment variable is set, use it first.
55
+
56
+ Returns:
57
+ str:
58
+ """
59
+ if npm_registry := os.environ.get("NPM_CONFIG_REGISTRY", ""):
60
+ return npm_registry
61
+ else:
62
+ return get_best_registry()
reflex/utils/telemetry.py CHANGED
@@ -94,9 +94,7 @@ def _raise_on_missing_project_hash() -> bool:
94
94
  False when compilation should be skipped (i.e. no .web directory is required).
95
95
  Otherwise return True.
96
96
  """
97
- if should_skip_compile():
98
- return False
99
- return True
97
+ return not should_skip_compile()
100
98
 
101
99
 
102
100
  def _prepare_event(event: str, **kwargs) -> dict:
reflex/utils/types.py CHANGED
@@ -18,6 +18,7 @@ from typing import (
18
18
  List,
19
19
  Literal,
20
20
  Optional,
21
+ Sequence,
21
22
  Tuple,
22
23
  Type,
23
24
  Union,
@@ -102,14 +103,14 @@ if TYPE_CHECKING:
102
103
 
103
104
  # ArgsSpec = Callable[[Var], list[Var]]
104
105
  ArgsSpec = (
105
- Callable[[], List[Var]]
106
- | Callable[[Var], List[Var]]
107
- | Callable[[Var, Var], List[Var]]
108
- | Callable[[Var, Var, Var], List[Var]]
109
- | Callable[[Var, Var, Var, Var], List[Var]]
110
- | Callable[[Var, Var, Var, Var, Var], List[Var]]
111
- | Callable[[Var, Var, Var, Var, Var, Var], List[Var]]
112
- | Callable[[Var, Var, Var, Var, Var, Var, Var], List[Var]]
106
+ Callable[[], Sequence[Var]]
107
+ | Callable[[Var], Sequence[Var]]
108
+ | Callable[[Var, Var], Sequence[Var]]
109
+ | Callable[[Var, Var, Var], Sequence[Var]]
110
+ | Callable[[Var, Var, Var, Var], Sequence[Var]]
111
+ | Callable[[Var, Var, Var, Var, Var], Sequence[Var]]
112
+ | Callable[[Var, Var, Var, Var, Var, Var], Sequence[Var]]
113
+ | Callable[[Var, Var, Var, Var, Var, Var, Var], Sequence[Var]]
113
114
  )
114
115
  else:
115
116
  ArgsSpec = Callable[..., List[Any]]
@@ -182,6 +183,26 @@ def is_generic_alias(cls: GenericType) -> bool:
182
183
  return isinstance(cls, GenericAliasTypes)
183
184
 
184
185
 
186
+ def unionize(*args: GenericType) -> Type:
187
+ """Unionize the types.
188
+
189
+ Args:
190
+ args: The types to unionize.
191
+
192
+ Returns:
193
+ The unionized types.
194
+ """
195
+ if not args:
196
+ return Any
197
+ if len(args) == 1:
198
+ return args[0]
199
+ # We are bisecting the args list here to avoid hitting the recursion limit
200
+ # In Python versions >= 3.11, we can simply do `return Union[*args]`
201
+ midpoint = len(args) // 2
202
+ first_half, second_half = args[:midpoint], args[midpoint:]
203
+ return Union[unionize(*first_half), unionize(*second_half)]
204
+
205
+
185
206
  def is_none(cls: GenericType) -> bool:
186
207
  """Check if a class is None.
187
208
 
@@ -220,6 +241,27 @@ def is_literal(cls: GenericType) -> bool:
220
241
  return get_origin(cls) is Literal
221
242
 
222
243
 
244
+ def has_args(cls) -> bool:
245
+ """Check if the class has generic parameters.
246
+
247
+ Args:
248
+ cls: The class to check.
249
+
250
+ Returns:
251
+ Whether the class has generic
252
+ """
253
+ if get_args(cls):
254
+ return True
255
+
256
+ # Check if the class inherits from a generic class (using __orig_bases__)
257
+ if hasattr(cls, "__orig_bases__"):
258
+ for base in cls.__orig_bases__:
259
+ if get_args(base):
260
+ return True
261
+
262
+ return False
263
+
264
+
223
265
  def is_optional(cls: GenericType) -> bool:
224
266
  """Check if a class is an Optional.
225
267
 
@@ -337,11 +379,9 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
337
379
  return type_
338
380
  elif is_union(cls):
339
381
  # Check in each arg of the annotation.
340
- for arg in get_args(cls):
341
- type_ = get_attribute_access_type(arg, name)
342
- if type_ is not None:
343
- # Return the first attribute type that is accessible.
344
- return type_
382
+ return unionize(
383
+ *(get_attribute_access_type(arg, name) for arg in get_args(cls))
384
+ )
345
385
  elif isinstance(cls, type):
346
386
  # Bare class
347
387
  if sys.version_info >= (3, 10):
@@ -374,7 +414,7 @@ def get_base_class(cls: GenericType) -> Type:
374
414
  if is_literal(cls):
375
415
  # only literals of the same type are supported.
376
416
  arg_type = type(get_args(cls)[0])
377
- if not all(type(arg) == arg_type for arg in get_args(cls)):
417
+ if not all(type(arg) is arg_type for arg in get_args(cls)):
378
418
  raise TypeError("only literals of the same type are supported")
379
419
  return type(get_args(cls)[0])
380
420
 
@@ -525,7 +565,11 @@ def is_backend_base_variable(name: str, cls: Type) -> bool:
525
565
  if name.startswith(f"_{cls.__name__}__"):
526
566
  return False
527
567
 
528
- hints = get_type_hints(cls)
568
+ # Extract the namespace of the original module if defined (dynamic substates).
569
+ if callable(getattr(cls, "_get_type_hints", None)):
570
+ hints = cls._get_type_hints()
571
+ else:
572
+ hints = get_type_hints(cls)
529
573
  if name in hints:
530
574
  hint = get_origin(hints[name])
531
575
  if hint == ClassVar:
@@ -538,7 +582,7 @@ def is_backend_base_variable(name: str, cls: Type) -> bool:
538
582
 
539
583
  if name in cls.__dict__:
540
584
  value = cls.__dict__[name]
541
- if type(value) == classmethod:
585
+ if type(value) is classmethod:
542
586
  return False
543
587
  if callable(value):
544
588
  return False
reflex/vars/__init__.py CHANGED
@@ -1,8 +1,10 @@
1
1
  """Immutable-Based Var System."""
2
2
 
3
+ from .base import Field as Field
3
4
  from .base import LiteralVar as LiteralVar
4
5
  from .base import Var as Var
5
6
  from .base import VarData as VarData
7
+ from .base import field as field
6
8
  from .base import get_unique_variable_name as get_unique_variable_name
7
9
  from .base import get_uuid_string_var as get_uuid_string_var
8
10
  from .base import var_operation as var_operation
reflex/vars/base.py CHANGED
@@ -56,7 +56,7 @@ from reflex.utils.imports import (
56
56
  ParsedImportDict,
57
57
  parse_imports,
58
58
  )
59
- from reflex.utils.types import GenericType, Self, get_origin
59
+ from reflex.utils.types import GenericType, Self, get_origin, has_args, unionize
60
60
 
61
61
  if TYPE_CHECKING:
62
62
  from reflex.state import BaseState
@@ -239,7 +239,7 @@ class Var(Generic[VAR_TYPE]):
239
239
  **kwargs,
240
240
  )
241
241
 
242
- if (js_expr := kwargs.get("_js_expr", None)) is not None:
242
+ if (js_expr := kwargs.get("_js_expr")) is not None:
243
243
  object.__setattr__(value_with_replaced, "_js_expr", js_expr)
244
244
 
245
245
  return value_with_replaced
@@ -429,71 +429,75 @@ class Var(Generic[VAR_TYPE]):
429
429
  return self.to(EventVar, output)
430
430
  if fixed_output_type is EventChain:
431
431
  return self.to(EventChainVar, output)
432
- if issubclass(fixed_output_type, Base):
433
- return self.to(ObjectVar, output)
432
+ try:
433
+ if issubclass(fixed_output_type, Base):
434
+ return self.to(ObjectVar, output)
435
+ except TypeError:
436
+ pass
434
437
  if dataclasses.is_dataclass(fixed_output_type) and not issubclass(
435
438
  fixed_output_type, Var
436
439
  ):
437
440
  return self.to(ObjectVar, output)
438
441
 
439
- if issubclass(output, BooleanVar):
440
- return ToBooleanVarOperation.create(self)
442
+ if inspect.isclass(output):
443
+ if issubclass(output, BooleanVar):
444
+ return ToBooleanVarOperation.create(self)
445
+
446
+ if issubclass(output, NumberVar):
447
+ if fixed_type is not None:
448
+ if fixed_type in types.UnionTypes:
449
+ inner_types = get_args(base_type)
450
+ if not all(issubclass(t, (int, float)) for t in inner_types):
451
+ raise TypeError(
452
+ f"Unsupported type {var_type} for NumberVar. Must be int or float."
453
+ )
441
454
 
442
- if issubclass(output, NumberVar):
443
- if fixed_type is not None:
444
- if fixed_type is Union:
445
- inner_types = get_args(base_type)
446
- if not all(issubclass(t, (int, float)) for t in inner_types):
455
+ elif not issubclass(fixed_type, (int, float)):
447
456
  raise TypeError(
448
457
  f"Unsupported type {var_type} for NumberVar. Must be int or float."
449
458
  )
459
+ return ToNumberVarOperation.create(self, var_type or float)
450
460
 
451
- elif not issubclass(fixed_type, (int, float)):
461
+ if issubclass(output, ArrayVar):
462
+ if fixed_type is not None and not issubclass(
463
+ fixed_type, (list, tuple, set)
464
+ ):
452
465
  raise TypeError(
453
- f"Unsupported type {var_type} for NumberVar. Must be int or float."
466
+ f"Unsupported type {var_type} for ArrayVar. Must be list, tuple, or set."
454
467
  )
455
- return ToNumberVarOperation.create(self, var_type or float)
468
+ return ToArrayOperation.create(self, var_type or list)
456
469
 
457
- if issubclass(output, ArrayVar):
458
- if fixed_type is not None and not issubclass(
459
- fixed_type, (list, tuple, set)
460
- ):
461
- raise TypeError(
462
- f"Unsupported type {var_type} for ArrayVar. Must be list, tuple, or set."
463
- )
464
- return ToArrayOperation.create(self, var_type or list)
470
+ if issubclass(output, StringVar):
471
+ return ToStringOperation.create(self, var_type or str)
465
472
 
466
- if issubclass(output, StringVar):
467
- return ToStringOperation.create(self, var_type or str)
473
+ if issubclass(output, EventVar):
474
+ return ToEventVarOperation.create(self, var_type or EventSpec)
468
475
 
469
- if issubclass(output, EventVar):
470
- return ToEventVarOperation.create(self, var_type or EventSpec)
476
+ if issubclass(output, EventChainVar):
477
+ return ToEventChainVarOperation.create(self, var_type or EventChain)
471
478
 
472
- if issubclass(output, EventChainVar):
473
- return ToEventChainVarOperation.create(self, var_type or EventChain)
479
+ if issubclass(output, (ObjectVar, Base)):
480
+ return ToObjectOperation.create(self, var_type or dict)
474
481
 
475
- if issubclass(output, (ObjectVar, Base)):
476
- return ToObjectOperation.create(self, var_type or dict)
482
+ if issubclass(output, FunctionVar):
483
+ # if fixed_type is not None and not issubclass(fixed_type, Callable):
484
+ # raise TypeError(
485
+ # f"Unsupported type {var_type} for FunctionVar. Must be Callable."
486
+ # )
487
+ return ToFunctionOperation.create(self, var_type or Callable)
477
488
 
478
- if issubclass(output, FunctionVar):
479
- # if fixed_type is not None and not issubclass(fixed_type, Callable):
480
- # raise TypeError(
481
- # f"Unsupported type {var_type} for FunctionVar. Must be Callable."
482
- # )
483
- return ToFunctionOperation.create(self, var_type or Callable)
484
-
485
- if issubclass(output, NoneVar):
486
- return ToNoneOperation.create(self)
489
+ if issubclass(output, NoneVar):
490
+ return ToNoneOperation.create(self)
487
491
 
488
- if dataclasses.is_dataclass(output):
489
- return ToObjectOperation.create(self, var_type or dict)
492
+ if dataclasses.is_dataclass(output):
493
+ return ToObjectOperation.create(self, var_type or dict)
490
494
 
491
- # If we can't determine the first argument, we just replace the _var_type.
492
- if not issubclass(output, Var) or var_type is None:
493
- return dataclasses.replace(
494
- self,
495
- _var_type=output,
496
- )
495
+ # If we can't determine the first argument, we just replace the _var_type.
496
+ if not issubclass(output, Var) or var_type is None:
497
+ return dataclasses.replace(
498
+ self,
499
+ _var_type=output,
500
+ )
497
501
 
498
502
  # We couldn't determine the output type to be any other Var type, so we replace the _var_type.
499
503
  if var_type is not None:
@@ -530,7 +534,7 @@ class Var(Generic[VAR_TYPE]):
530
534
 
531
535
  fixed_type = get_origin(var_type) or var_type
532
536
 
533
- if fixed_type is Union:
537
+ if fixed_type in types.UnionTypes:
534
538
  inner_types = get_args(var_type)
535
539
 
536
540
  if all(
@@ -568,8 +572,11 @@ class Var(Generic[VAR_TYPE]):
568
572
  return self.to(EventVar, self._var_type)
569
573
  if issubclass(fixed_type, EventChain):
570
574
  return self.to(EventChainVar, self._var_type)
571
- if issubclass(fixed_type, Base):
572
- return self.to(ObjectVar, self._var_type)
575
+ try:
576
+ if issubclass(fixed_type, Base):
577
+ return self.to(ObjectVar, self._var_type)
578
+ except TypeError:
579
+ pass
573
580
  if dataclasses.is_dataclass(fixed_type):
574
581
  return self.to(ObjectVar, self._var_type)
575
582
  return self
@@ -1237,26 +1244,6 @@ def var_operation(
1237
1244
  return wrapper
1238
1245
 
1239
1246
 
1240
- def unionize(*args: Type) -> Type:
1241
- """Unionize the types.
1242
-
1243
- Args:
1244
- args: The types to unionize.
1245
-
1246
- Returns:
1247
- The unionized types.
1248
- """
1249
- if not args:
1250
- return Any
1251
- if len(args) == 1:
1252
- return args[0]
1253
- # We are bisecting the args list here to avoid hitting the recursion limit
1254
- # In Python versions >= 3.11, we can simply do `return Union[*args]`
1255
- midpoint = len(args) // 2
1256
- first_half, second_half = args[:midpoint], args[midpoint:]
1257
- return Union[unionize(*first_half), unionize(*second_half)]
1258
-
1259
-
1260
1247
  def figure_out_type(value: Any) -> types.GenericType:
1261
1248
  """Figure out the type of the value.
1262
1249
 
@@ -1266,6 +1253,11 @@ def figure_out_type(value: Any) -> types.GenericType:
1266
1253
  Returns:
1267
1254
  The type of the value.
1268
1255
  """
1256
+ if isinstance(value, Var):
1257
+ return value._var_type
1258
+ type_ = type(value)
1259
+ if has_args(type_):
1260
+ return type_
1269
1261
  if isinstance(value, list):
1270
1262
  return List[unionize(*(figure_out_type(v) for v in value))]
1271
1263
  if isinstance(value, set):
@@ -1277,8 +1269,6 @@ def figure_out_type(value: Any) -> types.GenericType:
1277
1269
  unionize(*(figure_out_type(k) for k in value)),
1278
1270
  unionize(*(figure_out_type(v) for v in value.values())),
1279
1271
  ]
1280
- if isinstance(value, Var):
1281
- return value._var_type
1282
1272
  return type(value)
1283
1273
 
1284
1274
 
@@ -2832,3 +2822,68 @@ def dispatch(
2832
2822
  _var_data=var_data,
2833
2823
  _var_type=result_var_type,
2834
2824
  ).guess_type()
2825
+
2826
+
2827
+ V = TypeVar("V")
2828
+
2829
+
2830
+ class Field(Generic[T]):
2831
+ """Shadow class for Var to allow for type hinting in the IDE."""
2832
+
2833
+ def __set__(self, instance, value: T):
2834
+ """Set the Var.
2835
+
2836
+ Args:
2837
+ instance: The instance of the class setting the Var.
2838
+ value: The value to set the Var to.
2839
+ """
2840
+
2841
+ @overload
2842
+ def __get__(self: Field[bool], instance: None, owner) -> BooleanVar: ...
2843
+
2844
+ @overload
2845
+ def __get__(self: Field[int], instance: None, owner) -> NumberVar: ...
2846
+
2847
+ @overload
2848
+ def __get__(self: Field[str], instance: None, owner) -> StringVar: ...
2849
+
2850
+ @overload
2851
+ def __get__(self: Field[None], instance: None, owner) -> NoneVar: ...
2852
+
2853
+ @overload
2854
+ def __get__(
2855
+ self: Field[List[V]] | Field[Set[V]] | Field[Tuple[V, ...]],
2856
+ instance: None,
2857
+ owner,
2858
+ ) -> ArrayVar[List[V]]: ...
2859
+
2860
+ @overload
2861
+ def __get__(
2862
+ self: Field[Dict[str, V]], instance: None, owner
2863
+ ) -> ObjectVar[Dict[str, V]]: ...
2864
+
2865
+ @overload
2866
+ def __get__(self, instance: None, owner) -> Var[T]: ...
2867
+
2868
+ @overload
2869
+ def __get__(self, instance, owner) -> T: ...
2870
+
2871
+ def __get__(self, instance, owner): # type: ignore
2872
+ """Get the Var.
2873
+
2874
+ Args:
2875
+ instance: The instance of the class accessing the Var.
2876
+ owner: The class that the Var is attached to.
2877
+ """
2878
+
2879
+
2880
+ def field(value: T) -> Field[T]:
2881
+ """Create a Field with a value.
2882
+
2883
+ Args:
2884
+ value: The value of the Field.
2885
+
2886
+ Returns:
2887
+ The Field.
2888
+ """
2889
+ return value # type: ignore
reflex/vars/object.py CHANGED
@@ -119,6 +119,8 @@ class ObjectVar(Var[OBJECT_TYPE]):
119
119
  """
120
120
  return object_entries_operation(self)
121
121
 
122
+ items = entries
123
+
122
124
  def merge(self, other: ObjectVar):
123
125
  """Merge two objects.
124
126
 
@@ -260,7 +262,9 @@ class ObjectVar(Var[OBJECT_TYPE]):
260
262
  var_type = get_args(var_type)[0]
261
263
 
262
264
  fixed_type = var_type if isclass(var_type) else get_origin(var_type)
263
- if isclass(fixed_type) and not issubclass(fixed_type, dict):
265
+ if (isclass(fixed_type) and not issubclass(fixed_type, dict)) or (
266
+ fixed_type in types.UnionTypes
267
+ ):
264
268
  attribute_type = get_attribute_access_type(var_type, name)
265
269
  if attribute_type is None:
266
270
  raise VarAttributeError(
reflex/vars/sequence.py CHANGED
@@ -545,7 +545,7 @@ class LiteralStringVar(LiteralVar, StringVar):
545
545
  def create(
546
546
  cls,
547
547
  value: str,
548
- _var_type: GenericType | None = str,
548
+ _var_type: GenericType | None = None,
549
549
  _var_data: VarData | None = None,
550
550
  ) -> StringVar:
551
551
  """Create a var from a string value.
@@ -558,6 +558,9 @@ class LiteralStringVar(LiteralVar, StringVar):
558
558
  Returns:
559
559
  The var.
560
560
  """
561
+ # Determine var type in case the value is inherited from str.
562
+ _var_type = _var_type or type(value) or str
563
+
561
564
  if REFLEX_VAR_OPENING_TAG in value:
562
565
  strings_and_vals: list[Var | str] = []
563
566
  offset = 0
@@ -884,6 +887,12 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
884
887
  i: int | NumberVar,
885
888
  ) -> ArrayVar[Set[INNER_ARRAY_VAR]]: ...
886
889
 
890
+ @overload
891
+ def __getitem__(
892
+ self: ARRAY_VAR_OF_LIST_ELEMENT[Tuple[KEY_TYPE, VALUE_TYPE]],
893
+ i: int | NumberVar,
894
+ ) -> ArrayVar[Tuple[KEY_TYPE, VALUE_TYPE]]: ...
895
+
887
896
  @overload
888
897
  def __getitem__(
889
898
  self: ARRAY_VAR_OF_LIST_ELEMENT[Tuple[INNER_ARRAY_VAR, ...]],
@@ -1146,7 +1155,7 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
1146
1155
  function_var = ArgsFunctionOperation.create(tuple(), return_value)
1147
1156
  else:
1148
1157
  # generic number var
1149
- number_var = Var("").to(NumberVar)
1158
+ number_var = Var("").to(NumberVar, int)
1150
1159
 
1151
1160
  first_arg_type = self[number_var]._var_type
1152
1161
 
@@ -1158,7 +1167,10 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
1158
1167
  _var_type=first_arg_type,
1159
1168
  ).guess_type()
1160
1169
 
1161
- function_var = ArgsFunctionOperation.create((arg_name,), fn(first_arg))
1170
+ function_var = ArgsFunctionOperation.create(
1171
+ (arg_name,),
1172
+ Var.create(fn(first_arg)),
1173
+ )
1162
1174
 
1163
1175
  return map_array_operation(self, function_var)
1164
1176
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reflex
3
- Version: 0.6.2a2
3
+ Version: 0.6.3
4
4
  Summary: Web apps in pure Python.
5
5
  Home-page: https://reflex.dev
6
6
  License: Apache-2.0
@@ -35,7 +35,7 @@ Requires-Dist: redis (>=4.3.5,<6.0)
35
35
  Requires-Dist: reflex-chakra (>=0.6.0)
36
36
  Requires-Dist: reflex-hosting-cli (>=0.1.2,<2.0)
37
37
  Requires-Dist: rich (>=13.0.0,<14.0)
38
- Requires-Dist: setuptools (>=69.1.1,<70.2)
38
+ Requires-Dist: setuptools (>=75.0)
39
39
  Requires-Dist: sqlmodel (>=0.0.14,<0.1)
40
40
  Requires-Dist: starlette-admin (>=0.11.0,<1.0)
41
41
  Requires-Dist: tomlkit (>=0.12.4,<1.0)
@@ -68,7 +68,7 @@ Description-Content-Type: text/markdown
68
68
 
69
69
  ---
70
70
 
71
- [English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
71
+ [English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
72
72
 
73
73
  ---
74
74