Skip to content

Commit 4808c42

Browse files
committed
optimize various var functions
1 parent 5fd8ea9 commit 4808c42

File tree

7 files changed

+220
-41
lines changed

7 files changed

+220
-41
lines changed

reflex/utils/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ def is_literal(cls: GenericType) -> bool:
291291
return getattr(cls, "__origin__", None) is Literal
292292

293293

294+
@lru_cache
294295
def has_args(cls: type) -> bool:
295296
"""Check if the class has generic parameters.
296297

reflex/vars/base.py

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,82 @@ def _create_literal_var(
15271527
def __post_init__(self):
15281528
"""Post-initialize the var."""
15291529

1530+
@classmethod
1531+
def _get_all_var_data_without_creating_var(
1532+
cls,
1533+
value: Any,
1534+
) -> VarData | None:
1535+
return cls.create(value)._get_all_var_data()
1536+
1537+
@classmethod
1538+
def _get_all_var_data_without_creating_var_dispatch(
1539+
cls,
1540+
value: Any,
1541+
) -> VarData | None:
1542+
"""Get all the var data without creating a var.
1543+
1544+
Args:
1545+
value: The value to get the var data from.
1546+
1547+
Returns:
1548+
The var data or None.
1549+
1550+
Raises:
1551+
TypeError: If the value is not a supported type for LiteralVar.
1552+
"""
1553+
from .object import LiteralObjectVar
1554+
from .sequence import LiteralStringVar
1555+
1556+
if isinstance(value, Var):
1557+
return value._get_all_var_data()
1558+
1559+
for literal_subclass, var_subclass in _var_literal_subclasses[::-1]:
1560+
if isinstance(value, var_subclass.python_types):
1561+
return literal_subclass._get_all_var_data_without_creating_var(value)
1562+
1563+
if (
1564+
(as_var_method := getattr(value, "_as_var", None)) is not None
1565+
and callable(as_var_method)
1566+
and isinstance((resulting_var := as_var_method()), Var)
1567+
):
1568+
return resulting_var._get_all_var_data()
1569+
1570+
from reflex.event import EventHandler
1571+
from reflex.utils.format import get_event_handler_parts
1572+
1573+
if isinstance(value, EventHandler):
1574+
return Var(
1575+
_js_expr=".".join(filter(None, get_event_handler_parts(value)))
1576+
)._get_all_var_data()
1577+
1578+
serialized_value = serializers.serialize(value)
1579+
if serialized_value is not None:
1580+
if isinstance(serialized_value, Mapping):
1581+
return LiteralObjectVar._get_all_var_data_without_creating_var(
1582+
serialized_value
1583+
)
1584+
if isinstance(serialized_value, str):
1585+
return LiteralStringVar._get_all_var_data_without_creating_var(
1586+
serialized_value
1587+
)
1588+
return LiteralVar._get_all_var_data_without_creating_var_dispatch(
1589+
serialized_value
1590+
)
1591+
1592+
if dataclasses.is_dataclass(value) and not isinstance(value, type):
1593+
return LiteralObjectVar._get_all_var_data_without_creating_var(
1594+
{
1595+
k: (None if callable(v) else v)
1596+
for k, v in dataclasses.asdict(value).items()
1597+
}
1598+
)
1599+
1600+
if isinstance(value, range):
1601+
return None
1602+
1603+
msg = f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
1604+
raise TypeError(msg)
1605+
15301606
@property
15311607
def _var_value(self) -> Any:
15321608
msg = "LiteralVar subclasses must implement the _var_value property."
@@ -1688,30 +1764,30 @@ def figure_out_type(value: Any) -> types.GenericType:
16881764
Returns:
16891765
The type of the value.
16901766
"""
1691-
if isinstance(value, Var):
1692-
return value._var_type
1693-
type_ = type(value)
1694-
if has_args(type_):
1695-
return type_
1696-
if isinstance(value, list):
1697-
if not value:
1698-
return Sequence[NoReturn]
1699-
return Sequence[unionize(*(figure_out_type(v) for v in value))]
1700-
if isinstance(value, set):
1701-
return set[unionize(*(figure_out_type(v) for v in value))]
1702-
if isinstance(value, tuple):
1703-
if not value:
1704-
return tuple[NoReturn, ...]
1705-
if len(value) <= 5:
1706-
return tuple[tuple(figure_out_type(v) for v in value)]
1707-
return tuple[unionize(*(figure_out_type(v) for v in value)), ...]
1708-
if isinstance(value, Mapping):
1709-
if not value:
1710-
return Mapping[NoReturn, NoReturn]
1711-
return Mapping[
1712-
unionize(*(figure_out_type(k) for k in value)),
1713-
unionize(*(figure_out_type(v) for v in value.values())),
1714-
]
1767+
if isinstance(value, (list, set, tuple, Mapping, Var)):
1768+
if isinstance(value, Var):
1769+
return value._var_type
1770+
if has_args(value_type := type(value)):
1771+
return value_type
1772+
if isinstance(value, list):
1773+
if not value:
1774+
return Sequence[NoReturn]
1775+
return Sequence[unionize(*{figure_out_type(v) for v in value})]
1776+
if isinstance(value, set):
1777+
return set[unionize(*{figure_out_type(v) for v in value})]
1778+
if isinstance(value, tuple):
1779+
if not value:
1780+
return tuple[NoReturn, ...]
1781+
if len(value) <= 5:
1782+
return tuple[tuple(figure_out_type(v) for v in value)]
1783+
return tuple[unionize(*{figure_out_type(v) for v in value}), ...]
1784+
if isinstance(value, Mapping):
1785+
if not value:
1786+
return Mapping[NoReturn, NoReturn]
1787+
return Mapping[
1788+
unionize(*{figure_out_type(k) for k in value}),
1789+
unionize(*{figure_out_type(v) for v in value.values()}),
1790+
]
17151791
return type(value)
17161792

17171793

@@ -2883,6 +2959,10 @@ def json(self) -> str:
28832959
"""
28842960
return "null"
28852961

2962+
@classmethod
2963+
def _get_all_var_data_without_creating_var(cls, value: None) -> VarData | None:
2964+
return None
2965+
28862966
@classmethod
28872967
def create(
28882968
cls,

reflex/vars/color.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,23 @@ class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
2929

3030
_var_value: Color = dataclasses.field(default_factory=lambda: Color(color="black"))
3131

32+
@classmethod
33+
def _get_all_var_data_without_creating_var(
34+
cls,
35+
value: Color,
36+
) -> VarData | None:
37+
return VarData.merge(
38+
LiteralStringVar._get_all_var_data_without_creating_var(value.color)
39+
if isinstance(value.color, str)
40+
else value.color._get_all_var_data(),
41+
value.alpha._get_all_var_data()
42+
if not isinstance(value.alpha, bool)
43+
else None,
44+
value.shade._get_all_var_data()
45+
if not isinstance(value.shade, int)
46+
else None,
47+
)
48+
3249
@classmethod
3350
def create(
3451
cls,
@@ -111,14 +128,17 @@ def _cached_get_all_var_data(self) -> VarData | None:
111128
The var data.
112129
"""
113130
return VarData.merge(
114-
*[
115-
LiteralVar.create(var)._get_all_var_data()
116-
for var in (
117-
self._var_value.color,
118-
self._var_value.alpha,
119-
self._var_value.shade,
120-
)
121-
],
131+
LiteralStringVar._get_all_var_data_without_creating_var(
132+
self._var_value.color
133+
)
134+
if isinstance(self._var_value.color, str)
135+
else self._var_value.color._get_all_var_data(),
136+
self._var_value.alpha._get_all_var_data()
137+
if not isinstance(self._var_value.alpha, bool)
138+
else None,
139+
self._var_value.shade._get_all_var_data()
140+
if not isinstance(self._var_value.shade, int)
141+
else None,
122142
self._var_data,
123143
)
124144

reflex/vars/datetime.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,14 @@ def date_compare_operation(
174174
class LiteralDatetimeVar(LiteralVar, DateTimeVar):
175175
"""Base class for immutable datetime and date vars."""
176176

177-
_var_value: datetime | date = dataclasses.field(default=datetime.now())
177+
_var_value: date = dataclasses.field(default=datetime.now())
178178

179179
@classmethod
180-
def create(cls, value: datetime | date, _var_data: VarData | None = None):
180+
def _get_all_var_data_without_creating_var(cls, value: date) -> VarData | None:
181+
return None
182+
183+
@classmethod
184+
def create(cls, value: date, _var_data: VarData | None = None):
181185
"""Create a new instance of the class.
182186
183187
Args:

reflex/vars/number.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,20 @@ def __hash__(self) -> int:
973973
"""
974974
return hash((type(self).__name__, self._var_value))
975975

976+
@classmethod
977+
def _get_all_var_data_without_creating_var(
978+
cls, value: float | int | decimal.Decimal
979+
) -> VarData | None:
980+
"""Get all the var data without creating the var.
981+
982+
Args:
983+
value: The value of the var.
984+
985+
Returns:
986+
The var data.
987+
"""
988+
return None
989+
976990
@classmethod
977991
def create(
978992
cls, value: float | int | decimal.Decimal, _var_data: VarData | None = None
@@ -1027,6 +1041,18 @@ def __hash__(self) -> int:
10271041
"""
10281042
return hash((type(self).__name__, self._var_value))
10291043

1044+
@classmethod
1045+
def _get_all_var_data_without_creating_var(cls, value: bool) -> VarData | None:
1046+
"""Get all the var data without creating the var.
1047+
1048+
Args:
1049+
value: The value of the var.
1050+
1051+
Returns:
1052+
The var data.
1053+
"""
1054+
return None
1055+
10301056
@classmethod
10311057
def create(cls, value: bool, _var_data: VarData | None = None):
10321058
"""Create the boolean var.

reflex/vars/object.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
var_operation_return,
4141
)
4242
from .number import BooleanVar, NumberVar, raise_unsupported_operand_types
43-
from .sequence import ArrayVar, StringVar
43+
from .sequence import ArrayVar, LiteralArrayVar, StringVar
4444

4545
OBJECT_TYPE = TypeVar("OBJECT_TYPE", covariant=True)
4646

@@ -437,6 +437,24 @@ def __hash__(self) -> int:
437437
"""
438438
return hash((type(self).__name__, self._js_expr))
439439

440+
@classmethod
441+
def _get_all_var_data_without_creating_var(
442+
cls,
443+
value: Mapping,
444+
) -> VarData | None:
445+
"""Get all the var data without creating a var.
446+
447+
Args:
448+
value: The value to get the var data from.
449+
450+
Returns:
451+
The var data.
452+
"""
453+
return VarData.merge(
454+
LiteralArrayVar._get_all_var_data_without_creating_var(value),
455+
LiteralArrayVar._get_all_var_data_without_creating_var(value.values()),
456+
)
457+
440458
@cached_property_no_lock
441459
def _cached_get_all_var_data(self) -> VarData | None:
442460
"""Get all the var data.
@@ -445,11 +463,10 @@ def _cached_get_all_var_data(self) -> VarData | None:
445463
The var data.
446464
"""
447465
return VarData.merge(
448-
*[LiteralVar.create(var)._get_all_var_data() for var in self._var_value],
449-
*[
450-
LiteralVar.create(var)._get_all_var_data()
451-
for var in self._var_value.values()
452-
],
466+
LiteralArrayVar._get_all_var_data_without_creating_var(self._var_value),
467+
LiteralArrayVar._get_all_var_data_without_creating_var(
468+
self._var_value.values()
469+
),
453470
self._var_data,
454471
)
455472

reflex/vars/sequence.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,23 @@ def _cached_var_name(self) -> str:
495495
+ "]"
496496
)
497497

498+
@classmethod
499+
def _get_all_var_data_without_creating_var(cls, value: Iterable) -> VarData | None:
500+
"""Get all the VarData associated with the Var without creating a Var.
501+
502+
Args:
503+
value: The value to get the VarData for.
504+
505+
Returns:
506+
The VarData associated with the Var.
507+
"""
508+
return VarData.merge(
509+
*[
510+
LiteralVar._get_all_var_data_without_creating_var_dispatch(element)
511+
for element in value
512+
]
513+
)
514+
498515
@cached_property_no_lock
499516
def _cached_get_all_var_data(self) -> VarData | None:
500517
"""Get all the VarData associated with the Var.
@@ -504,7 +521,7 @@ def _cached_get_all_var_data(self) -> VarData | None:
504521
"""
505522
return VarData.merge(
506523
*[
507-
LiteralVar.create(element)._get_all_var_data()
524+
LiteralVar._get_all_var_data_without_creating_var_dispatch(element)
508525
for element in self._var_value
509526
],
510527
self._var_data,
@@ -1147,6 +1164,20 @@ class LiteralStringVar(LiteralVar, StringVar[str]):
11471164

11481165
_var_value: str = dataclasses.field(default="")
11491166

1167+
@classmethod
1168+
def _get_all_var_data_without_creating_var(cls, value: str) -> VarData | None:
1169+
"""Get all the VarData associated with the Var without creating a Var.
1170+
1171+
Args:
1172+
value: The value to get the VarData for.
1173+
1174+
Returns:
1175+
The VarData associated with the Var.
1176+
"""
1177+
if REFLEX_VAR_OPENING_TAG not in value:
1178+
return None
1179+
return cls.create(value)._get_all_var_data()
1180+
11501181
@classmethod
11511182
def create(
11521183
cls,

0 commit comments

Comments
 (0)