reflex 0.5.10a3__py3-none-any.whl → 0.6.0__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/jinja/custom_components/pyproject.toml.jinja2 +2 -2
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -4
- reflex/.templates/jinja/web/utils/context.js.jinja2 +1 -1
- reflex/.templates/jinja/web/utils/theme.js.jinja2 +1 -1
- reflex/.templates/web/utils/state.js +3 -1
- reflex/__init__.py +10 -3
- reflex/__init__.pyi +3 -2
- reflex/app.py +47 -11
- reflex/app_module_for_backend.py +1 -1
- reflex/base.py +3 -2
- reflex/compiler/compiler.py +5 -5
- reflex/compiler/utils.py +5 -3
- reflex/components/base/app_wrap.py +2 -4
- reflex/components/base/app_wrap.pyi +16 -26
- reflex/components/base/bare.py +6 -4
- reflex/components/base/body.pyi +16 -26
- reflex/components/base/document.pyi +76 -126
- reflex/components/base/error_boundary.py +9 -8
- reflex/components/base/error_boundary.pyi +18 -30
- reflex/components/base/fragment.pyi +16 -26
- reflex/components/base/head.pyi +31 -51
- reflex/components/base/link.py +1 -1
- reflex/components/base/link.pyi +31 -51
- reflex/components/base/meta.pyi +61 -101
- reflex/components/base/script.py +2 -2
- reflex/components/base/script.pyi +20 -36
- reflex/components/component.py +107 -130
- reflex/components/core/banner.py +61 -66
- reflex/components/core/banner.pyi +129 -230
- reflex/components/core/client_side_routing.py +2 -2
- reflex/components/core/client_side_routing.pyi +31 -51
- reflex/components/core/clipboard.py +4 -3
- reflex/components/core/clipboard.pyi +19 -31
- reflex/components/core/cond.py +21 -44
- reflex/components/core/debounce.py +7 -9
- reflex/components/core/debounce.pyi +19 -31
- reflex/components/core/foreach.py +4 -14
- reflex/components/core/html.py +1 -1
- reflex/components/core/html.pyi +34 -44
- reflex/components/core/match.py +36 -43
- reflex/components/core/upload.py +27 -26
- reflex/components/core/upload.pyi +81 -116
- reflex/components/datadisplay/code.py +55 -29
- reflex/components/datadisplay/code.pyi +303 -410
- reflex/components/datadisplay/dataeditor.py +13 -9
- reflex/components/datadisplay/dataeditor.pyi +39 -51
- reflex/components/el/__init__.py +0 -1
- reflex/components/el/__init__.pyi +0 -11
- reflex/components/el/element.pyi +16 -26
- reflex/components/el/elements/__init__.py +1 -7
- reflex/components/el/elements/__init__.pyi +1 -15
- reflex/components/el/elements/base.py +1 -1
- reflex/components/el/elements/base.pyi +33 -43
- reflex/components/el/elements/forms.py +26 -33
- reflex/components/el/elements/forms.pyi +542 -694
- reflex/components/el/elements/inline.py +1 -1
- reflex/components/el/elements/inline.pyi +909 -1189
- reflex/components/el/elements/media.py +1 -22
- reflex/components/el/elements/media.pyi +765 -975
- reflex/components/el/elements/metadata.py +3 -5
- reflex/components/el/elements/metadata.pyi +175 -235
- reflex/components/el/elements/other.py +1 -1
- reflex/components/el/elements/other.pyi +228 -298
- reflex/components/el/elements/scripts.py +1 -1
- reflex/components/el/elements/scripts.pyi +106 -136
- reflex/components/el/elements/sectioning.py +0 -2
- reflex/components/el/elements/sectioning.pyi +481 -631
- reflex/components/el/elements/tables.py +1 -1
- reflex/components/el/elements/tables.pyi +341 -441
- reflex/components/el/elements/typography.py +1 -1
- reflex/components/el/elements/typography.pyi +491 -641
- reflex/components/gridjs/datatable.py +9 -13
- reflex/components/gridjs/datatable.pyi +33 -53
- reflex/components/lucide/icon.py +3 -127
- reflex/components/lucide/icon.pyi +31 -160
- reflex/components/markdown/markdown.py +32 -42
- reflex/components/markdown/markdown.pyi +28 -41
- reflex/components/moment/moment.py +13 -12
- reflex/components/moment/moment.pyi +22 -33
- reflex/components/next/base.pyi +16 -26
- reflex/components/next/image.py +1 -5
- reflex/components/next/image.pyi +21 -35
- reflex/components/next/link.py +1 -1
- reflex/components/next/link.pyi +16 -26
- reflex/components/next/video.py +1 -1
- reflex/components/next/video.pyi +16 -26
- reflex/components/plotly/plotly.py +17 -30
- reflex/components/plotly/plotly.pyi +38 -52
- reflex/components/props.py +21 -10
- reflex/components/radix/__init__.pyi +2 -1
- reflex/components/radix/primitives/accordion.py +6 -7
- reflex/components/radix/primitives/accordion.pyi +415 -485
- reflex/components/radix/primitives/base.py +1 -1
- reflex/components/radix/primitives/base.pyi +31 -51
- reflex/components/radix/primitives/drawer.py +1 -1
- reflex/components/radix/primitives/drawer.pyi +162 -262
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/form.pyi +247 -353
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/progress.pyi +226 -276
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/primitives/slider.pyi +82 -132
- reflex/components/radix/themes/base.py +8 -25
- reflex/components/radix/themes/base.pyi +171 -242
- reflex/components/radix/themes/color_mode.py +11 -20
- reflex/components/radix/themes/color_mode.pyi +198 -231
- reflex/components/radix/themes/components/__init__.pyi +1 -0
- reflex/components/radix/themes/components/alert_dialog.py +1 -1
- reflex/components/radix/themes/components/alert_dialog.pyi +129 -199
- reflex/components/radix/themes/components/aspect_ratio.py +1 -1
- reflex/components/radix/themes/components/aspect_ratio.pyi +16 -26
- reflex/components/radix/themes/components/avatar.py +1 -1
- reflex/components/radix/themes/components/avatar.pyi +69 -79
- reflex/components/radix/themes/components/badge.py +1 -1
- reflex/components/radix/themes/components/badge.pyi +87 -97
- reflex/components/radix/themes/components/button.py +1 -1
- reflex/components/radix/themes/components/button.pyi +97 -107
- reflex/components/radix/themes/components/callout.py +1 -1
- reflex/components/radix/themes/components/callout.pyi +317 -367
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +37 -47
- reflex/components/radix/themes/components/checkbox.py +2 -4
- reflex/components/radix/themes/components/checkbox.pyi +205 -241
- reflex/components/radix/themes/components/checkbox_cards.py +1 -1
- reflex/components/radix/themes/components/checkbox_cards.pyi +92 -112
- reflex/components/radix/themes/components/checkbox_group.py +1 -1
- reflex/components/radix/themes/components/checkbox_group.pyi +84 -104
- reflex/components/radix/themes/components/context_menu.py +1 -1
- reflex/components/radix/themes/components/context_menu.pyi +230 -310
- reflex/components/radix/themes/components/data_list.py +6 -1
- reflex/components/radix/themes/components/data_list.pyi +131 -166
- reflex/components/radix/themes/components/dialog.py +1 -1
- reflex/components/radix/themes/components/dialog.pyi +132 -202
- reflex/components/radix/themes/components/dropdown_menu.py +1 -1
- reflex/components/radix/themes/components/dropdown_menu.pyi +241 -323
- reflex/components/radix/themes/components/hover_card.py +1 -1
- reflex/components/radix/themes/components/hover_card.pyi +86 -126
- reflex/components/radix/themes/components/icon_button.py +1 -1
- reflex/components/radix/themes/components/icon_button.pyi +97 -107
- reflex/components/radix/themes/components/inset.py +1 -1
- reflex/components/radix/themes/components/inset.pyi +46 -56
- reflex/components/radix/themes/components/popover.py +1 -1
- reflex/components/radix/themes/components/popover.pyi +91 -131
- reflex/components/radix/themes/components/progress.py +1 -1
- reflex/components/radix/themes/components/progress.pyi +70 -80
- reflex/components/radix/themes/components/radio.py +1 -1
- reflex/components/radix/themes/components/radio.pyi +68 -78
- reflex/components/radix/themes/components/radio_cards.py +1 -1
- reflex/components/radix/themes/components/radio_cards.pyi +96 -116
- reflex/components/radix/themes/components/radio_group.py +32 -31
- reflex/components/radix/themes/components/radio_group.pyi +230 -266
- reflex/components/radix/themes/components/scroll_area.py +1 -1
- reflex/components/radix/themes/components/scroll_area.pyi +20 -30
- reflex/components/radix/themes/components/segmented_control.py +1 -1
- reflex/components/radix/themes/components/segmented_control.pyi +88 -110
- reflex/components/radix/themes/components/select.py +1 -1
- reflex/components/radix/themes/components/select.pyi +365 -461
- reflex/components/radix/themes/components/separator.py +2 -4
- reflex/components/radix/themes/components/separator.pyi +68 -78
- reflex/components/radix/themes/components/skeleton.py +1 -1
- reflex/components/radix/themes/components/skeleton.pyi +22 -32
- reflex/components/radix/themes/components/slider.py +1 -1
- reflex/components/radix/themes/components/slider.pyi +74 -86
- reflex/components/radix/themes/components/spinner.py +1 -1
- reflex/components/radix/themes/components/spinner.pyi +18 -28
- reflex/components/radix/themes/components/switch.py +1 -1
- reflex/components/radix/themes/components/switch.pyi +70 -82
- reflex/components/radix/themes/components/table.py +1 -1
- reflex/components/radix/themes/components/table.pyi +254 -324
- reflex/components/radix/themes/components/tabs.py +1 -1
- reflex/components/radix/themes/components/tabs.pyi +134 -188
- reflex/components/radix/themes/components/text_area.py +1 -1
- reflex/components/radix/themes/components/text_area.pyi +95 -109
- reflex/components/radix/themes/components/text_field.py +1 -80
- reflex/components/radix/themes/components/text_field.pyi +245 -290
- reflex/components/radix/themes/components/tooltip.py +1 -1
- reflex/components/radix/themes/components/tooltip.pyi +25 -35
- reflex/components/radix/themes/layout/__init__.pyi +1 -0
- reflex/components/radix/themes/layout/base.py +1 -1
- reflex/components/radix/themes/layout/base.pyi +55 -65
- reflex/components/radix/themes/layout/box.pyi +33 -43
- reflex/components/radix/themes/layout/center.pyi +55 -65
- reflex/components/radix/themes/layout/container.py +2 -4
- reflex/components/radix/themes/layout/container.pyi +35 -45
- reflex/components/radix/themes/layout/flex.py +1 -1
- reflex/components/radix/themes/layout/flex.pyi +55 -65
- reflex/components/radix/themes/layout/grid.py +1 -1
- reflex/components/radix/themes/layout/grid.pyi +63 -73
- reflex/components/radix/themes/layout/list.py +1 -1
- reflex/components/radix/themes/layout/list.pyi +188 -238
- reflex/components/radix/themes/layout/section.py +2 -4
- reflex/components/radix/themes/layout/section.pyi +35 -45
- reflex/components/radix/themes/layout/spacer.pyi +55 -65
- reflex/components/radix/themes/layout/stack.py +1 -1
- reflex/components/radix/themes/layout/stack.pyi +125 -155
- reflex/components/radix/themes/typography/blockquote.py +1 -1
- reflex/components/radix/themes/typography/blockquote.pyi +88 -98
- reflex/components/radix/themes/typography/code.py +1 -1
- reflex/components/radix/themes/typography/code.pyi +89 -99
- reflex/components/radix/themes/typography/heading.py +1 -1
- reflex/components/radix/themes/typography/heading.pyi +95 -105
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/link.pyi +101 -111
- reflex/components/radix/themes/typography/text.py +1 -1
- reflex/components/radix/themes/typography/text.pyi +494 -564
- reflex/components/react_player/audio.pyi +32 -58
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/react_player/react_player.pyi +32 -58
- reflex/components/react_player/video.pyi +32 -58
- reflex/components/recharts/cartesian.py +22 -19
- reflex/components/recharts/cartesian.pyi +658 -840
- reflex/components/recharts/charts.py +3 -3
- reflex/components/recharts/charts.pyi +238 -342
- reflex/components/recharts/general.py +8 -8
- reflex/components/recharts/general.pyi +175 -225
- reflex/components/recharts/polar.py +11 -11
- reflex/components/recharts/polar.pyi +135 -171
- reflex/components/recharts/recharts.pyi +31 -51
- reflex/components/sonner/toast.py +27 -31
- reflex/components/sonner/toast.pyi +36 -45
- reflex/components/suneditor/editor.py +1 -1
- reflex/components/suneditor/editor.pyi +54 -76
- reflex/components/tags/cond_tag.py +6 -4
- reflex/components/tags/iter_tag.py +37 -25
- reflex/components/tags/match_tag.py +6 -4
- reflex/components/tags/tag.py +43 -28
- reflex/constants/base.py +3 -1
- reflex/constants/event.py +1 -0
- reflex/custom_components/custom_components.py +3 -1
- reflex/event.py +166 -108
- reflex/experimental/__init__.py +25 -6
- reflex/experimental/client_state.py +34 -57
- reflex/experimental/hooks.py +12 -17
- reflex/experimental/layout.py +4 -4
- reflex/experimental/layout.pyi +130 -180
- reflex/middleware/hydrate_middleware.py +2 -0
- reflex/middleware/middleware.py +3 -3
- reflex/model.py +22 -0
- reflex/reflex.py +4 -0
- reflex/state.py +491 -110
- reflex/style.py +56 -39
- reflex/testing.py +8 -3
- reflex/utils/exceptions.py +32 -0
- reflex/utils/exec.py +0 -14
- reflex/utils/format.py +80 -209
- reflex/utils/imports.py +16 -73
- reflex/utils/net.py +43 -0
- reflex/utils/path_ops.py +13 -1
- reflex/utils/prerequisites.py +81 -41
- reflex/utils/pyi_generator.py +12 -6
- reflex/utils/serializers.py +13 -41
- reflex/utils/telemetry.py +3 -2
- reflex/utils/types.py +47 -7
- reflex/{experimental/vars → vars}/__init__.py +6 -3
- reflex/vars/base.py +2563 -0
- reflex/vars/function.py +196 -0
- reflex/vars/number.py +1158 -0
- reflex/vars/object.py +562 -0
- reflex/vars/sequence.py +1604 -0
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/METADATA +6 -9
- reflex-0.6.0.dist-info/RECORD +382 -0
- reflex/.templates/apps/demo/.gitignore +0 -4
- reflex/.templates/apps/demo/assets/favicon.ico +0 -0
- reflex/.templates/apps/demo/assets/github.svg +0 -10
- reflex/.templates/apps/demo/assets/icon.svg +0 -37
- reflex/.templates/apps/demo/assets/logo.svg +0 -68
- reflex/.templates/apps/demo/assets/paneleft.svg +0 -13
- reflex/.templates/apps/demo/code/__init__.py +0 -1
- reflex/.templates/apps/demo/code/demo.py +0 -127
- reflex/.templates/apps/demo/code/pages/__init__.py +0 -7
- reflex/.templates/apps/demo/code/pages/chatapp.py +0 -31
- reflex/.templates/apps/demo/code/pages/datatable.py +0 -360
- reflex/.templates/apps/demo/code/pages/forms.py +0 -257
- reflex/.templates/apps/demo/code/pages/graphing.py +0 -253
- reflex/.templates/apps/demo/code/pages/home.py +0 -56
- reflex/.templates/apps/demo/code/sidebar.py +0 -178
- reflex/.templates/apps/demo/code/state.py +0 -22
- reflex/.templates/apps/demo/code/states/form_state.py +0 -40
- reflex/.templates/apps/demo/code/states/pie_state.py +0 -47
- reflex/.templates/apps/demo/code/styles.py +0 -68
- reflex/.templates/apps/demo/code/webui/__init__.py +0 -0
- reflex/.templates/apps/demo/code/webui/components/__init__.py +0 -4
- reflex/.templates/apps/demo/code/webui/components/chat.py +0 -118
- reflex/.templates/apps/demo/code/webui/components/loading_icon.py +0 -19
- reflex/.templates/apps/demo/code/webui/components/modal.py +0 -56
- reflex/.templates/apps/demo/code/webui/components/navbar.py +0 -70
- reflex/.templates/apps/demo/code/webui/components/sidebar.py +0 -66
- reflex/.templates/apps/demo/code/webui/state.py +0 -146
- reflex/.templates/apps/demo/code/webui/styles.py +0 -88
- reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +0 -36
- reflex/experimental/vars/base.py +0 -583
- reflex/experimental/vars/function.py +0 -290
- reflex/experimental/vars/number.py +0 -1458
- reflex/experimental/vars/object.py +0 -804
- reflex/experimental/vars/sequence.py +0 -1764
- reflex/utils/watch.py +0 -96
- reflex/vars.py +0 -2604
- reflex/vars.pyi +0 -218
- reflex-0.5.10a3.dist-info/RECORD +0 -413
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/LICENSE +0 -0
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/WHEEL +0 -0
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/entry_points.txt +0 -0
reflex/vars/sequence.py
ADDED
|
@@ -0,0 +1,1604 @@
|
|
|
1
|
+
"""Collection of string classes and utilities."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
import inspect
|
|
7
|
+
import json
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
import typing
|
|
11
|
+
from typing import (
|
|
12
|
+
TYPE_CHECKING,
|
|
13
|
+
Any,
|
|
14
|
+
ClassVar,
|
|
15
|
+
Dict,
|
|
16
|
+
List,
|
|
17
|
+
Literal,
|
|
18
|
+
NoReturn,
|
|
19
|
+
Set,
|
|
20
|
+
Tuple,
|
|
21
|
+
Type,
|
|
22
|
+
TypeVar,
|
|
23
|
+
Union,
|
|
24
|
+
overload,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
from reflex import constants
|
|
28
|
+
from reflex.constants.base import REFLEX_VAR_OPENING_TAG
|
|
29
|
+
from reflex.utils.exceptions import VarTypeError
|
|
30
|
+
from reflex.utils.types import GenericType, get_origin
|
|
31
|
+
|
|
32
|
+
from .base import (
|
|
33
|
+
CachedVarOperation,
|
|
34
|
+
CustomVarOperationReturn,
|
|
35
|
+
LiteralNoneVar,
|
|
36
|
+
LiteralVar,
|
|
37
|
+
ToOperation,
|
|
38
|
+
Var,
|
|
39
|
+
VarData,
|
|
40
|
+
_global_vars,
|
|
41
|
+
cached_property_no_lock,
|
|
42
|
+
figure_out_type,
|
|
43
|
+
get_unique_variable_name,
|
|
44
|
+
unionize,
|
|
45
|
+
var_operation,
|
|
46
|
+
var_operation_return,
|
|
47
|
+
)
|
|
48
|
+
from .number import (
|
|
49
|
+
BooleanVar,
|
|
50
|
+
LiteralNumberVar,
|
|
51
|
+
NumberVar,
|
|
52
|
+
raise_unsupported_operand_types,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if TYPE_CHECKING:
|
|
56
|
+
from .object import ObjectVar
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class StringVar(Var[str]):
|
|
60
|
+
"""Base class for immutable string vars."""
|
|
61
|
+
|
|
62
|
+
@overload
|
|
63
|
+
def __add__(self, other: StringVar | str) -> ConcatVarOperation: ...
|
|
64
|
+
|
|
65
|
+
@overload
|
|
66
|
+
def __add__(self, other: NoReturn) -> NoReturn: ...
|
|
67
|
+
|
|
68
|
+
def __add__(self, other: Any) -> ConcatVarOperation:
|
|
69
|
+
"""Concatenate two strings.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
other: The other string.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
The string concatenation operation.
|
|
76
|
+
"""
|
|
77
|
+
if not isinstance(other, (StringVar, str)):
|
|
78
|
+
raise_unsupported_operand_types("+", (type(self), type(other)))
|
|
79
|
+
|
|
80
|
+
return ConcatVarOperation.create(self, other)
|
|
81
|
+
|
|
82
|
+
@overload
|
|
83
|
+
def __radd__(self, other: StringVar | str) -> ConcatVarOperation: ...
|
|
84
|
+
|
|
85
|
+
@overload
|
|
86
|
+
def __radd__(self, other: NoReturn) -> NoReturn: ...
|
|
87
|
+
|
|
88
|
+
def __radd__(self, other: Any) -> ConcatVarOperation:
|
|
89
|
+
"""Concatenate two strings.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
other: The other string.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
The string concatenation operation.
|
|
96
|
+
"""
|
|
97
|
+
if not isinstance(other, (StringVar, str)):
|
|
98
|
+
raise_unsupported_operand_types("+", (type(other), type(self)))
|
|
99
|
+
|
|
100
|
+
return ConcatVarOperation.create(other, self)
|
|
101
|
+
|
|
102
|
+
@overload
|
|
103
|
+
def __mul__(self, other: NumberVar | int) -> StringVar: ...
|
|
104
|
+
|
|
105
|
+
@overload
|
|
106
|
+
def __mul__(self, other: NoReturn) -> NoReturn: ...
|
|
107
|
+
|
|
108
|
+
def __mul__(self, other: Any) -> StringVar:
|
|
109
|
+
"""Multiply the sequence by a number or an integer.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
other: The number or integer to multiply the sequence by.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
StringVar: The resulting sequence after multiplication.
|
|
116
|
+
"""
|
|
117
|
+
if not isinstance(other, (NumberVar, int)):
|
|
118
|
+
raise_unsupported_operand_types("*", (type(self), type(other)))
|
|
119
|
+
|
|
120
|
+
return (self.split() * other).join()
|
|
121
|
+
|
|
122
|
+
@overload
|
|
123
|
+
def __rmul__(self, other: NumberVar | int) -> StringVar: ...
|
|
124
|
+
|
|
125
|
+
@overload
|
|
126
|
+
def __rmul__(self, other: NoReturn) -> NoReturn: ...
|
|
127
|
+
|
|
128
|
+
def __rmul__(self, other: Any) -> StringVar:
|
|
129
|
+
"""Multiply the sequence by a number or an integer.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
other: The number or integer to multiply the sequence by.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
StringVar: The resulting sequence after multiplication.
|
|
136
|
+
"""
|
|
137
|
+
if not isinstance(other, (NumberVar, int)):
|
|
138
|
+
raise_unsupported_operand_types("*", (type(other), type(self)))
|
|
139
|
+
|
|
140
|
+
return (self.split() * other).join()
|
|
141
|
+
|
|
142
|
+
@overload
|
|
143
|
+
def __getitem__(self, i: slice) -> StringVar: ...
|
|
144
|
+
|
|
145
|
+
@overload
|
|
146
|
+
def __getitem__(self, i: int | NumberVar) -> StringVar: ...
|
|
147
|
+
|
|
148
|
+
def __getitem__(self, i: Any) -> StringVar:
|
|
149
|
+
"""Get a slice of the string.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
i: The slice.
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
The string slice operation.
|
|
156
|
+
"""
|
|
157
|
+
if isinstance(i, slice):
|
|
158
|
+
return self.split()[i].join()
|
|
159
|
+
if not isinstance(i, (int, NumberVar)) or (
|
|
160
|
+
isinstance(i, NumberVar) and i._is_strict_float()
|
|
161
|
+
):
|
|
162
|
+
raise_unsupported_operand_types("[]", (type(self), type(i)))
|
|
163
|
+
return string_item_operation(self, i)
|
|
164
|
+
|
|
165
|
+
def length(self) -> NumberVar:
|
|
166
|
+
"""Get the length of the string.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
The string length operation.
|
|
170
|
+
"""
|
|
171
|
+
return self.split().length()
|
|
172
|
+
|
|
173
|
+
def lower(self) -> StringVar:
|
|
174
|
+
"""Convert the string to lowercase.
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
The string lower operation.
|
|
178
|
+
"""
|
|
179
|
+
return string_lower_operation(self)
|
|
180
|
+
|
|
181
|
+
def upper(self) -> StringVar:
|
|
182
|
+
"""Convert the string to uppercase.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
The string upper operation.
|
|
186
|
+
"""
|
|
187
|
+
return string_upper_operation(self)
|
|
188
|
+
|
|
189
|
+
def strip(self) -> StringVar:
|
|
190
|
+
"""Strip the string.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
The string strip operation.
|
|
194
|
+
"""
|
|
195
|
+
return string_strip_operation(self)
|
|
196
|
+
|
|
197
|
+
def reversed(self) -> StringVar:
|
|
198
|
+
"""Reverse the string.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
The string reverse operation.
|
|
202
|
+
"""
|
|
203
|
+
return self.split().reverse().join()
|
|
204
|
+
|
|
205
|
+
@overload
|
|
206
|
+
def contains(
|
|
207
|
+
self, other: StringVar | str, field: StringVar | str | None = None
|
|
208
|
+
) -> BooleanVar: ...
|
|
209
|
+
|
|
210
|
+
@overload
|
|
211
|
+
def contains(
|
|
212
|
+
self, other: NoReturn, field: StringVar | str | None = None
|
|
213
|
+
) -> NoReturn: ...
|
|
214
|
+
|
|
215
|
+
def contains(self, other: Any, field: Any = None) -> BooleanVar:
|
|
216
|
+
"""Check if the string contains another string.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
other: The other string.
|
|
220
|
+
field: The field to check.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
The string contains operation.
|
|
224
|
+
"""
|
|
225
|
+
if not isinstance(other, (StringVar, str)):
|
|
226
|
+
raise_unsupported_operand_types("contains", (type(self), type(other)))
|
|
227
|
+
if field is not None:
|
|
228
|
+
if not isinstance(field, (StringVar, str)):
|
|
229
|
+
raise_unsupported_operand_types("contains", (type(self), type(field)))
|
|
230
|
+
return string_contains_field_operation(self, other, field)
|
|
231
|
+
return string_contains_operation(self, other)
|
|
232
|
+
|
|
233
|
+
@overload
|
|
234
|
+
def split(self, separator: StringVar | str = "") -> ArrayVar[List[str]]: ...
|
|
235
|
+
|
|
236
|
+
@overload
|
|
237
|
+
def split(self, separator: NoReturn) -> NoReturn: ...
|
|
238
|
+
|
|
239
|
+
def split(self, separator: Any = "") -> ArrayVar[List[str]]:
|
|
240
|
+
"""Split the string.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
separator: The separator.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
The string split operation.
|
|
247
|
+
"""
|
|
248
|
+
if not isinstance(separator, (StringVar, str)):
|
|
249
|
+
raise_unsupported_operand_types("split", (type(self), type(separator)))
|
|
250
|
+
return string_split_operation(self, separator)
|
|
251
|
+
|
|
252
|
+
@overload
|
|
253
|
+
def startswith(self, prefix: StringVar | str) -> BooleanVar: ...
|
|
254
|
+
|
|
255
|
+
@overload
|
|
256
|
+
def startswith(self, prefix: NoReturn) -> NoReturn: ...
|
|
257
|
+
|
|
258
|
+
def startswith(self, prefix: Any) -> BooleanVar:
|
|
259
|
+
"""Check if the string starts with a prefix.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
prefix: The prefix.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
The string starts with operation.
|
|
266
|
+
"""
|
|
267
|
+
if not isinstance(prefix, (StringVar, str)):
|
|
268
|
+
raise_unsupported_operand_types("startswith", (type(self), type(prefix)))
|
|
269
|
+
return string_starts_with_operation(self, prefix)
|
|
270
|
+
|
|
271
|
+
@overload
|
|
272
|
+
def __lt__(self, other: StringVar | str) -> BooleanVar: ...
|
|
273
|
+
|
|
274
|
+
@overload
|
|
275
|
+
def __lt__(self, other: NoReturn) -> NoReturn: ...
|
|
276
|
+
|
|
277
|
+
def __lt__(self, other: Any):
|
|
278
|
+
"""Check if the string is less than another string.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
other: The other string.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
The string less than operation.
|
|
285
|
+
"""
|
|
286
|
+
if not isinstance(other, (StringVar, str)):
|
|
287
|
+
raise_unsupported_operand_types("<", (type(self), type(other)))
|
|
288
|
+
|
|
289
|
+
return string_lt_operation(self, other)
|
|
290
|
+
|
|
291
|
+
@overload
|
|
292
|
+
def __gt__(self, other: StringVar | str) -> BooleanVar: ...
|
|
293
|
+
|
|
294
|
+
@overload
|
|
295
|
+
def __gt__(self, other: NoReturn) -> NoReturn: ...
|
|
296
|
+
|
|
297
|
+
def __gt__(self, other: Any):
|
|
298
|
+
"""Check if the string is greater than another string.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
other: The other string.
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
The string greater than operation.
|
|
305
|
+
"""
|
|
306
|
+
if not isinstance(other, (StringVar, str)):
|
|
307
|
+
raise_unsupported_operand_types(">", (type(self), type(other)))
|
|
308
|
+
|
|
309
|
+
return string_gt_operation(self, other)
|
|
310
|
+
|
|
311
|
+
@overload
|
|
312
|
+
def __le__(self, other: StringVar | str) -> BooleanVar: ...
|
|
313
|
+
|
|
314
|
+
@overload
|
|
315
|
+
def __le__(self, other: NoReturn) -> NoReturn: ...
|
|
316
|
+
|
|
317
|
+
def __le__(self, other: Any):
|
|
318
|
+
"""Check if the string is less than or equal to another string.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
other: The other string.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
The string less than or equal operation.
|
|
325
|
+
"""
|
|
326
|
+
if not isinstance(other, (StringVar, str)):
|
|
327
|
+
raise_unsupported_operand_types("<=", (type(self), type(other)))
|
|
328
|
+
|
|
329
|
+
return string_le_operation(self, other)
|
|
330
|
+
|
|
331
|
+
@overload
|
|
332
|
+
def __ge__(self, other: StringVar | str) -> BooleanVar: ...
|
|
333
|
+
|
|
334
|
+
@overload
|
|
335
|
+
def __ge__(self, other: NoReturn) -> NoReturn: ...
|
|
336
|
+
|
|
337
|
+
def __ge__(self, other: Any):
|
|
338
|
+
"""Check if the string is greater than or equal to another string.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
other: The other string.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
The string greater than or equal operation.
|
|
345
|
+
"""
|
|
346
|
+
if not isinstance(other, (StringVar, str)):
|
|
347
|
+
raise_unsupported_operand_types(">=", (type(self), type(other)))
|
|
348
|
+
|
|
349
|
+
return string_ge_operation(self, other)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
@var_operation
|
|
353
|
+
def string_lt_operation(lhs: StringVar | str, rhs: StringVar | str):
|
|
354
|
+
"""Check if a string is less than another string.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
lhs: The left-hand side string.
|
|
358
|
+
rhs: The right-hand side string.
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
The string less than operation.
|
|
362
|
+
"""
|
|
363
|
+
return var_operation_return(js_expression=f"{lhs} < {rhs}", var_type=bool)
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@var_operation
|
|
367
|
+
def string_gt_operation(lhs: StringVar | str, rhs: StringVar | str):
|
|
368
|
+
"""Check if a string is greater than another string.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
lhs: The left-hand side string.
|
|
372
|
+
rhs: The right-hand side string.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
The string greater than operation.
|
|
376
|
+
"""
|
|
377
|
+
return var_operation_return(js_expression=f"{lhs} > {rhs}", var_type=bool)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
@var_operation
|
|
381
|
+
def string_le_operation(lhs: StringVar | str, rhs: StringVar | str):
|
|
382
|
+
"""Check if a string is less than or equal to another string.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
lhs: The left-hand side string.
|
|
386
|
+
rhs: The right-hand side string.
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
The string less than or equal operation.
|
|
390
|
+
"""
|
|
391
|
+
return var_operation_return(js_expression=f"{lhs} <= {rhs}", var_type=bool)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
@var_operation
|
|
395
|
+
def string_ge_operation(lhs: StringVar | str, rhs: StringVar | str):
|
|
396
|
+
"""Check if a string is greater than or equal to another string.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
lhs: The left-hand side string.
|
|
400
|
+
rhs: The right-hand side string.
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
The string greater than or equal operation.
|
|
404
|
+
"""
|
|
405
|
+
return var_operation_return(js_expression=f"{lhs} >= {rhs}", var_type=bool)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@var_operation
|
|
409
|
+
def string_lower_operation(string: StringVar):
|
|
410
|
+
"""Convert a string to lowercase.
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
string: The string to convert.
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
The lowercase string.
|
|
417
|
+
"""
|
|
418
|
+
return var_operation_return(js_expression=f"{string}.toLowerCase()", var_type=str)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
@var_operation
|
|
422
|
+
def string_upper_operation(string: StringVar):
|
|
423
|
+
"""Convert a string to uppercase.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
string: The string to convert.
|
|
427
|
+
|
|
428
|
+
Returns:
|
|
429
|
+
The uppercase string.
|
|
430
|
+
"""
|
|
431
|
+
return var_operation_return(js_expression=f"{string}.toUpperCase()", var_type=str)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
@var_operation
|
|
435
|
+
def string_strip_operation(string: StringVar):
|
|
436
|
+
"""Strip a string.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
string: The string to strip.
|
|
440
|
+
|
|
441
|
+
Returns:
|
|
442
|
+
The stripped string.
|
|
443
|
+
"""
|
|
444
|
+
return var_operation_return(js_expression=f"{string}.trim()", var_type=str)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
@var_operation
|
|
448
|
+
def string_contains_field_operation(
|
|
449
|
+
haystack: StringVar, needle: StringVar | str, field: StringVar | str
|
|
450
|
+
):
|
|
451
|
+
"""Check if a string contains another string.
|
|
452
|
+
|
|
453
|
+
Args:
|
|
454
|
+
haystack: The haystack.
|
|
455
|
+
needle: The needle.
|
|
456
|
+
field: The field to check.
|
|
457
|
+
|
|
458
|
+
Returns:
|
|
459
|
+
The string contains operation.
|
|
460
|
+
"""
|
|
461
|
+
return var_operation_return(
|
|
462
|
+
js_expression=f"{haystack}.some(obj => obj[{field}] === {needle})",
|
|
463
|
+
var_type=bool,
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
@var_operation
|
|
468
|
+
def string_contains_operation(haystack: StringVar, needle: StringVar | str):
|
|
469
|
+
"""Check if a string contains another string.
|
|
470
|
+
|
|
471
|
+
Args:
|
|
472
|
+
haystack: The haystack.
|
|
473
|
+
needle: The needle.
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
The string contains operation.
|
|
477
|
+
"""
|
|
478
|
+
return var_operation_return(
|
|
479
|
+
js_expression=f"{haystack}.includes({needle})", var_type=bool
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
@var_operation
|
|
484
|
+
def string_starts_with_operation(full_string: StringVar, prefix: StringVar | str):
|
|
485
|
+
"""Check if a string starts with a prefix.
|
|
486
|
+
|
|
487
|
+
Args:
|
|
488
|
+
full_string: The full string.
|
|
489
|
+
prefix: The prefix.
|
|
490
|
+
|
|
491
|
+
Returns:
|
|
492
|
+
Whether the string starts with the prefix.
|
|
493
|
+
"""
|
|
494
|
+
return var_operation_return(
|
|
495
|
+
js_expression=f"{full_string}.startsWith({prefix})", var_type=bool
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
@var_operation
|
|
500
|
+
def string_item_operation(string: StringVar, index: NumberVar | int):
|
|
501
|
+
"""Get an item from a string.
|
|
502
|
+
|
|
503
|
+
Args:
|
|
504
|
+
string: The string.
|
|
505
|
+
index: The index of the item.
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
The item from the string.
|
|
509
|
+
"""
|
|
510
|
+
return var_operation_return(js_expression=f"{string}.at({index})", var_type=str)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
@var_operation
|
|
514
|
+
def array_join_operation(array: ArrayVar, sep: StringVar | str = ""):
|
|
515
|
+
"""Join the elements of an array.
|
|
516
|
+
|
|
517
|
+
Args:
|
|
518
|
+
array: The array.
|
|
519
|
+
sep: The separator.
|
|
520
|
+
|
|
521
|
+
Returns:
|
|
522
|
+
The joined elements.
|
|
523
|
+
"""
|
|
524
|
+
return var_operation_return(js_expression=f"{array}.join({sep})", var_type=str)
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
# Compile regex for finding reflex var tags.
|
|
528
|
+
_decode_var_pattern_re = (
|
|
529
|
+
rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
|
|
530
|
+
)
|
|
531
|
+
_decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
@dataclasses.dataclass(
|
|
535
|
+
eq=False,
|
|
536
|
+
frozen=True,
|
|
537
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
538
|
+
)
|
|
539
|
+
class LiteralStringVar(LiteralVar, StringVar):
|
|
540
|
+
"""Base class for immutable literal string vars."""
|
|
541
|
+
|
|
542
|
+
_var_value: str = dataclasses.field(default="")
|
|
543
|
+
|
|
544
|
+
@classmethod
|
|
545
|
+
def create(
|
|
546
|
+
cls,
|
|
547
|
+
value: str,
|
|
548
|
+
_var_type: GenericType | None = str,
|
|
549
|
+
_var_data: VarData | None = None,
|
|
550
|
+
) -> StringVar:
|
|
551
|
+
"""Create a var from a string value.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
value: The value to create the var from.
|
|
555
|
+
_var_type: The type of the var.
|
|
556
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
557
|
+
|
|
558
|
+
Returns:
|
|
559
|
+
The var.
|
|
560
|
+
"""
|
|
561
|
+
if REFLEX_VAR_OPENING_TAG in value:
|
|
562
|
+
strings_and_vals: list[Var | str] = []
|
|
563
|
+
offset = 0
|
|
564
|
+
|
|
565
|
+
# Find all tags
|
|
566
|
+
while m := _decode_var_pattern.search(value):
|
|
567
|
+
start, end = m.span()
|
|
568
|
+
|
|
569
|
+
strings_and_vals.append(value[:start])
|
|
570
|
+
|
|
571
|
+
serialized_data = m.group(1)
|
|
572
|
+
|
|
573
|
+
if serialized_data.isnumeric() or (
|
|
574
|
+
serialized_data[0] == "-" and serialized_data[1:].isnumeric()
|
|
575
|
+
):
|
|
576
|
+
# This is a global immutable var.
|
|
577
|
+
var = _global_vars[int(serialized_data)]
|
|
578
|
+
strings_and_vals.append(var)
|
|
579
|
+
value = value[(end + len(var._js_expr)) :]
|
|
580
|
+
|
|
581
|
+
offset += end - start
|
|
582
|
+
|
|
583
|
+
strings_and_vals.append(value)
|
|
584
|
+
|
|
585
|
+
filtered_strings_and_vals = [
|
|
586
|
+
s for s in strings_and_vals if isinstance(s, Var) or s
|
|
587
|
+
]
|
|
588
|
+
if len(filtered_strings_and_vals) == 1:
|
|
589
|
+
only_string = filtered_strings_and_vals[0]
|
|
590
|
+
if isinstance(only_string, str):
|
|
591
|
+
return LiteralVar.create(only_string).to(StringVar, _var_type)
|
|
592
|
+
else:
|
|
593
|
+
return only_string.to(StringVar, only_string._var_type)
|
|
594
|
+
|
|
595
|
+
concat_result = ConcatVarOperation.create(
|
|
596
|
+
*filtered_strings_and_vals,
|
|
597
|
+
_var_data=_var_data,
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
return (
|
|
601
|
+
concat_result
|
|
602
|
+
if _var_type is str
|
|
603
|
+
else concat_result.to(StringVar, _var_type)
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
return LiteralStringVar(
|
|
607
|
+
_js_expr=json.dumps(value),
|
|
608
|
+
_var_type=_var_type,
|
|
609
|
+
_var_data=_var_data,
|
|
610
|
+
_var_value=value,
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
def __hash__(self) -> int:
|
|
614
|
+
"""Get the hash of the var.
|
|
615
|
+
|
|
616
|
+
Returns:
|
|
617
|
+
The hash of the var.
|
|
618
|
+
"""
|
|
619
|
+
return hash((self.__class__.__name__, self._var_value))
|
|
620
|
+
|
|
621
|
+
def json(self) -> str:
|
|
622
|
+
"""Get the JSON representation of the var.
|
|
623
|
+
|
|
624
|
+
Returns:
|
|
625
|
+
The JSON representation of the var.
|
|
626
|
+
"""
|
|
627
|
+
return json.dumps(self._var_value)
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
@dataclasses.dataclass(
|
|
631
|
+
eq=False,
|
|
632
|
+
frozen=True,
|
|
633
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
634
|
+
)
|
|
635
|
+
class ConcatVarOperation(CachedVarOperation, StringVar):
|
|
636
|
+
"""Representing a concatenation of literal string vars."""
|
|
637
|
+
|
|
638
|
+
_var_value: Tuple[Var, ...] = dataclasses.field(default_factory=tuple)
|
|
639
|
+
|
|
640
|
+
@cached_property_no_lock
|
|
641
|
+
def _cached_var_name(self) -> str:
|
|
642
|
+
"""The name of the var.
|
|
643
|
+
|
|
644
|
+
Returns:
|
|
645
|
+
The name of the var.
|
|
646
|
+
"""
|
|
647
|
+
list_of_strs: List[Union[str, Var]] = []
|
|
648
|
+
last_string = ""
|
|
649
|
+
for var in self._var_value:
|
|
650
|
+
if isinstance(var, LiteralStringVar):
|
|
651
|
+
last_string += var._var_value
|
|
652
|
+
else:
|
|
653
|
+
if last_string:
|
|
654
|
+
list_of_strs.append(last_string)
|
|
655
|
+
last_string = ""
|
|
656
|
+
list_of_strs.append(var)
|
|
657
|
+
|
|
658
|
+
if last_string:
|
|
659
|
+
list_of_strs.append(last_string)
|
|
660
|
+
|
|
661
|
+
list_of_strs_filtered = [
|
|
662
|
+
str(LiteralVar.create(s)) for s in list_of_strs if isinstance(s, Var) or s
|
|
663
|
+
]
|
|
664
|
+
|
|
665
|
+
if len(list_of_strs_filtered) == 1:
|
|
666
|
+
return list_of_strs_filtered[0]
|
|
667
|
+
|
|
668
|
+
return "(" + "+".join(list_of_strs_filtered) + ")"
|
|
669
|
+
|
|
670
|
+
@cached_property_no_lock
|
|
671
|
+
def _cached_get_all_var_data(self) -> VarData | None:
|
|
672
|
+
"""Get all the VarData asVarDatae Var.
|
|
673
|
+
|
|
674
|
+
Returns:
|
|
675
|
+
The VarData associated with the Var.
|
|
676
|
+
"""
|
|
677
|
+
return VarData.merge(
|
|
678
|
+
*[
|
|
679
|
+
var._get_all_var_data()
|
|
680
|
+
for var in self._var_value
|
|
681
|
+
if isinstance(var, Var)
|
|
682
|
+
],
|
|
683
|
+
self._var_data,
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
@classmethod
|
|
687
|
+
def create(
|
|
688
|
+
cls,
|
|
689
|
+
*value: Var | str,
|
|
690
|
+
_var_data: VarData | None = None,
|
|
691
|
+
) -> ConcatVarOperation:
|
|
692
|
+
"""Create a var from a string value.
|
|
693
|
+
|
|
694
|
+
Args:
|
|
695
|
+
value: The values to concatenate.
|
|
696
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
697
|
+
|
|
698
|
+
Returns:
|
|
699
|
+
The var.
|
|
700
|
+
"""
|
|
701
|
+
return cls(
|
|
702
|
+
_js_expr="",
|
|
703
|
+
_var_type=str,
|
|
704
|
+
_var_data=_var_data,
|
|
705
|
+
_var_value=tuple(map(LiteralVar.create, value)),
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
ARRAY_VAR_TYPE = TypeVar("ARRAY_VAR_TYPE", bound=Union[List, Tuple, Set])
|
|
710
|
+
|
|
711
|
+
OTHER_TUPLE = TypeVar("OTHER_TUPLE")
|
|
712
|
+
|
|
713
|
+
INNER_ARRAY_VAR = TypeVar("INNER_ARRAY_VAR")
|
|
714
|
+
|
|
715
|
+
KEY_TYPE = TypeVar("KEY_TYPE")
|
|
716
|
+
VALUE_TYPE = TypeVar("VALUE_TYPE")
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
class ArrayVar(Var[ARRAY_VAR_TYPE]):
|
|
720
|
+
"""Base class for immutable array vars."""
|
|
721
|
+
|
|
722
|
+
@overload
|
|
723
|
+
def join(self, sep: StringVar | str = "") -> StringVar: ...
|
|
724
|
+
|
|
725
|
+
@overload
|
|
726
|
+
def join(self, sep: NoReturn) -> NoReturn: ...
|
|
727
|
+
|
|
728
|
+
def join(self, sep: Any = "") -> StringVar:
|
|
729
|
+
"""Join the elements of the array.
|
|
730
|
+
|
|
731
|
+
Args:
|
|
732
|
+
sep: The separator between elements.
|
|
733
|
+
|
|
734
|
+
Returns:
|
|
735
|
+
The joined elements.
|
|
736
|
+
"""
|
|
737
|
+
if not isinstance(sep, (StringVar, str)):
|
|
738
|
+
raise_unsupported_operand_types("join", (type(self), type(sep)))
|
|
739
|
+
return array_join_operation(self, sep)
|
|
740
|
+
|
|
741
|
+
def reverse(self) -> ArrayVar[ARRAY_VAR_TYPE]:
|
|
742
|
+
"""Reverse the array.
|
|
743
|
+
|
|
744
|
+
Returns:
|
|
745
|
+
The reversed array.
|
|
746
|
+
"""
|
|
747
|
+
return array_reverse_operation(self)
|
|
748
|
+
|
|
749
|
+
@overload
|
|
750
|
+
def __add__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> ArrayVar[ARRAY_VAR_TYPE]: ...
|
|
751
|
+
|
|
752
|
+
@overload
|
|
753
|
+
def __add__(self, other: NoReturn) -> NoReturn: ...
|
|
754
|
+
|
|
755
|
+
def __add__(self, other: Any) -> ArrayVar[ARRAY_VAR_TYPE]:
|
|
756
|
+
"""Concatenate two arrays.
|
|
757
|
+
|
|
758
|
+
Parameters:
|
|
759
|
+
other: The other array to concatenate.
|
|
760
|
+
|
|
761
|
+
Returns:
|
|
762
|
+
ArrayConcatOperation: The concatenation of the two arrays.
|
|
763
|
+
"""
|
|
764
|
+
if not isinstance(other, ArrayVar):
|
|
765
|
+
raise_unsupported_operand_types("+", (type(self), type(other)))
|
|
766
|
+
|
|
767
|
+
return array_concat_operation(self, other)
|
|
768
|
+
|
|
769
|
+
@overload
|
|
770
|
+
def __getitem__(self, i: slice) -> ArrayVar[ARRAY_VAR_TYPE]: ...
|
|
771
|
+
|
|
772
|
+
@overload
|
|
773
|
+
def __getitem__(
|
|
774
|
+
self: (
|
|
775
|
+
ArrayVar[Tuple[int, OTHER_TUPLE]]
|
|
776
|
+
| ArrayVar[Tuple[float, OTHER_TUPLE]]
|
|
777
|
+
| ArrayVar[Tuple[int | float, OTHER_TUPLE]]
|
|
778
|
+
),
|
|
779
|
+
i: Literal[0, -2],
|
|
780
|
+
) -> NumberVar: ...
|
|
781
|
+
|
|
782
|
+
@overload
|
|
783
|
+
def __getitem__(
|
|
784
|
+
self: (
|
|
785
|
+
ArrayVar[Tuple[OTHER_TUPLE, int]]
|
|
786
|
+
| ArrayVar[Tuple[OTHER_TUPLE, float]]
|
|
787
|
+
| ArrayVar[Tuple[OTHER_TUPLE, int | float]]
|
|
788
|
+
),
|
|
789
|
+
i: Literal[1, -1],
|
|
790
|
+
) -> NumberVar: ...
|
|
791
|
+
|
|
792
|
+
@overload
|
|
793
|
+
def __getitem__(
|
|
794
|
+
self: ArrayVar[Tuple[str, OTHER_TUPLE]], i: Literal[0, -2]
|
|
795
|
+
) -> StringVar: ...
|
|
796
|
+
|
|
797
|
+
@overload
|
|
798
|
+
def __getitem__(
|
|
799
|
+
self: ArrayVar[Tuple[OTHER_TUPLE, str]], i: Literal[1, -1]
|
|
800
|
+
) -> StringVar: ...
|
|
801
|
+
|
|
802
|
+
@overload
|
|
803
|
+
def __getitem__(
|
|
804
|
+
self: ArrayVar[Tuple[bool, OTHER_TUPLE]], i: Literal[0, -2]
|
|
805
|
+
) -> BooleanVar: ...
|
|
806
|
+
|
|
807
|
+
@overload
|
|
808
|
+
def __getitem__(
|
|
809
|
+
self: ArrayVar[Tuple[OTHER_TUPLE, bool]], i: Literal[1, -1]
|
|
810
|
+
) -> BooleanVar: ...
|
|
811
|
+
|
|
812
|
+
@overload
|
|
813
|
+
def __getitem__(
|
|
814
|
+
self: (
|
|
815
|
+
ARRAY_VAR_OF_LIST_ELEMENT[int]
|
|
816
|
+
| ARRAY_VAR_OF_LIST_ELEMENT[float]
|
|
817
|
+
| ARRAY_VAR_OF_LIST_ELEMENT[int | float]
|
|
818
|
+
),
|
|
819
|
+
i: int | NumberVar,
|
|
820
|
+
) -> NumberVar: ...
|
|
821
|
+
|
|
822
|
+
@overload
|
|
823
|
+
def __getitem__(
|
|
824
|
+
self: ARRAY_VAR_OF_LIST_ELEMENT[str], i: int | NumberVar
|
|
825
|
+
) -> StringVar: ...
|
|
826
|
+
|
|
827
|
+
@overload
|
|
828
|
+
def __getitem__(
|
|
829
|
+
self: ARRAY_VAR_OF_LIST_ELEMENT[bool], i: int | NumberVar
|
|
830
|
+
) -> BooleanVar: ...
|
|
831
|
+
|
|
832
|
+
@overload
|
|
833
|
+
def __getitem__(
|
|
834
|
+
self: ARRAY_VAR_OF_LIST_ELEMENT[List[INNER_ARRAY_VAR]],
|
|
835
|
+
i: int | NumberVar,
|
|
836
|
+
) -> ArrayVar[List[INNER_ARRAY_VAR]]: ...
|
|
837
|
+
|
|
838
|
+
@overload
|
|
839
|
+
def __getitem__(
|
|
840
|
+
self: ARRAY_VAR_OF_LIST_ELEMENT[Set[INNER_ARRAY_VAR]],
|
|
841
|
+
i: int | NumberVar,
|
|
842
|
+
) -> ArrayVar[Set[INNER_ARRAY_VAR]]: ...
|
|
843
|
+
|
|
844
|
+
@overload
|
|
845
|
+
def __getitem__(
|
|
846
|
+
self: ARRAY_VAR_OF_LIST_ELEMENT[Tuple[INNER_ARRAY_VAR, ...]],
|
|
847
|
+
i: int | NumberVar,
|
|
848
|
+
) -> ArrayVar[Tuple[INNER_ARRAY_VAR, ...]]: ...
|
|
849
|
+
|
|
850
|
+
@overload
|
|
851
|
+
def __getitem__(
|
|
852
|
+
self: ARRAY_VAR_OF_LIST_ELEMENT[Dict[KEY_TYPE, VALUE_TYPE]],
|
|
853
|
+
i: int | NumberVar,
|
|
854
|
+
) -> ObjectVar[Dict[KEY_TYPE, VALUE_TYPE]]: ...
|
|
855
|
+
|
|
856
|
+
@overload
|
|
857
|
+
def __getitem__(self, i: int | NumberVar) -> Var: ...
|
|
858
|
+
|
|
859
|
+
def __getitem__(self, i: Any) -> ArrayVar[ARRAY_VAR_TYPE] | Var:
|
|
860
|
+
"""Get a slice of the array.
|
|
861
|
+
|
|
862
|
+
Args:
|
|
863
|
+
i: The slice.
|
|
864
|
+
|
|
865
|
+
Returns:
|
|
866
|
+
The array slice operation.
|
|
867
|
+
"""
|
|
868
|
+
if isinstance(i, slice):
|
|
869
|
+
return ArraySliceOperation.create(self, i)
|
|
870
|
+
if not isinstance(i, (int, NumberVar)) or (
|
|
871
|
+
isinstance(i, NumberVar) and i._is_strict_float()
|
|
872
|
+
):
|
|
873
|
+
raise_unsupported_operand_types("[]", (type(self), type(i)))
|
|
874
|
+
return array_item_operation(self, i)
|
|
875
|
+
|
|
876
|
+
def length(self) -> NumberVar:
|
|
877
|
+
"""Get the length of the array.
|
|
878
|
+
|
|
879
|
+
Returns:
|
|
880
|
+
The length of the array.
|
|
881
|
+
"""
|
|
882
|
+
return array_length_operation(self)
|
|
883
|
+
|
|
884
|
+
@overload
|
|
885
|
+
@classmethod
|
|
886
|
+
def range(cls, stop: int | NumberVar, /) -> ArrayVar[List[int]]: ...
|
|
887
|
+
|
|
888
|
+
@overload
|
|
889
|
+
@classmethod
|
|
890
|
+
def range(
|
|
891
|
+
cls,
|
|
892
|
+
start: int | NumberVar,
|
|
893
|
+
end: int | NumberVar,
|
|
894
|
+
step: int | NumberVar = 1,
|
|
895
|
+
/,
|
|
896
|
+
) -> ArrayVar[List[int]]: ...
|
|
897
|
+
|
|
898
|
+
@overload
|
|
899
|
+
@classmethod
|
|
900
|
+
def range(
|
|
901
|
+
cls,
|
|
902
|
+
first_endpoint: int | NumberVar,
|
|
903
|
+
second_endpoint: int | NumberVar | None = None,
|
|
904
|
+
step: int | NumberVar | None = None,
|
|
905
|
+
) -> ArrayVar[List[int]]: ...
|
|
906
|
+
|
|
907
|
+
@classmethod
|
|
908
|
+
def range(
|
|
909
|
+
cls,
|
|
910
|
+
first_endpoint: int | NumberVar,
|
|
911
|
+
second_endpoint: int | NumberVar | None = None,
|
|
912
|
+
step: int | NumberVar | None = None,
|
|
913
|
+
) -> ArrayVar[List[int]]:
|
|
914
|
+
"""Create a range of numbers.
|
|
915
|
+
|
|
916
|
+
Args:
|
|
917
|
+
first_endpoint: The end of the range if second_endpoint is not provided, otherwise the start of the range.
|
|
918
|
+
second_endpoint: The end of the range.
|
|
919
|
+
step: The step of the range.
|
|
920
|
+
|
|
921
|
+
Returns:
|
|
922
|
+
The range of numbers.
|
|
923
|
+
"""
|
|
924
|
+
if any(
|
|
925
|
+
not isinstance(i, (int, NumberVar))
|
|
926
|
+
for i in (first_endpoint, second_endpoint, step)
|
|
927
|
+
if i is not None
|
|
928
|
+
):
|
|
929
|
+
raise_unsupported_operand_types(
|
|
930
|
+
"range", (type(first_endpoint), type(second_endpoint), type(step))
|
|
931
|
+
)
|
|
932
|
+
if second_endpoint is None:
|
|
933
|
+
start = 0
|
|
934
|
+
end = first_endpoint
|
|
935
|
+
else:
|
|
936
|
+
start = first_endpoint
|
|
937
|
+
end = second_endpoint
|
|
938
|
+
|
|
939
|
+
return array_range_operation(start, end, step or 1)
|
|
940
|
+
|
|
941
|
+
@overload
|
|
942
|
+
def contains(self, other: Any) -> BooleanVar: ...
|
|
943
|
+
|
|
944
|
+
@overload
|
|
945
|
+
def contains(self, other: Any, field: StringVar | str) -> BooleanVar: ...
|
|
946
|
+
|
|
947
|
+
def contains(self, other: Any, field: Any = None) -> BooleanVar:
|
|
948
|
+
"""Check if the array contains an element.
|
|
949
|
+
|
|
950
|
+
Args:
|
|
951
|
+
other: The element to check for.
|
|
952
|
+
field: The field to check.
|
|
953
|
+
|
|
954
|
+
Returns:
|
|
955
|
+
The array contains operation.
|
|
956
|
+
"""
|
|
957
|
+
if field is not None:
|
|
958
|
+
if not isinstance(field, (StringVar, str)):
|
|
959
|
+
raise_unsupported_operand_types("contains", (type(self), type(field)))
|
|
960
|
+
return array_contains_field_operation(self, other, field)
|
|
961
|
+
return array_contains_operation(self, other)
|
|
962
|
+
|
|
963
|
+
def pluck(self, field: StringVar | str) -> ArrayVar:
|
|
964
|
+
"""Pluck a field from the array.
|
|
965
|
+
|
|
966
|
+
Args:
|
|
967
|
+
field: The field to pluck from the array.
|
|
968
|
+
|
|
969
|
+
Returns:
|
|
970
|
+
The array pluck operation.
|
|
971
|
+
"""
|
|
972
|
+
return array_pluck_operation(self, field)
|
|
973
|
+
|
|
974
|
+
@overload
|
|
975
|
+
def __mul__(self, other: NumberVar | int) -> ArrayVar[ARRAY_VAR_TYPE]: ...
|
|
976
|
+
|
|
977
|
+
@overload
|
|
978
|
+
def __mul__(self, other: NoReturn) -> NoReturn: ...
|
|
979
|
+
|
|
980
|
+
def __mul__(self, other: Any) -> ArrayVar[ARRAY_VAR_TYPE]:
|
|
981
|
+
"""Multiply the sequence by a number or integer.
|
|
982
|
+
|
|
983
|
+
Parameters:
|
|
984
|
+
other: The number or integer to multiply the sequence by.
|
|
985
|
+
|
|
986
|
+
Returns:
|
|
987
|
+
ArrayVar[ARRAY_VAR_TYPE]: The result of multiplying the sequence by the given number or integer.
|
|
988
|
+
"""
|
|
989
|
+
if not isinstance(other, (NumberVar, int)) or (
|
|
990
|
+
isinstance(other, NumberVar) and other._is_strict_float()
|
|
991
|
+
):
|
|
992
|
+
raise_unsupported_operand_types("*", (type(self), type(other)))
|
|
993
|
+
|
|
994
|
+
return repeat_array_operation(self, other)
|
|
995
|
+
|
|
996
|
+
__rmul__ = __mul__ # type: ignore
|
|
997
|
+
|
|
998
|
+
@overload
|
|
999
|
+
def __lt__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> BooleanVar: ...
|
|
1000
|
+
|
|
1001
|
+
@overload
|
|
1002
|
+
def __lt__(self, other: list | tuple) -> BooleanVar: ...
|
|
1003
|
+
|
|
1004
|
+
def __lt__(self, other: Any):
|
|
1005
|
+
"""Check if the array is less than another array.
|
|
1006
|
+
|
|
1007
|
+
Args:
|
|
1008
|
+
other: The other array.
|
|
1009
|
+
|
|
1010
|
+
Returns:
|
|
1011
|
+
The array less than operation.
|
|
1012
|
+
"""
|
|
1013
|
+
if not isinstance(other, (ArrayVar, list, tuple)):
|
|
1014
|
+
raise_unsupported_operand_types("<", (type(self), type(other)))
|
|
1015
|
+
|
|
1016
|
+
return array_lt_operation(self, other)
|
|
1017
|
+
|
|
1018
|
+
@overload
|
|
1019
|
+
def __gt__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> BooleanVar: ...
|
|
1020
|
+
|
|
1021
|
+
@overload
|
|
1022
|
+
def __gt__(self, other: list | tuple) -> BooleanVar: ...
|
|
1023
|
+
|
|
1024
|
+
def __gt__(self, other: Any):
|
|
1025
|
+
"""Check if the array is greater than another array.
|
|
1026
|
+
|
|
1027
|
+
Args:
|
|
1028
|
+
other: The other array.
|
|
1029
|
+
|
|
1030
|
+
Returns:
|
|
1031
|
+
The array greater than operation.
|
|
1032
|
+
"""
|
|
1033
|
+
if not isinstance(other, (ArrayVar, list, tuple)):
|
|
1034
|
+
raise_unsupported_operand_types(">", (type(self), type(other)))
|
|
1035
|
+
|
|
1036
|
+
return array_gt_operation(self, other)
|
|
1037
|
+
|
|
1038
|
+
@overload
|
|
1039
|
+
def __le__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> BooleanVar: ...
|
|
1040
|
+
|
|
1041
|
+
@overload
|
|
1042
|
+
def __le__(self, other: list | tuple) -> BooleanVar: ...
|
|
1043
|
+
|
|
1044
|
+
def __le__(self, other: Any):
|
|
1045
|
+
"""Check if the array is less than or equal to another array.
|
|
1046
|
+
|
|
1047
|
+
Args:
|
|
1048
|
+
other: The other array.
|
|
1049
|
+
|
|
1050
|
+
Returns:
|
|
1051
|
+
The array less than or equal operation.
|
|
1052
|
+
"""
|
|
1053
|
+
if not isinstance(other, (ArrayVar, list, tuple)):
|
|
1054
|
+
raise_unsupported_operand_types("<=", (type(self), type(other)))
|
|
1055
|
+
|
|
1056
|
+
return array_le_operation(self, other)
|
|
1057
|
+
|
|
1058
|
+
@overload
|
|
1059
|
+
def __ge__(self, other: ArrayVar[ARRAY_VAR_TYPE]) -> BooleanVar: ...
|
|
1060
|
+
|
|
1061
|
+
@overload
|
|
1062
|
+
def __ge__(self, other: list | tuple) -> BooleanVar: ...
|
|
1063
|
+
|
|
1064
|
+
def __ge__(self, other: Any):
|
|
1065
|
+
"""Check if the array is greater than or equal to another array.
|
|
1066
|
+
|
|
1067
|
+
Args:
|
|
1068
|
+
other: The other array.
|
|
1069
|
+
|
|
1070
|
+
Returns:
|
|
1071
|
+
The array greater than or equal operation.
|
|
1072
|
+
"""
|
|
1073
|
+
if not isinstance(other, (ArrayVar, list, tuple)):
|
|
1074
|
+
raise_unsupported_operand_types(">=", (type(self), type(other)))
|
|
1075
|
+
|
|
1076
|
+
return array_ge_operation(self, other)
|
|
1077
|
+
|
|
1078
|
+
def foreach(self, fn: Any):
|
|
1079
|
+
"""Apply a function to each element of the array.
|
|
1080
|
+
|
|
1081
|
+
Args:
|
|
1082
|
+
fn: The function to apply.
|
|
1083
|
+
|
|
1084
|
+
Returns:
|
|
1085
|
+
The array after applying the function.
|
|
1086
|
+
|
|
1087
|
+
Raises:
|
|
1088
|
+
VarTypeError: If the function takes more than one argument.
|
|
1089
|
+
"""
|
|
1090
|
+
from .function import ArgsFunctionOperation
|
|
1091
|
+
|
|
1092
|
+
if not callable(fn):
|
|
1093
|
+
raise_unsupported_operand_types("foreach", (type(self), type(fn)))
|
|
1094
|
+
# get the number of arguments of the function
|
|
1095
|
+
num_args = len(inspect.signature(fn).parameters)
|
|
1096
|
+
if num_args > 1:
|
|
1097
|
+
raise VarTypeError(
|
|
1098
|
+
"The function passed to foreach should take at most one argument."
|
|
1099
|
+
)
|
|
1100
|
+
|
|
1101
|
+
if num_args == 0:
|
|
1102
|
+
return_value = fn()
|
|
1103
|
+
function_var = ArgsFunctionOperation.create(tuple(), return_value)
|
|
1104
|
+
else:
|
|
1105
|
+
# generic number var
|
|
1106
|
+
number_var = Var("").to(NumberVar)
|
|
1107
|
+
|
|
1108
|
+
first_arg_type = self[number_var]._var_type
|
|
1109
|
+
|
|
1110
|
+
arg_name = get_unique_variable_name()
|
|
1111
|
+
|
|
1112
|
+
# get first argument type
|
|
1113
|
+
first_arg = Var(
|
|
1114
|
+
_js_expr=arg_name,
|
|
1115
|
+
_var_type=first_arg_type,
|
|
1116
|
+
).guess_type()
|
|
1117
|
+
|
|
1118
|
+
function_var = ArgsFunctionOperation.create((arg_name,), fn(first_arg))
|
|
1119
|
+
|
|
1120
|
+
return map_array_operation(self, function_var)
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
LIST_ELEMENT = TypeVar("LIST_ELEMENT")
|
|
1124
|
+
|
|
1125
|
+
ARRAY_VAR_OF_LIST_ELEMENT = Union[
|
|
1126
|
+
ArrayVar[List[LIST_ELEMENT]],
|
|
1127
|
+
ArrayVar[Set[LIST_ELEMENT]],
|
|
1128
|
+
ArrayVar[Tuple[LIST_ELEMENT, ...]],
|
|
1129
|
+
]
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
@dataclasses.dataclass(
|
|
1133
|
+
eq=False,
|
|
1134
|
+
frozen=True,
|
|
1135
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1136
|
+
)
|
|
1137
|
+
class LiteralArrayVar(CachedVarOperation, LiteralVar, ArrayVar[ARRAY_VAR_TYPE]):
|
|
1138
|
+
"""Base class for immutable literal array vars."""
|
|
1139
|
+
|
|
1140
|
+
_var_value: Union[
|
|
1141
|
+
List[Union[Var, Any]],
|
|
1142
|
+
Set[Union[Var, Any]],
|
|
1143
|
+
Tuple[Union[Var, Any], ...],
|
|
1144
|
+
] = dataclasses.field(default_factory=list)
|
|
1145
|
+
|
|
1146
|
+
@cached_property_no_lock
|
|
1147
|
+
def _cached_var_name(self) -> str:
|
|
1148
|
+
"""The name of the var.
|
|
1149
|
+
|
|
1150
|
+
Returns:
|
|
1151
|
+
The name of the var.
|
|
1152
|
+
"""
|
|
1153
|
+
return (
|
|
1154
|
+
"["
|
|
1155
|
+
+ ", ".join(
|
|
1156
|
+
[str(LiteralVar.create(element)) for element in self._var_value]
|
|
1157
|
+
)
|
|
1158
|
+
+ "]"
|
|
1159
|
+
)
|
|
1160
|
+
|
|
1161
|
+
@cached_property_no_lock
|
|
1162
|
+
def _cached_get_all_var_data(self) -> VarData | None:
|
|
1163
|
+
"""Get all the VarData associated with the Var.
|
|
1164
|
+
|
|
1165
|
+
Returns:
|
|
1166
|
+
The VarData associated with the Var.
|
|
1167
|
+
"""
|
|
1168
|
+
return VarData.merge(
|
|
1169
|
+
*[
|
|
1170
|
+
LiteralVar.create(element)._get_all_var_data()
|
|
1171
|
+
for element in self._var_value
|
|
1172
|
+
],
|
|
1173
|
+
self._var_data,
|
|
1174
|
+
)
|
|
1175
|
+
|
|
1176
|
+
def __hash__(self) -> int:
|
|
1177
|
+
"""Get the hash of the var.
|
|
1178
|
+
|
|
1179
|
+
Returns:
|
|
1180
|
+
The hash of the var.
|
|
1181
|
+
"""
|
|
1182
|
+
return hash((self.__class__.__name__, self._js_expr))
|
|
1183
|
+
|
|
1184
|
+
def json(self) -> str:
|
|
1185
|
+
"""Get the JSON representation of the var.
|
|
1186
|
+
|
|
1187
|
+
Returns:
|
|
1188
|
+
The JSON representation of the var.
|
|
1189
|
+
"""
|
|
1190
|
+
return (
|
|
1191
|
+
"["
|
|
1192
|
+
+ ", ".join(
|
|
1193
|
+
[LiteralVar.create(element).json() for element in self._var_value]
|
|
1194
|
+
)
|
|
1195
|
+
+ "]"
|
|
1196
|
+
)
|
|
1197
|
+
|
|
1198
|
+
@classmethod
|
|
1199
|
+
def create(
|
|
1200
|
+
cls,
|
|
1201
|
+
value: ARRAY_VAR_TYPE,
|
|
1202
|
+
_var_type: Type[ARRAY_VAR_TYPE] | None = None,
|
|
1203
|
+
_var_data: VarData | None = None,
|
|
1204
|
+
) -> LiteralArrayVar[ARRAY_VAR_TYPE]:
|
|
1205
|
+
"""Create a var from a string value.
|
|
1206
|
+
|
|
1207
|
+
Args:
|
|
1208
|
+
value: The value to create the var from.
|
|
1209
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
1210
|
+
|
|
1211
|
+
Returns:
|
|
1212
|
+
The var.
|
|
1213
|
+
"""
|
|
1214
|
+
return cls(
|
|
1215
|
+
_js_expr="",
|
|
1216
|
+
_var_type=figure_out_type(value) if _var_type is None else _var_type,
|
|
1217
|
+
_var_data=_var_data,
|
|
1218
|
+
_var_value=value,
|
|
1219
|
+
)
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
@var_operation
|
|
1223
|
+
def string_split_operation(string: StringVar, sep: StringVar | str = ""):
|
|
1224
|
+
"""Split a string.
|
|
1225
|
+
|
|
1226
|
+
Args:
|
|
1227
|
+
string: The string to split.
|
|
1228
|
+
sep: The separator.
|
|
1229
|
+
|
|
1230
|
+
Returns:
|
|
1231
|
+
The split string.
|
|
1232
|
+
"""
|
|
1233
|
+
return var_operation_return(
|
|
1234
|
+
js_expression=f"{string}.split({sep})", var_type=List[str]
|
|
1235
|
+
)
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
@dataclasses.dataclass(
|
|
1239
|
+
eq=False,
|
|
1240
|
+
frozen=True,
|
|
1241
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1242
|
+
)
|
|
1243
|
+
class ArraySliceOperation(CachedVarOperation, ArrayVar):
|
|
1244
|
+
"""Base class for immutable string vars that are the result of a string slice operation."""
|
|
1245
|
+
|
|
1246
|
+
_array: ArrayVar = dataclasses.field(
|
|
1247
|
+
default_factory=lambda: LiteralArrayVar.create([])
|
|
1248
|
+
)
|
|
1249
|
+
_start: NumberVar | int = dataclasses.field(default_factory=lambda: 0)
|
|
1250
|
+
_stop: NumberVar | int = dataclasses.field(default_factory=lambda: 0)
|
|
1251
|
+
_step: NumberVar | int = dataclasses.field(default_factory=lambda: 1)
|
|
1252
|
+
|
|
1253
|
+
@cached_property_no_lock
|
|
1254
|
+
def _cached_var_name(self) -> str:
|
|
1255
|
+
"""The name of the var.
|
|
1256
|
+
|
|
1257
|
+
Returns:
|
|
1258
|
+
The name of the var.
|
|
1259
|
+
|
|
1260
|
+
Raises:
|
|
1261
|
+
ValueError: If the slice step is zero.
|
|
1262
|
+
"""
|
|
1263
|
+
start, end, step = self._start, self._stop, self._step
|
|
1264
|
+
|
|
1265
|
+
normalized_start = (
|
|
1266
|
+
LiteralVar.create(start) if start is not None else Var(_js_expr="undefined")
|
|
1267
|
+
)
|
|
1268
|
+
normalized_end = (
|
|
1269
|
+
LiteralVar.create(end) if end is not None else Var(_js_expr="undefined")
|
|
1270
|
+
)
|
|
1271
|
+
if step is None:
|
|
1272
|
+
return f"{str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)})"
|
|
1273
|
+
if not isinstance(step, Var):
|
|
1274
|
+
if step < 0:
|
|
1275
|
+
actual_start = end + 1 if end is not None else 0
|
|
1276
|
+
actual_end = start + 1 if start is not None else self._array.length()
|
|
1277
|
+
return str(self._array[actual_start:actual_end].reverse()[::-step])
|
|
1278
|
+
if step == 0:
|
|
1279
|
+
raise ValueError("slice step cannot be zero")
|
|
1280
|
+
return f"{str(self._array)}.slice({str(normalized_start)}, {str(normalized_end)}).filter((_, i) => i % {str(step)} === 0)"
|
|
1281
|
+
|
|
1282
|
+
actual_start_reverse = end + 1 if end is not None else 0
|
|
1283
|
+
actual_end_reverse = start + 1 if start is not None else self._array.length()
|
|
1284
|
+
|
|
1285
|
+
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)"
|
|
1286
|
+
|
|
1287
|
+
@classmethod
|
|
1288
|
+
def create(
|
|
1289
|
+
cls,
|
|
1290
|
+
array: ArrayVar,
|
|
1291
|
+
slice: slice,
|
|
1292
|
+
_var_data: VarData | None = None,
|
|
1293
|
+
) -> ArraySliceOperation:
|
|
1294
|
+
"""Create a var from a string value.
|
|
1295
|
+
|
|
1296
|
+
Args:
|
|
1297
|
+
array: The array.
|
|
1298
|
+
slice: The slice.
|
|
1299
|
+
_var_data: Additional hooks and imports associated with the Var.
|
|
1300
|
+
|
|
1301
|
+
Returns:
|
|
1302
|
+
The var.
|
|
1303
|
+
"""
|
|
1304
|
+
return cls(
|
|
1305
|
+
_js_expr="",
|
|
1306
|
+
_var_type=array._var_type,
|
|
1307
|
+
_var_data=_var_data,
|
|
1308
|
+
_array=array,
|
|
1309
|
+
_start=slice.start,
|
|
1310
|
+
_stop=slice.stop,
|
|
1311
|
+
_step=slice.step,
|
|
1312
|
+
)
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
@var_operation
|
|
1316
|
+
def array_pluck_operation(
|
|
1317
|
+
array: ArrayVar[ARRAY_VAR_TYPE],
|
|
1318
|
+
field: StringVar | str,
|
|
1319
|
+
) -> CustomVarOperationReturn[ARRAY_VAR_TYPE]:
|
|
1320
|
+
"""Pluck a field from an array of objects.
|
|
1321
|
+
|
|
1322
|
+
Args:
|
|
1323
|
+
array: The array to pluck from.
|
|
1324
|
+
field: The field to pluck from the objects in the array.
|
|
1325
|
+
|
|
1326
|
+
Returns:
|
|
1327
|
+
The reversed array.
|
|
1328
|
+
"""
|
|
1329
|
+
return var_operation_return(
|
|
1330
|
+
js_expression=f"{array}.map(e=>e?.[{field}])",
|
|
1331
|
+
var_type=array._var_type,
|
|
1332
|
+
)
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
@var_operation
|
|
1336
|
+
def array_reverse_operation(
|
|
1337
|
+
array: ArrayVar[ARRAY_VAR_TYPE],
|
|
1338
|
+
) -> CustomVarOperationReturn[ARRAY_VAR_TYPE]:
|
|
1339
|
+
"""Reverse an array.
|
|
1340
|
+
|
|
1341
|
+
Args:
|
|
1342
|
+
array: The array to reverse.
|
|
1343
|
+
|
|
1344
|
+
Returns:
|
|
1345
|
+
The reversed array.
|
|
1346
|
+
"""
|
|
1347
|
+
return var_operation_return(
|
|
1348
|
+
js_expression=f"{array}.slice().reverse()",
|
|
1349
|
+
var_type=array._var_type,
|
|
1350
|
+
)
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
@var_operation
|
|
1354
|
+
def array_lt_operation(lhs: ArrayVar | list | tuple, rhs: ArrayVar | list | tuple):
|
|
1355
|
+
"""Check if an array is less than another array.
|
|
1356
|
+
|
|
1357
|
+
Args:
|
|
1358
|
+
lhs: The left-hand side array.
|
|
1359
|
+
rhs: The right-hand side array.
|
|
1360
|
+
|
|
1361
|
+
Returns:
|
|
1362
|
+
The array less than operation.
|
|
1363
|
+
"""
|
|
1364
|
+
return var_operation_return(js_expression=f"{lhs} < {rhs}", var_type=bool)
|
|
1365
|
+
|
|
1366
|
+
|
|
1367
|
+
@var_operation
|
|
1368
|
+
def array_gt_operation(lhs: ArrayVar | list | tuple, rhs: ArrayVar | list | tuple):
|
|
1369
|
+
"""Check if an array is greater than another array.
|
|
1370
|
+
|
|
1371
|
+
Args:
|
|
1372
|
+
lhs: The left-hand side array.
|
|
1373
|
+
rhs: The right-hand side array.
|
|
1374
|
+
|
|
1375
|
+
Returns:
|
|
1376
|
+
The array greater than operation.
|
|
1377
|
+
"""
|
|
1378
|
+
return var_operation_return(js_expression=f"{lhs} > {rhs}", var_type=bool)
|
|
1379
|
+
|
|
1380
|
+
|
|
1381
|
+
@var_operation
|
|
1382
|
+
def array_le_operation(lhs: ArrayVar | list | tuple, rhs: ArrayVar | list | tuple):
|
|
1383
|
+
"""Check if an array is less than or equal to another array.
|
|
1384
|
+
|
|
1385
|
+
Args:
|
|
1386
|
+
lhs: The left-hand side array.
|
|
1387
|
+
rhs: The right-hand side array.
|
|
1388
|
+
|
|
1389
|
+
Returns:
|
|
1390
|
+
The array less than or equal operation.
|
|
1391
|
+
"""
|
|
1392
|
+
return var_operation_return(js_expression=f"{lhs} <= {rhs}", var_type=bool)
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
@var_operation
|
|
1396
|
+
def array_ge_operation(lhs: ArrayVar | list | tuple, rhs: ArrayVar | list | tuple):
|
|
1397
|
+
"""Check if an array is greater than or equal to another array.
|
|
1398
|
+
|
|
1399
|
+
Args:
|
|
1400
|
+
lhs: The left-hand side array.
|
|
1401
|
+
rhs: The right-hand side array.
|
|
1402
|
+
|
|
1403
|
+
Returns:
|
|
1404
|
+
The array greater than or equal operation.
|
|
1405
|
+
"""
|
|
1406
|
+
return var_operation_return(js_expression=f"{lhs} >= {rhs}", var_type=bool)
|
|
1407
|
+
|
|
1408
|
+
|
|
1409
|
+
@var_operation
|
|
1410
|
+
def array_length_operation(array: ArrayVar):
|
|
1411
|
+
"""Get the length of an array.
|
|
1412
|
+
|
|
1413
|
+
Args:
|
|
1414
|
+
array: The array.
|
|
1415
|
+
|
|
1416
|
+
Returns:
|
|
1417
|
+
The length of the array.
|
|
1418
|
+
"""
|
|
1419
|
+
return var_operation_return(
|
|
1420
|
+
js_expression=f"{array}.length",
|
|
1421
|
+
var_type=int,
|
|
1422
|
+
)
|
|
1423
|
+
|
|
1424
|
+
|
|
1425
|
+
def is_tuple_type(t: GenericType) -> bool:
|
|
1426
|
+
"""Check if a type is a tuple type.
|
|
1427
|
+
|
|
1428
|
+
Args:
|
|
1429
|
+
t: The type to check.
|
|
1430
|
+
|
|
1431
|
+
Returns:
|
|
1432
|
+
Whether the type is a tuple type.
|
|
1433
|
+
"""
|
|
1434
|
+
if inspect.isclass(t):
|
|
1435
|
+
return issubclass(t, tuple)
|
|
1436
|
+
return get_origin(t) is tuple
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
@var_operation
|
|
1440
|
+
def array_item_operation(array: ArrayVar, index: NumberVar | int):
|
|
1441
|
+
"""Get an item from an array.
|
|
1442
|
+
|
|
1443
|
+
Args:
|
|
1444
|
+
array: The array.
|
|
1445
|
+
index: The index of the item.
|
|
1446
|
+
|
|
1447
|
+
Returns:
|
|
1448
|
+
The item from the array.
|
|
1449
|
+
"""
|
|
1450
|
+
args = typing.get_args(array._var_type)
|
|
1451
|
+
if args and isinstance(index, LiteralNumberVar) and is_tuple_type(array._var_type):
|
|
1452
|
+
index_value = int(index._var_value)
|
|
1453
|
+
element_type = args[index_value % len(args)]
|
|
1454
|
+
else:
|
|
1455
|
+
element_type = unionize(*args)
|
|
1456
|
+
|
|
1457
|
+
return var_operation_return(
|
|
1458
|
+
js_expression=f"{str(array)}.at({str(index)})",
|
|
1459
|
+
var_type=element_type,
|
|
1460
|
+
)
|
|
1461
|
+
|
|
1462
|
+
|
|
1463
|
+
@var_operation
|
|
1464
|
+
def array_range_operation(
|
|
1465
|
+
start: NumberVar | int, stop: NumberVar | int, step: NumberVar | int
|
|
1466
|
+
):
|
|
1467
|
+
"""Create a range of numbers.
|
|
1468
|
+
|
|
1469
|
+
Args:
|
|
1470
|
+
start: The start of the range.
|
|
1471
|
+
stop: The end of the range.
|
|
1472
|
+
step: The step of the range.
|
|
1473
|
+
|
|
1474
|
+
Returns:
|
|
1475
|
+
The range of numbers.
|
|
1476
|
+
"""
|
|
1477
|
+
return var_operation_return(
|
|
1478
|
+
js_expression=f"Array.from({{ length: ({str(stop)} - {str(start)}) / {str(step)} }}, (_, i) => {str(start)} + i * {str(step)})",
|
|
1479
|
+
var_type=List[int],
|
|
1480
|
+
)
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
@var_operation
|
|
1484
|
+
def array_contains_field_operation(
|
|
1485
|
+
haystack: ArrayVar, needle: Any | Var, field: StringVar | str
|
|
1486
|
+
):
|
|
1487
|
+
"""Check if an array contains an element.
|
|
1488
|
+
|
|
1489
|
+
Args:
|
|
1490
|
+
haystack: The array to check.
|
|
1491
|
+
needle: The element to check for.
|
|
1492
|
+
field: The field to check.
|
|
1493
|
+
|
|
1494
|
+
Returns:
|
|
1495
|
+
The array contains operation.
|
|
1496
|
+
"""
|
|
1497
|
+
return var_operation_return(
|
|
1498
|
+
js_expression=f"{haystack}.some(obj => obj[{field}] === {needle})",
|
|
1499
|
+
var_type=bool,
|
|
1500
|
+
)
|
|
1501
|
+
|
|
1502
|
+
|
|
1503
|
+
@var_operation
|
|
1504
|
+
def array_contains_operation(haystack: ArrayVar, needle: Any | Var):
|
|
1505
|
+
"""Check if an array contains an element.
|
|
1506
|
+
|
|
1507
|
+
Args:
|
|
1508
|
+
haystack: The array to check.
|
|
1509
|
+
needle: The element to check for.
|
|
1510
|
+
|
|
1511
|
+
Returns:
|
|
1512
|
+
The array contains operation.
|
|
1513
|
+
"""
|
|
1514
|
+
return var_operation_return(
|
|
1515
|
+
js_expression=f"{haystack}.includes({needle})",
|
|
1516
|
+
var_type=bool,
|
|
1517
|
+
)
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
@dataclasses.dataclass(
|
|
1521
|
+
eq=False,
|
|
1522
|
+
frozen=True,
|
|
1523
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1524
|
+
)
|
|
1525
|
+
class ToStringOperation(ToOperation, StringVar):
|
|
1526
|
+
"""Base class for immutable string vars that are the result of a to string operation."""
|
|
1527
|
+
|
|
1528
|
+
_original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
|
|
1529
|
+
|
|
1530
|
+
_default_var_type: ClassVar[Type] = str
|
|
1531
|
+
|
|
1532
|
+
|
|
1533
|
+
@dataclasses.dataclass(
|
|
1534
|
+
eq=False,
|
|
1535
|
+
frozen=True,
|
|
1536
|
+
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1537
|
+
)
|
|
1538
|
+
class ToArrayOperation(ToOperation, ArrayVar):
|
|
1539
|
+
"""Base class for immutable array vars that are the result of a to array operation."""
|
|
1540
|
+
|
|
1541
|
+
_original: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
|
|
1542
|
+
|
|
1543
|
+
_default_var_type: ClassVar[Type] = List[Any]
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
@var_operation
|
|
1547
|
+
def repeat_array_operation(
|
|
1548
|
+
array: ArrayVar[ARRAY_VAR_TYPE], count: NumberVar | int
|
|
1549
|
+
) -> CustomVarOperationReturn[ARRAY_VAR_TYPE]:
|
|
1550
|
+
"""Repeat an array a number of times.
|
|
1551
|
+
|
|
1552
|
+
Args:
|
|
1553
|
+
array: The array to repeat.
|
|
1554
|
+
count: The number of times to repeat the array.
|
|
1555
|
+
|
|
1556
|
+
Returns:
|
|
1557
|
+
The repeated array.
|
|
1558
|
+
"""
|
|
1559
|
+
return var_operation_return(
|
|
1560
|
+
js_expression=f"Array.from({{ length: {count} }}).flatMap(() => {array})",
|
|
1561
|
+
var_type=array._var_type,
|
|
1562
|
+
)
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
if TYPE_CHECKING:
|
|
1566
|
+
from .function import FunctionVar
|
|
1567
|
+
|
|
1568
|
+
|
|
1569
|
+
@var_operation
|
|
1570
|
+
def map_array_operation(
|
|
1571
|
+
array: ArrayVar[ARRAY_VAR_TYPE],
|
|
1572
|
+
function: FunctionVar,
|
|
1573
|
+
):
|
|
1574
|
+
"""Map a function over an array.
|
|
1575
|
+
|
|
1576
|
+
Args:
|
|
1577
|
+
array: The array.
|
|
1578
|
+
function: The function to map.
|
|
1579
|
+
|
|
1580
|
+
Returns:
|
|
1581
|
+
The mapped array.
|
|
1582
|
+
"""
|
|
1583
|
+
return var_operation_return(
|
|
1584
|
+
js_expression=f"{array}.map({function})", var_type=List[Any]
|
|
1585
|
+
)
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
@var_operation
|
|
1589
|
+
def array_concat_operation(
|
|
1590
|
+
lhs: ArrayVar[ARRAY_VAR_TYPE], rhs: ArrayVar[ARRAY_VAR_TYPE]
|
|
1591
|
+
) -> CustomVarOperationReturn[ARRAY_VAR_TYPE]:
|
|
1592
|
+
"""Concatenate two arrays.
|
|
1593
|
+
|
|
1594
|
+
Args:
|
|
1595
|
+
lhs: The left-hand side array.
|
|
1596
|
+
rhs: The right-hand side array.
|
|
1597
|
+
|
|
1598
|
+
Returns:
|
|
1599
|
+
The concatenated array.
|
|
1600
|
+
"""
|
|
1601
|
+
return var_operation_return(
|
|
1602
|
+
js_expression=f"[...{lhs}, ...{rhs}]",
|
|
1603
|
+
var_type=Union[lhs._var_type, rhs._var_type],
|
|
1604
|
+
)
|