Skip to content

Commit

Permalink
fix dynamic icons for underscore and positional argument (#4767)
Browse files Browse the repository at this point in the history
* fix dynamic icons for underscore and positional argument

* use no return
  • Loading branch information
adhami3310 authored Feb 7, 2025
1 parent b3b79a6 commit f322047
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 23 deletions.
4 changes: 1 addition & 3 deletions reflex/components/core/sticky.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ def add_style(self):
default=True,
global_ref=False,
)
localhost_hostnames = Var.create(
["localhost", "127.0.0.1", "[::1]"]
).guess_type()
localhost_hostnames = Var.create(["localhost", "127.0.0.1", "[::1]"])
is_localhost_expr = localhost_hostnames.contains(
Var("window.location.hostname", _var_type=str).guess_type(),
)
Expand Down
14 changes: 11 additions & 3 deletions reflex/components/lucide/icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from reflex.utils import format
from reflex.utils.imports import ImportVar
from reflex.vars.base import LiteralVar, Var
from reflex.vars.sequence import LiteralStringVar
from reflex.vars.sequence import LiteralStringVar, StringVar


class LucideIconComponent(Component):
Expand Down Expand Up @@ -40,7 +40,12 @@ def create(cls, *children, **props) -> Component:
The created component.
"""
if children:
if len(children) == 1 and isinstance(children[0], str):
if len(children) == 1:
child = Var.create(children[0]).guess_type()
if not isinstance(child, StringVar):
raise AttributeError(
f"Icon name must be a string, got {children[0]._var_type if isinstance(children[0], Var) else children[0]}"
)
props["tag"] = children[0]
else:
raise AttributeError(
Expand All @@ -56,7 +61,10 @@ def create(cls, *children, **props) -> Component:
else:
raise TypeError(f"Icon name must be a string, got {type(tag)}")
elif isinstance(tag, Var):
return DynamicIcon.create(name=tag, **props)
tag_stringified = tag.guess_type()
if not isinstance(tag_stringified, StringVar):
raise TypeError(f"Icon name must be a string, got {tag._var_type}")
return DynamicIcon.create(name=tag_stringified.replace("_", "-"), **props)

if (
not isinstance(tag, str)
Expand Down
34 changes: 25 additions & 9 deletions reflex/vars/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@
if TYPE_CHECKING:
from reflex.state import BaseState

from .number import BooleanVar, NumberVar
from .object import ObjectVar
from .sequence import ArrayVar, StringVar
from .number import BooleanVar, LiteralBooleanVar, LiteralNumberVar, NumberVar
from .object import LiteralObjectVar, ObjectVar
from .sequence import ArrayVar, LiteralArrayVar, LiteralStringVar, StringVar


VAR_TYPE = TypeVar("VAR_TYPE", covariant=True)
Expand Down Expand Up @@ -573,29 +573,45 @@ def _replace(

return value_with_replaced

@overload
@classmethod
def create( # pyright: ignore[reportOverlappingOverload]
cls,
value: NoReturn,
_var_data: VarData | None = None,
) -> Var[Any]: ...

@overload
@classmethod
def create( # pyright: ignore[reportOverlappingOverload]
cls,
value: bool,
_var_data: VarData | None = None,
) -> BooleanVar: ...
) -> LiteralBooleanVar: ...

@overload
@classmethod
def create(
cls,
value: int,
_var_data: VarData | None = None,
) -> NumberVar[int]: ...
) -> LiteralNumberVar[int]: ...

@overload
@classmethod
def create(
cls,
value: float,
_var_data: VarData | None = None,
) -> NumberVar[float]: ...
) -> LiteralNumberVar[float]: ...

@overload
@classmethod
def create( # pyright: ignore [reportOverlappingOverload]
cls,
value: str,
_var_data: VarData | None = None,
) -> LiteralStringVar: ...

@overload
@classmethod
Expand All @@ -611,23 +627,23 @@ def create( # pyright: ignore[reportOverlappingOverload]
cls,
value: None,
_var_data: VarData | None = None,
) -> NoneVar: ...
) -> LiteralNoneVar: ...

@overload
@classmethod
def create(
cls,
value: MAPPING_TYPE,
_var_data: VarData | None = None,
) -> ObjectVar[MAPPING_TYPE]: ...
) -> LiteralObjectVar[MAPPING_TYPE]: ...

@overload
@classmethod
def create(
cls,
value: SEQUENCE_TYPE,
_var_data: VarData | None = None,
) -> ArrayVar[SEQUENCE_TYPE]: ...
) -> LiteralArrayVar[SEQUENCE_TYPE]: ...

@overload
@classmethod
Expand Down
2 changes: 1 addition & 1 deletion reflex/vars/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ def boolean_not_operation(value: BooleanVar):
frozen=True,
slots=True,
)
class LiteralNumberVar(LiteralVar, NumberVar):
class LiteralNumberVar(LiteralVar, NumberVar[NUMBER_T]):
"""Base class for immutable literal number vars."""

_var_value: float | int = dataclasses.field(default=0)
Expand Down
31 changes: 29 additions & 2 deletions reflex/vars/sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,33 @@ def __ge__(self, other: Any):

return string_ge_operation(self, other)

@overload
def replace( # pyright: ignore [reportOverlappingOverload]
self, search_value: StringVar | str, new_value: StringVar | str
) -> StringVar: ...

@overload
def replace(
self, search_value: Any, new_value: Any
) -> CustomVarOperationReturn[StringVar]: ...

def replace(self, search_value: Any, new_value: Any) -> StringVar: # pyright: ignore [reportInconsistentOverload]
"""Replace a string with a value.
Args:
search_value: The string to search.
new_value: The value to be replaced with.
Returns:
The string replace operation.
"""
if not isinstance(search_value, (StringVar, str)):
raise_unsupported_operand_types("replace", (type(self), type(search_value)))
if not isinstance(new_value, (StringVar, str)):
raise_unsupported_operand_types("replace", (type(self), type(new_value)))

return string_replace_operation(self, search_value, new_value)


@var_operation
def string_lt_operation(lhs: StringVar[Any] | str, rhs: StringVar[Any] | str):
Expand Down Expand Up @@ -570,7 +597,7 @@ def array_join_operation(array: ArrayVar, sep: StringVar[Any] | str = ""):

@var_operation
def string_replace_operation(
string: StringVar, search_value: StringVar | str, new_value: StringVar | str
string: StringVar[Any], search_value: StringVar | str, new_value: StringVar | str
):
"""Replace a string with a value.
Expand All @@ -583,7 +610,7 @@ def string_replace_operation(
The string replace operation.
"""
return var_operation_return(
js_expression=f"{string}.replace({search_value}, {new_value})",
js_expression=f"{string}.replaceAll({search_value}, {new_value})",
var_type=str,
)

Expand Down
5 changes: 4 additions & 1 deletion tests/units/components/datadisplay/test_shiki_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from reflex.components.radix.themes.layout.box import Box
from reflex.style import Style
from reflex.vars import Var
from reflex.vars.base import LiteralVar


@pytest.mark.parametrize(
Expand Down Expand Up @@ -99,7 +100,9 @@ def test_create_shiki_code_block(

applied_styles = component.style
for key, value in expected_styles.items():
assert Var.create(applied_styles[key])._var_value == value
var = Var.create(applied_styles[key])
assert isinstance(var, LiteralVar)
assert var._var_value == value


@pytest.mark.parametrize(
Expand Down
8 changes: 4 additions & 4 deletions tests/units/vars/test_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ class ObjectState(rx.State):


@pytest.mark.parametrize("type_", [Base, Bare, SqlaModel, Dataclass])
def test_var_create(type_: GenericType) -> None:
def test_var_create(type_: type[Base | Bare | SqlaModel | Dataclass]) -> None:
my_object = type_()
var = Var.create(my_object)
assert var._var_type is type_

assert isinstance(var, ObjectVar)
quantity = var.quantity
assert quantity._var_type is int

Expand All @@ -94,12 +94,12 @@ def test_literal_create(type_: GenericType) -> None:


@pytest.mark.parametrize("type_", [Base, Bare, SqlaModel, Dataclass])
def test_guess(type_: GenericType) -> None:
def test_guess(type_: type[Base | Bare | SqlaModel | Dataclass]) -> None:
my_object = type_()
var = Var.create(my_object)
var = var.guess_type()
assert var._var_type is type_

assert isinstance(var, ObjectVar)
quantity = var.quantity
assert quantity._var_type is int

Expand Down

0 comments on commit f322047

Please sign in to comment.