diff options
| -rw-r--r-- | Lib/asyncio/base_events.py | 5 | ||||
| -rw-r--r-- | Lib/asyncio/coroutines.py | 24 | ||||
| -rw-r--r-- | Lib/asyncio/tasks.py | 7 | ||||
| -rw-r--r-- | Lib/test/test_asyncio/test_tasks.py | 49 | 
4 files changed, 70 insertions, 15 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 833f81d4a9..f6d7a58f5e 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -155,7 +155,10 @@ class BaseEventLoop(events.AbstractEventLoop):          """Schedule a coroutine object.          Return a task object.""" -        return tasks.Task(coro, loop=self) +        task = tasks.Task(coro, loop=self) +        if task._source_traceback: +            del task._source_traceback[-1] +        return task      def _make_socket_transport(self, sock, protocol, waiter=None, *,                                 extra=None, server=None): diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index 48730c225a..4cbfa854ef 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -57,7 +57,7 @@ del has_yield_from_bug  class CoroWrapper: -    # Wrapper for coroutine in _DEBUG mode. +    # Wrapper for coroutine object in _DEBUG mode.      def __init__(self, gen, func):          assert inspect.isgenerator(gen), gen @@ -68,8 +68,11 @@ class CoroWrapper:          # decorator      def __repr__(self): -        return ('<%s %s>' -                % (self.__class__.__name__, _format_coroutine(self))) +        coro_repr = _format_coroutine(self) +        if self._source_traceback: +            frame = self._source_traceback[-1] +            coro_repr += ', created at %s:%s' % (frame[0], frame[1]) +        return '<%s %s>' % (self.__class__.__name__, coro_repr)      def __iter__(self):          return self @@ -181,9 +184,18 @@ def _format_coroutine(coro):          coro_name = coro.__name__      filename = coro.gi_code.co_filename -    if coro.gi_frame is not None: +    if (isinstance(coro, CoroWrapper) +    and not inspect.isgeneratorfunction(coro.func)): +        filename, lineno = events._get_function_source(coro.func) +        if coro.gi_frame is None: +            coro_repr = '%s() done, defined at %s:%s' % (coro_name, filename, lineno) +        else: +            coro_repr = '%s() running, defined at %s:%s' % (coro_name, filename, lineno) +    elif coro.gi_frame is not None:          lineno = coro.gi_frame.f_lineno -        return '%s() at %s:%s' % (coro_name, filename, lineno) +        coro_repr = '%s() running at %s:%s' % (coro_name, filename, lineno)      else:          lineno = coro.gi_code.co_firstlineno -        return '%s() done at %s:%s' % (coro_name, filename, lineno) +        coro_repr = '%s() done, defined at %s:%s' % (coro_name, filename, lineno) + +    return coro_repr diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index befc2967c7..61f48223ca 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -101,7 +101,12 @@ class Task(futures.Future):          else:              info.append(self._state.lower()) -        info.append(coroutines._format_coroutine(self._coro)) +        coro = coroutines._format_coroutine(self._coro) +        info.append('coro=<%s>' % coro) + +        if self._source_traceback: +            frame = self._source_traceback[-1] +            info.append('created at %s:%s' % (frame[0], frame[1]))          if self._state == futures._FINISHED:              info.append(self._format_result()) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index afadc7c1ed..b13818f7f3 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -24,6 +24,19 @@ def coroutine_function():      pass +def format_coroutine(qualname, state, src, source_traceback, generator=False): +    if generator: +        state = '%s' % state +    else: +        state = '%s, defined' % state +    if source_traceback is not None: +        frame = source_traceback[-1] +        return ('coro=<%s() %s at %s> created at %s:%s' +                % (qualname, state, src, frame[0], frame[1])) +    else: +        return 'coro=<%s() %s at %s>' % (qualname, state, src) + +  class Dummy:      def __repr__(self): @@ -149,7 +162,9 @@ class TaskTests(test_utils.TestCase):          # test pending Task          t = asyncio.Task(gen, loop=self.loop)          t.add_done_callback(Dummy()) -        coro = '%s() at %s' % (coro_qualname, src) + +        coro = format_coroutine(coro_qualname, 'running', src, +                                t._source_traceback, generator=True)          self.assertEqual(repr(t),                           '<Task pending %s cb=[<Dummy>()]>' % coro) @@ -161,13 +176,16 @@ class TaskTests(test_utils.TestCase):          # test cancelled Task          self.assertRaises(asyncio.CancelledError,                            self.loop.run_until_complete, t) -        coro = '%s() done at %s' % (coro_qualname, src) +        coro = format_coroutine(coro_qualname, 'done', src, +                                t._source_traceback)          self.assertEqual(repr(t),                           '<Task cancelled %s>' % coro)          # test finished Task          t = asyncio.Task(notmuch(), loop=self.loop)          self.loop.run_until_complete(t) +        coro = format_coroutine(coro_qualname, 'done', src, +                                t._source_traceback)          self.assertEqual(repr(t),                           "<Task finished %s result='abc'>" % coro) @@ -206,18 +224,35 @@ class TaskTests(test_utils.TestCase):          if PY35:              self.assertEqual(gen.__qualname__, coro_qualname) -        # format the coroutine object -        code = gen.gi_code -        coro = ('%s() at %s:%s' -                % (coro_qualname, code.co_filename, code.co_firstlineno)) -          # test repr(CoroWrapper)          if coroutines._DEBUG: +            # format the coroutine object +            if coroutines._DEBUG: +                filename, lineno = test_utils.get_function_source(notmuch) +                frame = gen._source_traceback[-1] +                coro = ('%s() running, defined at %s:%s, created at %s:%s' +                        % (coro_qualname, filename, lineno, +                           frame[0], frame[1])) +            else: +                code = gen.gi_code +                coro = ('%s() running at %s:%s' +                        % (coro_qualname, code.co_filename, code.co_firstlineno)) +              self.assertEqual(repr(gen), '<CoroWrapper %s>' % coro)          # test pending Task          t = asyncio.Task(gen, loop=self.loop)          t.add_done_callback(Dummy()) + +        # format the coroutine object +        if coroutines._DEBUG: +            src = '%s:%s' % test_utils.get_function_source(notmuch) +        else: +            code = gen.gi_code +            src = '%s:%s' % (code.co_filename, code.co_firstlineno) +        coro = format_coroutine(coro_qualname, 'running', src, +                                t._source_traceback, +                                generator=not coroutines._DEBUG)          self.assertEqual(repr(t),                           '<Task pending %s cb=[<Dummy>()]>' % coro)          self.loop.run_until_complete(t)  | 
