diff options
author | Nathaniel J. Smith <njs@pobox.com> | 2018-01-21 14:44:07 (GMT) |
---|---|---|
committer | Yury Selivanov <yury@magic.io> | 2018-01-21 14:44:07 (GMT) |
commit | fc2f407829d9817ddacccae6944dd0879cfaca24 (patch) | |
tree | 1775a28a8181975363798f9b3e7cb2bb100e49a2 /Lib/asyncio | |
parent | 1211c9a9897a174b7261ca258cabf289815a40d8 (diff) | |
download | cpython-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.py | 49 | ||||
-rw-r--r-- | Lib/asyncio/coroutines.py | 33 |
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): |