(Merge 3.4) asyncio, Tulip issue 137: In debug mode, add the traceback where
the coroutine object was created to the "coroutine ... was never yield from" log
This commit is contained in:
parent
19b011109d
commit
fe4a979099
|
@ -43,6 +43,7 @@ class CoroWrapper:
|
|||
assert inspect.isgenerator(gen), gen
|
||||
self.gen = gen
|
||||
self.func = func
|
||||
self._source_traceback = traceback.extract_stack(sys._getframe(1))
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
@ -81,13 +82,13 @@ class CoroWrapper:
|
|||
gen = getattr(self, 'gen', None)
|
||||
frame = getattr(gen, 'gi_frame', None)
|
||||
if frame is not None and frame.f_lasti == -1:
|
||||
func = self.func
|
||||
code = func.__code__
|
||||
filename = code.co_filename
|
||||
lineno = code.co_firstlineno
|
||||
logger.error(
|
||||
'Coroutine %r defined at %s:%s was never yielded from',
|
||||
func.__name__, filename, lineno)
|
||||
func = events._format_callback(self.func, ())
|
||||
tb = ''.join(traceback.format_list(self._source_traceback))
|
||||
message = ('Coroutine %s was never yielded from\n'
|
||||
'Coroutine object created at (most recent call last):\n'
|
||||
'%s'
|
||||
% (func, tb.rstrip()))
|
||||
logger.error(message)
|
||||
|
||||
|
||||
def coroutine(func):
|
||||
|
@ -112,6 +113,8 @@ def coroutine(func):
|
|||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwds):
|
||||
w = CoroWrapper(coro(*args, **kwds), func)
|
||||
if w._source_traceback:
|
||||
del w._source_traceback[-1]
|
||||
w.__name__ = func.__name__
|
||||
if _PY35:
|
||||
w.__qualname__ = func.__qualname__
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""Tests for tasks.py."""
|
||||
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
import types
|
||||
import unittest
|
||||
|
@ -1572,6 +1573,37 @@ class TaskTests(test_utils.TestCase):
|
|||
})
|
||||
mock_handler.reset_mock()
|
||||
|
||||
@mock.patch('asyncio.tasks.logger')
|
||||
def test_coroutine_never_yielded(self, m_log):
|
||||
debug = asyncio.tasks._DEBUG
|
||||
try:
|
||||
asyncio.tasks._DEBUG = True
|
||||
@asyncio.coroutine
|
||||
def coro_noop():
|
||||
pass
|
||||
finally:
|
||||
asyncio.tasks._DEBUG = debug
|
||||
|
||||
tb_filename = __file__
|
||||
tb_lineno = sys._getframe().f_lineno + 1
|
||||
coro = coro_noop()
|
||||
coro = None
|
||||
support.gc_collect()
|
||||
|
||||
self.assertTrue(m_log.error.called)
|
||||
message = m_log.error.call_args[0][0]
|
||||
func_filename, func_lineno = test_utils.get_function_source(coro_noop)
|
||||
regex = (r'^Coroutine %s\(\) at %s:%s was never yielded from\n'
|
||||
r'Coroutine object created at \(most recent call last\):\n'
|
||||
r'.*\n'
|
||||
r' File "%s", line %s, in test_coroutine_never_yielded\n'
|
||||
r' coro = coro_noop\(\)$'
|
||||
% (re.escape(coro_noop.__qualname__),
|
||||
func_filename, func_lineno,
|
||||
tb_filename, tb_lineno))
|
||||
|
||||
self.assertRegex(message, re.compile(regex, re.DOTALL))
|
||||
|
||||
|
||||
class GatherTestsBase:
|
||||
|
||||
|
|
Loading…
Reference in New Issue