diff --git a/src/python/jw/pkg/lib/App.py b/src/python/jw/pkg/lib/App.py index 6eb45581..263938c2 100644 --- a/src/python/jw/pkg/lib/App.py +++ b/src/python/jw/pkg/lib/App.py @@ -4,6 +4,7 @@ import asyncio import cProfile import os import sys +import warnings from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace from typing import TYPE_CHECKING, Any, cast, override @@ -31,6 +32,17 @@ if TYPE_CHECKING: from typing import TypeVar T = TypeVar('T') +def _get_current_event_loop() -> asyncio.AbstractEventLoop | None: + """Return the current event loop of this thread, or None if there is + none, without creating one implicitly or emitting a deprecation + warning.""" + with warnings.catch_warnings(): + warnings.simplefilter('error', DeprecationWarning) + try: + return asyncio.get_event_loop() + except (RuntimeError, DeprecationWarning): + return None + class App: # export def _add_arguments(self, parser: ArgumentParser) -> None: @@ -341,7 +353,9 @@ class App: # export return self.__parser def run(self, argv: list[str] | None = None) -> None: + previous_eloop: asyncio.AbstractEventLoop | None = None if self.__eloop is None: + previous_eloop = _get_current_event_loop() eloop = asyncio.new_event_loop() asyncio.set_event_loop(eloop) self.__eloop = eloop @@ -350,6 +364,12 @@ class App: # export ret = self.eloop.run_until_complete(self.__run(argv)) finally: self.close() + # -- Restore the event loop the thread had before run(), or + # unset the loop if there was none. + if previous_eloop is not None: + asyncio.set_event_loop(previous_eloop) + else: + asyncio.set_event_loop(None) return ret