reflex 0.5.7__py3-none-any.whl → 0.5.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

Files changed (44) hide show
  1. reflex/.templates/web/utils/state.js +1 -1
  2. reflex/app.py +20 -2
  3. reflex/components/core/banner.py +14 -0
  4. reflex/components/core/banner.pyi +3 -3
  5. reflex/components/core/debounce.py +3 -0
  6. reflex/components/el/__init__.py +1 -0
  7. reflex/components/el/__init__.pyi +8 -5
  8. reflex/components/el/elements/__init__.py +3 -1
  9. reflex/components/el/elements/__init__.pyi +8 -6
  10. reflex/components/el/elements/media.py +98 -18
  11. reflex/components/el/elements/media.pyi +523 -18
  12. reflex/components/el/elements/metadata.py +5 -1
  13. reflex/components/radix/primitives/base.py +1 -1
  14. reflex/components/radix/themes/layout/list.py +0 -2
  15. reflex/components/recharts/cartesian.py +46 -20
  16. reflex/components/recharts/cartesian.pyi +26 -14
  17. reflex/components/recharts/charts.py +4 -0
  18. reflex/components/recharts/charts.pyi +3 -0
  19. reflex/components/recharts/general.py +23 -9
  20. reflex/components/recharts/general.pyi +6 -4
  21. reflex/components/recharts/polar.py +35 -11
  22. reflex/components/recharts/polar.pyi +35 -7
  23. reflex/components/sonner/toast.py +28 -2
  24. reflex/components/sonner/toast.pyi +14 -7
  25. reflex/constants/base.py +21 -0
  26. reflex/constants/event.py +2 -0
  27. reflex/experimental/vars/__init__.py +17 -0
  28. reflex/experimental/vars/base.py +282 -15
  29. reflex/experimental/vars/function.py +214 -0
  30. reflex/experimental/vars/number.py +1295 -0
  31. reflex/experimental/vars/sequence.py +1039 -0
  32. reflex/reflex.py +29 -2
  33. reflex/state.py +59 -10
  34. reflex/utils/imports.py +71 -8
  35. reflex/utils/prerequisites.py +115 -35
  36. reflex/utils/pyi_generator.py +2 -0
  37. reflex/utils/redir.py +52 -0
  38. reflex/vars.py +220 -11
  39. reflex/vars.pyi +20 -2
  40. {reflex-0.5.7.dist-info → reflex-0.5.8.dist-info}/METADATA +2 -2
  41. {reflex-0.5.7.dist-info → reflex-0.5.8.dist-info}/RECORD +44 -40
  42. {reflex-0.5.7.dist-info → reflex-0.5.8.dist-info}/LICENSE +0 -0
  43. {reflex-0.5.7.dist-info → reflex-0.5.8.dist-info}/WHEEL +0 -0
  44. {reflex-0.5.7.dist-info → reflex-0.5.8.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1039 @@
1
+ """Collection of string classes and utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import dataclasses
6
+ import functools
7
+ import json
8
+ import re
9
+ import sys
10
+ from functools import cached_property
11
+ from typing import Any, List, Set, Tuple, Union
12
+
13
+ from reflex import constants
14
+ from reflex.constants.base import REFLEX_VAR_OPENING_TAG
15
+ from reflex.experimental.vars.base import (
16
+ ImmutableVar,
17
+ LiteralVar,
18
+ )
19
+ from reflex.experimental.vars.number import BooleanVar, NotEqualOperation, NumberVar
20
+ from reflex.vars import ImmutableVarData, Var, VarData, _global_vars
21
+
22
+
23
+ class StringVar(ImmutableVar):
24
+ """Base class for immutable string vars."""
25
+
26
+ def __add__(self, other: StringVar | str) -> ConcatVarOperation:
27
+ """Concatenate two strings.
28
+
29
+ Args:
30
+ other: The other string.
31
+
32
+ Returns:
33
+ The string concatenation operation.
34
+ """
35
+ return ConcatVarOperation(self, other)
36
+
37
+ def __radd__(self, other: StringVar | str) -> ConcatVarOperation:
38
+ """Concatenate two strings.
39
+
40
+ Args:
41
+ other: The other string.
42
+
43
+ Returns:
44
+ The string concatenation operation.
45
+ """
46
+ return ConcatVarOperation(other, self)
47
+
48
+ def __mul__(self, other: int) -> ConcatVarOperation:
49
+ """Concatenate two strings.
50
+
51
+ Args:
52
+ other: The other string.
53
+
54
+ Returns:
55
+ The string concatenation operation.
56
+ """
57
+ return ConcatVarOperation(*[self for _ in range(other)])
58
+
59
+ def __rmul__(self, other: int) -> ConcatVarOperation:
60
+ """Concatenate two strings.
61
+
62
+ Args:
63
+ other: The other string.
64
+
65
+ Returns:
66
+ The string concatenation operation.
67
+ """
68
+ return ConcatVarOperation(*[self for _ in range(other)])
69
+
70
+ def __getitem__(self, i: slice | int) -> StringSliceOperation | StringItemOperation:
71
+ """Get a slice of the string.
72
+
73
+ Args:
74
+ i: The slice.
75
+
76
+ Returns:
77
+ The string slice operation.
78
+ """
79
+ if isinstance(i, slice):
80
+ return StringSliceOperation(self, i)
81
+ return StringItemOperation(self, i)
82
+
83
+ def length(self) -> StringLengthOperation:
84
+ """Get the length of the string.
85
+
86
+ Returns:
87
+ The string length operation.
88
+ """
89
+ return StringLengthOperation(self)
90
+
91
+ def lower(self) -> StringLowerOperation:
92
+ """Convert the string to lowercase.
93
+
94
+ Returns:
95
+ The string lower operation.
96
+ """
97
+ return StringLowerOperation(self)
98
+
99
+ def upper(self) -> StringUpperOperation:
100
+ """Convert the string to uppercase.
101
+
102
+ Returns:
103
+ The string upper operation.
104
+ """
105
+ return StringUpperOperation(self)
106
+
107
+ def strip(self) -> StringStripOperation:
108
+ """Strip the string.
109
+
110
+ Returns:
111
+ The string strip operation.
112
+ """
113
+ return StringStripOperation(self)
114
+
115
+ def bool(self) -> NotEqualOperation:
116
+ """Boolean conversion.
117
+
118
+ Returns:
119
+ The boolean value of the string.
120
+ """
121
+ return NotEqualOperation(self.length(), 0)
122
+
123
+ def reversed(self) -> StringReverseOperation:
124
+ """Reverse the string.
125
+
126
+ Returns:
127
+ The string reverse operation.
128
+ """
129
+ return StringReverseOperation(self)
130
+
131
+ def contains(self, other: StringVar | str) -> StringContainsOperation:
132
+ """Check if the string contains another string.
133
+
134
+ Args:
135
+ other: The other string.
136
+
137
+ Returns:
138
+ The string contains operation.
139
+ """
140
+ return StringContainsOperation(self, other)
141
+
142
+ def split(self, separator: StringVar | str = "") -> StringSplitOperation:
143
+ """Split the string.
144
+
145
+ Args:
146
+ separator: The separator.
147
+
148
+ Returns:
149
+ The string split operation.
150
+ """
151
+ return StringSplitOperation(self, separator)
152
+
153
+
154
+ @dataclasses.dataclass(
155
+ eq=False,
156
+ frozen=True,
157
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
158
+ )
159
+ class StringToNumberOperation(NumberVar):
160
+ """Base class for immutable number vars that are the result of a string to number operation."""
161
+
162
+ a: StringVar = dataclasses.field(
163
+ default_factory=lambda: LiteralStringVar.create("")
164
+ )
165
+
166
+ def __init__(self, a: StringVar | str, _var_data: VarData | None = None):
167
+ """Initialize the string to number operation var.
168
+
169
+ Args:
170
+ a: The string.
171
+ _var_data: Additional hooks and imports associated with the Var.
172
+ """
173
+ super(StringToNumberOperation, self).__init__(
174
+ _var_name="",
175
+ _var_type=float,
176
+ _var_data=ImmutableVarData.merge(_var_data),
177
+ )
178
+ object.__setattr__(
179
+ self, "a", a if isinstance(a, Var) else LiteralStringVar.create(a)
180
+ )
181
+ object.__delattr__(self, "_var_name")
182
+
183
+ @cached_property
184
+ def _cached_var_name(self) -> str:
185
+ """The name of the var.
186
+
187
+ Raises:
188
+ NotImplementedError: Must be implemented by subclasses.
189
+ """
190
+ raise NotImplementedError(
191
+ "StringToNumberOperation must implement _cached_var_name"
192
+ )
193
+
194
+ def __getattr__(self, name: str) -> Any:
195
+ """Get an attribute of the var.
196
+
197
+ Args:
198
+ name: The name of the attribute.
199
+
200
+ Returns:
201
+ The attribute value.
202
+ """
203
+ if name == "_var_name":
204
+ return self._cached_var_name
205
+ getattr(super(StringToNumberOperation, self), name)
206
+
207
+ @cached_property
208
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
209
+ """Get all VarData associated with the Var.
210
+
211
+ Returns:
212
+ The VarData of the components and all of its children.
213
+ """
214
+ return ImmutableVarData.merge(self.a._get_all_var_data(), self._var_data)
215
+
216
+ def _get_all_var_data(self) -> ImmutableVarData | None:
217
+ return self._cached_get_all_var_data
218
+
219
+
220
+ class StringLengthOperation(StringToNumberOperation):
221
+ """Base class for immutable number vars that are the result of a string length operation."""
222
+
223
+ @cached_property
224
+ def _cached_var_name(self) -> str:
225
+ """The name of the var.
226
+
227
+ Returns:
228
+ The name of the var.
229
+ """
230
+ return f"{str(self.a)}.length"
231
+
232
+
233
+ @dataclasses.dataclass(
234
+ eq=False,
235
+ frozen=True,
236
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
237
+ )
238
+ class StringToStringOperation(StringVar):
239
+ """Base class for immutable string vars that are the result of a string to string operation."""
240
+
241
+ a: StringVar = dataclasses.field(
242
+ default_factory=lambda: LiteralStringVar.create("")
243
+ )
244
+
245
+ def __init__(self, a: StringVar | str, _var_data: VarData | None = None):
246
+ """Initialize the string to string operation var.
247
+
248
+ Args:
249
+ a: The string.
250
+ _var_data: Additional hooks and imports associated with the Var.
251
+ """
252
+ super(StringToStringOperation, self).__init__(
253
+ _var_name="",
254
+ _var_type=str,
255
+ _var_data=ImmutableVarData.merge(_var_data),
256
+ )
257
+ object.__setattr__(
258
+ self, "a", a if isinstance(a, Var) else LiteralStringVar.create(a)
259
+ )
260
+ object.__delattr__(self, "_var_name")
261
+
262
+ @cached_property
263
+ def _cached_var_name(self) -> str:
264
+ """The name of the var.
265
+
266
+ Raises:
267
+ NotImplementedError: Must be implemented by subclasses.
268
+ """
269
+ raise NotImplementedError(
270
+ "StringToStringOperation must implement _cached_var_name"
271
+ )
272
+
273
+ def __getattr__(self, name: str) -> Any:
274
+ """Get an attribute of the var.
275
+
276
+ Args:
277
+ name: The name of the attribute.
278
+
279
+ Returns:
280
+ The attribute value.
281
+ """
282
+ if name == "_var_name":
283
+ return self._cached_var_name
284
+ getattr(super(StringToStringOperation, self), name)
285
+
286
+ @cached_property
287
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
288
+ """Get all VarData associated with the Var.
289
+
290
+ Returns:
291
+ The VarData of the components and all of its children.
292
+ """
293
+ return ImmutableVarData.merge(
294
+ self.a._get_all_var_data() if isinstance(self.a, Var) else None,
295
+ self._var_data,
296
+ )
297
+
298
+ def _get_all_var_data(self) -> ImmutableVarData | None:
299
+ return self._cached_get_all_var_data
300
+
301
+
302
+ class StringLowerOperation(StringToStringOperation):
303
+ """Base class for immutable string vars that are the result of a string lower operation."""
304
+
305
+ @cached_property
306
+ def _cached_var_name(self) -> str:
307
+ """The name of the var.
308
+
309
+ Returns:
310
+ The name of the var.
311
+ """
312
+ return f"{str(self.a)}.toLowerCase()"
313
+
314
+
315
+ class StringUpperOperation(StringToStringOperation):
316
+ """Base class for immutable string vars that are the result of a string upper operation."""
317
+
318
+ @cached_property
319
+ def _cached_var_name(self) -> str:
320
+ """The name of the var.
321
+
322
+ Returns:
323
+ The name of the var.
324
+ """
325
+ return f"{str(self.a)}.toUpperCase()"
326
+
327
+
328
+ class StringStripOperation(StringToStringOperation):
329
+ """Base class for immutable string vars that are the result of a string strip operation."""
330
+
331
+ @cached_property
332
+ def _cached_var_name(self) -> str:
333
+ """The name of the var.
334
+
335
+ Returns:
336
+ The name of the var.
337
+ """
338
+ return f"{str(self.a)}.trim()"
339
+
340
+
341
+ class StringReverseOperation(StringToStringOperation):
342
+ """Base class for immutable string vars that are the result of a string reverse operation."""
343
+
344
+ @cached_property
345
+ def _cached_var_name(self) -> str:
346
+ """The name of the var.
347
+
348
+ Returns:
349
+ The name of the var.
350
+ """
351
+ return f"{str(self.a)}.split('').reverse().join('')"
352
+
353
+
354
+ @dataclasses.dataclass(
355
+ eq=False,
356
+ frozen=True,
357
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
358
+ )
359
+ class StringContainsOperation(BooleanVar):
360
+ """Base class for immutable boolean vars that are the result of a string contains operation."""
361
+
362
+ a: StringVar = dataclasses.field(
363
+ default_factory=lambda: LiteralStringVar.create("")
364
+ )
365
+ b: StringVar = dataclasses.field(
366
+ default_factory=lambda: LiteralStringVar.create("")
367
+ )
368
+
369
+ def __init__(
370
+ self, a: StringVar | str, b: StringVar | str, _var_data: VarData | None = None
371
+ ):
372
+ """Initialize the string contains operation var.
373
+
374
+ Args:
375
+ a: The first string.
376
+ b: The second string.
377
+ _var_data: Additional hooks and imports associated with the Var.
378
+ """
379
+ super(StringContainsOperation, self).__init__(
380
+ _var_name="",
381
+ _var_type=bool,
382
+ _var_data=ImmutableVarData.merge(_var_data),
383
+ )
384
+ object.__setattr__(
385
+ self, "a", a if isinstance(a, Var) else LiteralStringVar.create(a)
386
+ )
387
+ object.__setattr__(
388
+ self, "b", b if isinstance(b, Var) else LiteralStringVar.create(b)
389
+ )
390
+ object.__delattr__(self, "_var_name")
391
+
392
+ @cached_property
393
+ def _cached_var_name(self) -> str:
394
+ """The name of the var.
395
+
396
+ Returns:
397
+ The name of the var.
398
+ """
399
+ return f"{str(self.a)}.includes({str(self.b)})"
400
+
401
+ def __getattr__(self, name: str) -> Any:
402
+ """Get an attribute of the var.
403
+
404
+ Args:
405
+ name: The name of the attribute.
406
+
407
+ Returns:
408
+ The attribute value.
409
+ """
410
+ if name == "_var_name":
411
+ return self._cached_var_name
412
+ getattr(super(StringContainsOperation, self), name)
413
+
414
+ @cached_property
415
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
416
+ """Get all VarData associated with the Var.
417
+
418
+ Returns:
419
+ The VarData of the components and all of its children.
420
+ """
421
+ return ImmutableVarData.merge(
422
+ self.a._get_all_var_data(), self.b._get_all_var_data(), self._var_data
423
+ )
424
+
425
+ def _get_all_var_data(self) -> ImmutableVarData | None:
426
+ return self._cached_get_all_var_data
427
+
428
+
429
+ @dataclasses.dataclass(
430
+ eq=False,
431
+ frozen=True,
432
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
433
+ )
434
+ class StringSliceOperation(StringVar):
435
+ """Base class for immutable string vars that are the result of a string slice operation."""
436
+
437
+ a: StringVar = dataclasses.field(
438
+ default_factory=lambda: LiteralStringVar.create("")
439
+ )
440
+ _slice: slice = dataclasses.field(default_factory=lambda: slice(None, None, None))
441
+
442
+ def __init__(
443
+ self, a: StringVar | str, _slice: slice, _var_data: VarData | None = None
444
+ ):
445
+ """Initialize the string slice operation var.
446
+
447
+ Args:
448
+ a: The string.
449
+ _slice: The slice.
450
+ _var_data: Additional hooks and imports associated with the Var.
451
+ """
452
+ super(StringSliceOperation, self).__init__(
453
+ _var_name="",
454
+ _var_type=str,
455
+ _var_data=ImmutableVarData.merge(_var_data),
456
+ )
457
+ object.__setattr__(
458
+ self, "a", a if isinstance(a, Var) else LiteralStringVar.create(a)
459
+ )
460
+ object.__setattr__(self, "_slice", _slice)
461
+ object.__delattr__(self, "_var_name")
462
+
463
+ @cached_property
464
+ def _cached_var_name(self) -> str:
465
+ """The name of the var.
466
+
467
+ Returns:
468
+ The name of the var.
469
+
470
+ Raises:
471
+ ValueError: If the slice step is zero.
472
+ """
473
+ start, end, step = self._slice.start, self._slice.stop, self._slice.step
474
+
475
+ if step is not None and step < 0:
476
+ actual_start = end + 1 if end is not None else 0
477
+ actual_end = start + 1 if start is not None else self.a.length()
478
+ return str(
479
+ StringSliceOperation(
480
+ StringReverseOperation(
481
+ StringSliceOperation(self.a, slice(actual_start, actual_end))
482
+ ),
483
+ slice(None, None, -step),
484
+ )
485
+ )
486
+
487
+ start = (
488
+ LiteralVar.create(start)
489
+ if start is not None
490
+ else ImmutableVar.create_safe("undefined")
491
+ )
492
+ end = (
493
+ LiteralVar.create(end)
494
+ if end is not None
495
+ else ImmutableVar.create_safe("undefined")
496
+ )
497
+
498
+ if step is None:
499
+ return f"{str(self.a)}.slice({str(start)}, {str(end)})"
500
+ if step == 0:
501
+ raise ValueError("slice step cannot be zero")
502
+ return f"{str(self.a)}.slice({str(start)}, {str(end)}).split('').filter((_, i) => i % {str(step)} === 0).join('')"
503
+
504
+ def __getattr__(self, name: str) -> Any:
505
+ """Get an attribute of the var.
506
+
507
+ Args:
508
+ name: The name of the attribute.
509
+
510
+ Returns:
511
+ The attribute value.
512
+ """
513
+ if name == "_var_name":
514
+ return self._cached_var_name
515
+ getattr(super(StringSliceOperation, self), name)
516
+
517
+ @cached_property
518
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
519
+ """Get all VarData associated with the Var.
520
+
521
+ Returns:
522
+ The VarData of the components and all of its children.
523
+ """
524
+ return ImmutableVarData.merge(
525
+ self.a._get_all_var_data(),
526
+ self.start._get_all_var_data(),
527
+ self.end._get_all_var_data(),
528
+ self._var_data,
529
+ )
530
+
531
+ def _get_all_var_data(self) -> ImmutableVarData | None:
532
+ return self._cached_get_all_var_data
533
+
534
+
535
+ @dataclasses.dataclass(
536
+ eq=False,
537
+ frozen=True,
538
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
539
+ )
540
+ class StringItemOperation(StringVar):
541
+ """Base class for immutable string vars that are the result of a string item operation."""
542
+
543
+ a: StringVar = dataclasses.field(
544
+ default_factory=lambda: LiteralStringVar.create("")
545
+ )
546
+ i: int = dataclasses.field(default=0)
547
+
548
+ def __init__(self, a: StringVar | str, i: int, _var_data: VarData | None = None):
549
+ """Initialize the string item operation var.
550
+
551
+ Args:
552
+ a: The string.
553
+ i: The index.
554
+ _var_data: Additional hooks and imports associated with the Var.
555
+ """
556
+ super(StringItemOperation, self).__init__(
557
+ _var_name="",
558
+ _var_type=str,
559
+ _var_data=ImmutableVarData.merge(_var_data),
560
+ )
561
+ object.__setattr__(
562
+ self, "a", a if isinstance(a, Var) else LiteralStringVar.create(a)
563
+ )
564
+ object.__setattr__(self, "i", i)
565
+ object.__delattr__(self, "_var_name")
566
+
567
+ @cached_property
568
+ def _cached_var_name(self) -> str:
569
+ """The name of the var.
570
+
571
+ Returns:
572
+ The name of the var.
573
+ """
574
+ return f"{str(self.a)}.at({str(self.i)})"
575
+
576
+ def __getattr__(self, name: str) -> Any:
577
+ """Get an attribute of the var.
578
+
579
+ Args:
580
+ name: The name of the attribute.
581
+
582
+ Returns:
583
+ The attribute value.
584
+ """
585
+ if name == "_var_name":
586
+ return self._cached_var_name
587
+ getattr(super(StringItemOperation, self), name)
588
+
589
+ @cached_property
590
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
591
+ """Get all VarData associated with the Var.
592
+
593
+ Returns:
594
+ The VarData of the components and all of its children.
595
+ """
596
+ return ImmutableVarData.merge(self.a._get_all_var_data(), self._var_data)
597
+
598
+ def _get_all_var_data(self) -> ImmutableVarData | None:
599
+ return self._cached_get_all_var_data
600
+
601
+
602
+ class ArrayJoinOperation(StringVar):
603
+ """Base class for immutable string vars that are the result of an array join operation."""
604
+
605
+ a: ArrayVar = dataclasses.field(default_factory=lambda: LiteralArrayVar([]))
606
+ b: StringVar = dataclasses.field(
607
+ default_factory=lambda: LiteralStringVar.create("")
608
+ )
609
+
610
+ def __init__(
611
+ self, a: ArrayVar | list, b: StringVar | str, _var_data: VarData | None = None
612
+ ):
613
+ """Initialize the array join operation var.
614
+
615
+ Args:
616
+ a: The array.
617
+ b: The separator.
618
+ _var_data: Additional hooks and imports associated with the Var.
619
+ """
620
+ super(ArrayJoinOperation, self).__init__(
621
+ _var_name="",
622
+ _var_type=str,
623
+ _var_data=ImmutableVarData.merge(_var_data),
624
+ )
625
+ object.__setattr__(
626
+ self, "a", a if isinstance(a, Var) else LiteralArrayVar.create(a)
627
+ )
628
+ object.__setattr__(
629
+ self, "b", b if isinstance(b, Var) else LiteralStringVar.create(b)
630
+ )
631
+ object.__delattr__(self, "_var_name")
632
+
633
+ @cached_property
634
+ def _cached_var_name(self) -> str:
635
+ """The name of the var.
636
+
637
+ Returns:
638
+ The name of the var.
639
+ """
640
+ return f"{str(self.a)}.join({str(self.b)})"
641
+
642
+ def __getattr__(self, name: str) -> Any:
643
+ """Get an attribute of the var.
644
+
645
+ Args:
646
+ name: The name of the attribute.
647
+
648
+ Returns:
649
+ The attribute value.
650
+ """
651
+ if name == "_var_name":
652
+ return self._cached_var_name
653
+ getattr(super(ArrayJoinOperation, self), name)
654
+
655
+ @cached_property
656
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
657
+ """Get all VarData associated with the Var.
658
+
659
+ Returns:
660
+ The VarData of the components and all of its children.
661
+ """
662
+ return ImmutableVarData.merge(
663
+ self.a._get_all_var_data(), self.b._get_all_var_data(), self._var_data
664
+ )
665
+
666
+ def _get_all_var_data(self) -> ImmutableVarData | None:
667
+ return self._cached_get_all_var_data
668
+
669
+
670
+ # Compile regex for finding reflex var tags.
671
+ _decode_var_pattern_re = (
672
+ rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
673
+ )
674
+ _decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
675
+
676
+
677
+ @dataclasses.dataclass(
678
+ eq=False,
679
+ frozen=True,
680
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
681
+ )
682
+ class LiteralStringVar(LiteralVar, StringVar):
683
+ """Base class for immutable literal string vars."""
684
+
685
+ _var_value: str = dataclasses.field(default="")
686
+
687
+ def __init__(
688
+ self,
689
+ _var_value: str,
690
+ _var_data: VarData | None = None,
691
+ ):
692
+ """Initialize the string var.
693
+
694
+ Args:
695
+ _var_value: The value of the var.
696
+ _var_data: Additional hooks and imports associated with the Var.
697
+ """
698
+ super(LiteralStringVar, self).__init__(
699
+ _var_name=f'"{_var_value}"',
700
+ _var_type=str,
701
+ _var_data=ImmutableVarData.merge(_var_data),
702
+ )
703
+ object.__setattr__(self, "_var_value", _var_value)
704
+
705
+ @classmethod
706
+ def create(
707
+ cls,
708
+ value: str,
709
+ _var_data: VarData | None = None,
710
+ ) -> LiteralStringVar | ConcatVarOperation:
711
+ """Create a var from a string value.
712
+
713
+ Args:
714
+ value: The value to create the var from.
715
+ _var_data: Additional hooks and imports associated with the Var.
716
+
717
+ Returns:
718
+ The var.
719
+ """
720
+ if REFLEX_VAR_OPENING_TAG in value:
721
+ strings_and_vals: list[Var | str] = []
722
+ offset = 0
723
+
724
+ # Initialize some methods for reading json.
725
+ var_data_config = VarData().__config__
726
+
727
+ def json_loads(s):
728
+ try:
729
+ return var_data_config.json_loads(s)
730
+ except json.decoder.JSONDecodeError:
731
+ return var_data_config.json_loads(
732
+ var_data_config.json_loads(f'"{s}"')
733
+ )
734
+
735
+ # Find all tags
736
+ while m := _decode_var_pattern.search(value):
737
+ start, end = m.span()
738
+ if start > 0:
739
+ strings_and_vals.append(value[:start])
740
+
741
+ serialized_data = m.group(1)
742
+
743
+ if serialized_data.isnumeric() or (
744
+ serialized_data[0] == "-" and serialized_data[1:].isnumeric()
745
+ ):
746
+ # This is a global immutable var.
747
+ var = _global_vars[int(serialized_data)]
748
+ strings_and_vals.append(var)
749
+ value = value[(end + len(var._var_name)) :]
750
+ else:
751
+ data = json_loads(serialized_data)
752
+ string_length = data.pop("string_length", None)
753
+ var_data = VarData.parse_obj(data)
754
+
755
+ # Use string length to compute positions of interpolations.
756
+ if string_length is not None:
757
+ realstart = start + offset
758
+ var_data.interpolations = [
759
+ (realstart, realstart + string_length)
760
+ ]
761
+ strings_and_vals.append(
762
+ ImmutableVar.create_safe(
763
+ value[end : (end + string_length)], _var_data=var_data
764
+ )
765
+ )
766
+ value = value[(end + string_length) :]
767
+
768
+ offset += end - start
769
+
770
+ if value:
771
+ strings_and_vals.append(value)
772
+
773
+ return ConcatVarOperation(*strings_and_vals, _var_data=_var_data)
774
+
775
+ return LiteralStringVar(
776
+ value,
777
+ _var_data=_var_data,
778
+ )
779
+
780
+
781
+ @dataclasses.dataclass(
782
+ eq=False,
783
+ frozen=True,
784
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
785
+ )
786
+ class ConcatVarOperation(StringVar):
787
+ """Representing a concatenation of literal string vars."""
788
+
789
+ _var_value: Tuple[Union[Var, str], ...] = dataclasses.field(default_factory=tuple)
790
+
791
+ def __init__(self, *value: Var | str, _var_data: VarData | None = None):
792
+ """Initialize the operation of concatenating literal string vars.
793
+
794
+ Args:
795
+ value: The values to concatenate.
796
+ _var_data: Additional hooks and imports associated with the Var.
797
+ """
798
+ super(ConcatVarOperation, self).__init__(
799
+ _var_name="", _var_data=ImmutableVarData.merge(_var_data), _var_type=str
800
+ )
801
+ object.__setattr__(self, "_var_value", value)
802
+ object.__delattr__(self, "_var_name")
803
+
804
+ def __getattr__(self, name):
805
+ """Get an attribute of the var.
806
+
807
+ Args:
808
+ name: The name of the attribute.
809
+
810
+ Returns:
811
+ The attribute of the var.
812
+ """
813
+ if name == "_var_name":
814
+ return self._cached_var_name
815
+ return super(type(self), self).__getattr__(name)
816
+
817
+ @cached_property
818
+ def _cached_var_name(self) -> str:
819
+ """The name of the var.
820
+
821
+ Returns:
822
+ The name of the var.
823
+ """
824
+ return (
825
+ "("
826
+ + "+".join(
827
+ [
828
+ str(element) if isinstance(element, Var) else f'"{element}"'
829
+ for element in self._var_value
830
+ ]
831
+ )
832
+ + ")"
833
+ )
834
+
835
+ @cached_property
836
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
837
+ """Get all VarData associated with the Var.
838
+
839
+ Returns:
840
+ The VarData of the components and all of its children.
841
+ """
842
+ return ImmutableVarData.merge(
843
+ *[
844
+ var._get_all_var_data()
845
+ for var in self._var_value
846
+ if isinstance(var, Var)
847
+ ],
848
+ self._var_data,
849
+ )
850
+
851
+ def _get_all_var_data(self) -> ImmutableVarData | None:
852
+ """Wrapper method for cached property.
853
+
854
+ Returns:
855
+ The VarData of the components and all of its children.
856
+ """
857
+ return self._cached_get_all_var_data
858
+
859
+ def __post_init__(self):
860
+ """Post-initialize the var."""
861
+ pass
862
+
863
+
864
+ class ArrayVar(ImmutableVar):
865
+ """Base class for immutable array vars."""
866
+
867
+ from reflex.experimental.vars.sequence import StringVar
868
+
869
+ def join(self, sep: StringVar | str = "") -> ArrayJoinOperation:
870
+ """Join the elements of the array.
871
+
872
+ Args:
873
+ sep: The separator between elements.
874
+
875
+ Returns:
876
+ The joined elements.
877
+ """
878
+ from reflex.experimental.vars.sequence import ArrayJoinOperation
879
+
880
+ return ArrayJoinOperation(self, sep)
881
+
882
+
883
+ @dataclasses.dataclass(
884
+ eq=False,
885
+ frozen=True,
886
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
887
+ )
888
+ class LiteralArrayVar(LiteralVar, ArrayVar):
889
+ """Base class for immutable literal array vars."""
890
+
891
+ _var_value: Union[
892
+ List[Union[Var, Any]], Set[Union[Var, Any]], Tuple[Union[Var, Any], ...]
893
+ ] = dataclasses.field(default_factory=list)
894
+
895
+ def __init__(
896
+ self,
897
+ _var_value: list[Var | Any] | tuple[Var | Any] | set[Var | Any],
898
+ _var_data: VarData | None = None,
899
+ ):
900
+ """Initialize the array var.
901
+
902
+ Args:
903
+ _var_value: The value of the var.
904
+ _var_data: Additional hooks and imports associated with the Var.
905
+ """
906
+ super(LiteralArrayVar, self).__init__(
907
+ _var_name="",
908
+ _var_data=ImmutableVarData.merge(_var_data),
909
+ _var_type=list,
910
+ )
911
+ object.__setattr__(self, "_var_value", _var_value)
912
+ object.__delattr__(self, "_var_name")
913
+
914
+ def __getattr__(self, name):
915
+ """Get an attribute of the var.
916
+
917
+ Args:
918
+ name: The name of the attribute.
919
+
920
+ Returns:
921
+ The attribute of the var.
922
+ """
923
+ if name == "_var_name":
924
+ return self._cached_var_name
925
+ return super(type(self), self).__getattr__(name)
926
+
927
+ @functools.cached_property
928
+ def _cached_var_name(self) -> str:
929
+ """The name of the var.
930
+
931
+ Returns:
932
+ The name of the var.
933
+ """
934
+ return (
935
+ "["
936
+ + ", ".join(
937
+ [str(LiteralVar.create(element)) for element in self._var_value]
938
+ )
939
+ + "]"
940
+ )
941
+
942
+ @functools.cached_property
943
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
944
+ """Get all VarData associated with the Var.
945
+
946
+ Returns:
947
+ The VarData of the components and all of its children.
948
+ """
949
+ return ImmutableVarData.merge(
950
+ *[
951
+ var._get_all_var_data()
952
+ for var in self._var_value
953
+ if isinstance(var, Var)
954
+ ],
955
+ self._var_data,
956
+ )
957
+
958
+ def _get_all_var_data(self) -> ImmutableVarData | None:
959
+ """Wrapper method for cached property.
960
+
961
+ Returns:
962
+ The VarData of the components and all of its children.
963
+ """
964
+ return self._cached_get_all_var_data
965
+
966
+
967
+ @dataclasses.dataclass(
968
+ eq=False,
969
+ frozen=True,
970
+ **{"slots": True} if sys.version_info >= (3, 10) else {},
971
+ )
972
+ class StringSplitOperation(ArrayVar):
973
+ """Base class for immutable array vars that are the result of a string split operation."""
974
+
975
+ a: StringVar = dataclasses.field(
976
+ default_factory=lambda: LiteralStringVar.create("")
977
+ )
978
+ b: StringVar = dataclasses.field(
979
+ default_factory=lambda: LiteralStringVar.create("")
980
+ )
981
+
982
+ def __init__(
983
+ self, a: StringVar | str, b: StringVar | str, _var_data: VarData | None = None
984
+ ):
985
+ """Initialize the string split operation var.
986
+
987
+ Args:
988
+ a: The string.
989
+ b: The separator.
990
+ _var_data: Additional hooks and imports associated with the Var.
991
+ """
992
+ super(StringSplitOperation, self).__init__(
993
+ _var_name="",
994
+ _var_type=list,
995
+ _var_data=ImmutableVarData.merge(_var_data),
996
+ )
997
+ object.__setattr__(
998
+ self, "a", a if isinstance(a, Var) else LiteralStringVar.create(a)
999
+ )
1000
+ object.__setattr__(
1001
+ self, "b", b if isinstance(b, Var) else LiteralStringVar.create(b)
1002
+ )
1003
+ object.__delattr__(self, "_var_name")
1004
+
1005
+ @cached_property
1006
+ def _cached_var_name(self) -> str:
1007
+ """The name of the var.
1008
+
1009
+ Returns:
1010
+ The name of the var.
1011
+ """
1012
+ return f"{str(self.a)}.split({str(self.b)})"
1013
+
1014
+ def __getattr__(self, name: str) -> Any:
1015
+ """Get an attribute of the var.
1016
+
1017
+ Args:
1018
+ name: The name of the attribute.
1019
+
1020
+ Returns:
1021
+ The attribute value.
1022
+ """
1023
+ if name == "_var_name":
1024
+ return self._cached_var_name
1025
+ getattr(super(StringSplitOperation, self), name)
1026
+
1027
+ @cached_property
1028
+ def _cached_get_all_var_data(self) -> ImmutableVarData | None:
1029
+ """Get all VarData associated with the Var.
1030
+
1031
+ Returns:
1032
+ The VarData of the components and all of its children.
1033
+ """
1034
+ return ImmutableVarData.merge(
1035
+ self.a._get_all_var_data(), self.b._get_all_var_data(), self._var_data
1036
+ )
1037
+
1038
+ def _get_all_var_data(self) -> ImmutableVarData | None:
1039
+ return self._cached_get_all_var_data