From 5d7e3b6cd208dffdfe8530664081b62e0c7e3092 Mon Sep 17 00:00:00 2001
From: Yury Selivanov <yselivanov@sprymix.com>
Date: Tue, 17 Nov 2015 12:19:41 -0500
Subject: [PATCH] asyncio: Cleanup Future API

See https://github.com/python/asyncio/pull/292 for details.
---
 Lib/asyncio/futures.py                | 60 +++++++++++++--------------
 Lib/asyncio/proactor_events.py        |  3 +-
 Lib/asyncio/selector_events.py        |  6 ++-
 Lib/asyncio/tasks.py                  |  3 +-
 Lib/asyncio/unix_events.py            |  6 ++-
 Lib/test/test_asyncio/test_futures.py | 11 +++--
 6 files changed, 49 insertions(+), 40 deletions(-)

diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 166bc8047bf..4dcb6546be0 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -154,7 +154,7 @@ class Future:
         if self._loop.get_debug():
             self._source_traceback = traceback.extract_stack(sys._getframe(1))
 
-    def _format_callbacks(self):
+    def __format_callbacks(self):
         cb = self._callbacks
         size = len(cb)
         if not size:
@@ -184,7 +184,7 @@ class Future:
                 result = reprlib.repr(self._result)
                 info.append('result={}'.format(result))
         if self._callbacks:
-            info.append(self._format_callbacks())
+            info.append(self.__format_callbacks())
         if self._source_traceback:
             frame = self._source_traceback[-1]
             info.append('created at %s:%s' % (frame[0], frame[1]))
@@ -319,12 +319,6 @@ class Future:
 
     # So-called internal methods (note: no set_running_or_notify_cancel()).
 
-    def _set_result_unless_cancelled(self, result):
-        """Helper setting the result only if the future was not cancelled."""
-        if self.cancelled():
-            return
-        self.set_result(result)
-
     def set_result(self, result):
         """Mark the future done and set its result.
 
@@ -358,27 +352,6 @@ class Future:
             # have had a chance to call result() or exception().
             self._loop.call_soon(self._tb_logger.activate)
 
-    # Truly internal methods.
-
-    def _copy_state(self, other):
-        """Internal helper to copy state from another Future.
-
-        The other Future may be a concurrent.futures.Future.
-        """
-        assert other.done()
-        if self.cancelled():
-            return
-        assert not self.done()
-        if other.cancelled():
-            self.cancel()
-        else:
-            exception = other.exception()
-            if exception is not None:
-                self.set_exception(exception)
-            else:
-                result = other.result()
-                self.set_result(result)
-
     def __iter__(self):
         if not self.done():
             self._blocking = True
@@ -390,6 +363,13 @@ class Future:
         __await__ = __iter__ # make compatible with 'await' expression
 
 
+def _set_result_unless_cancelled(fut, result):
+    """Helper setting the result only if the future was not cancelled."""
+    if fut.cancelled():
+        return
+    fut.set_result(result)
+
+
 def _set_concurrent_future_state(concurrent, source):
     """Copy state from a future to a concurrent.futures.Future."""
     assert source.done()
@@ -405,6 +385,26 @@ def _set_concurrent_future_state(concurrent, source):
         concurrent.set_result(result)
 
 
+def _copy_future_state(source, dest):
+    """Internal helper to copy state from another Future.
+
+    The other Future may be a concurrent.futures.Future.
+    """
+    assert source.done()
+    if dest.cancelled():
+        return
+    assert not dest.done()
+    if source.cancelled():
+        dest.cancel()
+    else:
+        exception = source.exception()
+        if exception is not None:
+            dest.set_exception(exception)
+        else:
+            result = source.result()
+            dest.set_result(result)
+
+
 def _chain_future(source, destination):
     """Chain two futures so that when one completes, so does the other.
 
@@ -421,7 +421,7 @@ def _chain_future(source, destination):
 
     def _set_state(future, other):
         if isinstance(future, Future):
-            future._copy_state(other)
+            _copy_future_state(other, future)
         else:
             _set_concurrent_future_state(future, other)
 
diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py
index 9c514c8345d..7eac41eec02 100644
--- a/Lib/asyncio/proactor_events.py
+++ b/Lib/asyncio/proactor_events.py
@@ -41,7 +41,8 @@ class _ProactorBasePipeTransport(transports._FlowControlMixin,
         self._loop.call_soon(self._protocol.connection_made, self)
         if waiter is not None:
             # only wake up the waiter when connection_made() has been called
-            self._loop.call_soon(waiter._set_result_unless_cancelled, None)
+            self._loop.call_soon(futures._set_result_unless_cancelled,
+                                 waiter, None)
 
     def __repr__(self):
         info = [self.__class__.__name__]
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 236f7b36a8d..a05f81cd9de 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -636,7 +636,8 @@ class _SelectorSocketTransport(_SelectorTransport):
                              self._sock_fd, self._read_ready)
         if waiter is not None:
             # only wake up the waiter when connection_made() has been called
-            self._loop.call_soon(waiter._set_result_unless_cancelled, None)
+            self._loop.call_soon(futures._set_result_unless_cancelled,
+                                 waiter, None)
 
     def pause_reading(self):
         if self._closing:
@@ -990,7 +991,8 @@ class _SelectorDatagramTransport(_SelectorTransport):
                              self._sock_fd, self._read_ready)
         if waiter is not None:
             # only wake up the waiter when connection_made() has been called
-            self._loop.call_soon(waiter._set_result_unless_cancelled, None)
+            self._loop.call_soon(futures._set_result_unless_cancelled,
+                                 waiter, None)
 
     def get_write_buffer_size(self):
         return sum(len(data) for data, _ in self._buffer)
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 61f0645f97f..63cbcda32fe 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -500,7 +500,8 @@ def sleep(delay, result=None, *, loop=None):
 
     future = futures.Future(loop=loop)
     h = future._loop.call_later(delay,
-                                future._set_result_unless_cancelled, result)
+                                futures._set_result_unless_cancelled,
+                                future, result)
     try:
         return (yield from future)
     finally:
diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py
index f75e89f3175..7747ff41bb8 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -319,7 +319,8 @@ class _UnixReadPipeTransport(transports.ReadTransport):
                              self._fileno, self._read_ready)
         if waiter is not None:
             # only wake up the waiter when connection_made() has been called
-            self._loop.call_soon(waiter._set_result_unless_cancelled, None)
+            self._loop.call_soon(futures._set_result_unless_cancelled,
+                                 waiter, None)
 
     def __repr__(self):
         info = [self.__class__.__name__]
@@ -442,7 +443,8 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
 
         if waiter is not None:
             # only wake up the waiter when connection_made() has been called
-            self._loop.call_soon(waiter._set_result_unless_cancelled, None)
+            self._loop.call_soon(futures._set_result_unless_cancelled,
+                                 waiter, None)
 
     def __repr__(self):
         info = [self.__class__.__name__]
diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py
index 0bc0581d281..55fdff3f8d5 100644
--- a/Lib/test/test_asyncio/test_futures.py
+++ b/Lib/test/test_asyncio/test_futures.py
@@ -174,11 +174,13 @@ class FutureTests(test_utils.TestCase):
                          '<Future cancelled>')
 
     def test_copy_state(self):
+        from asyncio.futures import _copy_future_state
+
         f = asyncio.Future(loop=self.loop)
         f.set_result(10)
 
         newf = asyncio.Future(loop=self.loop)
-        newf._copy_state(f)
+        _copy_future_state(f, newf)
         self.assertTrue(newf.done())
         self.assertEqual(newf.result(), 10)
 
@@ -186,7 +188,7 @@ class FutureTests(test_utils.TestCase):
         f_exception.set_exception(RuntimeError())
 
         newf_exception = asyncio.Future(loop=self.loop)
-        newf_exception._copy_state(f_exception)
+        _copy_future_state(f_exception, newf_exception)
         self.assertTrue(newf_exception.done())
         self.assertRaises(RuntimeError, newf_exception.result)
 
@@ -194,7 +196,7 @@ class FutureTests(test_utils.TestCase):
         f_cancelled.cancel()
 
         newf_cancelled = asyncio.Future(loop=self.loop)
-        newf_cancelled._copy_state(f_cancelled)
+        _copy_future_state(f_cancelled, newf_cancelled)
         self.assertTrue(newf_cancelled.cancelled())
 
     def test_iter(self):
@@ -382,9 +384,10 @@ class FutureTests(test_utils.TestCase):
         self.check_future_exception_never_retrieved(True)
 
     def test_set_result_unless_cancelled(self):
+        from asyncio import futures
         fut = asyncio.Future(loop=self.loop)
         fut.cancel()
-        fut._set_result_unless_cancelled(2)
+        futures._set_result_unless_cancelled(fut, 2)
         self.assertTrue(fut.cancelled())
 
 
-- 
2.30.9