[Python-checkins] cpython (merge 3.5 -> default): Rename Future._blocking to _asyncio_future_blocking.

guido.van.rossum python-checkins at python.org
Fri Sep 9 16:01:19 EDT 2016


https://hg.python.org/cpython/rev/b2a5aed737bf
changeset:   103455:b2a5aed737bf
parent:      103453:7464142fc867
parent:      103454:ab1e10e3dc35
user:        Guido van Rossum <guido at dropbox.com>
date:        Fri Sep 09 12:58:15 2016 -0700
summary:
  Rename Future._blocking to _asyncio_future_blocking.

This is now an official "protected" API that can be used to write
classes that are duck-type-compatible with Future without subclassing
it.  (For that purpose I also changed isinstance(result, Future) to
check for this attribute instead.)

Hopefully Amber Brown can use this to make Twisted.Deferred compatible
with asyncio.Future.

Tests and docs are TBD. (Also there are more isinstance() checks to fix.)

files:
  Lib/asyncio/futures.py |  12 ++++++++++--
  Lib/asyncio/tasks.py   |   7 ++++---
  2 files changed, 14 insertions(+), 5 deletions(-)


diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -134,7 +134,15 @@
     _loop = None
     _source_traceback = None
 
-    _blocking = False  # proper use of future (yield vs yield from)
+    # This field is used for a dual purpose:
+    # - Its presence is a marker to declare that a class implements
+    #   the Future protocol (i.e. is intended to be duck-type compatible).
+    #   The value must also be not-None, to enable a subclass to declare
+    #   that it is not compatible by setting this to None.
+    # - It is set by __iter__() below so that Task._step() can tell
+    #   the difference between `yield from Future()` (correct) vs.
+    #   `yield Future()` (incorrect).
+    _asyncio_future_blocking = False
 
     _log_traceback = False   # Used for Python 3.4 and later
     _tb_logger = None        # Used for Python 3.3 only
@@ -357,7 +365,7 @@
 
     def __iter__(self):
         if not self.done():
-            self._blocking = True
+            self._asyncio_future_blocking = True
             yield self  # This tells Task to wait for completion.
         assert self.done(), "yield from wasn't used with future"
         return self.result()  # May raise too.
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -249,7 +249,8 @@
             self.set_exception(exc)
             raise
         else:
-            if isinstance(result, futures.Future):
+            blocking = getattr(result, '_asyncio_future_blocking', None)
+            if blocking is not None:
                 # Yielded Future must come from Future.__iter__().
                 if result._loop is not self._loop:
                     self._loop.call_soon(
@@ -257,8 +258,8 @@
                         RuntimeError(
                             'Task {!r} got Future {!r} attached to a '
                             'different loop'.format(self, result)))
-                elif result._blocking:
-                    result._blocking = False
+                elif blocking:
+                    result._asyncio_future_blocking = False
                     result.add_done_callback(self._wakeup)
                     self._fut_waiter = result
                     if self._must_cancel:

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


More information about the Python-checkins mailing list