Skip to content

Commit 2494598

Browse files
committed
handle RuntimeError in get_event_loop after asyncio.run
1 parent b9afd28 commit 2494598

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

src/textual/app.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,17 @@ async def run_app() -> ReturnType | None:
21592159
# eagerly bind the event loop, and result in Future bound to wrong
21602160
# loop errors.
21612161
return asyncio.run(run_app())
2162-
return asyncio.get_event_loop().run_until_complete(run_app())
2162+
try:
2163+
global_loop = asyncio.get_event_loop()
2164+
except RuntimeError:
2165+
# the global event loop may have been destroyed by someone running
2166+
# asyncio.run(), or asyncio.set_event_loop(None), in which case
2167+
# we need to use asyncio.run() also. (We run this outside the
2168+
# context of an exception handler)
2169+
pass
2170+
else:
2171+
return global_loop.run_until_complete(run_app())
2172+
return asyncio.run(run_app())
21632173
return loop.run_until_complete(run_app())
21642174

21652175
async def _on_css_change(self) -> None:

tests/test_app.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,20 @@ def on_mount(self) -> None:
367367
app = MyApp()
368368
result = await app.run_async()
369369
assert result == 42
370+
371+
372+
def test_app_loop_run_after_asyncio_run() -> None:
373+
"""Test that App.run runs after asyncio.run has run."""
374+
375+
class MyApp(App[int]):
376+
def on_mount(self) -> None:
377+
self.exit(42)
378+
379+
async def amain():
380+
pass
381+
382+
asyncio.run(amain())
383+
384+
app = MyApp()
385+
result = app.run()
386+
assert result == 42

0 commit comments

Comments
 (0)