Merge branch 'main' into lendemor/builtins_states

This commit is contained in:
Lendemor 2024-10-23 17:28:15 +02:00
commit 7320425285
4 changed files with 59 additions and 1 deletions

View File

@ -328,7 +328,10 @@ _MAPPING: dict = {
],
"middleware": ["middleware", "Middleware"],
"model": ["session", "Model"],
"state": ["var"],
"state": [
"var",
"dynamic",
],
"style": ["Style", "toggle_color_mode"],
"utils.imports": ["ImportVar"],
"utils.serializers": ["serializer"],

View File

@ -184,6 +184,7 @@ from .middleware import middleware as middleware
from .model import Model as Model
from .model import session as session
from .page import page as page
from .state import dynamic as dynamic
from .state import var as var
from .style import Style as Style
from .style import toggle_color_mode as toggle_color_mode

View File

@ -30,6 +30,7 @@ from typing import (
Set,
Tuple,
Type,
TypeVar,
Union,
cast,
get_args,
@ -78,6 +79,7 @@ from reflex.utils import console, format, path_ops, prerequisites, types
from reflex.utils.exceptions import (
ComputedVarShadowsBaseVars,
ComputedVarShadowsStateVar,
DynamicComponentInvalidSignature,
DynamicRouteArgShadowsStateVar,
EventHandlerShadowsBuiltInStateMethod,
ImmutableStateError,
@ -94,6 +96,9 @@ from reflex.vars import VarData
Delta = Dict[str, Any]
var = computed_var
if TYPE_CHECKING:
from reflex.components.component import Component
# If the state is this large, it's considered a performance issue.
TOO_LARGE_SERIALIZED_STATE = 100 * 1024 # 100kb
@ -2085,6 +2090,51 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
return state
T = TypeVar("T", bound=BaseState)
def dynamic(func: Callable[[T], Component]):
"""Create a dynamically generated components from a state class.
Args:
func: The function to generate the component.
Returns:
The dynamically generated component.
Raises:
DynamicComponentInvalidSignature: If the function does not have exactly one parameter.
DynamicComponentInvalidSignature: If the function does not have a type hint for the state class.
"""
number_of_parameters = len(inspect.signature(func).parameters)
func_signature = get_type_hints(func)
if "return" in func_signature:
func_signature.pop("return")
values = list(func_signature.values())
if number_of_parameters != 1:
raise DynamicComponentInvalidSignature(
"The function must have exactly one parameter, which is the state class."
)
if len(values) != 1:
raise DynamicComponentInvalidSignature(
"You must provide a type hint for the state class in the function."
)
state_class: Type[T] = values[0]
def wrapper() -> Component:
from reflex.components.base.fragment import fragment
return fragment(state_class._evaluate(lambda state: func(state)))
return wrapper
class StateProxy(wrapt.ObjectProxy):
"""Proxy of a state instance to control mutability of vars for a background task.

View File

@ -139,3 +139,7 @@ class StateSchemaMismatchError(ReflexError, TypeError):
class EnvironmentVarValueError(ReflexError, ValueError):
"""Raised when an environment variable is set to an invalid value."""
class DynamicComponentInvalidSignature(ReflexError, TypeError):
"""Raised when a dynamic component has an invalid signature."""