Commit 1140a034 authored by Guido van Rossum's avatar Guido van Rossum

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.
parent c1db513e
...@@ -134,7 +134,15 @@ class Future: ...@@ -134,7 +134,15 @@ class Future:
_loop = None _loop = None
_source_traceback = 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 _log_traceback = False # Used for Python 3.4 and later
_tb_logger = None # Used for Python 3.3 only _tb_logger = None # Used for Python 3.3 only
...@@ -357,7 +365,7 @@ class Future: ...@@ -357,7 +365,7 @@ class Future:
def __iter__(self): def __iter__(self):
if not self.done(): if not self.done():
self._blocking = True self._asyncio_future_blocking = True
yield self # This tells Task to wait for completion. yield self # This tells Task to wait for completion.
assert self.done(), "yield from wasn't used with future" assert self.done(), "yield from wasn't used with future"
return self.result() # May raise too. return self.result() # May raise too.
......
...@@ -249,7 +249,8 @@ class Task(futures.Future): ...@@ -249,7 +249,8 @@ class Task(futures.Future):
self.set_exception(exc) self.set_exception(exc)
raise raise
else: 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__(). # Yielded Future must come from Future.__iter__().
if result._loop is not self._loop: if result._loop is not self._loop:
self._loop.call_soon( self._loop.call_soon(
...@@ -257,8 +258,8 @@ class Task(futures.Future): ...@@ -257,8 +258,8 @@ class Task(futures.Future):
RuntimeError( RuntimeError(
'Task {!r} got Future {!r} attached to a ' 'Task {!r} got Future {!r} attached to a '
'different loop'.format(self, result))) 'different loop'.format(self, result)))
elif result._blocking: elif blocking:
result._blocking = False result._asyncio_future_blocking = False
result.add_done_callback(self._wakeup) result.add_done_callback(self._wakeup)
self._fut_waiter = result self._fut_waiter = result
if self._must_cancel: if self._must_cancel:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment