Skip to content

Textual crashes on application error #248

@mhils

Description

@mhils

When my custom application code raises an exception in on_mount, Textual clears the screen (which hides the original error) and then crashes itself.

When debugging #247 I found that the way Textual crashes is rather unsatisfying way upon exit (Screenshot 1). Scrolling up reveals parts of the beautifully rendered error message, which unfortunately is cut off (Screenshot 2).

Screenshot 1 Screenshot 2
image image

Based on my limited testing this affects both Windows and Linux, both on main and the css branch1.

Steps to reproduce

Repro: Insert raise RuntimeError in the get_markdown callback in examples/simple.py:

async def get_markdown(filename: str) -> None:
with open(filename, "rt") as fh:
readme = Markdown(fh.read(), hyperlinks=True)
await body.update(readme)
await self.call_later(get_markdown, "richreadme.md")

Additional Information

The amount of info that is cut off depends on the terminal size, presumably because textual clears the current screen upon exit and everything above the fold stays.

terminal width 120x40
PS C:\Users\user\git\textual\examples> python .\simple.py
╭───────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────╮
│                                                                                                                      │
│ C:\Python310\lib\site-packages\textual\message_pump.py:306 in on_callback                                            │
│                                                                                                                      │
│   303 │   │   return await self.post_message(message)                                                                │
│   304 │                                                                                                              │
│   305 │   async def on_callback(self, event: events.Callback) -> None:                                               │
│ ❱ 306 │   │   await event.callback()                                                                                 │
│   307 │                                                                                                              │
│   308 │   def emit_no_wait(self, message: Message) -> bool:                                                          │
│   309 │   │   if self._parent:                                                                                       │
│                                                                                                                      │
│ ╭───────────────────────────────────────────────────── locals ─────────────────────────────────────────────────────╮ │

Traceback (most recent call last):
File "C:\Python310\lib\site-packages\textual_timer.py", line 89, in _run
async def _run(self) -> None:
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Python310\lib\site-packages\textual\app.py", line 204, in run_app
await app.process_messages()
File "C:\Python310\lib\site-packages\textual\app.py", line 311, in process_messages
await self.animator.stop()
File "C:\Python310\lib\site-packages\textual_animator.py", line 119, in stop
await self._timer.stop()
File "C:\Python310\lib\site-packages\textual_timer.py", line 79, in stop
await self._task
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\user\git\textual\examples\simple.py", line 38, in
MyApp.run(title="Simple App", log="textual.log")
File "C:\Python310\lib\site-packages\textual\app.py", line 206, in run
asyncio.run(run_app())
File "C:\Python310\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
return future.result()
asyncio.exceptions.CancelledError

terminal width 80x40
PS C:\Users\user\git\textual\examples> python .\simple.py
╭───────────────────── Traceback (most recent call last) ──────────────────────╮
│                                                                              │
│ C:\Python310\lib\site-packages\textual\message_pump.py:306 in on_callback    │
│                                                                              │
│   303 │   │   return await self.post_message(message)                        │
│   304 │                                                                      │
│   305 │   async def on_callback(self, event: events.Callback) -> None:       │
│ ❱ 306 │   │   await event.callback()                                         │
│   307 │                                                                      │
│   308 │   def emit_no_wait(self, message: Message) -> bool:                  │
│   309 │   │   if self._parent:                                               │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │ event = Callback(                                                        │ │
│ │         │   callback=functools.partial(.get_markdown at 0x000001D291BED630>,     │ │
│ │         'richreadme.md')                                                 │ │

Traceback (most recent call last):
File "C:\Python310\lib\site-packages\textual_timer.py", line 89, in _run
async def _run(self) -> None:
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Python310\lib\site-packages\textual\app.py", line 204, in run_app
await app.process_messages()
File "C:\Python310\lib\site-packages\textual\app.py", line 311, in process_messages
await self.animator.stop()
File "C:\Python310\lib\site-packages\textual_animator.py", line 119, in stop
await self._timer.stop()
File "C:\Python310\lib\site-packages\textual_timer.py", line 79, in stop
await self._task
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\user\git\textual\examples\simple.py", line 38, in
MyApp.run(title="Simple App", log="textual.log")
File "C:\Python310\lib\site-packages\textual\app.py", line 206, in run
asyncio.run(run_app())
File "C:\Python310\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
return future.result()
asyncio.exceptions.CancelledError

terminal width 80x20
PS C:\Users\user\git\textual\examples> python .\simple.py
╭───────────────────── Traceback (most recent call last) ──────────────────────╮
│                                                                              │
│ C:\Python310\lib\site-packages\textual\message_pump.py:306 in on_callback    │
│                                                                              │
│   303 │   │   return await self.post_message(message)                        │
│   304 │                                                                      │
│   305 │   async def on_callback(self, event: events.Callback) -> None:       │
│ ❱ 306 │   │   await event.callback()                                         │
│   307 │                                                                      │
│   308 │   def emit_no_wait(self, message: Message) -> bool:                  │
│   309 │   │   if self._parent:                                               │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │ event = Callback(                                                        │ │
│ │         │   callback=functools.partial(.get_markdown at 0x000001CA9AA1D630>,     │ │
│ │         'richreadme.md')                                                 │ │
│ │         )                                                                │ │
│ │  self = MyApp(title='Simple App')                                        │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│ C:\Users\user\git\textual\examples\simple.py:32 in get_markdown              │
│                                                                              │
│   29 │   │                                                                   │
│   30 │   │   async def get_markdown(filename: str) -> None:                  │
│   31 │   │   │   with open(filename, "r") as fh:                             │
│ ❱ 32 │   │   │   │   readme = Markdown(fh.read(), hyperlinks=True)           │
│   33 │   │   │   await body.update(readme)                                   │
│   34 │   │                                                                   │
│   35 │   │   await self.call_later(get_markdown, "richreadme.md")            │
│                                                                              │
│ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
│ │     body = ScrollView(name='ScrollView#1')                               │ │
│ │       fh = <_io.TextIOWrapper name='richreadme.md' mode='r'              │ │
│ │            encoding='cp1252'>                                            │ │
│ │ filename = 'richreadme.md'                                               │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │

Traceback (most recent call last):
File "C:\Python310\lib\site-packages\textual_timer.py", line 89, in _run
async def _run(self) -> None:
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Python310\lib\site-packages\textual\app.py", line 204, in run_app
await app.process_messages()
File "C:\Python310\lib\site-packages\textual\app.py", line 311, in process_messages
await self.animator.stop()
File "C:\Python310\lib\site-packages\textual_animator.py", line 119, in stop
await self._timer.stop()
File "C:\Python310\lib\site-packages\textual_timer.py", line 79, in stop
await self._task
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\user\git\textual\examples\simple.py", line 38, in
MyApp.run(title="Simple App", log="textual.log")
File "C:\Python310\lib\site-packages\textual\app.py", line 206, in run
asyncio.run(run_app())
File "C:\Python310\lib\asyncio\runners.py", line 44, in run
return loop.run_until_complete(main)
File "C:\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
return future.result()
asyncio.exceptions.CancelledError

Footnotes

  1. The simple example on the css branch only renders a black screen at the moment, but the crash behavior is the same.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions