diff --git a/changes/3342.bugfix.rst b/changes/3342.bugfix.rst new file mode 100644 index 0000000000..cd5cb86728 --- /dev/null +++ b/changes/3342.bugfix.rst @@ -0,0 +1 @@ +An incompatibility with Textual 3.0 that caused log messages to be generated on the console on app exit has been resolved. diff --git a/textual/pyproject.toml b/textual/pyproject.toml index 1c922f4306..ef7297f7f3 100644 --- a/textual/pyproject.toml +++ b/textual/pyproject.toml @@ -66,7 +66,7 @@ root = ".." [tool.setuptools_dynamic_dependencies] dependencies = [ - "textual >= 0.44.0", + "textual >= 3.0.0, < 4.0.0", "toga-core == {version}", ] diff --git a/textual/src/toga_textual/app.py b/textual/src/toga_textual/app.py index 6dfe60a2f0..571301004a 100644 --- a/textual/src/toga_textual/app.py +++ b/textual/src/toga_textual/app.py @@ -1,4 +1,5 @@ import asyncio +import threading import toga from textual.app import App as TextualApp @@ -27,6 +28,7 @@ def __init__(self, interface): self.interface._impl = self self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) self.native = TogaApp(self) self._current_window = None @@ -56,7 +58,21 @@ def exit(self): self.native.exit() def main_loop(self): - self.loop.run_until_complete(self.native.run_async(headless=self.headless)) + # This is duplicating the bulk of TextualApp.run(); however, that entry point + # doesn't give any control over the event loop that is used. The key detail + # is that the _context() is required to capture logging messages generated + # as the app is shutting down. See textualize/textual#5091. + with self.native._context(): + try: + self.native._loop = self.loop + self.native._thread_id = threading.get_ident() + + self.loop.run_until_complete( + self.native.run_async(headless=self.headless) + ) + finally: + self.native._loop = None + self.native._thread_id = 0 def set_icon(self, icon): pass