Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue with switch screen. #2692

Merged
merged 1 commit into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 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/).

- Fixed zero division error https://github.com/Textualize/textual/issues/2673
- Fix `scroll_to_center` when there were nested layers out of view (Compositor full_map not populated fully) https://github.com/Textualize/textual/pull/2684
- Issues with `switch_screen` not updating the results callback appropriately https://github.com/Textualize/textual/issues/2650

### Added

Expand All @@ -35,6 +36,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `Tree` and `DirectoryTree` Messages no longer accept a `tree` parameter, using `self.node.tree` instead. https://github.com/Textualize/textual/issues/2529
- Keybinding <kbd>right</kbd> in `Input` is also used to accept a suggestion if the cursor is at the end of the input https://github.com/Textualize/textual/pull/2604
- `Input.__init__` now accepts a `suggester` attribute for completion suggestions https://github.com/Textualize/textual/pull/2604
- Using `switch_screen` to switch to the currently active screen is now a no-op https://github.com/Textualize/textual/pull/2692

### Removed

Expand Down
22 changes: 13 additions & 9 deletions src/textual/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -1611,15 +1611,19 @@ def switch_screen(self, screen: Screen | str) -> AwaitMount:
raise TypeError(
f"switch_screen requires a Screen instance or str; not {screen!r}"
)
if self.screen is not screen:
previous_screen = self._replace_screen(self._screen_stack.pop())
previous_screen._pop_result_callback()
next_screen, await_mount = self._get_screen(screen)
self._screen_stack.append(next_screen)
self.screen.post_message(events.ScreenResume())
self.log.system(f"{self.screen} is current (SWITCHED)")
return await_mount
return AwaitMount(self.screen, [])

next_screen, await_mount = self._get_screen(screen)
if screen is self.screen or next_screen is self.screen:
self.log.system(f"Screen {screen} is already current.")
return AwaitMount(self.screen, [])

previous_screen = self._replace_screen(self._screen_stack.pop())
previous_screen._pop_result_callback()
self._screen_stack.append(next_screen)
self.screen.post_message(events.ScreenResume())
self.screen._push_result_callback(self.screen, None)
self.log.system(f"{self.screen} is current (SWITCHED)")
return await_mount

def install_screen(self, screen: Screen, name: str) -> None:
"""Install a screen.
Expand Down
52 changes: 52 additions & 0 deletions tests/test_screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,55 @@ async def key_p(self) -> None:
await pilot.press("p")
with pytest.raises(ScreenStackError):
app.bottom.dismiss()


async def test_switch_screen_no_op():
"""Regression test for https://github.com/Textualize/textual/issues/2650"""

class MyScreen(Screen):
pass

class MyApp(App[None]):
SCREENS = {"screen": MyScreen()}

def on_mount(self):
self.push_screen("screen")

app = MyApp()
async with app.run_test():
screen_id = id(app.screen)
app.switch_screen("screen")
assert screen_id == id(app.screen)
app.switch_screen("screen")
assert screen_id == id(app.screen)


async def test_switch_screen_updates_results_callback_stack():
"""Regression test for https://github.com/Textualize/textual/issues/2650"""

class ScreenA(Screen):
pass

class ScreenB(Screen):
pass

class MyApp(App[None]):
SCREENS = {
"a": ScreenA(),
"b": ScreenB(),
}

def callback(self, _):
return 42

def on_mount(self):
self.push_screen("a", self.callback)

app = MyApp()
async with app.run_test():
assert len(app.screen._result_callbacks) == 1
assert app.screen._result_callbacks[-1].callback(None) == 42

app.switch_screen("b")
assert len(app.screen._result_callbacks) == 1
assert app.screen._result_callbacks[-1].callback is None