add immutable var class ()

* add immutable var class

* add missing docs

* override _replace

* fix type imports

* override create as well

* remove deprecated properties and arguments

* remove unused code in ImmutableVar

* fix namespace issue

* no Self in 3.8
This commit is contained in:
Khaleel Al-Adhami 2024-07-03 21:23:04 +03:00 committed by GitHub
parent 59752d0cde
commit 046c0f9760
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 163 additions and 0 deletions
reflex/experimental

View File

@ -8,6 +8,7 @@ from reflex.components.sonner.toast import toast as toast
from ..utils.console import warn
from . import hooks as hooks
from . import vars as vars
from .assets import asset as asset
from .client_state import ClientStateVar as ClientStateVar
from .layout import layout as layout
@ -42,6 +43,7 @@ _x = ExperimentalNamespace(
asset=asset,
client_state=ClientStateVar.create,
hooks=hooks,
vars=vars,
layout=layout,
progress=progress,
PropsBase=PropsBase,

View File

@ -0,0 +1,3 @@
"""Experimental Immutable-Based Var System."""
from .base import ImmutableVar as ImmutableVar

View File

@ -0,0 +1,158 @@
"""Collection of base classes."""
from __future__ import annotations
import dataclasses
import sys
from typing import Any, Optional, Type
from reflex.utils import serializers, types
from reflex.utils.exceptions import VarTypeError
from reflex.vars import Var, VarData, _extract_var_data
@dataclasses.dataclass(
eq=False,
frozen=True,
**{"slots": True} if sys.version_info >= (3, 10) else {},
)
class ImmutableVar(Var):
"""Base class for immutable vars."""
# The name of the var.
_var_name: str = dataclasses.field()
# The type of the var.
_var_type: Type = dataclasses.field(default=Any)
# Extra metadata associated with the Var
_var_data: Optional[VarData] = dataclasses.field(default=None)
@property
def _var_is_local(self) -> bool:
"""Whether this is a local javascript variable.
Returns:
False
"""
return False
@property
def _var_is_string(self) -> bool:
"""Whether the var is a string literal.
Returns:
False
"""
return False
@property
def _var_full_name_needs_state_prefix(self) -> bool:
"""Whether the full name of the var needs a _var_state prefix.
Returns:
False
"""
return False
def _replace(self, merge_var_data=None, **kwargs: Any):
"""Make a copy of this Var with updated fields.
Args:
merge_var_data: VarData to merge into the existing VarData.
**kwargs: Var fields to update.
Returns:
A new ImmutableVar with the updated fields overwriting the corresponding fields in this Var.
Raises:
TypeError: If _var_is_local, _var_is_string, or _var_full_name_needs_state_prefix is not None.
"""
if kwargs.get("_var_is_local", False) is not False:
raise TypeError(
"The _var_is_local argument is not supported for ImmutableVar."
)
if kwargs.get("_var_is_string", False) is not False:
raise TypeError(
"The _var_is_string argument is not supported for ImmutableVar."
)
if kwargs.get("_var_full_name_needs_state_prefix", False) is not False:
raise TypeError(
"The _var_full_name_needs_state_prefix argument is not supported for ImmutableVar."
)
field_values = dict(
_var_name=kwargs.pop("_var_name", self._var_name),
_var_type=kwargs.pop("_var_type", self._var_type),
_var_data=VarData.merge(
kwargs.get("_var_data", self._var_data), merge_var_data
),
)
return ImmutableVar(**field_values)
@classmethod
def create(
cls,
value: Any,
_var_is_local: bool | None = None,
_var_is_string: bool | None = None,
_var_data: VarData | None = None,
) -> Var | None:
"""Create a var from a value.
Args:
value: The value to create the var from.
_var_is_local: Whether the var is local. Deprecated.
_var_is_string: Whether the var is a string literal. Deprecated.
_var_data: Additional hooks and imports associated with the Var.
Returns:
The var.
Raises:
VarTypeError: If the value is JSON-unserializable.
TypeError: If _var_is_local or _var_is_string is not None.
"""
if _var_is_local is not None:
raise TypeError(
"The _var_is_local argument is not supported for ImmutableVar."
)
if _var_is_string is not None:
raise TypeError(
"The _var_is_string argument is not supported for ImmutableVar."
)
from reflex.utils import format
# Check for none values.
if value is None:
return None
# If the value is already a var, do nothing.
if isinstance(value, Var):
return value
# Try to pull the imports and hooks from contained values.
if not isinstance(value, str):
_var_data = VarData.merge(*_extract_var_data(value), _var_data)
# Try to serialize the value.
type_ = type(value)
if type_ in types.JSONType:
name = value
else:
name, _serialized_type = serializers.serialize(value, get_type=True)
if name is None:
raise VarTypeError(
f"No JSON serializer found for var {value} of type {type_}."
)
name = name if isinstance(name, str) else format.json_dumps(name)
return ImmutableVar(
_var_name=name,
_var_type=type_,
_var_data=_var_data,
)