summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
diff options
context:
space:
mode:
authorNathaniel J. Smith <njs@pobox.com>2018-01-21 14:44:07 (GMT)
committerYury Selivanov <yury@magic.io>2018-01-21 14:44:07 (GMT)
commitfc2f407829d9817ddacccae6944dd0879cfaca24 (patch)
tree1775a28a8181975363798f9b3e7cb2bb100e49a2 /Lib/asyncio
parent1211c9a9897a174b7261ca258cabf289815a40d8 (diff)
downloadcpython-fc2f407829d9817ddacccae6944dd0879cfaca24.zip
cpython-fc2f407829d9817ddacccae6944dd0879cfaca24.tar.gz
cpython-fc2f407829d9817ddacccae6944dd0879cfaca24.tar.bz2
bpo-32591: Add native coroutine origin tracking (#5250)
* Add coro.cr_origin and sys.set_coroutine_origin_tracking_depth * Use coroutine origin information in the unawaited coroutine warning * Stop using set_coroutine_wrapper in asyncio debug mode * In BaseEventLoop.set_debug, enable debugging in the correct thread
Diffstat (limited to 'Lib/asyncio')
-rw-r--r--Lib/asyncio/base_events.py49
-rw-r--r--Lib/asyncio/coroutines.py33
2 files changed, 16 insertions, 66 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 00c84a8..a10e706 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -34,6 +34,7 @@ try:
except ImportError: # pragma: no cover
ssl = None
+from . import constants
from . import coroutines
from . import events
from . import futures
@@ -224,7 +225,8 @@ class BaseEventLoop(events.AbstractEventLoop):
self.slow_callback_duration = 0.1
self._current_handle = None
self._task_factory = None
- self._coroutine_wrapper_set = False
+ self._coroutine_origin_tracking_enabled = False
+ self._coroutine_origin_tracking_saved_depth = None
if hasattr(sys, 'get_asyncgen_hooks'):
# Python >= 3.6
@@ -382,7 +384,7 @@ class BaseEventLoop(events.AbstractEventLoop):
if events._get_running_loop() is not None:
raise RuntimeError(
'Cannot run the event loop while another loop is running')
- self._set_coroutine_wrapper(self._debug)
+ self._set_coroutine_origin_tracking(self._debug)
self._thread_id = threading.get_ident()
if self._asyncgens is not None:
old_agen_hooks = sys.get_asyncgen_hooks()
@@ -398,7 +400,7 @@ class BaseEventLoop(events.AbstractEventLoop):
self._stopping = False
self._thread_id = None
events._set_running_loop(None)
- self._set_coroutine_wrapper(False)
+ self._set_coroutine_origin_tracking(False)
if self._asyncgens is not None:
sys.set_asyncgen_hooks(*old_agen_hooks)
@@ -1531,39 +1533,20 @@ 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 == enabled:
+ def _set_coroutine_origin_tracking(self, enabled):
+ if bool(enabled) == bool(self._coroutine_origin_tracking_enabled):
return
- wrapper = coroutines.debug_wrapper
- current_wrapper = get_wrapper()
-
if enabled:
- if current_wrapper not in (None, wrapper):
- warnings.warn(
- f"loop.set_debug(True): cannot set debug coroutine "
- f"wrapper; another wrapper is already set "
- f"{current_wrapper!r}",
- RuntimeWarning)
- else:
- set_wrapper(wrapper)
- self._coroutine_wrapper_set = True
+ self._coroutine_origin_tracking_saved_depth = (
+ sys.get_coroutine_origin_tracking_depth())
+ sys.set_coroutine_origin_tracking_depth(
+ constants.DEBUG_STACK_DEPTH)
else:
- if current_wrapper not in (None, wrapper):
- warnings.warn(
- f"loop.set_debug(False): cannot unset debug coroutine "
- f"wrapper; another wrapper was set {current_wrapper!r}",
- RuntimeWarning)
- else:
- set_wrapper(None)
- self._coroutine_wrapper_set = False
+ sys.set_coroutine_origin_tracking_depth(
+ self._coroutine_origin_tracking_saved_depth)
+
+ self._coroutine_origin_tracking_enabled = enabled
def get_debug(self):
return self._debug
@@ -1572,4 +1555,4 @@ class BaseEventLoop(events.AbstractEventLoop):
self._debug = enabled
if self.is_running():
- self._set_coroutine_wrapper(enabled)
+ self.call_soon_threadsafe(self._set_coroutine_origin_tracking, enabled)
diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
index 9c860a4..5a29100 100644
--- a/Lib/asyncio/coroutines.py
+++ b/Lib/asyncio/coroutines.py
@@ -32,14 +32,6 @@ def _is_debug_mode():
_DEBUG = _is_debug_mode()
-def debug_wrapper(gen):
- # This function is called from 'sys.set_coroutine_wrapper'.
- # We only wrap here coroutines defined via 'async def' syntax.
- # Generator-based coroutines are wrapped in @coroutine
- # decorator.
- return CoroWrapper(gen, None)
-
-
class CoroWrapper:
# Wrapper for coroutine object in _DEBUG mode.
@@ -87,39 +79,16 @@ class CoroWrapper:
return self.gen.gi_code
def __await__(self):
- cr_await = getattr(self.gen, 'cr_await', None)
- if cr_await is not None:
- raise RuntimeError(
- f"Cannot await on coroutine {self.gen!r} while it's "
- f"awaiting for {cr_await!r}")
return self
@property
def gi_yieldfrom(self):
return self.gen.gi_yieldfrom
- @property
- def cr_await(self):
- return self.gen.cr_await
-
- @property
- def cr_running(self):
- return self.gen.cr_running
-
- @property
- def cr_code(self):
- return self.gen.cr_code
-
- @property
- def cr_frame(self):
- return self.gen.cr_frame
-
def __del__(self):
# Be careful accessing self.gen.frame -- self.gen might not exist.
gen = getattr(self, 'gen', None)
frame = getattr(gen, 'gi_frame', None)
- if frame is None:
- frame = getattr(gen, 'cr_frame', None)
if frame is not None and frame.f_lasti == -1:
msg = f'{self!r} was never yielded from'
tb = getattr(self, '_source_traceback', ())
@@ -141,8 +110,6 @@ def coroutine(func):
if inspect.iscoroutinefunction(func):
# In Python 3.5 that's all we need to do for coroutines
# defined with "async def".
- # Wrapping in CoroWrapper will happen via
- # 'sys.set_coroutine_wrapper' function.
return func
if inspect.isgeneratorfunction(func):