diff options
author | Guido van Rossum <guido@python.org> | 2016-09-09 19:54:54 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2016-09-09 19:54:54 (GMT) |
commit | 1140a0342613c30feaedfe96b9e09ad7248de490 (patch) | |
tree | eeb925307793df12b7cb5e3c561a2a3aa152437f | |
parent | c1db513e368eb485df49a4bd354984136f3a39bd (diff) | |
download | cpython-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.py | 12 | ||||
-rw-r--r-- | Lib/asyncio/tasks.py | 7 |
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: |