Commit e8944cb2 authored by Yury Selivanov's avatar Yury Selivanov

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.
parent c2dd6801
...@@ -198,6 +198,7 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -198,6 +198,7 @@ class BaseEventLoop(events.AbstractEventLoop):
self.slow_callback_duration = 0.1 self.slow_callback_duration = 0.1
self._current_handle = None self._current_handle = None
self._task_factory = None self._task_factory = None
self._coroutine_wrapper_set = False
def __repr__(self): def __repr__(self):
return ('<%s running=%s closed=%s debug=%s>' return ('<%s running=%s closed=%s debug=%s>'
...@@ -291,6 +292,7 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -291,6 +292,7 @@ class BaseEventLoop(events.AbstractEventLoop):
self._check_closed() self._check_closed()
if self.is_running(): if self.is_running():
raise RuntimeError('Event loop is running.') raise RuntimeError('Event loop is running.')
self._set_coroutine_wrapper(self._debug)
self._thread_id = threading.get_ident() self._thread_id = threading.get_ident()
try: try:
while True: while True:
...@@ -300,6 +302,7 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -300,6 +302,7 @@ class BaseEventLoop(events.AbstractEventLoop):
break break
finally: finally:
self._thread_id = None self._thread_id = None
self._set_coroutine_wrapper(False)
def run_until_complete(self, future): def run_until_complete(self, future):
"""Run until the Future is done. """Run until the Future is done.
...@@ -360,7 +363,6 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -360,7 +363,6 @@ class BaseEventLoop(events.AbstractEventLoop):
return return
if self._debug: if self._debug:
logger.debug("Close %r", self) logger.debug("Close %r", self)
try:
self._closed = True self._closed = True
self._ready.clear() self._ready.clear()
self._scheduled.clear() self._scheduled.clear()
...@@ -368,10 +370,6 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -368,10 +370,6 @@ class BaseEventLoop(events.AbstractEventLoop):
if executor is not None: if executor is not None:
self._default_executor = None self._default_executor = None
executor.shutdown(wait=False) executor.shutdown(wait=False)
finally:
# It is important to unregister "sys.coroutine_wrapper"
# if it was registered.
self.set_debug(False)
def is_closed(self): def is_closed(self):
"""Returns True if the event loop was closed.""" """Returns True if the event loop was closed."""
...@@ -1199,19 +1197,20 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -1199,19 +1197,20 @@ class BaseEventLoop(events.AbstractEventLoop):
handle._run() handle._run()
handle = None # Needed to break cycles when an exception occurs. handle = None # Needed to break cycles when an exception occurs.
def get_debug(self): def _set_coroutine_wrapper(self, enabled):
return self._debug
def set_debug(self, enabled):
self._debug = enabled
wrapper = coroutines.debug_wrapper
try: try:
set_wrapper = sys.set_coroutine_wrapper set_wrapper = sys.set_coroutine_wrapper
get_wrapper = sys.get_coroutine_wrapper
except AttributeError: except AttributeError:
pass return
else:
current_wrapper = sys.get_coroutine_wrapper() enabled = bool(enabled)
if self._coroutine_wrapper_set is enabled:
return
wrapper = coroutines.debug_wrapper
current_wrapper = get_wrapper()
if enabled: if enabled:
if current_wrapper not in (None, wrapper): if current_wrapper not in (None, wrapper):
warnings.warn( warnings.warn(
...@@ -1220,6 +1219,7 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -1220,6 +1219,7 @@ class BaseEventLoop(events.AbstractEventLoop):
current_wrapper, RuntimeWarning) current_wrapper, RuntimeWarning)
else: else:
set_wrapper(wrapper) set_wrapper(wrapper)
self._coroutine_wrapper_set = True
else: else:
if current_wrapper not in (None, wrapper): if current_wrapper not in (None, wrapper):
warnings.warn( warnings.warn(
...@@ -1228,3 +1228,13 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -1228,3 +1228,13 @@ class BaseEventLoop(events.AbstractEventLoop):
current_wrapper, RuntimeWarning) current_wrapper, RuntimeWarning)
else: else:
set_wrapper(None) set_wrapper(None)
self._coroutine_wrapper_set = False
def get_debug(self):
return self._debug
def set_debug(self, enabled):
self._debug = enabled
if self.is_running():
self._set_coroutine_wrapper(enabled)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment