summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
diff options
context:
space:
mode:
authorYury Selivanov <yselivanov@sprymix.com>2015-05-12 15:43:04 (GMT)
committerYury Selivanov <yselivanov@sprymix.com>2015-05-12 15:43:04 (GMT)
commite8944cb217747ccf32073aa284dc28ffd1f8dd55 (patch)
tree706b5b2022e5a01f45eb2f7ee900e6e5a0e36e9e /Lib/asyncio
parentc2dd680115b38783dbdf5c84cae932558b35c45b (diff)
downloadcpython-e8944cb217747ccf32073aa284dc28ffd1f8dd55.zip
cpython-e8944cb217747ccf32073aa284dc28ffd1f8dd55.tar.gz
cpython-e8944cb217747ccf32073aa284dc28ffd1f8dd55.tar.bz2
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.
Diffstat (limited to 'Lib/asyncio')
-rw-r--r--Lib/asyncio/base_events.py80
1 files changed, 45 insertions, 35 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 38344a7..5a536a2 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -198,6 +198,7 @@ class BaseEventLoop(events.AbstractEventLoop):
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 @@ class BaseEventLoop(events.AbstractEventLoop):
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 @@ class BaseEventLoop(events.AbstractEventLoop):
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 @@ class BaseEventLoop(events.AbstractEventLoop):
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 @@ class BaseEventLoop(events.AbstractEventLoop):
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)