use ArgsFunctionOperation
This commit is contained in:
parent
dc18101118
commit
ec5f751f3f
@ -6,13 +6,14 @@ import textwrap
|
|||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from typing import Any, Callable, Dict, Union
|
from typing import Any, Callable, Dict, Union
|
||||||
|
import dataclasses
|
||||||
|
|
||||||
from reflex.components.component import Component, CustomComponent
|
from reflex.components.component import Component, CustomComponent
|
||||||
from reflex.components.tags.tag import Tag
|
from reflex.components.tags.tag import Tag
|
||||||
from reflex.utils import types
|
from reflex.utils import types
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.vars.base import LiteralVar, Var
|
from reflex.vars.base import LiteralVar, Var
|
||||||
from reflex.vars.function import ARRAY_ISARRAY
|
from reflex.vars.function import ARRAY_ISARRAY, ArgsFunctionOperation
|
||||||
from reflex.vars.number import ternary_operation
|
from reflex.vars.number import ternary_operation
|
||||||
|
|
||||||
# Special vars used in the component map.
|
# Special vars used in the component map.
|
||||||
@ -75,8 +76,10 @@ def get_base_component_map() -> dict[str, Callable]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(frozen=True)
|
||||||
class MarkdownComponentMap:
|
class MarkdownComponentMap:
|
||||||
"""Mixin class for handling custom component maps in Markdown components."""
|
"""Mixin class for handling custom component maps in Markdown components."""
|
||||||
|
_explicit_return: bool = dataclasses.field(default=False)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_component_map_custom_code(cls) -> str:
|
def get_component_map_custom_code(cls) -> str:
|
||||||
@ -89,22 +92,23 @@ class MarkdownComponentMap:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_map_fn_var(
|
def create_map_fn_var(
|
||||||
cls, fn_body: str | None = None, fn_args: list[str] | None = None
|
cls, fn_body: Var | None = None, fn_args: tuple[str, ...] | None = None, explicit_return: bool | None = None
|
||||||
) -> Var:
|
) -> Var:
|
||||||
"""Create a function Var for the component map.
|
"""Create a function Var for the component map.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fn_body: The formatted component as a string.
|
fn_body: The formatted component as a string.
|
||||||
fn_args: The function arguments.
|
fn_args: The function arguments.
|
||||||
|
explicit_return: Whether to use explicit return syntax.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The function Var for the component map.
|
The function Var for the component map.
|
||||||
"""
|
"""
|
||||||
fn_args = fn_args or cls.get_fn_args()
|
fn_args = fn_args or cls.get_fn_args()
|
||||||
fn_body = fn_body or cls.get_fn_body()
|
fn_body = fn_body if fn_body is not None else cls.get_fn_body()
|
||||||
fn_args_str = ", ".join(fn_args)
|
explicit_return = explicit_return or cls._explicit_return
|
||||||
|
|
||||||
return Var(_js_expr=f"(({{{fn_args_str}}}) => {fn_body})")
|
return ArgsFunctionOperation.create(args_names=fn_args, return_expr=fn_body, destructure_args=True, explicit_return=explicit_return)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fn_args(cls) -> list[str]:
|
def get_fn_args(cls) -> list[str]:
|
||||||
@ -116,13 +120,13 @@ class MarkdownComponentMap:
|
|||||||
return ["node", _CHILDREN._js_expr, _PROPS._js_expr]
|
return ["node", _CHILDREN._js_expr, _PROPS._js_expr]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fn_body(cls) -> str:
|
def get_fn_body(cls) -> Var:
|
||||||
"""Get the function body for the component map.
|
"""Get the function body for the component map.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The function body as a string.
|
The function body as a string.
|
||||||
"""
|
"""
|
||||||
return "()"
|
return Var(_js_expr="", _var_type=str)
|
||||||
|
|
||||||
|
|
||||||
class Markdown(Component):
|
class Markdown(Component):
|
||||||
@ -269,23 +273,24 @@ class Markdown(Component):
|
|||||||
codeblock_custom_code = "\n".join(custom_code_list)
|
codeblock_custom_code = "\n".join(custom_code_list)
|
||||||
|
|
||||||
# Format the code to handle inline and block code.
|
# Format the code to handle inline and block code.
|
||||||
formatted_code = f"""{{{codeblock_custom_code};
|
formatted_code = f"""{codeblock_custom_code};
|
||||||
return inline ? (
|
return inline ? (
|
||||||
{self.format_component("code")}
|
{self.format_component("code")}
|
||||||
) : (
|
) : (
|
||||||
{self.format_component("codeblock", language=_LANGUAGE)}
|
{self.format_component("codeblock", language=_LANGUAGE)}
|
||||||
);
|
);
|
||||||
}}""".replace("\n", " ")
|
""".replace("\n", " ")
|
||||||
|
|
||||||
return MarkdownComponentMap.create_map_fn_var(
|
return MarkdownComponentMap.create_map_fn_var(
|
||||||
fn_args=[
|
fn_args=(
|
||||||
"node",
|
"node",
|
||||||
"inline",
|
"inline",
|
||||||
"className",
|
"className",
|
||||||
_CHILDREN._js_expr,
|
_CHILDREN._js_expr,
|
||||||
_PROPS._js_expr,
|
_PROPS._js_expr,
|
||||||
],
|
),
|
||||||
fn_body=formatted_code,
|
fn_body=Var(_js_expr=formatted_code),
|
||||||
|
explicit_return=True
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_component(self, tag: str, **props) -> Component:
|
def get_component(self, tag: str, **props) -> Component:
|
||||||
@ -354,11 +359,12 @@ class Markdown(Component):
|
|||||||
Returns:
|
Returns:
|
||||||
The function Var for the component map.
|
The function Var for the component map.
|
||||||
"""
|
"""
|
||||||
|
formatted_component = Var(_js_expr=f"({self.format_component(tag)})", _var_type=str)
|
||||||
if isinstance(component, MarkdownComponentMap):
|
if isinstance(component, MarkdownComponentMap):
|
||||||
return component.create_map_fn_var(f"({self.format_component(tag)})")
|
return component.create_map_fn_var(fn_body=formatted_component)
|
||||||
|
|
||||||
# fallback to the default fn Var creation if the component is not a MarkdownComponentMap.
|
# fallback to the default fn Var creation if the component is not a MarkdownComponentMap.
|
||||||
return MarkdownComponentMap.create_map_fn_var(f"({self.format_component(tag)})")
|
return MarkdownComponentMap.create_map_fn_var(fn_body=formatted_component)
|
||||||
|
|
||||||
def _get_map_fn_custom_code_from_children(self, component) -> list[str]:
|
def _get_map_fn_custom_code_from_children(self, component) -> list[str]:
|
||||||
"""Recursively get markdown custom code from children components.
|
"""Recursively get markdown custom code from children components.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
# ------------------- DO NOT EDIT ----------------------
|
# ------------------- DO NOT EDIT ----------------------
|
||||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||||
# ------------------------------------------------------
|
# ------------------------------------------------------
|
||||||
|
import dataclasses
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||||
|
|
||||||
@ -28,18 +29,21 @@ NO_PROPS_TAGS = ("ul", "ol", "li")
|
|||||||
|
|
||||||
@lru_cache
|
@lru_cache
|
||||||
def get_base_component_map() -> dict[str, Callable]: ...
|
def get_base_component_map() -> dict[str, Callable]: ...
|
||||||
|
@dataclasses.dataclass(frozen=True)
|
||||||
class MarkdownComponentMap:
|
class MarkdownComponentMap:
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_component_map_custom_code(cls) -> str: ...
|
def get_component_map_custom_code(cls) -> str: ...
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_map_fn_var(
|
def create_map_fn_var(
|
||||||
cls, fn_body: str | None = None, fn_args: list[str] | None = None
|
cls,
|
||||||
|
fn_body: Var | None = None,
|
||||||
|
fn_args: tuple[str, ...] | None = None,
|
||||||
|
explicit_return: bool | None = None,
|
||||||
) -> Var: ...
|
) -> Var: ...
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fn_args(cls) -> list[str]: ...
|
def get_fn_args(cls) -> list[str]: ...
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fn_body(cls) -> str: ...
|
def get_fn_body(cls) -> Var: ...
|
||||||
|
|
||||||
class Markdown(Component):
|
class Markdown(Component):
|
||||||
@overload
|
@overload
|
||||||
|
@ -7,6 +7,7 @@ import sys
|
|||||||
from typing import Any, Callable, Optional, Tuple, Type, Union
|
from typing import Any, Callable, Optional, Tuple, Type, Union
|
||||||
|
|
||||||
from reflex.utils.types import GenericType
|
from reflex.utils.types import GenericType
|
||||||
|
from reflex.utils import format
|
||||||
|
|
||||||
from .base import CachedVarOperation, LiteralVar, Var, VarData, cached_property_no_lock
|
from .base import CachedVarOperation, LiteralVar, Var, VarData, cached_property_no_lock
|
||||||
|
|
||||||
@ -136,6 +137,8 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|||||||
|
|
||||||
_args_names: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
|
_args_names: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
|
||||||
_return_expr: Union[Var, Any] = dataclasses.field(default=None)
|
_return_expr: Union[Var, Any] = dataclasses.field(default=None)
|
||||||
|
_destructure_args: bool = dataclasses.field(default=False)
|
||||||
|
_explicit_return: bool = dataclasses.field(default=True)
|
||||||
|
|
||||||
@cached_property_no_lock
|
@cached_property_no_lock
|
||||||
def _cached_var_name(self) -> str:
|
def _cached_var_name(self) -> str:
|
||||||
@ -144,21 +147,36 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|||||||
Returns:
|
Returns:
|
||||||
The name of the var.
|
The name of the var.
|
||||||
"""
|
"""
|
||||||
return f"(({', '.join(self._args_names)}) => ({str(LiteralVar.create(self._return_expr))}))"
|
arg_names_str = ", ".join(self._args_names)
|
||||||
|
return_expr_str = str(LiteralVar.create(self._return_expr))
|
||||||
|
|
||||||
|
if self._destructure_args:
|
||||||
|
arg_names_str = format.wrap(arg_names_str, "{", "}")
|
||||||
|
|
||||||
|
# Wrap return expression in curly braces if explicit return syntax is used.
|
||||||
|
return_expr_str = format.wrap(return_expr_str, "{", "}") if self._explicit_return else format.wrap(return_expr_str, "(", ")")
|
||||||
|
|
||||||
|
return f"(({arg_names_str}) => {return_expr_str})"
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(
|
def create(
|
||||||
cls,
|
cls,
|
||||||
args_names: Tuple[str, ...],
|
args_names: Tuple[str, ...],
|
||||||
return_expr: Var | Any,
|
return_expr: Var | Any,
|
||||||
|
destructure_args: bool = False,
|
||||||
|
explicit_return: bool = False,
|
||||||
_var_type: GenericType = Callable,
|
_var_type: GenericType = Callable,
|
||||||
_var_data: VarData | None = None,
|
_var_data: VarData | None = None,
|
||||||
|
|
||||||
) -> ArgsFunctionOperation:
|
) -> ArgsFunctionOperation:
|
||||||
"""Create a new function var.
|
"""Create a new function var.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
args_names: The names of the arguments.
|
args_names: The names of the arguments.
|
||||||
return_expr: The return expression of the function.
|
return_expr: The return expression of the function.
|
||||||
|
destructure_args: Whether to destructure the arguments.
|
||||||
|
explicit_return: Whether to use explicit return syntax.
|
||||||
_var_data: Additional hooks and imports associated with the Var.
|
_var_data: Additional hooks and imports associated with the Var.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -170,6 +188,8 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|||||||
_var_data=_var_data,
|
_var_data=_var_data,
|
||||||
_args_names=args_names,
|
_args_names=args_names,
|
||||||
_return_expr=return_expr,
|
_return_expr=return_expr,
|
||||||
|
_destructure_args=destructure_args,
|
||||||
|
_explicit_return=explicit_return
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,22 +18,22 @@ class CustomMarkdownComponent(Component, MarkdownComponentMap):
|
|||||||
library = "custom"
|
library = "custom"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fn_args(cls) -> list[str]:
|
def get_fn_args(cls) -> tuple[str, ...]:
|
||||||
"""Return the function arguments.
|
"""Return the function arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The function arguments.
|
The function arguments.
|
||||||
"""
|
"""
|
||||||
return ["custom_node", "custom_children", "custom_props"]
|
return ("custom_node", "custom_children", "custom_props")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_fn_body(cls) -> str:
|
def get_fn_body(cls) -> Var:
|
||||||
"""Return the function body.
|
"""Return the function body.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The function body.
|
The function body.
|
||||||
"""
|
"""
|
||||||
return "{return custom_node + custom_children + custom_props;}"
|
return Var(_js_expr="{return custom_node + custom_children + custom_props}")
|
||||||
|
|
||||||
|
|
||||||
def syntax_highlighter_memoized_component(codeblock: Type[Component]):
|
def syntax_highlighter_memoized_component(codeblock: Type[Component]):
|
||||||
@ -58,67 +58,74 @@ def syntax_highlighter_memoized_component(codeblock: Type[Component]):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"fn_body, fn_args, expected",
|
"fn_body, fn_args, explicit_return, expected",
|
||||||
[
|
[
|
||||||
(None, None, Var(_js_expr="(({node, children, ...props}) => ())")),
|
(None, None, False, Var(_js_expr="(({node, children, ...props}) => ())")),
|
||||||
("{return node;}", ["node"], Var(_js_expr="(({node}) => {return node;})")),
|
("return node", ("node", ), True, Var(_js_expr="(({node}) => {return node})")),
|
||||||
(
|
(
|
||||||
"{return node + children;}",
|
"return node + children",
|
||||||
["node", "children"],
|
("node", "children"),
|
||||||
Var(_js_expr="(({node, children}) => {return node + children;})"),
|
True,
|
||||||
|
Var(_js_expr="(({node, children}) => {return node + children})"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"{return node + props;}",
|
"return node + props",
|
||||||
["node", "...props"],
|
("node", "...props"),
|
||||||
Var(_js_expr="(({node, ...props}) => {return node + props;})"),
|
True,
|
||||||
|
Var(_js_expr="(({node, ...props}) => {return node + props})"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"{return node + children + props;}",
|
"return node + children + props",
|
||||||
["node", "children", "...props"],
|
("node", "children", "...props"),
|
||||||
|
True,
|
||||||
Var(
|
Var(
|
||||||
_js_expr="(({node, children, ...props}) => {return node + children + props;})"
|
_js_expr="(({node, children, ...props}) => {return node + children + props})"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_create_map_fn_var(fn_body, fn_args, expected):
|
def test_create_map_fn_var(fn_body, fn_args, explicit_return, expected):
|
||||||
result = MarkdownComponentMap.create_map_fn_var(fn_body, fn_args)
|
result = MarkdownComponentMap.create_map_fn_var(fn_body= Var(_js_expr=fn_body,_var_type=str) if fn_body else None, fn_args=fn_args, explicit_return=explicit_return)
|
||||||
assert result._js_expr == expected._js_expr
|
assert result._js_expr == expected._js_expr
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"cls, fn_body, fn_args, expected",
|
"cls, fn_body, fn_args, explicit_return, expected",
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
MarkdownComponentMap,
|
MarkdownComponentMap,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
False,
|
||||||
Var(_js_expr="(({node, children, ...props}) => ())"),
|
Var(_js_expr="(({node, children, ...props}) => ())"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
MarkdownComponentMap,
|
MarkdownComponentMap,
|
||||||
"{return node};",
|
"return node",
|
||||||
["node"],
|
("node", ),
|
||||||
Var(_js_expr="(({node}) => {return node};)"),
|
True,
|
||||||
|
Var(_js_expr="(({node}) => {return node})"),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
CustomMarkdownComponent,
|
CustomMarkdownComponent,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
True,
|
||||||
Var(
|
Var(
|
||||||
_js_expr="(({custom_node, custom_children, custom_props}) => {return custom_node + custom_children + custom_props;})"
|
_js_expr="(({custom_node, custom_children, custom_props}) => {return custom_node + custom_children + custom_props})"
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
CustomMarkdownComponent,
|
CustomMarkdownComponent,
|
||||||
"{return custom_node;}",
|
"return custom_node",
|
||||||
["custom_node"],
|
("custom_node",),
|
||||||
Var(_js_expr="(({custom_node}) => {return custom_node;})"),
|
True,
|
||||||
|
Var(_js_expr="(({custom_node}) => {return custom_node})"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_create_map_fn_var_subclass(cls, fn_body, fn_args, expected):
|
def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expected):
|
||||||
result = cls.create_map_fn_var(fn_body, fn_args)
|
result = cls.create_map_fn_var(fn_body= Var(_js_expr=fn_body, _var_type=int) if fn_body else None, fn_args=fn_args, explicit_return=explicit_return)
|
||||||
assert result._js_expr == expected._js_expr
|
assert result._js_expr == expected._js_expr
|
||||||
|
|
||||||
|
|
||||||
|
@ -940,6 +940,18 @@ def test_function_var():
|
|||||||
== '(((name) => (("Hello, "+name+"!")))("Steven Universe"))'
|
== '(((name) => (("Hello, "+name+"!")))("Steven Universe"))'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Test with destructured arguments
|
||||||
|
destructured_func = ArgsFunctionOperation.create(
|
||||||
|
("a","b"), Var(_js_expr="a + b"), destructure_args=True
|
||||||
|
)
|
||||||
|
assert str(destructured_func.call({"a": 1, "b": 2})) == '(({a, b}) => (a + b))({"a": 1, "b": 2})'
|
||||||
|
|
||||||
|
# Test with explicit return
|
||||||
|
explicit_return_func = ArgsFunctionOperation.create(
|
||||||
|
("a", "b"), Var(_js_expr="return a + b"), explicit_return=True
|
||||||
|
)
|
||||||
|
assert str(explicit_return_func.call(1, 2)) == '((a, b) => {return a + b})(1, 2)'
|
||||||
|
|
||||||
|
|
||||||
def test_var_operation():
|
def test_var_operation():
|
||||||
@var_operation
|
@var_operation
|
||||||
|
Loading…
Reference in New Issue
Block a user