|
@@ -12,7 +12,6 @@ import json
|
|
|
import random
|
|
|
import re
|
|
|
import string
|
|
|
-import sys
|
|
|
import warnings
|
|
|
from types import CodeType, FunctionType
|
|
|
from typing import (
|
|
@@ -82,6 +81,7 @@ if TYPE_CHECKING:
|
|
|
VAR_TYPE = TypeVar("VAR_TYPE", covariant=True)
|
|
|
OTHER_VAR_TYPE = TypeVar("OTHER_VAR_TYPE")
|
|
|
STRING_T = TypeVar("STRING_T", bound=str)
|
|
|
+SEQUENCE_TYPE = TypeVar("SEQUENCE_TYPE", bound=Sequence)
|
|
|
|
|
|
warnings.filterwarnings("ignore", message="fields may not start with an underscore")
|
|
|
|
|
@@ -449,7 +449,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
@dataclasses.dataclass(
|
|
|
eq=False,
|
|
|
frozen=True,
|
|
|
- **{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
|
+ slots=True,
|
|
|
)
|
|
|
class ToVarOperation(ToOperation, cls):
|
|
|
"""Base class of converting a var to another var type."""
|
|
@@ -597,7 +597,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
|
|
|
@overload
|
|
|
@classmethod
|
|
|
- def create(
|
|
|
+ def create( # pyright: ignore [reportOverlappingOverload]
|
|
|
cls,
|
|
|
value: STRING_T,
|
|
|
_var_data: VarData | None = None,
|
|
@@ -611,6 +611,22 @@ class Var(Generic[VAR_TYPE]):
|
|
|
_var_data: VarData | None = None,
|
|
|
) -> NoneVar: ...
|
|
|
|
|
|
+ @overload
|
|
|
+ @classmethod
|
|
|
+ def create(
|
|
|
+ cls,
|
|
|
+ value: MAPPING_TYPE,
|
|
|
+ _var_data: VarData | None = None,
|
|
|
+ ) -> ObjectVar[MAPPING_TYPE]: ...
|
|
|
+
|
|
|
+ @overload
|
|
|
+ @classmethod
|
|
|
+ def create(
|
|
|
+ cls,
|
|
|
+ value: SEQUENCE_TYPE,
|
|
|
+ _var_data: VarData | None = None,
|
|
|
+ ) -> ArrayVar[SEQUENCE_TYPE]: ...
|
|
|
+
|
|
|
@overload
|
|
|
@classmethod
|
|
|
def create(
|
|
@@ -692,8 +708,8 @@ class Var(Generic[VAR_TYPE]):
|
|
|
@overload
|
|
|
def to(
|
|
|
self,
|
|
|
- output: type[Mapping],
|
|
|
- ) -> ObjectVar[Mapping]: ...
|
|
|
+ output: type[MAPPING_TYPE],
|
|
|
+ ) -> ObjectVar[MAPPING_TYPE]: ...
|
|
|
|
|
|
@overload
|
|
|
def to(
|
|
@@ -744,7 +760,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
return get_to_operation(NoneVar).create(self) # pyright: ignore [reportReturnType]
|
|
|
|
|
|
# Handle fixed_output_type being Base or a dataclass.
|
|
|
- if can_use_in_object_var(fixed_output_type):
|
|
|
+ if can_use_in_object_var(output):
|
|
|
return self.to(ObjectVar, output)
|
|
|
|
|
|
if inspect.isclass(output):
|
|
@@ -776,6 +792,9 @@ class Var(Generic[VAR_TYPE]):
|
|
|
|
|
|
return self
|
|
|
|
|
|
+ @overload
|
|
|
+ def guess_type(self: Var[NoReturn]) -> Var[Any]: ... # pyright: ignore [reportOverlappingOverload]
|
|
|
+
|
|
|
@overload
|
|
|
def guess_type(self: Var[str]) -> StringVar: ...
|
|
|
|
|
@@ -785,6 +804,9 @@ class Var(Generic[VAR_TYPE]):
|
|
|
@overload
|
|
|
def guess_type(self: Var[int] | Var[float] | Var[int | float]) -> NumberVar: ...
|
|
|
|
|
|
+ @overload
|
|
|
+ def guess_type(self: Var[BASE_TYPE]) -> ObjectVar[BASE_TYPE]: ...
|
|
|
+
|
|
|
@overload
|
|
|
def guess_type(self) -> Self: ...
|
|
|
|
|
@@ -933,7 +955,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
|
|
|
return setter
|
|
|
|
|
|
- def _var_set_state(self, state: type[BaseState] | str):
|
|
|
+ def _var_set_state(self, state: type[BaseState] | str) -> Self:
|
|
|
"""Set the state of the var.
|
|
|
|
|
|
Args:
|
|
@@ -948,7 +970,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
else format_state_name(state.get_full_name())
|
|
|
)
|
|
|
|
|
|
- return StateOperation.create(
|
|
|
+ return StateOperation.create( # pyright: ignore [reportReturnType]
|
|
|
formatted_state_name,
|
|
|
self,
|
|
|
_var_data=VarData.merge(
|
|
@@ -1127,43 +1149,6 @@ class Var(Generic[VAR_TYPE]):
|
|
|
"""
|
|
|
return self
|
|
|
|
|
|
- def __getattr__(self, name: str):
|
|
|
- """Get an attribute of the var.
|
|
|
-
|
|
|
- Args:
|
|
|
- name: The name of the attribute.
|
|
|
-
|
|
|
- Returns:
|
|
|
- The attribute.
|
|
|
-
|
|
|
- Raises:
|
|
|
- VarAttributeError: If the attribute does not exist.
|
|
|
- TypeError: If the var type is Any.
|
|
|
- """
|
|
|
- if name.startswith("_"):
|
|
|
- return self.__getattribute__(name)
|
|
|
-
|
|
|
- if name == "contains":
|
|
|
- raise TypeError(
|
|
|
- f"Var of type {self._var_type} does not support contains check."
|
|
|
- )
|
|
|
- if name == "reverse":
|
|
|
- raise TypeError("Cannot reverse non-list var.")
|
|
|
-
|
|
|
- if self._var_type is Any:
|
|
|
- raise TypeError(
|
|
|
- f"You must provide an annotation for the state var `{self!s}`. Annotation cannot be `{self._var_type}`."
|
|
|
- )
|
|
|
-
|
|
|
- if name in REPLACED_NAMES:
|
|
|
- raise VarAttributeError(
|
|
|
- f"Field {name!r} was renamed to {REPLACED_NAMES[name]!r}"
|
|
|
- )
|
|
|
-
|
|
|
- raise VarAttributeError(
|
|
|
- f"The State var has no attribute '{name}' or may have been annotated wrongly.",
|
|
|
- )
|
|
|
-
|
|
|
def _decode(self) -> Any:
|
|
|
"""Decode Var as a python value.
|
|
|
|
|
@@ -1225,36 +1210,76 @@ class Var(Generic[VAR_TYPE]):
|
|
|
|
|
|
return ArrayVar.range(first_endpoint, second_endpoint, step)
|
|
|
|
|
|
- def __bool__(self) -> bool:
|
|
|
- """Raise exception if using Var in a boolean context.
|
|
|
+ if not TYPE_CHECKING:
|
|
|
|
|
|
- Raises:
|
|
|
- VarTypeError: when attempting to bool-ify the Var.
|
|
|
- """
|
|
|
- raise VarTypeError(
|
|
|
- f"Cannot convert Var {str(self)!r} to bool for use with `if`, `and`, `or`, and `not`. "
|
|
|
- "Instead use `rx.cond` and bitwise operators `&` (and), `|` (or), `~` (invert)."
|
|
|
- )
|
|
|
+ def __getattr__(self, name: str):
|
|
|
+ """Get an attribute of the var.
|
|
|
|
|
|
- def __iter__(self) -> Any:
|
|
|
- """Raise exception if using Var in an iterable context.
|
|
|
+ Args:
|
|
|
+ name: The name of the attribute.
|
|
|
|
|
|
- Raises:
|
|
|
- VarTypeError: when attempting to iterate over the Var.
|
|
|
- """
|
|
|
- raise VarTypeError(
|
|
|
- f"Cannot iterate over Var {str(self)!r}. Instead use `rx.foreach`."
|
|
|
- )
|
|
|
+ Raises:
|
|
|
+ VarAttributeError: If the attribute does not exist.
|
|
|
+ UntypedVarError: If the var type is Any.
|
|
|
+ TypeError: If the var type is Any.
|
|
|
|
|
|
- def __contains__(self, _: Any) -> Var:
|
|
|
- """Override the 'in' operator to alert the user that it is not supported.
|
|
|
+ # noqa: DAR101 self
|
|
|
+ """
|
|
|
+ if name.startswith("_"):
|
|
|
+ raise VarAttributeError(f"Attribute {name} not found.")
|
|
|
|
|
|
- Raises:
|
|
|
- VarTypeError: the operation is not supported
|
|
|
- """
|
|
|
- raise VarTypeError(
|
|
|
- "'in' operator not supported for Var types, use Var.contains() instead."
|
|
|
- )
|
|
|
+ if name == "contains":
|
|
|
+ raise TypeError(
|
|
|
+ f"Var of type {self._var_type} does not support contains check."
|
|
|
+ )
|
|
|
+ if name == "reverse":
|
|
|
+ raise TypeError("Cannot reverse non-list var.")
|
|
|
+
|
|
|
+ if self._var_type is Any:
|
|
|
+ raise exceptions.UntypedVarError(
|
|
|
+ f"You must provide an annotation for the state var `{self!s}`. Annotation cannot be `{self._var_type}`."
|
|
|
+ )
|
|
|
+
|
|
|
+ raise VarAttributeError(
|
|
|
+ f"The State var has no attribute '{name}' or may have been annotated wrongly.",
|
|
|
+ )
|
|
|
+
|
|
|
+ def __bool__(self) -> bool:
|
|
|
+ """Raise exception if using Var in a boolean context.
|
|
|
+
|
|
|
+ Raises:
|
|
|
+ VarTypeError: when attempting to bool-ify the Var.
|
|
|
+
|
|
|
+ # noqa: DAR101 self
|
|
|
+ """
|
|
|
+ raise VarTypeError(
|
|
|
+ f"Cannot convert Var {str(self)!r} to bool for use with `if`, `and`, `or`, and `not`. "
|
|
|
+ "Instead use `rx.cond` and bitwise operators `&` (and), `|` (or), `~` (invert)."
|
|
|
+ )
|
|
|
+
|
|
|
+ def __iter__(self) -> Any:
|
|
|
+ """Raise exception if using Var in an iterable context.
|
|
|
+
|
|
|
+ Raises:
|
|
|
+ VarTypeError: when attempting to iterate over the Var.
|
|
|
+
|
|
|
+ # noqa: DAR101 self
|
|
|
+ """
|
|
|
+ raise VarTypeError(
|
|
|
+ f"Cannot iterate over Var {str(self)!r}. Instead use `rx.foreach`."
|
|
|
+ )
|
|
|
+
|
|
|
+ def __contains__(self, _: Any) -> Var:
|
|
|
+ """Override the 'in' operator to alert the user that it is not supported.
|
|
|
+
|
|
|
+ Raises:
|
|
|
+ VarTypeError: the operation is not supported
|
|
|
+
|
|
|
+ # noqa: DAR101 self
|
|
|
+ """
|
|
|
+ raise VarTypeError(
|
|
|
+ "'in' operator not supported for Var types, use Var.contains() instead."
|
|
|
+ )
|
|
|
|
|
|
|
|
|
OUTPUT = TypeVar("OUTPUT", bound=Var)
|
|
@@ -1471,6 +1496,12 @@ class LiteralVar(Var):
|
|
|
def __post_init__(self):
|
|
|
"""Post-initialize the var."""
|
|
|
|
|
|
+ @property
|
|
|
+ def _var_value(self) -> Any:
|
|
|
+ raise NotImplementedError(
|
|
|
+ "LiteralVar subclasses must implement the _var_value property."
|
|
|
+ )
|
|
|
+
|
|
|
def json(self) -> str:
|
|
|
"""Serialize the var to a JSON string.
|
|
|
|
|
@@ -1543,7 +1574,7 @@ def var_operation(
|
|
|
) -> Callable[P, StringVar]: ...
|
|
|
|
|
|
|
|
|
-LIST_T = TypeVar("LIST_T", bound=Union[List[Any], Tuple, Set])
|
|
|
+LIST_T = TypeVar("LIST_T", bound=Sequence)
|
|
|
|
|
|
|
|
|
@overload
|
|
@@ -1780,7 +1811,7 @@ def _or_operation(a: Var, b: Var):
|
|
|
@dataclasses.dataclass(
|
|
|
eq=False,
|
|
|
frozen=True,
|
|
|
- **{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
|
+ slots=True,
|
|
|
)
|
|
|
class CallableVar(Var):
|
|
|
"""Decorate a Var-returning function to act as both a Var and a function.
|
|
@@ -1861,7 +1892,7 @@ def is_computed_var(obj: Any) -> TypeGuard[ComputedVar]:
|
|
|
@dataclasses.dataclass(
|
|
|
eq=False,
|
|
|
frozen=True,
|
|
|
- **{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
|
+ slots=True,
|
|
|
)
|
|
|
class ComputedVar(Var[RETURN_TYPE]):
|
|
|
"""A field with computed getters."""
|
|
@@ -2070,13 +2101,6 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|
|
owner: Type,
|
|
|
) -> ArrayVar[list[LIST_INSIDE]]: ...
|
|
|
|
|
|
- @overload
|
|
|
- def __get__(
|
|
|
- self: ComputedVar[set[LIST_INSIDE]],
|
|
|
- instance: None,
|
|
|
- owner: Type,
|
|
|
- ) -> ArrayVar[set[LIST_INSIDE]]: ...
|
|
|
-
|
|
|
@overload
|
|
|
def __get__(
|
|
|
self: ComputedVar[tuple[LIST_INSIDE, ...]],
|
|
@@ -2436,7 +2460,7 @@ def var_operation_return(
|
|
|
@dataclasses.dataclass(
|
|
|
eq=False,
|
|
|
frozen=True,
|
|
|
- **{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
|
+ slots=True,
|
|
|
)
|
|
|
class CustomVarOperation(CachedVarOperation, Var[T]):
|
|
|
"""Base class for custom var operations."""
|
|
@@ -2507,7 +2531,7 @@ class NoneVar(Var[None], python_types=type(None)):
|
|
|
@dataclasses.dataclass(
|
|
|
eq=False,
|
|
|
frozen=True,
|
|
|
- **{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
|
+ slots=True,
|
|
|
)
|
|
|
class LiteralNoneVar(LiteralVar, NoneVar):
|
|
|
"""A var representing None."""
|
|
@@ -2569,7 +2593,7 @@ def get_to_operation(var_subclass: Type[Var]) -> Type[ToOperation]:
|
|
|
@dataclasses.dataclass(
|
|
|
eq=False,
|
|
|
frozen=True,
|
|
|
- **{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
|
+ slots=True,
|
|
|
)
|
|
|
class StateOperation(CachedVarOperation, Var):
|
|
|
"""A var operation that accesses a field on an object."""
|
|
@@ -2716,19 +2740,6 @@ def _extract_var_data(value: Iterable) -> list[VarData | None]:
|
|
|
return var_datas
|
|
|
|
|
|
|
|
|
-# These names were changed in reflex 0.3.0
|
|
|
-REPLACED_NAMES = {
|
|
|
- "full_name": "_var_full_name",
|
|
|
- "name": "_js_expr",
|
|
|
- "state": "_var_data.state",
|
|
|
- "type_": "_var_type",
|
|
|
- "is_local": "_var_is_local",
|
|
|
- "is_string": "_var_is_string",
|
|
|
- "set_state": "_var_set_state",
|
|
|
- "deps": "_deps",
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
dispatchers: Dict[GenericType, Callable[[Var], Var]] = {}
|
|
|
|
|
|
|