reflex 0.5.10a3__py3-none-any.whl → 0.6.0a1__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 (237) hide show
  1. reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -4
  2. reflex/.templates/jinja/web/utils/context.js.jinja2 +1 -1
  3. reflex/.templates/jinja/web/utils/theme.js.jinja2 +1 -1
  4. reflex/__init__.py +3 -2
  5. reflex/__init__.pyi +2 -2
  6. reflex/app.py +43 -9
  7. reflex/base.py +3 -2
  8. reflex/compiler/compiler.py +6 -6
  9. reflex/compiler/utils.py +5 -3
  10. reflex/components/base/app_wrap.py +2 -4
  11. reflex/components/base/app_wrap.pyi +17 -17
  12. reflex/components/base/bare.py +7 -4
  13. reflex/components/base/body.pyi +17 -17
  14. reflex/components/base/document.pyi +81 -81
  15. reflex/components/base/error_boundary.py +10 -8
  16. reflex/components/base/error_boundary.pyi +20 -19
  17. reflex/components/base/fragment.pyi +17 -17
  18. reflex/components/base/head.pyi +33 -33
  19. reflex/components/base/link.pyi +34 -33
  20. reflex/components/base/meta.pyi +65 -65
  21. reflex/components/base/script.py +2 -1
  22. reflex/components/base/script.pyi +21 -20
  23. reflex/components/component.py +116 -145
  24. reflex/components/core/banner.py +59 -60
  25. reflex/components/core/banner.pyi +86 -150
  26. reflex/components/core/client_side_routing.py +2 -1
  27. reflex/components/core/client_side_routing.pyi +34 -33
  28. reflex/components/core/clipboard.py +2 -2
  29. reflex/components/core/clipboard.pyi +19 -18
  30. reflex/components/core/cond.py +21 -44
  31. reflex/components/core/debounce.py +6 -8
  32. reflex/components/core/debounce.pyi +19 -18
  33. reflex/components/core/foreach.py +5 -14
  34. reflex/components/core/html.pyi +18 -17
  35. reflex/components/core/match.py +36 -43
  36. reflex/components/core/upload.py +32 -25
  37. reflex/components/core/upload.pyi +84 -73
  38. reflex/components/datadisplay/code.py +55 -28
  39. reflex/components/datadisplay/code.pyi +20 -17
  40. reflex/components/datadisplay/dataeditor.py +17 -11
  41. reflex/components/datadisplay/dataeditor.pyi +34 -33
  42. reflex/components/el/__init__.py +0 -1
  43. reflex/components/el/__init__.pyi +0 -11
  44. reflex/components/el/element.pyi +17 -17
  45. reflex/components/el/elements/__init__.py +1 -7
  46. reflex/components/el/elements/__init__.pyi +1 -15
  47. reflex/components/el/elements/base.pyi +18 -17
  48. reflex/components/el/elements/forms.py +24 -31
  49. reflex/components/el/elements/forms.pyi +237 -236
  50. reflex/components/el/elements/inline.pyi +450 -449
  51. reflex/components/el/elements/media.py +0 -21
  52. reflex/components/el/elements/media.pyi +338 -337
  53. reflex/components/el/elements/metadata.py +3 -2
  54. reflex/components/el/elements/metadata.pyi +98 -97
  55. reflex/components/el/elements/other.pyi +114 -113
  56. reflex/components/el/elements/scripts.pyi +50 -49
  57. reflex/components/el/elements/sectioning.pyi +242 -241
  58. reflex/components/el/elements/tables.pyi +162 -161
  59. reflex/components/el/elements/typography.pyi +242 -241
  60. reflex/components/gridjs/datatable.py +13 -14
  61. reflex/components/gridjs/datatable.pyi +34 -33
  62. reflex/components/lucide/icon.py +2 -126
  63. reflex/components/lucide/icon.pyi +34 -142
  64. reflex/components/markdown/markdown.py +30 -35
  65. reflex/components/markdown/markdown.pyi +29 -32
  66. reflex/components/moment/moment.pyi +19 -18
  67. reflex/components/next/base.pyi +17 -17
  68. reflex/components/next/image.py +0 -4
  69. reflex/components/next/image.pyi +20 -19
  70. reflex/components/next/link.pyi +18 -17
  71. reflex/components/next/video.pyi +18 -17
  72. reflex/components/plotly/plotly.py +16 -28
  73. reflex/components/plotly/plotly.pyi +36 -35
  74. reflex/components/props.py +21 -10
  75. reflex/components/radix/__init__.pyi +1 -1
  76. reflex/components/radix/primitives/__init__.pyi +0 -1
  77. reflex/components/radix/primitives/accordion.py +7 -8
  78. reflex/components/radix/primitives/accordion.pyi +117 -116
  79. reflex/components/radix/primitives/base.pyi +34 -33
  80. reflex/components/radix/primitives/drawer.pyi +169 -168
  81. reflex/components/radix/primitives/form.pyi +168 -167
  82. reflex/components/radix/primitives/progress.pyi +82 -81
  83. reflex/components/radix/primitives/slider.pyi +84 -83
  84. reflex/components/radix/themes/base.py +8 -4
  85. reflex/components/radix/themes/base.pyi +114 -113
  86. reflex/components/radix/themes/color_mode.py +12 -21
  87. reflex/components/radix/themes/color_mode.pyi +67 -67
  88. reflex/components/radix/themes/components/__init__.pyi +1 -0
  89. reflex/components/radix/themes/components/alert_dialog.pyi +118 -117
  90. reflex/components/radix/themes/components/aspect_ratio.pyi +18 -17
  91. reflex/components/radix/themes/components/avatar.pyi +18 -17
  92. reflex/components/radix/themes/components/badge.pyi +18 -17
  93. reflex/components/radix/themes/components/button.pyi +18 -17
  94. reflex/components/radix/themes/components/callout.pyi +82 -81
  95. reflex/components/radix/themes/components/card.pyi +18 -17
  96. reflex/components/radix/themes/components/checkbox.py +2 -3
  97. reflex/components/radix/themes/components/checkbox.pyi +53 -52
  98. reflex/components/radix/themes/components/checkbox_cards.pyi +34 -33
  99. reflex/components/radix/themes/components/checkbox_group.pyi +34 -33
  100. reflex/components/radix/themes/components/context_menu.pyi +140 -139
  101. reflex/components/radix/themes/components/data_list.py +5 -0
  102. reflex/components/radix/themes/components/data_list.pyi +71 -65
  103. reflex/components/radix/themes/components/dialog.pyi +121 -120
  104. reflex/components/radix/themes/components/dropdown_menu.pyi +142 -141
  105. reflex/components/radix/themes/components/hover_card.pyi +68 -67
  106. reflex/components/radix/themes/components/icon_button.py +2 -1
  107. reflex/components/radix/themes/components/icon_button.pyi +18 -17
  108. reflex/components/radix/themes/components/inset.pyi +18 -17
  109. reflex/components/radix/themes/components/popover.pyi +73 -72
  110. reflex/components/radix/themes/components/progress.pyi +18 -17
  111. reflex/components/radix/themes/components/radio.pyi +18 -17
  112. reflex/components/radix/themes/components/radio_cards.pyi +35 -34
  113. reflex/components/radix/themes/components/radio_group.py +35 -31
  114. reflex/components/radix/themes/components/radio_group.pyi +73 -66
  115. reflex/components/radix/themes/components/scroll_area.pyi +18 -17
  116. reflex/components/radix/themes/components/segmented_control.pyi +35 -34
  117. reflex/components/radix/themes/components/select.py +2 -1
  118. reflex/components/radix/themes/components/select.pyi +155 -154
  119. reflex/components/radix/themes/components/separator.py +2 -3
  120. reflex/components/radix/themes/components/separator.pyi +18 -17
  121. reflex/components/radix/themes/components/skeleton.pyi +18 -17
  122. reflex/components/radix/themes/components/slider.py +2 -1
  123. reflex/components/radix/themes/components/slider.pyi +20 -19
  124. reflex/components/radix/themes/components/spinner.pyi +18 -17
  125. reflex/components/radix/themes/components/switch.pyi +19 -18
  126. reflex/components/radix/themes/components/table.pyi +114 -113
  127. reflex/components/radix/themes/components/tabs.pyi +84 -83
  128. reflex/components/radix/themes/components/text_area.pyi +21 -20
  129. reflex/components/radix/themes/components/text_field.py +0 -79
  130. reflex/components/radix/themes/components/text_field.pyi +57 -63
  131. reflex/components/radix/themes/components/tooltip.pyi +21 -20
  132. reflex/components/radix/themes/layout/base.pyi +18 -17
  133. reflex/components/radix/themes/layout/box.pyi +18 -17
  134. reflex/components/radix/themes/layout/center.pyi +18 -17
  135. reflex/components/radix/themes/layout/container.py +2 -3
  136. reflex/components/radix/themes/layout/container.pyi +18 -17
  137. reflex/components/radix/themes/layout/flex.pyi +18 -17
  138. reflex/components/radix/themes/layout/grid.pyi +18 -17
  139. reflex/components/radix/themes/layout/list.py +5 -4
  140. reflex/components/radix/themes/layout/list.pyi +86 -85
  141. reflex/components/radix/themes/layout/section.py +2 -3
  142. reflex/components/radix/themes/layout/section.pyi +18 -17
  143. reflex/components/radix/themes/layout/spacer.pyi +18 -17
  144. reflex/components/radix/themes/layout/stack.pyi +50 -49
  145. reflex/components/radix/themes/typography/blockquote.pyi +18 -17
  146. reflex/components/radix/themes/typography/code.pyi +18 -17
  147. reflex/components/radix/themes/typography/heading.pyi +18 -17
  148. reflex/components/radix/themes/typography/link.pyi +18 -17
  149. reflex/components/radix/themes/typography/text.pyi +114 -113
  150. reflex/components/react_player/audio.pyi +34 -33
  151. reflex/components/react_player/react_player.pyi +34 -33
  152. reflex/components/react_player/video.pyi +34 -33
  153. reflex/components/recharts/cartesian.py +23 -19
  154. reflex/components/recharts/cartesian.pyi +297 -296
  155. reflex/components/recharts/charts.py +6 -5
  156. reflex/components/recharts/charts.pyi +179 -178
  157. reflex/components/recharts/general.py +8 -7
  158. reflex/components/recharts/general.pyi +82 -81
  159. reflex/components/recharts/polar.py +14 -13
  160. reflex/components/recharts/polar.pyi +76 -75
  161. reflex/components/recharts/recharts.pyi +33 -33
  162. reflex/components/sonner/toast.py +30 -33
  163. reflex/components/sonner/toast.pyi +27 -25
  164. reflex/components/suneditor/editor.py +2 -1
  165. reflex/components/suneditor/editor.pyi +27 -26
  166. reflex/components/tags/iter_tag.py +16 -16
  167. reflex/components/tags/tag.py +8 -10
  168. reflex/constants/base.py +3 -1
  169. reflex/constants/event.py +1 -0
  170. reflex/event.py +89 -79
  171. reflex/experimental/__init__.py +25 -6
  172. reflex/experimental/client_state.py +34 -58
  173. reflex/experimental/hooks.py +13 -18
  174. reflex/experimental/layout.py +5 -5
  175. reflex/experimental/layout.pyi +84 -83
  176. reflex/{experimental/vars → ivars}/__init__.py +0 -1
  177. reflex/ivars/base.py +2180 -0
  178. reflex/ivars/function.py +200 -0
  179. reflex/ivars/number.py +1137 -0
  180. reflex/ivars/object.py +564 -0
  181. reflex/ivars/sequence.py +1601 -0
  182. reflex/model.py +22 -0
  183. reflex/reflex.py +4 -0
  184. reflex/state.py +388 -73
  185. reflex/style.py +52 -34
  186. reflex/testing.py +8 -3
  187. reflex/utils/exceptions.py +12 -0
  188. reflex/utils/exec.py +0 -14
  189. reflex/utils/format.py +74 -223
  190. reflex/utils/net.py +43 -0
  191. reflex/utils/path_ops.py +13 -1
  192. reflex/utils/prerequisites.py +46 -26
  193. reflex/utils/pyi_generator.py +5 -4
  194. reflex/utils/serializers.py +13 -31
  195. reflex/utils/types.py +44 -9
  196. reflex/vars.py +127 -2230
  197. {reflex-0.5.10a3.dist-info → reflex-0.6.0a1.dist-info}/METADATA +4 -6
  198. reflex-0.6.0a1.dist-info/RECORD +384 -0
  199. reflex/.templates/apps/demo/.gitignore +0 -4
  200. reflex/.templates/apps/demo/assets/favicon.ico +0 -0
  201. reflex/.templates/apps/demo/assets/github.svg +0 -10
  202. reflex/.templates/apps/demo/assets/icon.svg +0 -37
  203. reflex/.templates/apps/demo/assets/logo.svg +0 -68
  204. reflex/.templates/apps/demo/assets/paneleft.svg +0 -13
  205. reflex/.templates/apps/demo/code/__init__.py +0 -1
  206. reflex/.templates/apps/demo/code/demo.py +0 -127
  207. reflex/.templates/apps/demo/code/pages/__init__.py +0 -7
  208. reflex/.templates/apps/demo/code/pages/chatapp.py +0 -31
  209. reflex/.templates/apps/demo/code/pages/datatable.py +0 -360
  210. reflex/.templates/apps/demo/code/pages/forms.py +0 -257
  211. reflex/.templates/apps/demo/code/pages/graphing.py +0 -253
  212. reflex/.templates/apps/demo/code/pages/home.py +0 -56
  213. reflex/.templates/apps/demo/code/sidebar.py +0 -178
  214. reflex/.templates/apps/demo/code/state.py +0 -22
  215. reflex/.templates/apps/demo/code/states/form_state.py +0 -40
  216. reflex/.templates/apps/demo/code/states/pie_state.py +0 -47
  217. reflex/.templates/apps/demo/code/styles.py +0 -68
  218. reflex/.templates/apps/demo/code/webui/__init__.py +0 -0
  219. reflex/.templates/apps/demo/code/webui/components/__init__.py +0 -4
  220. reflex/.templates/apps/demo/code/webui/components/chat.py +0 -118
  221. reflex/.templates/apps/demo/code/webui/components/loading_icon.py +0 -19
  222. reflex/.templates/apps/demo/code/webui/components/modal.py +0 -56
  223. reflex/.templates/apps/demo/code/webui/components/navbar.py +0 -70
  224. reflex/.templates/apps/demo/code/webui/components/sidebar.py +0 -66
  225. reflex/.templates/apps/demo/code/webui/state.py +0 -146
  226. reflex/.templates/apps/demo/code/webui/styles.py +0 -88
  227. reflex/experimental/vars/base.py +0 -583
  228. reflex/experimental/vars/function.py +0 -290
  229. reflex/experimental/vars/number.py +0 -1458
  230. reflex/experimental/vars/object.py +0 -804
  231. reflex/experimental/vars/sequence.py +0 -1764
  232. reflex/utils/watch.py +0 -96
  233. reflex/vars.pyi +0 -218
  234. reflex-0.5.10a3.dist-info/RECORD +0 -413
  235. {reflex-0.5.10a3.dist-info → reflex-0.6.0a1.dist-info}/LICENSE +0 -0
  236. {reflex-0.5.10a3.dist-info → reflex-0.6.0a1.dist-info}/WHEEL +0 -0
  237. {reflex-0.5.10a3.dist-info → reflex-0.6.0a1.dist-info}/entry_points.txt +0 -0
@@ -1,583 +0,0 @@
1
- """Collection of base classes."""
2
-
3
- from __future__ import annotations
4
-
5
- import dataclasses
6
- import functools
7
- import inspect
8
- import sys
9
- from typing import (
10
- TYPE_CHECKING,
11
- Any,
12
- Callable,
13
- Dict,
14
- Generic,
15
- List,
16
- Optional,
17
- Set,
18
- Tuple,
19
- Type,
20
- TypeVar,
21
- Union,
22
- overload,
23
- )
24
-
25
- from typing_extensions import ParamSpec, get_origin
26
-
27
- from reflex import constants
28
- from reflex.base import Base
29
- from reflex.utils import serializers, types
30
- from reflex.utils.exceptions import VarTypeError
31
- from reflex.vars import (
32
- ImmutableVarData,
33
- Var,
34
- VarData,
35
- _decode_var_immutable,
36
- _extract_var_data,
37
- _global_vars,
38
- )
39
-
40
- if TYPE_CHECKING:
41
- from .function import FunctionVar, ToFunctionOperation
42
- from .number import (
43
- BooleanVar,
44
- NumberVar,
45
- ToBooleanVarOperation,
46
- ToNumberVarOperation,
47
- )
48
- from .object import ObjectVar, ToObjectOperation
49
- from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
50
-
51
- VAR_TYPE = TypeVar("VAR_TYPE")
52
-
53
-
54
- @dataclasses.dataclass(
55
- eq=False,
56
- frozen=True,
57
- **{"slots": True} if sys.version_info >= (3, 10) else {},
58
- )
59
- class ImmutableVar(Var, Generic[VAR_TYPE]):
60
- """Base class for immutable vars."""
61
-
62
- # The name of the var.
63
- _var_name: str = dataclasses.field()
64
-
65
- # The type of the var.
66
- _var_type: types.GenericType = dataclasses.field(default=Any)
67
-
68
- # Extra metadata associated with the Var
69
- _var_data: Optional[ImmutableVarData] = dataclasses.field(default=None)
70
-
71
- def __str__(self) -> str:
72
- """String representation of the var. Guaranteed to be a valid Javascript expression.
73
-
74
- Returns:
75
- The name of the var.
76
- """
77
- return self._var_name
78
-
79
- @property
80
- def _var_is_local(self) -> bool:
81
- """Whether this is a local javascript variable.
82
-
83
- Returns:
84
- False
85
- """
86
- return False
87
-
88
- @property
89
- def _var_is_string(self) -> bool:
90
- """Whether the var is a string literal.
91
-
92
- Returns:
93
- False
94
- """
95
- return False
96
-
97
- @property
98
- def _var_full_name_needs_state_prefix(self) -> bool:
99
- """Whether the full name of the var needs a _var_state prefix.
100
-
101
- Returns:
102
- False
103
- """
104
- return False
105
-
106
- def __post_init__(self):
107
- """Post-initialize the var."""
108
- # Decode any inline Var markup and apply it to the instance
109
- _var_data, _var_name = _decode_var_immutable(self._var_name)
110
-
111
- if _var_data or _var_name != self._var_name:
112
- self.__init__(
113
- _var_name=_var_name,
114
- _var_type=self._var_type,
115
- _var_data=ImmutableVarData.merge(self._var_data, _var_data),
116
- )
117
-
118
- def __hash__(self) -> int:
119
- """Define a hash function for the var.
120
-
121
- Returns:
122
- The hash of the var.
123
- """
124
- return hash((self._var_name, self._var_type, self._var_data))
125
-
126
- def _get_all_var_data(self) -> ImmutableVarData | None:
127
- """Get all VarData associated with the Var.
128
-
129
- Returns:
130
- The VarData of the components and all of its children.
131
- """
132
- return self._var_data
133
-
134
- def _replace(self, merge_var_data=None, **kwargs: Any):
135
- """Make a copy of this Var with updated fields.
136
-
137
- Args:
138
- merge_var_data: VarData to merge into the existing VarData.
139
- **kwargs: Var fields to update.
140
-
141
- Returns:
142
- A new ImmutableVar with the updated fields overwriting the corresponding fields in this Var.
143
-
144
- Raises:
145
- TypeError: If _var_is_local, _var_is_string, or _var_full_name_needs_state_prefix is not None.
146
- """
147
- if kwargs.get("_var_is_local", False) is not False:
148
- raise TypeError(
149
- "The _var_is_local argument is not supported for ImmutableVar."
150
- )
151
-
152
- if kwargs.get("_var_is_string", False) is not False:
153
- raise TypeError(
154
- "The _var_is_string argument is not supported for ImmutableVar."
155
- )
156
-
157
- if kwargs.get("_var_full_name_needs_state_prefix", False) is not False:
158
- raise TypeError(
159
- "The _var_full_name_needs_state_prefix argument is not supported for ImmutableVar."
160
- )
161
-
162
- field_values = dict(
163
- _var_name=kwargs.pop("_var_name", self._var_name),
164
- _var_type=kwargs.pop("_var_type", self._var_type),
165
- _var_data=ImmutableVarData.merge(
166
- kwargs.get("_var_data", self._var_data), merge_var_data
167
- ),
168
- )
169
- return type(self)(**field_values)
170
-
171
- @classmethod
172
- def create(
173
- cls,
174
- value: Any,
175
- _var_is_local: bool | None = None,
176
- _var_is_string: bool | None = None,
177
- _var_data: VarData | None = None,
178
- ) -> ImmutableVar | Var | None:
179
- """Create a var from a value.
180
-
181
- Args:
182
- value: The value to create the var from.
183
- _var_is_local: Whether the var is local. Deprecated.
184
- _var_is_string: Whether the var is a string literal. Deprecated.
185
- _var_data: Additional hooks and imports associated with the Var.
186
-
187
- Returns:
188
- The var.
189
-
190
- Raises:
191
- VarTypeError: If the value is JSON-unserializable.
192
- TypeError: If _var_is_local or _var_is_string is not None.
193
- """
194
- if _var_is_local is not None:
195
- raise TypeError(
196
- "The _var_is_local argument is not supported for ImmutableVar."
197
- )
198
-
199
- if _var_is_string is not None:
200
- raise TypeError(
201
- "The _var_is_string argument is not supported for ImmutableVar."
202
- )
203
-
204
- from reflex.utils import format
205
-
206
- # Check for none values.
207
- if value is None:
208
- return None
209
-
210
- # If the value is already a var, do nothing.
211
- if isinstance(value, Var):
212
- return value
213
-
214
- # Try to pull the imports and hooks from contained values.
215
- if not isinstance(value, str):
216
- _var_data = VarData.merge(*_extract_var_data(value), _var_data)
217
-
218
- # Try to serialize the value.
219
- type_ = type(value)
220
- if type_ in types.JSONType:
221
- name = value
222
- else:
223
- name, _serialized_type = serializers.serialize(value, get_type=True)
224
- if name is None:
225
- raise VarTypeError(
226
- f"No JSON serializer found for var {value} of type {type_}."
227
- )
228
- name = name if isinstance(name, str) else format.json_dumps(name)
229
-
230
- return cls(
231
- _var_name=name,
232
- _var_type=type_,
233
- _var_data=(
234
- ImmutableVarData(
235
- state=_var_data.state,
236
- imports=_var_data.imports,
237
- hooks=_var_data.hooks,
238
- )
239
- if _var_data
240
- else None
241
- ),
242
- )
243
-
244
- @classmethod
245
- def create_safe(
246
- cls,
247
- value: Any,
248
- _var_is_local: bool | None = None,
249
- _var_is_string: bool | None = None,
250
- _var_data: VarData | None = None,
251
- ) -> Var | ImmutableVar:
252
- """Create a var from a value, asserting that it is not None.
253
-
254
- Args:
255
- value: The value to create the var from.
256
- _var_is_local: Whether the var is local. Deprecated.
257
- _var_is_string: Whether the var is a string literal. Deprecated.
258
- _var_data: Additional hooks and imports associated with the Var.
259
-
260
- Returns:
261
- The var.
262
- """
263
- var = cls.create(
264
- value,
265
- _var_is_local=_var_is_local,
266
- _var_is_string=_var_is_string,
267
- _var_data=_var_data,
268
- )
269
- assert var is not None
270
- return var
271
-
272
- def __format__(self, format_spec: str) -> str:
273
- """Format the var into a Javascript equivalent to an f-string.
274
-
275
- Args:
276
- format_spec: The format specifier (Ignored for now).
277
-
278
- Returns:
279
- The formatted var.
280
- """
281
- hashed_var = hash(self)
282
-
283
- _global_vars[hashed_var] = self
284
-
285
- # Encode the _var_data into the formatted output for tracking purposes.
286
- return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._var_name}"
287
-
288
- @overload
289
- def to(
290
- self, output: Type[NumberVar], var_type: type[int] | type[float] = float
291
- ) -> ToNumberVarOperation: ...
292
-
293
- @overload
294
- def to(self, output: Type[BooleanVar]) -> ToBooleanVarOperation: ...
295
-
296
- @overload
297
- def to(
298
- self,
299
- output: Type[ArrayVar],
300
- var_type: type[list] | type[tuple] | type[set] = list,
301
- ) -> ToArrayOperation: ...
302
-
303
- @overload
304
- def to(self, output: Type[StringVar]) -> ToStringOperation: ...
305
-
306
- @overload
307
- def to(
308
- self, output: Type[ObjectVar], var_type: types.GenericType = dict
309
- ) -> ToObjectOperation: ...
310
-
311
- @overload
312
- def to(
313
- self, output: Type[FunctionVar], var_type: Type[Callable] = Callable
314
- ) -> ToFunctionOperation: ...
315
-
316
- @overload
317
- def to(
318
- self, output: Type[OUTPUT], var_type: types.GenericType | None = None
319
- ) -> OUTPUT: ...
320
-
321
- def to(
322
- self, output: Type[OUTPUT], var_type: types.GenericType | None = None
323
- ) -> Var:
324
- """Convert the var to a different type.
325
-
326
- Args:
327
- output: The output type.
328
- var_type: The type of the var.
329
-
330
- Raises:
331
- TypeError: If the var_type is not a supported type for the output.
332
-
333
- Returns:
334
- The converted var.
335
- """
336
- from .number import (
337
- BooleanVar,
338
- NumberVar,
339
- ToBooleanVarOperation,
340
- ToNumberVarOperation,
341
- )
342
-
343
- fixed_type = (
344
- var_type
345
- if var_type is None or inspect.isclass(var_type)
346
- else get_origin(var_type)
347
- )
348
-
349
- if issubclass(output, NumberVar):
350
- if fixed_type is not None and not issubclass(fixed_type, (int, float)):
351
- raise TypeError(
352
- f"Unsupported type {var_type} for NumberVar. Must be int or float."
353
- )
354
- return ToNumberVarOperation(self, var_type or float)
355
- if issubclass(output, BooleanVar):
356
- return ToBooleanVarOperation(self)
357
-
358
- from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
359
-
360
- if issubclass(output, ArrayVar):
361
- if fixed_type is not None and not issubclass(
362
- fixed_type, (list, tuple, set)
363
- ):
364
- raise TypeError(
365
- f"Unsupported type {var_type} for ArrayVar. Must be list, tuple, or set."
366
- )
367
- return ToArrayOperation(self, var_type or list)
368
- if issubclass(output, StringVar):
369
- return ToStringOperation(self)
370
-
371
- from .object import ObjectVar, ToObjectOperation
372
-
373
- if issubclass(output, ObjectVar):
374
- return ToObjectOperation(self, var_type or dict)
375
-
376
- from .function import FunctionVar, ToFunctionOperation
377
-
378
- if issubclass(output, FunctionVar):
379
- if fixed_type is not None and not issubclass(fixed_type, Callable):
380
- raise TypeError(
381
- f"Unsupported type {var_type} for FunctionVar. Must be Callable."
382
- )
383
- return ToFunctionOperation(self, var_type or Callable)
384
-
385
- return output(
386
- _var_name=self._var_name,
387
- _var_type=self._var_type if var_type is None else var_type,
388
- _var_data=self._var_data,
389
- )
390
-
391
- def guess_type(self) -> ImmutableVar:
392
- """Guess the type of the var.
393
-
394
- Returns:
395
- The guessed type.
396
- """
397
- from .number import NumberVar
398
- from .object import ObjectVar
399
- from .sequence import ArrayVar, StringVar
400
-
401
- if self._var_type is Any:
402
- return self
403
-
404
- var_type = self._var_type
405
-
406
- fixed_type = var_type if inspect.isclass(var_type) else get_origin(var_type)
407
-
408
- if issubclass(fixed_type, (int, float)):
409
- return self.to(NumberVar, var_type)
410
- if issubclass(fixed_type, dict):
411
- return self.to(ObjectVar, var_type)
412
- if issubclass(fixed_type, (list, tuple, set)):
413
- return self.to(ArrayVar, var_type)
414
- if issubclass(fixed_type, str):
415
- return self.to(StringVar)
416
- if issubclass(fixed_type, Base):
417
- return self.to(ObjectVar, var_type)
418
- return self
419
-
420
-
421
- OUTPUT = TypeVar("OUTPUT", bound=ImmutableVar)
422
-
423
-
424
- class LiteralVar(ImmutableVar):
425
- """Base class for immutable literal vars."""
426
-
427
- @classmethod
428
- def create(
429
- cls,
430
- value: Any,
431
- _var_data: VarData | None = None,
432
- ) -> Var:
433
- """Create a var from a value.
434
-
435
- Args:
436
- value: The value to create the var from.
437
- _var_data: Additional hooks and imports associated with the Var.
438
-
439
- Returns:
440
- The var.
441
-
442
- Raises:
443
- TypeError: If the value is not a supported type for LiteralVar.
444
- """
445
- if isinstance(value, Var):
446
- if _var_data is None:
447
- return value
448
- return value._replace(merge_var_data=_var_data)
449
-
450
- if value is None:
451
- return ImmutableVar.create_safe("null", _var_data=_var_data)
452
-
453
- from .object import LiteralObjectVar
454
-
455
- if isinstance(value, Base):
456
- return LiteralObjectVar(
457
- value.dict(), _var_type=type(value), _var_data=_var_data
458
- )
459
-
460
- from .number import LiteralBooleanVar, LiteralNumberVar
461
- from .sequence import LiteralArrayVar, LiteralStringVar
462
-
463
- if isinstance(value, str):
464
- return LiteralStringVar.create(value, _var_data=_var_data)
465
-
466
- type_mapping = {
467
- int: LiteralNumberVar,
468
- float: LiteralNumberVar,
469
- bool: LiteralBooleanVar,
470
- dict: LiteralObjectVar,
471
- list: LiteralArrayVar,
472
- tuple: LiteralArrayVar,
473
- set: LiteralArrayVar,
474
- }
475
-
476
- constructor = type_mapping.get(type(value))
477
-
478
- if constructor is None:
479
- raise TypeError(f"Unsupported type {type(value)} for LiteralVar.")
480
-
481
- return constructor(value, _var_data=_var_data)
482
-
483
- def __post_init__(self):
484
- """Post-initialize the var."""
485
-
486
- def json(self) -> str:
487
- """Serialize the var to a JSON string.
488
-
489
- Raises:
490
- NotImplementedError: If the method is not implemented.
491
- """
492
- raise NotImplementedError(
493
- "LiteralVar subclasses must implement the json method."
494
- )
495
-
496
-
497
- P = ParamSpec("P")
498
- T = TypeVar("T", bound=ImmutableVar)
499
-
500
-
501
- def var_operation(*, output: Type[T]) -> Callable[[Callable[P, str]], Callable[P, T]]:
502
- """Decorator for creating a var operation.
503
-
504
- Example:
505
- ```python
506
- @var_operation(output=NumberVar)
507
- def add(a: NumberVar, b: NumberVar):
508
- return f"({a} + {b})"
509
- ```
510
-
511
- Args:
512
- output: The output type of the operation.
513
-
514
- Returns:
515
- The decorator.
516
- """
517
-
518
- def decorator(func: Callable[P, str], output=output):
519
- @functools.wraps(func)
520
- def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
521
- args_vars = [
522
- LiteralVar.create(arg) if not isinstance(arg, Var) else arg
523
- for arg in args
524
- ]
525
- kwargs_vars = {
526
- key: LiteralVar.create(value) if not isinstance(value, Var) else value
527
- for key, value in kwargs.items()
528
- }
529
- return output(
530
- _var_name=func(*args_vars, **kwargs_vars), # type: ignore
531
- _var_data=VarData.merge(
532
- *[arg._get_all_var_data() for arg in args if isinstance(arg, Var)],
533
- *[
534
- arg._get_all_var_data()
535
- for arg in kwargs.values()
536
- if isinstance(arg, Var)
537
- ],
538
- ),
539
- )
540
-
541
- return wrapper
542
-
543
- return decorator
544
-
545
-
546
- def unionize(*args: Type) -> Type:
547
- """Unionize the types.
548
-
549
- Args:
550
- args: The types to unionize.
551
-
552
- Returns:
553
- The unionized types.
554
- """
555
- if not args:
556
- return Any
557
- first, *rest = args
558
- if not rest:
559
- return first
560
- return Union[first, unionize(*rest)]
561
-
562
-
563
- def figure_out_type(value: Any) -> Type:
564
- """Figure out the type of the value.
565
-
566
- Args:
567
- value: The value to figure out the type of.
568
-
569
- Returns:
570
- The type of the value.
571
- """
572
- if isinstance(value, list):
573
- return List[unionize(*(figure_out_type(v) for v in value))]
574
- if isinstance(value, set):
575
- return Set[unionize(*(figure_out_type(v) for v in value))]
576
- if isinstance(value, tuple):
577
- return Tuple[unionize(*(figure_out_type(v) for v in value)), ...]
578
- if isinstance(value, dict):
579
- return Dict[
580
- unionize(*(figure_out_type(k) for k in value)),
581
- unionize(*(figure_out_type(v) for v in value.values())),
582
- ]
583
- return type(value)