bpo-32643: Drop support for a few private Task and Future APIs. (#5293)

Specifically, it's not possible to subclass Task/Future classes
and override the following methods:

* Future._schedule_callbacks
* Task._step
* Task._wakeup
This commit is contained in:
Yury Selivanov 2018-01-24 11:31:01 -05:00 committed by GitHub
parent 8ded5b8037
commit 22feeb88b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 33 additions and 229 deletions

View file

@ -99,7 +99,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
self._coro = coro
self._context = contextvars.copy_context()
self._loop.call_soon(self._step, context=self._context)
self._loop.call_soon(self.__step, context=self._context)
_register_task(self)
def __del__(self):
@ -185,11 +185,11 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
# catches and ignores the cancellation so we may have
# to cancel it again later.
return True
# It must be the case that self._step is already scheduled.
# It must be the case that self.__step is already scheduled.
self._must_cancel = True
return True
def _step(self, exc=None):
def __step(self, exc=None):
if self.done():
raise futures.InvalidStateError(
f'_step(): already done: {self!r}, {exc!r}')
@ -232,17 +232,17 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
f'Task {self!r} got Future '
f'{result!r} attached to a different loop')
self._loop.call_soon(
self._step, new_exc, context=self._context)
self.__step, new_exc, context=self._context)
elif blocking:
if result is self:
new_exc = RuntimeError(
f'Task cannot await on itself: {self!r}')
self._loop.call_soon(
self._step, new_exc, context=self._context)
self.__step, new_exc, context=self._context)
else:
result._asyncio_future_blocking = False
result.add_done_callback(
self._wakeup, context=self._context)
self.__wakeup, context=self._context)
self._fut_waiter = result
if self._must_cancel:
if self._fut_waiter.cancel():
@ -252,33 +252,33 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
f'yield was used instead of yield from '
f'in task {self!r} with {result!r}')
self._loop.call_soon(
self._step, new_exc, context=self._context)
self.__step, new_exc, context=self._context)
elif result is None:
# Bare yield relinquishes control for one event loop iteration.
self._loop.call_soon(self._step, context=self._context)
self._loop.call_soon(self.__step, context=self._context)
elif inspect.isgenerator(result):
# Yielding a generator is just wrong.
new_exc = RuntimeError(
f'yield was used instead of yield from for '
f'generator in task {self!r} with {result}')
self._loop.call_soon(
self._step, new_exc, context=self._context)
self.__step, new_exc, context=self._context)
else:
# Yielding something else is an error.
new_exc = RuntimeError(f'Task got bad yield: {result!r}')
self._loop.call_soon(
self._step, new_exc, context=self._context)
self.__step, new_exc, context=self._context)
finally:
_leave_task(self._loop, self)
self = None # Needed to break cycles when an exception occurs.
def _wakeup(self, future):
def __wakeup(self, future):
try:
future.result()
except Exception as exc:
# This may also be a cancellation.
self._step(exc)
self.__step(exc)
else:
# Don't pass the value of `future.result()` explicitly,
# as `Future.__iter__` and `Future.__await__` don't need it.
@ -286,7 +286,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
# Python eval loop would use `.send(value)` method call,
# instead of `__next__()`, which is slower for futures
# that return non-generator iterators from their `__iter__`.
self._step()
self.__step()
self = None # Needed to break cycles when an exception occurs.
@ -513,7 +513,7 @@ def __sleep0():
This is a private helper for 'asyncio.sleep()', used
when the 'delay' is set to 0. It uses a bare 'yield'
expression (which Task._step knows how to handle)
expression (which Task.__step knows how to handle)
instead of creating a Future object.
"""
yield