Commit 8f1c9932 authored by Yury Selivanov's avatar Yury Selivanov

Issue #24400: Fix CoroWrapper for 'async def' coroutines

parents 3bdbcedf 29a602a1
...@@ -103,9 +103,6 @@ class CoroWrapper: ...@@ -103,9 +103,6 @@ class CoroWrapper:
def __iter__(self): def __iter__(self):
return self return self
if _PY35:
__await__ = __iter__ # make compatible with 'await' expression
def __next__(self): def __next__(self):
return self.gen.send(None) return self.gen.send(None)
...@@ -143,10 +140,28 @@ class CoroWrapper: ...@@ -143,10 +140,28 @@ class CoroWrapper:
def gi_code(self): def gi_code(self):
return self.gen.gi_code return self.gen.gi_code
if _PY35:
__await__ = __iter__ # make compatible with 'await' expression
@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): def __del__(self):
# Be careful accessing self.gen.frame -- self.gen might not exist. # Be careful accessing self.gen.frame -- self.gen might not exist.
gen = getattr(self, 'gen', None) gen = getattr(self, 'gen', None)
frame = getattr(gen, 'gi_frame', 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: if frame is not None and frame.f_lasti == -1:
msg = '%r was never yielded from' % self msg = '%r was never yielded from' % self
tb = getattr(self, '_source_traceback', ()) tb = getattr(self, '_source_traceback', ())
...@@ -233,28 +248,43 @@ def iscoroutine(obj): ...@@ -233,28 +248,43 @@ def iscoroutine(obj):
def _format_coroutine(coro): def _format_coroutine(coro):
assert iscoroutine(coro) assert iscoroutine(coro)
coro_name = None
if isinstance(coro, CoroWrapper): if isinstance(coro, CoroWrapper):
func = coro.func func = coro.func
coro_name = coro.__qualname__
else: else:
func = coro func = coro
coro_name = events._format_callback(func, ())
filename = coro.gi_code.co_filename if coro_name is None:
coro_name = events._format_callback(func, ())
try:
coro_code = coro.gi_code
except AttributeError:
coro_code = coro.cr_code
try:
coro_frame = coro.gi_frame
except AttributeError:
coro_frame = coro.cr_frame
filename = coro_code.co_filename
if (isinstance(coro, CoroWrapper) if (isinstance(coro, CoroWrapper)
and not inspect.isgeneratorfunction(coro.func)): and not inspect.isgeneratorfunction(coro.func)
and coro.func is not None):
filename, lineno = events._get_function_source(coro.func) filename, lineno = events._get_function_source(coro.func)
if coro.gi_frame is None: if coro_frame is None:
coro_repr = ('%s done, defined at %s:%s' coro_repr = ('%s done, defined at %s:%s'
% (coro_name, filename, lineno)) % (coro_name, filename, lineno))
else: else:
coro_repr = ('%s running, defined at %s:%s' coro_repr = ('%s running, defined at %s:%s'
% (coro_name, filename, lineno)) % (coro_name, filename, lineno))
elif coro.gi_frame is not None: elif coro_frame is not None:
lineno = coro.gi_frame.f_lineno lineno = coro_frame.f_lineno
coro_repr = ('%s running at %s:%s' coro_repr = ('%s running at %s:%s'
% (coro_name, filename, lineno)) % (coro_name, filename, lineno))
else: else:
lineno = coro.gi_code.co_firstlineno lineno = coro_code.co_firstlineno
coro_repr = ('%s done, defined at %s:%s' coro_repr = ('%s done, defined at %s:%s'
% (coro_name, filename, lineno)) % (coro_name, filename, lineno))
......
...@@ -119,7 +119,7 @@ class CoroutineTests(BaseTest): ...@@ -119,7 +119,7 @@ class CoroutineTests(BaseTest):
self.assertEqual(coro.send(None), 'spam') self.assertEqual(coro.send(None), 'spam')
coro.close() coro.close()
def test_async_ded_coroutines(self): def test_async_def_coroutines(self):
async def bar(): async def bar():
return 'spam' return 'spam'
async def foo(): async def foo():
...@@ -134,5 +134,28 @@ class CoroutineTests(BaseTest): ...@@ -134,5 +134,28 @@ class CoroutineTests(BaseTest):
data = self.loop.run_until_complete(foo()) data = self.loop.run_until_complete(foo())
self.assertEqual(data, 'spam') self.assertEqual(data, 'spam')
@mock.patch('asyncio.coroutines.logger')
def test_async_def_wrapped(self, m_log):
async def foo():
pass
async def start():
foo_coro = foo()
self.assertRegex(
repr(foo_coro),
r'<CoroWrapper .*\.foo running at .*pep492.*>')
with support.check_warnings((r'.*foo.*was never',
RuntimeWarning)):
foo_coro = None
support.gc_collect()
self.assertTrue(m_log.error.called)
message = m_log.error.call_args[0][0]
self.assertRegex(message,
r'CoroWrapper.*foo.*was never')
self.loop.set_debug(True)
self.loop.run_until_complete(start())
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -1715,7 +1715,8 @@ class TaskTests(test_utils.TestCase): ...@@ -1715,7 +1715,8 @@ class TaskTests(test_utils.TestCase):
self.assertTrue(m_log.error.called) self.assertTrue(m_log.error.called)
message = m_log.error.call_args[0][0] message = m_log.error.call_args[0][0]
func_filename, func_lineno = test_utils.get_function_source(coro_noop) func_filename, func_lineno = test_utils.get_function_source(coro_noop)
regex = (r'^<CoroWrapper %s\(\) .* at %s:%s, .*> '
regex = (r'^<CoroWrapper %s\(?\)? .* at %s:%s, .*> '
r'was never yielded from\n' r'was never yielded from\n'
r'Coroutine object created at \(most recent call last\):\n' r'Coroutine object created at \(most recent call last\):\n'
r'.*\n' r'.*\n'
......
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