Textualize / textual

The lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.
https://textual.textualize.io/
MIT License
24.11k stars 744 forks source link

switch_screen() hangs #1714

Closed nnmm closed 1 year ago

nnmm commented 1 year ago

Description

If I call self.app.switch_screen(), the app hangs and needs two Ctrl-C presses to fully stop.

Here is an example app – press "A", then "B". You'll see that screen B is not shown and the app hangs.

from textual.app import App, ComposeResult
from textual.screen import Screen
from textual.widgets import Static, Header, Footer

class ScreenA(Screen):
    BINDINGS = [("b", "switch_to_b", "Switch to screen B")]

    def compose(self) -> ComposeResult:
        yield Header()
        yield Static("A")
        yield Footer()

    def action_switch_to_b(self):
        self.app.switch_screen(ScreenB())

class ScreenB(Screen):
    def compose(self) -> ComposeResult:
        yield Header()
        yield Static("B")
        yield Footer()

class ModalApp(App):
    BINDINGS = [("a", "push_a", "Push screen A")]

    def compose(self) -> ComposeResult:
        yield Header()
        yield Footer()

    def action_push_a(self) -> None:
        self.push_screen(ScreenA())

if __name__ == "__main__":
    app = ModalApp()
    app.run()

Screen A is only there because I wanted to make sure that it was not because I was switching the root screen.

If I replace the switch_screen() with push_screen(), screen B is shown as expected.

Textual Diagnostics

Versions

Name Value
Textual 0.10.1
Rich 13.3.1

Python

Name Value
Version 3.8.10
Implementation CPython
Compiler GCC 9.4.0
Executable /home/nnmm/.local/bin/my_project/.venv/bin/python

Operating System

Name Value
System Linux
Release 5.4.0-137-generic
Version #154-Ubuntu SMP Thu Jan 5 17:03:22 UTC 2023

Terminal

Name Value
Terminal Application Unknown
TERM tmux-256color
COLORTERM truecolor
FORCE_COLOR Not set
NO_COLOR Not set

Rich Console options

Name Value
size width=381, height=77
legacy_windows False
min_width 1
max_width 381
is_terminal True
encoding utf-8
max_height 77
justify None
overflow None
no_wrap False
highlight None
markup None
height None
github-actions[bot] commented 1 year ago

Thank you for your issue. Give us a little time to review it.

PS. You might want to check the FAQ if you haven't done so already.

This is an automated reply, generated by FAQtory

nnmm commented 1 year ago

I should add that this used to work, it only stopped working when I upgraded from version 0.9.1 to 0.10.1.

davep commented 1 year ago

Confirmed on 0.10.1. Testing with main (as of 2023-02-06) I get a different result: rather than a hang I get a crash with this error:

NoMatches: No nodes match <DOMQuery Header() filter='HeaderTitle'>
willmcgugan commented 1 year ago

I see what is going on. When the new screen mounts, the header calls watch which checks all the watchers. This invokes a watcher on the screen that has just been removed, and by the time it is handled it's DOM is empty.

github-actions[bot] commented 1 year ago

Don't forget to star the repository!

Follow @textualizeio for Textual updates.