bpo-34270: Make it possible to name asyncio tasks (GH-8547)
Co-authored-by: Antti Haapala <antti.haapala@anttipatterns.com>
This commit is contained in:
parent
52dee687af
commit
cca4eec3c0
|
@ -246,7 +246,7 @@ Futures
|
|||
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
|
||||
a future. Return a :class:`Task` object.
|
||||
|
@ -255,8 +255,14 @@ Tasks
|
|||
interoperability. In this case, the result type is a subclass of
|
||||
: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
|
||||
|
||||
.. versionchanged:: 3.8
|
||||
Added the ``name`` parameter.
|
||||
|
||||
.. method:: AbstractEventLoop.set_task_factory(factory)
|
||||
|
||||
Set a task factory that will be used by
|
||||
|
|
|
@ -387,10 +387,13 @@ with the result.
|
|||
Task
|
||||
----
|
||||
|
||||
.. function:: create_task(coro)
|
||||
.. function:: create_task(coro, \*, name=None)
|
||||
|
||||
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,
|
||||
:exc:`RuntimeError` is raised if there is no running loop in
|
||||
|
@ -398,7 +401,10 @@ Task
|
|||
|
||||
.. 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>`,
|
||||
subclass of :class:`Future`.
|
||||
|
@ -438,6 +444,9 @@ Task
|
|||
.. versionchanged:: 3.7
|
||||
Added support for the :mod:`contextvars` module.
|
||||
|
||||
.. versionchanged:: 3.8
|
||||
Added the ``name`` parameter.
|
||||
|
||||
.. classmethod:: all_tasks(loop=None)
|
||||
|
||||
Return a set of all tasks for an event loop.
|
||||
|
@ -504,6 +513,27 @@ Task
|
|||
get_stack(). The file argument is an I/O stream to which the output
|
||||
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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -249,6 +249,13 @@ Changes in the Python API
|
|||
* ``PyGC_Head`` struct is changed completely. All code touched the
|
||||
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
|
||||
------------------------
|
||||
|
|
|
@ -384,18 +384,20 @@ class BaseEventLoop(events.AbstractEventLoop):
|
|||
"""Create a Future object attached to the loop."""
|
||||
return futures.Future(loop=self)
|
||||
|
||||
def create_task(self, coro):
|
||||
def create_task(self, coro, *, name=None):
|
||||
"""Schedule a coroutine object.
|
||||
|
||||
Return a task object.
|
||||
"""
|
||||
self._check_closed()
|
||||
if self._task_factory is None:
|
||||
task = tasks.Task(coro, loop=self)
|
||||
task = tasks.Task(coro, loop=self, name=name)
|
||||
if task._source_traceback:
|
||||
del task._source_traceback[-1]
|
||||
else:
|
||||
task = self._task_factory(self, coro)
|
||||
tasks._set_task_name(task, name)
|
||||
|
||||
return task
|
||||
|
||||
def set_task_factory(self, factory):
|
||||
|
|
|
@ -12,11 +12,13 @@ def _task_repr_info(task):
|
|||
# replace status
|
||||
info[0] = 'cancelling'
|
||||
|
||||
info.insert(1, 'name=%r' % task.get_name())
|
||||
|
||||
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:
|
||||
info.insert(2, f'wait_for={task._fut_waiter!r}')
|
||||
info.insert(3, f'wait_for={task._fut_waiter!r}')
|
||||
return info
|
||||
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ class AbstractEventLoop:
|
|||
|
||||
# Method scheduling a coroutine object: create a task.
|
||||
|
||||
def create_task(self, coro):
|
||||
def create_task(self, coro, *, name=None):
|
||||
raise NotImplementedError
|
||||
|
||||
# Methods for interacting with threads.
|
||||
|
|
|
@ -13,6 +13,7 @@ import concurrent.futures
|
|||
import contextvars
|
||||
import functools
|
||||
import inspect
|
||||
import itertools
|
||||
import types
|
||||
import warnings
|
||||
import weakref
|
||||
|
@ -23,6 +24,11 @@ from . import events
|
|||
from . import futures
|
||||
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):
|
||||
"""Return a currently executed task."""
|
||||
|
@ -48,6 +54,16 @@ def _all_tasks_compat(loop=None):
|
|||
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
|
||||
# from a Python Future implementation.
|
||||
|
||||
|
@ -94,7 +110,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
|
|||
stacklevel=2)
|
||||
return _all_tasks_compat(loop)
|
||||
|
||||
def __init__(self, coro, *, loop=None):
|
||||
def __init__(self, coro, *, loop=None, name=None):
|
||||
super().__init__(loop=loop)
|
||||
if self._source_traceback:
|
||||
del self._source_traceback[-1]
|
||||
|
@ -104,6 +120,11 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
|
|||
self._log_destroy_pending = False
|
||||
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._fut_waiter = None
|
||||
self._coro = coro
|
||||
|
@ -126,6 +147,12 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
|
|||
def _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):
|
||||
raise RuntimeError('Task does not support set_result operation')
|
||||
|
||||
|
@ -312,13 +339,15 @@ else:
|
|||
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.
|
||||
|
||||
Return a Task object.
|
||||
"""
|
||||
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.
|
||||
|
|
|
@ -825,6 +825,34 @@ class BaseEventLoopTests(test_utils.TestCase):
|
|||
task._log_destroy_pending = False
|
||||
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):
|
||||
# Python issue #22601: ensure that the temporary task created by
|
||||
# run_forever() consumes the KeyboardInterrupt and so don't log
|
||||
|
|
|
@ -87,8 +87,8 @@ class BaseTaskTests:
|
|||
Task = None
|
||||
Future = None
|
||||
|
||||
def new_task(self, loop, coro):
|
||||
return self.__class__.Task(coro, loop=loop)
|
||||
def new_task(self, loop, coro, name='TestTask'):
|
||||
return self.__class__.Task(coro, loop=loop, name=name)
|
||||
|
||||
def new_future(self, loop):
|
||||
return self.__class__.Future(loop=loop)
|
||||
|
@ -295,12 +295,12 @@ class BaseTaskTests:
|
|||
coro = format_coroutine(coro_qualname, 'running', src,
|
||||
t._source_traceback, generator=True)
|
||||
self.assertEqual(repr(t),
|
||||
'<Task pending %s cb=[<Dummy>()]>' % coro)
|
||||
"<Task pending name='TestTask' %s cb=[<Dummy>()]>" % coro)
|
||||
|
||||
# test cancelling Task
|
||||
t.cancel() # Does not take immediate effect!
|
||||
self.assertEqual(repr(t),
|
||||
'<Task cancelling %s cb=[<Dummy>()]>' % coro)
|
||||
"<Task cancelling name='TestTask' %s cb=[<Dummy>()]>" % coro)
|
||||
|
||||
# test cancelled Task
|
||||
self.assertRaises(asyncio.CancelledError,
|
||||
|
@ -308,7 +308,7 @@ class BaseTaskTests:
|
|||
coro = format_coroutine(coro_qualname, 'done', src,
|
||||
t._source_traceback)
|
||||
self.assertEqual(repr(t),
|
||||
'<Task cancelled %s>' % coro)
|
||||
"<Task cancelled name='TestTask' %s>" % coro)
|
||||
|
||||
# test finished Task
|
||||
t = self.new_task(self.loop, notmuch())
|
||||
|
@ -316,7 +316,36 @@ class BaseTaskTests:
|
|||
coro = format_coroutine(coro_qualname, 'done', src,
|
||||
t._source_traceback)
|
||||
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):
|
||||
self.loop.set_debug(False)
|
||||
|
@ -376,7 +405,7 @@ class BaseTaskTests:
|
|||
t._source_traceback,
|
||||
generator=not coroutines._DEBUG)
|
||||
self.assertEqual(repr(t),
|
||||
'<Task pending %s cb=[<Dummy>()]>' % coro)
|
||||
"<Task pending name='TestTask' %s cb=[<Dummy>()]>" % coro)
|
||||
self.loop.run_until_complete(t)
|
||||
|
||||
def test_task_repr_wait_for(self):
|
||||
|
@ -2260,6 +2289,18 @@ class BaseTaskTests:
|
|||
|
||||
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):
|
||||
cvar = contextvars.ContextVar('cvar', default='nope')
|
||||
|
||||
|
|
|
@ -573,6 +573,7 @@ Elliot Gorokhovsky
|
|||
Hans de Graaff
|
||||
Tim Graham
|
||||
Kim Gräsman
|
||||
Alex Grönholm
|
||||
Nathaniel Gray
|
||||
Eddy De Greef
|
||||
Duane Griffin
|
||||
|
@ -594,6 +595,7 @@ Michael Guravage
|
|||
Lars Gustäbel
|
||||
Thomas Güttler
|
||||
Jonas H.
|
||||
Antti Haapala
|
||||
Joseph Hackman
|
||||
Barry Haddow
|
||||
Philipp Hagemeister
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
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;
|
|||
static PyObject *cached_running_holder;
|
||||
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. */
|
||||
static PyObject *all_tasks;
|
||||
|
@ -78,6 +80,7 @@ typedef struct {
|
|||
FutureObj_HEAD(task)
|
||||
PyObject *task_fut_waiter;
|
||||
PyObject *task_coro;
|
||||
PyObject *task_name;
|
||||
PyContext *task_context;
|
||||
int task_must_cancel;
|
||||
int task_log_destroy_pending;
|
||||
|
@ -1934,13 +1937,15 @@ _asyncio.Task.__init__
|
|||
coro: object
|
||||
*
|
||||
loop: object = None
|
||||
name: object = None
|
||||
|
||||
A coroutine wrapped in a Future.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static int
|
||||
_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop)
|
||||
/*[clinic end generated code: output=9f24774c2287fc2f input=8d132974b049593e]*/
|
||||
_asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
|
||||
PyObject *name)
|
||||
/*[clinic end generated code: output=88b12b83d570df50 input=352a3137fe60091d]*/
|
||||
{
|
||||
if (future_init((FutureObj*)self, loop)) {
|
||||
return -1;
|
||||
|
@ -1969,6 +1974,18 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop)
|
|||
Py_INCREF(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)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1981,6 +1998,7 @@ TaskObj_clear(TaskObj *task)
|
|||
(void)FutureObj_clear((FutureObj*) task);
|
||||
Py_CLEAR(task->task_context);
|
||||
Py_CLEAR(task->task_coro);
|
||||
Py_CLEAR(task->task_name);
|
||||
Py_CLEAR(task->task_fut_waiter);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1990,6 +2008,7 @@ TaskObj_traverse(TaskObj *task, visitproc visit, void *arg)
|
|||
{
|
||||
Py_VISIT(task->task_context);
|
||||
Py_VISIT(task->task_coro);
|
||||
Py_VISIT(task->task_name);
|
||||
Py_VISIT(task->task_fut_waiter);
|
||||
(void)FutureObj_traverse((FutureObj*) task, visit, arg);
|
||||
return 0;
|
||||
|
@ -2297,6 +2316,41 @@ _asyncio_Task_set_exception(TaskObj *self, PyObject *exception)
|
|||
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
|
||||
TaskObj_finalize(TaskObj *task)
|
||||
|
@ -2382,6 +2436,8 @@ static PyMethodDef TaskType_methods[] = {
|
|||
_ASYNCIO_TASK_GET_STACK_METHODDEF
|
||||
_ASYNCIO_TASK_PRINT_STACK_METHODDEF
|
||||
_ASYNCIO_TASK__REPR_INFO_METHODDEF
|
||||
_ASYNCIO_TASK_GET_NAME_METHODDEF
|
||||
_ASYNCIO_TASK_SET_NAME_METHODDEF
|
||||
{NULL, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
|
@ -253,28 +253,30 @@ _asyncio_Future__repr_info(FutureObj *self, PyObject *Py_UNUSED(ignored))
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(_asyncio_Task___init____doc__,
|
||||
"Task(coro, *, loop=None)\n"
|
||||
"Task(coro, *, loop=None, name=None)\n"
|
||||
"--\n"
|
||||
"\n"
|
||||
"A coroutine wrapped in a Future.");
|
||||
|
||||
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
|
||||
_asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
int return_value = -1;
|
||||
static const char * const _keywords[] = {"coro", "loop", NULL};
|
||||
static _PyArg_Parser _parser = {"O|$O:Task", _keywords, 0};
|
||||
static const char * const _keywords[] = {"coro", "loop", "name", NULL};
|
||||
static _PyArg_Parser _parser = {"O|$OO:Task", _keywords, 0};
|
||||
PyObject *coro;
|
||||
PyObject *loop = Py_None;
|
||||
PyObject *name = Py_None;
|
||||
|
||||
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
|
||||
&coro, &loop)) {
|
||||
&coro, &loop, &name)) {
|
||||
goto exit;
|
||||
}
|
||||
return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop);
|
||||
return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop, name);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
|
@ -500,6 +502,31 @@ PyDoc_STRVAR(_asyncio_Task_set_exception__doc__,
|
|||
#define _ASYNCIO_TASK_SET_EXCEPTION_METHODDEF \
|
||||
{"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__,
|
||||
"_get_running_loop($module, /)\n"
|
||||
"--\n"
|
||||
|
@ -711,4 +738,4 @@ _asyncio__leave_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs,
|
|||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=b6148b0134e7a819 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=67da879c9f841505 input=a9049054013a1b77]*/
|
||||
|
|
Loading…
Reference in New Issue