summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2016-09-09 19:54:54 (GMT)
committerGuido van Rossum <guido@python.org>2016-09-09 19:54:54 (GMT)
commit1140a0342613c30feaedfe96b9e09ad7248de490 (patch)
treeeeb925307793df12b7cb5e3c561a2a3aa152437f
parentc1db513e368eb485df49a4bd354984136f3a39bd (diff)
downloadcpython-1140a0342613c30feaedfe96b9e09ad7248de490.zip
cpython-1140a0342613c30feaedfe96b9e09ad7248de490.tar.gz
cpython-1140a0342613c30feaedfe96b9e09ad7248de490.tar.bz2
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.
-rw-r--r--Lib/asyncio/futures.py12
-rw-r--r--Lib/asyncio/tasks.py7
2 files changed, 14 insertions, 5 deletions
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 1feba4d..edc13dc 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -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.
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 0cca8e3..3e200f6 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -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: