[Python-checkins] cpython (3.4): asyncio: Make sure sys.set_coroutine_wrapper is called *only* when loop is

yury.selivanov python-checkins at python.org
Tue May 12 17:45:56 CEST 2015


https://hg.python.org/cpython/rev/ee7d2c9c70ab
changeset:   95985:ee7d2c9c70ab
branch:      3.4
parent:      95981:e656bece13fa
user:        Yury Selivanov <yselivanov at sprymix.com>
date:        Tue May 12 11:43:04 2015 -0400
summary:
  asyncio: Make sure sys.set_coroutine_wrapper is called *only* when loop is running.

Previous approach of installing coroutine wrapper in loop.set_debug() and
uninstalling it in loop.close() was very fragile.  Most of asyncio tests
do not call loop.close() at all.  Since coroutine wrapper is a global
setting, we have to make sure that it's only set when the loop is
running, and is automatically unset when it stops running.

Issue #24017.

files:
  Lib/asyncio/base_events.py |  80 ++++++++++++++-----------
  1 files changed, 45 insertions(+), 35 deletions(-)


diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -198,6 +198,7 @@
         self.slow_callback_duration = 0.1
         self._current_handle = None
         self._task_factory = None
+        self._coroutine_wrapper_set = False
 
     def __repr__(self):
         return ('<%s running=%s closed=%s debug=%s>'
@@ -291,6 +292,7 @@
         self._check_closed()
         if self.is_running():
             raise RuntimeError('Event loop is running.')
+        self._set_coroutine_wrapper(self._debug)
         self._thread_id = threading.get_ident()
         try:
             while True:
@@ -300,6 +302,7 @@
                     break
         finally:
             self._thread_id = None
+            self._set_coroutine_wrapper(False)
 
     def run_until_complete(self, future):
         """Run until the Future is done.
@@ -360,18 +363,13 @@
             return
         if self._debug:
             logger.debug("Close %r", self)
-        try:
-            self._closed = True
-            self._ready.clear()
-            self._scheduled.clear()
-            executor = self._default_executor
-            if executor is not None:
-                self._default_executor = None
-                executor.shutdown(wait=False)
-        finally:
-            # It is important to unregister "sys.coroutine_wrapper"
-            # if it was registered.
-            self.set_debug(False)
+        self._closed = True
+        self._ready.clear()
+        self._scheduled.clear()
+        executor = self._default_executor
+        if executor is not None:
+            self._default_executor = None
+            executor.shutdown(wait=False)
 
     def is_closed(self):
         """Returns True if the event loop was closed."""
@@ -1199,32 +1197,44 @@
                 handle._run()
         handle = None  # Needed to break cycles when an exception occurs.
 
+    def _set_coroutine_wrapper(self, enabled):
+        try:
+            set_wrapper = sys.set_coroutine_wrapper
+            get_wrapper = sys.get_coroutine_wrapper
+        except AttributeError:
+            return
+
+        enabled = bool(enabled)
+        if self._coroutine_wrapper_set is enabled:
+            return
+
+        wrapper = coroutines.debug_wrapper
+        current_wrapper = get_wrapper()
+
+        if enabled:
+            if current_wrapper not in (None, wrapper):
+                warnings.warn(
+                    "loop.set_debug(True): cannot set debug coroutine "
+                    "wrapper; another wrapper is already set %r" %
+                    current_wrapper, RuntimeWarning)
+            else:
+                set_wrapper(wrapper)
+                self._coroutine_wrapper_set = True
+        else:
+            if current_wrapper not in (None, wrapper):
+                warnings.warn(
+                    "loop.set_debug(False): cannot unset debug coroutine "
+                    "wrapper; another wrapper was set %r" %
+                    current_wrapper, RuntimeWarning)
+            else:
+                set_wrapper(None)
+                self._coroutine_wrapper_set = False
+
     def get_debug(self):
         return self._debug
 
     def set_debug(self, enabled):
         self._debug = enabled
-        wrapper = coroutines.debug_wrapper
 
-        try:
-            set_wrapper = sys.set_coroutine_wrapper
-        except AttributeError:
-            pass
-        else:
-            current_wrapper = sys.get_coroutine_wrapper()
-            if enabled:
-                if current_wrapper not in (None, wrapper):
-                    warnings.warn(
-                        "loop.set_debug(True): cannot set debug coroutine "
-                        "wrapper; another wrapper is already set %r" %
-                        current_wrapper, RuntimeWarning)
-                else:
-                    set_wrapper(wrapper)
-            else:
-                if current_wrapper not in (None, wrapper):
-                    warnings.warn(
-                        "loop.set_debug(False): cannot unset debug coroutine "
-                        "wrapper; another wrapper was set %r" %
-                        current_wrapper, RuntimeWarning)
-                else:
-                    set_wrapper(None)
+        if self.is_running():
+            self._set_coroutine_wrapper(enabled)

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list