callback invoke

This commit is contained in:
Will McGugan
2021-08-13 20:46:03 +01:00
parent 5aa6224e65
commit ed477c5682
4 changed files with 39 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
from rich.console import RenderableType
from rich.panel import Panel from rich.panel import Panel
from textual import events
from textual.app import App from textual.app import App
from textual.reactive import Reactive from textual.reactive import Reactive
from textual.widget import Widget from textual.widget import Widget
@@ -8,22 +8,22 @@ from textual.widget import Widget
class Hover(Widget): class Hover(Widget):
mouse_over: Reactive[bool] = Reactive(False) mouse_over = Reactive(False)
def render(self) -> Panel: def render(self) -> RenderableType:
return Panel("Hello [b]World[/b]", style=("on red" if self.mouse_over else "")) return Panel("Hello [b]World[/b]", style=("on red" if self.mouse_over else ""))
async def on_enter(self, event: events.Enter) -> None: def on_enter(self) -> None:
self.mouse_over = True self.mouse_over = True
async def on_leave(self, event: events.Leave) -> None: def on_leave(self) -> None:
self.mouse_over = False self.mouse_over = False
class HoverApp(App): class HoverApp(App):
"""Demonstrates smooth animation""" """Demonstrates smooth animation"""
async def on_mount(self, event: events.Mount) -> None: async def on_mount(self) -> None:
"""Build layout here.""" """Build layout here."""
hovers = (Hover() for _ in range(10)) hovers = (Hover() for _ in range(10))

28
src/textual/_callback.py Normal file
View File

@@ -0,0 +1,28 @@
from __future__ import annotations
from functools import lru_cache
from inspect import signature, isawaitable
from typing import Any, Callable
@lru_cache(maxsize=2048)
def count_parameters(func: Callable) -> int:
"""Count the number of parameters in a callable"""
return len(signature(func).parameters)
async def invoke(callback: Callable, *params: object) -> Any:
"""Invoke a callback with an arbitrary number of parameters.
Args:
callback (Callable): [description]
Returns:
Any: [description]
"""
parameter_count = count_parameters(callback)
result = callback(*params[:parameter_count])
if isawaitable(result):
await result

View File

@@ -12,6 +12,7 @@ from rich.traceback import Traceback
from . import events from . import events
from . import log from . import log
from ._timer import Timer, TimerCallback from ._timer import Timer, TimerCallback
from ._callback import invoke
from ._context import active_app from ._context import active_app
from .message import Message from .message import Message
from .reactive import Reactive from .reactive import Reactive
@@ -241,7 +242,7 @@ class MessagePump:
for method in self._get_dispatch_methods(f"on_{event.name}", event): for method in self._get_dispatch_methods(f"on_{event.name}", event):
log(event, ">>>", self, verbosity=event.verbosity) log(event, ">>>", self, verbosity=event.verbosity)
await method(event) await invoke(method, event)
if event.bubble and self._parent and not event._stop_propagation: if event.bubble and self._parent and not event._stop_propagation:
if event.sender != self._parent and self.is_parent_active: if event.sender != self._parent and self.is_parent_active:
@@ -308,9 +309,7 @@ class MessagePump:
event.stop() event.stop()
if event.callback is not None: if event.callback is not None:
try: try:
callback_result = event.callback() await invoke(event.callback)
if inspect.isawaitable(callback_result):
await callback_result
except Exception as error: except Exception as error:
raise CallbackError( raise CallbackError(
f"unable to run callback {event.callback!r}; {error}" f"unable to run callback {event.callback!r}; {error}"

View File

@@ -16,6 +16,7 @@ from typing import (
from . import log from . import log
from . import events from . import events
from ._callback import count_parameters
from ._types import MessageTarget from ._types import MessageTarget
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -28,10 +29,6 @@ if TYPE_CHECKING:
ReactiveType = TypeVar("ReactiveType") ReactiveType = TypeVar("ReactiveType")
def count_params(func: Callable) -> int:
return len(inspect.signature(func).parameters)
class Reactive(Generic[ReactiveType]): class Reactive(Generic[ReactiveType]):
"""Reactive descriptor.""" """Reactive descriptor."""
@@ -92,7 +89,7 @@ class Reactive(Generic[ReactiveType]):
obj: Reactable, watch_function: Callable, old_value: Any, value: Any obj: Reactable, watch_function: Callable, old_value: Any, value: Any
) -> None: ) -> None:
_rich_traceback_guard = True _rich_traceback_guard = True
if count_params(watch_function) == 2: if count_parameters(watch_function) == 2:
await watch_function(old_value, value) await watch_function(old_value, value)
else: else:
await watch_function(value) await watch_function(value)