Skip to content

Commit

Permalink
Error when dismissing non-active screen.
Browse files Browse the repository at this point in the history
Related issues: #2575.
  • Loading branch information
rodrigogiraoserrao committed May 16, 2023
1 parent 6147c28 commit 7a8d692
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- App `title` and `sub_title` attributes can be set to any type https://github.com/Textualize/textual/issues/2521
- Using `Widget.move_child` where the target and the child being moved are the same is now a no-op https://github.com/Textualize/textual/issues/1743
- Calling `dismiss` on a screen that is not at the top of the stack now raises an exception https://github.com/Textualize/textual/issues/2575

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion src/textual/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class ScreenError(Exception):


class ScreenStackError(ScreenError):
"""Raised when attempting to pop the last screen from the stack."""
"""Raised when trying to manipulate the screen stack incorrectly."""


class CssPathError(Exception):
Expand Down
9 changes: 9 additions & 0 deletions src/textual/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from ._compositor import Compositor, MapGeometry
from ._context import visible_screen_stack
from ._types import CallbackType
from .app import ScreenStackError
from .binding import Binding
from .css.match import match
from .css.parse import parse_selectors
Expand Down Expand Up @@ -771,13 +772,21 @@ def dismiss(self, result: ScreenResultType | Type[_NoResult] = _NoResult) -> Non
Args:
result: The optional result to be passed to the result callback.
Raises:
ScreenStackError: If trying to dismiss a screen that is not at the top of
the stack.
Note:
If the screen was pushed with a callback, the callback will be
called with the given result and then a call to
[`App.pop_screen`][textual.app.App.pop_screen] is performed. If
no callback was provided calling this method is the same as
simply calling [`App.pop_screen`][textual.app.App.pop_screen].
"""
if self is not self.app.screen:
raise ScreenStackError(
f"Can't dismiss screen {self} that's not at the top of the stack."
)
if result is not self._NoResult and self._result_callbacks:
self._result_callbacks[-1](cast(ScreenResultType, result))
self.app.pop_screen()
Expand Down
14 changes: 14 additions & 0 deletions tests/test_screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,17 @@ class MyApp(App[None]):
assert app.focused is None
app.pop_screen()
assert app.focused.id == "two"


async def test_dismiss_non_top_screen():
class MyApp(App[None]):
async def key_p(self) -> None:
self.bottom, top = Screen(), Screen()
await self.push_screen(self.bottom)
await self.push_screen(top)

app = MyApp()
async with app.run_test() as pilot:
await pilot.press("p")
with pytest.raises(ScreenStackError):
app.bottom.dismiss()

0 comments on commit 7a8d692

Please sign in to comment.