From e151f83deab9819fb8d9dfc59f9baa4a7273226c Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 29 May 2018 00:55:27 -0400 Subject: [PATCH] bpo-33672: Fix Task.__repr__ crash with Cython's bogus coroutines (GH-7180) [3.6 backport of 989b9e0] --- Lib/asyncio/coroutines.py | 23 ++++++++++++------- Lib/asyncio/events.py | 8 +++---- Lib/test/test_asyncio/test_events.py | 22 ++++++++++++++++++ .../2018-05-28-17-45-06.bpo-33672.GM_Xm_.rst | 1 + 4 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-05-28-17-45-06.bpo-33672.GM_Xm_.rst diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index 520a309f846..a9022f92a52 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -310,18 +310,25 @@ def _format_coroutine(coro): if coro_name is None: coro_name = events._format_callback(func, (), {}) - try: - coro_code = coro.gi_code - except AttributeError: + coro_code = None + if hasattr(coro, 'cr_code') and 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 = coro.gi_frame - except AttributeError: + coro_frame = None + if hasattr(coro, 'cr_frame') and coro.cr_frame: coro_frame = coro.cr_frame + elif hasattr(coro, 'gi_frame') and coro.gi_frame: + coro_frame = coro.gi_frame + + filename = '' + if coro_code and coro_code.co_filename: + filename = coro_code.co_filename - filename = coro_code.co_filename lineno = 0 + coro_repr = coro_name + if (isinstance(coro, CoroWrapper) and not inspect.isgeneratorfunction(coro.func) and coro.func is not None): @@ -338,7 +345,7 @@ def _format_coroutine(coro): lineno = coro_frame.f_lineno coro_repr = ('%s running at %s:%s' % (coro_name, filename, lineno)) - else: + elif coro_code: lineno = coro_code.co_firstlineno coro_repr = ('%s done, defined at %s:%s' % (coro_name, filename, lineno)) diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index 05dc8969f44..e654efc5526 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -58,10 +58,10 @@ def _format_callback(func, args, kwargs, suffix=''): suffix = _format_args_and_kwargs(args, kwargs) + suffix return _format_callback(func.func, func.args, func.keywords, suffix) - if hasattr(func, '__qualname__'): - func_repr = getattr(func, '__qualname__') - elif hasattr(func, '__name__'): - func_repr = getattr(func, '__name__') + if hasattr(func, '__qualname__') and func.__qualname__: + func_repr = func.__qualname__ + elif hasattr(func, '__name__') and func.__name__: + func_repr = func.__name__ else: func_repr = repr(func) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 1ecc89f2e75..548a4610f77 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -2467,6 +2467,28 @@ class HandleTests(test_utils.TestCase): # built-in async_gen.asend(). 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): diff --git a/Misc/NEWS.d/next/Library/2018-05-28-17-45-06.bpo-33672.GM_Xm_.rst b/Misc/NEWS.d/next/Library/2018-05-28-17-45-06.bpo-33672.GM_Xm_.rst new file mode 100644 index 00000000000..36373c02863 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-05-28-17-45-06.bpo-33672.GM_Xm_.rst @@ -0,0 +1 @@ +Fix Task.__repr__ crash with Cython's bogus coroutines