Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/reflex-base/news/+frozenset-literal.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`LiteralVar.create` now accepts a `frozenset`, rendered as an array like a `set`, with its element type inferred so `rx.foreach` and array operations over it are typed.
9 changes: 6 additions & 3 deletions packages/reflex-base/src/reflex_base/vars/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2185,7 +2185,7 @@ def figure_out_type(value: Any) -> types.GenericType:
Returns:
The type of the value.
"""
if isinstance(value, (list, set, tuple, Mapping, Var)):
if isinstance(value, (list, set, frozenset, tuple, Mapping, Var)):
if isinstance(value, Var):
return value._var_type
if has_args(value_type := type(value)):
Expand All @@ -2194,8 +2194,11 @@ def figure_out_type(value: Any) -> types.GenericType:
if not value:
return Sequence[NoReturn]
return Sequence[unionize(*{figure_out_type(v) for v in value[:100]})]
if isinstance(value, set):
return set[unionize(*{figure_out_type(v) for v in value})]
if isinstance(value, (set, frozenset)):
element_type = unionize(*{figure_out_type(v) for v in value})
if isinstance(value, frozenset):
return frozenset[element_type]
return set[element_type]
if isinstance(value, tuple):
if not value:
return tuple[NoReturn, ...]
Expand Down
3 changes: 2 additions & 1 deletion packages/reflex-base/src/reflex_base/vars/sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
VALUE_TYPE = TypeVar("VALUE_TYPE")


class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)):
class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set, frozenset)):
Comment thread
masenf marked this conversation as resolved.
Comment thread
masenf marked this conversation as resolved.
"""Base class for immutable array vars."""

def join(self, sep: StringVar | str = "") -> StringVar:
Expand Down Expand Up @@ -1920,6 +1920,7 @@ def _determine_value_of_array_index(
Iterable,
list,
set,
frozenset,
collections.abc.Sequence,
collections.abc.Iterable,
]:
Expand Down
15 changes: 15 additions & 0 deletions tests/units/test_var.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
ConcatVarOperation,
LiteralArrayVar,
LiteralStringVar,
StringVar,
)

import reflex as rx
Expand Down Expand Up @@ -421,6 +422,19 @@ def test_date_comparison_uses_compare_datetime():
assert str(lhs == rhs) == '(compareDatetime("2024-01-01", "2024-01-02") === 0)'


def test_frozenset_literal_types_its_elements():
"""A frozen set literal infers its element type like a set does."""
# The static array bound is Sequence, which no set satisfies; see the PR.
var = cast(ArrayVar, v(frozenset({"a"})))

assert var._var_type == frozenset[str]
assert isinstance(var[0], StringVar)
assert re.fullmatch(
r'\["a"\]\.map\(\(\((\w+)\) => \1\.toUpperCase\(\)\)\)',
str(var.map(lambda item: item.upper())),
)


def test_datetime_equality_with_other_type_uses_default_comparison():
value = v(datetime(2024, 1, 1))
expected_equality = (
Expand All @@ -436,6 +450,7 @@ def test_datetime_equality_with_other_type_uses_default_comparison():
[
(v([1, 2, 3]), "[1, 2, 3]"),
(v({1, 2, 3}), "[1, 2, 3]"),
(v(frozenset({1, 2, 3})), "[1, 2, 3]"),
(v(["1", "2", "3"]), '["1", "2", "3"]'),
(
Var(_js_expr="foo")._var_set_state("state").to(list),
Expand Down
Loading