bpo-33672: Fix Task.__repr__ crash with Cython's bogus coroutines (GH-7180)

[3.6 backport of 989b9e0]
This commit is contained in:
Yury Selivanov 2018-05-29 00:55:27 -04:00 committed by GitHub
parent 7593b8a507
commit e151f83dea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 12 deletions

View File

@ -310,18 +310,25 @@ def _format_coroutine(coro):
if coro_name is None: if coro_name is None:
coro_name = events._format_callback(func, (), {}) coro_name = events._format_callback(func, (), {})
try: coro_code = None
coro_code = coro.gi_code if hasattr(coro, 'cr_code') and coro.cr_code:
except AttributeError:
coro_code = coro.cr_code coro_code = coro.cr_code
elif hasattr(coro, 'gi_code') and coro.gi_code:
coro_code = coro.gi_code
try: coro_frame = None
coro_frame = coro.gi_frame if hasattr(coro, 'cr_frame') and coro.cr_frame:
except AttributeError:
coro_frame = coro.cr_frame coro_frame = coro.cr_frame
elif hasattr(coro, 'gi_frame') and coro.gi_frame:
coro_frame = coro.gi_frame
filename = '<empty co_filename>'
if coro_code and coro_code.co_filename:
filename = coro_code.co_filename
filename = coro_code.co_filename
lineno = 0 lineno = 0
coro_repr = coro_name
if (isinstance(coro, CoroWrapper) and if (isinstance(coro, CoroWrapper) and
not inspect.isgeneratorfunction(coro.func) and not inspect.isgeneratorfunction(coro.func) and
coro.func is not None): coro.func is not None):
@ -338,7 +345,7 @@ def _format_coroutine(coro):
lineno = coro_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: elif coro_code:
lineno = coro_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))

View File

@ -58,10 +58,10 @@ def _format_callback(func, args, kwargs, suffix=''):
suffix = _format_args_and_kwargs(args, kwargs) + suffix suffix = _format_args_and_kwargs(args, kwargs) + suffix
return _format_callback(func.func, func.args, func.keywords, suffix) return _format_callback(func.func, func.args, func.keywords, suffix)
if hasattr(func, '__qualname__'): if hasattr(func, '__qualname__') and func.__qualname__:
func_repr = getattr(func, '__qualname__') func_repr = func.__qualname__
elif hasattr(func, '__name__'): elif hasattr(func, '__name__') and func.__name__:
func_repr = getattr(func, '__name__') func_repr = func.__name__
else: else:
func_repr = repr(func) func_repr = repr(func)

View File

@ -2467,6 +2467,28 @@ class HandleTests(test_utils.TestCase):
# built-in async_gen.asend(). # built-in async_gen.asend().
self.assertEqual(coroutines._format_coroutine(coro), 'Coro()') self.assertEqual(coroutines._format_coroutine(coro), 'Coro()')
coro = Coro()
coro.__qualname__ = 'AAA'
coro.cr_code = None
self.assertEqual(coroutines._format_coroutine(coro), 'AAA()')
coro = Coro()
coro.__qualname__ = 'AAA'
coro.cr_code = None
coro.cr_frame = None
self.assertEqual(coroutines._format_coroutine(coro), 'AAA()')
coro = Coro()
coro.__qualname__ = None
coro.cr_code = None
coro.cr_frame = None
self.assertEqual(coroutines._format_coroutine(coro), f'{repr(coro)}()')
coro = Coro()
coro.cr_code = None
coro.cr_frame = None
self.assertEqual(coroutines._format_coroutine(coro), f'{repr(coro)}()')
class TimerTests(unittest.TestCase): class TimerTests(unittest.TestCase):

View File

@ -0,0 +1 @@
Fix Task.__repr__ crash with Cython's bogus coroutines