]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
avoid thread unsafe catch_warnings (#3124)
authorThomas Grainger <tagrain@gmail.com>
Fri, 18 Mar 2022 18:53:37 +0000 (18:53 +0000)
committerGitHub <noreply@github.com>
Fri, 18 Mar 2022 18:53:37 +0000 (14:53 -0400)
`with warnings.catch_warnings():` mutates the warnings filters for the
whole process and so is unsafe to call from multiple threads

tornado/ioloop.py
tornado/platform/asyncio.py
tornado/test/asyncio_test.py

index cf5a85c9f2a28968844e1bad97660f774fbda20b..1a8f3c8ed835929c9c941dfacb5e8a03f7685283 100644 (file)
@@ -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()
index 231b70696e8f5fc40bb3a0634f2410cdc4c01e0f..cc11adc5aaf929b561c84703e07ef03be30aa31c 100644 (file)
@@ -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:
index bdb27e8293137db012189998c786ebec990258f1..551a9a8d5a299d11f1e64f6c59b81cafbfb7b207 100644 (file)
@@ -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)