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

Cannot find "active_app" #5421

Open
davidbrochart opened this issue Dec 21, 2024 · 7 comments
Open

Cannot find "active_app" #5421

davidbrochart opened this issue Dec 21, 2024 · 7 comments

Comments

@davidbrochart
Copy link
Contributor

While running a Textual app with its run_async() method, I get this message in the Textual console:

Task exception was never retrieved
future: <Task finished name='set_timer#1' coro=<Timer._run_timer() done, defined at
/home/david/git/textual/src/textual/timer.py:137> exception=LookupError(<ContextVar
name='active_app' at 0x7f64d1c924d0>)>
Traceback (most recent call last):
  File "/home/david/git/textual/src/textual/timer.py", line 140, in _run_timer
    await self._run()
  File "/home/david/git/textual/src/textual/timer.py", line 169, in _run
    await self._tick(next_timer=next_timer, count=count)
  File "/home/david/git/textual/src/textual/timer.py", line 176, in _tick
    app = active_app.get()
LookupError: <ContextVar name='active_app' at 0x7f64d1c924d0>

Sometimes it makes the app crash, sometimes not.
I don't have a reproducible example because it happens in a bigger application, but do you know what could cause this?

# Textual Diagnostics

## Versions

| Name    | Value  |
|---------|--------|
| Textual | 1.0.0  |
| Rich    | 13.9.4 |

## Python

| Name           | Value                                                                     |
|----------------|---------------------------------------------------------------------------|
| Version        | 3.13.1                                                                    |
| Implementation | CPython                                                                   |
| Compiler       | GCC 13.3.0                                                                |
| Executable     | /home/david/.local/share/hatch/env/virtual/jpterm/N1y3coPp/dev/bin/python |

## Operating System

| Name    | Value                                                |
|---------|------------------------------------------------------|
| System  | Linux                                                |
| Release | 6.1.0-27-amd64                                       |
| Version | #1 SMP PREEMPT_DYNAMIC Debian 6.1.115-1 (2024-11-01) |

## Terminal

| Name                 | Value           |
|----------------------|-----------------|
| Terminal Application | vscode (1.96.1) |
| TERM                 | xterm-256color  |
| COLORTERM            | truecolor       |
| FORCE_COLOR          | *Not set*       |
| NO_COLOR             | *Not set*       |

## Rich Console options

| Name           | Value               |
|----------------|---------------------|
| size           | width=95, height=45 |
| legacy_windows | False               |
| min_width      | 1                   |
| max_width      | 95                  |
| is_terminal    | True                |
| encoding       | utf-8               |
| max_height     | 45                  |
| justify        | None                |
| overflow       | None                |
| no_wrap        | False               |
| highlight      | None                |
| markup         | None                |
| height         | None                |

If you don't have the textual command on your path, you may have forgotten to install the textual-dev package.

Feel free to add screenshots and / or videos. These can be very helpful!

Copy link

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

@davidbrochart
Copy link
Contributor Author

davidbrochart commented Dec 21, 2024

This snippet triggers the error:

import asyncio
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.widgets import MarkdownViewer

EXAMPLE_MARKDOWN = """\
# Markdown Viewer

This is an example of Textual's `MarkdownViewer` widget.


## Features

Markdown syntax and extensions are supported.

- Typography *emphasis*, **strong**, `inline code` etc.
- Headers
- Lists (bullet and ordered)
- Syntax highlighted code blocks
- Tables!

## Tables

Tables are displayed in a DataTable widget.

| Name            | Type   | Default | Description                        |
| --------------- | ------ | ------- | ---------------------------------- |
| `show_header`   | `bool` | `True`  | Show the table header              |
| `fixed_rows`    | `int`  | `0`     | Number of fixed rows               |
| `fixed_columns` | `int`  | `0`     | Number of fixed columns            |
| `zebra_stripes` | `bool` | `False` | Display alternating colors on rows |
| `header_height` | `int`  | `1`     | Height of header row               |
| `show_cursor`   | `bool` | `True`  | Show a cell cursor                 |
"""

class MyApp(App):
    def compose(self) -> ComposeResult:
        self.container = Container()
        yield self.container

async def task(app: MyApp):
    await asyncio.sleep(1)
    app.container.mount(MarkdownViewer(EXAMPLE_MARKDOWN))

async def main():
    app = MyApp()
    t0 = asyncio.create_task(task(app))
    t1 = asyncio.create_task(app.run_async())
    await asyncio.Future()

if __name__ == "__main__":
    asyncio.run(main())

@davidbrochart
Copy link
Contributor Author

Note that it works fine if I replace MarkdownViewer(EXAMPLE_MARKDOWN) with Header() for instance.

@davidbrochart
Copy link
Contributor Author

One workaround is to:

from textual._context import active_app

And to set the active app before mounting the widget:

active_app.set(app)
app.container.mount(MarkdownViewer(EXAMPLE_MARKDOWN))

But I'm not sure if there's a better solution?

@willmcgugan
Copy link
Collaborator

I wouldn't expect the MRE to work. It looks like it would call mount before the app is running. The earliest that should work is when the App handles the Ready event. If you try to do anything with the DOM prior to that, then the results may be undefined.

Not sure if that explains your original issue. Could you be creating a timer before the app is running?

@davidbrochart
Copy link
Contributor Author

The mount is called after the app is running, but in a different stack, so contextvars are unrelated. That's why setting the active_app before the mount solves the issue.

@basnijholt
Copy link

basnijholt commented Jan 3, 2025

I am running into this problem when calling await app.recompose(), the workaround @davidbrochart mentioned (active_app.set(app)) works.

For context, I am running into it here basnijholt/tuitorial#18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants