[Python-checkins] cpython (merge 3.4 -> default): (Merge 3.4) asyncio: sync with Tulip

victor.stinner python-checkins at python.org
Thu Jul 10 22:36:54 CEST 2014


http://hg.python.org/cpython/rev/a67adfaf670b
changeset:   91628:a67adfaf670b
parent:      91626:03b406f5aae0
parent:      91627:f13cde63ca73
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Thu Jul 10 22:34:58 2014 +0200
summary:
  (Merge 3.4) asyncio: sync with Tulip

- Issues #21936, #21163: Fix sporadic failures of
  test_future_exception_never_retrieved()
- Handle.cancel() now clears references to callback and args
- In debug mode, repr(Handle) now contains the location where the Handle was
  created.

files:
  Lib/asyncio/events.py                 |  18 +++-
  Lib/test/test_asyncio/test_events.py  |  66 ++++++++++++--
  Lib/test/test_asyncio/test_futures.py |   6 +
  3 files changed, 74 insertions(+), 16 deletions(-)


diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py
--- a/Lib/asyncio/events.py
+++ b/Lib/asyncio/events.py
@@ -82,14 +82,20 @@
             self._source_traceback = None
 
     def __repr__(self):
-        info = []
+        info = [self.__class__.__name__]
         if self._cancelled:
             info.append('cancelled')
-        info.append(_format_callback(self._callback, self._args))
-        return '<%s %s>' % (self.__class__.__name__, ' '.join(info))
+        if self._callback is not None:
+            info.append(_format_callback(self._callback, self._args))
+        if self._source_traceback:
+            frame = self._source_traceback[-1]
+            info.append('created at %s:%s' % (frame[0], frame[1]))
+        return '<%s>' % ' '.join(info)
 
     def cancel(self):
         self._cancelled = True
+        self._callback = None
+        self._args = None
 
     def _run(self):
         try:
@@ -125,7 +131,11 @@
         if self._cancelled:
             info.append('cancelled')
         info.append('when=%s' % self._when)
-        info.append(_format_callback(self._callback, self._args))
+        if self._callback is not None:
+            info.append(_format_callback(self._callback, self._args))
+        if self._source_traceback:
+            frame = self._source_traceback[-1]
+            info.append('created at %s:%s' % (frame[0], frame[1]))
         return '<%s %s>' % (self.__class__.__name__, ' '.join(info))
 
     def __hash__(self):
diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -1810,27 +1810,30 @@
         wd['h'] = h  # Would fail without __weakref__ slot.
 
     def test_handle_repr(self):
+        self.loop.get_debug.return_value = False
+
         # simple function
-        h = asyncio.Handle(noop, (), self.loop)
-        src = test_utils.get_function_source(noop)
+        h = asyncio.Handle(noop, (1, 2), self.loop)
+        filename, lineno = test_utils.get_function_source(noop)
         self.assertEqual(repr(h),
-                        '<Handle noop() at %s:%s>' % src)
+                        '<Handle noop(1, 2) at %s:%s>'
+                        % (filename, lineno))
 
         # cancelled handle
         h.cancel()
         self.assertEqual(repr(h),
-                        '<Handle cancelled noop() at %s:%s>' % src)
+                        '<Handle cancelled>')
 
         # decorated function
         cb = asyncio.coroutine(noop)
         h = asyncio.Handle(cb, (), self.loop)
         self.assertEqual(repr(h),
-                        '<Handle noop() at %s:%s>' % src)
+                        '<Handle noop() at %s:%s>'
+                        % (filename, lineno))
 
         # partial function
         cb = functools.partial(noop, 1, 2)
         h = asyncio.Handle(cb, (3,), self.loop)
-        filename, lineno = src
         regex = (r'^<Handle noop\(1, 2\)\(3\) at %s:%s>$'
                  % (re.escape(filename), lineno))
         self.assertRegex(repr(h), regex)
@@ -1839,16 +1842,33 @@
         if sys.version_info >= (3, 4):
             method = HandleTests.test_handle_repr
             cb = functools.partialmethod(method)
-            src = test_utils.get_function_source(method)
+            filename, lineno = test_utils.get_function_source(method)
             h = asyncio.Handle(cb, (), self.loop)
 
-            filename, lineno = src
             cb_regex = r'<function HandleTests.test_handle_repr .*>'
             cb_regex = (r'functools.partialmethod\(%s, , \)\(\)' % cb_regex)
             regex = (r'^<Handle %s at %s:%s>$'
                      % (cb_regex, re.escape(filename), lineno))
             self.assertRegex(repr(h), regex)
 
+    def test_handle_repr_debug(self):
+        self.loop.get_debug.return_value = True
+
+        # simple function
+        create_filename = __file__
+        create_lineno = sys._getframe().f_lineno + 1
+        h = asyncio.Handle(noop, (1, 2), self.loop)
+        filename, lineno = test_utils.get_function_source(noop)
+        self.assertEqual(repr(h),
+                        '<Handle noop(1, 2) at %s:%s created at %s:%s>'
+                        % (filename, lineno, create_filename, create_lineno))
+
+        # cancelled handle
+        h.cancel()
+        self.assertEqual(repr(h),
+                        '<Handle cancelled created at %s:%s>'
+                        % (create_filename, create_lineno))
+
     def test_handle_source_traceback(self):
         loop = asyncio.get_event_loop_policy().new_event_loop()
         loop.set_debug(True)
@@ -1894,7 +1914,7 @@
         def callback(*args):
             return args
 
-        args = ()
+        args = (1, 2, 3)
         when = time.monotonic()
         h = asyncio.TimerHandle(when, callback, args, mock.Mock())
         self.assertIs(h._callback, callback)
@@ -1904,7 +1924,8 @@
         # cancel
         h.cancel()
         self.assertTrue(h._cancelled)
-
+        self.assertIsNone(h._callback)
+        self.assertIsNone(h._args)
 
         # when cannot be None
         self.assertRaises(AssertionError,
@@ -1912,6 +1933,8 @@
                           self.loop)
 
     def test_timer_repr(self):
+        self.loop.get_debug.return_value = False
+
         # simple function
         h = asyncio.TimerHandle(123, noop, (), self.loop)
         src = test_utils.get_function_source(noop)
@@ -1921,8 +1944,27 @@
         # cancelled handle
         h.cancel()
         self.assertEqual(repr(h),
-                        '<TimerHandle cancelled when=123 noop() at %s:%s>'
-                        % src)
+                        '<TimerHandle cancelled when=123>')
+
+    def test_timer_repr_debug(self):
+        self.loop.get_debug.return_value = True
+
+        # simple function
+        create_filename = __file__
+        create_lineno = sys._getframe().f_lineno + 1
+        h = asyncio.TimerHandle(123, noop, (), self.loop)
+        filename, lineno = test_utils.get_function_source(noop)
+        self.assertEqual(repr(h),
+                        '<TimerHandle when=123 noop() '
+                        'at %s:%s created at %s:%s>'
+                        % (filename, lineno, create_filename, create_lineno))
+
+        # cancelled handle
+        h.cancel()
+        self.assertEqual(repr(h),
+                        '<TimerHandle cancelled when=123 created at %s:%s>'
+                        % (create_filename, create_lineno))
+
 
     def test_timer_comparison(self):
         def callback(*args):
diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py
--- a/Lib/test/test_asyncio/test_futures.py
+++ b/Lib/test/test_asyncio/test_futures.py
@@ -299,6 +299,12 @@
 
     @mock.patch('asyncio.base_events.logger')
     def test_future_exception_never_retrieved(self, m_log):
+        # FIXME: Python issue #21163, other tests may "leak" pending task which
+        # emit a warning when they are destroyed by the GC
+        support.gc_collect()
+        m_log.error.reset_mock()
+        # ---
+
         self.loop.set_debug(True)
 
         def memory_error():

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


More information about the Python-checkins mailing list