Commit cca4eec3 authored by Alex Grönholm's avatar Alex Grönholm Committed by Yury Selivanov

bpo-34270: Make it possible to name asyncio tasks (GH-8547)

Co-authored-by: default avatarAntti Haapala <antti.haapala@anttipatterns.com>
parent 52dee687
...@@ -246,7 +246,7 @@ Futures ...@@ -246,7 +246,7 @@ Futures
Tasks Tasks
----- -----
.. method:: AbstractEventLoop.create_task(coro) .. method:: AbstractEventLoop.create_task(coro, \*, name=None)
Schedule the execution of a :ref:`coroutine object <coroutine>`: wrap it in Schedule the execution of a :ref:`coroutine object <coroutine>`: wrap it in
a future. Return a :class:`Task` object. a future. Return a :class:`Task` object.
...@@ -255,8 +255,14 @@ Tasks ...@@ -255,8 +255,14 @@ Tasks
interoperability. In this case, the result type is a subclass of interoperability. In this case, the result type is a subclass of
:class:`Task`. :class:`Task`.
If the *name* argument is provided and not ``None``, it is set as the name
of the task using :meth:`Task.set_name`.
.. versionadded:: 3.4.2 .. versionadded:: 3.4.2
.. versionchanged:: 3.8
Added the ``name`` parameter.
.. method:: AbstractEventLoop.set_task_factory(factory) .. method:: AbstractEventLoop.set_task_factory(factory)
Set a task factory that will be used by Set a task factory that will be used by
......
...@@ -387,18 +387,24 @@ with the result. ...@@ -387,18 +387,24 @@ with the result.
Task Task
---- ----
.. function:: create_task(coro) .. function:: create_task(coro, \*, name=None)
Wrap a :ref:`coroutine <coroutine>` *coro* into a task and schedule Wrap a :ref:`coroutine <coroutine>` *coro* into a task and schedule
its execution. Return the task object. its execution. Return the task object.
If *name* is not ``None``, it is set as the name of the task using
:meth:`Task.set_name`.
The task is executed in :func:`get_running_loop` context, The task is executed in :func:`get_running_loop` context,
:exc:`RuntimeError` is raised if there is no running loop in :exc:`RuntimeError` is raised if there is no running loop in
current thread. current thread.
.. versionadded:: 3.7 .. versionadded:: 3.7
.. class:: Task(coro, \*, loop=None) .. versionchanged:: 3.8
Added the ``name`` parameter.
.. class:: Task(coro, \*, loop=None, name=None)
A unit for concurrent running of :ref:`coroutines <coroutine>`, A unit for concurrent running of :ref:`coroutines <coroutine>`,
subclass of :class:`Future`. subclass of :class:`Future`.
...@@ -438,6 +444,9 @@ Task ...@@ -438,6 +444,9 @@ Task
.. versionchanged:: 3.7 .. versionchanged:: 3.7
Added support for the :mod:`contextvars` module. Added support for the :mod:`contextvars` module.
.. versionchanged:: 3.8
Added the ``name`` parameter.
.. classmethod:: all_tasks(loop=None) .. classmethod:: all_tasks(loop=None)
Return a set of all tasks for an event loop. Return a set of all tasks for an event loop.
...@@ -504,6 +513,27 @@ Task ...@@ -504,6 +513,27 @@ Task
get_stack(). The file argument is an I/O stream to which the output get_stack(). The file argument is an I/O stream to which the output
is written; by default output is written to sys.stderr. is written; by default output is written to sys.stderr.
.. method:: get_name()
Return the name of the task.
If no name has been explicitly assigned to the task, the default
``Task`` implementation generates a default name during instantiation.
.. versionadded:: 3.8
.. method:: set_name(value)
Set the name of the task.
The *value* argument can be any object, which is then converted to a
string.
In the default ``Task`` implementation, the name will be visible in the
:func:`repr` output of a task object.
.. versionadded:: 3.8
Example: Parallel execution of tasks Example: Parallel execution of tasks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......
...@@ -249,6 +249,13 @@ Changes in the Python API ...@@ -249,6 +249,13 @@ Changes in the Python API
* ``PyGC_Head`` struct is changed completely. All code touched the * ``PyGC_Head`` struct is changed completely. All code touched the
struct member should be rewritten. (See :issue:`33597`) struct member should be rewritten. (See :issue:`33597`)
* Asyncio tasks can now be named, either by passing the ``name`` keyword
argument to :func:`asyncio.create_task` or
the :meth:`~asyncio.AbstractEventLoop.create_task` event loop method, or by
calling the :meth:`~asyncio.Task.set_name` method on the task object. The
task name is visible in the ``repr()`` output of :class:`asyncio.Task` and
can also be retrieved using the :meth:`~asyncio.Task.get_name` method.
CPython bytecode changes CPython bytecode changes
------------------------ ------------------------
......
...@@ -384,18 +384,20 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -384,18 +384,20 @@ class BaseEventLoop(events.AbstractEventLoop):
"""Create a Future object attached to the loop.""" """Create a Future object attached to the loop."""
return futures.Future(loop=self) return futures.Future(loop=self)
def create_task(self, coro): def create_task(self, coro, *, name=None):
"""Schedule a coroutine object. """Schedule a coroutine object.
Return a task object. Return a task object.
""" """
self._check_closed() self._check_closed()
if self._task_factory is None: if self._task_factory is None:
task = tasks.Task(coro, loop=self) task = tasks.Task(coro, loop=self, name=name)
if task._source_traceback: if task._source_traceback:
del task._source_traceback[-1] del task._source_traceback[-1]
else: else:
task = self._task_factory(self, coro) task = self._task_factory(self, coro)
tasks._set_task_name(task, name)
return task return task
def set_task_factory(self, factory): def set_task_factory(self, factory):
......
...@@ -12,11 +12,13 @@ def _task_repr_info(task): ...@@ -12,11 +12,13 @@ def _task_repr_info(task):
# replace status # replace status
info[0] = 'cancelling' info[0] = 'cancelling'
info.insert(1, 'name=%r' % task.get_name())
coro = coroutines._format_coroutine(task._coro) coro = coroutines._format_coroutine(task._coro)
info.insert(1, f'coro=<{coro}>') info.insert(2, f'coro=<{coro}>')
if task._fut_waiter is not None: if task._fut_waiter is not None:
info.insert(2, f'wait_for={task._fut_waiter!r}') info.insert(3, f'wait_for={task._fut_waiter!r}')
return info return info
......
...@@ -277,7 +277,7 @@ class AbstractEventLoop: ...@@ -277,7 +277,7 @@ class AbstractEventLoop:
# Method scheduling a coroutine object: create a task. # Method scheduling a coroutine object: create a task.
def create_task(self, coro): def create_task(self, coro, *, name=None):
raise NotImplementedError raise NotImplementedError
# Methods for interacting with threads. # Methods for interacting with threads.
......
...@@ -13,6 +13,7 @@ import concurrent.futures ...@@ -13,6 +13,7 @@ import concurrent.futures
import contextvars import contextvars
import functools import functools
import inspect import inspect
import itertools
import types import types
import warnings import warnings
import weakref import weakref
...@@ -23,6 +24,11 @@ from . import events ...@@ -23,6 +24,11 @@ from . import events
from . import futures from . import futures
from .coroutines import coroutine from .coroutines import coroutine
# Helper to generate new task names
# This uses itertools.count() instead of a "+= 1" operation because the latter
# is not thread safe. See bpo-11866 for a longer explanation.
_task_name_counter = itertools.count(1).__next__
def current_task(loop=None): def current_task(loop=None):
"""Return a currently executed task.""" """Return a currently executed task."""
...@@ -48,6 +54,16 @@ def _all_tasks_compat(loop=None): ...@@ -48,6 +54,16 @@ def _all_tasks_compat(loop=None):
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}
def _set_task_name(task, name):
if name is not None:
try:
set_name = task.set_name
except AttributeError:
pass
else:
set_name(name)
class Task(futures._PyFuture): # Inherit Python Task implementation class Task(futures._PyFuture): # Inherit Python Task implementation
# from a Python Future implementation. # from a Python Future implementation.
...@@ -94,7 +110,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation ...@@ -94,7 +110,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
stacklevel=2) stacklevel=2)
return _all_tasks_compat(loop) return _all_tasks_compat(loop)
def __init__(self, coro, *, loop=None): def __init__(self, coro, *, loop=None, name=None):
super().__init__(loop=loop) super().__init__(loop=loop)
if self._source_traceback: if self._source_traceback:
del self._source_traceback[-1] del self._source_traceback[-1]
...@@ -104,6 +120,11 @@ class Task(futures._PyFuture): # Inherit Python Task implementation ...@@ -104,6 +120,11 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
self._log_destroy_pending = False self._log_destroy_pending = False
raise TypeError(f"a coroutine was expected, got {coro!r}") raise TypeError(f"a coroutine was expected, got {coro!r}")
if name is None:
self._name = f'Task-{_task_name_counter()}'
else:
self._name = str(name)
self._must_cancel = False self._must_cancel = False
self._fut_waiter = None self._fut_waiter = None
self._coro = coro self._coro = coro
...@@ -126,6 +147,12 @@ class Task(futures._PyFuture): # Inherit Python Task implementation ...@@ -126,6 +147,12 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
def _repr_info(self): def _repr_info(self):
return base_tasks._task_repr_info(self) return base_tasks._task_repr_info(self)
def get_name(self):
return self._name
def set_name(self, value):
self._name = str(value)
def set_result(self, result): def set_result(self, result):
raise RuntimeError('Task does not support set_result operation') raise RuntimeError('Task does not support set_result operation')
...@@ -312,13 +339,15 @@ else: ...@@ -312,13 +339,15 @@ else:
Task = _CTask = _asyncio.Task Task = _CTask = _asyncio.Task
def create_task(coro): def create_task(coro, *, name=None):
"""Schedule the execution of a coroutine object in a spawn task. """Schedule the execution of a coroutine object in a spawn task.
Return a Task object. Return a Task object.
""" """
loop = events.get_running_loop() loop = events.get_running_loop()
return loop.create_task(coro) task = loop.create_task(coro)
_set_task_name(task, name)
return task
# wait() and as_completed() similar to those in PEP 3148. # wait() and as_completed() similar to those in PEP 3148.
......
...@@ -825,6 +825,34 @@ class BaseEventLoopTests(test_utils.TestCase): ...@@ -825,6 +825,34 @@ class BaseEventLoopTests(test_utils.TestCase):
task._log_destroy_pending = False task._log_destroy_pending = False
coro.close() coro.close()
def test_create_named_task_with_default_factory(self):
async def test():
pass
loop = asyncio.new_event_loop()
task = loop.create_task(test(), name='test_task')
try:
self.assertEqual(task.get_name(), 'test_task')
finally:
loop.run_until_complete(task)
loop.close()
def test_create_named_task_with_custom_factory(self):
def task_factory(loop, coro):
return asyncio.Task(coro, loop=loop)
async def test():
pass
loop = asyncio.new_event_loop()
loop.set_task_factory(task_factory)
task = loop.create_task(test(), name='test_task')
try:
self.assertEqual(task.get_name(), 'test_task')
finally:
loop.run_until_complete(task)
loop.close()
def test_run_forever_keyboard_interrupt(self): def test_run_forever_keyboard_interrupt(self):
# Python issue #22601: ensure that the temporary task created by # Python issue #22601: ensure that the temporary task created by
# run_forever() consumes the KeyboardInterrupt and so don't log # run_forever() consumes the KeyboardInterrupt and so don't log
......
...@@ -87,8 +87,8 @@ class BaseTaskTests: ...@@ -87,8 +87,8 @@ class BaseTaskTests:
Task = None Task = None
Future = None Future = None
def new_task(self, loop, coro): def new_task(self, loop, coro, name='TestTask'):
return self.__class__.Task(coro, loop=loop) return self.__class__.Task(coro, loop=loop, name=name)
def new_future(self, loop): def new_future(self, loop):
return self.__class__.Future(loop=loop) return self.__class__.Future(loop=loop)
...@@ -295,12 +295,12 @@ class BaseTaskTests: ...@@ -295,12 +295,12 @@ class BaseTaskTests:
coro = format_coroutine(coro_qualname, 'running', src, coro = format_coroutine(coro_qualname, 'running', src,
t._source_traceback, generator=True) t._source_traceback, generator=True)
self.assertEqual(repr(t), self.assertEqual(repr(t),
'<Task pending %s cb=[<Dummy>()]>' % coro) "<Task pending name='TestTask' %s cb=[<Dummy>()]>" % coro)
# test cancelling Task # test cancelling Task
t.cancel() # Does not take immediate effect! t.cancel() # Does not take immediate effect!
self.assertEqual(repr(t), self.assertEqual(repr(t),
'<Task cancelling %s cb=[<Dummy>()]>' % coro) "<Task cancelling name='TestTask' %s cb=[<Dummy>()]>" % coro)
# test cancelled Task # test cancelled Task
self.assertRaises(asyncio.CancelledError, self.assertRaises(asyncio.CancelledError,
...@@ -308,7 +308,7 @@ class BaseTaskTests: ...@@ -308,7 +308,7 @@ class BaseTaskTests:
coro = format_coroutine(coro_qualname, 'done', src, coro = format_coroutine(coro_qualname, 'done', src,
t._source_traceback) t._source_traceback)
self.assertEqual(repr(t), self.assertEqual(repr(t),
'<Task cancelled %s>' % coro) "<Task cancelled name='TestTask' %s>" % coro)
# test finished Task # test finished Task
t = self.new_task(self.loop, notmuch()) t = self.new_task(self.loop, notmuch())
...@@ -316,7 +316,36 @@ class BaseTaskTests: ...@@ -316,7 +316,36 @@ class BaseTaskTests:
coro = format_coroutine(coro_qualname, 'done', src, coro = format_coroutine(coro_qualname, 'done', src,
t._source_traceback) t._source_traceback)
self.assertEqual(repr(t), self.assertEqual(repr(t),
"<Task finished %s result='abc'>" % coro) "<Task finished name='TestTask' %s result='abc'>" % coro)
def test_task_repr_autogenerated(self):
@asyncio.coroutine
def notmuch():
return 123
t1 = self.new_task(self.loop, notmuch(), None)
t2 = self.new_task(self.loop, notmuch(), None)
self.assertNotEqual(repr(t1), repr(t2))
match1 = re.match("^<Task pending name='Task-(\d+)'", repr(t1))
self.assertIsNotNone(match1)
match2 = re.match("^<Task pending name='Task-(\d+)'", repr(t2))
self.assertIsNotNone(match2)
# Autogenerated task names should have monotonically increasing numbers
self.assertLess(int(match1.group(1)), int(match2.group(1)))
self.loop.run_until_complete(t1)
self.loop.run_until_complete(t2)
def test_task_repr_name_not_str(self):
@asyncio.coroutine
def notmuch():
return 123
t = self.new_task(self.loop, notmuch())
t.set_name({6})
self.assertEqual(t.get_name(), '{6}')
self.loop.run_until_complete(t)
def test_task_repr_coro_decorator(self): def test_task_repr_coro_decorator(self):
self.loop.set_debug(False) self.loop.set_debug(False)
...@@ -376,7 +405,7 @@ class BaseTaskTests: ...@@ -376,7 +405,7 @@ class BaseTaskTests:
t._source_traceback, t._source_traceback,
generator=not coroutines._DEBUG) generator=not coroutines._DEBUG)
self.assertEqual(repr(t), self.assertEqual(repr(t),
'<Task pending %s cb=[<Dummy>()]>' % coro) "<Task pending name='TestTask' %s cb=[<Dummy>()]>" % coro)
self.loop.run_until_complete(t) self.loop.run_until_complete(t)
def test_task_repr_wait_for(self): def test_task_repr_wait_for(self):
...@@ -2260,6 +2289,18 @@ class BaseTaskTests: ...@@ -2260,6 +2289,18 @@ class BaseTaskTests:
self.loop.run_until_complete(coro()) self.loop.run_until_complete(coro())
def test_bare_create_named_task(self):
async def coro_noop():
pass
async def coro():
task = asyncio.create_task(coro_noop(), name='No-op')
self.assertEqual(task.get_name(), 'No-op')
await task
self.loop.run_until_complete(coro())
def test_context_1(self): def test_context_1(self):
cvar = contextvars.ContextVar('cvar', default='nope') cvar = contextvars.ContextVar('cvar', default='nope')
......
...@@ -573,6 +573,7 @@ Elliot Gorokhovsky ...@@ -573,6 +573,7 @@ Elliot Gorokhovsky
Hans de Graaff Hans de Graaff
Tim Graham Tim Graham
Kim Gräsman Kim Gräsman
Alex Grönholm
Nathaniel Gray Nathaniel Gray
Eddy De Greef Eddy De Greef
Duane Griffin Duane Griffin
...@@ -594,6 +595,7 @@ Michael Guravage ...@@ -594,6 +595,7 @@ Michael Guravage
Lars Gustäbel Lars Gustäbel
Thomas Güttler Thomas Güttler
Jonas H. Jonas H.
Antti Haapala
Joseph Hackman Joseph Hackman
Barry Haddow Barry Haddow
Philipp Hagemeister Philipp Hagemeister
......
The default asyncio task class now always has a name which can be get or set
using two new methods (:meth:`~asyncio.Task.get_name()` and
:meth:`~asyncio.Task.set_name`) and is visible in the :func:`repr` output. An
initial name can also be set using the new ``name`` keyword argument to
:func:`asyncio.create_task` or the
:meth:`~asyncio.AbstractEventLoop.create_task` method of the event loop.
If no initial name is set, the default Task implementation generates a name
like ``Task-1`` using a monotonic counter.
...@@ -37,6 +37,8 @@ static PyObject *context_kwname; ...@@ -37,6 +37,8 @@ static PyObject *context_kwname;
static PyObject *cached_running_holder; static PyObject *cached_running_holder;
static volatile uint64_t cached_running_holder_tsid; static volatile uint64_t cached_running_holder_tsid;
/* Counter for autogenerated Task names */
static uint64_t task_name_counter = 0;
/* WeakSet containing all alive tasks. */ /* WeakSet containing all alive tasks. */
static PyObject *all_tasks; static PyObject *all_tasks;
...@@ -78,6 +80,7 @@ typedef struct { ...@@ -78,6 +80,7 @@ typedef struct {
FutureObj_HEAD(task) FutureObj_HEAD(task)
PyObject *task_fut_waiter; PyObject *task_fut_waiter;
PyObject *task_coro; PyObject *task_coro;
PyObject *task_name;
PyContext *task_context; PyContext *task_context;
int task_must_cancel; int task_must_cancel;
int task_log_destroy_pending; int task_log_destroy_pending;
...@@ -1934,13 +1937,15 @@ _asyncio.Task.__init__ ...@@ -1934,13 +1937,15 @@ _asyncio.Task.__init__
coro: object coro: object
* *
loop: object = None loop: object = None
name: object = None
A coroutine wrapped in a Future. A coroutine wrapped in a Future.
[clinic start generated code]*/ [clinic start generated code]*/
static int static int
_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop) _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
/*[clinic end generated code: output=9f24774c2287fc2f input=8d132974b049593e]*/ PyObject *name)
/*[clinic end generated code: output=88b12b83d570df50 input=352a3137fe60091d]*/
{ {
if (future_init((FutureObj*)self, loop)) { if (future_init((FutureObj*)self, loop)) {
return -1; return -1;
...@@ -1969,6 +1974,18 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop) ...@@ -1969,6 +1974,18 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop)
Py_INCREF(coro); Py_INCREF(coro);
Py_XSETREF(self->task_coro, coro); Py_XSETREF(self->task_coro, coro);
if (name == Py_None) {
name = PyUnicode_FromFormat("Task-%" PRIu64, ++task_name_counter);
} else if (!PyUnicode_Check(name)) {
name = PyObject_Str(name);
} else {
Py_INCREF(name);
}
Py_XSETREF(self->task_name, name);
if (self->task_name == NULL) {
return -1;
}
if (task_call_step_soon(self, NULL)) { if (task_call_step_soon(self, NULL)) {
return -1; return -1;
} }
...@@ -1981,6 +1998,7 @@ TaskObj_clear(TaskObj *task) ...@@ -1981,6 +1998,7 @@ TaskObj_clear(TaskObj *task)
(void)FutureObj_clear((FutureObj*) task); (void)FutureObj_clear((FutureObj*) task);
Py_CLEAR(task->task_context); Py_CLEAR(task->task_context);
Py_CLEAR(task->task_coro); Py_CLEAR(task->task_coro);
Py_CLEAR(task->task_name);
Py_CLEAR(task->task_fut_waiter); Py_CLEAR(task->task_fut_waiter);
return 0; return 0;
} }
...@@ -1990,6 +2008,7 @@ TaskObj_traverse(TaskObj *task, visitproc visit, void *arg) ...@@ -1990,6 +2008,7 @@ TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
{ {
Py_VISIT(task->task_context); Py_VISIT(task->task_context);
Py_VISIT(task->task_coro); Py_VISIT(task->task_coro);
Py_VISIT(task->task_name);
Py_VISIT(task->task_fut_waiter); Py_VISIT(task->task_fut_waiter);
(void)FutureObj_traverse((FutureObj*) task, visit, arg); (void)FutureObj_traverse((FutureObj*) task, visit, arg);
return 0; return 0;
...@@ -2297,6 +2316,41 @@ _asyncio_Task_set_exception(TaskObj *self, PyObject *exception) ...@@ -2297,6 +2316,41 @@ _asyncio_Task_set_exception(TaskObj *self, PyObject *exception)
return NULL; return NULL;
} }
/*[clinic input]
_asyncio.Task.get_name
[clinic start generated code]*/
static PyObject *
_asyncio_Task_get_name_impl(TaskObj *self)
/*[clinic end generated code: output=0ecf1570c3b37a8f input=a4a6595d12f4f0f8]*/
{
if (self->task_name) {
Py_INCREF(self->task_name);
return self->task_name;
}
Py_RETURN_NONE;
}
/*[clinic input]
_asyncio.Task.set_name
value: object
/
[clinic start generated code]*/
static PyObject *
_asyncio_Task_set_name(TaskObj *self, PyObject *value)
/*[clinic end generated code: output=138a8d51e32057d6 input=a8359b6e65f8fd31]*/
{
PyObject *name = PyObject_Str(value);
if (name == NULL) {
return NULL;
}
Py_XSETREF(self->task_name, name);
Py_RETURN_NONE;
}
static void static void
TaskObj_finalize(TaskObj *task) TaskObj_finalize(TaskObj *task)
...@@ -2382,6 +2436,8 @@ static PyMethodDef TaskType_methods[] = { ...@@ -2382,6 +2436,8 @@ static PyMethodDef TaskType_methods[] = {
_ASYNCIO_TASK_GET_STACK_METHODDEF _ASYNCIO_TASK_GET_STACK_METHODDEF
_ASYNCIO_TASK_PRINT_STACK_METHODDEF _ASYNCIO_TASK_PRINT_STACK_METHODDEF
_ASYNCIO_TASK__REPR_INFO_METHODDEF _ASYNCIO_TASK__REPR_INFO_METHODDEF
_ASYNCIO_TASK_GET_NAME_METHODDEF
_ASYNCIO_TASK_SET_NAME_METHODDEF
{NULL, NULL} /* Sentinel */ {NULL, NULL} /* Sentinel */
}; };
......
...@@ -253,28 +253,30 @@ _asyncio_Future__repr_info(FutureObj *self, PyObject *Py_UNUSED(ignored)) ...@@ -253,28 +253,30 @@ _asyncio_Future__repr_info(FutureObj *self, PyObject *Py_UNUSED(ignored))
} }
PyDoc_STRVAR(_asyncio_Task___init____doc__, PyDoc_STRVAR(_asyncio_Task___init____doc__,
"Task(coro, *, loop=None)\n" "Task(coro, *, loop=None, name=None)\n"
"--\n" "--\n"
"\n" "\n"
"A coroutine wrapped in a Future."); "A coroutine wrapped in a Future.");
static int static int
_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop); _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
PyObject *name);
static int static int
_asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) _asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs)
{ {
int return_value = -1; int return_value = -1;
static const char * const _keywords[] = {"coro", "loop", NULL}; static const char * const _keywords[] = {"coro", "loop", "name", NULL};
static _PyArg_Parser _parser = {"O|$O:Task", _keywords, 0}; static _PyArg_Parser _parser = {"O|$OO:Task", _keywords, 0};
PyObject *coro; PyObject *coro;
PyObject *loop = Py_None; PyObject *loop = Py_None;
PyObject *name = Py_None;
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
&coro, &loop)) { &coro, &loop, &name)) {
goto exit; goto exit;
} }
return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop); return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop, name);
exit: exit:
return return_value; return return_value;
...@@ -500,6 +502,31 @@ PyDoc_STRVAR(_asyncio_Task_set_exception__doc__, ...@@ -500,6 +502,31 @@ PyDoc_STRVAR(_asyncio_Task_set_exception__doc__,
#define _ASYNCIO_TASK_SET_EXCEPTION_METHODDEF \ #define _ASYNCIO_TASK_SET_EXCEPTION_METHODDEF \
{"set_exception", (PyCFunction)_asyncio_Task_set_exception, METH_O, _asyncio_Task_set_exception__doc__}, {"set_exception", (PyCFunction)_asyncio_Task_set_exception, METH_O, _asyncio_Task_set_exception__doc__},
PyDoc_STRVAR(_asyncio_Task_get_name__doc__,
"get_name($self, /)\n"
"--\n"
"\n");
#define _ASYNCIO_TASK_GET_NAME_METHODDEF \
{"get_name", (PyCFunction)_asyncio_Task_get_name, METH_NOARGS, _asyncio_Task_get_name__doc__},
static PyObject *
_asyncio_Task_get_name_impl(TaskObj *self);
static PyObject *
_asyncio_Task_get_name(TaskObj *self, PyObject *Py_UNUSED(ignored))
{
return _asyncio_Task_get_name_impl(self);
}
PyDoc_STRVAR(_asyncio_Task_set_name__doc__,
"set_name($self, value, /)\n"
"--\n"
"\n");
#define _ASYNCIO_TASK_SET_NAME_METHODDEF \
{"set_name", (PyCFunction)_asyncio_Task_set_name, METH_O, _asyncio_Task_set_name__doc__},
PyDoc_STRVAR(_asyncio__get_running_loop__doc__, PyDoc_STRVAR(_asyncio__get_running_loop__doc__,
"_get_running_loop($module, /)\n" "_get_running_loop($module, /)\n"
"--\n" "--\n"
...@@ -711,4 +738,4 @@ _asyncio__leave_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, ...@@ -711,4 +738,4 @@ _asyncio__leave_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=b6148b0134e7a819 input=a9049054013a1b77]*/ /*[clinic end generated code: output=67da879c9f841505 input=a9049054013a1b77]*/
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