reflex 0.7.4a2__py3-none-any.whl → 0.7.5__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 (162) hide show
  1. reflex/__init__.py +1 -0
  2. reflex/__init__.pyi +1 -0
  3. reflex/app.py +10 -8
  4. reflex/app_mixins/middleware.py +13 -20
  5. reflex/compiler/compiler.py +10 -3
  6. reflex/compiler/utils.py +4 -4
  7. reflex/components/base/app_wrap.pyi +7 -3
  8. reflex/components/base/body.pyi +7 -3
  9. reflex/components/base/document.pyi +27 -7
  10. reflex/components/base/error_boundary.pyi +7 -3
  11. reflex/components/base/fragment.pyi +7 -3
  12. reflex/components/base/head.pyi +12 -4
  13. reflex/components/base/link.pyi +12 -4
  14. reflex/components/base/meta.pyi +22 -6
  15. reflex/components/base/script.pyi +7 -3
  16. reflex/components/base/strict_mode.pyi +7 -3
  17. reflex/components/component.py +64 -23
  18. reflex/components/core/auto_scroll.pyi +7 -3
  19. reflex/components/core/banner.py +6 -2
  20. reflex/components/core/banner.pyi +32 -8
  21. reflex/components/core/client_side_routing.pyi +12 -4
  22. reflex/components/core/clipboard.pyi +7 -3
  23. reflex/components/core/debounce.pyi +7 -3
  24. reflex/components/core/foreach.py +5 -1
  25. reflex/components/core/html.pyi +7 -3
  26. reflex/components/core/match.py +5 -5
  27. reflex/components/core/sticky.pyi +21 -6
  28. reflex/components/core/upload.pyi +27 -7
  29. reflex/components/datadisplay/code.pyi +12 -4
  30. reflex/components/datadisplay/dataeditor.py +2 -2
  31. reflex/components/datadisplay/dataeditor.pyi +17 -3
  32. reflex/components/datadisplay/shiki_code_block.pyi +17 -4
  33. reflex/components/el/__init__.pyi +1 -1
  34. reflex/components/el/element.pyi +7 -3
  35. reflex/components/el/elements/__init__.py +3 -1
  36. reflex/components/el/elements/__init__.pyi +3 -2
  37. reflex/components/el/elements/base.pyi +7 -3
  38. reflex/components/el/elements/forms.py +1 -1
  39. reflex/components/el/elements/forms.pyi +72 -16
  40. reflex/components/el/elements/inline.pyi +142 -30
  41. reflex/components/el/elements/media.pyi +127 -27
  42. reflex/components/el/elements/metadata.pyi +32 -8
  43. reflex/components/el/elements/other.pyi +37 -9
  44. reflex/components/el/elements/scripts.pyi +17 -5
  45. reflex/components/el/elements/sectioning.pyi +77 -17
  46. reflex/components/el/elements/tables.pyi +52 -12
  47. reflex/components/el/elements/typography.pyi +77 -17
  48. reflex/components/gridjs/datatable.py +2 -2
  49. reflex/components/gridjs/datatable.pyi +12 -4
  50. reflex/components/lucide/icon.py +7 -6
  51. reflex/components/lucide/icon.pyi +22 -7
  52. reflex/components/markdown/markdown.py +1 -1
  53. reflex/components/markdown/markdown.pyi +7 -3
  54. reflex/components/moment/moment.pyi +7 -3
  55. reflex/components/next/base.pyi +7 -3
  56. reflex/components/next/image.pyi +7 -3
  57. reflex/components/next/link.pyi +7 -3
  58. reflex/components/next/video.pyi +7 -3
  59. reflex/components/plotly/plotly.pyi +47 -11
  60. reflex/components/radix/primitives/accordion.pyi +37 -9
  61. reflex/components/radix/primitives/base.pyi +12 -4
  62. reflex/components/radix/primitives/drawer.pyi +57 -13
  63. reflex/components/radix/primitives/form.pyi +52 -12
  64. reflex/components/radix/primitives/progress.pyi +27 -7
  65. reflex/components/radix/primitives/slider.pyi +27 -7
  66. reflex/components/radix/themes/base.pyi +41 -10
  67. reflex/components/radix/themes/color_mode.py +2 -2
  68. reflex/components/radix/themes/color_mode.pyi +17 -5
  69. reflex/components/radix/themes/components/alert_dialog.pyi +36 -9
  70. reflex/components/radix/themes/components/aspect_ratio.pyi +7 -3
  71. reflex/components/radix/themes/components/avatar.pyi +6 -3
  72. reflex/components/radix/themes/components/badge.pyi +6 -3
  73. reflex/components/radix/themes/components/button.pyi +6 -3
  74. reflex/components/radix/themes/components/callout.pyi +26 -7
  75. reflex/components/radix/themes/components/card.pyi +6 -3
  76. reflex/components/radix/themes/components/checkbox.pyi +16 -5
  77. reflex/components/radix/themes/components/checkbox_cards.pyi +11 -4
  78. reflex/components/radix/themes/components/checkbox_group.pyi +11 -4
  79. reflex/components/radix/themes/components/context_menu.pyi +66 -15
  80. reflex/components/radix/themes/components/data_list.pyi +21 -6
  81. reflex/components/radix/themes/components/dialog.pyi +36 -9
  82. reflex/components/radix/themes/components/dropdown_menu.pyi +41 -10
  83. reflex/components/radix/themes/components/hover_card.pyi +21 -6
  84. reflex/components/radix/themes/components/icon_button.pyi +6 -3
  85. reflex/components/radix/themes/components/inset.pyi +6 -3
  86. reflex/components/radix/themes/components/popover.pyi +21 -6
  87. reflex/components/radix/themes/components/progress.pyi +6 -3
  88. reflex/components/radix/themes/components/radio.pyi +6 -3
  89. reflex/components/radix/themes/components/radio_cards.pyi +11 -4
  90. reflex/components/radix/themes/components/radio_group.py +6 -1
  91. reflex/components/radix/themes/components/radio_group.pyi +21 -6
  92. reflex/components/radix/themes/components/scroll_area.pyi +7 -3
  93. reflex/components/radix/themes/components/segmented_control.pyi +11 -4
  94. reflex/components/radix/themes/components/select.pyi +46 -11
  95. reflex/components/radix/themes/components/separator.pyi +6 -3
  96. reflex/components/radix/themes/components/skeleton.pyi +6 -3
  97. reflex/components/radix/themes/components/slider.pyi +6 -3
  98. reflex/components/radix/themes/components/spinner.pyi +6 -3
  99. reflex/components/radix/themes/components/switch.pyi +6 -3
  100. reflex/components/radix/themes/components/table.pyi +36 -9
  101. reflex/components/radix/themes/components/tabs.pyi +26 -7
  102. reflex/components/radix/themes/components/text_area.pyi +6 -3
  103. reflex/components/radix/themes/components/text_field.py +3 -2
  104. reflex/components/radix/themes/components/text_field.pyi +16 -5
  105. reflex/components/radix/themes/components/tooltip.pyi +7 -3
  106. reflex/components/radix/themes/layout/base.pyi +6 -3
  107. reflex/components/radix/themes/layout/box.pyi +7 -3
  108. reflex/components/radix/themes/layout/center.pyi +6 -3
  109. reflex/components/radix/themes/layout/container.pyi +6 -3
  110. reflex/components/radix/themes/layout/flex.pyi +6 -3
  111. reflex/components/radix/themes/layout/grid.pyi +6 -3
  112. reflex/components/radix/themes/layout/list.pyi +27 -7
  113. reflex/components/radix/themes/layout/section.pyi +6 -3
  114. reflex/components/radix/themes/layout/spacer.pyi +6 -3
  115. reflex/components/radix/themes/layout/stack.pyi +16 -5
  116. reflex/components/radix/themes/typography/blockquote.pyi +6 -3
  117. reflex/components/radix/themes/typography/code.pyi +6 -3
  118. reflex/components/radix/themes/typography/heading.pyi +6 -3
  119. reflex/components/radix/themes/typography/link.pyi +6 -3
  120. reflex/components/radix/themes/typography/text.pyi +36 -9
  121. reflex/components/react_player/audio.pyi +7 -3
  122. reflex/components/react_player/react_player.pyi +7 -3
  123. reflex/components/react_player/video.pyi +7 -3
  124. reflex/components/recharts/cartesian.pyi +97 -21
  125. reflex/components/recharts/charts.pyi +62 -14
  126. reflex/components/recharts/general.pyi +32 -8
  127. reflex/components/recharts/polar.py +1 -1
  128. reflex/components/recharts/polar.pyi +33 -9
  129. reflex/components/recharts/recharts.pyi +12 -4
  130. reflex/components/sonner/toast.pyi +7 -2
  131. reflex/components/suneditor/editor.pyi +7 -3
  132. reflex/config.py +18 -1
  133. reflex/constants/installer.py +22 -1
  134. reflex/custom_components/custom_components.py +12 -7
  135. reflex/event.py +26 -10
  136. reflex/experimental/__init__.py +17 -6
  137. reflex/experimental/layout.pyi +27 -7
  138. reflex/model.py +3 -3
  139. reflex/reflex.py +33 -18
  140. reflex/state.py +4 -4
  141. reflex/style.py +2 -2
  142. reflex/testing.py +17 -5
  143. reflex/utils/console.py +2 -3
  144. reflex/utils/exec.py +4 -0
  145. reflex/utils/imports.py +14 -7
  146. reflex/utils/net.py +107 -18
  147. reflex/utils/prerequisites.py +92 -13
  148. reflex/utils/processes.py +52 -19
  149. reflex/utils/pyi_generator.py +66 -53
  150. reflex/utils/redir.py +3 -1
  151. reflex/utils/registry.py +15 -5
  152. reflex/utils/serializers.py +1 -2
  153. reflex/utils/types.py +4 -4
  154. reflex/vars/base.py +58 -22
  155. reflex/vars/number.py +23 -6
  156. reflex/vars/sequence.py +2 -0
  157. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/METADATA +2 -2
  158. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/RECORD +162 -162
  159. /reflex/{experimental → utils}/misc.py +0 -0
  160. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/WHEEL +0 -0
  161. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/entry_points.txt +0 -0
  162. {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/licenses/LICENSE +0 -0
reflex/utils/registry.py CHANGED
@@ -4,6 +4,7 @@ import httpx
4
4
 
5
5
  from reflex.config import environment
6
6
  from reflex.utils import console, net
7
+ from reflex.utils.decorator import once
7
8
 
8
9
 
9
10
  def latency(registry: str) -> int:
@@ -16,10 +17,13 @@ def latency(registry: str) -> int:
16
17
  int: The latency of the registry in microseconds.
17
18
  """
18
19
  try:
19
- return net.get(registry).elapsed.microseconds
20
+ time_to_respond = net.get(registry, timeout=2).elapsed.microseconds
20
21
  except httpx.HTTPError:
21
22
  console.info(f"Failed to connect to {registry}.")
22
23
  return 10_000_000
24
+ else:
25
+ console.debug(f"Latency of {registry}: {time_to_respond}")
26
+ return time_to_respond
23
27
 
24
28
 
25
29
  def average_latency(registry: str, attempts: int = 3) -> int:
@@ -32,7 +36,9 @@ def average_latency(registry: str, attempts: int = 3) -> int:
32
36
  Returns:
33
37
  The average latency of the registry in microseconds.
34
38
  """
35
- return sum(latency(registry) for _ in range(attempts)) // attempts
39
+ registry_latency = sum(latency(registry) for _ in range(attempts)) // attempts
40
+ console.debug(f"Average latency of {registry}: {registry_latency}")
41
+ return registry_latency
36
42
 
37
43
 
38
44
  def _get_best_registry() -> str:
@@ -41,14 +47,18 @@ def _get_best_registry() -> str:
41
47
  Returns:
42
48
  The best registry.
43
49
  """
50
+ console.debug("Getting best registry...")
44
51
  registries = [
45
- "https://registry.npmjs.org",
46
- "https://r.cnpmjs.org",
52
+ ("https://registry.npmjs.org", 1),
53
+ ("https://registry.npmmirror.com", 2),
47
54
  ]
48
55
 
49
- return min(registries, key=average_latency)
56
+ best_registry = min(registries, key=lambda x: average_latency(x[0]) * x[1])[0]
57
+ console.debug(f"Best registry: {best_registry}")
58
+ return best_registry
50
59
 
51
60
 
61
+ @once
52
62
  def get_npm_registry() -> str:
53
63
  """Get npm registry. If environment variable is set, use it first.
54
64
 
@@ -16,7 +16,6 @@ from typing import (
16
16
  Callable,
17
17
  Literal,
18
18
  Sequence,
19
- Set,
20
19
  Type,
21
20
  TypeVar,
22
21
  Union,
@@ -322,7 +321,7 @@ if BaseModelV1 is not BaseModelV2:
322
321
 
323
322
 
324
323
  @serializer
325
- def serialize_set(value: Set) -> list:
324
+ def serialize_set(value: set) -> list:
326
325
  """Serialize a set to a JSON serializable list.
327
326
 
328
327
  Args:
reflex/utils/types.py CHANGED
@@ -140,7 +140,7 @@ def is_generic_alias(cls: GenericType) -> bool:
140
140
  Returns:
141
141
  Whether the class is a generic alias.
142
142
  """
143
- return isinstance(cls, GenericAliasTypes) # pyright: ignore [reportArgumentType]
143
+ return isinstance(cls, GenericAliasTypes)
144
144
 
145
145
 
146
146
  @lru_cache()
@@ -923,7 +923,7 @@ StateBases = get_base_class(StateVar)
923
923
  StateIterBases = get_base_class(StateIterVar)
924
924
 
925
925
 
926
- def safe_issubclass(cls: Type, cls_check: Type | tuple[Type, ...]):
926
+ def safe_issubclass(cls: Any, cls_check: Any | tuple[Any, ...]):
927
927
  """Check if a class is a subclass of another class. Returns False if internal error occurs.
928
928
 
929
929
  Args:
@@ -1047,8 +1047,8 @@ def typehint_issubclass(
1047
1047
 
1048
1048
  # Check if the origin of both types is the same (e.g., list for list[int])
1049
1049
  if not safe_issubclass(
1050
- provided_type_origin or possible_subclass, # pyright: ignore [reportArgumentType]
1051
- accepted_type_origin or possible_superclass, # pyright: ignore [reportArgumentType]
1050
+ provided_type_origin or possible_subclass,
1051
+ accepted_type_origin or possible_superclass,
1052
1052
  ):
1053
1053
  return False
1054
1054
 
reflex/vars/base.py CHANGED
@@ -30,6 +30,7 @@ from typing import (
30
30
  Mapping,
31
31
  NoReturn,
32
32
  ParamSpec,
33
+ Protocol,
33
34
  Sequence,
34
35
  Set,
35
36
  Tuple,
@@ -59,10 +60,11 @@ from reflex.utils.exceptions import (
59
60
  )
60
61
  from reflex.utils.format import format_state_name
61
62
  from reflex.utils.imports import (
63
+ ImmutableImportDict,
62
64
  ImmutableParsedImportDict,
63
65
  ImportDict,
64
66
  ImportVar,
65
- ParsedImportDict,
67
+ ParsedImportTuple,
66
68
  parse_imports,
67
69
  )
68
70
  from reflex.utils.types import (
@@ -122,7 +124,7 @@ class VarData:
122
124
  field_name: str = dataclasses.field(default="")
123
125
 
124
126
  # Imports needed to render this var
125
- imports: ImmutableParsedImportDict = dataclasses.field(default_factory=tuple)
127
+ imports: ParsedImportTuple = dataclasses.field(default_factory=tuple)
126
128
 
127
129
  # Hooks that need to be present in the component to render this var
128
130
  hooks: tuple[str, ...] = dataclasses.field(default_factory=tuple)
@@ -140,7 +142,7 @@ class VarData:
140
142
  self,
141
143
  state: str = "",
142
144
  field_name: str = "",
143
- imports: ImportDict | ParsedImportDict | None = None,
145
+ imports: ImmutableImportDict | ImmutableParsedImportDict | None = None,
144
146
  hooks: Mapping[str, VarData | None] | Sequence[str] | str | None = None,
145
147
  deps: list[Var] | None = None,
146
148
  position: Hooks.HookPosition | None = None,
@@ -161,7 +163,7 @@ class VarData:
161
163
  hooks = [hooks]
162
164
  if not isinstance(hooks, dict):
163
165
  hooks = dict.fromkeys(hooks or [])
164
- immutable_imports: ImmutableParsedImportDict = tuple(
166
+ immutable_imports: ParsedImportTuple = tuple(
165
167
  (k, tuple(v)) for k, v in parse_imports(imports or {}).items()
166
168
  )
167
169
  object.__setattr__(self, "state", state)
@@ -988,7 +990,7 @@ class Var(Generic[VAR_TYPE]):
988
990
  setattr(state, actual_name, value)
989
991
  except ValueError:
990
992
  console.debug(
991
- f"{type(state).__name__}.{self._js_expr}: Failed conversion of {value} to '{self._var_type.__name__}'. Value not set.",
993
+ f"{type(state).__name__}.{self._js_expr}: Failed conversion of {value!s} to '{self._var_type.__name__}'. Value not set.",
992
994
  )
993
995
  else:
994
996
  setattr(state, actual_name, value)
@@ -1058,7 +1060,9 @@ class Var(Generic[VAR_TYPE]):
1058
1060
 
1059
1061
  return boolify(self)
1060
1062
 
1061
- def __and__(self, other: Var | Any) -> Var:
1063
+ def __and__(
1064
+ self, other: Var[OTHER_VAR_TYPE] | Any
1065
+ ) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
1062
1066
  """Perform a logical AND operation on the current instance and another variable.
1063
1067
 
1064
1068
  Args:
@@ -1069,7 +1073,9 @@ class Var(Generic[VAR_TYPE]):
1069
1073
  """
1070
1074
  return and_operation(self, other)
1071
1075
 
1072
- def __rand__(self, other: Var | Any) -> Var:
1076
+ def __rand__(
1077
+ self, other: Var[OTHER_VAR_TYPE] | Any
1078
+ ) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
1073
1079
  """Perform a logical AND operation on the current instance and another variable.
1074
1080
 
1075
1081
  Args:
@@ -1080,7 +1086,9 @@ class Var(Generic[VAR_TYPE]):
1080
1086
  """
1081
1087
  return and_operation(other, self)
1082
1088
 
1083
- def __or__(self, other: Var | Any) -> Var:
1089
+ def __or__(
1090
+ self, other: Var[OTHER_VAR_TYPE] | Any
1091
+ ) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
1084
1092
  """Perform a logical OR operation on the current instance and another variable.
1085
1093
 
1086
1094
  Args:
@@ -1091,7 +1099,9 @@ class Var(Generic[VAR_TYPE]):
1091
1099
  """
1092
1100
  return or_operation(self, other)
1093
1101
 
1094
- def __ror__(self, other: Var | Any) -> Var:
1102
+ def __ror__(
1103
+ self, other: Var[OTHER_VAR_TYPE] | Any
1104
+ ) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
1095
1105
  """Perform a logical OR operation on the current instance and another variable.
1096
1106
 
1097
1107
  Args:
@@ -1478,7 +1488,7 @@ class LiteralVar(Var):
1478
1488
  _var_literal_subclasses.append((cls, var_subclass))
1479
1489
 
1480
1490
  @classmethod
1481
- def create( # pyright: ignore [reportArgumentType]
1491
+ def _create_literal_var(
1482
1492
  cls,
1483
1493
  value: Any,
1484
1494
  _var_data: VarData | None = None,
@@ -1559,6 +1569,9 @@ class LiteralVar(Var):
1559
1569
  f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
1560
1570
  )
1561
1571
 
1572
+ if not TYPE_CHECKING:
1573
+ create = _create_literal_var
1574
+
1562
1575
  def __post_init__(self):
1563
1576
  """Post-initialize the var."""
1564
1577
 
@@ -1835,6 +1848,21 @@ class cached_property: # noqa: N801
1835
1848
  cached_property_no_lock = cached_property
1836
1849
 
1837
1850
 
1851
+ class VarProtocol(Protocol):
1852
+ """A protocol for Var."""
1853
+
1854
+ __dataclass_fields__: ClassVar[dict[str, dataclasses.Field[Any]]]
1855
+
1856
+ @property
1857
+ def _js_expr(self) -> str: ...
1858
+
1859
+ @property
1860
+ def _var_type(self) -> types.GenericType: ...
1861
+
1862
+ @property
1863
+ def _var_data(self) -> VarData: ...
1864
+
1865
+
1838
1866
  class CachedVarOperation:
1839
1867
  """Base class for cached var operations to lower boilerplate code."""
1840
1868
 
@@ -1869,7 +1897,7 @@ class CachedVarOperation:
1869
1897
  return self._cached_get_all_var_data
1870
1898
 
1871
1899
  @cached_property_no_lock
1872
- def _cached_get_all_var_data(self) -> VarData | None:
1900
+ def _cached_get_all_var_data(self: VarProtocol) -> VarData | None:
1873
1901
  """Get the cached VarData.
1874
1902
 
1875
1903
  Returns:
@@ -1879,14 +1907,13 @@ class CachedVarOperation:
1879
1907
  *(
1880
1908
  value._get_all_var_data() if isinstance(value, Var) else None
1881
1909
  for value in (
1882
- getattr(self, field.name)
1883
- for field in dataclasses.fields(self) # pyright: ignore [reportArgumentType]
1910
+ getattr(self, field.name) for field in dataclasses.fields(self)
1884
1911
  )
1885
1912
  ),
1886
1913
  self._var_data,
1887
1914
  )
1888
1915
 
1889
- def __hash__(self) -> int:
1916
+ def __hash__(self: DataclassInstance) -> int:
1890
1917
  """Calculate the hash of the object.
1891
1918
 
1892
1919
  Returns:
@@ -1897,14 +1924,16 @@ class CachedVarOperation:
1897
1924
  type(self).__name__,
1898
1925
  *[
1899
1926
  getattr(self, field.name)
1900
- for field in dataclasses.fields(self) # pyright: ignore [reportArgumentType]
1927
+ for field in dataclasses.fields(self)
1901
1928
  if field.name not in ["_js_expr", "_var_data", "_var_type"]
1902
1929
  ],
1903
1930
  )
1904
1931
  )
1905
1932
 
1906
1933
 
1907
- def and_operation(a: Var | Any, b: Var | Any) -> Var:
1934
+ def and_operation(
1935
+ a: Var[VAR_TYPE] | Any, b: Var[OTHER_VAR_TYPE] | Any
1936
+ ) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
1908
1937
  """Perform a logical AND operation on two variables.
1909
1938
 
1910
1939
  Args:
@@ -1934,7 +1963,9 @@ def _and_operation(a: Var, b: Var):
1934
1963
  )
1935
1964
 
1936
1965
 
1937
- def or_operation(a: Var | Any, b: Var | Any) -> Var:
1966
+ def or_operation(
1967
+ a: Var[VAR_TYPE] | Any, b: Var[OTHER_VAR_TYPE] | Any
1968
+ ) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
1938
1969
  """Perform a logical OR operation on two variables.
1939
1970
 
1940
1971
  Args:
@@ -2340,7 +2371,7 @@ class ComputedVar(Var[RETURN_TYPE]):
2340
2371
  if not _isinstance(value, self._var_type, nested=1, treat_var_as_type=False):
2341
2372
  console.error(
2342
2373
  f"Computed var '{type(instance).__name__}.{self._js_expr}' must return"
2343
- f" a value of type '{self._var_type}', got '{value}' of type {type(value)}."
2374
+ f" a value of type '{self._var_type}', got '{value!s}' of type {type(value)}."
2344
2375
  )
2345
2376
 
2346
2377
  def _deps(
@@ -2976,7 +3007,7 @@ def get_uuid_string_var() -> Var:
2976
3007
  unique_uuid_var = get_unique_variable_name()
2977
3008
  unique_uuid_var_data = VarData(
2978
3009
  imports={
2979
- f"$/{constants.Dirs.STATE_PATH}": {ImportVar(tag="generateUUID")}, # pyright: ignore [reportArgumentType]
3010
+ f"$/{constants.Dirs.STATE_PATH}": ImportVar(tag="generateUUID"),
2980
3011
  "react": "useMemo",
2981
3012
  },
2982
3013
  hooks={f"const {unique_uuid_var} = useMemo(generateUUID, [])": None},
@@ -3286,10 +3317,15 @@ class Field(Generic[FIELD_TYPE]):
3286
3317
 
3287
3318
  @overload
3288
3319
  def __get__(
3289
- self: Field[int]
3290
- | Field[float]
3320
+ self: Field[int] | Field[int | None],
3321
+ instance: None,
3322
+ owner: Any,
3323
+ ) -> NumberVar[int]: ...
3324
+
3325
+ @overload
3326
+ def __get__(
3327
+ self: Field[float]
3291
3328
  | Field[int | float]
3292
- | Field[int | None]
3293
3329
  | Field[float | None]
3294
3330
  | Field[int | float | None],
3295
3331
  instance: None,
reflex/vars/number.py CHANGED
@@ -16,6 +16,8 @@ from typing import (
16
16
  overload,
17
17
  )
18
18
 
19
+ from typing_extensions import TypeVar as TypeVarExt
20
+
19
21
  from reflex.constants.base import Dirs
20
22
  from reflex.utils.exceptions import (
21
23
  PrimitiveUnserializableToJSONError,
@@ -35,7 +37,9 @@ from .base import (
35
37
  var_operation_return,
36
38
  )
37
39
 
38
- NUMBER_T = TypeVar("NUMBER_T", int, float, bool)
40
+ NUMBER_T = TypeVarExt(
41
+ "NUMBER_T", bound=(int | float), default=(int | float), covariant=True
42
+ )
39
43
 
40
44
  if TYPE_CHECKING:
41
45
  from .sequence import ArrayVar
@@ -313,13 +317,19 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
313
317
  """
314
318
  return self
315
319
 
316
- def __round__(self):
320
+ def __round__(self, ndigits: int | NumberVar = 0) -> NumberVar:
317
321
  """Round the number.
318
322
 
323
+ Args:
324
+ ndigits: The number of digits to round.
325
+
319
326
  Returns:
320
327
  The number round operation.
321
328
  """
322
- return number_round_operation(self)
329
+ if not isinstance(ndigits, NUMBER_TYPES):
330
+ raise_unsupported_operand_types("round", (type(self), type(ndigits)))
331
+
332
+ return number_round_operation(self, +ndigits)
323
333
 
324
334
  def __ceil__(self):
325
335
  """Ceil the number.
@@ -653,16 +663,23 @@ def number_exponent_operation(lhs: NumberVar, rhs: NumberVar):
653
663
 
654
664
 
655
665
  @var_operation
656
- def number_round_operation(value: NumberVar):
666
+ def number_round_operation(value: NumberVar, ndigits: NumberVar | int):
657
667
  """Round the number.
658
668
 
659
669
  Args:
660
670
  value: The number.
671
+ ndigits: The number of digits.
661
672
 
662
673
  Returns:
663
674
  The number round operation.
664
675
  """
665
- return var_operation_return(js_expression=f"Math.round({value})", var_type=int)
676
+ if (isinstance(ndigits, LiteralNumberVar) and ndigits._var_value == 0) or (
677
+ isinstance(ndigits, int) and ndigits == 0
678
+ ):
679
+ return var_operation_return(js_expression=f"Math.round({value})", var_type=int)
680
+ return var_operation_return(
681
+ js_expression=f"(+{value}.toFixed({ndigits}))", var_type=float
682
+ )
666
683
 
667
684
 
668
685
  @var_operation
@@ -1064,7 +1081,7 @@ U = TypeVar("U")
1064
1081
 
1065
1082
  @var_operation
1066
1083
  def ternary_operation(
1067
- condition: BooleanVar, if_true: Var[T], if_false: Var[U]
1084
+ condition: Var[bool], if_true: Var[T], if_false: Var[U]
1068
1085
  ) -> CustomVarOperationReturn[T | U]:
1069
1086
  """Create a ternary operation.
1070
1087
 
reflex/vars/sequence.py CHANGED
@@ -1604,6 +1604,8 @@ def _determine_value_of_array_index(
1604
1604
  return args[0] if args else Any
1605
1605
  if origin_var_type is tuple:
1606
1606
  args = get_args(var_type)
1607
+ if len(args) == 2 and args[1] is ...:
1608
+ return args[0]
1607
1609
  return (
1608
1610
  args[int(index) % len(args)]
1609
1611
  if args and index is not None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reflex
3
- Version: 0.7.4a2
3
+ Version: 0.7.5
4
4
  Summary: Web apps in pure Python.
5
5
  Project-URL: homepage, https://reflex.dev
6
6
  Project-URL: repository, https://github.com/reflex-dev/reflex
@@ -23,7 +23,7 @@ Requires-Dist: build<2.0,>=1.0.3
23
23
  Requires-Dist: charset-normalizer<4.0,>=3.3.2
24
24
  Requires-Dist: distro<2.0,>=1.8.0; platform_system == 'Linux'
25
25
  Requires-Dist: fastapi!=0.111.0,!=0.111.1,>=0.96.0
26
- Requires-Dist: granian[reload]>=2.0.0
26
+ Requires-Dist: granian[reload]>=2.2.0
27
27
  Requires-Dist: gunicorn<24.0.0,>=23.0.0
28
28
  Requires-Dist: httpx<1.0,>=0.25.1
29
29
  Requires-Dist: jinja2<4.0,>=3.1.2