[Python-checkins] cpython (merge 3.4 -> default): Asyncio issue 222 / PR 231 (Victor Stinner) -- fix @coroutine functions without

guido.van.rossum python-checkins at python.org
Sun May 3 03:46:18 CEST 2015


https://hg.python.org/cpython/rev/352d1fb2a8e4
changeset:   95856:352d1fb2a8e4
parent:      95854:02e3bf65b2f8
parent:      95855:3795daceff85
user:        Guido van Rossum <guido at python.org>
date:        Sat May 02 18:45:51 2015 -0700
summary:
  Asyncio issue 222 / PR 231 (Victor Stinner) -- fix @coroutine functions without __name__. (Merged from 3.4 branch.)

files:
  Lib/asyncio/coroutines.py           |  18 +++-
  Lib/asyncio/events.py               |  14 ++-
  Lib/asyncio/futures.py              |   2 +-
  Lib/test/test_asyncio/test_tasks.py |  65 +++++++++++-----
  Misc/NEWS                           |  27 +++++++
  5 files changed, 94 insertions(+), 32 deletions(-)


diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
--- a/Lib/asyncio/coroutines.py
+++ b/Lib/asyncio/coroutines.py
@@ -151,7 +151,8 @@
             w = CoroWrapper(coro(*args, **kwds), func)
             if w._source_traceback:
                 del w._source_traceback[-1]
-            w.__name__ = func.__name__
+            if hasattr(func, '__name__'):
+                w.__name__ = func.__name__
             if hasattr(func, '__qualname__'):
                 w.__qualname__ = func.__qualname__
             w.__doc__ = func.__doc__
@@ -175,25 +176,30 @@
 
 def _format_coroutine(coro):
     assert iscoroutine(coro)
-    coro_name = getattr(coro, '__qualname__', coro.__name__)
+
+    if isinstance(coro, CoroWrapper):
+        func = coro.func
+    else:
+        func = coro
+    coro_name = events._format_callback(func, ())
 
     filename = coro.gi_code.co_filename
     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_repr = ('%s done, defined at %s:%s'
                          % (coro_name, filename, lineno))
         else:
-            coro_repr = ('%s() running, defined at %s:%s'
+            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
-        coro_repr = ('%s() running at %s:%s'
+        coro_repr = ('%s running at %s:%s'
                      % (coro_name, filename, lineno))
     else:
         lineno = coro.gi_code.co_firstlineno
-        coro_repr = ('%s() done, defined at %s:%s'
+        coro_repr = ('%s done, defined at %s:%s'
                      % (coro_name, filename, lineno))
 
     return coro_repr
diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py
--- a/Lib/asyncio/events.py
+++ b/Lib/asyncio/events.py
@@ -54,15 +54,21 @@
             suffix = _format_args(args) + suffix
         return _format_callback(func.func, func.args, suffix)
 
-    func_repr = getattr(func, '__qualname__', None)
-    if not func_repr:
+    if hasattr(func, '__qualname__'):
+        func_repr = getattr(func, '__qualname__')
+    elif hasattr(func, '__name__'):
+        func_repr = getattr(func, '__name__')
+    else:
         func_repr = repr(func)
 
     if args is not None:
         func_repr += _format_args(args)
     if suffix:
         func_repr += suffix
+    return func_repr
 
+def _format_callback_source(func, args):
+    func_repr = _format_callback(func, args)
     source = _get_function_source(func)
     if source:
         func_repr += ' at %s:%s' % source
@@ -92,7 +98,7 @@
         if self._cancelled:
             info.append('cancelled')
         if self._callback is not None:
-            info.append(_format_callback(self._callback, self._args))
+            info.append(_format_callback_source(self._callback, self._args))
         if self._source_traceback:
             frame = self._source_traceback[-1]
             info.append('created at %s:%s' % (frame[0], frame[1]))
@@ -119,7 +125,7 @@
         try:
             self._callback(*self._args)
         except Exception as exc:
-            cb = _format_callback(self._callback, self._args)
+            cb = _format_callback_source(self._callback, self._args)
             msg = 'Exception in callback {}'.format(cb)
             context = {
                 'message': msg,
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -162,7 +162,7 @@
             cb = ''
 
         def format_cb(callback):
-            return events._format_callback(callback, ())
+            return events._format_callback_source(callback, ())
 
         if size == 1:
             cb = format_cb(cb[0])
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
@@ -1,5 +1,7 @@
 """Tests for tasks.py."""
 
+import contextlib
+import functools
 import os
 import re
 import sys
@@ -28,6 +30,19 @@
     pass
 
 
+ at contextlib.contextmanager
+def set_coroutine_debug(enabled):
+    coroutines = asyncio.coroutines
+
+    old_debug = coroutines._DEBUG
+    try:
+        coroutines._DEBUG = enabled
+        yield
+    finally:
+        coroutines._DEBUG = old_debug
+
+
+
 def format_coroutine(qualname, state, src, source_traceback, generator=False):
     if generator:
         state = '%s' % state
@@ -279,6 +294,29 @@
         fut.set_result(None)
         self.loop.run_until_complete(task)
 
+    def test_task_repr_partial_corowrapper(self):
+        # Issue #222: repr(CoroWrapper) must not fail in debug mode if the
+        # coroutine is a partial function
+        with set_coroutine_debug(True):
+            self.loop.set_debug(True)
+
+            @asyncio.coroutine
+            def func(x, y):
+                yield from asyncio.sleep(0)
+
+            partial_func = asyncio.coroutine(functools.partial(func, 1))
+            task = self.loop.create_task(partial_func(2))
+
+            # make warnings quiet
+            task._log_destroy_pending = False
+            self.addCleanup(task._coro.close)
+
+        coro_repr = repr(task._coro)
+        expected = ('<CoroWrapper TaskTests.test_task_repr_partial_corowrapper'
+                    '.<locals>.func(1)() running, ')
+        self.assertTrue(coro_repr.startswith(expected),
+                        coro_repr)
+
     def test_task_basics(self):
         @asyncio.coroutine
         def outer():
@@ -1555,25 +1593,16 @@
             # The frame should have changed.
             self.assertIsNone(gen.gi_frame)
 
-        # Save debug flag.
-        old_debug = asyncio.coroutines._DEBUG
-        try:
-            # Test with debug flag cleared.
-            asyncio.coroutines._DEBUG = False
+        # Test with debug flag cleared.
+        with set_coroutine_debug(False):
             check()
 
-            # Test with debug flag set.
-            asyncio.coroutines._DEBUG = True
+        # Test with debug flag set.
+        with set_coroutine_debug(True):
             check()
 
-        finally:
-            # Restore original debug flag.
-            asyncio.coroutines._DEBUG = old_debug
-
     def test_yield_from_corowrapper(self):
-        old_debug = asyncio.coroutines._DEBUG
-        asyncio.coroutines._DEBUG = True
-        try:
+        with set_coroutine_debug(True):
             @asyncio.coroutine
             def t1():
                 return (yield from t2())
@@ -1591,8 +1620,6 @@
             task = asyncio.Task(t1(), loop=self.loop)
             val = self.loop.run_until_complete(task)
             self.assertEqual(val, (1, 2, 3))
-        finally:
-            asyncio.coroutines._DEBUG = old_debug
 
     def test_yield_from_corowrapper_send(self):
         def foo():
@@ -1663,14 +1690,10 @@
 
     @mock.patch('asyncio.coroutines.logger')
     def test_coroutine_never_yielded(self, m_log):
-        debug = asyncio.coroutines._DEBUG
-        try:
-            asyncio.coroutines._DEBUG = True
+        with set_coroutine_debug(True):
             @asyncio.coroutine
             def coro_noop():
                 pass
-        finally:
-            asyncio.coroutines._DEBUG = debug
 
         tb_filename = __file__
         tb_lineno = sys._getframe().f_lineno + 2
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -101,6 +101,7 @@
 Library
 -------
 
+<<<<<<< local
 - Issue #16914: new debuglevel 2 in smtplib adds timestamps to debug output.
 
 - Issue #7159: urllib.request now supports sending auth credentials
@@ -125,6 +126,32 @@
 - Issue #21217: inspect.getsourcelines() now tries to compute the start and end
   lines from the code object, fixing an issue when a lambda function is used as
   decorator argument. Patch by Thomas Ballinger and Allison Kaptur.
+=======
+- Asyncio issue 222 / PR 231 (Victor Stinner) -- fix @coroutine
+  functions without __name__.
+
+- Issue #9246: On POSIX, os.getcwd() now supports paths longer than 1025 bytes.
+  Patch written by William Orr.
+
+- Issues #24099, #24100, and #24101: Fix free-after-use bug in heapq's siftup
+  and siftdown functions.
+
+- Backport collections.deque fixes from Python 3.5.  Prevents reentrant badness
+  during deletion by deferring the decref until the container has been restored
+  to a consistent state.
+
+- Issue #23008: Fixed resolving attributes with boolean value is False in pydoc.
+
+- Fix asyncio issue 235: LifoQueue and PriorityQueue's put didn't
+  increment unfinished tasks (this bug was introduced in 3.4.3 when
+  JoinableQueue was merged with Queue).
+
+- Issue #23908: os functions now reject paths with embedded null character
+  on Windows instead of silently truncate them.
+
+- Issue #23728: binascii.crc_hqx() could return an integer outside of the range
+  0-0xffff for empty data.
+>>>>>>> other
 
 - Issue #23811: Add missing newline to the PyCompileError error message.
   Patch by Alex Shkop.

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


More information about the Python-checkins mailing list