From fff42606df2283b1a2b973c4a188fa2029c80ec9 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 22 Jul 2024 16:47:12 +0100 Subject: [PATCH] refactor --- src/textual/_dispatch_key.py | 10 ++++++---- src/textual/app.py | 2 +- src/textual/screen.py | 9 ++------- tests/test_message_pump.py | 7 ++++--- tests/test_screens.py | 8 +++++--- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/textual/_dispatch_key.py b/src/textual/_dispatch_key.py index e4b0a5e8a9..92bf7312c8 100644 --- a/src/textual/_dispatch_key.py +++ b/src/textual/_dispatch_key.py @@ -45,10 +45,12 @@ def _raise_duplicate_key_handlers_error( f"Consider combining them into a single handler.", ) - screen = node.screen + try: + screen = node.screen + except Exception: + screen = None for key_method_name in event.name_aliases: - key_method = get_key_handler(node, key_method_name) - if key_method is not None: + if (key_method := get_key_handler(node, key_method_name)) is not None: if invoked_method: _raise_duplicate_key_handlers_error( key_name, invoked_method.__name__, key_method.__name__ @@ -56,7 +58,7 @@ def _raise_duplicate_key_handlers_error( # If key handlers return False, then they are not considered handled # This allows key handlers to do some conditional logic - if not screen.is_active: + if screen is not None and not screen.is_active: break handled = (await invoke(key_method, event)) is not False invoked_method = key_method diff --git a/src/textual/app.py b/src/textual/app.py index 5e23f429c1..7aab856659 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -801,7 +801,7 @@ def is_inline(self) -> bool: return False if self._driver is None else self._driver.is_inline @property - def screen_stack(self) -> Sequence[Screen[Any]]: + def screen_stack(self) -> list[Screen[Any]]: """A snapshot of the current screen stack. Returns: diff --git a/src/textual/screen.py b/src/textual/screen.py index d51831da3c..b7e8c5998b 100644 --- a/src/textual/screen.py +++ b/src/textual/screen.py @@ -1237,8 +1237,8 @@ def dismiss( !!! note - Only the active screen may be dismissed. If you try to dismiss a screen that isn't active, - this method will raise a `ScreenError`. + Only the active screen may be dismissed. This method will produce a warning in the logs if + called on an inactive screen (but otherwise have no effect). If `result` is provided and a callback was set when the screen was [pushed][textual.app.App.push_screen], then the callback will be invoked with `result`. @@ -1246,11 +1246,6 @@ def dismiss( Args: result: The optional result to be passed to the result callback. - Raises: - ScreenError: If the screen being dismissed is not active. - ScreenStackError: If trying to dismiss a screen that is not at the top of - the stack. - """ if not self.is_active: self.log.warning("Can't dismiss inactive screen") diff --git a/tests/test_message_pump.py b/tests/test_message_pump.py index 90b840bf85..58fb5d325a 100644 --- a/tests/test_message_pump.py +++ b/tests/test_message_pump.py @@ -1,5 +1,6 @@ import pytest +from textual._dispatch_key import dispatch_key from textual.app import App, ComposeResult from textual.errors import DuplicateKeyHandlers from textual.events import Key @@ -20,7 +21,7 @@ def key_ctrl_i(self): async def test_dispatch_key_valid_key(): widget = ValidWidget() - result = await widget.dispatch_key(Key(key="x", character="x")) + result = await dispatch_key(widget, Key(key="x", character="x")) assert result is True assert widget.called_by == widget.key_x @@ -29,7 +30,7 @@ async def test_dispatch_key_valid_key_alias(): """When you press tab or ctrl+i, it comes through as a tab key event, but handlers for tab and ctrl+i are both considered valid.""" widget = ValidWidget() - result = await widget.dispatch_key(Key(key="tab", character="\t")) + result = await dispatch_key(widget, Key(key="tab", character="\t")) assert result is True assert widget.called_by == widget.key_ctrl_i @@ -55,7 +56,7 @@ async def test_dispatch_key_raises_when_conflicting_handler_aliases(): In the terminal, they're the same thing, so we fail fast via exception here.""" widget = DuplicateHandlersWidget() with pytest.raises(DuplicateKeyHandlers): - await widget.dispatch_key(Key(key="tab", character="\t")) + await dispatch_key(widget, Key(key="tab", character="\t")) assert widget.called_by == widget.key_tab diff --git a/tests/test_screens.py b/tests/test_screens.py index aef83dfdb4..adb8afecd6 100644 --- a/tests/test_screens.py +++ b/tests/test_screens.py @@ -5,7 +5,7 @@ import pytest from textual import work -from textual.app import App, ComposeResult, ScreenError, ScreenStackError +from textual.app import App, ComposeResult, ScreenStackError from textual.events import MouseMove from textual.geometry import Offset from textual.screen import Screen @@ -301,8 +301,10 @@ async def key_p(self) -> None: app = MyApp() async with app.run_test() as pilot: await pilot.press("p") - with pytest.raises(ScreenError): - await app.bottom.dismiss() + # A noop if not the top + stack = list(app.screen_stack) + await app.bottom.dismiss() + assert app.screen_stack == stack async def test_dismiss_action():