]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Rename Future._blocking to _asyncio_future_blocking.
authorGuido van Rossum <guido@python.org>
Fri, 9 Sep 2016 19:54:54 +0000 (12:54 -0700)
committerGuido van Rossum <guido@python.org>
Fri, 9 Sep 2016 19:54:54 +0000 (12:54 -0700)
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.

Lib/asyncio/futures.py
Lib/asyncio/tasks.py

index 1feba4d370070d83068acca374b66cd269bfcadb..edc13dcc474fb86f39e2abfceded678fdbdd6a21 100644 (file)
@@ -134,7 +134,15 @@ class Future:
     _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 @@ class Future:
 
     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.
index 0cca8e36a59b546f301a3088c77bbd07ad60afe7..3e200f6338d23af6260f845bc0deae29e6983734 100644 (file)
@@ -249,7 +249,8 @@ class Task(futures.Future):
             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 @@ class Task(futures.Future):
                         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: