Commit 416c1ebd authored by Yury Selivanov's avatar Yury Selivanov Committed by GitHub

bpo-32610: Fix asyncio.all_tasks() to return only pending tasks. (GH-7174)

parent fdccfe09
...@@ -443,6 +443,8 @@ Task ...@@ -443,6 +443,8 @@ Task
Return a set of all tasks for an event loop. Return a set of all tasks for an event loop.
By default all tasks for the current event loop are returned. By default all tasks for the current event loop are returned.
If *loop* is ``None``, :func:`get_event_loop` function
is used to get the current loop.
.. classmethod:: current_task(loop=None) .. classmethod:: current_task(loop=None)
...@@ -567,8 +569,9 @@ Task functions ...@@ -567,8 +569,9 @@ Task functions
Return a set of :class:`Task` objects created for the loop. Return a set of :class:`Task` objects created for the loop.
If *loop* is ``None`` :func:`get_event_loop` is used for getting If *loop* is ``None``, :func:`get_running_loop` is used for getting
current loop. current loop (contrary to the deprecated :meth:`Task.all_tasks` method
that uses :func:`get_event_loop`.)
.. versionadded:: 3.7 .. versionadded:: 3.7
......
...@@ -18,6 +18,10 @@ from .subprocess import * ...@@ -18,6 +18,10 @@ from .subprocess import *
from .tasks import * from .tasks import *
from .transports import * from .transports import *
# Exposed for _asynciomodule.c to implement now deprecated
# Task.all_tasks() method. This function will be removed in 3.9.
from .tasks import _all_tasks_compat # NoQA
__all__ = (base_events.__all__ + __all__ = (base_events.__all__ +
coroutines.__all__ + coroutines.__all__ +
events.__all__ + events.__all__ +
......
...@@ -51,8 +51,7 @@ def run(main, *, debug=False): ...@@ -51,8 +51,7 @@ def run(main, *, debug=False):
def _cancel_all_tasks(loop): def _cancel_all_tasks(loop):
to_cancel = [task for task in tasks.all_tasks(loop) to_cancel = tasks.all_tasks(loop)
if not task.done()]
if not to_cancel: if not to_cancel:
return return
......
...@@ -33,6 +33,16 @@ def current_task(loop=None): ...@@ -33,6 +33,16 @@ def current_task(loop=None):
def all_tasks(loop=None): def all_tasks(loop=None):
"""Return a set of all tasks for the loop.""" """Return a set of all tasks for the loop."""
if loop is None:
loop = events.get_running_loop()
return {t for t in _all_tasks
if futures._get_loop(t) is loop and not t.done()}
def _all_tasks_compat(loop=None):
# Different from "all_task()" by returning *all* Tasks, including
# the completed ones. Used to implement deprecated "Tasks.all_task()"
# method.
if loop is None: if loop is None:
loop = events.get_event_loop() loop = events.get_event_loop()
return {t for t in _all_tasks if futures._get_loop(t) is loop} return {t for t in _all_tasks if futures._get_loop(t) is loop}
...@@ -82,7 +92,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation ...@@ -82,7 +92,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
"use asyncio.all_tasks() instead", "use asyncio.all_tasks() instead",
PendingDeprecationWarning, PendingDeprecationWarning,
stacklevel=2) stacklevel=2)
return all_tasks(loop) return _all_tasks_compat(loop)
def __init__(self, coro, *, loop=None): def __init__(self, coro, *, loop=None):
super().__init__(loop=loop) super().__init__(loop=loop)
......
...@@ -1897,8 +1897,10 @@ class BaseTaskTests: ...@@ -1897,8 +1897,10 @@ class BaseTaskTests:
# See http://bugs.python.org/issue29271 for details: # See http://bugs.python.org/issue29271 for details:
asyncio.set_event_loop(self.loop) asyncio.set_event_loop(self.loop)
try: try:
self.assertEqual(asyncio.all_tasks(), {task}) with self.assertWarns(PendingDeprecationWarning):
self.assertEqual(asyncio.all_tasks(None), {task}) self.assertEqual(Task.all_tasks(), {task})
with self.assertWarns(PendingDeprecationWarning):
self.assertEqual(Task.all_tasks(None), {task})
finally: finally:
asyncio.set_event_loop(None) asyncio.set_event_loop(None)
...@@ -2483,6 +2485,9 @@ class BaseTaskIntrospectionTests: ...@@ -2483,6 +2485,9 @@ class BaseTaskIntrospectionTests:
def _loop(self): def _loop(self):
return loop return loop
def done(self):
return False
task = TaskLike() task = TaskLike()
loop = mock.Mock() loop = mock.Mock()
...@@ -2496,6 +2501,9 @@ class BaseTaskIntrospectionTests: ...@@ -2496,6 +2501,9 @@ class BaseTaskIntrospectionTests:
def get_loop(self): def get_loop(self):
return loop return loop
def done(self):
return False
task = TaskLike() task = TaskLike()
loop = mock.Mock() loop = mock.Mock()
...@@ -2504,6 +2512,23 @@ class BaseTaskIntrospectionTests: ...@@ -2504,6 +2512,23 @@ class BaseTaskIntrospectionTests:
self.assertEqual(asyncio.all_tasks(loop), {task}) self.assertEqual(asyncio.all_tasks(loop), {task})
self._unregister_task(task) self._unregister_task(task)
def test__register_task_3(self):
class TaskLike:
def get_loop(self):
return loop
def done(self):
return True
task = TaskLike()
loop = mock.Mock()
self.assertEqual(asyncio.all_tasks(loop), set())
self._register_task(task)
self.assertEqual(asyncio.all_tasks(loop), set())
self.assertEqual(asyncio.Task.all_tasks(loop), {task})
self._unregister_task(task)
def test__enter_task(self): def test__enter_task(self):
task = mock.Mock() task = mock.Mock()
loop = mock.Mock() loop = mock.Mock()
......
Make asyncio.all_tasks() return only pending tasks.
...@@ -11,7 +11,7 @@ module _asyncio ...@@ -11,7 +11,7 @@ module _asyncio
/* identifiers used from some functions */ /* identifiers used from some functions */
_Py_IDENTIFIER(__asyncio_running_event_loop__); _Py_IDENTIFIER(__asyncio_running_event_loop__);
_Py_IDENTIFIER(add_done_callback); _Py_IDENTIFIER(add_done_callback);
_Py_IDENTIFIER(all_tasks); _Py_IDENTIFIER(_all_tasks_compat);
_Py_IDENTIFIER(call_soon); _Py_IDENTIFIER(call_soon);
_Py_IDENTIFIER(cancel); _Py_IDENTIFIER(cancel);
_Py_IDENTIFIER(current_task); _Py_IDENTIFIER(current_task);
...@@ -2125,7 +2125,7 @@ _asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop) ...@@ -2125,7 +2125,7 @@ _asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop)
return NULL; return NULL;
} }
all_tasks_func = _PyObject_GetAttrId(asyncio_mod, &PyId_all_tasks); all_tasks_func = _PyObject_GetAttrId(asyncio_mod, &PyId__all_tasks_compat);
if (all_tasks_func == NULL) { if (all_tasks_func == NULL) {
return NULL; return NULL;
} }
......
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