implement _evaluate in state (#4018)
* implement _evaluate in state * add warning * use typing_extension * add integration test
This commit is contained in:
parent
1b3422dab6
commit
62021b0b40
@ -35,6 +35,7 @@ from typing import (
|
|||||||
|
|
||||||
import dill
|
import dill
|
||||||
from sqlalchemy.orm import DeclarativeBase
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
from reflex.config import get_config
|
from reflex.config import get_config
|
||||||
from reflex.vars.base import (
|
from reflex.vars.base import (
|
||||||
@ -43,6 +44,7 @@ from reflex.vars.base import (
|
|||||||
Var,
|
Var,
|
||||||
computed_var,
|
computed_var,
|
||||||
dispatch,
|
dispatch,
|
||||||
|
get_unique_variable_name,
|
||||||
is_computed_var,
|
is_computed_var,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -695,6 +697,36 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
and hasattr(value, "__code__")
|
and hasattr(value, "__code__")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _evaluate(cls, f: Callable[[Self], Any]) -> Var:
|
||||||
|
"""Evaluate a function to a ComputedVar. Experimental.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
f: The function to evaluate.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The ComputedVar.
|
||||||
|
"""
|
||||||
|
console.warn(
|
||||||
|
"The _evaluate method is experimental and may be removed in future versions."
|
||||||
|
)
|
||||||
|
from reflex.components.base.fragment import fragment
|
||||||
|
from reflex.components.component import Component
|
||||||
|
|
||||||
|
unique_var_name = get_unique_variable_name()
|
||||||
|
|
||||||
|
@computed_var(_js_expr=unique_var_name, return_type=Component)
|
||||||
|
def computed_var_func(state: Self):
|
||||||
|
return fragment(f(state))
|
||||||
|
|
||||||
|
setattr(cls, unique_var_name, computed_var_func)
|
||||||
|
cls.computed_vars[unique_var_name] = computed_var_func
|
||||||
|
cls.vars[unique_var_name] = computed_var_func
|
||||||
|
cls._update_substate_inherited_vars({unique_var_name: computed_var_func})
|
||||||
|
cls._always_dirty_computed_vars.add(unique_var_name)
|
||||||
|
|
||||||
|
return getattr(cls, unique_var_name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _mixins(cls) -> List[Type]:
|
def _mixins(cls) -> List[Type]:
|
||||||
"""Get the mixin classes of the state.
|
"""Get the mixin classes of the state.
|
||||||
|
@ -1559,8 +1559,9 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|||||||
Raises:
|
Raises:
|
||||||
TypeError: If the computed var dependencies are not Var instances or var names.
|
TypeError: If the computed var dependencies are not Var instances or var names.
|
||||||
"""
|
"""
|
||||||
hints = get_type_hints(fget)
|
hint = kwargs.pop("return_type", None) or get_type_hints(fget).get(
|
||||||
hint = hints.get("return", Any)
|
"return", Any
|
||||||
|
)
|
||||||
|
|
||||||
kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
|
kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
|
||||||
kwargs["_var_type"] = kwargs.pop("_var_type", hint)
|
kwargs["_var_type"] = kwargs.pop("_var_type", hint)
|
||||||
|
@ -16,6 +16,8 @@ def DynamicComponents():
|
|||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
class DynamicComponentsState(rx.State):
|
class DynamicComponentsState(rx.State):
|
||||||
|
value: int = 10
|
||||||
|
|
||||||
button: rx.Component = rx.button(
|
button: rx.Component = rx.button(
|
||||||
"Click me",
|
"Click me",
|
||||||
custom_attrs={
|
custom_attrs={
|
||||||
@ -52,11 +54,20 @@ def DynamicComponents():
|
|||||||
|
|
||||||
app = rx.App()
|
app = rx.App()
|
||||||
|
|
||||||
|
def factorial(n: int) -> int:
|
||||||
|
if n == 0:
|
||||||
|
return 1
|
||||||
|
return n * factorial(n - 1)
|
||||||
|
|
||||||
@app.add_page
|
@app.add_page
|
||||||
def index():
|
def index():
|
||||||
return rx.vstack(
|
return rx.vstack(
|
||||||
DynamicComponentsState.client_token_component,
|
DynamicComponentsState.client_token_component,
|
||||||
DynamicComponentsState.button,
|
DynamicComponentsState.button,
|
||||||
|
rx.text(
|
||||||
|
DynamicComponentsState._evaluate(lambda state: factorial(state.value)),
|
||||||
|
id="factorial",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -150,3 +161,7 @@ def test_dynamic_components(driver, dynamic_components: AppHarness):
|
|||||||
dynamic_components.poll_for_content(button, exp_not_equal="Click me")
|
dynamic_components.poll_for_content(button, exp_not_equal="Click me")
|
||||||
== "Clicked"
|
== "Clicked"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
factorial = poll_for_result(lambda: driver.find_element(By.ID, "factorial"))
|
||||||
|
assert factorial
|
||||||
|
assert factorial.text == "3628800"
|
||||||
|
Loading…
Reference in New Issue
Block a user