[Python-checkins] cpython (merge 3.5 -> default): Issue #24400: Fix CoroWrapper for 'async def' coroutines

yury.selivanov python-checkins at python.org
Wed Jun 24 16:48:34 CEST 2015


https://hg.python.org/cpython/rev/2e4d604c449d
changeset:   96657:2e4d604c449d
parent:      96654:245c09b7516f
parent:      96656:338597d2e93b
user:        Yury Selivanov <yselivanov at sprymix.com>
date:        Wed Jun 24 10:32:41 2015 -0400
summary:
  Issue #24400: Fix CoroWrapper for 'async def' coroutines

files:
  Lib/asyncio/coroutines.py            |  50 ++++++++++++---
  Lib/test/test_asyncio/test_pep492.py |  25 +++++++-
  Lib/test/test_asyncio/test_tasks.py  |   3 +-
  3 files changed, 66 insertions(+), 12 deletions(-)


diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
--- a/Lib/asyncio/coroutines.py
+++ b/Lib/asyncio/coroutines.py
@@ -103,9 +103,6 @@
     def __iter__(self):
         return self
 
-    if _PY35:
-        __await__ = __iter__ # make compatible with 'await' expression
-
     def __next__(self):
         return self.gen.send(None)
 
@@ -143,10 +140,28 @@
     def gi_code(self):
         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):
         # Be careful accessing self.gen.frame -- self.gen might not exist.
         gen = getattr(self, 'gen', 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:
             msg = '%r was never yielded from' % self
             tb = getattr(self, '_source_traceback', ())
@@ -233,28 +248,43 @@
 def _format_coroutine(coro):
     assert iscoroutine(coro)
 
+    coro_name = None
     if isinstance(coro, CoroWrapper):
         func = coro.func
+        coro_name = coro.__qualname__
     else:
         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)
-    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)
-        if coro.gi_frame is None:
+        if coro_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
+    elif coro_frame is not None:
+        lineno = coro_frame.f_lineno
         coro_repr = ('%s running at %s:%s'
                      % (coro_name, filename, lineno))
     else:
-        lineno = coro.gi_code.co_firstlineno
+        lineno = coro_code.co_firstlineno
         coro_repr = ('%s done, defined at %s:%s'
                      % (coro_name, filename, lineno))
 
diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py
--- a/Lib/test/test_asyncio/test_pep492.py
+++ b/Lib/test/test_asyncio/test_pep492.py
@@ -119,7 +119,7 @@
         self.assertEqual(coro.send(None), 'spam')
         coro.close()
 
-    def test_async_ded_coroutines(self):
+    def test_async_def_coroutines(self):
         async def bar():
             return 'spam'
         async def foo():
@@ -134,5 +134,28 @@
         data = self.loop.run_until_complete(foo())
         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__':
     unittest.main()
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -1715,7 +1715,8 @@
         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'^<CoroWrapper %s\(\) .* at %s:%s, .*> '
+
+        regex = (r'^<CoroWrapper %s\(?\)? .* at %s:%s, .*> '
                     r'was never yielded from\n'
                  r'Coroutine object created at \(most recent call last\):\n'
                  r'.*\n'

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list