mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Added SkipAction exception
This commit is contained in:
@@ -4,6 +4,10 @@ import ast
|
||||
import re
|
||||
|
||||
|
||||
class SkipAction(Exception):
|
||||
"""Raise in an action to skip the action (and allow any parent bindings to run)."""
|
||||
|
||||
|
||||
class ActionError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ from rich.protocol import is_renderable
|
||||
from rich.segment import Segment, Segments
|
||||
from rich.traceback import Traceback
|
||||
|
||||
from . import Logger, LogGroup, LogVerbosity, actions, events, log, messages
|
||||
from . import actions, Logger, LogGroup, LogVerbosity, events, log, messages
|
||||
from ._animator import DEFAULT_EASING, Animatable, Animator, EasingFunction
|
||||
from ._ansi_sequences import SYNC_END, SYNC_START
|
||||
from ._callback import invoke
|
||||
@@ -47,6 +47,7 @@ from ._event_broker import NoHandler, extract_handler_actions
|
||||
from ._filter import LineFilter, Monochrome
|
||||
from ._path import _make_path_object_relative
|
||||
from ._typing import Final, TypeAlias
|
||||
from .actions import SkipAction
|
||||
from .await_remove import AwaitRemove
|
||||
from .binding import Binding, Bindings
|
||||
from .css.query import NoMatches
|
||||
@@ -1752,7 +1753,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
):
|
||||
binding = bindings.keys.get(key)
|
||||
if binding is not None and binding.priority == priority:
|
||||
if await self.action(binding.action, namespace) in (True, None):
|
||||
if await self.action(binding.action, namespace):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -1822,30 +1823,41 @@ class App(Generic[ReturnType], DOMNode):
|
||||
async def _dispatch_action(
|
||||
self, namespace: object, action_name: str, params: Any
|
||||
) -> bool:
|
||||
"""Dispatch an action to an action method.
|
||||
|
||||
Args:
|
||||
namespace (object): Namespace (object) of action.
|
||||
action_name (str): Name of the action.
|
||||
params (Any): Action parameters.
|
||||
|
||||
Returns:
|
||||
bool: True if handled, otherwise False.
|
||||
"""
|
||||
_rich_traceback_guard = True
|
||||
|
||||
log(
|
||||
"<action>",
|
||||
namespace=namespace,
|
||||
action_name=action_name,
|
||||
params=params,
|
||||
)
|
||||
_rich_traceback_guard = True
|
||||
)
|
||||
|
||||
public_method_name = f"action_{action_name}"
|
||||
private_method_name = f"_{public_method_name}"
|
||||
|
||||
private_method = getattr(namespace, private_method_name, None)
|
||||
public_method = getattr(namespace, public_method_name, None)
|
||||
|
||||
if private_method is None and public_method is None:
|
||||
try:
|
||||
private_method = getattr(namespace, f"_action_{action_name}", None)
|
||||
if callable(private_method):
|
||||
await invoke(private_method, *params)
|
||||
return True
|
||||
public_method = getattr(namespace, f"action_{action_name}", None)
|
||||
if callable(public_method):
|
||||
await invoke(public_method, *params)
|
||||
return True
|
||||
log(
|
||||
f"<action> {action_name!r} has no target. Couldn't find methods {public_method_name!r} or {private_method_name!r}"
|
||||
f"<action> {action_name!r} has no target."
|
||||
f" Could not find methods '_action_{action_name}' or 'action_{action_name}'"
|
||||
)
|
||||
|
||||
if callable(private_method):
|
||||
return await invoke(private_method, *params)
|
||||
elif callable(public_method):
|
||||
return await invoke(public_method, *params)
|
||||
|
||||
except SkipAction:
|
||||
# The action method raised this to explicitly not handle the action
|
||||
log("<action> {action_name!r} skipped.")
|
||||
return False
|
||||
|
||||
async def _broker_event(
|
||||
@@ -1856,7 +1868,7 @@ class App(Generic[ReturnType], DOMNode):
|
||||
Args:
|
||||
event_name (str): _description_
|
||||
event (events.Event): An event object.
|
||||
default_namespace (object | None): TODO: _description_
|
||||
default_namespace (object | None): The default namespace, where one isn't supplied.
|
||||
|
||||
Returns:
|
||||
bool: True if an action was processed.
|
||||
|
||||
@@ -44,6 +44,7 @@ from ._layout import Layout
|
||||
from ._segment_tools import align_lines
|
||||
from ._styles_cache import StylesCache
|
||||
from ._types import Lines
|
||||
from .actions import SkipAction
|
||||
from .await_remove import AwaitRemove
|
||||
from .binding import Binding
|
||||
from .box_model import BoxModel, get_box_model
|
||||
@@ -2403,42 +2404,42 @@ class Widget(DOMNode):
|
||||
def _on_scroll_to_region(self, message: messages.ScrollToRegion) -> None:
|
||||
self.scroll_to_region(message.region, animate=True)
|
||||
|
||||
def action_scroll_home(self) -> bool | None:
|
||||
def action_scroll_home(self) -> None:
|
||||
if not self._allow_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_home()
|
||||
|
||||
def action_scroll_end(self) -> bool | None:
|
||||
def action_scroll_end(self) -> None:
|
||||
if not self._allow_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_end()
|
||||
|
||||
def action_scroll_left(self) -> bool | None:
|
||||
def action_scroll_left(self) -> None:
|
||||
if not self.allow_horizontal_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_left()
|
||||
|
||||
def action_scroll_right(self) -> bool | None:
|
||||
def action_scroll_right(self) -> None:
|
||||
if not self.allow_horizontal_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_right()
|
||||
|
||||
def action_scroll_up(self) -> bool | None:
|
||||
def action_scroll_up(self) -> None:
|
||||
if not self.allow_vertical_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_up()
|
||||
|
||||
def action_scroll_down(self) -> bool | None:
|
||||
def action_scroll_down(self) -> None:
|
||||
if not self.allow_vertical_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_down()
|
||||
|
||||
def action_page_down(self) -> bool | None:
|
||||
def action_page_down(self) -> None:
|
||||
if not self.allow_vertical_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_page_down()
|
||||
|
||||
def action_page_up(self) -> bool | None:
|
||||
def action_page_up(self) -> None:
|
||||
if not self.allow_vertical_scroll:
|
||||
return False
|
||||
raise SkipAction()
|
||||
self.scroll_page_up()
|
||||
|
||||
@@ -11,6 +11,7 @@ background relating to this.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from textual.actions import SkipAction
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.containers import Container
|
||||
@@ -626,7 +627,7 @@ async def test_skip_action() -> None:
|
||||
def action_test(self, text: str) -> bool:
|
||||
nonlocal no_handle_invoked
|
||||
no_handle_invoked = True
|
||||
return False
|
||||
raise SkipAction()
|
||||
|
||||
class SkipApp(App):
|
||||
def compose(self) -> ComposeResult:
|
||||
|
||||
Reference in New Issue
Block a user