reflex 0.5.7a1__py3-none-any.whl → 0.5.8a1__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.
- reflex/.templates/web/utils/state.js +1 -1
- reflex/app.py +20 -2
- reflex/components/core/banner.py +14 -0
- reflex/components/core/banner.pyi +3 -3
- reflex/components/core/debounce.py +3 -0
- reflex/components/el/__init__.py +1 -0
- reflex/components/el/__init__.pyi +8 -5
- reflex/components/el/elements/__init__.py +3 -1
- reflex/components/el/elements/__init__.pyi +8 -6
- reflex/components/el/elements/media.py +98 -18
- reflex/components/el/elements/media.pyi +523 -18
- reflex/components/el/elements/metadata.py +5 -1
- reflex/components/radix/primitives/base.py +1 -1
- reflex/components/radix/themes/layout/list.py +0 -2
- reflex/components/recharts/cartesian.py +46 -20
- reflex/components/recharts/cartesian.pyi +26 -14
- reflex/components/recharts/charts.py +4 -0
- reflex/components/recharts/charts.pyi +3 -0
- reflex/components/recharts/general.py +23 -9
- reflex/components/recharts/general.pyi +6 -4
- reflex/components/recharts/polar.py +35 -11
- reflex/components/recharts/polar.pyi +35 -7
- reflex/components/sonner/toast.py +28 -2
- reflex/components/sonner/toast.pyi +14 -7
- reflex/constants/base.py +21 -0
- reflex/constants/event.py +2 -0
- reflex/experimental/vars/__init__.py +17 -0
- reflex/experimental/vars/base.py +282 -15
- reflex/experimental/vars/function.py +214 -0
- reflex/experimental/vars/number.py +1295 -0
- reflex/experimental/vars/sequence.py +1039 -0
- reflex/reflex.py +29 -2
- reflex/state.py +59 -10
- reflex/utils/imports.py +71 -8
- reflex/utils/prerequisites.py +115 -35
- reflex/utils/pyi_generator.py +2 -0
- reflex/utils/redir.py +52 -0
- reflex/vars.py +220 -11
- reflex/vars.pyi +20 -2
- {reflex-0.5.7a1.dist-info → reflex-0.5.8a1.dist-info}/METADATA +2 -2
- {reflex-0.5.7a1.dist-info → reflex-0.5.8a1.dist-info}/RECORD +44 -40
- {reflex-0.5.7a1.dist-info → reflex-0.5.8a1.dist-info}/LICENSE +0 -0
- {reflex-0.5.7a1.dist-info → reflex-0.5.8a1.dist-info}/WHEEL +0 -0
- {reflex-0.5.7a1.dist-info → reflex-0.5.8a1.dist-info}/entry_points.txt +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Any, Literal, Optional, Union
|
|
5
|
+
from typing import Any, ClassVar, Literal, Optional, Union
|
|
6
6
|
|
|
7
7
|
from reflex.base import Base
|
|
8
8
|
from reflex.components.component import Component, ComponentNamespace
|
|
@@ -211,6 +211,9 @@ class Toaster(Component):
|
|
|
211
211
|
# Pauses toast timers when the page is hidden, e.g., when the tab is backgrounded, the browser is minimized, or the OS is locked.
|
|
212
212
|
pause_when_page_is_hidden: Var[bool]
|
|
213
213
|
|
|
214
|
+
# Marked True when any Toast component is created.
|
|
215
|
+
is_used: ClassVar[bool] = False
|
|
216
|
+
|
|
214
217
|
def add_hooks(self) -> list[Var | str]:
|
|
215
218
|
"""Add hooks for the toaster component.
|
|
216
219
|
|
|
@@ -231,7 +234,7 @@ class Toaster(Component):
|
|
|
231
234
|
return [hook]
|
|
232
235
|
|
|
233
236
|
@staticmethod
|
|
234
|
-
def send_toast(message: str, level: str | None = None, **props) -> EventSpec:
|
|
237
|
+
def send_toast(message: str = "", level: str | None = None, **props) -> EventSpec:
|
|
235
238
|
"""Send a toast message.
|
|
236
239
|
|
|
237
240
|
Args:
|
|
@@ -239,10 +242,19 @@ class Toaster(Component):
|
|
|
239
242
|
level: The level of the toast.
|
|
240
243
|
**props: The options for the toast.
|
|
241
244
|
|
|
245
|
+
Raises:
|
|
246
|
+
ValueError: If the Toaster component is not created.
|
|
247
|
+
|
|
242
248
|
Returns:
|
|
243
249
|
The toast event.
|
|
244
250
|
"""
|
|
251
|
+
if not Toaster.is_used:
|
|
252
|
+
raise ValueError(
|
|
253
|
+
"Toaster component must be created before sending a toast. (use `rx.toast.provider()`)"
|
|
254
|
+
)
|
|
245
255
|
toast_command = f"{toast_ref}.{level}" if level is not None else toast_ref
|
|
256
|
+
if message == "" and ("title" not in props or "description" not in props):
|
|
257
|
+
raise ValueError("Toast message or title or description must be provided.")
|
|
246
258
|
if props:
|
|
247
259
|
args = serialize(ToastProps(**props)) # type: ignore
|
|
248
260
|
toast = f"{toast_command}(`{message}`, {args})"
|
|
@@ -331,6 +343,20 @@ class Toaster(Component):
|
|
|
331
343
|
)
|
|
332
344
|
return call_script(dismiss_action)
|
|
333
345
|
|
|
346
|
+
@classmethod
|
|
347
|
+
def create(cls, *children, **props) -> Component:
|
|
348
|
+
"""Create a toaster component.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
*children: The children of the toaster.
|
|
352
|
+
**props: The properties of the toaster.
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
The toaster component.
|
|
356
|
+
"""
|
|
357
|
+
cls.is_used = True
|
|
358
|
+
return super().create(*children, **props)
|
|
359
|
+
|
|
334
360
|
|
|
335
361
|
# TODO: figure out why loading toast stay open forever
|
|
336
362
|
# def toast_loading(message: str, **kwargs):
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# ------------------- DO NOT EDIT ----------------------
|
|
4
4
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
5
5
|
# ------------------------------------------------------
|
|
6
|
-
from typing import Any, Callable, Dict, Literal, Optional, Union, overload
|
|
6
|
+
from typing import Any, Callable, ClassVar, Dict, Literal, Optional, Union, overload
|
|
7
7
|
|
|
8
8
|
from reflex.base import Base
|
|
9
9
|
from reflex.components.component import Component, ComponentNamespace
|
|
@@ -52,9 +52,13 @@ class ToastProps(PropsBase):
|
|
|
52
52
|
def dict(self, *args, **kwargs) -> dict[str, Any]: ...
|
|
53
53
|
|
|
54
54
|
class Toaster(Component):
|
|
55
|
+
is_used: ClassVar[bool] = False
|
|
56
|
+
|
|
55
57
|
def add_hooks(self) -> list[Var | str]: ...
|
|
56
58
|
@staticmethod
|
|
57
|
-
def send_toast(
|
|
59
|
+
def send_toast(
|
|
60
|
+
message: str = "", level: str | None = None, **props
|
|
61
|
+
) -> EventSpec: ...
|
|
58
62
|
@staticmethod
|
|
59
63
|
def toast_info(message: str, **kwargs): ...
|
|
60
64
|
@staticmethod
|
|
@@ -158,10 +162,10 @@ class Toaster(Component):
|
|
|
158
162
|
] = None,
|
|
159
163
|
**props,
|
|
160
164
|
) -> "Toaster":
|
|
161
|
-
"""Create
|
|
165
|
+
"""Create a toaster component.
|
|
162
166
|
|
|
163
167
|
Args:
|
|
164
|
-
*children: The children of the
|
|
168
|
+
*children: The children of the toaster.
|
|
165
169
|
theme: the theme of the toast
|
|
166
170
|
rich_colors: whether to show rich colors
|
|
167
171
|
expand: whether to expand the toast
|
|
@@ -182,10 +186,10 @@ class Toaster(Component):
|
|
|
182
186
|
class_name: The class name for the component.
|
|
183
187
|
autofocus: Whether the component should take the focus once the page is loaded
|
|
184
188
|
custom_attrs: custom attribute
|
|
185
|
-
**props: The
|
|
189
|
+
**props: The properties of the toaster.
|
|
186
190
|
|
|
187
191
|
Returns:
|
|
188
|
-
The component.
|
|
192
|
+
The toaster component.
|
|
189
193
|
"""
|
|
190
194
|
...
|
|
191
195
|
|
|
@@ -200,7 +204,7 @@ class ToastNamespace(ComponentNamespace):
|
|
|
200
204
|
|
|
201
205
|
@staticmethod
|
|
202
206
|
def __call__(
|
|
203
|
-
message: str, level: Optional[str] = None, **props
|
|
207
|
+
message: str = "", level: Optional[str] = None, **props
|
|
204
208
|
) -> "Optional[EventSpec]":
|
|
205
209
|
"""Send a toast message.
|
|
206
210
|
|
|
@@ -209,6 +213,9 @@ class ToastNamespace(ComponentNamespace):
|
|
|
209
213
|
level: The level of the toast.
|
|
210
214
|
**props: The options for the toast.
|
|
211
215
|
|
|
216
|
+
Raises:
|
|
217
|
+
ValueError: If the Toaster component is not created.
|
|
218
|
+
|
|
212
219
|
Returns:
|
|
213
220
|
The toast event.
|
|
214
221
|
"""
|
reflex/constants/base.py
CHANGED
|
@@ -94,6 +94,27 @@ class Templates(SimpleNamespace):
|
|
|
94
94
|
# The default template
|
|
95
95
|
DEFAULT = "blank"
|
|
96
96
|
|
|
97
|
+
# The reflex.build frontend host
|
|
98
|
+
REFLEX_BUILD_FRONTEND = os.environ.get(
|
|
99
|
+
"REFLEX_BUILD_FRONTEND", "https://flexgen.reflex.run"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# The reflex.build backend host
|
|
103
|
+
REFLEX_BUILD_BACKEND = os.environ.get(
|
|
104
|
+
"REFLEX_BUILD_BACKEND", "https://rxh-prod-flexgen.fly.dev"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# The URL to redirect to reflex.build
|
|
108
|
+
REFLEX_BUILD_URL = (
|
|
109
|
+
REFLEX_BUILD_FRONTEND + "/gen?reflex_init_token={reflex_init_token}"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# The URL to poll waiting for the user to select a generation.
|
|
113
|
+
REFLEX_BUILD_POLL_URL = REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
|
|
114
|
+
|
|
115
|
+
# The URL to fetch the generation's reflex code
|
|
116
|
+
REFLEX_BUILD_CODE_URL = REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}"
|
|
117
|
+
|
|
97
118
|
class Dirs(SimpleNamespace):
|
|
98
119
|
"""Folders used by the template system of Reflex."""
|
|
99
120
|
|
reflex/constants/event.py
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
"""Experimental Immutable-Based Var System."""
|
|
2
2
|
|
|
3
3
|
from .base import ImmutableVar as ImmutableVar
|
|
4
|
+
from .base import LiteralObjectVar as LiteralObjectVar
|
|
5
|
+
from .base import LiteralVar as LiteralVar
|
|
6
|
+
from .base import ObjectVar as ObjectVar
|
|
7
|
+
from .base import var_operation as var_operation
|
|
8
|
+
from .function import FunctionStringVar as FunctionStringVar
|
|
9
|
+
from .function import FunctionVar as FunctionVar
|
|
10
|
+
from .function import VarOperationCall as VarOperationCall
|
|
11
|
+
from .number import BooleanVar as BooleanVar
|
|
12
|
+
from .number import LiteralBooleanVar as LiteralBooleanVar
|
|
13
|
+
from .number import LiteralNumberVar as LiteralNumberVar
|
|
14
|
+
from .number import NumberVar as NumberVar
|
|
15
|
+
from .sequence import ArrayJoinOperation as ArrayJoinOperation
|
|
16
|
+
from .sequence import ArrayVar as ArrayVar
|
|
17
|
+
from .sequence import ConcatVarOperation as ConcatVarOperation
|
|
18
|
+
from .sequence import LiteralArrayVar as LiteralArrayVar
|
|
19
|
+
from .sequence import LiteralStringVar as LiteralStringVar
|
|
20
|
+
from .sequence import StringVar as StringVar
|
reflex/experimental/vars/base.py
CHANGED
|
@@ -3,13 +3,32 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import dataclasses
|
|
6
|
+
import functools
|
|
6
7
|
import sys
|
|
7
|
-
from typing import
|
|
8
|
+
from typing import (
|
|
9
|
+
Any,
|
|
10
|
+
Callable,
|
|
11
|
+
Dict,
|
|
12
|
+
Optional,
|
|
13
|
+
Type,
|
|
14
|
+
TypeVar,
|
|
15
|
+
Union,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from typing_extensions import ParamSpec
|
|
8
19
|
|
|
9
|
-
from reflex
|
|
20
|
+
from reflex import constants
|
|
21
|
+
from reflex.base import Base
|
|
10
22
|
from reflex.utils import serializers, types
|
|
11
23
|
from reflex.utils.exceptions import VarTypeError
|
|
12
|
-
from reflex.vars import
|
|
24
|
+
from reflex.vars import (
|
|
25
|
+
ImmutableVarData,
|
|
26
|
+
Var,
|
|
27
|
+
VarData,
|
|
28
|
+
_decode_var_immutable,
|
|
29
|
+
_extract_var_data,
|
|
30
|
+
_global_vars,
|
|
31
|
+
)
|
|
13
32
|
|
|
14
33
|
|
|
15
34
|
@dataclasses.dataclass(
|
|
@@ -27,7 +46,15 @@ class ImmutableVar(Var):
|
|
|
27
46
|
_var_type: Type = dataclasses.field(default=Any)
|
|
28
47
|
|
|
29
48
|
# Extra metadata associated with the Var
|
|
30
|
-
_var_data: Optional[
|
|
49
|
+
_var_data: Optional[ImmutableVarData] = dataclasses.field(default=None)
|
|
50
|
+
|
|
51
|
+
def __str__(self) -> str:
|
|
52
|
+
"""String representation of the var. Guaranteed to be a valid Javascript expression.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The name of the var.
|
|
56
|
+
"""
|
|
57
|
+
return self._var_name
|
|
31
58
|
|
|
32
59
|
@property
|
|
33
60
|
def _var_is_local(self) -> bool:
|
|
@@ -59,12 +86,31 @@ class ImmutableVar(Var):
|
|
|
59
86
|
def __post_init__(self):
|
|
60
87
|
"""Post-initialize the var."""
|
|
61
88
|
# Decode any inline Var markup and apply it to the instance
|
|
62
|
-
_var_data, _var_name =
|
|
63
|
-
|
|
89
|
+
_var_data, _var_name = _decode_var_immutable(self._var_name)
|
|
90
|
+
|
|
91
|
+
if _var_data or _var_name != self._var_name:
|
|
64
92
|
self.__init__(
|
|
65
|
-
_var_name,
|
|
93
|
+
_var_name=_var_name,
|
|
94
|
+
_var_type=self._var_type,
|
|
95
|
+
_var_data=ImmutableVarData.merge(self._var_data, _var_data),
|
|
66
96
|
)
|
|
67
97
|
|
|
98
|
+
def __hash__(self) -> int:
|
|
99
|
+
"""Define a hash function for the var.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
The hash of the var.
|
|
103
|
+
"""
|
|
104
|
+
return hash((self._var_name, self._var_type, self._var_data))
|
|
105
|
+
|
|
106
|
+
def _get_all_var_data(self) -> ImmutableVarData | None:
|
|
107
|
+
"""Get all VarData associated with the Var.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
The VarData of the components and all of its children.
|
|
111
|
+
"""
|
|
112
|
+
return self._var_data
|
|
113
|
+
|
|
68
114
|
def _replace(self, merge_var_data=None, **kwargs: Any):
|
|
69
115
|
"""Make a copy of this Var with updated fields.
|
|
70
116
|
|
|
@@ -96,11 +142,11 @@ class ImmutableVar(Var):
|
|
|
96
142
|
field_values = dict(
|
|
97
143
|
_var_name=kwargs.pop("_var_name", self._var_name),
|
|
98
144
|
_var_type=kwargs.pop("_var_type", self._var_type),
|
|
99
|
-
_var_data=
|
|
145
|
+
_var_data=ImmutableVarData.merge(
|
|
100
146
|
kwargs.get("_var_data", self._var_data), merge_var_data
|
|
101
147
|
),
|
|
102
148
|
)
|
|
103
|
-
return
|
|
149
|
+
return type(self)(**field_values)
|
|
104
150
|
|
|
105
151
|
@classmethod
|
|
106
152
|
def create(
|
|
@@ -109,7 +155,7 @@ class ImmutableVar(Var):
|
|
|
109
155
|
_var_is_local: bool | None = None,
|
|
110
156
|
_var_is_string: bool | None = None,
|
|
111
157
|
_var_data: VarData | None = None,
|
|
112
|
-
) -> Var | None:
|
|
158
|
+
) -> ImmutableVar | Var | None:
|
|
113
159
|
"""Create a var from a value.
|
|
114
160
|
|
|
115
161
|
Args:
|
|
@@ -161,10 +207,18 @@ class ImmutableVar(Var):
|
|
|
161
207
|
)
|
|
162
208
|
name = name if isinstance(name, str) else format.json_dumps(name)
|
|
163
209
|
|
|
164
|
-
return
|
|
210
|
+
return cls(
|
|
165
211
|
_var_name=name,
|
|
166
212
|
_var_type=type_,
|
|
167
|
-
_var_data=
|
|
213
|
+
_var_data=(
|
|
214
|
+
ImmutableVarData(
|
|
215
|
+
state=_var_data.state,
|
|
216
|
+
imports=_var_data.imports,
|
|
217
|
+
hooks=_var_data.hooks,
|
|
218
|
+
)
|
|
219
|
+
if _var_data
|
|
220
|
+
else None
|
|
221
|
+
),
|
|
168
222
|
)
|
|
169
223
|
|
|
170
224
|
@classmethod
|
|
@@ -174,7 +228,7 @@ class ImmutableVar(Var):
|
|
|
174
228
|
_var_is_local: bool | None = None,
|
|
175
229
|
_var_is_string: bool | None = None,
|
|
176
230
|
_var_data: VarData | None = None,
|
|
177
|
-
) -> Var:
|
|
231
|
+
) -> Var | ImmutableVar:
|
|
178
232
|
"""Create a var from a value, asserting that it is not None.
|
|
179
233
|
|
|
180
234
|
Args:
|
|
@@ -204,7 +258,220 @@ class ImmutableVar(Var):
|
|
|
204
258
|
Returns:
|
|
205
259
|
The formatted var.
|
|
206
260
|
"""
|
|
207
|
-
|
|
261
|
+
hashed_var = hash(self)
|
|
262
|
+
|
|
263
|
+
_global_vars[hashed_var] = self
|
|
208
264
|
|
|
209
265
|
# Encode the _var_data into the formatted output for tracking purposes.
|
|
210
|
-
return f"{REFLEX_VAR_OPENING_TAG}{
|
|
266
|
+
return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._var_name}"
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class ObjectVar(ImmutableVar):
|
|
270
|
+
"""Base class for immutable object vars."""
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class LiteralVar(ImmutableVar):
|
|
274
|
+
"""Base class for immutable literal vars."""
|
|
275
|
+
|
|
276
|
+
@classmethod
|
|
277
|
+
def create(
|
|
278
|
+
cls,
|
|
279
|
+
value: Any,
|
|
280
|
+
_var_data: VarData | None = None,
|
|
281
|
+
) -> Var:
|
|
282
|
+
"""Create a var from a value.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
value: The value to create the var from.
|
|
286
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
The var.
|
|
290
|
+
|
|
291
|
+
Raises:
|
|
292
|
+
TypeError: If the value is not a supported type for LiteralVar.
|
|
293
|
+
"""
|
|
294
|
+
if isinstance(value, Var):
|
|
295
|
+
if _var_data is None:
|
|
296
|
+
return value
|
|
297
|
+
return value._replace(merge_var_data=_var_data)
|
|
298
|
+
|
|
299
|
+
if value is None:
|
|
300
|
+
return ImmutableVar.create_safe("null", _var_data=_var_data)
|
|
301
|
+
|
|
302
|
+
if isinstance(value, Base):
|
|
303
|
+
return LiteralObjectVar(
|
|
304
|
+
value.dict(), _var_type=type(value), _var_data=_var_data
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
from .number import LiteralBooleanVar, LiteralNumberVar
|
|
308
|
+
from .sequence import LiteralArrayVar, LiteralStringVar
|
|
309
|
+
|
|
310
|
+
if isinstance(value, str):
|
|
311
|
+
return LiteralStringVar.create(value, _var_data=_var_data)
|
|
312
|
+
|
|
313
|
+
type_mapping = {
|
|
314
|
+
int: LiteralNumberVar,
|
|
315
|
+
float: LiteralNumberVar,
|
|
316
|
+
bool: LiteralBooleanVar,
|
|
317
|
+
dict: LiteralObjectVar,
|
|
318
|
+
list: LiteralArrayVar,
|
|
319
|
+
tuple: LiteralArrayVar,
|
|
320
|
+
set: LiteralArrayVar,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
constructor = type_mapping.get(type(value))
|
|
324
|
+
|
|
325
|
+
if constructor is None:
|
|
326
|
+
raise TypeError(f"Unsupported type {type(value)} for LiteralVar.")
|
|
327
|
+
|
|
328
|
+
return constructor(value, _var_data=_var_data)
|
|
329
|
+
|
|
330
|
+
def __post_init__(self):
|
|
331
|
+
"""Post-initialize the var."""
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@dataclasses.dataclass(
|
|
335
|
+
eq=False,
|
|
336
|
+
frozen=True,
|
|
337
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
338
|
+
)
|
|
339
|
+
class LiteralObjectVar(LiteralVar):
|
|
340
|
+
"""Base class for immutable literal object vars."""
|
|
341
|
+
|
|
342
|
+
_var_value: Dict[Union[Var, Any], Union[Var, Any]] = dataclasses.field(
|
|
343
|
+
default_factory=dict
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
def __init__(
|
|
347
|
+
self,
|
|
348
|
+
_var_value: dict[Var | Any, Var | Any],
|
|
349
|
+
_var_type: Type = dict,
|
|
350
|
+
_var_data: VarData | None = None,
|
|
351
|
+
):
|
|
352
|
+
"""Initialize the object var.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
_var_value: The value of the var.
|
|
356
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
357
|
+
"""
|
|
358
|
+
super(LiteralObjectVar, self).__init__(
|
|
359
|
+
_var_name="",
|
|
360
|
+
_var_type=_var_type,
|
|
361
|
+
_var_data=ImmutableVarData.merge(_var_data),
|
|
362
|
+
)
|
|
363
|
+
object.__setattr__(
|
|
364
|
+
self,
|
|
365
|
+
"_var_value",
|
|
366
|
+
_var_value,
|
|
367
|
+
)
|
|
368
|
+
object.__delattr__(self, "_var_name")
|
|
369
|
+
|
|
370
|
+
def __getattr__(self, name):
|
|
371
|
+
"""Get an attribute of the var.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
name: The name of the attribute.
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
The attribute of the var.
|
|
378
|
+
"""
|
|
379
|
+
if name == "_var_name":
|
|
380
|
+
return self._cached_var_name
|
|
381
|
+
return super(type(self), self).__getattr__(name)
|
|
382
|
+
|
|
383
|
+
@functools.cached_property
|
|
384
|
+
def _cached_var_name(self) -> str:
|
|
385
|
+
"""The name of the var.
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
The name of the var.
|
|
389
|
+
"""
|
|
390
|
+
return (
|
|
391
|
+
"{ "
|
|
392
|
+
+ ", ".join(
|
|
393
|
+
[
|
|
394
|
+
f"[{str(LiteralVar.create(key))}] : {str(LiteralVar.create(value))}"
|
|
395
|
+
for key, value in self._var_value.items()
|
|
396
|
+
]
|
|
397
|
+
)
|
|
398
|
+
+ " }"
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
@functools.cached_property
|
|
402
|
+
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
|
|
403
|
+
"""Get all VarData associated with the Var.
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
The VarData of the components and all of its children.
|
|
407
|
+
"""
|
|
408
|
+
return ImmutableVarData.merge(
|
|
409
|
+
*[
|
|
410
|
+
value._get_all_var_data()
|
|
411
|
+
for key, value in self._var_value
|
|
412
|
+
if isinstance(value, Var)
|
|
413
|
+
],
|
|
414
|
+
*[
|
|
415
|
+
key._get_all_var_data()
|
|
416
|
+
for key, value in self._var_value
|
|
417
|
+
if isinstance(key, Var)
|
|
418
|
+
],
|
|
419
|
+
self._var_data,
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
def _get_all_var_data(self) -> ImmutableVarData | None:
|
|
423
|
+
"""Wrapper method for cached property.
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
The VarData of the components and all of its children.
|
|
427
|
+
"""
|
|
428
|
+
return self._cached_get_all_var_data
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
P = ParamSpec("P")
|
|
432
|
+
T = TypeVar("T", bound=ImmutableVar)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def var_operation(*, output: Type[T]) -> Callable[[Callable[P, str]], Callable[P, T]]:
|
|
436
|
+
"""Decorator for creating a var operation.
|
|
437
|
+
|
|
438
|
+
Example:
|
|
439
|
+
```python
|
|
440
|
+
@var_operation(output=NumberVar)
|
|
441
|
+
def add(a: NumberVar, b: NumberVar):
|
|
442
|
+
return f"({a} + {b})"
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
output: The output type of the operation.
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
The decorator.
|
|
450
|
+
"""
|
|
451
|
+
|
|
452
|
+
def decorator(func: Callable[P, str], output=output):
|
|
453
|
+
@functools.wraps(func)
|
|
454
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
|
455
|
+
args_vars = [
|
|
456
|
+
LiteralVar.create(arg) if not isinstance(arg, Var) else arg
|
|
457
|
+
for arg in args
|
|
458
|
+
]
|
|
459
|
+
kwargs_vars = {
|
|
460
|
+
key: LiteralVar.create(value) if not isinstance(value, Var) else value
|
|
461
|
+
for key, value in kwargs.items()
|
|
462
|
+
}
|
|
463
|
+
return output(
|
|
464
|
+
_var_name=func(*args_vars, **kwargs_vars), # type: ignore
|
|
465
|
+
_var_data=VarData.merge(
|
|
466
|
+
*[arg._get_all_var_data() for arg in args if isinstance(arg, Var)],
|
|
467
|
+
*[
|
|
468
|
+
arg._get_all_var_data()
|
|
469
|
+
for arg in kwargs.values()
|
|
470
|
+
if isinstance(arg, Var)
|
|
471
|
+
],
|
|
472
|
+
),
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
return wrapper
|
|
476
|
+
|
|
477
|
+
return decorator
|