From: Thomas Grainger Date: Fri, 18 Mar 2022 18:53:37 +0000 (+0000) Subject: avoid thread unsafe catch_warnings (#3124) X-Git-Tag: v6.2.0b1~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba068451c811b48cb3faa0adbc7bce335228b3f5;p=thirdparty%2Ftornado.git avoid thread unsafe catch_warnings (#3124) `with warnings.catch_warnings():` mutates the warnings filters for the whole process and so is unsafe to call from multiple threads --- diff --git a/tornado/ioloop.py b/tornado/ioloop.py index cf5a85c9f..1a8f3c8ed 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -326,6 +326,10 @@ class IOLoop(Configurable): .. deprecated:: 6.2 """ warnings.warn("clear_current is deprecated", DeprecationWarning) + IOLoop._clear_current() + + @staticmethod + def _clear_current() -> None: old = IOLoop.current(instance=False) if old is not None: old._clear_current_hook() diff --git a/tornado/platform/asyncio.py b/tornado/platform/asyncio.py index 231b70696..cc11adc5a 100644 --- a/tornado/platform/asyncio.py +++ b/tornado/platform/asyncio.py @@ -74,6 +74,20 @@ def _atexit_callback() -> None: atexit.register(_atexit_callback) +if sys.version_info >= (3, 10): + + def _get_event_loop() -> asyncio.AbstractEventLoop: + try: + return asyncio.get_running_loop() + except RuntimeError: + pass + + return asyncio.get_event_loop_policy().get_event_loop() + + +else: + from asyncio import get_event_loop as _get_event_loop + class BaseAsyncIOLoop(IOLoop): def initialize( # type: ignore @@ -191,9 +205,7 @@ class BaseAsyncIOLoop(IOLoop): def start(self) -> None: try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - old_loop = asyncio.get_event_loop() + old_loop = _get_event_loop() except (RuntimeError, AssertionError): old_loop = None # type: ignore try: @@ -320,11 +332,7 @@ class AsyncIOLoop(BaseAsyncIOLoop): def close(self, all_fds: bool = False) -> None: if self.is_current: - with warnings.catch_warnings(): - # We can't get here unless the warning in make_current - # was swallowed, so swallow the one from clear_current too. - warnings.simplefilter("ignore", DeprecationWarning) - self.clear_current() + self._clear_current() super().close(all_fds=all_fds) def make_current(self) -> None: diff --git a/tornado/test/asyncio_test.py b/tornado/test/asyncio_test.py index bdb27e829..551a9a8d5 100644 --- a/tornado/test/asyncio_test.py +++ b/tornado/test/asyncio_test.py @@ -129,7 +129,7 @@ class LeakTest(unittest.TestCase): with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) loop = AsyncIOLoop() - loop.close() + loop.close() new_count = len(IOLoop._ioloop_for_asyncio) - orig_count self.assertEqual(new_count, 0)