Skip to content

Commit 08a7a4e

Browse files
committed
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 python#24017.
2 parents baa2e56 + e8944cb commit 08a7a4e

File tree

1 file changed

+45
-35
lines changed

1 file changed

+45
-35
lines changed

Lib/asyncio/base_events.py

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ def __init__(self):
198198
self.slow_callback_duration = 0.1
199199
self._current_handle = None
200200
self._task_factory = None
201+
self._coroutine_wrapper_set = False
201202

202203
def __repr__(self):
203204
return ('<%s running=%s closed=%s debug=%s>'
@@ -291,6 +292,7 @@ def run_forever(self):
291292
self._check_closed()
292293
if self.is_running():
293294
raise RuntimeError('Event loop is running.')
295+
self._set_coroutine_wrapper(self._debug)
294296
self._thread_id = threading.get_ident()
295297
try:
296298
while True:
@@ -300,6 +302,7 @@ def run_forever(self):
300302
break
301303
finally:
302304
self._thread_id = None
305+
self._set_coroutine_wrapper(False)
303306

304307
def run_until_complete(self, future):
305308
"""Run until the Future is done.
@@ -360,18 +363,13 @@ def close(self):
360363
return
361364
if self._debug:
362365
logger.debug("Close %r", self)
363-
try:
364-
self._closed = True
365-
self._ready.clear()
366-
self._scheduled.clear()
367-
executor = self._default_executor
368-
if executor is not None:
369-
self._default_executor = None
370-
executor.shutdown(wait=False)
371-
finally:
372-
# It is important to unregister "sys.coroutine_wrapper"
373-
# if it was registered.
374-
self.set_debug(False)
366+
self._closed = True
367+
self._ready.clear()
368+
self._scheduled.clear()
369+
executor = self._default_executor
370+
if executor is not None:
371+
self._default_executor = None
372+
executor.shutdown(wait=False)
375373

376374
def is_closed(self):
377375
"""Returns True if the event loop was closed."""
@@ -1199,32 +1197,44 @@ def _run_once(self):
11991197
handle._run()
12001198
handle = None # Needed to break cycles when an exception occurs.
12011199

1200+
def _set_coroutine_wrapper(self, enabled):
1201+
try:
1202+
set_wrapper = sys.set_coroutine_wrapper
1203+
get_wrapper = sys.get_coroutine_wrapper
1204+
except AttributeError:
1205+
return
1206+
1207+
enabled = bool(enabled)
1208+
if self._coroutine_wrapper_set is enabled:
1209+
return
1210+
1211+
wrapper = coroutines.debug_wrapper
1212+
current_wrapper = get_wrapper()
1213+
1214+
if enabled:
1215+
if current_wrapper not in (None, wrapper):
1216+
warnings.warn(
1217+
"loop.set_debug(True): cannot set debug coroutine "
1218+
"wrapper; another wrapper is already set %r" %
1219+
current_wrapper, RuntimeWarning)
1220+
else:
1221+
set_wrapper(wrapper)
1222+
self._coroutine_wrapper_set = True
1223+
else:
1224+
if current_wrapper not in (None, wrapper):
1225+
warnings.warn(
1226+
"loop.set_debug(False): cannot unset debug coroutine "
1227+
"wrapper; another wrapper was set %r" %
1228+
current_wrapper, RuntimeWarning)
1229+
else:
1230+
set_wrapper(None)
1231+
self._coroutine_wrapper_set = False
1232+
12021233
def get_debug(self):
12031234
return self._debug
12041235

12051236
def set_debug(self, enabled):
12061237
self._debug = enabled
1207-
wrapper = coroutines.debug_wrapper
12081238

1209-
try:
1210-
set_wrapper = sys.set_coroutine_wrapper
1211-
except AttributeError:
1212-
pass
1213-
else:
1214-
current_wrapper = sys.get_coroutine_wrapper()
1215-
if enabled:
1216-
if current_wrapper not in (None, wrapper):
1217-
warnings.warn(
1218-
"loop.set_debug(True): cannot set debug coroutine "
1219-
"wrapper; another wrapper is already set %r" %
1220-
current_wrapper, RuntimeWarning)
1221-
else:
1222-
set_wrapper(wrapper)
1223-
else:
1224-
if current_wrapper not in (None, wrapper):
1225-
warnings.warn(
1226-
"loop.set_debug(False): cannot unset debug coroutine "
1227-
"wrapper; another wrapper was set %r" %
1228-
current_wrapper, RuntimeWarning)
1229-
else:
1230-
set_wrapper(None)
1239+
if self.is_running():
1240+
self._set_coroutine_wrapper(enabled)

0 commit comments

Comments
 (0)