summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorYury Selivanov <yury@magic.io>2018-01-24 16:31:01 (GMT)
committerGitHub <noreply@github.com>2018-01-24 16:31:01 (GMT)
commit22feeb88b473b288950cdb2f6c5d28692274b5f9 (patch)
tree805ea2b2b684bb331f1205f1347b5b60e1dfd2db /Lib
parent8ded5b803705328749622256701b3f08a9d6c5ab (diff)
downloadcpython-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.py8
-rw-r--r--Lib/asyncio/tasks.py28
-rw-r--r--Lib/test/test_asyncio/test_futures.py4
-rw-r--r--Lib/test/test_asyncio/test_tasks.py28
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