reflex 0.6.6.post2__py3-none-any.whl → 0.6.7__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 (141) hide show
  1. reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +5 -1
  2. reflex/.templates/web/utils/state.js +36 -28
  3. reflex/__init__.py +1 -1
  4. reflex/__init__.pyi +1 -0
  5. reflex/app.py +41 -16
  6. reflex/assets.py +2 -2
  7. reflex/base.py +8 -7
  8. reflex/compiler/templates.py +1 -0
  9. reflex/compiler/utils.py +2 -3
  10. reflex/components/base/bare.py +2 -2
  11. reflex/components/component.py +54 -29
  12. reflex/components/core/banner.py +2 -2
  13. reflex/components/core/banner.pyi +1 -1
  14. reflex/components/core/client_side_routing.py +2 -2
  15. reflex/components/core/client_side_routing.pyi +1 -1
  16. reflex/components/core/clipboard.py +11 -9
  17. reflex/components/core/clipboard.pyi +1 -1
  18. reflex/components/core/cond.py +3 -3
  19. reflex/components/core/foreach.py +1 -1
  20. reflex/components/core/html.pyi +1 -1
  21. reflex/components/core/upload.py +8 -8
  22. reflex/components/datadisplay/code.py +5 -5
  23. reflex/components/datadisplay/dataeditor.py +8 -28
  24. reflex/components/datadisplay/dataeditor.pyi +1 -1
  25. reflex/components/datadisplay/shiki_code_block.py +7 -7
  26. reflex/components/dynamic.py +2 -2
  27. reflex/components/el/elements/__init__.py +1 -1
  28. reflex/components/el/elements/__init__.pyi +1 -1
  29. reflex/components/el/elements/base.py +2 -2
  30. reflex/components/el/elements/base.pyi +1 -1
  31. reflex/components/el/elements/forms.py +40 -10
  32. reflex/components/el/elements/forms.pyi +17 -15
  33. reflex/components/el/elements/inline.py +1 -1
  34. reflex/components/el/elements/inline.pyi +28 -28
  35. reflex/components/el/elements/media.py +1 -4
  36. reflex/components/el/elements/media.pyi +25 -26
  37. reflex/components/el/elements/metadata.py +6 -6
  38. reflex/components/el/elements/metadata.pyi +4 -4
  39. reflex/components/el/elements/other.py +17 -9
  40. reflex/components/el/elements/other.pyi +7 -7
  41. reflex/components/el/elements/scripts.py +1 -2
  42. reflex/components/el/elements/scripts.pyi +3 -3
  43. reflex/components/el/elements/sectioning.py +16 -16
  44. reflex/components/el/elements/sectioning.pyi +15 -15
  45. reflex/components/el/elements/tables.py +1 -1
  46. reflex/components/el/elements/tables.pyi +10 -10
  47. reflex/components/el/elements/typography.py +1 -1
  48. reflex/components/el/elements/typography.pyi +15 -15
  49. reflex/components/markdown/markdown.py +3 -3
  50. reflex/components/next/image.py +1 -1
  51. reflex/components/next/image.pyi +1 -1
  52. reflex/components/plotly/plotly.py +2 -2
  53. reflex/components/radix/primitives/accordion.py +2 -1
  54. reflex/components/radix/primitives/form.pyi +3 -3
  55. reflex/components/radix/primitives/slider.py +1 -1
  56. reflex/components/radix/themes/base.py +4 -10
  57. reflex/components/radix/themes/color_mode.pyi +2 -2
  58. reflex/components/radix/themes/components/alert_dialog.pyi +1 -1
  59. reflex/components/radix/themes/components/badge.pyi +1 -1
  60. reflex/components/radix/themes/components/button.pyi +1 -1
  61. reflex/components/radix/themes/components/callout.pyi +5 -5
  62. reflex/components/radix/themes/components/card.pyi +1 -1
  63. reflex/components/radix/themes/components/checkbox.pyi +3 -3
  64. reflex/components/radix/themes/components/context_menu.py +11 -0
  65. reflex/components/radix/themes/components/context_menu.pyi +155 -0
  66. reflex/components/radix/themes/components/dialog.pyi +1 -1
  67. reflex/components/radix/themes/components/hover_card.pyi +1 -1
  68. reflex/components/radix/themes/components/icon_button.py +1 -1
  69. reflex/components/radix/themes/components/icon_button.pyi +1 -1
  70. reflex/components/radix/themes/components/inset.pyi +1 -1
  71. reflex/components/radix/themes/components/popover.pyi +1 -1
  72. reflex/components/radix/themes/components/radio_group.py +2 -4
  73. reflex/components/radix/themes/components/radio_group.pyi +1 -1
  74. reflex/components/radix/themes/components/select.pyi +3 -3
  75. reflex/components/radix/themes/components/slider.pyi +1 -1
  76. reflex/components/radix/themes/components/switch.pyi +1 -1
  77. reflex/components/radix/themes/components/table.pyi +7 -7
  78. reflex/components/radix/themes/components/tabs.pyi +2 -2
  79. reflex/components/radix/themes/components/text_area.py +3 -0
  80. reflex/components/radix/themes/components/text_area.pyi +3 -1
  81. reflex/components/radix/themes/components/text_field.py +16 -1
  82. reflex/components/radix/themes/components/text_field.pyi +105 -17
  83. reflex/components/radix/themes/layout/box.pyi +1 -1
  84. reflex/components/radix/themes/layout/center.pyi +1 -1
  85. reflex/components/radix/themes/layout/flex.pyi +1 -1
  86. reflex/components/radix/themes/layout/grid.pyi +1 -1
  87. reflex/components/radix/themes/layout/list.py +0 -4
  88. reflex/components/radix/themes/layout/list.pyi +3 -8
  89. reflex/components/radix/themes/layout/section.pyi +1 -1
  90. reflex/components/radix/themes/layout/spacer.pyi +1 -1
  91. reflex/components/radix/themes/layout/stack.pyi +3 -3
  92. reflex/components/radix/themes/typography/blockquote.pyi +1 -1
  93. reflex/components/radix/themes/typography/code.pyi +1 -1
  94. reflex/components/radix/themes/typography/heading.pyi +1 -1
  95. reflex/components/radix/themes/typography/link.py +5 -1
  96. reflex/components/radix/themes/typography/link.pyi +1 -1
  97. reflex/components/radix/themes/typography/text.pyi +7 -7
  98. reflex/components/recharts/cartesian.py +1 -1
  99. reflex/components/recharts/charts.py +4 -4
  100. reflex/components/recharts/polar.py +1 -1
  101. reflex/components/recharts/polar.pyi +1 -1
  102. reflex/components/sonner/toast.py +4 -7
  103. reflex/components/suneditor/editor.py +6 -6
  104. reflex/components/suneditor/editor.pyi +6 -6
  105. reflex/config.py +25 -10
  106. reflex/constants/compiler.py +6 -0
  107. reflex/constants/config.py +2 -0
  108. reflex/constants/custom_components.py +1 -1
  109. reflex/constants/route.py +1 -1
  110. reflex/custom_components/custom_components.py +21 -21
  111. reflex/event.py +57 -22
  112. reflex/experimental/client_state.py +2 -1
  113. reflex/experimental/layout.py +0 -6
  114. reflex/model.py +125 -9
  115. reflex/reflex.py +12 -8
  116. reflex/state.py +200 -88
  117. reflex/style.py +1 -4
  118. reflex/testing.py +10 -11
  119. reflex/utils/build.py +1 -1
  120. reflex/utils/console.py +75 -6
  121. reflex/utils/exceptions.py +12 -0
  122. reflex/utils/exec.py +10 -10
  123. reflex/utils/export.py +1 -2
  124. reflex/utils/format.py +11 -8
  125. reflex/utils/path_ops.py +2 -2
  126. reflex/utils/prerequisites.py +31 -28
  127. reflex/utils/processes.py +4 -4
  128. reflex/utils/pyi_generator.py +12 -11
  129. reflex/utils/types.py +6 -3
  130. reflex/vars/__init__.py +1 -0
  131. reflex/vars/base.py +75 -38
  132. reflex/vars/datetime.py +222 -0
  133. reflex/vars/function.py +3 -3
  134. reflex/vars/number.py +3 -3
  135. reflex/vars/object.py +5 -5
  136. reflex/vars/sequence.py +7 -7
  137. {reflex-0.6.6.post2.dist-info → reflex-0.6.7.dist-info}/METADATA +2 -2
  138. {reflex-0.6.6.post2.dist-info → reflex-0.6.7.dist-info}/RECORD +141 -140
  139. {reflex-0.6.6.post2.dist-info → reflex-0.6.7.dist-info}/LICENSE +0 -0
  140. {reflex-0.6.6.post2.dist-info → reflex-0.6.7.dist-info}/WHEEL +0 -0
  141. {reflex-0.6.6.post2.dist-info → reflex-0.6.7.dist-info}/entry_points.txt +0 -0
reflex/vars/base.py CHANGED
@@ -42,7 +42,8 @@ from typing_extensions import ParamSpec, TypeGuard, deprecated, get_type_hints,
42
42
 
43
43
  from reflex import constants
44
44
  from reflex.base import Base
45
- from reflex.utils import console, imports, serializers, types
45
+ from reflex.constants.compiler import Hooks
46
+ from reflex.utils import console, exceptions, imports, serializers, types
46
47
  from reflex.utils.exceptions import (
47
48
  VarAttributeError,
48
49
  VarDependencyError,
@@ -115,12 +116,20 @@ class VarData:
115
116
  # Hooks that need to be present in the component to render this var
116
117
  hooks: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
117
118
 
119
+ # Dependencies of the var
120
+ deps: Tuple[Var, ...] = dataclasses.field(default_factory=tuple)
121
+
122
+ # Position of the hook in the component
123
+ position: Hooks.HookPosition | None = None
124
+
118
125
  def __init__(
119
126
  self,
120
127
  state: str = "",
121
128
  field_name: str = "",
122
129
  imports: ImportDict | ParsedImportDict | None = None,
123
130
  hooks: dict[str, None] | None = None,
131
+ deps: list[Var] | None = None,
132
+ position: Hooks.HookPosition | None = None,
124
133
  ):
125
134
  """Initialize the var data.
126
135
 
@@ -129,6 +138,8 @@ class VarData:
129
138
  field_name: The name of the field in the state.
130
139
  imports: Imports needed to render this var.
131
140
  hooks: Hooks that need to be present in the component to render this var.
141
+ deps: Dependencies of the var for useCallback.
142
+ position: Position of the hook in the component.
132
143
  """
133
144
  immutable_imports: ImmutableParsedImportDict = tuple(
134
145
  sorted(
@@ -139,6 +150,8 @@ class VarData:
139
150
  object.__setattr__(self, "field_name", field_name)
140
151
  object.__setattr__(self, "imports", immutable_imports)
141
152
  object.__setattr__(self, "hooks", tuple(hooks or {}))
153
+ object.__setattr__(self, "deps", tuple(deps or []))
154
+ object.__setattr__(self, "position", position or None)
142
155
 
143
156
  def old_school_imports(self) -> ImportDict:
144
157
  """Return the imports as a mutable dict.
@@ -146,7 +159,7 @@ class VarData:
146
159
  Returns:
147
160
  The imports as a mutable dict.
148
161
  """
149
- return dict((k, list(v)) for k, v in self.imports)
162
+ return {k: list(v) for k, v in self.imports}
150
163
 
151
164
  def merge(*all: VarData | None) -> VarData | None:
152
165
  """Merge multiple var data objects.
@@ -154,6 +167,9 @@ class VarData:
154
167
  Args:
155
168
  *all: The var data objects to merge.
156
169
 
170
+ Raises:
171
+ ReflexError: If trying to merge VarData with different positions.
172
+
157
173
  Returns:
158
174
  The merged var data object.
159
175
 
@@ -184,12 +200,32 @@ class VarData:
184
200
  *(var_data.imports for var_data in all_var_datas)
185
201
  )
186
202
 
187
- if state or _imports or hooks or field_name:
203
+ deps = [dep for var_data in all_var_datas for dep in var_data.deps]
204
+
205
+ positions = list(
206
+ {
207
+ var_data.position
208
+ for var_data in all_var_datas
209
+ if var_data.position is not None
210
+ }
211
+ )
212
+ if positions:
213
+ if len(positions) > 1:
214
+ raise exceptions.ReflexError(
215
+ f"Cannot merge var data with different positions: {positions}"
216
+ )
217
+ position = positions[0]
218
+ else:
219
+ position = None
220
+
221
+ if state or _imports or hooks or field_name or deps or position:
188
222
  return VarData(
189
223
  state=state,
190
224
  field_name=field_name,
191
225
  imports=_imports,
192
226
  hooks=hooks,
227
+ deps=deps,
228
+ position=position,
193
229
  )
194
230
 
195
231
  return None
@@ -200,7 +236,14 @@ class VarData:
200
236
  Returns:
201
237
  True if any field is set to a non-default value.
202
238
  """
203
- return bool(self.state or self.imports or self.hooks or self.field_name)
239
+ return bool(
240
+ self.state
241
+ or self.imports
242
+ or self.hooks
243
+ or self.field_name
244
+ or self.deps
245
+ or self.position
246
+ )
204
247
 
205
248
  @classmethod
206
249
  def from_state(cls, state: Type[BaseState] | str, field_name: str = "") -> VarData:
@@ -480,7 +523,6 @@ class Var(Generic[VAR_TYPE]):
480
523
  raise TypeError(
481
524
  "The _var_full_name_needs_state_prefix argument is not supported for Var."
482
525
  )
483
-
484
526
  value_with_replaced = dataclasses.replace(
485
527
  self,
486
528
  _var_type=_var_type or self._var_type,
@@ -1057,7 +1099,7 @@ class Var(Generic[VAR_TYPE]):
1057
1099
 
1058
1100
  if self._var_type is Any:
1059
1101
  raise TypeError(
1060
- f"You must provide an annotation for the state var `{str(self)}`. Annotation cannot be `{self._var_type}`."
1102
+ f"You must provide an annotation for the state var `{self!s}`. Annotation cannot be `{self._var_type}`."
1061
1103
  )
1062
1104
 
1063
1105
  if name in REPLACED_NAMES:
@@ -1569,7 +1611,7 @@ class CachedVarOperation:
1569
1611
  if name == "_js_expr":
1570
1612
  return self._cached_var_name
1571
1613
 
1572
- parent_classes = inspect.getmro(self.__class__)
1614
+ parent_classes = inspect.getmro(type(self))
1573
1615
 
1574
1616
  next_class = parent_classes[parent_classes.index(CachedVarOperation) + 1]
1575
1617
 
@@ -1591,14 +1633,12 @@ class CachedVarOperation:
1591
1633
  The cached VarData.
1592
1634
  """
1593
1635
  return VarData.merge(
1594
- *map(
1595
- lambda value: (
1596
- value._get_all_var_data() if isinstance(value, Var) else None
1597
- ),
1598
- map(
1599
- lambda field: getattr(self, field.name),
1600
- dataclasses.fields(self), # type: ignore
1601
- ),
1636
+ *(
1637
+ value._get_all_var_data() if isinstance(value, Var) else None
1638
+ for value in (
1639
+ getattr(self, field.name)
1640
+ for field in dataclasses.fields(self) # type: ignore
1641
+ )
1602
1642
  ),
1603
1643
  self._var_data,
1604
1644
  )
@@ -1611,7 +1651,7 @@ class CachedVarOperation:
1611
1651
  """
1612
1652
  return hash(
1613
1653
  (
1614
- self.__class__.__name__,
1654
+ type(self).__name__,
1615
1655
  *[
1616
1656
  getattr(self, field.name)
1617
1657
  for field in dataclasses.fields(self) # type: ignore
@@ -1733,7 +1773,7 @@ class CallableVar(Var):
1733
1773
  Returns:
1734
1774
  The hash of the object.
1735
1775
  """
1736
- return hash((self.__class__.__name__, self.original_var))
1776
+ return hash((type(self).__name__, self.original_var))
1737
1777
 
1738
1778
 
1739
1779
  RETURN_TYPE = TypeVar("RETURN_TYPE")
@@ -1889,20 +1929,20 @@ class ComputedVar(Var[RETURN_TYPE]):
1889
1929
  Raises:
1890
1930
  TypeError: If kwargs contains keys that are not allowed.
1891
1931
  """
1892
- field_values = dict(
1893
- fget=kwargs.pop("fget", self._fget),
1894
- initial_value=kwargs.pop("initial_value", self._initial_value),
1895
- cache=kwargs.pop("cache", self._cache),
1896
- deps=kwargs.pop("deps", self._static_deps),
1897
- auto_deps=kwargs.pop("auto_deps", self._auto_deps),
1898
- interval=kwargs.pop("interval", self._update_interval),
1899
- backend=kwargs.pop("backend", self._backend),
1900
- _js_expr=kwargs.pop("_js_expr", self._js_expr),
1901
- _var_type=kwargs.pop("_var_type", self._var_type),
1902
- _var_data=kwargs.pop(
1932
+ field_values = {
1933
+ "fget": kwargs.pop("fget", self._fget),
1934
+ "initial_value": kwargs.pop("initial_value", self._initial_value),
1935
+ "cache": kwargs.pop("cache", self._cache),
1936
+ "deps": kwargs.pop("deps", self._static_deps),
1937
+ "auto_deps": kwargs.pop("auto_deps", self._auto_deps),
1938
+ "interval": kwargs.pop("interval", self._update_interval),
1939
+ "backend": kwargs.pop("backend", self._backend),
1940
+ "_js_expr": kwargs.pop("_js_expr", self._js_expr),
1941
+ "_var_type": kwargs.pop("_var_type", self._var_type),
1942
+ "_var_data": kwargs.pop(
1903
1943
  "_var_data", VarData.merge(self._var_data, merge_var_data)
1904
1944
  ),
1905
- )
1945
+ }
1906
1946
 
1907
1947
  if kwargs:
1908
1948
  unexpected_kwargs = ", ".join(kwargs.keys())
@@ -2117,7 +2157,7 @@ class ComputedVar(Var[RETURN_TYPE]):
2117
2157
  ref_obj = None
2118
2158
  if instruction.argval in invalid_names:
2119
2159
  raise VarValueError(
2120
- f"Cached var {str(self)} cannot access arbitrary state via `{instruction.argval}`."
2160
+ f"Cached var {self!s} cannot access arbitrary state via `{instruction.argval}`."
2121
2161
  )
2122
2162
  if callable(ref_obj):
2123
2163
  # recurse into callable attributes
@@ -2371,10 +2411,7 @@ class CustomVarOperation(CachedVarOperation, Var[T]):
2371
2411
  The cached VarData.
2372
2412
  """
2373
2413
  return VarData.merge(
2374
- *map(
2375
- lambda arg: arg[1]._get_all_var_data(),
2376
- self._args,
2377
- ),
2414
+ *(arg[1]._get_all_var_data() for arg in self._args),
2378
2415
  self._return._get_all_var_data(),
2379
2416
  self._var_data,
2380
2417
  )
@@ -2492,7 +2529,7 @@ class StateOperation(CachedVarOperation, Var):
2492
2529
  Returns:
2493
2530
  The cached var name.
2494
2531
  """
2495
- return f"{str(self._state_name)}.{str(self._field)}"
2532
+ return f"{self._state_name!s}.{self._field!s}"
2496
2533
 
2497
2534
  def __getattr__(self, name: str) -> Any:
2498
2535
  """Get an attribute of the var.
@@ -2804,9 +2841,9 @@ def dispatch(
2804
2841
 
2805
2842
  if result_origin_var_type in dispatchers:
2806
2843
  fn = dispatchers[result_origin_var_type]
2807
- fn_first_arg_type = list(inspect.signature(fn).parameters.values())[
2808
- 0
2809
- ].annotation
2844
+ fn_first_arg_type = next(
2845
+ iter(inspect.signature(fn).parameters.values())
2846
+ ).annotation
2810
2847
 
2811
2848
  fn_return = inspect.signature(fn).return_annotation
2812
2849
 
@@ -0,0 +1,222 @@
1
+ """Immutable datetime and date vars."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import dataclasses
6
+ import sys
7
+ from datetime import date, datetime
8
+ from typing import Any, NoReturn, TypeVar, Union, overload
9
+
10
+ from reflex.utils.exceptions import VarTypeError
11
+ from reflex.vars.number import BooleanVar
12
+
13
+ from .base import (
14
+ CustomVarOperationReturn,
15
+ LiteralVar,
16
+ Var,
17
+ VarData,
18
+ var_operation,
19
+ var_operation_return,
20
+ )
21
+
22
+ DATETIME_T = TypeVar("DATETIME_T", datetime, date)
23
+
24
+ datetime_types = Union[datetime, date]
25
+
26
+
27
+ def raise_var_type_error():
28
+ """Raise a VarTypeError.
29
+
30
+ Raises:
31
+ VarTypeError: Cannot compare a datetime object with a non-datetime object.
32
+ """
33
+ raise VarTypeError("Cannot compare a datetime object with a non-datetime object.")
34
+
35
+
36
+ class DateTimeVar(Var[DATETIME_T], python_types=(datetime, date)):
37
+ """A variable that holds a datetime or date object."""
38
+
39
+ @overload
40
+ def __lt__(self, other: datetime_types) -> BooleanVar: ...
41
+
42
+ @overload
43
+ def __lt__(self, other: NoReturn) -> NoReturn: ...
44
+
45
+ def __lt__(self, other: Any):
46
+ """Less than comparison.
47
+
48
+ Args:
49
+ other: The other datetime to compare.
50
+
51
+ Returns:
52
+ The result of the comparison.
53
+ """
54
+ if not isinstance(other, DATETIME_TYPES):
55
+ raise_var_type_error()
56
+ return date_lt_operation(self, other)
57
+
58
+ @overload
59
+ def __le__(self, other: datetime_types) -> BooleanVar: ...
60
+
61
+ @overload
62
+ def __le__(self, other: NoReturn) -> NoReturn: ...
63
+
64
+ def __le__(self, other: Any):
65
+ """Less than or equal comparison.
66
+
67
+ Args:
68
+ other: The other datetime to compare.
69
+
70
+ Returns:
71
+ The result of the comparison.
72
+ """
73
+ if not isinstance(other, DATETIME_TYPES):
74
+ raise_var_type_error()
75
+ return date_le_operation(self, other)
76
+
77
+ @overload
78
+ def __gt__(self, other: datetime_types) -> BooleanVar: ...
79
+
80
+ @overload
81
+ def __gt__(self, other: NoReturn) -> NoReturn: ...
82
+
83
+ def __gt__(self, other: Any):
84
+ """Greater than comparison.
85
+
86
+ Args:
87
+ other: The other datetime to compare.
88
+
89
+ Returns:
90
+ The result of the comparison.
91
+ """
92
+ if not isinstance(other, DATETIME_TYPES):
93
+ raise_var_type_error()
94
+ return date_gt_operation(self, other)
95
+
96
+ @overload
97
+ def __ge__(self, other: datetime_types) -> BooleanVar: ...
98
+
99
+ @overload
100
+ def __ge__(self, other: NoReturn) -> NoReturn: ...
101
+
102
+ def __ge__(self, other: Any):
103
+ """Greater than or equal comparison.
104
+
105
+ Args:
106
+ other: The other datetime to compare.
107
+
108
+ Returns:
109
+ The result of the comparison.
110
+ """
111
+ if not isinstance(other, DATETIME_TYPES):
112
+ raise_var_type_error()
113
+ return date_ge_operation(self, other)
114
+
115
+
116
+ @var_operation
117
+ def date_gt_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
118
+ """Greater than comparison.
119
+
120
+ Args:
121
+ lhs: The left-hand side of the operation.
122
+ rhs: The right-hand side of the operation.
123
+
124
+ Returns:
125
+ The result of the operation.
126
+ """
127
+ return date_compare_operation(rhs, lhs, strict=True)
128
+
129
+
130
+ @var_operation
131
+ def date_lt_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
132
+ """Less than comparison.
133
+
134
+ Args:
135
+ lhs: The left-hand side of the operation.
136
+ rhs: The right-hand side of the operation.
137
+
138
+ Returns:
139
+ The result of the operation.
140
+ """
141
+ return date_compare_operation(lhs, rhs, strict=True)
142
+
143
+
144
+ @var_operation
145
+ def date_le_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
146
+ """Less than or equal comparison.
147
+
148
+ Args:
149
+ lhs: The left-hand side of the operation.
150
+ rhs: The right-hand side of the operation.
151
+
152
+ Returns:
153
+ The result of the operation.
154
+ """
155
+ return date_compare_operation(lhs, rhs)
156
+
157
+
158
+ @var_operation
159
+ def date_ge_operation(lhs: Var | Any, rhs: Var | Any) -> CustomVarOperationReturn:
160
+ """Greater than or equal comparison.
161
+
162
+ Args:
163
+ lhs: The left-hand side of the operation.
164
+ rhs: The right-hand side of the operation.
165
+
166
+ Returns:
167
+ The result of the operation.
168
+ """
169
+ return date_compare_operation(rhs, lhs)
170
+
171
+
172
+ def date_compare_operation(
173
+ lhs: DateTimeVar[DATETIME_T] | Any,
174
+ rhs: DateTimeVar[DATETIME_T] | Any,
175
+ strict: bool = False,
176
+ ) -> CustomVarOperationReturn:
177
+ """Check if the value is less than the other value.
178
+
179
+ Args:
180
+ lhs: The left-hand side of the operation.
181
+ rhs: The right-hand side of the operation.
182
+ strict: Whether to use strict comparison.
183
+
184
+ Returns:
185
+ The result of the operation.
186
+ """
187
+ return var_operation_return(
188
+ f"({lhs} { '<' if strict else '<='} {rhs})",
189
+ bool,
190
+ )
191
+
192
+
193
+ @dataclasses.dataclass(
194
+ eq=False,
195
+ frozen=True,
196
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
197
+ )
198
+ class LiteralDatetimeVar(LiteralVar, DateTimeVar):
199
+ """Base class for immutable datetime and date vars."""
200
+
201
+ _var_value: datetime | date = dataclasses.field(default=datetime.now())
202
+
203
+ @classmethod
204
+ def create(cls, value: datetime | date, _var_data: VarData | None = None):
205
+ """Create a new instance of the class.
206
+
207
+ Args:
208
+ value: The value to set.
209
+
210
+ Returns:
211
+ LiteralDatetimeVar: The new instance of the class.
212
+ """
213
+ js_expr = f'"{value!s}"'
214
+ return cls(
215
+ _js_expr=js_expr,
216
+ _var_type=type(value),
217
+ _var_value=value,
218
+ _var_data=_var_data,
219
+ )
220
+
221
+
222
+ DATETIME_TYPES = (datetime, date, DateTimeVar)
reflex/vars/function.py CHANGED
@@ -240,7 +240,7 @@ class VarOperationCall(Generic[P, R], CachedVarOperation, Var[R]):
240
240
  Returns:
241
241
  The name of the var.
242
242
  """
243
- return f"({str(self._func)}({', '.join([str(LiteralVar.create(arg)) for arg in self._args])}))"
243
+ return f"({self._func!s}({', '.join([str(LiteralVar.create(arg)) for arg in self._args])}))"
244
244
 
245
245
  @cached_property_no_lock
246
246
  def _cached_get_all_var_data(self) -> VarData | None:
@@ -292,7 +292,7 @@ class VarOperationCall(Generic[P, R], CachedVarOperation, Var[R]):
292
292
  class DestructuredArg:
293
293
  """Class for destructured arguments."""
294
294
 
295
- fields: Tuple[str, ...] = tuple()
295
+ fields: Tuple[str, ...] = ()
296
296
  rest: Optional[str] = None
297
297
 
298
298
  def to_javascript(self) -> str:
@@ -314,7 +314,7 @@ class DestructuredArg:
314
314
  class FunctionArgs:
315
315
  """Class for function arguments."""
316
316
 
317
- args: Tuple[Union[str, DestructuredArg], ...] = tuple()
317
+ args: Tuple[Union[str, DestructuredArg], ...] = ()
318
318
  rest: Optional[str] = None
319
319
 
320
320
 
reflex/vars/number.py CHANGED
@@ -51,7 +51,7 @@ def raise_unsupported_operand_types(
51
51
  VarTypeError: The operand types are unsupported.
52
52
  """
53
53
  raise VarTypeError(
54
- f"Unsupported Operand type(s) for {operator}: {', '.join(map(lambda t: t.__name__, operands_types))}"
54
+ f"Unsupported Operand type(s) for {operator}: {', '.join(t.__name__ for t in operands_types)}"
55
55
  )
56
56
 
57
57
 
@@ -1012,7 +1012,7 @@ class LiteralNumberVar(LiteralVar, NumberVar):
1012
1012
  Returns:
1013
1013
  int: The hash value of the object.
1014
1014
  """
1015
- return hash((self.__class__.__name__, self._var_value))
1015
+ return hash((type(self).__name__, self._var_value))
1016
1016
 
1017
1017
  @classmethod
1018
1018
  def create(cls, value: float | int, _var_data: VarData | None = None):
@@ -1064,7 +1064,7 @@ class LiteralBooleanVar(LiteralVar, BooleanVar):
1064
1064
  Returns:
1065
1065
  int: The hash value of the object.
1066
1066
  """
1067
- return hash((self.__class__.__name__, self._var_value))
1067
+ return hash((type(self).__name__, self._var_value))
1068
1068
 
1069
1069
  @classmethod
1070
1070
  def create(cls, value: bool, _var_data: VarData | None = None):
reflex/vars/object.py CHANGED
@@ -272,7 +272,7 @@ class ObjectVar(Var[OBJECT_TYPE], python_types=dict):
272
272
  attribute_type = get_attribute_access_type(var_type, name)
273
273
  if attribute_type is None:
274
274
  raise VarAttributeError(
275
- f"The State var `{str(self)}` has no attribute '{name}' or may have been annotated "
275
+ f"The State var `{self!s}` has no attribute '{name}' or may have been annotated "
276
276
  f"wrongly."
277
277
  )
278
278
  return ObjectItemOperation.create(self, name, attribute_type).guess_type()
@@ -332,7 +332,7 @@ class LiteralObjectVar(CachedVarOperation, ObjectVar[OBJECT_TYPE], LiteralVar):
332
332
  "({ "
333
333
  + ", ".join(
334
334
  [
335
- f"[{str(LiteralVar.create(key))}] : {str(LiteralVar.create(value))}"
335
+ f"[{LiteralVar.create(key)!s}] : {LiteralVar.create(value)!s}"
336
336
  for key, value in self._var_value.items()
337
337
  ]
338
338
  )
@@ -362,7 +362,7 @@ class LiteralObjectVar(CachedVarOperation, ObjectVar[OBJECT_TYPE], LiteralVar):
362
362
  Returns:
363
363
  The hash of the var.
364
364
  """
365
- return hash((self.__class__.__name__, self._js_expr))
365
+ return hash((type(self).__name__, self._js_expr))
366
366
 
367
367
  @cached_property_no_lock
368
368
  def _cached_get_all_var_data(self) -> VarData | None:
@@ -494,8 +494,8 @@ class ObjectItemOperation(CachedVarOperation, Var):
494
494
  The name of the operation.
495
495
  """
496
496
  if types.is_optional(self._object._var_type):
497
- return f"{str(self._object)}?.[{str(self._key)}]"
498
- return f"{str(self._object)}[{str(self._key)}]"
497
+ return f"{self._object!s}?.[{self._key!s}]"
498
+ return f"{self._object!s}[{self._key!s}]"
499
499
 
500
500
  @classmethod
501
501
  def create(
reflex/vars/sequence.py CHANGED
@@ -667,7 +667,7 @@ class LiteralStringVar(LiteralVar, StringVar[str]):
667
667
  Returns:
668
668
  The hash of the var.
669
669
  """
670
- return hash((self.__class__.__name__, self._var_value))
670
+ return hash((type(self).__name__, self._var_value))
671
671
 
672
672
  def json(self) -> str:
673
673
  """Get the JSON representation of the var.
@@ -1177,7 +1177,7 @@ class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(list, tuple, set)):
1177
1177
 
1178
1178
  if num_args == 0:
1179
1179
  return_value = fn()
1180
- function_var = ArgsFunctionOperation.create(tuple(), return_value)
1180
+ function_var = ArgsFunctionOperation.create((), return_value)
1181
1181
  else:
1182
1182
  # generic number var
1183
1183
  number_var = Var("").to(NumberVar, int)
@@ -1349,7 +1349,7 @@ class ArraySliceOperation(CachedVarOperation, ArrayVar):
1349
1349
  LiteralVar.create(end) if end is not None else Var(_js_expr="undefined")
1350
1350
  )
1351
1351
  if step is None:
1352
- return f"{str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)})"
1352
+ return f"{self._array!s}.slice({normalized_start!s}, {normalized_end!s})"
1353
1353
  if not isinstance(step, Var):
1354
1354
  if step < 0:
1355
1355
  actual_start = end + 1 if end is not None else 0
@@ -1357,12 +1357,12 @@ class ArraySliceOperation(CachedVarOperation, ArrayVar):
1357
1357
  return str(self._array[actual_start:actual_end].reverse()[::-step])
1358
1358
  if step == 0:
1359
1359
  raise ValueError("slice step cannot be zero")
1360
- return f"{str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)}).filter((_, i) => i % {str(step)} === 0)"
1360
+ return f"{self._array!s}.slice({normalized_start!s}, {normalized_end!s}).filter((_, i) => i % {step!s} === 0)"
1361
1361
 
1362
1362
  actual_start_reverse = end + 1 if end is not None else 0
1363
1363
  actual_end_reverse = start + 1 if start is not None else self._array.length()
1364
1364
 
1365
- return f"{str(self.step)} > 0 ? {str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)}).filter((_, i) => i % {str(step)} === 0) : {str(self._array)}.slice({str(actual_start_reverse)}, {str(actual_end_reverse)}).reverse().filter((_, i) => i % {str(-step)} === 0)"
1365
+ return f"{self.step!s} > 0 ? {self._array!s}.slice({normalized_start!s}, {normalized_end!s}).filter((_, i) => i % {step!s} === 0) : {self._array!s}.slice({actual_start_reverse!s}, {actual_end_reverse!s}).reverse().filter((_, i) => i % {-step!s} === 0)"
1366
1366
 
1367
1367
  @classmethod
1368
1368
  def create(
@@ -1535,7 +1535,7 @@ def array_item_operation(array: ArrayVar, index: NumberVar | int):
1535
1535
  element_type = unionize(*args)
1536
1536
 
1537
1537
  return var_operation_return(
1538
- js_expression=f"{str(array)}.at({str(index)})",
1538
+ js_expression=f"{array!s}.at({index!s})",
1539
1539
  var_type=element_type,
1540
1540
  )
1541
1541
 
@@ -1555,7 +1555,7 @@ def array_range_operation(
1555
1555
  The range of numbers.
1556
1556
  """
1557
1557
  return var_operation_return(
1558
- js_expression=f"Array.from({{ length: ({str(stop)} - {str(start)}) / {str(step)} }}, (_, i) => {str(start)} + i * {str(step)})",
1558
+ js_expression=f"Array.from({{ length: ({stop!s} - {start!s}) / {step!s} }}, (_, i) => {start!s} + i * {step!s})",
1559
1559
  var_type=List[int],
1560
1560
  )
1561
1561
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: reflex
3
- Version: 0.6.6.post2
3
+ Version: 0.6.7
4
4
  Summary: Web apps in pure Python.
5
5
  Home-page: https://reflex.dev
6
6
  License: Apache-2.0
@@ -39,7 +39,7 @@ 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)
42
- Requires-Dist: twine (>=4.0.0,<6.0)
42
+ Requires-Dist: twine (>=4.0.0,<7.0)
43
43
  Requires-Dist: typer (>=0.4.2,<1.0)
44
44
  Requires-Dist: typing_extensions (>=4.6.0)
45
45
  Requires-Dist: uvicorn (>=0.20.0)