Compare commits
16 Commits
main
...
release/re
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9308caa215 | ||
![]() |
68de3f41c4 | ||
![]() |
addf633692 | ||
![]() |
004518dd51 | ||
![]() |
b112d35f62 | ||
![]() |
2aea1f29b6 | ||
![]() |
0457cbd747 | ||
![]() |
a6b2e640ac | ||
![]() |
542382c3e7 | ||
![]() |
20398c10f1 | ||
![]() |
f8881c391d | ||
![]() |
c460040040 | ||
![]() |
19bfdc4035 | ||
![]() |
f133bf53cc | ||
![]() |
11dcce3975 | ||
![]() |
3494a2d3f3 |
2
.github/workflows/check_node_latest.yml
vendored
2
.github/workflows/check_node_latest.yml
vendored
@ -14,7 +14,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check_latest_node:
|
check_latest_node:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.12']
|
python-version: ['3.12']
|
||||||
|
@ -24,7 +24,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
state_manager: ['redis', 'memory']
|
state_manager: ['redis', 'memory']
|
||||||
python-version: ['3.11.5', '3.12.0']
|
python-version: ['3.11.5', '3.12.0']
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
services:
|
services:
|
||||||
# Label used to access the service container
|
# Label used to access the service container
|
||||||
redis:
|
redis:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "reflex"
|
name = "reflex"
|
||||||
version = "0.6.3dev1"
|
version = "0.6.3.post1"
|
||||||
description = "Web apps in pure Python."
|
description = "Web apps in pure Python."
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
authors = [
|
authors = [
|
||||||
|
@ -31,7 +31,7 @@ class ErrorBoundary(Component):
|
|||||||
on_click: Optional[EventType[[]]] = None,
|
on_click: Optional[EventType[[]]] = None,
|
||||||
on_context_menu: Optional[EventType[[]]] = None,
|
on_context_menu: Optional[EventType[[]]] = None,
|
||||||
on_double_click: Optional[EventType[[]]] = None,
|
on_double_click: Optional[EventType[[]]] = None,
|
||||||
on_error: Optional[EventType[[]]] = None,
|
on_error: Optional[EventType] = None,
|
||||||
on_focus: Optional[EventType[[]]] = None,
|
on_focus: Optional[EventType[[]]] = None,
|
||||||
on_mount: Optional[EventType[[]]] = None,
|
on_mount: Optional[EventType[[]]] = None,
|
||||||
on_mouse_down: Optional[EventType[[]]] = None,
|
on_mouse_down: Optional[EventType[[]]] = None,
|
||||||
|
@ -45,6 +45,7 @@ from reflex.event import (
|
|||||||
EventVar,
|
EventVar,
|
||||||
call_event_fn,
|
call_event_fn,
|
||||||
call_event_handler,
|
call_event_handler,
|
||||||
|
empty_event,
|
||||||
get_handler_args,
|
get_handler_args,
|
||||||
)
|
)
|
||||||
from reflex.style import Style, format_as_emotion
|
from reflex.style import Style, format_as_emotion
|
||||||
@ -623,21 +624,21 @@ class Component(BaseComponent, ABC):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
default_triggers = {
|
default_triggers = {
|
||||||
EventTriggers.ON_FOCUS: lambda: [],
|
EventTriggers.ON_FOCUS: empty_event,
|
||||||
EventTriggers.ON_BLUR: lambda: [],
|
EventTriggers.ON_BLUR: empty_event,
|
||||||
EventTriggers.ON_CLICK: lambda: [],
|
EventTriggers.ON_CLICK: empty_event,
|
||||||
EventTriggers.ON_CONTEXT_MENU: lambda: [],
|
EventTriggers.ON_CONTEXT_MENU: empty_event,
|
||||||
EventTriggers.ON_DOUBLE_CLICK: lambda: [],
|
EventTriggers.ON_DOUBLE_CLICK: empty_event,
|
||||||
EventTriggers.ON_MOUSE_DOWN: lambda: [],
|
EventTriggers.ON_MOUSE_DOWN: empty_event,
|
||||||
EventTriggers.ON_MOUSE_ENTER: lambda: [],
|
EventTriggers.ON_MOUSE_ENTER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_LEAVE: lambda: [],
|
EventTriggers.ON_MOUSE_LEAVE: empty_event,
|
||||||
EventTriggers.ON_MOUSE_MOVE: lambda: [],
|
EventTriggers.ON_MOUSE_MOVE: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OUT: lambda: [],
|
EventTriggers.ON_MOUSE_OUT: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OVER: lambda: [],
|
EventTriggers.ON_MOUSE_OVER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_UP: lambda: [],
|
EventTriggers.ON_MOUSE_UP: empty_event,
|
||||||
EventTriggers.ON_SCROLL: lambda: [],
|
EventTriggers.ON_SCROLL: empty_event,
|
||||||
EventTriggers.ON_MOUNT: lambda: [],
|
EventTriggers.ON_MOUNT: empty_event,
|
||||||
EventTriggers.ON_UNMOUNT: lambda: [],
|
EventTriggers.ON_UNMOUNT: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Look for component specific triggers,
|
# Look for component specific triggers,
|
||||||
@ -648,7 +649,7 @@ class Component(BaseComponent, ABC):
|
|||||||
annotation = field.annotation
|
annotation = field.annotation
|
||||||
if (metadata := getattr(annotation, "__metadata__", None)) is not None:
|
if (metadata := getattr(annotation, "__metadata__", None)) is not None:
|
||||||
args_spec = metadata[0]
|
args_spec = metadata[0]
|
||||||
default_triggers[field.name] = args_spec or (lambda: [])
|
default_triggers[field.name] = args_spec or (empty_event) # type: ignore
|
||||||
return default_triggers
|
return default_triggers
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
@ -1705,7 +1706,7 @@ class CustomComponent(Component):
|
|||||||
value = self._create_event_chain(
|
value = self._create_event_chain(
|
||||||
value=value,
|
value=value,
|
||||||
args_spec=event_triggers_in_component_declaration.get(
|
args_spec=event_triggers_in_component_declaration.get(
|
||||||
key, lambda: []
|
key, empty_event
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
self.props[format.to_camel_case(key)] = value
|
self.props[format.to_camel_case(key)] = value
|
||||||
|
@ -139,20 +139,20 @@ class DataEditor(NoSSRComponent):
|
|||||||
on_cell_activated: Optional[EventType] = None,
|
on_cell_activated: Optional[EventType] = None,
|
||||||
on_cell_clicked: Optional[EventType] = None,
|
on_cell_clicked: Optional[EventType] = None,
|
||||||
on_cell_context_menu: Optional[EventType] = None,
|
on_cell_context_menu: Optional[EventType] = None,
|
||||||
on_cell_edited: Optional[EventType[[]]] = None,
|
on_cell_edited: Optional[EventType] = None,
|
||||||
on_click: Optional[EventType[[]]] = None,
|
on_click: Optional[EventType[[]]] = None,
|
||||||
on_column_resize: Optional[EventType[[]]] = None,
|
on_column_resize: Optional[EventType] = None,
|
||||||
on_context_menu: Optional[EventType[[]]] = None,
|
on_context_menu: Optional[EventType[[]]] = None,
|
||||||
on_delete: Optional[EventType[[]]] = None,
|
on_delete: Optional[EventType] = None,
|
||||||
on_double_click: Optional[EventType[[]]] = None,
|
on_double_click: Optional[EventType[[]]] = None,
|
||||||
on_finished_editing: Optional[EventType[[]]] = None,
|
on_finished_editing: Optional[EventType] = None,
|
||||||
on_focus: Optional[EventType[[]]] = None,
|
on_focus: Optional[EventType[[]]] = None,
|
||||||
on_group_header_clicked: Optional[EventType[[]]] = None,
|
on_group_header_clicked: Optional[EventType] = None,
|
||||||
on_group_header_context_menu: Optional[EventType[[]]] = None,
|
on_group_header_context_menu: Optional[EventType] = None,
|
||||||
on_group_header_renamed: Optional[EventType[[]]] = None,
|
on_group_header_renamed: Optional[EventType] = None,
|
||||||
on_header_clicked: Optional[EventType] = None,
|
on_header_clicked: Optional[EventType] = None,
|
||||||
on_header_context_menu: Optional[EventType] = None,
|
on_header_context_menu: Optional[EventType] = None,
|
||||||
on_header_menu_click: Optional[EventType[[]]] = None,
|
on_header_menu_click: Optional[EventType] = None,
|
||||||
on_item_hovered: Optional[EventType] = None,
|
on_item_hovered: Optional[EventType] = None,
|
||||||
on_mount: Optional[EventType[[]]] = None,
|
on_mount: Optional[EventType[[]]] = None,
|
||||||
on_mouse_down: Optional[EventType[[]]] = None,
|
on_mouse_down: Optional[EventType[[]]] = None,
|
||||||
|
@ -58,7 +58,7 @@ class Audio(ReactPlayer):
|
|||||||
on_play: Optional[EventType[[]]] = None,
|
on_play: Optional[EventType[[]]] = None,
|
||||||
on_playback_quality_change: Optional[EventType[[]]] = None,
|
on_playback_quality_change: Optional[EventType[[]]] = None,
|
||||||
on_playback_rate_change: Optional[EventType[[]]] = None,
|
on_playback_rate_change: Optional[EventType[[]]] = None,
|
||||||
on_progress: Optional[EventType[[]]] = None,
|
on_progress: Optional[EventType] = None,
|
||||||
on_ready: Optional[EventType[[]]] = None,
|
on_ready: Optional[EventType[[]]] = None,
|
||||||
on_scroll: Optional[EventType[[]]] = None,
|
on_scroll: Optional[EventType[[]]] = None,
|
||||||
on_seek: Optional[EventType] = None,
|
on_seek: Optional[EventType] = None,
|
||||||
|
@ -56,7 +56,7 @@ class ReactPlayer(NoSSRComponent):
|
|||||||
on_play: Optional[EventType[[]]] = None,
|
on_play: Optional[EventType[[]]] = None,
|
||||||
on_playback_quality_change: Optional[EventType[[]]] = None,
|
on_playback_quality_change: Optional[EventType[[]]] = None,
|
||||||
on_playback_rate_change: Optional[EventType[[]]] = None,
|
on_playback_rate_change: Optional[EventType[[]]] = None,
|
||||||
on_progress: Optional[EventType[[]]] = None,
|
on_progress: Optional[EventType] = None,
|
||||||
on_ready: Optional[EventType[[]]] = None,
|
on_ready: Optional[EventType[[]]] = None,
|
||||||
on_scroll: Optional[EventType[[]]] = None,
|
on_scroll: Optional[EventType[[]]] = None,
|
||||||
on_seek: Optional[EventType] = None,
|
on_seek: Optional[EventType] = None,
|
||||||
|
@ -58,7 +58,7 @@ class Video(ReactPlayer):
|
|||||||
on_play: Optional[EventType[[]]] = None,
|
on_play: Optional[EventType[[]]] = None,
|
||||||
on_playback_quality_change: Optional[EventType[[]]] = None,
|
on_playback_quality_change: Optional[EventType[[]]] = None,
|
||||||
on_playback_rate_change: Optional[EventType[[]]] = None,
|
on_playback_rate_change: Optional[EventType[[]]] = None,
|
||||||
on_progress: Optional[EventType[[]]] = None,
|
on_progress: Optional[EventType] = None,
|
||||||
on_ready: Optional[EventType[[]]] = None,
|
on_ready: Optional[EventType[[]]] = None,
|
||||||
on_scroll: Optional[EventType[[]]] = None,
|
on_scroll: Optional[EventType[[]]] = None,
|
||||||
on_seek: Optional[EventType] = None,
|
on_seek: Optional[EventType] = None,
|
||||||
|
@ -252,7 +252,7 @@ class Brush(Recharts):
|
|||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
A dict mapping the event trigger to the var that is passed to the handler.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
EventTriggers.ON_CHANGE: lambda: [],
|
EventTriggers.ON_CHANGE: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -293,10 +293,10 @@ class Cartesian(Recharts):
|
|||||||
name: Var[Union[str, int]]
|
name: Var[Union[str, int]]
|
||||||
|
|
||||||
# The customized event handler of animation start
|
# The customized event handler of animation start
|
||||||
on_animation_start: EventHandler[lambda: []]
|
on_animation_start: EventHandler[empty_event]
|
||||||
|
|
||||||
# The customized event handler of animation end
|
# The customized event handler of animation end
|
||||||
on_animation_end: EventHandler[lambda: []]
|
on_animation_end: EventHandler[empty_event]
|
||||||
|
|
||||||
# The customized event handler of click on the component in this group
|
# The customized event handler of click on the component in this group
|
||||||
on_click: EventHandler[empty_event]
|
on_click: EventHandler[empty_event]
|
||||||
|
@ -330,9 +330,9 @@ class RadarChart(ChartBase):
|
|||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
A dict mapping the event trigger to the var that is passed to the handler.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
EventTriggers.ON_CLICK: lambda: [],
|
EventTriggers.ON_CLICK: empty_event,
|
||||||
EventTriggers.ON_MOUSE_ENTER: lambda: [],
|
EventTriggers.ON_MOUSE_ENTER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_LEAVE: lambda: [],
|
EventTriggers.ON_MOUSE_LEAVE: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -419,14 +419,14 @@ class ScatterChart(ChartBase):
|
|||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
A dict mapping the event trigger to the var that is passed to the handler.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
EventTriggers.ON_CLICK: lambda: [],
|
EventTriggers.ON_CLICK: empty_event,
|
||||||
EventTriggers.ON_MOUSE_DOWN: lambda: [],
|
EventTriggers.ON_MOUSE_DOWN: empty_event,
|
||||||
EventTriggers.ON_MOUSE_UP: lambda: [],
|
EventTriggers.ON_MOUSE_UP: empty_event,
|
||||||
EventTriggers.ON_MOUSE_MOVE: lambda: [],
|
EventTriggers.ON_MOUSE_MOVE: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OVER: lambda: [],
|
EventTriggers.ON_MOUSE_OVER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OUT: lambda: [],
|
EventTriggers.ON_MOUSE_OUT: empty_event,
|
||||||
EventTriggers.ON_MOUSE_ENTER: lambda: [],
|
EventTriggers.ON_MOUSE_ENTER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_LEAVE: lambda: [],
|
EventTriggers.ON_MOUSE_LEAVE: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,14 +103,14 @@ class Pie(Recharts):
|
|||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
A dict mapping the event trigger to the var that is passed to the handler.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
EventTriggers.ON_ANIMATION_START: lambda: [],
|
EventTriggers.ON_ANIMATION_START: empty_event,
|
||||||
EventTriggers.ON_ANIMATION_END: lambda: [],
|
EventTriggers.ON_ANIMATION_END: empty_event,
|
||||||
EventTriggers.ON_CLICK: lambda: [],
|
EventTriggers.ON_CLICK: empty_event,
|
||||||
EventTriggers.ON_MOUSE_MOVE: lambda: [],
|
EventTriggers.ON_MOUSE_MOVE: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OVER: lambda: [],
|
EventTriggers.ON_MOUSE_OVER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OUT: lambda: [],
|
EventTriggers.ON_MOUSE_OUT: empty_event,
|
||||||
EventTriggers.ON_MOUSE_ENTER: lambda: [],
|
EventTriggers.ON_MOUSE_ENTER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_LEAVE: lambda: [],
|
EventTriggers.ON_MOUSE_LEAVE: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -167,8 +167,8 @@ class Radar(Recharts):
|
|||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
A dict mapping the event trigger to the var that is passed to the handler.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
EventTriggers.ON_ANIMATION_START: lambda: [],
|
EventTriggers.ON_ANIMATION_START: empty_event,
|
||||||
EventTriggers.ON_ANIMATION_END: lambda: [],
|
EventTriggers.ON_ANIMATION_END: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -219,14 +219,14 @@ class RadialBar(Recharts):
|
|||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
A dict mapping the event trigger to the var that is passed to the handler.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
EventTriggers.ON_CLICK: lambda: [],
|
EventTriggers.ON_CLICK: empty_event,
|
||||||
EventTriggers.ON_MOUSE_MOVE: lambda: [],
|
EventTriggers.ON_MOUSE_MOVE: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OVER: lambda: [],
|
EventTriggers.ON_MOUSE_OVER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OUT: lambda: [],
|
EventTriggers.ON_MOUSE_OUT: empty_event,
|
||||||
EventTriggers.ON_MOUSE_ENTER: lambda: [],
|
EventTriggers.ON_MOUSE_ENTER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_LEAVE: lambda: [],
|
EventTriggers.ON_MOUSE_LEAVE: empty_event,
|
||||||
EventTriggers.ON_ANIMATION_START: lambda: [],
|
EventTriggers.ON_ANIMATION_START: empty_event,
|
||||||
EventTriggers.ON_ANIMATION_END: lambda: [],
|
EventTriggers.ON_ANIMATION_END: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -392,12 +392,12 @@ class PolarRadiusAxis(Recharts):
|
|||||||
A dict mapping the event trigger to the var that is passed to the handler.
|
A dict mapping the event trigger to the var that is passed to the handler.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
EventTriggers.ON_CLICK: lambda: [],
|
EventTriggers.ON_CLICK: empty_event,
|
||||||
EventTriggers.ON_MOUSE_MOVE: lambda: [],
|
EventTriggers.ON_MOUSE_MOVE: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OVER: lambda: [],
|
EventTriggers.ON_MOUSE_OVER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_OUT: lambda: [],
|
EventTriggers.ON_MOUSE_OUT: empty_event,
|
||||||
EventTriggers.ON_MOUSE_ENTER: lambda: [],
|
EventTriggers.ON_MOUSE_ENTER: empty_event,
|
||||||
EventTriggers.ON_MOUSE_LEAVE: lambda: [],
|
EventTriggers.ON_MOUSE_LEAVE: empty_event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,16 +122,16 @@ class Editor(NoSSRComponent):
|
|||||||
class_name: Optional[Any] = None,
|
class_name: Optional[Any] = None,
|
||||||
autofocus: Optional[bool] = None,
|
autofocus: Optional[bool] = None,
|
||||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||||
on_blur: Optional[EventType[[]]] = None,
|
on_blur: Optional[EventType] = None,
|
||||||
on_change: Optional[EventType[[]]] = None,
|
on_change: Optional[EventType] = None,
|
||||||
on_click: Optional[EventType[[]]] = None,
|
on_click: Optional[EventType[[]]] = None,
|
||||||
on_context_menu: Optional[EventType[[]]] = None,
|
on_context_menu: Optional[EventType[[]]] = None,
|
||||||
on_copy: Optional[EventType[[]]] = None,
|
on_copy: Optional[EventType] = None,
|
||||||
on_cut: Optional[EventType[[]]] = None,
|
on_cut: Optional[EventType] = None,
|
||||||
on_double_click: Optional[EventType[[]]] = None,
|
on_double_click: Optional[EventType[[]]] = None,
|
||||||
on_focus: Optional[EventType[[]]] = None,
|
on_focus: Optional[EventType[[]]] = None,
|
||||||
on_input: Optional[EventType[[]]] = None,
|
on_input: Optional[EventType] = None,
|
||||||
on_load: Optional[EventType[[]]] = None,
|
on_load: Optional[EventType] = None,
|
||||||
on_mount: Optional[EventType[[]]] = None,
|
on_mount: Optional[EventType[[]]] = None,
|
||||||
on_mouse_down: Optional[EventType[[]]] = None,
|
on_mouse_down: Optional[EventType[[]]] = None,
|
||||||
on_mouse_enter: Optional[EventType[[]]] = None,
|
on_mouse_enter: Optional[EventType[[]]] = None,
|
||||||
@ -140,12 +140,12 @@ class Editor(NoSSRComponent):
|
|||||||
on_mouse_out: Optional[EventType[[]]] = None,
|
on_mouse_out: Optional[EventType[[]]] = None,
|
||||||
on_mouse_over: Optional[EventType[[]]] = None,
|
on_mouse_over: Optional[EventType[[]]] = None,
|
||||||
on_mouse_up: Optional[EventType[[]]] = None,
|
on_mouse_up: Optional[EventType[[]]] = None,
|
||||||
on_paste: Optional[EventType[[]]] = None,
|
on_paste: Optional[EventType] = None,
|
||||||
on_resize_editor: Optional[EventType[[]]] = None,
|
on_resize_editor: Optional[EventType] = None,
|
||||||
on_scroll: Optional[EventType[[]]] = None,
|
on_scroll: Optional[EventType[[]]] = None,
|
||||||
on_unmount: Optional[EventType[[]]] = None,
|
on_unmount: Optional[EventType[[]]] = None,
|
||||||
toggle_code_view: Optional[EventType[[]]] = None,
|
toggle_code_view: Optional[EventType] = None,
|
||||||
toggle_full_screen: Optional[EventType[[]]] = None,
|
toggle_full_screen: Optional[EventType] = None,
|
||||||
**props,
|
**props,
|
||||||
) -> "Editor":
|
) -> "Editor":
|
||||||
"""Create an instance of Editor. No children allowed.
|
"""Create an instance of Editor. No children allowed.
|
||||||
|
188
reflex/event.py
188
reflex/event.py
@ -22,6 +22,7 @@ from typing import (
|
|||||||
TypeVar,
|
TypeVar,
|
||||||
Union,
|
Union,
|
||||||
get_type_hints,
|
get_type_hints,
|
||||||
|
overload,
|
||||||
)
|
)
|
||||||
|
|
||||||
from typing_extensions import ParamSpec, get_args, get_origin
|
from typing_extensions import ParamSpec, get_args, get_origin
|
||||||
@ -32,14 +33,17 @@ from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
|
|||||||
from reflex.utils.types import ArgsSpec, GenericType
|
from reflex.utils.types import ArgsSpec, GenericType
|
||||||
from reflex.vars import VarData
|
from reflex.vars import VarData
|
||||||
from reflex.vars.base import (
|
from reflex.vars.base import (
|
||||||
CachedVarOperation,
|
|
||||||
LiteralNoneVar,
|
LiteralNoneVar,
|
||||||
LiteralVar,
|
LiteralVar,
|
||||||
ToOperation,
|
ToOperation,
|
||||||
Var,
|
Var,
|
||||||
cached_property_no_lock,
|
|
||||||
)
|
)
|
||||||
from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar, FunctionVar
|
from reflex.vars.function import (
|
||||||
|
ArgsFunctionOperation,
|
||||||
|
FunctionStringVar,
|
||||||
|
FunctionVar,
|
||||||
|
VarOperationCall,
|
||||||
|
)
|
||||||
from reflex.vars.object import ObjectVar
|
from reflex.vars.object import ObjectVar
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -395,11 +399,6 @@ class EventChain(EventActionsMixin):
|
|||||||
invocation: Optional[Var] = dataclasses.field(default=None)
|
invocation: Optional[Var] = dataclasses.field(default=None)
|
||||||
|
|
||||||
|
|
||||||
# These chains can be used for their side effects when no other events are desired.
|
|
||||||
stop_propagation = EventChain(events=[], args_spec=lambda: []).stop_propagation
|
|
||||||
prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default
|
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(
|
@dataclasses.dataclass(
|
||||||
init=True,
|
init=True,
|
||||||
frozen=True,
|
frozen=True,
|
||||||
@ -463,6 +462,11 @@ def empty_event() -> Tuple[()]:
|
|||||||
return tuple() # type: ignore
|
return tuple() # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
# These chains can be used for their side effects when no other events are desired.
|
||||||
|
stop_propagation = EventChain(events=[], args_spec=empty_event).stop_propagation
|
||||||
|
prevent_default = EventChain(events=[], args_spec=empty_event).prevent_default
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
@ -1041,7 +1045,8 @@ def resolve_annotation(annotations: dict[str, Any], arg_name: str):
|
|||||||
deprecation_version="0.6.3",
|
deprecation_version="0.6.3",
|
||||||
removal_version="0.7.0",
|
removal_version="0.7.0",
|
||||||
)
|
)
|
||||||
return JavascriptInputEvent
|
# Allow arbitrary attribute access two levels deep until removed.
|
||||||
|
return Dict[str, dict]
|
||||||
return annotation
|
return annotation
|
||||||
|
|
||||||
|
|
||||||
@ -1258,7 +1263,7 @@ class EventVar(ObjectVar):
|
|||||||
frozen=True,
|
frozen=True,
|
||||||
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
)
|
)
|
||||||
class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar):
|
class LiteralEventVar(VarOperationCall, LiteralVar, EventVar):
|
||||||
"""A literal event var."""
|
"""A literal event var."""
|
||||||
|
|
||||||
_var_value: EventSpec = dataclasses.field(default=None) # type: ignore
|
_var_value: EventSpec = dataclasses.field(default=None) # type: ignore
|
||||||
@ -1271,35 +1276,6 @@ class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar):
|
|||||||
"""
|
"""
|
||||||
return hash((self.__class__.__name__, self._js_expr))
|
return hash((self.__class__.__name__, self._js_expr))
|
||||||
|
|
||||||
@cached_property_no_lock
|
|
||||||
def _cached_var_name(self) -> str:
|
|
||||||
"""The name of the var.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The name of the var.
|
|
||||||
"""
|
|
||||||
return str(
|
|
||||||
FunctionStringVar("Event").call(
|
|
||||||
# event handler name
|
|
||||||
".".join(
|
|
||||||
filter(
|
|
||||||
None,
|
|
||||||
format.get_event_handler_parts(self._var_value.handler),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
# event handler args
|
|
||||||
{str(name): value for name, value in self._var_value.args},
|
|
||||||
# event actions
|
|
||||||
self._var_value.event_actions,
|
|
||||||
# client handler name
|
|
||||||
*(
|
|
||||||
[self._var_value.client_handler_name]
|
|
||||||
if self._var_value.client_handler_name
|
|
||||||
else []
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(
|
def create(
|
||||||
cls,
|
cls,
|
||||||
@ -1320,6 +1296,22 @@ class LiteralEventVar(CachedVarOperation, LiteralVar, EventVar):
|
|||||||
_var_type=EventSpec,
|
_var_type=EventSpec,
|
||||||
_var_data=_var_data,
|
_var_data=_var_data,
|
||||||
_var_value=value,
|
_var_value=value,
|
||||||
|
_func=FunctionStringVar("Event"),
|
||||||
|
_args=(
|
||||||
|
# event handler name
|
||||||
|
".".join(
|
||||||
|
filter(
|
||||||
|
None,
|
||||||
|
format.get_event_handler_parts(value.handler),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
# event handler args
|
||||||
|
{str(name): value for name, value in value.args},
|
||||||
|
# event actions
|
||||||
|
value.event_actions,
|
||||||
|
# client handler name
|
||||||
|
*([value.client_handler_name] if value.client_handler_name else []),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -1332,7 +1324,10 @@ class EventChainVar(FunctionVar):
|
|||||||
frozen=True,
|
frozen=True,
|
||||||
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
||||||
)
|
)
|
||||||
class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar):
|
# Note: LiteralVar is second in the inheritance list allowing it act like a
|
||||||
|
# CachedVarOperation (ArgsFunctionOperation) and get the _js_expr from the
|
||||||
|
# _cached_var_name property.
|
||||||
|
class LiteralEventChainVar(ArgsFunctionOperation, LiteralVar, EventChainVar):
|
||||||
"""A literal event chain var."""
|
"""A literal event chain var."""
|
||||||
|
|
||||||
_var_value: EventChain = dataclasses.field(default=None) # type: ignore
|
_var_value: EventChain = dataclasses.field(default=None) # type: ignore
|
||||||
@ -1345,41 +1340,6 @@ class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar):
|
|||||||
"""
|
"""
|
||||||
return hash((self.__class__.__name__, self._js_expr))
|
return hash((self.__class__.__name__, self._js_expr))
|
||||||
|
|
||||||
@cached_property_no_lock
|
|
||||||
def _cached_var_name(self) -> str:
|
|
||||||
"""The name of the var.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The name of the var.
|
|
||||||
"""
|
|
||||||
sig = inspect.signature(self._var_value.args_spec) # type: ignore
|
|
||||||
if sig.parameters:
|
|
||||||
arg_def = tuple((f"_{p}" for p in sig.parameters))
|
|
||||||
arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
|
|
||||||
else:
|
|
||||||
# add a default argument for addEvents if none were specified in value.args_spec
|
|
||||||
# used to trigger the preventDefault() on the event.
|
|
||||||
arg_def = ("...args",)
|
|
||||||
arg_def_expr = Var(_js_expr="args")
|
|
||||||
|
|
||||||
if self._var_value.invocation is None:
|
|
||||||
invocation = FunctionStringVar.create("addEvents")
|
|
||||||
else:
|
|
||||||
invocation = self._var_value.invocation
|
|
||||||
|
|
||||||
return str(
|
|
||||||
ArgsFunctionOperation.create(
|
|
||||||
arg_def,
|
|
||||||
invocation.call(
|
|
||||||
LiteralVar.create(
|
|
||||||
[LiteralVar.create(event) for event in self._var_value.events]
|
|
||||||
),
|
|
||||||
arg_def_expr,
|
|
||||||
self._var_value.event_actions,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(
|
def create(
|
||||||
cls,
|
cls,
|
||||||
@ -1395,10 +1355,31 @@ class LiteralEventChainVar(CachedVarOperation, LiteralVar, EventChainVar):
|
|||||||
Returns:
|
Returns:
|
||||||
The created LiteralEventChainVar instance.
|
The created LiteralEventChainVar instance.
|
||||||
"""
|
"""
|
||||||
|
sig = inspect.signature(value.args_spec) # type: ignore
|
||||||
|
if sig.parameters:
|
||||||
|
arg_def = tuple((f"_{p}" for p in sig.parameters))
|
||||||
|
arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
|
||||||
|
else:
|
||||||
|
# add a default argument for addEvents if none were specified in value.args_spec
|
||||||
|
# used to trigger the preventDefault() on the event.
|
||||||
|
arg_def = ("...args",)
|
||||||
|
arg_def_expr = Var(_js_expr="args")
|
||||||
|
|
||||||
|
if value.invocation is None:
|
||||||
|
invocation = FunctionStringVar.create("addEvents")
|
||||||
|
else:
|
||||||
|
invocation = value.invocation
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
_js_expr="",
|
_js_expr="",
|
||||||
_var_type=EventChain,
|
_var_type=EventChain,
|
||||||
_var_data=_var_data,
|
_var_data=_var_data,
|
||||||
|
_args_names=arg_def,
|
||||||
|
_return_expr=invocation.call(
|
||||||
|
LiteralVar.create([LiteralVar.create(event) for event in value.events]),
|
||||||
|
arg_def_expr,
|
||||||
|
value.event_actions,
|
||||||
|
),
|
||||||
_var_value=value,
|
_var_value=value,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1431,12 +1412,17 @@ class ToEventChainVarOperation(ToOperation, EventChainVar):
|
|||||||
|
|
||||||
G = ParamSpec("G")
|
G = ParamSpec("G")
|
||||||
|
|
||||||
IndividualEventType = Union[EventSpec, EventHandler, Callable[G, Any], Var]
|
IndividualEventType = Union[EventSpec, EventHandler, Callable[G, Any], Var[Any]]
|
||||||
|
|
||||||
EventType = Union[IndividualEventType[G], List[IndividualEventType[G]]]
|
EventType = Union[IndividualEventType[G], List[IndividualEventType[G]]]
|
||||||
|
|
||||||
P = ParamSpec("P")
|
P = ParamSpec("P")
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
V = TypeVar("V")
|
||||||
|
V2 = TypeVar("V2")
|
||||||
|
V3 = TypeVar("V3")
|
||||||
|
V4 = TypeVar("V4")
|
||||||
|
V5 = TypeVar("V5")
|
||||||
|
|
||||||
if sys.version_info >= (3, 10):
|
if sys.version_info >= (3, 10):
|
||||||
from typing import Concatenate
|
from typing import Concatenate
|
||||||
@ -1452,7 +1438,55 @@ if sys.version_info >= (3, 10):
|
|||||||
"""
|
"""
|
||||||
self.func = func
|
self.func = func
|
||||||
|
|
||||||
def __get__(self, instance, owner) -> Callable[P, T]:
|
@overload
|
||||||
|
def __get__(
|
||||||
|
self: EventCallback[[V], T], instance: None, owner
|
||||||
|
) -> Callable[[Union[Var[V], V]], EventSpec]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def __get__(
|
||||||
|
self: EventCallback[[V, V2], T], instance: None, owner
|
||||||
|
) -> Callable[[Union[Var[V], V], Union[Var[V2], V2]], EventSpec]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def __get__(
|
||||||
|
self: EventCallback[[V, V2, V3], T], instance: None, owner
|
||||||
|
) -> Callable[
|
||||||
|
[Union[Var[V], V], Union[Var[V2], V2], Union[Var[V3], V3]],
|
||||||
|
EventSpec,
|
||||||
|
]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def __get__(
|
||||||
|
self: EventCallback[[V, V2, V3, V4], T], instance: None, owner
|
||||||
|
) -> Callable[
|
||||||
|
[
|
||||||
|
Union[Var[V], V],
|
||||||
|
Union[Var[V2], V2],
|
||||||
|
Union[Var[V3], V3],
|
||||||
|
Union[Var[V4], V4],
|
||||||
|
],
|
||||||
|
EventSpec,
|
||||||
|
]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def __get__(
|
||||||
|
self: EventCallback[[V, V2, V3, V4, V5], T], instance: None, owner
|
||||||
|
) -> Callable[
|
||||||
|
[
|
||||||
|
Union[Var[V], V],
|
||||||
|
Union[Var[V2], V2],
|
||||||
|
Union[Var[V3], V3],
|
||||||
|
Union[Var[V4], V4],
|
||||||
|
Union[Var[V5], V5],
|
||||||
|
],
|
||||||
|
EventSpec,
|
||||||
|
]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def __get__(self, instance, owner) -> Callable[P, T]: ...
|
||||||
|
|
||||||
|
def __get__(self, instance, owner) -> Callable:
|
||||||
"""Get the function with the instance bound to it.
|
"""Get the function with the instance bound to it.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -2566,9 +2566,11 @@ class StateManager(Base, ABC):
|
|||||||
The state manager (either disk, memory or redis).
|
The state manager (either disk, memory or redis).
|
||||||
"""
|
"""
|
||||||
config = get_config()
|
config = get_config()
|
||||||
if config.state_manager_mode == constants.StateManagerMode.DISK:
|
if prerequisites.parse_redis_url() is not None:
|
||||||
return StateManagerMemory(state=state)
|
config.state_manager_mode = constants.StateManagerMode.REDIS
|
||||||
if config.state_manager_mode == constants.StateManagerMode.MEMORY:
|
if config.state_manager_mode == constants.StateManagerMode.MEMORY:
|
||||||
|
return StateManagerMemory(state=state)
|
||||||
|
if config.state_manager_mode == constants.StateManagerMode.DISK:
|
||||||
return StateManagerDisk(state=state)
|
return StateManagerDisk(state=state)
|
||||||
if config.state_manager_mode == constants.StateManagerMode.REDIS:
|
if config.state_manager_mode == constants.StateManagerMode.REDIS:
|
||||||
redis = prerequisites.get_redis()
|
redis = prerequisites.get_redis()
|
||||||
@ -2840,9 +2842,13 @@ class StateManagerDisk(StateManager):
|
|||||||
for substate in state.get_substates():
|
for substate in state.get_substates():
|
||||||
substate_token = _substate_key(client_token, substate)
|
substate_token = _substate_key(client_token, substate)
|
||||||
|
|
||||||
|
fresh_instance = await root_state.get_state(substate)
|
||||||
instance = await self.load_state(substate_token)
|
instance = await self.load_state(substate_token)
|
||||||
if instance is None:
|
if instance is not None:
|
||||||
instance = await root_state.get_state(substate)
|
# Ensure all substates exist, even if they weren't serialized previously.
|
||||||
|
instance.substates = fresh_instance.substates
|
||||||
|
else:
|
||||||
|
instance = fresh_instance
|
||||||
state.substates[substate.get_name()] = instance
|
state.substates[substate.get_name()] = instance
|
||||||
instance.parent_state = state
|
instance.parent_state = state
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ from reflex.event import EventChain, EventHandler
|
|||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
from reflex.utils.exceptions import ReflexError
|
from reflex.utils.exceptions import ReflexError
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
|
from reflex.utils.types import get_origin
|
||||||
from reflex.vars import VarData
|
from reflex.vars import VarData
|
||||||
from reflex.vars.base import CallableVar, LiteralVar, Var
|
from reflex.vars.base import CallableVar, LiteralVar, Var
|
||||||
from reflex.vars.function import FunctionVar
|
from reflex.vars.function import FunctionVar
|
||||||
@ -196,6 +197,10 @@ def convert(
|
|||||||
isinstance(value, Breakpoints)
|
isinstance(value, Breakpoints)
|
||||||
and all(not isinstance(v, dict) for v in value.values())
|
and all(not isinstance(v, dict) for v in value.values())
|
||||||
)
|
)
|
||||||
|
or (
|
||||||
|
isinstance(value, ObjectVar)
|
||||||
|
and not issubclass(get_origin(value._var_type) or value._var_type, dict)
|
||||||
|
)
|
||||||
else (key,)
|
else (key,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ def _generate_component_create_functiondef(
|
|||||||
|
|
||||||
def figure_out_return_type(annotation: Any):
|
def figure_out_return_type(annotation: Any):
|
||||||
if inspect.isclass(annotation) and issubclass(annotation, inspect._empty):
|
if inspect.isclass(annotation) and issubclass(annotation, inspect._empty):
|
||||||
return ast.Name(id="Optional[EventType[[]]]")
|
return ast.Name(id="Optional[EventType]")
|
||||||
if isinstance(annotation, str) and annotation.startswith("Tuple["):
|
if isinstance(annotation, str) and annotation.startswith("Tuple["):
|
||||||
inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]")
|
inside_of_tuple = annotation.removeprefix("Tuple[").removesuffix("]")
|
||||||
|
|
||||||
|
@ -1155,7 +1155,7 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
|
|||||||
function_var = ArgsFunctionOperation.create(tuple(), return_value)
|
function_var = ArgsFunctionOperation.create(tuple(), return_value)
|
||||||
else:
|
else:
|
||||||
# generic number var
|
# generic number var
|
||||||
number_var = Var("").to(NumberVar)
|
number_var = Var("").to(NumberVar, int)
|
||||||
|
|
||||||
first_arg_type = self[number_var]._var_type
|
first_arg_type = self[number_var]._var_type
|
||||||
|
|
||||||
@ -1167,7 +1167,10 @@ class ArrayVar(Var[ARRAY_VAR_TYPE]):
|
|||||||
_var_type=first_arg_type,
|
_var_type=first_arg_type,
|
||||||
).guess_type()
|
).guess_type()
|
||||||
|
|
||||||
function_var = ArgsFunctionOperation.create((arg_name,), fn(first_arg))
|
function_var = ArgsFunctionOperation.create(
|
||||||
|
(arg_name,),
|
||||||
|
Var.create(fn(first_arg)),
|
||||||
|
)
|
||||||
|
|
||||||
return map_array_operation(self, function_var)
|
return map_array_operation(self, function_var)
|
||||||
|
|
||||||
|
@ -2,11 +2,18 @@ from typing import List
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from reflex import event
|
from reflex.event import (
|
||||||
from reflex.event import Event, EventHandler, EventSpec, call_event_handler, fix_events
|
Event,
|
||||||
|
EventChain,
|
||||||
|
EventHandler,
|
||||||
|
EventSpec,
|
||||||
|
call_event_handler,
|
||||||
|
event,
|
||||||
|
fix_events,
|
||||||
|
)
|
||||||
from reflex.state import BaseState
|
from reflex.state import BaseState
|
||||||
from reflex.utils import format
|
from reflex.utils import format
|
||||||
from reflex.vars.base import LiteralVar, Var
|
from reflex.vars.base import Field, LiteralVar, Var, field
|
||||||
|
|
||||||
|
|
||||||
def make_var(value) -> Var:
|
def make_var(value) -> Var:
|
||||||
@ -388,3 +395,28 @@ def test_event_actions_on_state():
|
|||||||
assert sp_handler.event_actions == {"stopPropagation": True}
|
assert sp_handler.event_actions == {"stopPropagation": True}
|
||||||
# should NOT affect other references to the handler
|
# should NOT affect other references to the handler
|
||||||
assert not handler.event_actions
|
assert not handler.event_actions
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_var_data():
|
||||||
|
class S(BaseState):
|
||||||
|
x: Field[int] = field(0)
|
||||||
|
|
||||||
|
@event
|
||||||
|
def s(self, value: int):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Handler doesn't have any _var_data because it's just a str
|
||||||
|
handler_var = Var.create(S.s)
|
||||||
|
assert handler_var._get_all_var_data() is None
|
||||||
|
|
||||||
|
# Ensure spec carries _var_data
|
||||||
|
spec_var = Var.create(S.s(S.x))
|
||||||
|
assert spec_var._get_all_var_data() == S.x._get_all_var_data()
|
||||||
|
|
||||||
|
# Needed to instantiate the EventChain
|
||||||
|
def _args_spec(value: Var[int]) -> tuple[Var[int]]:
|
||||||
|
return (value,)
|
||||||
|
|
||||||
|
# Ensure chain carries _var_data
|
||||||
|
chain_var = Var.create(EventChain(events=[S.s(S.x)], args_spec=_args_spec))
|
||||||
|
assert chain_var._get_all_var_data() == S.x._get_all_var_data()
|
||||||
|
@ -3313,3 +3313,36 @@ def test_assignment_to_undeclared_vars():
|
|||||||
|
|
||||||
state.handle_supported_regular_vars()
|
state.handle_supported_regular_vars()
|
||||||
state.handle_non_var()
|
state.handle_non_var()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_deserialize_gc_state_disk(token):
|
||||||
|
"""Test that a state can be deserialized from disk with a grandchild state.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
token: A token.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Root(BaseState):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class State(Root):
|
||||||
|
num: int = 42
|
||||||
|
|
||||||
|
class Child(State):
|
||||||
|
foo: str = "bar"
|
||||||
|
|
||||||
|
dsm = StateManagerDisk(state=Root)
|
||||||
|
async with dsm.modify_state(token) as root:
|
||||||
|
s = await root.get_state(State)
|
||||||
|
s.num += 1
|
||||||
|
c = await root.get_state(Child)
|
||||||
|
assert s._get_was_touched()
|
||||||
|
assert not c._get_was_touched()
|
||||||
|
|
||||||
|
dsm2 = StateManagerDisk(state=Root)
|
||||||
|
root = await dsm2.get_state(token)
|
||||||
|
s = await root.get_state(State)
|
||||||
|
assert s.num == 43
|
||||||
|
c = await root.get_state(Child)
|
||||||
|
assert c.foo == "bar"
|
||||||
|
Loading…
Reference in New Issue
Block a user