Merge pull request #2580 from Textualize/dismiss-top

Error when dismissing non-active screen.
This commit is contained in:
Rodrigo Girão Serrão
2023-05-16 11:38:31 +01:00
committed by GitHub
4 changed files with 26 additions and 1 deletions

View File

@@ -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 - 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 - 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 ### Fixed

View File

@@ -156,7 +156,7 @@ class ScreenError(Exception):
class ScreenStackError(ScreenError): 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): class CssPathError(Exception):

View File

@@ -771,6 +771,10 @@ class Screen(Generic[ScreenResultType], Widget):
Args: Args:
result: The optional result to be passed to the result callback. 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: Note:
If the screen was pushed with a callback, the callback will be If the screen was pushed with a callback, the callback will be
called with the given result and then a call to called with the given result and then a call to
@@ -778,6 +782,12 @@ class Screen(Generic[ScreenResultType], Widget):
no callback was provided calling this method is the same as no callback was provided calling this method is the same as
simply calling [`App.pop_screen`][textual.app.App.pop_screen]. simply calling [`App.pop_screen`][textual.app.App.pop_screen].
""" """
if self is not self.app.screen:
from .app import ScreenStackError
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: if result is not self._NoResult and self._result_callbacks:
self._result_callbacks[-1](cast(ScreenResultType, result)) self._result_callbacks[-1](cast(ScreenResultType, result))
self.app.pop_screen() self.app.pop_screen()

View File

@@ -192,3 +192,17 @@ async def test_auto_focus():
assert app.focused is None assert app.focused is None
app.pop_screen() app.pop_screen()
assert app.focused.id == "two" 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()