Merge remote-tracking branch 'upstream/main' into state-compression
This commit is contained in:
commit
873b3a1306
@ -410,7 +410,14 @@ export const connect = async (
|
|||||||
autoUnref: false,
|
autoUnref: false,
|
||||||
});
|
});
|
||||||
// Ensure undefined fields in events are sent as null instead of removed
|
// Ensure undefined fields in events are sent as null instead of removed
|
||||||
socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v)
|
socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v);
|
||||||
|
socket.current.io.decoder.tryParse = (str) => {
|
||||||
|
try {
|
||||||
|
return JSON5.parse(str);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function checkVisibility() {
|
function checkVisibility() {
|
||||||
if (document.visibilityState === "visible") {
|
if (document.visibilityState === "visible") {
|
||||||
|
@ -136,6 +136,23 @@ def load_dynamic_serializer():
|
|||||||
|
|
||||||
module_code_lines.insert(0, "const React = window.__reflex.react;")
|
module_code_lines.insert(0, "const React = window.__reflex.react;")
|
||||||
|
|
||||||
|
function_line = next(
|
||||||
|
index
|
||||||
|
for index, line in enumerate(module_code_lines)
|
||||||
|
if line.startswith("export default function")
|
||||||
|
)
|
||||||
|
|
||||||
|
module_code_lines = [
|
||||||
|
line
|
||||||
|
for _, line in sorted(
|
||||||
|
enumerate(module_code_lines),
|
||||||
|
key=lambda x: (
|
||||||
|
not (x[1].startswith("import ") and x[0] < function_line),
|
||||||
|
x[0],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
return "\n".join(
|
return "\n".join(
|
||||||
[
|
[
|
||||||
"//__reflex_evaluate",
|
"//__reflex_evaluate",
|
||||||
|
@ -151,8 +151,8 @@ class ColorModeIconButton(IconButton):
|
|||||||
dropdown_menu.trigger(
|
dropdown_menu.trigger(
|
||||||
super().create(
|
super().create(
|
||||||
ColorModeIcon.create(),
|
ColorModeIcon.create(),
|
||||||
**props,
|
),
|
||||||
)
|
**props,
|
||||||
),
|
),
|
||||||
dropdown_menu.content(
|
dropdown_menu.content(
|
||||||
color_mode_item("light"),
|
color_mode_item("light"),
|
||||||
|
@ -567,6 +567,9 @@ class EnvironmentVariables:
|
|||||||
# The maximum size of the reflex state in kilobytes.
|
# The maximum size of the reflex state in kilobytes.
|
||||||
REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
|
REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
|
||||||
|
|
||||||
|
# Whether to use the turbopack bundler.
|
||||||
|
REFLEX_USE_TURBOPACK: EnvVar[bool] = env_var(True)
|
||||||
|
|
||||||
# Whether to compress the reflex state.
|
# Whether to compress the reflex state.
|
||||||
REFLEX_COMPRESS_STATE: EnvVar[bool] = env_var(False)
|
REFLEX_COMPRESS_STATE: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ class PackageJson(SimpleNamespace):
|
|||||||
"@emotion/react": "11.13.3",
|
"@emotion/react": "11.13.3",
|
||||||
"axios": "1.7.7",
|
"axios": "1.7.7",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"next": "14.2.16",
|
"next": "15.1.4",
|
||||||
"next-sitemap": "4.2.3",
|
"next-sitemap": "4.2.3",
|
||||||
"next-themes": "0.4.3",
|
"next-themes": "0.4.3",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
|
@ -519,7 +519,9 @@ def deploy(
|
|||||||
if prerequisites.needs_reinit(frontend=True):
|
if prerequisites.needs_reinit(frontend=True):
|
||||||
_init(name=config.app_name, loglevel=loglevel)
|
_init(name=config.app_name, loglevel=loglevel)
|
||||||
prerequisites.check_latest_package_version(constants.ReflexHostingCLI.MODULE_NAME)
|
prerequisites.check_latest_package_version(constants.ReflexHostingCLI.MODULE_NAME)
|
||||||
|
extra: dict[str, str] = (
|
||||||
|
{"config_path": config_path} if config_path is not None else {}
|
||||||
|
)
|
||||||
hosting_cli.deploy(
|
hosting_cli.deploy(
|
||||||
app_name=app_name,
|
app_name=app_name,
|
||||||
export_fn=lambda zip_dest_dir,
|
export_fn=lambda zip_dest_dir,
|
||||||
@ -545,7 +547,7 @@ def deploy(
|
|||||||
loglevel=type(loglevel).INFO, # type: ignore
|
loglevel=type(loglevel).INFO, # type: ignore
|
||||||
token=token,
|
token=token,
|
||||||
project=project,
|
project=project,
|
||||||
config_path=config_path,
|
**extra,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ from reflex.utils.exceptions import (
|
|||||||
LockExpiredError,
|
LockExpiredError,
|
||||||
ReflexRuntimeError,
|
ReflexRuntimeError,
|
||||||
SetUndefinedStateVarError,
|
SetUndefinedStateVarError,
|
||||||
|
StateMismatchError,
|
||||||
StateSchemaMismatchError,
|
StateSchemaMismatchError,
|
||||||
StateSerializationError,
|
StateSerializationError,
|
||||||
StateTooLargeError,
|
StateTooLargeError,
|
||||||
@ -1204,7 +1205,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
fget=func,
|
fget=func,
|
||||||
auto_deps=False,
|
auto_deps=False,
|
||||||
deps=["router"],
|
deps=["router"],
|
||||||
cache=True,
|
|
||||||
_js_expr=param,
|
_js_expr=param,
|
||||||
_var_data=VarData.from_state(cls),
|
_var_data=VarData.from_state(cls),
|
||||||
)
|
)
|
||||||
@ -1548,7 +1548,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
# Return the direct parent of target_state_cls for subsequent linking.
|
# Return the direct parent of target_state_cls for subsequent linking.
|
||||||
return parent_state
|
return parent_state
|
||||||
|
|
||||||
def _get_state_from_cache(self, state_cls: Type[BaseState]) -> BaseState:
|
def _get_state_from_cache(self, state_cls: Type[T_STATE]) -> T_STATE:
|
||||||
"""Get a state instance from the cache.
|
"""Get a state instance from the cache.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -1556,11 +1556,19 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The instance of state_cls associated with this state's client_token.
|
The instance of state_cls associated with this state's client_token.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
StateMismatchError: If the state instance is not of the expected type.
|
||||||
"""
|
"""
|
||||||
root_state = self._get_root_state()
|
root_state = self._get_root_state()
|
||||||
return root_state.get_substate(state_cls.get_full_name().split("."))
|
substate = root_state.get_substate(state_cls.get_full_name().split("."))
|
||||||
|
if not isinstance(substate, state_cls):
|
||||||
|
raise StateMismatchError(
|
||||||
|
f"Searched for state {state_cls.get_full_name()} but found {substate}."
|
||||||
|
)
|
||||||
|
return substate
|
||||||
|
|
||||||
async def _get_state_from_redis(self, state_cls: Type[BaseState]) -> BaseState:
|
async def _get_state_from_redis(self, state_cls: Type[T_STATE]) -> T_STATE:
|
||||||
"""Get a state instance from redis.
|
"""Get a state instance from redis.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -1571,6 +1579,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
RuntimeError: If redis is not used in this backend process.
|
RuntimeError: If redis is not used in this backend process.
|
||||||
|
StateMismatchError: If the state instance is not of the expected type.
|
||||||
"""
|
"""
|
||||||
# Fetch all missing parent states from redis.
|
# Fetch all missing parent states from redis.
|
||||||
parent_state_of_state_cls = await self._populate_parent_states(state_cls)
|
parent_state_of_state_cls = await self._populate_parent_states(state_cls)
|
||||||
@ -1582,14 +1591,22 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
f"Requested state {state_cls.get_full_name()} is not cached and cannot be accessed without redis. "
|
f"Requested state {state_cls.get_full_name()} is not cached and cannot be accessed without redis. "
|
||||||
"(All states should already be available -- this is likely a bug).",
|
"(All states should already be available -- this is likely a bug).",
|
||||||
)
|
)
|
||||||
return await state_manager.get_state(
|
|
||||||
|
state_in_redis = await state_manager.get_state(
|
||||||
token=_substate_key(self.router.session.client_token, state_cls),
|
token=_substate_key(self.router.session.client_token, state_cls),
|
||||||
top_level=False,
|
top_level=False,
|
||||||
get_substates=True,
|
get_substates=True,
|
||||||
parent_state=parent_state_of_state_cls,
|
parent_state=parent_state_of_state_cls,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_state(self, state_cls: Type[BaseState]) -> BaseState:
|
if not isinstance(state_in_redis, state_cls):
|
||||||
|
raise StateMismatchError(
|
||||||
|
f"Searched for state {state_cls.get_full_name()} but found {state_in_redis}."
|
||||||
|
)
|
||||||
|
|
||||||
|
return state_in_redis
|
||||||
|
|
||||||
|
async def get_state(self, state_cls: Type[T_STATE]) -> T_STATE:
|
||||||
"""Get an instance of the state associated with this token.
|
"""Get an instance of the state associated with this token.
|
||||||
|
|
||||||
Allows for arbitrary access to sibling states from within an event handler.
|
Allows for arbitrary access to sibling states from within an event handler.
|
||||||
@ -2358,6 +2375,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
return state # type: ignore
|
return state # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
T_STATE = TypeVar("T_STATE", bound=BaseState)
|
||||||
|
|
||||||
|
|
||||||
class State(BaseState):
|
class State(BaseState):
|
||||||
"""The app Base State."""
|
"""The app Base State."""
|
||||||
|
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
from types import FrameType
|
||||||
|
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
|
from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
|
||||||
from rich.prompt import Prompt
|
from rich.prompt import Prompt
|
||||||
@ -188,6 +193,33 @@ def warn(msg: str, dedupe: bool = False, **kwargs):
|
|||||||
print(f"[orange1]Warning: {msg}[/orange1]", **kwargs)
|
print(f"[orange1]Warning: {msg}[/orange1]", **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_first_non_framework_frame() -> FrameType | None:
|
||||||
|
import click
|
||||||
|
import typer
|
||||||
|
import typing_extensions
|
||||||
|
|
||||||
|
import reflex as rx
|
||||||
|
|
||||||
|
# Exclude utility modules that should never be the source of deprecated reflex usage.
|
||||||
|
exclude_modules = [click, rx, typer, typing_extensions]
|
||||||
|
exclude_roots = [
|
||||||
|
p.parent.resolve()
|
||||||
|
if (p := Path(m.__file__)).name == "__init__.py"
|
||||||
|
else p.resolve()
|
||||||
|
for m in exclude_modules
|
||||||
|
]
|
||||||
|
# Specifically exclude the reflex cli module.
|
||||||
|
if reflex_bin := shutil.which(b"reflex"):
|
||||||
|
exclude_roots.append(Path(reflex_bin.decode()))
|
||||||
|
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
while frame := frame and frame.f_back:
|
||||||
|
frame_path = Path(inspect.getfile(frame)).resolve()
|
||||||
|
if not any(frame_path.is_relative_to(root) for root in exclude_roots):
|
||||||
|
break
|
||||||
|
return frame
|
||||||
|
|
||||||
|
|
||||||
def deprecate(
|
def deprecate(
|
||||||
feature_name: str,
|
feature_name: str,
|
||||||
reason: str,
|
reason: str,
|
||||||
@ -206,15 +238,27 @@ def deprecate(
|
|||||||
dedupe: If True, suppress multiple console logs of deprecation message.
|
dedupe: If True, suppress multiple console logs of deprecation message.
|
||||||
kwargs: Keyword arguments to pass to the print function.
|
kwargs: Keyword arguments to pass to the print function.
|
||||||
"""
|
"""
|
||||||
if feature_name not in _EMITTED_DEPRECATION_WARNINGS:
|
dedupe_key = feature_name
|
||||||
|
loc = ""
|
||||||
|
|
||||||
|
# See if we can find where the deprecation exists in "user code"
|
||||||
|
origin_frame = _get_first_non_framework_frame()
|
||||||
|
if origin_frame is not None:
|
||||||
|
filename = Path(origin_frame.f_code.co_filename)
|
||||||
|
if filename.is_relative_to(Path.cwd()):
|
||||||
|
filename = filename.relative_to(Path.cwd())
|
||||||
|
loc = f"{filename}:{origin_frame.f_lineno}"
|
||||||
|
dedupe_key = f"{dedupe_key} {loc}"
|
||||||
|
|
||||||
|
if dedupe_key not in _EMITTED_DEPRECATION_WARNINGS:
|
||||||
msg = (
|
msg = (
|
||||||
f"{feature_name} has been deprecated in version {deprecation_version} {reason.rstrip('.')}. It will be completely "
|
f"{feature_name} has been deprecated in version {deprecation_version} {reason.rstrip('.')}. It will be completely "
|
||||||
f"removed in {removal_version}"
|
f"removed in {removal_version}. ({loc})"
|
||||||
)
|
)
|
||||||
if _LOG_LEVEL <= LogLevel.WARNING:
|
if _LOG_LEVEL <= LogLevel.WARNING:
|
||||||
print(f"[yellow]DeprecationWarning: {msg}[/yellow]", **kwargs)
|
print(f"[yellow]DeprecationWarning: {msg}[/yellow]", **kwargs)
|
||||||
if dedupe:
|
if dedupe:
|
||||||
_EMITTED_DEPRECATION_WARNINGS.add(feature_name)
|
_EMITTED_DEPRECATION_WARNINGS.add(dedupe_key)
|
||||||
|
|
||||||
|
|
||||||
def error(msg: str, dedupe: bool = False, **kwargs):
|
def error(msg: str, dedupe: bool = False, **kwargs):
|
||||||
|
@ -163,6 +163,10 @@ class StateSerializationError(ReflexError):
|
|||||||
"""Raised when the state cannot be serialized."""
|
"""Raised when the state cannot be serialized."""
|
||||||
|
|
||||||
|
|
||||||
|
class StateMismatchError(ReflexError, ValueError):
|
||||||
|
"""Raised when the state retrieved does not match the expected state."""
|
||||||
|
|
||||||
|
|
||||||
class SystemPackageMissingError(ReflexError):
|
class SystemPackageMissingError(ReflexError):
|
||||||
"""Raised when a system package is missing."""
|
"""Raised when a system package is missing."""
|
||||||
|
|
||||||
|
@ -610,10 +610,14 @@ def initialize_web_directory():
|
|||||||
init_reflex_json(project_hash=project_hash)
|
init_reflex_json(project_hash=project_hash)
|
||||||
|
|
||||||
|
|
||||||
|
def _turbopack_flag() -> str:
|
||||||
|
return " --turbopack" if environment.REFLEX_USE_TURBOPACK.get() else ""
|
||||||
|
|
||||||
|
|
||||||
def _compile_package_json():
|
def _compile_package_json():
|
||||||
return templates.PACKAGE_JSON.render(
|
return templates.PACKAGE_JSON.render(
|
||||||
scripts={
|
scripts={
|
||||||
"dev": constants.PackageJson.Commands.DEV,
|
"dev": constants.PackageJson.Commands.DEV + _turbopack_flag(),
|
||||||
"export": constants.PackageJson.Commands.EXPORT,
|
"export": constants.PackageJson.Commands.EXPORT,
|
||||||
"export_sitemap": constants.PackageJson.Commands.EXPORT_SITEMAP,
|
"export_sitemap": constants.PackageJson.Commands.EXPORT_SITEMAP,
|
||||||
"prod": constants.PackageJson.Commands.PROD,
|
"prod": constants.PackageJson.Commands.PROD,
|
||||||
|
@ -17,6 +17,7 @@ import typer
|
|||||||
from redis.exceptions import RedisError
|
from redis.exceptions import RedisError
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.utils import console, path_ops, prerequisites
|
from reflex.utils import console, path_ops, prerequisites
|
||||||
|
|
||||||
|
|
||||||
@ -156,24 +157,30 @@ def new_process(args, run: bool = False, show_logs: bool = False, **kwargs):
|
|||||||
Raises:
|
Raises:
|
||||||
Exit: When attempting to run a command with a None value.
|
Exit: When attempting to run a command with a None value.
|
||||||
"""
|
"""
|
||||||
node_bin_path = str(path_ops.get_node_bin_path())
|
# Check for invalid command first.
|
||||||
if not node_bin_path and not prerequisites.CURRENTLY_INSTALLING_NODE:
|
|
||||||
console.warn(
|
|
||||||
"The path to the Node binary could not be found. Please ensure that Node is properly "
|
|
||||||
"installed and added to your system's PATH environment variable or try running "
|
|
||||||
"`reflex init` again."
|
|
||||||
)
|
|
||||||
if None in args:
|
if None in args:
|
||||||
console.error(f"Invalid command: {args}")
|
console.error(f"Invalid command: {args}")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
# Add the node bin path to the PATH environment variable.
|
|
||||||
|
path_env: str = os.environ.get("PATH", "")
|
||||||
|
|
||||||
|
# Add node_bin_path to the PATH environment variable.
|
||||||
|
if not environment.REFLEX_BACKEND_ONLY.get():
|
||||||
|
node_bin_path = str(path_ops.get_node_bin_path())
|
||||||
|
if not node_bin_path and not prerequisites.CURRENTLY_INSTALLING_NODE:
|
||||||
|
console.warn(
|
||||||
|
"The path to the Node binary could not be found. Please ensure that Node is properly "
|
||||||
|
"installed and added to your system's PATH environment variable or try running "
|
||||||
|
"`reflex init` again."
|
||||||
|
)
|
||||||
|
path_env = os.pathsep.join([node_bin_path, path_env])
|
||||||
|
|
||||||
env: dict[str, str] = {
|
env: dict[str, str] = {
|
||||||
**os.environ,
|
**os.environ,
|
||||||
"PATH": os.pathsep.join(
|
"PATH": path_env,
|
||||||
[node_bin_path if node_bin_path else "", os.environ["PATH"]]
|
|
||||||
), # type: ignore
|
|
||||||
**kwargs.pop("env", {}),
|
**kwargs.pop("env", {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"env": env,
|
"env": env,
|
||||||
"stderr": None if show_logs else subprocess.STDOUT,
|
"stderr": None if show_logs else subprocess.STDOUT,
|
||||||
|
@ -561,7 +561,7 @@ class Var(Generic[VAR_TYPE]):
|
|||||||
if _var_is_local is not None:
|
if _var_is_local is not None:
|
||||||
console.deprecate(
|
console.deprecate(
|
||||||
feature_name="_var_is_local",
|
feature_name="_var_is_local",
|
||||||
reason="The _var_is_local argument is not supported for Var."
|
reason="The _var_is_local argument is not supported for Var. "
|
||||||
"If you want to create a Var from a raw Javascript expression, use the constructor directly",
|
"If you want to create a Var from a raw Javascript expression, use the constructor directly",
|
||||||
deprecation_version="0.6.0",
|
deprecation_version="0.6.0",
|
||||||
removal_version="0.7.0",
|
removal_version="0.7.0",
|
||||||
@ -569,7 +569,7 @@ class Var(Generic[VAR_TYPE]):
|
|||||||
if _var_is_string is not None:
|
if _var_is_string is not None:
|
||||||
console.deprecate(
|
console.deprecate(
|
||||||
feature_name="_var_is_string",
|
feature_name="_var_is_string",
|
||||||
reason="The _var_is_string argument is not supported for Var."
|
reason="The _var_is_string argument is not supported for Var. "
|
||||||
"If you want to create a Var from a raw Javascript expression, use the constructor directly",
|
"If you want to create a Var from a raw Javascript expression, use the constructor directly",
|
||||||
deprecation_version="0.6.0",
|
deprecation_version="0.6.0",
|
||||||
removal_version="0.7.0",
|
removal_version="0.7.0",
|
||||||
@ -1838,7 +1838,7 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|||||||
self,
|
self,
|
||||||
fget: Callable[[BASE_STATE], RETURN_TYPE],
|
fget: Callable[[BASE_STATE], RETURN_TYPE],
|
||||||
initial_value: RETURN_TYPE | types.Unset = types.Unset(),
|
initial_value: RETURN_TYPE | types.Unset = types.Unset(),
|
||||||
cache: bool = False,
|
cache: bool = True,
|
||||||
deps: Optional[List[Union[str, Var]]] = None,
|
deps: Optional[List[Union[str, Var]]] = None,
|
||||||
auto_deps: bool = True,
|
auto_deps: bool = True,
|
||||||
interval: Optional[Union[int, datetime.timedelta]] = None,
|
interval: Optional[Union[int, datetime.timedelta]] = None,
|
||||||
@ -2253,7 +2253,7 @@ if TYPE_CHECKING:
|
|||||||
def computed_var(
|
def computed_var(
|
||||||
fget: None = None,
|
fget: None = None,
|
||||||
initial_value: Any | types.Unset = types.Unset(),
|
initial_value: Any | types.Unset = types.Unset(),
|
||||||
cache: bool = False,
|
cache: bool = True,
|
||||||
deps: Optional[List[Union[str, Var]]] = None,
|
deps: Optional[List[Union[str, Var]]] = None,
|
||||||
auto_deps: bool = True,
|
auto_deps: bool = True,
|
||||||
interval: Optional[Union[datetime.timedelta, int]] = None,
|
interval: Optional[Union[datetime.timedelta, int]] = None,
|
||||||
@ -2266,7 +2266,7 @@ def computed_var(
|
|||||||
def computed_var(
|
def computed_var(
|
||||||
fget: Callable[[BASE_STATE], RETURN_TYPE],
|
fget: Callable[[BASE_STATE], RETURN_TYPE],
|
||||||
initial_value: RETURN_TYPE | types.Unset = types.Unset(),
|
initial_value: RETURN_TYPE | types.Unset = types.Unset(),
|
||||||
cache: bool = False,
|
cache: bool = True,
|
||||||
deps: Optional[List[Union[str, Var]]] = None,
|
deps: Optional[List[Union[str, Var]]] = None,
|
||||||
auto_deps: bool = True,
|
auto_deps: bool = True,
|
||||||
interval: Optional[Union[datetime.timedelta, int]] = None,
|
interval: Optional[Union[datetime.timedelta, int]] = None,
|
||||||
@ -2278,7 +2278,7 @@ def computed_var(
|
|||||||
def computed_var(
|
def computed_var(
|
||||||
fget: Callable[[BASE_STATE], Any] | None = None,
|
fget: Callable[[BASE_STATE], Any] | None = None,
|
||||||
initial_value: Any | types.Unset = types.Unset(),
|
initial_value: Any | types.Unset = types.Unset(),
|
||||||
cache: Optional[bool] = None,
|
cache: bool = True,
|
||||||
deps: Optional[List[Union[str, Var]]] = None,
|
deps: Optional[List[Union[str, Var]]] = None,
|
||||||
auto_deps: bool = True,
|
auto_deps: bool = True,
|
||||||
interval: Optional[Union[datetime.timedelta, int]] = None,
|
interval: Optional[Union[datetime.timedelta, int]] = None,
|
||||||
@ -2304,15 +2304,6 @@ def computed_var(
|
|||||||
ValueError: If caching is disabled and an update interval is set.
|
ValueError: If caching is disabled and an update interval is set.
|
||||||
VarDependencyError: If user supplies dependencies without caching.
|
VarDependencyError: If user supplies dependencies without caching.
|
||||||
"""
|
"""
|
||||||
if cache is None:
|
|
||||||
cache = False
|
|
||||||
console.deprecate(
|
|
||||||
"Default non-cached rx.var",
|
|
||||||
"the default value will be `@rx.var(cache=True)` in a future release. "
|
|
||||||
"To retain uncached var, explicitly pass `@rx.var(cache=False)`",
|
|
||||||
deprecation_version="0.6.8",
|
|
||||||
removal_version="0.7.0",
|
|
||||||
)
|
|
||||||
if cache is False and interval is not None:
|
if cache is False and interval is not None:
|
||||||
raise ValueError("Cannot set update interval without caching.")
|
raise ValueError("Cannot set update interval without caching.")
|
||||||
|
|
||||||
|
@ -390,6 +390,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|||||||
Returns:
|
Returns:
|
||||||
The function var.
|
The function var.
|
||||||
"""
|
"""
|
||||||
|
return_expr = Var.create(return_expr)
|
||||||
return cls(
|
return cls(
|
||||||
_js_expr="",
|
_js_expr="",
|
||||||
_var_type=_var_type,
|
_var_type=_var_type,
|
||||||
@ -445,6 +446,7 @@ class ArgsFunctionOperationBuilder(CachedVarOperation, BuilderFunctionVar):
|
|||||||
Returns:
|
Returns:
|
||||||
The function var.
|
The function var.
|
||||||
"""
|
"""
|
||||||
|
return_expr = Var.create(return_expr)
|
||||||
return cls(
|
return cls(
|
||||||
_js_expr="",
|
_js_expr="",
|
||||||
_var_type=_var_type,
|
_var_type=_var_type,
|
||||||
|
@ -20,7 +20,6 @@ from typing import (
|
|||||||
from reflex.constants.base import Dirs
|
from reflex.constants.base import Dirs
|
||||||
from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError
|
from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError
|
||||||
from reflex.utils.imports import ImportDict, ImportVar
|
from reflex.utils.imports import ImportDict, ImportVar
|
||||||
from reflex.utils.types import is_optional
|
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
CustomVarOperationReturn,
|
CustomVarOperationReturn,
|
||||||
@ -431,7 +430,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(other, NUMBER_TYPES):
|
if not isinstance(other, NUMBER_TYPES):
|
||||||
raise_unsupported_operand_types("<", (type(self), type(other)))
|
raise_unsupported_operand_types("<", (type(self), type(other)))
|
||||||
return less_than_operation(self, +other)
|
return less_than_operation(+self, +other)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __le__(self, other: number_types) -> BooleanVar: ...
|
def __le__(self, other: number_types) -> BooleanVar: ...
|
||||||
@ -450,7 +449,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(other, NUMBER_TYPES):
|
if not isinstance(other, NUMBER_TYPES):
|
||||||
raise_unsupported_operand_types("<=", (type(self), type(other)))
|
raise_unsupported_operand_types("<=", (type(self), type(other)))
|
||||||
return less_than_or_equal_operation(self, +other)
|
return less_than_or_equal_operation(+self, +other)
|
||||||
|
|
||||||
def __eq__(self, other: Any):
|
def __eq__(self, other: Any):
|
||||||
"""Equal comparison.
|
"""Equal comparison.
|
||||||
@ -462,7 +461,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
|
|||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
if isinstance(other, NUMBER_TYPES):
|
if isinstance(other, NUMBER_TYPES):
|
||||||
return equal_operation(self, +other)
|
return equal_operation(+self, +other)
|
||||||
return equal_operation(self, other)
|
return equal_operation(self, other)
|
||||||
|
|
||||||
def __ne__(self, other: Any):
|
def __ne__(self, other: Any):
|
||||||
@ -475,7 +474,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
|
|||||||
The result of the comparison.
|
The result of the comparison.
|
||||||
"""
|
"""
|
||||||
if isinstance(other, NUMBER_TYPES):
|
if isinstance(other, NUMBER_TYPES):
|
||||||
return not_equal_operation(self, +other)
|
return not_equal_operation(+self, +other)
|
||||||
return not_equal_operation(self, other)
|
return not_equal_operation(self, other)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
@ -495,7 +494,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(other, NUMBER_TYPES):
|
if not isinstance(other, NUMBER_TYPES):
|
||||||
raise_unsupported_operand_types(">", (type(self), type(other)))
|
raise_unsupported_operand_types(">", (type(self), type(other)))
|
||||||
return greater_than_operation(self, +other)
|
return greater_than_operation(+self, +other)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def __ge__(self, other: number_types) -> BooleanVar: ...
|
def __ge__(self, other: number_types) -> BooleanVar: ...
|
||||||
@ -514,17 +513,7 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
|
|||||||
"""
|
"""
|
||||||
if not isinstance(other, NUMBER_TYPES):
|
if not isinstance(other, NUMBER_TYPES):
|
||||||
raise_unsupported_operand_types(">=", (type(self), type(other)))
|
raise_unsupported_operand_types(">=", (type(self), type(other)))
|
||||||
return greater_than_or_equal_operation(self, +other)
|
return greater_than_or_equal_operation(+self, +other)
|
||||||
|
|
||||||
def bool(self):
|
|
||||||
"""Boolean conversion.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The boolean value of the number.
|
|
||||||
"""
|
|
||||||
if is_optional(self._var_type):
|
|
||||||
return boolify((self != None) & (self != 0)) # noqa: E711
|
|
||||||
return self != 0
|
|
||||||
|
|
||||||
def _is_strict_float(self) -> bool:
|
def _is_strict_float(self) -> bool:
|
||||||
"""Check if the number is a float.
|
"""Check if the number is a float.
|
||||||
|
@ -22,22 +22,22 @@ def ComputedVars():
|
|||||||
count: int = 0
|
count: int = 0
|
||||||
|
|
||||||
# cached var with dep on count
|
# cached var with dep on count
|
||||||
@rx.var(cache=True, interval=15)
|
@rx.var(interval=15)
|
||||||
def count1(self) -> int:
|
def count1(self) -> int:
|
||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
# cached backend var with dep on count
|
# cached backend var with dep on count
|
||||||
@rx.var(cache=True, interval=15, backend=True)
|
@rx.var(interval=15, backend=True)
|
||||||
def count1_backend(self) -> int:
|
def count1_backend(self) -> int:
|
||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
# same as above but implicit backend with `_` prefix
|
# same as above but implicit backend with `_` prefix
|
||||||
@rx.var(cache=True, interval=15)
|
@rx.var(interval=15)
|
||||||
def _count1_backend(self) -> int:
|
def _count1_backend(self) -> int:
|
||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
# explicit disabled auto_deps
|
# explicit disabled auto_deps
|
||||||
@rx.var(interval=15, cache=True, auto_deps=False)
|
@rx.var(interval=15, auto_deps=False)
|
||||||
def count3(self) -> int:
|
def count3(self) -> int:
|
||||||
# this will not add deps, because auto_deps is False
|
# this will not add deps, because auto_deps is False
|
||||||
print(self.count1)
|
print(self.count1)
|
||||||
@ -45,19 +45,27 @@ def ComputedVars():
|
|||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
# explicit dependency on count var
|
# explicit dependency on count var
|
||||||
@rx.var(cache=True, deps=["count"], auto_deps=False)
|
@rx.var(deps=["count"], auto_deps=False)
|
||||||
def depends_on_count(self) -> int:
|
def depends_on_count(self) -> int:
|
||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
# explicit dependency on count1 var
|
# explicit dependency on count1 var
|
||||||
@rx.var(cache=True, deps=[count1], auto_deps=False)
|
@rx.var(deps=[count1], auto_deps=False)
|
||||||
def depends_on_count1(self) -> int:
|
def depends_on_count1(self) -> int:
|
||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
@rx.var(deps=[count3], auto_deps=False, cache=True)
|
@rx.var(
|
||||||
|
deps=[count3],
|
||||||
|
auto_deps=False,
|
||||||
|
)
|
||||||
def depends_on_count3(self) -> int:
|
def depends_on_count3(self) -> int:
|
||||||
return self.count
|
return self.count
|
||||||
|
|
||||||
|
# special floats should be properly decoded on the frontend
|
||||||
|
@rx.var(cache=True, initial_value=[])
|
||||||
|
def special_floats(self) -> list[float]:
|
||||||
|
return [42.9, float("nan"), float("inf"), float("-inf")]
|
||||||
|
|
||||||
@rx.event
|
@rx.event
|
||||||
def increment(self):
|
def increment(self):
|
||||||
self.count += 1
|
self.count += 1
|
||||||
@ -103,6 +111,11 @@ def ComputedVars():
|
|||||||
State.depends_on_count3,
|
State.depends_on_count3,
|
||||||
id="depends_on_count3",
|
id="depends_on_count3",
|
||||||
),
|
),
|
||||||
|
rx.text("special_floats:"),
|
||||||
|
rx.text(
|
||||||
|
State.special_floats.join(", "),
|
||||||
|
id="special_floats",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -224,6 +237,10 @@ async def test_computed_vars(
|
|||||||
assert depends_on_count3
|
assert depends_on_count3
|
||||||
assert depends_on_count3.text == "0"
|
assert depends_on_count3.text == "0"
|
||||||
|
|
||||||
|
special_floats = driver.find_element(By.ID, "special_floats")
|
||||||
|
assert special_floats
|
||||||
|
assert special_floats.text == "42.9, NaN, Infinity, -Infinity"
|
||||||
|
|
||||||
increment = driver.find_element(By.ID, "increment")
|
increment = driver.find_element(By.ID, "increment")
|
||||||
assert increment.is_enabled()
|
assert increment.is_enabled()
|
||||||
|
|
||||||
|
@ -74,16 +74,16 @@ def DynamicRoute():
|
|||||||
class ArgState(rx.State):
|
class ArgState(rx.State):
|
||||||
"""The app state."""
|
"""The app state."""
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def arg(self) -> int:
|
def arg(self) -> int:
|
||||||
return int(self.arg_str or 0)
|
return int(self.arg_str or 0)
|
||||||
|
|
||||||
class ArgSubState(ArgState):
|
class ArgSubState(ArgState):
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def cached_arg(self) -> int:
|
def cached_arg(self) -> int:
|
||||||
return self.arg
|
return self.arg
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def cached_arg_str(self) -> str:
|
def cached_arg_str(self) -> str:
|
||||||
return self.arg_str
|
return self.arg_str
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ def LifespanApp():
|
|||||||
print("Lifespan global started.")
|
print("Lifespan global started.")
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
lifespan_task_global += inc # pyright: ignore[reportUnboundVariable]
|
lifespan_task_global += inc # pyright: ignore[reportUnboundVariable, reportPossiblyUnboundVariable]
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
except asyncio.CancelledError as ce:
|
except asyncio.CancelledError as ce:
|
||||||
print(f"Lifespan global cancelled: {ce}.")
|
print(f"Lifespan global cancelled: {ce}.")
|
||||||
@ -45,11 +45,11 @@ def LifespanApp():
|
|||||||
class LifespanState(rx.State):
|
class LifespanState(rx.State):
|
||||||
interval: int = 100
|
interval: int = 100
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def task_global(self) -> int:
|
def task_global(self) -> int:
|
||||||
return lifespan_task_global
|
return lifespan_task_global
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def context_global(self) -> int:
|
def context_global(self) -> int:
|
||||||
return lifespan_context_global
|
return lifespan_context_global
|
||||||
|
|
||||||
|
@ -22,31 +22,31 @@ def MediaApp():
|
|||||||
img.format = format # type: ignore
|
img.format = format # type: ignore
|
||||||
return img
|
return img
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def img_default(self) -> Image.Image:
|
def img_default(self) -> Image.Image:
|
||||||
return self._blue()
|
return self._blue()
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def img_bmp(self) -> Image.Image:
|
def img_bmp(self) -> Image.Image:
|
||||||
return self._blue(format="BMP")
|
return self._blue(format="BMP")
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def img_jpg(self) -> Image.Image:
|
def img_jpg(self) -> Image.Image:
|
||||||
return self._blue(format="JPEG")
|
return self._blue(format="JPEG")
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def img_png(self) -> Image.Image:
|
def img_png(self) -> Image.Image:
|
||||||
return self._blue(format="PNG")
|
return self._blue(format="PNG")
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def img_gif(self) -> Image.Image:
|
def img_gif(self) -> Image.Image:
|
||||||
return self._blue(format="GIF")
|
return self._blue(format="GIF")
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def img_webp(self) -> Image.Image:
|
def img_webp(self) -> Image.Image:
|
||||||
return self._blue(format="WEBP")
|
return self._blue(format="WEBP")
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def img_from_url(self) -> Image.Image:
|
def img_from_url(self) -> Image.Image:
|
||||||
img_url = "https://picsum.photos/id/1/200/300"
|
img_url = "https://picsum.photos/id/1/200/300"
|
||||||
img_resp = httpx.get(img_url, follow_redirects=True)
|
img_resp = httpx.get(img_url, follow_redirects=True)
|
||||||
|
@ -908,7 +908,7 @@ class DynamicState(BaseState):
|
|||||||
"""Increment the counter var."""
|
"""Increment the counter var."""
|
||||||
self.counter = self.counter + 1
|
self.counter = self.counter + 1
|
||||||
|
|
||||||
@computed_var(cache=True)
|
@computed_var
|
||||||
def comp_dynamic(self) -> str:
|
def comp_dynamic(self) -> str:
|
||||||
"""A computed var that depends on the dynamic var.
|
"""A computed var that depends on the dynamic var.
|
||||||
|
|
||||||
@ -1549,11 +1549,11 @@ def test_app_with_valid_var_dependencies(compilable_app: tuple[App, Path]):
|
|||||||
base: int = 0
|
base: int = 0
|
||||||
_backend: int = 0
|
_backend: int = 0
|
||||||
|
|
||||||
@computed_var(cache=True)
|
@computed_var()
|
||||||
def foo(self) -> str:
|
def foo(self) -> str:
|
||||||
return "foo"
|
return "foo"
|
||||||
|
|
||||||
@computed_var(deps=["_backend", "base", foo], cache=True)
|
@computed_var(deps=["_backend", "base", foo])
|
||||||
def bar(self) -> str:
|
def bar(self) -> str:
|
||||||
return "bar"
|
return "bar"
|
||||||
|
|
||||||
@ -1565,7 +1565,7 @@ def test_app_with_invalid_var_dependencies(compilable_app: tuple[App, Path]):
|
|||||||
app, _ = compilable_app
|
app, _ = compilable_app
|
||||||
|
|
||||||
class InvalidDepState(BaseState):
|
class InvalidDepState(BaseState):
|
||||||
@computed_var(deps=["foolksjdf"], cache=True)
|
@computed_var(deps=["foolksjdf"])
|
||||||
def bar(self) -> str:
|
def bar(self) -> str:
|
||||||
return "bar"
|
return "bar"
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ class GrandchildState(ChildState):
|
|||||||
class GrandchildState2(ChildState2):
|
class GrandchildState2(ChildState2):
|
||||||
"""A grandchild state fixture."""
|
"""A grandchild state fixture."""
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def cached(self) -> str:
|
def cached(self) -> str:
|
||||||
"""A cached var.
|
"""A cached var.
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ class GrandchildState2(ChildState2):
|
|||||||
class GrandchildState3(ChildState3):
|
class GrandchildState3(ChildState3):
|
||||||
"""A great grandchild state fixture."""
|
"""A great grandchild state fixture."""
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def computed(self) -> str:
|
def computed(self) -> str:
|
||||||
"""A computed var.
|
"""A computed var.
|
||||||
|
|
||||||
@ -796,7 +796,7 @@ async def test_process_event_simple(test_state):
|
|||||||
|
|
||||||
# The delta should contain the changes, including computed vars.
|
# The delta should contain the changes, including computed vars.
|
||||||
assert update.delta == {
|
assert update.delta == {
|
||||||
TestState.get_full_name(): {"num1": 69, "sum": 72.14, "upper": ""},
|
TestState.get_full_name(): {"num1": 69, "sum": 72.14},
|
||||||
GrandchildState3.get_full_name(): {"computed": ""},
|
GrandchildState3.get_full_name(): {"computed": ""},
|
||||||
}
|
}
|
||||||
assert update.events == []
|
assert update.events == []
|
||||||
@ -823,7 +823,7 @@ async def test_process_event_substate(test_state, child_state, grandchild_state)
|
|||||||
assert child_state.value == "HI"
|
assert child_state.value == "HI"
|
||||||
assert child_state.count == 24
|
assert child_state.count == 24
|
||||||
assert update.delta == {
|
assert update.delta == {
|
||||||
TestState.get_full_name(): {"sum": 3.14, "upper": ""},
|
# TestState.get_full_name(): {"sum": 3.14, "upper": ""},
|
||||||
ChildState.get_full_name(): {"value": "HI", "count": 24},
|
ChildState.get_full_name(): {"value": "HI", "count": 24},
|
||||||
GrandchildState3.get_full_name(): {"computed": ""},
|
GrandchildState3.get_full_name(): {"computed": ""},
|
||||||
}
|
}
|
||||||
@ -839,7 +839,7 @@ async def test_process_event_substate(test_state, child_state, grandchild_state)
|
|||||||
update = await test_state._process(event).__anext__()
|
update = await test_state._process(event).__anext__()
|
||||||
assert grandchild_state.value2 == "new"
|
assert grandchild_state.value2 == "new"
|
||||||
assert update.delta == {
|
assert update.delta == {
|
||||||
TestState.get_full_name(): {"sum": 3.14, "upper": ""},
|
# TestState.get_full_name(): {"sum": 3.14, "upper": ""},
|
||||||
GrandchildState.get_full_name(): {"value2": "new"},
|
GrandchildState.get_full_name(): {"value2": "new"},
|
||||||
GrandchildState3.get_full_name(): {"computed": ""},
|
GrandchildState3.get_full_name(): {"computed": ""},
|
||||||
}
|
}
|
||||||
@ -989,7 +989,7 @@ class InterdependentState(BaseState):
|
|||||||
v1: int = 0
|
v1: int = 0
|
||||||
_v2: int = 1
|
_v2: int = 1
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def v1x2(self) -> int:
|
def v1x2(self) -> int:
|
||||||
"""Depends on var v1.
|
"""Depends on var v1.
|
||||||
|
|
||||||
@ -998,7 +998,7 @@ class InterdependentState(BaseState):
|
|||||||
"""
|
"""
|
||||||
return self.v1 * 2
|
return self.v1 * 2
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def v2x2(self) -> int:
|
def v2x2(self) -> int:
|
||||||
"""Depends on backend var _v2.
|
"""Depends on backend var _v2.
|
||||||
|
|
||||||
@ -1007,7 +1007,7 @@ class InterdependentState(BaseState):
|
|||||||
"""
|
"""
|
||||||
return self._v2 * 2
|
return self._v2 * 2
|
||||||
|
|
||||||
@rx.var(cache=True, backend=True)
|
@rx.var(backend=True)
|
||||||
def v2x2_backend(self) -> int:
|
def v2x2_backend(self) -> int:
|
||||||
"""Depends on backend var _v2.
|
"""Depends on backend var _v2.
|
||||||
|
|
||||||
@ -1016,7 +1016,7 @@ class InterdependentState(BaseState):
|
|||||||
"""
|
"""
|
||||||
return self._v2 * 2
|
return self._v2 * 2
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def v1x2x2(self) -> int:
|
def v1x2x2(self) -> int:
|
||||||
"""Depends on ComputedVar v1x2.
|
"""Depends on ComputedVar v1x2.
|
||||||
|
|
||||||
@ -1025,7 +1025,7 @@ class InterdependentState(BaseState):
|
|||||||
"""
|
"""
|
||||||
return self.v1x2 * 2 # type: ignore
|
return self.v1x2 * 2 # type: ignore
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def _v3(self) -> int:
|
def _v3(self) -> int:
|
||||||
"""Depends on backend var _v2.
|
"""Depends on backend var _v2.
|
||||||
|
|
||||||
@ -1034,7 +1034,7 @@ class InterdependentState(BaseState):
|
|||||||
"""
|
"""
|
||||||
return self._v2
|
return self._v2
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def v3x2(self) -> int:
|
def v3x2(self) -> int:
|
||||||
"""Depends on ComputedVar _v3.
|
"""Depends on ComputedVar _v3.
|
||||||
|
|
||||||
@ -1239,7 +1239,7 @@ def test_computed_var_cached():
|
|||||||
class ComputedState(BaseState):
|
class ComputedState(BaseState):
|
||||||
v: int = 0
|
v: int = 0
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_v(self) -> int:
|
def comp_v(self) -> int:
|
||||||
nonlocal comp_v_calls
|
nonlocal comp_v_calls
|
||||||
comp_v_calls += 1
|
comp_v_calls += 1
|
||||||
@ -1264,15 +1264,15 @@ def test_computed_var_cached_depends_on_non_cached():
|
|||||||
class ComputedState(BaseState):
|
class ComputedState(BaseState):
|
||||||
v: int = 0
|
v: int = 0
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def no_cache_v(self) -> int:
|
def no_cache_v(self) -> int:
|
||||||
return self.v
|
return self.v
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def dep_v(self) -> int:
|
def dep_v(self) -> int:
|
||||||
return self.no_cache_v # type: ignore
|
return self.no_cache_v # type: ignore
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_v(self) -> int:
|
def comp_v(self) -> int:
|
||||||
return self.v
|
return self.v
|
||||||
|
|
||||||
@ -1304,14 +1304,14 @@ def test_computed_var_depends_on_parent_non_cached():
|
|||||||
counter = 0
|
counter = 0
|
||||||
|
|
||||||
class ParentState(BaseState):
|
class ParentState(BaseState):
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def no_cache_v(self) -> int:
|
def no_cache_v(self) -> int:
|
||||||
nonlocal counter
|
nonlocal counter
|
||||||
counter += 1
|
counter += 1
|
||||||
return counter
|
return counter
|
||||||
|
|
||||||
class ChildState(ParentState):
|
class ChildState(ParentState):
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def dep_v(self) -> int:
|
def dep_v(self) -> int:
|
||||||
return self.no_cache_v # type: ignore
|
return self.no_cache_v # type: ignore
|
||||||
|
|
||||||
@ -1357,7 +1357,7 @@ def test_cached_var_depends_on_event_handler(use_partial: bool):
|
|||||||
def handler(self):
|
def handler(self):
|
||||||
self.x = self.x + 1
|
self.x = self.x + 1
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def cached_x_side_effect(self) -> int:
|
def cached_x_side_effect(self) -> int:
|
||||||
self.handler()
|
self.handler()
|
||||||
nonlocal counter
|
nonlocal counter
|
||||||
@ -1393,7 +1393,7 @@ def test_computed_var_dependencies():
|
|||||||
def testprop(self) -> int:
|
def testprop(self) -> int:
|
||||||
return self.v
|
return self.v
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_v(self) -> int:
|
def comp_v(self) -> int:
|
||||||
"""Direct access.
|
"""Direct access.
|
||||||
|
|
||||||
@ -1402,7 +1402,7 @@ def test_computed_var_dependencies():
|
|||||||
"""
|
"""
|
||||||
return self.v
|
return self.v
|
||||||
|
|
||||||
@rx.var(cache=True, backend=True)
|
@rx.var(backend=True)
|
||||||
def comp_v_backend(self) -> int:
|
def comp_v_backend(self) -> int:
|
||||||
"""Direct access backend var.
|
"""Direct access backend var.
|
||||||
|
|
||||||
@ -1411,7 +1411,7 @@ def test_computed_var_dependencies():
|
|||||||
"""
|
"""
|
||||||
return self.v
|
return self.v
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_v_via_property(self) -> int:
|
def comp_v_via_property(self) -> int:
|
||||||
"""Access v via property.
|
"""Access v via property.
|
||||||
|
|
||||||
@ -1420,7 +1420,7 @@ def test_computed_var_dependencies():
|
|||||||
"""
|
"""
|
||||||
return self.testprop
|
return self.testprop
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_w(self):
|
def comp_w(self):
|
||||||
"""Nested lambda.
|
"""Nested lambda.
|
||||||
|
|
||||||
@ -1429,7 +1429,7 @@ def test_computed_var_dependencies():
|
|||||||
"""
|
"""
|
||||||
return lambda: self.w
|
return lambda: self.w
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_x(self):
|
def comp_x(self):
|
||||||
"""Nested function.
|
"""Nested function.
|
||||||
|
|
||||||
@ -1442,7 +1442,7 @@ def test_computed_var_dependencies():
|
|||||||
|
|
||||||
return _
|
return _
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_y(self) -> List[int]:
|
def comp_y(self) -> List[int]:
|
||||||
"""Comprehension iterating over attribute.
|
"""Comprehension iterating over attribute.
|
||||||
|
|
||||||
@ -1451,7 +1451,7 @@ def test_computed_var_dependencies():
|
|||||||
"""
|
"""
|
||||||
return [round(y) for y in self.y]
|
return [round(y) for y in self.y]
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def comp_z(self) -> List[bool]:
|
def comp_z(self) -> List[bool]:
|
||||||
"""Comprehension accesses attribute.
|
"""Comprehension accesses attribute.
|
||||||
|
|
||||||
@ -2027,10 +2027,6 @@ async def test_state_proxy(grandchild_state: GrandchildState, mock_app: rx.App):
|
|||||||
assert mcall.args[0] == str(SocketEvent.EVENT)
|
assert mcall.args[0] == str(SocketEvent.EVENT)
|
||||||
assert mcall.args[1] == StateUpdate(
|
assert mcall.args[1] == StateUpdate(
|
||||||
delta={
|
delta={
|
||||||
parent_state.get_full_name(): {
|
|
||||||
"upper": "",
|
|
||||||
"sum": 3.14,
|
|
||||||
},
|
|
||||||
grandchild_state.get_full_name(): {
|
grandchild_state.get_full_name(): {
|
||||||
"value2": "42",
|
"value2": "42",
|
||||||
},
|
},
|
||||||
@ -2053,7 +2049,7 @@ class BackgroundTaskState(BaseState):
|
|||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.router_data = {"simulate": "hydrate"}
|
self.router_data = {"simulate": "hydrate"}
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def computed_order(self) -> List[str]:
|
def computed_order(self) -> List[str]:
|
||||||
"""Get the order as a computed var.
|
"""Get the order as a computed var.
|
||||||
|
|
||||||
@ -3040,10 +3036,6 @@ async def test_get_state(mock_app: rx.App, token: str):
|
|||||||
grandchild_state.value2 = "set_value"
|
grandchild_state.value2 = "set_value"
|
||||||
|
|
||||||
assert test_state.get_delta() == {
|
assert test_state.get_delta() == {
|
||||||
TestState.get_full_name(): {
|
|
||||||
"sum": 3.14,
|
|
||||||
"upper": "",
|
|
||||||
},
|
|
||||||
GrandchildState.get_full_name(): {
|
GrandchildState.get_full_name(): {
|
||||||
"value2": "set_value",
|
"value2": "set_value",
|
||||||
},
|
},
|
||||||
@ -3081,10 +3073,6 @@ async def test_get_state(mock_app: rx.App, token: str):
|
|||||||
child_state2.value = "set_c2_value"
|
child_state2.value = "set_c2_value"
|
||||||
|
|
||||||
assert new_test_state.get_delta() == {
|
assert new_test_state.get_delta() == {
|
||||||
TestState.get_full_name(): {
|
|
||||||
"sum": 3.14,
|
|
||||||
"upper": "",
|
|
||||||
},
|
|
||||||
ChildState2.get_full_name(): {
|
ChildState2.get_full_name(): {
|
||||||
"value": "set_c2_value",
|
"value": "set_c2_value",
|
||||||
},
|
},
|
||||||
@ -3139,7 +3127,7 @@ async def test_get_state_from_sibling_not_cached(mock_app: rx.App, token: str):
|
|||||||
|
|
||||||
child3_var: int = 0
|
child3_var: int = 0
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def v(self):
|
def v(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -3210,8 +3198,8 @@ def test_potentially_dirty_substates():
|
|||||||
def bar(self) -> str:
|
def bar(self) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
assert RxState._potentially_dirty_substates() == {State}
|
assert RxState._potentially_dirty_substates() == set()
|
||||||
assert State._potentially_dirty_substates() == {C1}
|
assert State._potentially_dirty_substates() == set()
|
||||||
assert C1._potentially_dirty_substates() == set()
|
assert C1._potentially_dirty_substates() == set()
|
||||||
|
|
||||||
|
|
||||||
@ -3226,7 +3214,7 @@ def test_router_var_dep() -> None:
|
|||||||
class RouterVarDepState(RouterVarParentState):
|
class RouterVarDepState(RouterVarParentState):
|
||||||
"""A state with a router var dependency."""
|
"""A state with a router var dependency."""
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def foo(self) -> str:
|
def foo(self) -> str:
|
||||||
return self.router.page.params.get("foo", "")
|
return self.router.page.params.get("foo", "")
|
||||||
|
|
||||||
@ -3421,7 +3409,7 @@ class MixinState(State, mixin=True):
|
|||||||
_backend: int = 0
|
_backend: int = 0
|
||||||
_backend_no_default: dict
|
_backend_no_default: dict
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def computed(self) -> str:
|
def computed(self) -> str:
|
||||||
"""A computed var on mixin state.
|
"""A computed var on mixin state.
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class SubA_A_A_A(SubA_A_A):
|
|||||||
class SubA_A_A_B(SubA_A_A):
|
class SubA_A_A_B(SubA_A_A):
|
||||||
"""SubA_A_A_B is a child of SubA_A_A."""
|
"""SubA_A_A_B is a child of SubA_A_A."""
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def sub_a_a_a_cached(self) -> int:
|
def sub_a_a_a_cached(self) -> int:
|
||||||
"""A cached var.
|
"""A cached var.
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ class TreeD(Root):
|
|||||||
|
|
||||||
d: int
|
d: int
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def d_var(self) -> int:
|
def d_var(self) -> int:
|
||||||
"""A computed var.
|
"""A computed var.
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ class SubE_A_A_A_A(SubE_A_A_A):
|
|||||||
|
|
||||||
sub_e_a_a_a_a: int
|
sub_e_a_a_a_a: int
|
||||||
|
|
||||||
@rx.var
|
@rx.var(cache=False)
|
||||||
def sub_e_a_a_a_a_var(self) -> int:
|
def sub_e_a_a_a_a_var(self) -> int:
|
||||||
"""A computed var.
|
"""A computed var.
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ class SubE_A_A_A_D(SubE_A_A_A):
|
|||||||
|
|
||||||
sub_e_a_a_a_d: int
|
sub_e_a_a_a_d: int
|
||||||
|
|
||||||
@rx.var(cache=True)
|
@rx.var
|
||||||
def sub_e_a_a_a_d_var(self) -> int:
|
def sub_e_a_a_a_d_var(self) -> int:
|
||||||
"""A computed var.
|
"""A computed var.
|
||||||
|
|
||||||
|
@ -1004,7 +1004,7 @@ def test_all_number_operations():
|
|||||||
|
|
||||||
assert (
|
assert (
|
||||||
str(even_more_complicated_number)
|
str(even_more_complicated_number)
|
||||||
== "!(((Math.abs(Math.floor(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2))) || (2 && Math.round(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2)))) !== 0))"
|
== "!(isTrue((Math.abs(Math.floor(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2))) || (2 && Math.round(((Math.floor(((-((-5.4 + 1)) * 2) / 3) / 2) % 3) ** 2))))))"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert str(LiteralNumberVar.create(5) > False) == "(5 > 0)"
|
assert str(LiteralNumberVar.create(5) > False) == "(5 > 0)"
|
||||||
@ -1814,10 +1814,7 @@ def cv_fget(state: BaseState) -> int:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_computed_var_deps(deps: List[Union[str, Var]], expected: Set[str]):
|
def test_computed_var_deps(deps: List[Union[str, Var]], expected: Set[str]):
|
||||||
@computed_var(
|
@computed_var(deps=deps)
|
||||||
deps=deps,
|
|
||||||
cache=True,
|
|
||||||
)
|
|
||||||
def test_var(state) -> int:
|
def test_var(state) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@ -1835,10 +1832,7 @@ def test_computed_var_deps(deps: List[Union[str, Var]], expected: Set[str]):
|
|||||||
def test_invalid_computed_var_deps(deps: List):
|
def test_invalid_computed_var_deps(deps: List):
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
|
|
||||||
@computed_var(
|
@computed_var(deps=deps)
|
||||||
deps=deps,
|
|
||||||
cache=True,
|
|
||||||
)
|
|
||||||
def test_var(state) -> int:
|
def test_var(state) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user