mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
callback invoke
This commit is contained in:
@@ -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
28
src/textual/_callback.py
Normal 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
|
||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user