solve more CI issues, down to 94 failures

This commit is contained in:
Khaleel Al-Adhami 2024-08-13 13:06:58 -07:00
parent 2c26dadacd
commit 2f49ce0201
21 changed files with 223 additions and 252 deletions

View File

@ -4,7 +4,6 @@ from __future__ import annotations
from typing import Optional
from reflex.components.base.bare import Bare
from reflex.components.component import Component
from reflex.components.core.cond import cond
from reflex.components.el.elements.typography import Div
@ -57,7 +56,7 @@ has_too_many_connection_errors: Var = ImmutableVar.create_safe(
).to(BooleanVar)
class WebsocketTargetURL(Bare):
class WebsocketTargetURL:
"""A component that renders the websocket target URL."""
def add_imports(self) -> ImportDict:

View File

@ -5,12 +5,12 @@
# ------------------------------------------------------
from typing import Any, Callable, Dict, Literal, Optional, Union, overload
from reflex.components.base.bare import Bare
from reflex.components.component import Component
from reflex.components.el.elements.typography import Div
from reflex.components.lucide.icon import Icon
from reflex.components.sonner.toast import Toaster, ToastProps
from reflex.event import EventHandler, EventSpec
from reflex.ivars.base import ImmutableVar
from reflex.style import Style
from reflex.utils.imports import ImportDict, ImportVar
from reflex.vars import Var, VarData
@ -22,63 +22,10 @@ connection_errors_count: Var
has_connection_errors: Var
has_too_many_connection_errors: Var
class WebsocketTargetURL(Bare):
class WebsocketTargetURL:
def add_imports(self) -> ImportDict: ...
@overload
@classmethod
def create( # type: ignore
cls,
*children,
contents: Optional[Union[Var[Any], Any]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
on_blur: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_click: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_context_menu: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_double_click: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_focus: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mount: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
on_scroll: Optional[Union[EventHandler, EventSpec, list, Callable, Var]] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, list, Callable, Var]
] = None,
**props,
) -> "WebsocketTargetURL":
"""Create a websocket target URL component.
Returns:
The websocket target URL component.
"""
...
def create(cls) -> ImmutableVar: ... # type: ignore
def default_connection_error() -> list[str | Var | Component]: ...

View File

@ -94,6 +94,9 @@ class Match(MemoizationLeaf):
if len([case for case in cases if not isinstance(case, tuple)]) > 1:
raise ValueError("rx.match can only have one default case.")
if not cases:
raise ValueError("rx.match should have at least one case.")
# Get the default case which should be the last non-tuple arg
if not isinstance(cases[-1], tuple):
default = cases.pop()

View File

@ -180,7 +180,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
kwargs.get("_var_data", self._var_data), merge_var_data
),
)
return type(self)(**field_values)
return dataclasses.replace(self, **field_values)
@classmethod
def create(
@ -780,10 +780,14 @@ class LiteralVar(ImmutableVar):
event_name = LiteralVar.create(
".".join(get_event_handler_parts(value.handler))
)
event_args = LiteralVar.create({name: value for name, value in value.args})
event_args = LiteralVar.create(
{str(name): value for name, value in value.args}
)
event_client_name = LiteralVar.create(value.client_handler_name)
return FunctionStringVar("Event").call(
event_name, event_args, event_client_name
event_name,
event_args,
*([event_client_name] if value.client_handler_name else []),
)
if isinstance(value, EventChain):
@ -944,7 +948,7 @@ def unionize(*args: Type) -> Type:
return Union[first, unionize(*rest)]
def figure_out_type(value: Any) -> Type:
def figure_out_type(value: Any) -> types.GenericType:
"""Figure out the type of the value.
Args:
@ -964,6 +968,8 @@ def figure_out_type(value: Any) -> Type:
unionize(*(figure_out_type(k) for k in value)),
unionize(*(figure_out_type(v) for v in value.values())),
]
if isinstance(value, Var):
return value._var_type
return type(value)

View File

@ -343,15 +343,10 @@ class LiteralObjectVar(LiteralVar, ObjectVar[OBJECT_TYPE]):
"""
return ImmutableVarData.merge(
*[
value._get_all_var_data()
LiteralVar.create(value)._get_all_var_data()
for value in self._var_value.values()
if isinstance(value, Var)
],
*[
key._get_all_var_data()
for key in self._var_value
if isinstance(key, Var)
],
*[LiteralVar.create(key)._get_all_var_data() for key in self._var_value],
self._var_data,
)

View File

@ -794,8 +794,15 @@ class LiteralStringVar(LiteralVar, StringVar):
strings_and_vals.append(value)
filtered_strings_and_vals = [
s for s in strings_and_vals if isinstance(s, Var) or s
]
if len(filtered_strings_and_vals) == 1:
return filtered_strings_and_vals[0].to(StringVar) # type: ignore
return ConcatVarOperation.create(
*filter(lambda s: isinstance(s, Var) or s, strings_and_vals),
*filtered_strings_and_vals,
_var_data=_var_data,
)
@ -853,7 +860,22 @@ class ConcatVarOperation(StringVar):
Returns:
The name of the var.
"""
return "(" + "+".join([str(element) for element in self._var_value]) + ")"
list_of_strs = [""]
for var in self._var_value:
if isinstance(var, LiteralStringVar):
list_of_strs[-1] += var._var_value
else:
list_of_strs.append(var)
list_of_strs.append("")
list_of_strs_filtered = [
str(LiteralVar.create(s)) for s in list_of_strs if isinstance(s, Var) or s
]
if len(list_of_strs_filtered) == 1:
return list_of_strs_filtered[0]
return "(" + "+".join(list_of_strs_filtered) + ")"
@cached_property
def _cached_get_all_var_data(self) -> ImmutableVarData | None:
@ -1201,11 +1223,7 @@ class LiteralArrayVar(LiteralVar, ArrayVar[ARRAY_VAR_TYPE]):
The VarData of the components and all of its children.
"""
return ImmutableVarData.merge(
*[
var._get_all_var_data()
for var in self._var_value
if isinstance(var, Var)
],
*[LiteralVar.create(var)._get_all_var_data() for var in self._var_value],
self._var_data,
)

View File

@ -132,11 +132,7 @@ def convert_item(
# Otherwise, convert to Var to collapse VarData encoded in f-string.
new_var = LiteralVar.create(style_item)
var_data = new_var._get_all_var_data() if new_var is not None else None
if var_data:
# The wrapped backtick is used to identify the Var for interpolation.
return f"{str(new_var)}", var_data
return style_item, None
return new_var, var_data
def convert_list(

View File

@ -771,8 +771,8 @@ class Var:
return (
self._var_name == other._var_name
and self._var_type == other._var_type
and ImmutableVarData.merge(self._var_data)
== ImmutableVarData.merge(other._var_data)
and ImmutableVarData.merge(self._get_all_var_data())
== ImmutableVarData.merge(other._get_all_var_data())
)
return (

View File

@ -6,8 +6,8 @@ from reflex.components.base.bare import Bare
@pytest.mark.parametrize(
"contents,expected",
[
("hello", "hello"),
("{}", "{}"),
("hello", '{"hello"}'),
("{}", '{"{}"}'),
(None, ""),
("${default_state.name}", "${default_state.name}"),
("{state.name}", "{state.name}"),

View File

@ -13,7 +13,7 @@ def test_script_inline():
assert render_dict["name"] == "Script"
assert not render_dict["contents"]
assert len(render_dict["children"]) == 1
assert render_dict["children"][0]["contents"] == "{`let x = 42`}"
assert render_dict["children"][0]["contents"] == '{"let x = 42"}'
def test_script_src():

View File

@ -9,8 +9,11 @@ from reflex.components.radix.themes.typography.text import Text
def test_websocket_target_url():
url = WebsocketTargetURL.create()
_imports = url._get_all_imports(collapse=True)
assert tuple(_imports) == ("/utils/state", "/env.json")
var_data = url._get_all_var_data()
assert var_data is not None
assert sorted(tuple((key for key, _ in var_data.imports))) == sorted(
("/utils/state", "/env.json")
)
def test_connection_banner():

View File

@ -3,7 +3,7 @@ import pytest
import reflex as rx
from reflex.components.datadisplay.code import CodeBlock
from reflex.constants.colors import Color
from reflex.vars import Var
from reflex.ivars.base import LiteralVar
class ColorState(rx.State):
@ -18,38 +18,38 @@ color_state_name = ColorState.get_full_name().replace(".", "__")
def create_color_var(color):
return Var.create(color)
return LiteralVar.create(color)
@pytest.mark.parametrize(
"color, expected",
[
(create_color_var(rx.color("mint")), "var(--mint-7)"),
(create_color_var(rx.color("mint", 3)), "var(--mint-3)"),
(create_color_var(rx.color("mint", 3, True)), "var(--mint-a3)"),
(create_color_var(rx.color("mint")), '"var(--mint-7)"'),
(create_color_var(rx.color("mint", 3)), '"var(--mint-3)"'),
(create_color_var(rx.color("mint", 3, True)), '"var(--mint-a3)"'),
(
create_color_var(rx.color(ColorState.color, ColorState.shade)), # type: ignore
f"var(--${{{color_state_name}.color}}-${{{color_state_name}.shade}})",
f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")',
),
(
create_color_var(rx.color(f"{ColorState.color}", f"{ColorState.shade}")), # type: ignore
f"var(--${{{color_state_name}.color}}-${{{color_state_name}.shade}})",
f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")',
),
(
create_color_var(
rx.color(f"{ColorState.color_part}ato", f"{ColorState.shade}") # type: ignore
),
f"var(--${{{color_state_name}.color_part}}ato-${{{color_state_name}.shade}})",
f'("var(--"+{str(color_state_name)}.color_part+"ato-"+{str(color_state_name)}.shade+")")',
),
(
create_color_var(f'{rx.color(ColorState.color, f"{ColorState.shade}")}'), # type: ignore
f"var(--${{{color_state_name}.color}}-${{{color_state_name}.shade}})",
f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")',
),
(
create_color_var(
f'{rx.color(f"{ColorState.color}", f"{ColorState.shade}")}' # type: ignore
),
f"var(--${{{color_state_name}.color}}-${{{color_state_name}.shade}})",
f'("var(--"+{str(color_state_name)}.color+"-"+{str(color_state_name)}.shade+")")',
),
],
)
@ -67,11 +67,11 @@ def test_color(color, expected):
[
(
rx.cond(True, rx.color("mint"), rx.color("tomato", 5)),
"{isTrue(true) ? `var(--mint-7)` : `var(--tomato-5)`}",
'(Boolean(true) ? "var(--mint-7)" : "var(--tomato-5)")',
),
(
rx.cond(True, rx.color(ColorState.color), rx.color(ColorState.color, 5)), # type: ignore
f"{{isTrue(true) ? `var(--${{{color_state_name}.color}}-7)` : `var(--${{{color_state_name}.color}}-5)`}}",
f'(Boolean(true) ? ("var(--"+{str(color_state_name)}.color+"-7)") : ("var(--"+{str(color_state_name)}.color+"-5)"))',
),
(
rx.match(
@ -80,9 +80,9 @@ def test_color(color, expected):
("second", rx.color("tomato", 5)),
rx.color(ColorState.color, 2), # type: ignore
),
"{(() => { switch (JSON.stringify(`condition`)) {case JSON.stringify(`first`): return (`var(--mint-7)`);"
" break;case JSON.stringify(`second`): return (`var(--tomato-5)`); break;default: "
f"return (`var(--${{{color_state_name}.color}}-2)`); break;}};}})()}}",
'(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"): return ("var(--mint-7)");'
' break;case JSON.stringify("second"): return ("var(--tomato-5)"); break;default: '
f'return (("var(--"+{str(color_state_name)}.color+"-2)")); break;}};}})()',
),
(
rx.match(
@ -91,10 +91,10 @@ def test_color(color, expected):
("second", rx.color(ColorState.color, 5)), # type: ignore
rx.color(ColorState.color, 2), # type: ignore
),
"{(() => { switch (JSON.stringify(`condition`)) {case JSON.stringify(`first`): "
f"return (`var(--${{{color_state_name}.color}}-7)`); break;case JSON.stringify(`second`): "
f"return (`var(--${{{color_state_name}.color}}-5)`); break;default: "
f"return (`var(--${{{color_state_name}.color}}-2)`); break;}};}})()}}",
'(() => { switch (JSON.stringify("condition")) {case JSON.stringify("first"): '
f'return (("var(--"+{str(color_state_name)}.color+"-7)")); break;case JSON.stringify("second"): '
f'return (("var(--"+{str(color_state_name)}.color+"-5)")); break;default: '
f'return (("var(--"+{str(color_state_name)}.color+"-2)")); break;}};}})()',
),
],
)
@ -105,9 +105,9 @@ def test_color_with_conditionals(cond_var, expected):
@pytest.mark.parametrize(
"color, expected",
[
(create_color_var(rx.color("red")), "{`var(--red-7)`}"),
(create_color_var(rx.color("green", shade=1)), "{`var(--green-1)`}"),
(create_color_var(rx.color("blue", alpha=True)), "{`var(--blue-a7)`}"),
(create_color_var(rx.color("red")), '"var(--red-7)"'),
(create_color_var(rx.color("green", shade=1)), '"var(--green-1)"'),
(create_color_var(rx.color("blue", alpha=True)), '"var(--blue-a7)"'),
("red", "red"),
("green", "green"),
("blue", "blue"),
@ -122,4 +122,4 @@ def test_radix_color(color, expected):
expected (str): The expected custom_style string, radix or literal
"""
code_block = CodeBlock.create("Hello World", background_color=color)
assert code_block.custom_style["backgroundColor"].__format__("") == expected # type: ignore
assert str(code_block.custom_style["backgroundColor"]) == expected # type: ignore

View File

@ -6,10 +6,10 @@ import pytest
from reflex.components.base.fragment import Fragment
from reflex.components.core.cond import Cond, cond
from reflex.components.radix.themes.typography.text import Text
from reflex.ivars.number import NumberVar
from reflex.ivars.base import ImmutableVar, LiteralVar, immutable_computed_var
from reflex.state import BaseState, State
from reflex.utils.format import format_state_name
from reflex.vars import Var, computed_var
from reflex.vars import Var
@pytest.fixture
@ -22,8 +22,8 @@ def cond_state(request):
def test_f_string_cond_interpolation():
# make sure backticks inside interpolation don't get escaped
var = Var.create(f"x {cond(True, 'a', 'b')}")
assert str(var) == "x ${isTrue(true) ? `a` : `b`}"
var = LiteralVar.create(f"x {cond(True, 'a', 'b')}")
assert str(var) == '("x "+(Boolean(true) ? "a" : "b"))'
@pytest.mark.parametrize(
@ -102,10 +102,10 @@ def test_prop_cond(c1: Any, c2: Any):
assert isinstance(prop_cond, Var)
if not isinstance(c1, Var):
c1 = json.dumps(c1).replace('"', "`")
c1 = json.dumps(c1)
if not isinstance(c2, Var):
c2 = json.dumps(c2).replace('"', "`")
assert str(prop_cond) == f"{{Boolean(true) ? {c1} : {c2}}}"
c2 = json.dumps(c2)
assert str(prop_cond) == f"(Boolean(true) ? {c1} : {c2})"
def test_cond_no_mix():
@ -134,23 +134,23 @@ def test_cond_computed_var():
"""Test if cond works with computed vars."""
class CondStateComputed(State):
@computed_var
@immutable_computed_var
def computed_int(self) -> int:
return 0
@computed_var
@immutable_computed_var
def computed_str(self) -> str:
return "a string"
comp = cond(True, CondStateComputed.computed_int, CondStateComputed.computed_str)
# TODO: shouln't this be a ComputedVar?
assert isinstance(comp, NumberVar)
assert isinstance(comp, ImmutableVar)
state_name = format_state_name(CondStateComputed.get_full_name())
assert (
str(comp)
== f"{{Boolean(true) ? {state_name}.computed_int : {state_name}.computed_str}}"
== f"(Boolean(true) ? {state_name}.computed_int : {state_name}.computed_str)"
)
assert comp._var_type == Union[int, str]

View File

@ -4,8 +4,8 @@ import pytest
import reflex as rx
from reflex.components.core.debounce import DEFAULT_DEBOUNCE_TIMEOUT
from reflex.ivars.base import LiteralVar
from reflex.state import BaseState
from reflex.vars import BaseVar
def test_create_no_child():
@ -60,11 +60,7 @@ def test_render_child_props():
assert "css" in tag.props and isinstance(tag.props["css"], rx.Var)
for prop in ["foo", "bar", "baz", "quuc"]:
assert prop in str(tag.props["css"])
assert tag.props["value"].equals(
BaseVar(
_var_name="real", _var_type=str, _var_is_local=True, _var_is_string=False
)
)
assert tag.props["value"].equals(LiteralVar.create("real"))
assert len(tag.props["onChange"].events) == 1
assert tag.props["onChange"].events[0].handler == S.on_change
assert tag.contents == ""
@ -156,11 +152,7 @@ def test_render_child_props_recursive():
assert "css" in tag.props and isinstance(tag.props["css"], rx.Var)
for prop in ["foo", "bar", "baz", "quuc"]:
assert prop in str(tag.props["css"])
assert tag.props["value"].equals(
BaseVar(
_var_name="outer", _var_type=str, _var_is_local=True, _var_is_string=False
)
)
assert tag.props["value"].equals(LiteralVar.create("outer"))
assert tag.props["forceNotifyOnBlur"]._var_name == "false"
assert tag.props["forceNotifyByEnter"]._var_name == "false"
assert tag.props["debounceTimeout"]._var_name == "42"

View File

@ -278,7 +278,7 @@ def test_foreach_component_styles():
)
)
component._add_style_recursive({box: {"color": "red"}})
assert 'css={{"color": "red"}}' in str(component)
assert 'css={({ ["color"] : "red" })}' in str(component)
def test_foreach_component_state():

View File

@ -15,8 +15,8 @@ def test_html_many_children():
def test_html_create():
html = Html.create("<p>Hello !</p>")
assert str(html.dangerouslySetInnerHTML) == '{"__html": "<p>Hello !</p>"}' # type: ignore
assert str(html.dangerouslySetInnerHTML) == '({ ["__html"] : "<p>Hello !</p>" })' # type: ignore
assert (
str(html)
== '<div className={`rx-Html`} dangerouslySetInnerHTML={{"__html": "<p>Hello !</p>"}}/>'
== '<div className={"rx-Html"} dangerouslySetInnerHTML={({ ["__html"] : "<p>Hello !</p>" })}/>'
)

View File

@ -1,4 +1,4 @@
from typing import Tuple
from typing import Dict, List, Tuple
import pytest
@ -6,7 +6,7 @@ import reflex as rx
from reflex.components.core.match import Match
from reflex.state import BaseState
from reflex.utils.exceptions import MatchTypeError
from reflex.vars import BaseVar
from reflex.vars import Var
class MatchState(BaseState):
@ -35,7 +35,7 @@ def test_match_components():
[match_child] = match_dict["children"]
assert match_child["name"] == "match"
assert str(match_child["cond"]) == f"{{{MatchState.get_name()}.value}}"
assert str(match_child["cond"]) == f"{MatchState.get_name()}.value"
match_cases = match_child["match_cases"]
assert len(match_cases) == 6
@ -44,7 +44,7 @@ def test_match_components():
assert match_cases[0][0]._var_type == int
first_return_value_render = match_cases[0][1].render()
assert first_return_value_render["name"] == "RadixThemesText"
assert first_return_value_render["children"][0]["contents"] == "{`first value`}"
assert first_return_value_render["children"][0]["contents"] == '{"first value"}'
assert match_cases[1][0]._var_name == "2"
assert match_cases[1][0]._var_type == int
@ -52,36 +52,36 @@ def test_match_components():
assert match_cases[1][1]._var_type == int
second_return_value_render = match_cases[1][2].render()
assert second_return_value_render["name"] == "RadixThemesText"
assert second_return_value_render["children"][0]["contents"] == "{`second value`}"
assert second_return_value_render["children"][0]["contents"] == '{"second value"}'
assert match_cases[2][0]._var_name == "[1, 2]"
assert match_cases[2][0]._var_type == list
assert match_cases[2][0]._var_type == List[int]
third_return_value_render = match_cases[2][1].render()
assert third_return_value_render["name"] == "RadixThemesText"
assert third_return_value_render["children"][0]["contents"] == "{`third value`}"
assert third_return_value_render["children"][0]["contents"] == '{"third value"}'
assert match_cases[3][0]._var_name == "random"
assert match_cases[3][0]._var_name == '"random"'
assert match_cases[3][0]._var_type == str
fourth_return_value_render = match_cases[3][1].render()
assert fourth_return_value_render["name"] == "RadixThemesText"
assert fourth_return_value_render["children"][0]["contents"] == "{`fourth value`}"
assert fourth_return_value_render["children"][0]["contents"] == '{"fourth value"}'
assert match_cases[4][0]._var_name == '{"foo": "bar"}'
assert match_cases[4][0]._var_type == dict
assert match_cases[4][0]._var_name == '({ ["foo"] : "bar" })'
assert match_cases[4][0]._var_type == Dict[str, str]
fifth_return_value_render = match_cases[4][1].render()
assert fifth_return_value_render["name"] == "RadixThemesText"
assert fifth_return_value_render["children"][0]["contents"] == "{`fifth value`}"
assert fifth_return_value_render["children"][0]["contents"] == '{"fifth value"}'
assert match_cases[5][0]._var_name == f"(({MatchState.get_name()}.num) + (1))"
assert match_cases[5][0]._var_name == f"({MatchState.get_name()}.num + 1)"
assert match_cases[5][0]._var_type == int
fifth_return_value_render = match_cases[5][1].render()
assert fifth_return_value_render["name"] == "RadixThemesText"
assert fifth_return_value_render["children"][0]["contents"] == "{`sixth value`}"
assert fifth_return_value_render["children"][0]["contents"] == '{"sixth value"}'
default = match_child["default"].render()
assert default["name"] == "RadixThemesText"
assert default["children"][0]["contents"] == "{`default value`}"
assert default["children"][0]["contents"] == '{"default value"}'
@pytest.mark.parametrize(
@ -99,12 +99,12 @@ def test_match_components():
(MatchState.string, f"{MatchState.value} - string"),
"default value",
),
f"(() => {{ switch (JSON.stringify({MatchState.get_name()}.value)) {{case JSON.stringify(1): return (`first`); break;case JSON.stringify(2): case JSON.stringify(3): return "
"(`second value`); break;case JSON.stringify([1, 2]): return (`third-value`); break;case JSON.stringify(`random`): "
'return (`fourth_value`); break;case JSON.stringify({"foo": "bar"}): return (`fifth value`); '
f"break;case JSON.stringify((({MatchState.get_name()}.num) + (1))): return (`sixth value`); break;case JSON.stringify(`${{{MatchState.get_name()}.value}} - string`): "
f"return ({MatchState.get_name()}.string); break;case JSON.stringify({MatchState.get_name()}.string): return (`${{{MatchState.get_name()}.value}} - string`); break;default: "
"return (`default value`); break;};})()",
f'(() => {{ switch (JSON.stringify({MatchState.get_name()}.value)) {{case JSON.stringify(1): return ("first"); break;case JSON.stringify(2): case JSON.stringify(3): return '
'("second value"); break;case JSON.stringify([1, 2]): return ("third-value"); break;case JSON.stringify("random"): '
'return ("fourth_value"); break;case JSON.stringify(({ ["foo"] : "bar" })): return ("fifth value"); '
f'break;case JSON.stringify(({MatchState.get_name()}.num + 1)): return ("sixth value"); break;case JSON.stringify(({MatchState.get_name()}.value+" - string")): '
f'return ({MatchState.get_name()}.string); break;case JSON.stringify({MatchState.get_name()}.string): return (({MatchState.get_name()}.value+" - string")); break;default: '
'return ("default value"); break;};})()',
),
(
(
@ -118,11 +118,11 @@ def test_match_components():
(MatchState.string, f"{MatchState.value} - string"),
MatchState.string,
),
f"(() => {{ switch (JSON.stringify({MatchState.get_name()}.value)) {{case JSON.stringify(1): return (`first`); break;case JSON.stringify(2): case JSON.stringify(3): return "
"(`second value`); break;case JSON.stringify([1, 2]): return (`third-value`); break;case JSON.stringify(`random`): "
'return (`fourth_value`); break;case JSON.stringify({"foo": "bar"}): return (`fifth value`); '
f"break;case JSON.stringify((({MatchState.get_name()}.num) + (1))): return (`sixth value`); break;case JSON.stringify(`${{{MatchState.get_name()}.value}} - string`): "
f"return ({MatchState.get_name()}.string); break;case JSON.stringify({MatchState.get_name()}.string): return (`${{{MatchState.get_name()}.value}} - string`); break;default: "
f'(() => {{ switch (JSON.stringify({MatchState.get_name()}.value)) {{case JSON.stringify(1): return ("first"); break;case JSON.stringify(2): case JSON.stringify(3): return '
'("second value"); break;case JSON.stringify([1, 2]): return ("third-value"); break;case JSON.stringify("random"): '
'return ("fourth_value"); break;case JSON.stringify(({ ["foo"] : "bar" })): return ("fifth value"); '
f'break;case JSON.stringify(({MatchState.get_name()}.num + 1)): return ("sixth value"); break;case JSON.stringify(({MatchState.get_name()}.value+" - string")): '
f'return ({MatchState.get_name()}.string); break;case JSON.stringify({MatchState.get_name()}.string): return (({MatchState.get_name()}.value+" - string")); break;default: '
f"return ({MatchState.get_name()}.string); break;}};}})()",
),
],
@ -135,7 +135,7 @@ def test_match_vars(cases, expected):
expected: The expected var full name.
"""
match_comp = Match.create(MatchState.value, *cases)
assert isinstance(match_comp, BaseVar)
assert isinstance(match_comp, Var)
assert match_comp._var_full_name == expected
@ -247,8 +247,8 @@ def test_match_case_tuple_elements(match_case):
(MatchState.num + 1, "black"),
rx.text("default value"),
),
"Match cases should have the same return types. Case 3 with return value `red` of type "
"<class 'reflex.vars.BaseVar'> is not <class 'reflex.components.component.BaseComponent'>",
'Match cases should have the same return types. Case 3 with return value `"red"` of type '
"<class 'reflex.ivars.sequence.LiteralStringVar'> is not <class 'reflex.components.component.BaseComponent'>",
),
(
(
@ -260,8 +260,8 @@ def test_match_case_tuple_elements(match_case):
([1, 2], rx.text("third value")),
rx.text("default value"),
),
"Match cases should have the same return types. Case 3 with return value `<RadixThemesText as={`p`}> {`first value`} </RadixThemesText>` "
"of type <class 'reflex.components.radix.themes.typography.text.Text'> is not <class 'reflex.vars.BaseVar'>",
'Match cases should have the same return types. Case 3 with return value `<RadixThemesText as={"p"}> {"first value"} </RadixThemesText>` '
"of type <class 'reflex.components.radix.themes.typography.text.Text'> is not <class 'reflex.vars.Var'>",
),
],
)

View File

@ -4,7 +4,7 @@ from reflex.components.datadisplay.code import CodeBlock
@pytest.mark.parametrize(
"theme, expected", [("light", "one-light"), ("dark", "one-dark")]
"theme, expected", [("light", '"one-light"'), ("dark", '"one-dark"')]
)
def test_code_light_dark_theme(theme, expected):
code_block = CodeBlock.create(theme=theme)

View File

@ -83,11 +83,11 @@ def test_upload_root_component_render(upload_root_component):
# upload
assert upload["name"] == "ReactDropzone"
assert upload["props"] == [
"id={`default`}",
'id={"default"}',
"multiple={true}",
"onDrop={e => setFilesById(filesById => {\n"
" const updatedFilesById = Object.assign({}, filesById);\n"
" updatedFilesById[`default`] = e;\n"
' updatedFilesById["default"] = e;\n'
" return updatedFilesById;\n"
" })\n"
" }",
@ -99,23 +99,23 @@ def test_upload_root_component_render(upload_root_component):
[box] = upload["children"]
assert box["name"] == "RadixThemesBox"
assert box["props"] == [
"className={`rx-Upload`}",
'css={{"border": "1px dotted black"}}',
'className={"rx-Upload"}',
'css={({ ["border"] : "1px dotted black" })}',
"{...getRootProps()}",
]
# input, button and text inside of box
[input, button, text] = box["children"]
assert input["name"] == "input"
assert input["props"] == ["type={`file`}", "{...getInputProps()}"]
assert input["props"] == ['type={"file"}', "{...getInputProps()}"]
assert button["name"] == "RadixThemesButton"
assert button["children"][0]["contents"] == "{`select file`}"
assert button["children"][0]["contents"] == '{"select file"}'
assert text["name"] == "RadixThemesText"
assert (
text["children"][0]["contents"]
== "{`Drag and drop files here or click to select files`}"
== '{"Drag and drop files here or click to select files"}'
)
@ -130,11 +130,11 @@ def test_upload_component_render(upload_component):
# upload
assert upload["name"] == "ReactDropzone"
assert upload["props"] == [
"id={`default`}",
'id={"default"}',
"multiple={true}",
"onDrop={e => setFilesById(filesById => {\n"
" const updatedFilesById = Object.assign({}, filesById);\n"
" updatedFilesById[`default`] = e;\n"
' updatedFilesById["default"] = e;\n'
" return updatedFilesById;\n"
" })\n"
" }",
@ -146,23 +146,23 @@ def test_upload_component_render(upload_component):
[box] = upload["children"]
assert box["name"] == "RadixThemesBox"
assert box["props"] == [
"className={`rx-Upload`}",
'css={{"border": "1px dotted black", "padding": "5em", "textAlign": "center"}}',
'className={"rx-Upload"}',
'css={({ ["border"] : "1px dotted black", ["padding"] : "5em", ["textAlign"] : "center" })}',
"{...getRootProps()}",
]
# input, button and text inside of box
[input, button, text] = box["children"]
assert input["name"] == "input"
assert input["props"] == ["type={`file`}", "{...getInputProps()}"]
assert input["props"] == ['type={"file"}', "{...getInputProps()}"]
assert button["name"] == "RadixThemesButton"
assert button["children"][0]["contents"] == "{`select file`}"
assert button["children"][0]["contents"] == '{"select file"}'
assert text["name"] == "RadixThemesText"
assert (
text["children"][0]["contents"]
== "{`Drag and drop files here or click to select files`}"
== '{"Drag and drop files here or click to select files"}'
)
@ -175,13 +175,13 @@ def test_upload_component_with_props_render(upload_component_with_props):
upload = upload_component_with_props.render()
assert upload["props"] == [
"id={`default`}",
'id={"default"}',
"maxFiles={2}",
"multiple={true}",
"noDrag={true}",
"onDrop={e => setFilesById(filesById => {\n"
" const updatedFilesById = Object.assign({}, filesById);\n"
" updatedFilesById[`default`] = e;\n"
' updatedFilesById["default"] = e;\n'
" return updatedFilesById;\n"
" })\n"
" }",
@ -193,11 +193,11 @@ def test_upload_component_id_with_special_chars(upload_component_id_special):
upload = upload_component_id_special.render()
assert upload["props"] == [
r"id={`#spec!\`al-_98ID`}",
r'id={"#spec!`al-_98ID"}',
"multiple={true}",
"onDrop={e => setFilesById(filesById => {\n"
" const updatedFilesById = Object.assign({}, filesById);\n"
" updatedFilesById[`#spec!\\`al-_98ID`] = e;\n"
' updatedFilesById["#spec!`al-_98ID"] = e;\n'
" return updatedFilesById;\n"
" })\n"
" }",

View File

@ -36,9 +36,13 @@ def test_set_src_str():
"""Test that setting the src works."""
image = rx.image(src="pic2.jpeg")
# when using next/image, we explicitly create a _var_is_str Var
# assert str(image.src) == "{`pic2.jpeg`}" # type: ignore
assert str(image.src) in (
'"pic2.jpeg"',
"'pic2.jpeg'",
"`pic2.jpeg`",
)
# For plain rx.el.img, an explicit var is not created, so the quoting happens later
assert str(image.src) == "pic2.jpeg" # type: ignore
# assert str(image.src) == "pic2.jpeg" # type: ignore
def test_set_src_img(pil_image: Img):

View File

@ -17,6 +17,7 @@ from reflex.components.component import (
)
from reflex.constants import EventTriggers
from reflex.event import EventChain, EventHandler, parse_args_spec
from reflex.ivars.base import LiteralVar
from reflex.state import BaseState
from reflex.style import Style
from reflex.utils import imports
@ -229,8 +230,8 @@ def test_set_style_attrs(component1):
component1: A test component.
"""
component = component1(color="white", text_align="center")
assert component.style["color"] == "white"
assert component.style["textAlign"] == "center"
assert str(component.style["color"]) == '"white"'
assert str(component.style["textAlign"]) == '"center"'
def test_custom_attrs(component1):
@ -254,7 +255,10 @@ def test_create_component(component1):
c = component1.create(*children, **attrs)
assert isinstance(c, component1)
assert c.children == children
assert c.style == {"color": "white", "textAlign": "center"}
assert (
str(LiteralVar.create(c.style))
== '({ ["color"] : "white", ["textAlign"] : "center" })'
)
@pytest.mark.parametrize(
@ -418,8 +422,8 @@ def test_add_style(component1, component2):
}
c1 = component1()._add_style_recursive(style) # type: ignore
c2 = component2()._add_style_recursive(style) # type: ignore
assert c1.style["color"] == "white"
assert c2.style["color"] == "black"
assert str(c1.style["color"]) == '"white"'
assert str(c2.style["color"]) == '"black"'
def test_add_style_create(component1, component2):
@ -435,8 +439,8 @@ def test_add_style_create(component1, component2):
}
c1 = component1()._add_style_recursive(style) # type: ignore
c2 = component2()._add_style_recursive(style) # type: ignore
assert c1.style["color"] == "white"
assert c2.style["color"] == "black"
assert str(c1.style["color"]) == '"white"'
assert str(c2.style["color"]) == '"black"'
def test_get_imports(component1, component2):
@ -606,8 +610,8 @@ def test_create_filters_none_props(test_component):
assert "prop4" not in component.get_props()
# Assert that the style prop is present in the component's props
assert component.style["color"] == "white"
assert component.style["text-align"] == "center"
assert str(component.style["color"]) == '"white"'
assert str(component.style["text-align"]) == '"center"'
@pytest.mark.parametrize("children", [((None,),), ("foo", ("bar", (None,)))])
@ -634,7 +638,7 @@ def test_component_create_unallowed_types(children, test_component):
"children": [
{
"name": "RadixThemesText",
"props": ["as={`p`}"],
"props": ['as={"p"}'],
"contents": "",
"args": None,
"special_props": set(),
@ -642,7 +646,7 @@ def test_component_create_unallowed_types(children, test_component):
{
"name": "",
"props": [],
"contents": "{`first_text`}",
"contents": '{"first_text"}',
"args": None,
"special_props": set(),
"children": [],
@ -669,7 +673,7 @@ def test_component_create_unallowed_types(children, test_component):
"args": None,
"autofocus": False,
"children": [],
"contents": "{`first_text`}",
"contents": '{"first_text"}',
"name": "",
"props": [],
"special_props": set(),
@ -677,7 +681,7 @@ def test_component_create_unallowed_types(children, test_component):
],
"contents": "",
"name": "RadixThemesText",
"props": ["as={`p`}"],
"props": ['as={"p"}'],
"special_props": set(),
},
{
@ -688,7 +692,7 @@ def test_component_create_unallowed_types(children, test_component):
"args": None,
"autofocus": False,
"children": [],
"contents": "{`second_text`}",
"contents": '{"second_text"}',
"name": "",
"props": [],
"special_props": set(),
@ -696,7 +700,7 @@ def test_component_create_unallowed_types(children, test_component):
],
"contents": "",
"name": "RadixThemesText",
"props": ["as={`p`}"],
"props": ['as={"p"}'],
"special_props": set(),
},
],
@ -720,7 +724,7 @@ def test_component_create_unallowed_types(children, test_component):
"args": None,
"autofocus": False,
"children": [],
"contents": "{`first_text`}",
"contents": '{"first_text"}',
"name": "",
"props": [],
"special_props": set(),
@ -728,7 +732,7 @@ def test_component_create_unallowed_types(children, test_component):
],
"contents": "",
"name": "RadixThemesText",
"props": ["as={`p`}"],
"props": ['as={"p"}'],
"special_props": set(),
},
{
@ -747,7 +751,7 @@ def test_component_create_unallowed_types(children, test_component):
"args": None,
"autofocus": False,
"children": [],
"contents": "{`second_text`}",
"contents": '{"second_text"}',
"name": "",
"props": [],
"special_props": set(),
@ -755,7 +759,7 @@ def test_component_create_unallowed_types(children, test_component):
],
"contents": "",
"name": "RadixThemesText",
"props": ["as={`p`}"],
"props": ['as={"p"}'],
"special_props": set(),
}
],
@ -824,9 +828,9 @@ def test_component_event_trigger_arbitrary_args():
comp = C1.create(on_foo=C1State.mock_handler)
assert comp.render()["props"][0] == (
"onFoo={(__e,_alpha,_bravo,_charlie) => addEvents("
f'[Event("{C1State.get_full_name()}.mock_handler", {{_e:__e.target.value,_bravo:_bravo["nested"],_charlie:((_charlie.custom) + (42))}})], '
"[__e,_alpha,_bravo,_charlie], {})}"
"onFoo={((__e, _alpha, _bravo, _charlie) => ((addEvents("
f'[(Event("{C1State.get_full_name()}.mock_handler", ({{ ["_e"] : __e["target"]["value"], ["_bravo"] : _bravo["nested"], ["_charlie"] : (_charlie["custom"] + 42) }})))], '
"[__e, _alpha, _bravo, _charlie], ({ })))))}"
)
@ -1002,10 +1006,10 @@ def test_component_with_only_valid_children(fixture, request):
@pytest.mark.parametrize(
"component,rendered",
[
(rx.text("hi"), "<RadixThemesText as={`p`}>\n {`hi`}\n</RadixThemesText>"),
(rx.text("hi"), '<RadixThemesText as={"p"}>\n {"hi"}\n</RadixThemesText>'),
(
rx.box(rx.chakra.heading("test", size="md")),
"<RadixThemesBox>\n <Heading size={`md`}>\n {`test`}\n</Heading>\n</RadixThemesBox>",
'<RadixThemesBox>\n <Heading size={"md"}>\n {"test"}\n</Heading>\n</RadixThemesBox>',
),
],
)
@ -1060,7 +1064,7 @@ def test_stateful_banner():
assert isinstance(stateful_component, StatefulComponent)
TEST_VAR = Var.create_safe("test")._replace(
TEST_VAR = LiteralVar.create("test")._replace(
merge_var_data=VarData(
hooks={"useTest": None},
imports={"test": [ImportVar(tag="test")]},
@ -1068,36 +1072,36 @@ TEST_VAR = Var.create_safe("test")._replace(
interpolations=[],
)
)
FORMATTED_TEST_VAR = Var.create(f"foo{TEST_VAR}bar")
FORMATTED_TEST_VAR = LiteralVar.create(f"foo{TEST_VAR}bar")
STYLE_VAR = TEST_VAR._replace(_var_name="style", _var_is_local=False)
EVENT_CHAIN_VAR = TEST_VAR._replace(_var_type=EventChain)
ARG_VAR = Var.create("arg")
TEST_VAR_DICT_OF_DICT = Var.create_safe({"a": {"b": "test"}})._replace(
TEST_VAR_DICT_OF_DICT = LiteralVar.create({"a": {"b": "test"}})._replace(
merge_var_data=TEST_VAR._var_data
)
FORMATTED_TEST_VAR_DICT_OF_DICT = Var.create_safe({"a": {"b": f"footestbar"}})._replace(
FORMATTED_TEST_VAR_DICT_OF_DICT = LiteralVar.create(
{"a": {"b": f"footestbar"}}
)._replace(merge_var_data=TEST_VAR._var_data)
TEST_VAR_LIST_OF_LIST = LiteralVar.create([["test"]])._replace(
merge_var_data=TEST_VAR._var_data
)
FORMATTED_TEST_VAR_LIST_OF_LIST = LiteralVar.create([["footestbar"]])._replace(
merge_var_data=TEST_VAR._var_data
)
TEST_VAR_LIST_OF_LIST = Var.create_safe([["test"]])._replace(
merge_var_data=TEST_VAR._var_data
)
FORMATTED_TEST_VAR_LIST_OF_LIST = Var.create_safe([["footestbar"]])._replace(
TEST_VAR_LIST_OF_LIST_OF_LIST = LiteralVar.create([[["test"]]])._replace(
merge_var_data=TEST_VAR._var_data
)
FORMATTED_TEST_VAR_LIST_OF_LIST_OF_LIST = LiteralVar.create(
[[["footestbar"]]]
)._replace(merge_var_data=TEST_VAR._var_data)
TEST_VAR_LIST_OF_LIST_OF_LIST = Var.create_safe([[["test"]]])._replace(
TEST_VAR_LIST_OF_DICT = LiteralVar.create([{"a": "test"}])._replace(
merge_var_data=TEST_VAR._var_data
)
FORMATTED_TEST_VAR_LIST_OF_LIST_OF_LIST = Var.create_safe([[["footestbar"]]])._replace(
merge_var_data=TEST_VAR._var_data
)
TEST_VAR_LIST_OF_DICT = Var.create_safe([{"a": "test"}])._replace(
merge_var_data=TEST_VAR._var_data
)
FORMATTED_TEST_VAR_LIST_OF_DICT = Var.create_safe([{"a": "footestbar"}])._replace(
FORMATTED_TEST_VAR_LIST_OF_DICT = LiteralVar.create([{"a": "footestbar"}])._replace(
merge_var_data=TEST_VAR._var_data
)
@ -1186,7 +1190,7 @@ class EventState(rx.State):
id="direct-special_props",
),
pytest.param(
rx.fragment(special_props={Var.create(f"foo{TEST_VAR}bar")}),
rx.fragment(special_props={LiteralVar.create(f"foo{TEST_VAR}bar")}),
[FORMATTED_TEST_VAR],
id="fstring-special_props",
),
@ -1295,6 +1299,8 @@ def test_get_vars(component, exp_vars):
comp_vars,
sorted(exp_vars, key=lambda v: v._var_name),
):
print(str(comp_var), str(exp_var))
print(comp_var._get_all_var_data(), exp_var._get_all_var_data())
assert comp_var.equals(exp_var)
@ -1334,9 +1340,11 @@ def test_instantiate_all_components():
continue
component = getattr(
rx,
component_name
if not isinstance(component_name, tuple)
else component_name[1],
(
component_name
if not isinstance(component_name, tuple)
else component_name[1]
),
)
if isinstance(component, type) and issubclass(component, Component):
component.create()
@ -1594,14 +1602,14 @@ def test_rename_props():
c1 = C1.create(prop1="prop1_1", prop2="prop2_1")
rendered_c1 = c1.render()
assert "renamed_prop1={`prop1_1`}" in rendered_c1["props"]
assert "renamed_prop2={`prop2_1`}" in rendered_c1["props"]
assert 'renamed_prop1={"prop1_1"}' in rendered_c1["props"]
assert 'renamed_prop2={"prop2_1"}' in rendered_c1["props"]
c2 = C2.create(prop1="prop1_2", prop2="prop2_2", prop3="prop3_2")
rendered_c2 = c2.render()
assert "renamed_prop1={`prop1_2`}" in rendered_c2["props"]
assert "subclass_prop2={`prop2_2`}" in rendered_c2["props"]
assert "renamed_prop3={`prop3_2`}" in rendered_c2["props"]
assert 'renamed_prop1={"prop1_2"}' in rendered_c2["props"]
assert 'subclass_prop2={"prop2_2"}' in rendered_c2["props"]
assert 'renamed_prop3={"prop3_2"}' in rendered_c2["props"]
def test_deprecated_props(capsys):
@ -1625,9 +1633,9 @@ def test_deprecated_props(capsys):
assert not out_err.out
c1_1_render = c1_1.render()
assert "type={`type1`}" in c1_1_render["props"]
assert "min={`min1`}" in c1_1_render["props"]
assert "max={`max1`}" in c1_1_render["props"]
assert 'type={"type1"}' in c1_1_render["props"]
assert 'min={"min1"}' in c1_1_render["props"]
assert 'max={"max1"}' in c1_1_render["props"]
# Deprecation warning is emitted with underscore suffix,
# but the component still works.
@ -1637,9 +1645,9 @@ def test_deprecated_props(capsys):
assert not out_err.err
c1_2_render = c1_2.render()
assert "type={`type2`}" in c1_2_render["props"]
assert "min={`min2`}" in c1_2_render["props"]
assert "max={`max2`}" in c1_2_render["props"]
assert 'type={"type2"}' in c1_2_render["props"]
assert 'min={"min2"}' in c1_2_render["props"]
assert 'max={"max2"}' in c1_2_render["props"]
class C2(Component):
tag = "C2"
@ -1655,9 +1663,9 @@ def test_deprecated_props(capsys):
assert not out_err.out
c2_1_render = c2_1.render()
assert "type={`type1`}" in c2_1_render["props"]
assert "min={`min1`}" in c2_1_render["props"]
assert "max={`max1`}" in c2_1_render["props"]
assert 'type={"type1"}' in c2_1_render["props"]
assert 'min={"min1"}' in c2_1_render["props"]
assert 'max={"max1"}' in c2_1_render["props"]
def test_custom_component_get_imports():
@ -2007,11 +2015,11 @@ def test_add_style_embedded_vars(test_state: BaseState):
Args:
test_state: A test state.
"""
v0 = Var.create_safe("parent")._replace(
v0 = LiteralVar.create("parent")._replace(
merge_var_data=VarData(hooks={"useParent": None}), # type: ignore
)
v1 = rx.color("plum", 10)
v2 = Var.create_safe("text")._replace(
v2 = LiteralVar.create("text")._replace(
merge_var_data=VarData(hooks={"useText": None}), # type: ignore
)
@ -2044,7 +2052,7 @@ def test_add_style_embedded_vars(test_state: BaseState):
assert "useParent" in page._get_all_hooks_internal()
assert (
str(page).count(
f'css={{{{"fakeParent": "parent", "color": "var(--plum-10)", "fake": "text", "margin": `${{{test_state.get_name()}.num}}%`}}}}'
f'css={{({{ ["fakeParent"] : "parent", ["color"] : "var(--plum-10)", ["fake"] : "text", ["margin"] : ({test_state.get_name()}.num+"%") }})}}'
)
== 1
)
@ -2065,10 +2073,10 @@ def test_add_style_foreach():
assert len(page.children[0].children) == 1
# Expect the style to be added to the child of the foreach
assert 'css={{"color": "red"}}' in str(page.children[0].children[0])
assert 'css={({ ["color"] : "red" })}' in str(page.children[0].children[0])
# Expect only one instance of this CSS dict in the rendered page
assert str(page).count('css={{"color": "red"}}') == 1
assert str(page).count('css={({ ["color"] : "red" })}') == 1
class TriggerState(rx.State):