From d3b12a84fa6450d1d007331b31ac968ac33a0e4e Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami <khaleel.aladhami@gmail.com> Date: Thu, 23 Jan 2025 11:54:45 -0800 Subject: [PATCH] optimize var operation output --- reflex/components/core/cond.py | 20 +-- reflex/vars/base.py | 166 +++++++----------- reflex/vars/function.py | 94 ++++++++-- tests/units/components/core/test_colors.py | 6 +- tests/units/components/core/test_cond.py | 16 +- tests/units/components/core/test_match.py | 4 +- .../components/markdown/test_markdown.py | 8 +- tests/units/test_var.py | 141 ++++----------- 8 files changed, 202 insertions(+), 253 deletions(-) diff --git a/reflex/components/core/cond.py b/reflex/components/core/cond.py index 0ab543248..153953668 100644 --- a/reflex/components/core/cond.py +++ b/reflex/components/core/cond.py @@ -9,8 +9,7 @@ from reflex.components.component import BaseComponent, Component from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode from reflex.utils import types from reflex.utils.types import safe_issubclass -from reflex.vars.base import LiteralVar, ReflexCallable, Var -from reflex.vars.function import ArgsFunctionOperation +from reflex.vars.base import LiteralVar, Var from reflex.vars.number import ternary_operation @@ -53,23 +52,12 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var: if c2 is None: raise ValueError("For conditional vars, the second argument must be set.") - c1 = Var.create(c1) - c2 = Var.create(c2) - # Create the conditional var. return ternary_operation( cond_var.bool(), - ArgsFunctionOperation.create( - (), - c1, - _var_type=ReflexCallable[[], c1._var_type], - ), - ArgsFunctionOperation.create( - (), - c2, - _var_type=ReflexCallable[[], c2._var_type], - ), - ).call() + c1, + c2, + ) @overload diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 990a19e31..4502ec7bd 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -1788,7 +1788,7 @@ def var_operation( ```python @var_operation def add(a: Var[int], b: Var[int]): - return custom_var_operation(f"{a} + {b}") + return var_operation_return(f"{a} + {b}") ``` Args: @@ -1854,6 +1854,9 @@ def var_operation( custom_operation_return = func(*arg_vars) + def simplified_operation(*args): + return func(*args)._js_expr + args_operation = ArgsFunctionOperation.create( tuple(map(str, arg_vars)), custom_operation_return, @@ -1867,6 +1870,7 @@ def var_operation( function_name=func_name, type_computer=custom_operation_return._type_computer, _raw_js_function=custom_operation_return._raw_js_function, + _original_var_operation=simplified_operation, _var_type=ReflexCallable[ tuple( arg_python_type @@ -3222,15 +3226,7 @@ def and_operation(a: Var | Any, b: Var | Any) -> Var: Returns: The result of the logical AND operation. """ - from .function import ArgsFunctionOperation - - a = Var.create(a) - b = Var.create(b) - - return _and_func_operation( - ArgsFunctionOperation.create((), a, _var_type=ReflexCallable[[], a._var_type]), - ArgsFunctionOperation.create((), b, _var_type=ReflexCallable[[], b._var_type]), - ) + return _and_operation(a, b) def or_operation(a: Var | Any, b: Var | Any) -> Var: @@ -3243,99 +3239,7 @@ def or_operation(a: Var | Any, b: Var | Any) -> Var: Returns: The result of the logical OR operation. """ - from .function import ArgsFunctionOperation - - a = Var.create(a) - b = Var.create(b) - - return _or_func_operation( - ArgsFunctionOperation.create((), a, _var_type=ReflexCallable[[], a._var_type]), - ArgsFunctionOperation.create((), b, _var_type=ReflexCallable[[], b._var_type]), - ) - - -T_LOGICAL = TypeVar("T_LOGICAL") -U_LOGICAL = TypeVar("U_LOGICAL") - - -@var_operation -def _and_func_operation( - a: Var[ReflexCallable[[], T_LOGICAL]], b: Var[ReflexCallable[[], U_LOGICAL]] -) -> CustomVarOperationReturn[ReflexCallable[[], Union[T_LOGICAL, U_LOGICAL]]]: - """Perform a logical AND operation on two variables. - - Args: - a: The first variable. - b: The second variable. - - Returns: - The result of the logical AND operation. - """ - - def type_computer(*args: Var): - if not args: - return ( - ReflexCallable[[ReflexCallable[[], Any], ReflexCallable[[], Any]], Any], - type_computer, - ) - if len(args) == 1: - return ( - ReflexCallable[[ReflexCallable[[], Any]], Any], - functools.partial(type_computer, args[0]), - ) - - a_return_type = unwrap_reflex_callalbe(args[0]._var_type)[1] - b_return_type = unwrap_reflex_callalbe(args[1]._var_type)[1] - - return ( - ReflexCallable[[], unionize(a_return_type, b_return_type)], - None, - ) - - return var_operation_return( - js_expression=f"({a}() && {b}())", - type_computer=type_computer, - ) - - -@var_operation -def _or_func_operation( - a: Var[ReflexCallable[[], T_LOGICAL]], b: Var[ReflexCallable[[], U_LOGICAL]] -) -> CustomVarOperationReturn[ReflexCallable[[], Union[T_LOGICAL, U_LOGICAL]]]: - """Perform a logical OR operation on two variables. - - Args: - a: The first variable. - b: The second variable. - - Returns: - The result of the logical OR operation. - """ - - def type_computer(*args: Var): - if not args: - return ( - ReflexCallable[[ReflexCallable[[], Any], ReflexCallable[[], Any]], Any], - type_computer, - ) - if len(args) == 1: - return ( - ReflexCallable[[ReflexCallable[[], Any]], Any], - functools.partial(type_computer, args[0]), - ) - - a_return_type = unwrap_reflex_callalbe(args[0]._var_type)[1] - b_return_type = unwrap_reflex_callalbe(args[1]._var_type)[1] - - return ( - ReflexCallable[[], unionize(a_return_type, b_return_type)], - None, - ) - - return var_operation_return( - js_expression=f"({a}() || {b}())", - type_computer=type_computer, - ) + return _or_operation(a, b) def passthrough_unary_type_computer(no_args: GenericType) -> TypeComputer: @@ -3402,3 +3306,59 @@ def nary_type_computer( ) return type_computer + + +T_LOGICAL = TypeVar("T_LOGICAL") +U_LOGICAL = TypeVar("U_LOGICAL") + + +@var_operation +def _and_operation( + a: Var[T_LOGICAL], b: Var[U_LOGICAL] +) -> CustomVarOperationReturn[Union[T_LOGICAL, U_LOGICAL]]: + """Perform a logical AND operation on two variables. + + Args: + a: The first variable. + b: The second variable. + + Returns: + The result of the logical AND operation. + """ + return var_operation_return( + js_expression=f"({a} && {b})", + type_computer=nary_type_computer( + ReflexCallable[[Any, Any], Any], + ReflexCallable[[Any], Any], + computer=lambda args: unionize( + args[0]._var_type, + args[1]._var_type, + ), + ), + ) + + +@var_operation +def _or_operation( + a: Var[T_LOGICAL], b: Var[U_LOGICAL] +) -> CustomVarOperationReturn[Union[T_LOGICAL, U_LOGICAL]]: + """Perform a logical OR operation on two variables. + + Args: + a: The first variable. + b: The second variable. + + Returns: + The result ocomputerf the logical OR operation. + """ + return var_operation_return( + js_expression=f"({a} || {b})", + type_computer=nary_type_computer( + ReflexCallable[[Any, Any], Any], + ReflexCallable[[Any], Any], + computer=lambda args: unionize( + args[0]._var_type, + args[1]._var_type, + ), + ), + ) diff --git a/reflex/vars/function.py b/reflex/vars/function.py index c03c7c1d2..ba3b21c19 100644 --- a/reflex/vars/function.py +++ b/reflex/vars/function.py @@ -1219,19 +1219,26 @@ class FunctionVar( args = tuple(map(LiteralVar.create, args)) self._pre_check(*args) return_type = self._return_type(*args) - if ( - isinstance(self, (ArgsFunctionOperation, ArgsFunctionOperationBuilder)) - and self._raw_js_function + if arg_len == len(args) and isinstance( + self, (ArgsFunctionOperation, ArgsFunctionOperationBuilder) ): - return VarOperationCall.create( - FunctionStringVar.create( - self._raw_js_function, - _var_type=self._var_type, + if self._raw_js_function is not None: + return VarOperationCall.create( + FunctionStringVar.create( + self._raw_js_function, + _var_type=self._var_type, + _var_data=self._get_all_var_data(), + ), + *args, + _var_type=return_type, + ).guess_type() + if self._original_var_operation is not None: + return ExpressionCall.create( + self._original_var_operation, + *args, _var_data=self._get_all_var_data(), - ), - *args, - _var_type=return_type, - ).guess_type() + _var_type=return_type, + ).guess_type() return VarOperationCall.create(self, *args, _var_type=return_type).guess_type() @@ -1361,6 +1368,61 @@ class FunctionVar( __call__ = call +@dataclasses.dataclass(frozen=True) +class ExpressionCall(CachedVarOperation, Var[R]): + """Class for expression calls.""" + + _original_var_operation: Callable = dataclasses.field(default=lambda *args: "") + _args: Tuple[Var, ...] = dataclasses.field(default_factory=tuple) + + @cached_property_no_lock + def _cached_var_name(self) -> str: + """The name of the var. + + Returns: + The name of the var. + """ + return self._original_var_operation(*self._args) + + @cached_property_no_lock + def _cached_get_all_var_data(self) -> VarData | None: + """Get all the var data associated with the var. + + Returns: + All the var data associated with the var. + """ + return VarData.merge( + *[arg._get_all_var_data() for arg in self._args], + self._var_data, + ) + + @classmethod + def create( + cls, + _original_var_operation: Callable, + *args: Var | Any, + _var_type: GenericType = Any, + _var_data: VarData | None = None, + ) -> ExpressionCall: + """Create a new expression call. + + Args: + _original_var_operation: The original var operation. + *args: The arguments to call the expression with. + _var_data: Additional hooks and imports associated with the Var. + + Returns: + The expression call var. + """ + return ExpressionCall( + _js_expr="", + _var_type=_var_type, + _var_data=_var_data, + _original_var_operation=_original_var_operation, + _args=args, + ) + + class BuilderFunctionVar( FunctionVar[CALLABLE_TYPE], default_type=ReflexCallable[Any, Any] ): @@ -1600,6 +1662,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar[CALLABLE_TYPE]): _type_computer: Optional[TypeComputer] = dataclasses.field(default=None) _explicit_return: bool = dataclasses.field(default=False) _raw_js_function: str | None = dataclasses.field(default=None) + _original_var_operation: Callable | None = dataclasses.field(default=None) _cached_var_name = cached_property_no_lock(format_args_function_operation) @@ -1619,6 +1682,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar[CALLABLE_TYPE]): explicit_return: bool = False, type_computer: Optional[TypeComputer] = None, _raw_js_function: str | None = None, + _original_var_operation: Callable | None = None, _var_type: GenericType = Callable, _var_data: VarData | None = None, ): @@ -1634,6 +1698,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar[CALLABLE_TYPE]): explicit_return: Whether to use explicit return syntax. type_computer: A function to compute the return type. _raw_js_function: If provided, it will be used when the operation is being called with all of its arguments at once. + _original_var_operation: The original var operation, if any. _var_type: The type of the var. _var_data: Additional hooks and imports associated with the Var. @@ -1647,6 +1712,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar[CALLABLE_TYPE]): _var_data=_var_data, _args=FunctionArgs(args=tuple(args_names), rest=rest), _raw_js_function=_raw_js_function, + _original_var_operation=_original_var_operation, _default_values=tuple(default_values), _function_name=function_name, _validators=tuple(validators), @@ -1678,6 +1744,7 @@ class ArgsFunctionOperationBuilder( _type_computer: Optional[TypeComputer] = dataclasses.field(default=None) _explicit_return: bool = dataclasses.field(default=False) _raw_js_function: str | None = dataclasses.field(default=None) + _original_var_operation: Callable | None = dataclasses.field(default=None) _cached_var_name = cached_property_no_lock(format_args_function_operation) @@ -1697,6 +1764,7 @@ class ArgsFunctionOperationBuilder( explicit_return: bool = False, type_computer: Optional[TypeComputer] = None, _raw_js_function: str | None = None, + _original_var_operation: Callable | None = None, _var_type: GenericType = Callable, _var_data: VarData | None = None, ): @@ -1711,9 +1779,10 @@ class ArgsFunctionOperationBuilder( function_name: The name of the function. explicit_return: Whether to use explicit return syntax. type_computer: A function to compute the return type. + _raw_js_function: If provided, it will be used when the operation is being called with all of its arguments at once. + _original_var_operation: The original var operation, if any. _var_type: The type of the var. _var_data: Additional hooks and imports associated with the Var. - _raw_js_function: If provided, it will be used when the operation is being called with all of its arguments at once. Returns: The function var. @@ -1725,6 +1794,7 @@ class ArgsFunctionOperationBuilder( _var_data=_var_data, _args=FunctionArgs(args=tuple(args_names), rest=rest), _raw_js_function=_raw_js_function, + _original_var_operation=_original_var_operation, _default_values=tuple(default_values), _function_name=function_name, _validators=tuple(validators), diff --git a/tests/units/components/core/test_colors.py b/tests/units/components/core/test_colors.py index 0a01bfcc0..c1295fb41 100644 --- a/tests/units/components/core/test_colors.py +++ b/tests/units/components/core/test_colors.py @@ -39,7 +39,7 @@ def create_color_var(color): create_color_var( rx.color(ColorState.color, ColorState.shade, ColorState.alpha) # type: ignore ), - f'("var(--"+{color_state_name!s}.color+"-"+(((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))({color_state_name!s}.alpha, "a", ""))+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")', + f'("var(--"+{color_state_name!s}.color+"-"+({color_state_name!s}.alpha ? "a" : "")+(((__to_string) => __to_string.toString())({color_state_name!s}.shade))+")")', Color, ), ( @@ -78,11 +78,11 @@ def test_color(color, expected, expected_type: Union[Type[str], Type[Color]]): [ ( rx.cond(True, rx.color("mint"), rx.color("tomato", 5)), - '((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))(true, (() => "var(--mint-7)"), (() => "var(--tomato-5)")))())', + '(true ? "var(--mint-7)" : "var(--tomato-5)")', ), ( rx.cond(True, rx.color(ColorState.color), rx.color(ColorState.color, 5)), # type: ignore - f'((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))(true, (() => ("var(--"+{color_state_name!s}.color+"-7)")), (() => ("var(--"+{color_state_name!s}.color+"-5)"))))())', + f'(true ? ("var(--"+{color_state_name!s}.color+"-7)") : ("var(--"+{color_state_name!s}.color+"-5)"))', ), ( rx.match( diff --git a/tests/units/components/core/test_cond.py b/tests/units/components/core/test_cond.py index 06b108317..98fa2e121 100644 --- a/tests/units/components/core/test_cond.py +++ b/tests/units/components/core/test_cond.py @@ -23,7 +23,7 @@ def test_f_string_cond_interpolation(): var = LiteralVar.create(f"x {cond(True, 'a', 'b')}") assert ( str(var) - == '("x "+((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))(true, (() => "a"), (() => "b")))()))' + == '("x "+(true ? "a" : "b"))' ) @@ -53,7 +53,7 @@ def test_validate_cond(cond_state: BaseState): assert isinstance(cond_var, Var) assert ( str(cond_var) - == f'((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))({cond_state.value.bool()!s}, (() => (jsx(RadixThemesText, ({{ ["as"] : "p" }}), (jsx(Fragment, ({{ }}), "cond is True"))))), (() => (jsx(RadixThemesText, ({{ ["as"] : "p" }}), (jsx(Fragment, ({{ }}), "cond is False")))))))())' + == f'({cond_state.value.bool()!s} ? (jsx(RadixThemesText, ({{ ["as"] : "p" }}), (jsx(Fragment, ({{ }}), "cond is True")))) : (jsx(RadixThemesText, ({{ ["as"] : "p" }}), (jsx(Fragment, ({{ }}), "cond is False")))))' ) var_data = cond_var._get_all_var_data() @@ -89,10 +89,7 @@ def test_prop_cond(c1: Any, c2: Any): c1 = json.dumps(c1) if not isinstance(c2, Var): c2 = json.dumps(c2) - assert ( - str(prop_cond) - == f"((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))(true, (() => {c1!s}), (() => {c2!s})))())" - ) + assert str(prop_cond) == f"(true ? {c1!s} : {c2!s})" def test_cond_mix(): @@ -101,7 +98,7 @@ def test_cond_mix(): assert isinstance(x, Var) assert ( str(x) - == '((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))(true, (() => "hello"), (() => (jsx(RadixThemesText, ({ ["as"] : "p" }), (jsx(Fragment, ({ }), "world")))))))())' + == '(true ? "hello" : (jsx(RadixThemesText, ({ ["as"] : "p" }), (jsx(Fragment, ({ }), "world")))))' ) @@ -112,7 +109,7 @@ def test_cond_no_else(): assert isinstance(comp, Var) assert ( str(comp) - == '((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))(true, (() => (jsx(RadixThemesText, ({ ["as"] : "p" }), (jsx(Fragment, ({ }), "hello"))))), (() => (jsx(Fragment, ({ }))))))())' + == '(true ? (jsx(RadixThemesText, ({ ["as"] : "p" }), (jsx(Fragment, ({ }), "hello")))) : (jsx(Fragment, ({ }))))' ) # Props do not support the use of cond without else @@ -139,8 +136,7 @@ def test_cond_computed_var(): state_name = format_state_name(CondStateComputed.get_full_name()) assert ( - str(comp) - == f"((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))(true, (() => {state_name}.computed_int), (() => {state_name}.computed_str)))())" + str(comp) == f"(true ? {state_name}.computed_int : {state_name}.computed_str)" ) assert comp._var_type == Union[int, str] diff --git a/tests/units/components/core/test_match.py b/tests/units/components/core/test_match.py index 129234c16..b374b0f41 100644 --- a/tests/units/components/core/test_match.py +++ b/tests/units/components/core/test_match.py @@ -36,7 +36,7 @@ class MatchState(BaseState): 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((((_lhs, _rhs) => (_lhs + _rhs))({MatchState.get_name()}.num, 1))): return ("sixth value"); break;case JSON.stringify(({MatchState.get_name()}.value+" - string")): ' + 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;};})()', ), @@ -55,7 +55,7 @@ class MatchState(BaseState): 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((((_lhs, _rhs) => (_lhs + _rhs))({MatchState.get_name()}.num, 1))): return ("sixth value"); break;case JSON.stringify(({MatchState.get_name()}.value+" - string")): ' + 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;}};}})()", ), diff --git a/tests/units/components/markdown/test_markdown.py b/tests/units/components/markdown/test_markdown.py index 93e30f0d3..6fddd0155 100644 --- a/tests/units/components/markdown/test_markdown.py +++ b/tests/units/components/markdown/test_markdown.py @@ -148,7 +148,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe ( "code", {}, - '(({node, inline, className, children, ...props}) => { const match = (className || \'\').match(/language-(?<lang>.*)/); const _language = match ? match[1] : \'\'; if (_language) { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Error importing language module for ${_language}:`, error); } })(); } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <SyntaxHighlighter children={(((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))((Array.isArray(children)), (((...args) => (((_array, _sep = "") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))("\\n")), children))} css={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} customStyle={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} language={_language} style={((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))((((_lhs, _rhs) => (_lhs === _rhs))(resolvedColorMode, "light")), (() => oneLight), (() => oneDark)))())} wrapLongLines={true} {...props}/> ); })', + r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; if (_language) { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Error importing language module for ${_language}:`, error); } })(); } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <SyntaxHighlighter children={((Array.isArray(children)) ? (((...args) => (((_array, _sep = "") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))("\n")) : children)} css={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} customStyle={({ ["marginTop"] : "1em", ["marginBottom"] : "1em" })} language={_language} style={((resolvedColorMode === "light") ? oneLight : oneDark)} wrapLongLines={true} {...props}/> ); })""" ), ( "code", @@ -157,7 +157,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe value, **props ) }, - '(({node, inline, className, children, ...props}) => { const match = (className || \'\').match(/language-(?<lang>.*)/); const _language = match ? match[1] : \'\'; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <RadixThemesBox css={({ ["pre"] : ({ ["margin"] : "0", ["padding"] : "24px", ["background"] : "transparent", ["overflow-x"] : "auto", ["border-radius"] : "6px" }) })} {...props}><ShikiCode code={(((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))((Array.isArray(children)), (((...args) => (((_array, _sep = "") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))("\\n")), children))} decorations={[]} language={_language} theme={((((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))((((_lhs, _rhs) => (_lhs === _rhs))(resolvedColorMode, "light")), (() => "one-light"), (() => "one-dark-pro")))())} transformers={[]}/></RadixThemesBox> ); })', + r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <RadixThemesBox css={({ ["pre"] : ({ ["margin"] : "0", ["padding"] : "24px", ["background"] : "transparent", ["overflow-x"] : "auto", ["border-radius"] : "6px" }) })} {...props}><ShikiCode code={((Array.isArray(children)) ? (((...args) => (((_array, _sep = "") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))("\n")) : children)} decorations={[]} language={_language} theme={((resolvedColorMode === "light") ? "one-light" : "one-dark-pro")} transformers={[]}/></RadixThemesBox> ); })""" ), ( "h1", @@ -171,7 +171,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe ( "code", {"codeblock": syntax_highlighter_memoized_component(CodeBlock)}, - "(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; if (_language) { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Error importing language module for ${_language}:`, error); } })(); } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={(((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))((Array.isArray(children)), (((...args) => (((_array, _sep = \"\") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))(\"\\n\")), children))} language={_language} {...props}/> ); })", + r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; if (_language) { (async () => { try { const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${_language}`); SyntaxHighlighter.registerLanguage(_language, module.default); } catch (error) { console.error(`Error importing language module for ${_language}:`, error); } })(); } ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={((Array.isArray(children)) ? (((...args) => (((_array, _sep = "") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))("\n")) : children)} language={_language} {...props}/> ); })""", ), ( "code", @@ -180,7 +180,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe ShikiHighLevelCodeBlock ) }, - """(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={(((_condition, _if_true, _if_false) => (_condition ? _if_true : _if_false))((Array.isArray(children)), (((...args) => (((_array, _sep = "") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))("\\n")), children))} language={_language} {...props}/> ); })""", + r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?<lang>.*)/); const _language = match ? match[1] : ''; ; return inline ? ( <RadixThemesCode {...props}>{children}</RadixThemesCode> ) : ( <CodeBlock code={((Array.isArray(children)) ? (((...args) => (((_array, _sep = "") => Array.prototype.join.apply(_array,[_sep]))(children, ...args)))("\n")) : children)} language={_language} {...props}/> ); })""", ), ], ) diff --git a/tests/units/test_var.py b/tests/units/test_var.py index f395c4116..b66d2f179 100644 --- a/tests/units/test_var.py +++ b/tests/units/test_var.py @@ -310,53 +310,21 @@ def test_basic_operations(TestObj): Args: TestObj: The test object. """ - assert str(v(1) == v(2)) == "(((_lhs, _rhs) => (_lhs === _rhs))(1, 2))" - assert str(v(1) != v(2)) == "(((_lhs, _rhs) => (_lhs !== _rhs))(1, 2))" - assert ( - str(LiteralNumberVar.create(1) < 2) == "(((_lhs, _rhs) => (_lhs < _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) <= 2) - == "(((_lhs, _rhs) => (_lhs <= _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) > 2) == "(((_lhs, _rhs) => (_lhs > _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) >= 2) - == "(((_lhs, _rhs) => (_lhs >= _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) + 2) == "(((_lhs, _rhs) => (_lhs + _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) - 2) == "(((_lhs, _rhs) => (_lhs - _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) * 2) == "(((_lhs, _rhs) => (_lhs * _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) / 2) == "(((_lhs, _rhs) => (_lhs / _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) // 2) - == "(((_lhs, _rhs) => Math.floor(_lhs / _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) % 2) == "(((_lhs, _rhs) => (_lhs % _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) ** 2) - == "(((_lhs, _rhs) => (_lhs ** _rhs))(1, 2))" - ) - assert ( - str(LiteralNumberVar.create(1) & v(2)) - == "(((_a, _b) => (_a() && _b()))((() => 1), (() => 2)))" - ) - assert ( - str(LiteralNumberVar.create(1) | v(2)) - == "(((_a, _b) => (_a() || _b()))((() => 1), (() => 2)))" - ) + assert str(v(1) == v(2)) == "(1 === 2)" + assert str(v(1) != v(2)) == "(1 !== 2)" + assert str(LiteralNumberVar.create(1) < 2) == "(1 < 2)" + assert str(LiteralNumberVar.create(1) <= 2) == "(1 <= 2)" + assert str(LiteralNumberVar.create(1) > 2) == "(1 > 2)" + assert str(LiteralNumberVar.create(1) >= 2) == "(1 >= 2)" + assert str(LiteralNumberVar.create(1) + 2) == "(1 + 2)" + assert str(LiteralNumberVar.create(1) - 2) == "(1 - 2)" + assert str(LiteralNumberVar.create(1) * 2) == "(1 * 2)" + assert str(LiteralNumberVar.create(1) / 2) == "(1 / 2)" + assert str(LiteralNumberVar.create(1) // 2) == "Math.floor(1 / 2)" + assert str(LiteralNumberVar.create(1) % 2) == "(1 % 2)" + assert str(LiteralNumberVar.create(1) ** 2) == "(1 ** 2)" + assert str(LiteralNumberVar.create(1) & v(2)) == "(1 && 2)" + assert str(LiteralNumberVar.create(1) | v(2)) == "(1 || 2)" assert ( str(LiteralArrayVar.create([1, 2, 3])[0]) == "(((...args) => (((_array, _index_or_slice) => atSliceOrIndex(_array, _index_or_slice))([1, 2, 3], ...args)))(0))" @@ -365,16 +333,10 @@ def test_basic_operations(TestObj): str(LiteralObjectVar.create({"a": 1, "b": 2})["a"]) == '({ ["a"] : 1, ["b"] : 2 })["a"]' ) + assert str(v("foo") == v("bar")) == '("foo" === "bar")' + assert str(Var(_js_expr="foo") == Var(_js_expr="bar")) == "(foo === bar)" assert ( - str(v("foo") == v("bar")) == '(((_lhs, _rhs) => (_lhs === _rhs))("foo", "bar"))' - ) - assert ( - str(Var(_js_expr="foo") == Var(_js_expr="bar")) - == "(((_lhs, _rhs) => (_lhs === _rhs))(foo, bar))" - ) - assert ( - str(LiteralVar.create("foo") == LiteralVar.create("bar")) - == '(((_lhs, _rhs) => (_lhs === _rhs))("foo", "bar"))' + str(LiteralVar.create("foo") == LiteralVar.create("bar")) == '("foo" === "bar")' ) print(Var(_js_expr="foo").to(ObjectVar, TestObj)._var_set_state("state")) assert ( @@ -382,7 +344,7 @@ def test_basic_operations(TestObj): Var(_js_expr="foo").to(ObjectVar, TestObj)._var_set_state("state").bar == LiteralVar.create("bar") ) - == '(((_lhs, _rhs) => (_lhs === _rhs))(state.foo["bar"], "bar"))' + == '(state.foo["bar"] === "bar")' ) assert ( str(Var(_js_expr="foo").to(ObjectVar, TestObj)._var_set_state("state").bar) @@ -543,32 +505,17 @@ def test_str_contains(var, expected): ], ) def test_dict_contains(var, expected): - assert ( - str(var.contains(1)) - == f"(((_object, _key) => _object.hasOwnProperty(_key))({expected!s}, 1))" - ) - assert ( - str(var.contains("1")) - == f'(((_object, _key) => _object.hasOwnProperty(_key))({expected!s}, "1"))' - ) - assert ( - str(var.contains(v(1))) - == f"(((_object, _key) => _object.hasOwnProperty(_key))({expected!s}, 1))" - ) - assert ( - str(var.contains(v("1"))) - == f'(((_object, _key) => _object.hasOwnProperty(_key))({expected!s}, "1"))' - ) + assert str(var.contains(1)) == f"{expected!s}.hasOwnProperty(1)" + assert str(var.contains("1")) == f'{expected!s}.hasOwnProperty("1")' + assert str(var.contains(v(1))) == f"{expected!s}.hasOwnProperty(1)" + assert str(var.contains(v("1"))) == f'{expected!s}.hasOwnProperty("1")' other_state_var = Var(_js_expr="other")._var_set_state("state").to(str) other_var = Var(_js_expr="other").to(str) assert ( str(var.contains(other_state_var)) - == f"(((_object, _key) => _object.hasOwnProperty(_key))({expected!s}, state.other))" - ) - assert ( - str(var.contains(other_var)) - == f"(((_object, _key) => _object.hasOwnProperty(_key))({expected!s}, other))" + == f"{expected!s}.hasOwnProperty(state.other)" ) + assert str(var.contains(other_var)) == f"{expected!s}.hasOwnProperty(other)" @pytest.mark.parametrize( @@ -1108,8 +1055,8 @@ def test_var_operation(): def add(a: Var[int], b: Var[int]): return var_operation_return(js_expression=f"({a} + {b})", var_type=int) - assert str(add(1, 2)) == "(((_a, _b) => (_a + _b))(1, 2))" - assert str(add(4, -9)) == "(((_a, _b) => (_a + _b))(4, -9))" + assert str(add(1, 2)) == "(1 + 2)" + assert str(add(4, -9)) == "(4 + -9)" five = LiteralNumberVar.create(5) seven = add(2, five) @@ -1153,7 +1100,7 @@ def test_all_number_operations(): assert ( str(complicated_number) - == "(((_lhs, _rhs) => (_lhs ** _rhs))((((_lhs, _rhs) => (_lhs % _rhs))((((_lhs, _rhs) => Math.floor(_lhs / _rhs))((((_lhs, _rhs) => (_lhs / _rhs))((((_lhs, _rhs) => (_lhs * _rhs))((((_value) => -(_value))((((_lhs, _rhs) => (_lhs + _rhs))(-5.4, 1)))), 2)), 3)), 2)), 3)), 2))" + == "((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2)" ) even_more_complicated_number = ~( @@ -1162,20 +1109,14 @@ def test_all_number_operations(): assert ( str(even_more_complicated_number) - == "(((_value) => !(_value))((isTrue((((_a, _b) => (_a() || _b()))((() => (Math.abs((Math.floor((((_lhs, _rhs) => (_lhs ** _rhs))((((_lhs, _rhs) => (_lhs % _rhs))((((_lhs, _rhs) => Math.floor(_lhs / _rhs))((((_lhs, _rhs) => (_lhs / _rhs))((((_lhs, _rhs) => (_lhs * _rhs))((((_value) => -(_value))((((_lhs, _rhs) => (_lhs + _rhs))(-5.4, 1)))), 2)), 3)), 2)), 3)), 2))))))), (() => (((_a, _b) => (_a() && _b()))((() => 2), (() => (((_value) => Math.round(_value))((((_lhs, _rhs) => (_lhs ** _rhs))((((_lhs, _rhs) => (_lhs % _rhs))((((_lhs, _rhs) => Math.floor(_lhs / _rhs))((((_lhs, _rhs) => (_lhs / _rhs))((((_lhs, _rhs) => (_lhs * _rhs))((((_value) => -(_value))((((_lhs, _rhs) => (_lhs + _rhs))(-5.4, 1)))), 2)), 3)), 2)), 3)), 2))))))))))))))" + == "!((isTrue(((Math.abs((Math.floor(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2))))) || (2 && Math.round(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2)))))))" ) - assert ( - str(LiteralNumberVar.create(5) > False) - == "(((_lhs, _rhs) => (_lhs > _rhs))(5, 0))" - ) - assert ( - str(LiteralBooleanVar.create(False) < 5) - == "(((_lhs, _rhs) => (_lhs < _rhs))((Number(false)), 5))" - ) + assert str(LiteralNumberVar.create(5) > False) == "(5 > 0)" + assert str(LiteralBooleanVar.create(False) < 5) == "((Number(false)) < 5)" assert ( str(LiteralBooleanVar.create(False) < LiteralBooleanVar.create(True)) - == "(((_lhs, _rhs) => (_lhs < _rhs))((Number(false)), (Number(true))))" + == "((Number(false)) < (Number(true)))" ) @@ -1218,7 +1159,7 @@ def test_index_operation(): ) assert ( str(array_var[0].to(NumberVar) + 9) - == "(((_lhs, _rhs) => (_lhs + _rhs))((((...args) => (((_array, _index_or_slice) => atSliceOrIndex(_array, _index_or_slice))([1, 2, 3, 4, 5], ...args)))(0)), 9))" + == "((((...args) => (((_array, _index_or_slice) => atSliceOrIndex(_array, _index_or_slice))([1, 2, 3, 4, 5], ...args)))(0)) + 9)" ) @@ -1261,14 +1202,8 @@ def test_array_operations(): str(ArrayVar.range(1, 10)) == "(((_e1, _e2 = null, _step = 1) => [...range(_e1, _e2, _step)])(1, 10))" ) - assert ( - str(ArrayVar.range(1, 10, 2)) - == "(((_e1, _e2 = null, _step = 1) => [...range(_e1, _e2, _step)])(1, 10, 2))" - ) - assert ( - str(ArrayVar.range(1, 10, -1)) - == "(((_e1, _e2 = null, _step = 1) => [...range(_e1, _e2, _step)])(1, 10, -1))" - ) + assert str(ArrayVar.range(1, 10, 2)) == "[...range(1, 10, 2)]" + assert str(ArrayVar.range(1, 10, -1)) == "[...range(1, 10, -1)]" def test_object_operations(): @@ -1289,7 +1224,7 @@ def test_object_operations(): assert str(object_var["a"]) == '({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })["a"]' assert ( str(object_var.merge(LiteralObjectVar.create({"c": 4, "d": 5}))) - == '(((_lhs, _rhs) => ({..._lhs, ..._rhs}))(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 }), ({ ["c"] : 4, ["d"] : 5 })))' + == '({...({ ["a"] : 1, ["b"] : 2, ["c"] : 3 }), ...({ ["c"] : 4, ["d"] : 5 })})' ) @@ -1329,11 +1264,11 @@ def test_type_chains(): ) assert ( str(object_var.entries()[1][1] - 1) # type: ignore - == '(((_lhs, _rhs) => (_lhs - _rhs))((((...args) => (((_array, _index_or_slice) => atSliceOrIndex(_array, _index_or_slice))((((...args) => (((_array, _index_or_slice) => atSliceOrIndex(_array, _index_or_slice))((Object.entries(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 }))), ...args)))(1)), ...args)))(1)), 1))' + == '((((...args) => (((_array, _index_or_slice) => atSliceOrIndex(_array, _index_or_slice))((((...args) => (((_array, _index_or_slice) => atSliceOrIndex(_array, _index_or_slice))((Object.entries(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 }))), ...args)))(1)), ...args)))(1)) - 1)' ) assert ( str(object_var["c"] + object_var["b"]) # type: ignore - == '(((_lhs, _rhs) => (_lhs + _rhs))(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })["c"], ({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })["b"]))' + == '(({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })["c"] + ({ ["a"] : 1, ["b"] : 2, ["c"] : 3 })["b"])' )