move hybrid_property to experimental namespace

This commit is contained in:
Benedikt Bartscher 2024-11-21 00:55:39 +01:00
parent c8527676d4
commit 1b3c82dcee
No known key found for this signature in database
5 changed files with 54 additions and 49 deletions

View File

@ -11,6 +11,7 @@ from ..utils.console import warn
from . import hooks as hooks from . import hooks as hooks
from .assets import asset as asset from .assets import asset as asset
from .client_state import ClientStateVar as ClientStateVar from .client_state import ClientStateVar as ClientStateVar
from .hybrid_property import hybrid_property as hybrid_property
from .layout import layout as layout from .layout import layout as layout
from .misc import run_in_thread as run_in_thread from .misc import run_in_thread as run_in_thread
@ -69,4 +70,5 @@ _x = ExperimentalNamespace(
PropsBase=PropsBase, PropsBase=PropsBase,
run_in_thread=run_in_thread, run_in_thread=run_in_thread,
code_block=code_block, code_block=code_block,
hybrid_property=hybrid_property,
) )

View File

@ -0,0 +1,49 @@
"""hybrid_property decorator which functions like a normal python property but additionally allows (class-level) access from the frontend. You can use the same code for frontend and backend, or implement 2 different methods."""
from typing import Any, Callable
from reflex.utils.types import Self, override
from reflex.vars.base import Var
class HybridProperty(property):
"""A hybrid property that can also be used in frontend/as var."""
# The optional var function for the property.
_var: Callable[[Any], Var] | None = None
@override
def __get__(self, instance: Any, owner: type | None = None, /) -> Any:
"""Get the value of the property. If the property is not bound to an instance return a frontend Var.
Args:
instance: The instance of the class accessing this property.
owner: The class that this descriptor is attached to.
Returns:
The value of the property or a frontend Var.
"""
if instance is not None:
return super().__get__(instance, owner)
if self._var is not None:
# Call custom var function if set
return self._var(owner)
else:
# Call the property getter function if no custom var function is set
assert self.fget is not None
return self.fget(owner)
def var(self, func: Callable[[Any], Var]) -> Self:
"""Set the (optional) var function for the property.
Args:
func: The var function to set.
Returns:
The property instance with the var function set.
"""
self._var = func
return self
hybrid_property = HybridProperty

View File

@ -7,7 +7,6 @@ from .base import VarData as VarData
from .base import field as field from .base import field as field
from .base import get_unique_variable_name as get_unique_variable_name from .base import get_unique_variable_name as get_unique_variable_name
from .base import get_uuid_string_var as get_uuid_string_var from .base import get_uuid_string_var as get_uuid_string_var
from .base import hybrid_property as hybrid_property
from .base import var_operation as var_operation from .base import var_operation as var_operation
from .base import var_operation_return as var_operation_return from .base import var_operation_return as var_operation_return
from .function import FunctionStringVar as FunctionStringVar from .function import FunctionStringVar as FunctionStringVar

View File

@ -2949,49 +2949,3 @@ def field(value: T) -> Field[T]:
The Field. The Field.
""" """
return value # type: ignore return value # type: ignore
VAR_CALLABLE = Callable[[Any], Var]
class HybridProperty(property):
"""A hybrid property that can also be used in frontend/as var."""
# The optional var function for the property.
_var: VAR_CALLABLE | None = None
@override
def __get__(self, instance: Any, owner: type | None = None, /) -> Any:
"""Get the value of the property. If the property is not bound to an instance return a frontend Var.
Args:
instance: The instance of the class accessing this property.
owner: The class that this descriptor is attached to.
Returns:
The value of the property or a frontend Var.
"""
if instance is not None:
return super().__get__(instance, owner)
if self._var is not None:
# Call custom var function if set
return self._var(owner)
else:
# Call the property getter function if no custom var function is set
assert self.fget is not None
return self.fget(owner)
def var(self, func: VAR_CALLABLE) -> Self:
"""Set the (optional) var function for the property.
Args:
func: The var function to set.
Returns:
The property instance with the var function set.
"""
self._var = func
return self
hybrid_property = HybridProperty

View File

@ -14,7 +14,8 @@ from reflex.testing import DEFAULT_TIMEOUT, AppHarness, WebDriver
def HybridProperties(): def HybridProperties():
"""Test app for hybrid properties.""" """Test app for hybrid properties."""
import reflex as rx import reflex as rx
from reflex.vars import Var, hybrid_property from reflex.experimental import hybrid_property
from reflex.vars import Var
class State(rx.State): class State(rx.State):
first_name: str = "John" first_name: str = "John"
@ -71,7 +72,7 @@ def HybridProperties():
rx.text(f"has_last_name: {State.has_last_name}", id="has_last_name"), rx.text(f"has_last_name: {State.has_last_name}", id="has_last_name"),
rx.input( rx.input(
value=State.last_name, value=State.last_name,
on_change=State.set_last_name, # type: ignore on_change=State.setvar("last_name"),
id="set_last_name", id="set_last_name",
), ),
), ),