diff options
author | Yury Selivanov <yury@magic.io> | 2018-01-24 16:31:01 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-24 16:31:01 (GMT) |
commit | 22feeb88b473b288950cdb2f6c5d28692274b5f9 (patch) | |
tree | 805ea2b2b684bb331f1205f1347b5b60e1dfd2db /Lib | |
parent | 8ded5b803705328749622256701b3f08a9d6c5ab (diff) | |
download | cpython-22feeb88b473b288950cdb2f6c5d28692274b5f9.zip cpython-22feeb88b473b288950cdb2f6c5d28692274b5f9.tar.gz cpython-22feeb88b473b288950cdb2f6c5d28692274b5f9.tar.bz2 |
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
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/asyncio/futures.py | 8 | ||||
-rw-r--r-- | Lib/asyncio/tasks.py | 28 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_futures.py | 4 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_tasks.py | 28 |
4 files changed, 21 insertions, 47 deletions
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py index 59621ff..4a56f32 100644 --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -131,10 +131,10 @@ class Future: if self._state != _PENDING: return False self._state = _CANCELLED - self._schedule_callbacks() + self.__schedule_callbacks() return True - def _schedule_callbacks(self): + def __schedule_callbacks(self): """Internal: Ask the event loop to call all callbacks. The callbacks are scheduled to be called as soon as possible. Also @@ -234,7 +234,7 @@ class Future: raise InvalidStateError('{}: {!r}'.format(self._state, self)) self._result = result self._state = _FINISHED - self._schedule_callbacks() + self.__schedule_callbacks() def set_exception(self, exception): """Mark the future done and set an exception. @@ -251,7 +251,7 @@ class Future: "and cannot be raised into a Future") self._exception = exception self._state = _FINISHED - self._schedule_callbacks() + self.__schedule_callbacks() self.__log_traceback = True def __await__(self): diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 609b8e8..3590748 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -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 diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 37f4c65..8c837ad 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -176,10 +176,6 @@ class BaseFutureTests: fut.remove_done_callback(lambda f: None) fut = self.cls.__new__(self.cls, loop=self.loop) - with self.assertRaises((RuntimeError, AttributeError)): - fut._schedule_callbacks() - - fut = self.cls.__new__(self.cls, loop=self.loop) try: repr(fut) except (RuntimeError, AttributeError): diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 1c361c8..daa1ff9 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1401,17 +1401,6 @@ class BaseTaskTests: self.assertTrue(t.done()) self.assertIsNone(t.result()) - def test_step_with_baseexception(self): - @asyncio.coroutine - def notmutch(): - raise BaseException() - - task = self.new_task(self.loop, notmutch()) - self.assertRaises(BaseException, task._step) - - self.assertTrue(task.done()) - self.assertIsInstance(task.exception(), BaseException) - def test_baseexception_during_cancel(self): def gen(): @@ -2275,22 +2264,12 @@ def add_subclass_tests(cls): self.calls = collections.defaultdict(lambda: 0) super().__init__(*args, **kwargs) - def _schedule_callbacks(self): - self.calls['_schedule_callbacks'] += 1 - return super()._schedule_callbacks() - def add_done_callback(self, *args, **kwargs): self.calls['add_done_callback'] += 1 return super().add_done_callback(*args, **kwargs) class Task(CommonFuture, BaseTask): - def _step(self, *args): - self.calls['_step'] += 1 - return super()._step(*args) - - def _wakeup(self, *args): - self.calls['_wakeup'] += 1 - return super()._wakeup(*args) + pass class Future(CommonFuture, BaseFuture): pass @@ -2310,12 +2289,11 @@ def add_subclass_tests(cls): self.assertEqual( dict(task.calls), - {'_step': 2, '_wakeup': 1, 'add_done_callback': 1, - '_schedule_callbacks': 1}) + {'add_done_callback': 1}) self.assertEqual( dict(fut.calls), - {'add_done_callback': 1, '_schedule_callbacks': 1}) + {'add_done_callback': 1}) # Add patched Task & Future back to the test case cls.Task = Task |