From 2128ea62a502661cb2519cd196efa00b4c58bf97 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 6 Sep 2022 16:43:08 +0100 Subject: [PATCH] added reactive to reference docs --- docs/reference/reactive.md | 1 + docs/tutorial.md | 2 +- src/textual/reactive.py | 41 +++++++++++++++----------------------- 3 files changed, 18 insertions(+), 26 deletions(-) create mode 100644 docs/reference/reactive.md diff --git a/docs/reference/reactive.md b/docs/reference/reactive.md new file mode 100644 index 000000000..b574e77da --- /dev/null +++ b/docs/reference/reactive.md @@ -0,0 +1 @@ +::: textual.reactive.Reactive diff --git a/docs/tutorial.md b/docs/tutorial.md index e668de546..73e2ad7e1 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -338,7 +338,7 @@ If you run "stopwatch04.py" now you will be able to toggle between the two state A recurring theme in Textual is that you rarely need to explicitly update a widget. It is possible: you can call [`refresh()`][textual.widget.Widget.refresh] to display new data. However, Textual prefers to do this automatically via _reactive_ attributes. -You can declare a reactive attribute with `textual.reactive.Reactive`. Let's use this feature to create a timer that displays elapsed time and keeps it updated. +You can declare a reactive attribute with [Reactive][textual.reactive.Reactive]. Let's use this feature to create a timer that displays elapsed time and keeps it updated. ```python title="stopwatch04.py" hl_lines="1 5 12-27" --8<-- "docs/examples/tutorial/stopwatch05.py" diff --git a/src/textual/reactive.py b/src/textual/reactive.py index 99dea0ea0..78ce82f00 100644 --- a/src/textual/reactive.py +++ b/src/textual/reactive.py @@ -1,19 +1,10 @@ from __future__ import annotations -from inspect import isawaitable from functools import partial -from typing import ( - Any, - Callable, - Generic, - Type, - Union, - TypeVar, - TYPE_CHECKING, -) +from inspect import isawaitable +from typing import TYPE_CHECKING, Any, Callable, Generic, Type, TypeVar, Union from . import events - from ._callback import count_parameters, invoke from ._types import MessageTarget @@ -31,7 +22,15 @@ T = TypeVar("T") class Reactive(Generic[ReactiveType]): - """Reactive descriptor.""" + """Reactive descriptor. + + Args: + default (ReactiveType | Callable[[], ReactiveType]): A default value or callable that returns a default. + layout (bool, optional): Perform a layout on change. Defaults to False. + repaint (bool, optional): Perform a repaint on change. Defaults to True. + init (bool, optional): Call watchers on initialize (post mount). Defaults to False. + + """ def __init__( self, @@ -41,14 +40,6 @@ class Reactive(Generic[ReactiveType]): repaint: bool = True, init: bool = False, ) -> None: - """Create a Reactive Widget attribute, - - Args: - default (ReactiveType | Callable[[], ReactiveType]): A default value or callable that returns a default. - layout (bool, optional): Perform a layout on change. Defaults to False. - repaint (bool, optional): Perform a repaint on change. Defaults to True. - init (bool, optional): Call watchers on initialize (post mount). Defaults to False. - """ self._default = default self._layout = layout self._repaint = repaint @@ -138,12 +129,12 @@ class Reactive(Generic[ReactiveType]): if current_value != value or first_set: setattr(obj, f"__first_set_{self.internal_name}", False) setattr(obj, self.internal_name, value) - self.check_watchers(obj, name, current_value) + self._check_watchers(obj, name, current_value) if self._layout or self._repaint: obj.refresh(repaint=self._repaint, layout=self._layout) @classmethod - def check_watchers(cls, obj: Reactable, name: str, old_value: Any) -> None: + def _check_watchers(cls, obj: Reactable, name: str, old_value: Any) -> None: internal_name = f"_reactive_{name}" value = getattr(obj, internal_name) @@ -158,7 +149,7 @@ class Reactive(Generic[ReactiveType]): watch_result = watch_function(value) if isawaitable(watch_result): await watch_result - await Reactive.compute(obj) + await Reactive._compute(obj) watch_function = getattr(obj, f"watch_{name}", None) if callable(watch_function): @@ -182,7 +173,7 @@ class Reactive(Generic[ReactiveType]): ) @classmethod - async def compute(cls, obj: Reactable) -> None: + async def _compute(cls, obj: Reactable) -> None: _rich_traceback_guard = True computes = getattr(obj, "__computes", []) for compute in computes: @@ -203,4 +194,4 @@ def watch( setattr(obj, watcher_name, set()) watchers = getattr(obj, watcher_name) watchers.add(callback) - Reactive.check_watchers(obj, attribute_name, current_value) + Reactive._check_watchers(obj, attribute_name, current_value)