mirror of
https://github.com/python/cpython.git
synced 2025-08-27 04:05:34 +00:00
gh-128307: Support eager_start=<bool> in create_eager_task_factory and various create_task functions (#128306)
Some create_task() functions were changed from `name=None, context=None` to `**kwargs`. Co-authored-by: Guido van Rossum <gvanrossum@gmail.com>
This commit is contained in:
parent
c4cc5d58ae
commit
08d7687094
7 changed files with 85 additions and 19 deletions
|
@ -361,7 +361,7 @@ Creating Futures and Tasks
|
||||||
|
|
||||||
.. versionadded:: 3.5.2
|
.. versionadded:: 3.5.2
|
||||||
|
|
||||||
.. method:: loop.create_task(coro, *, name=None, context=None)
|
.. method:: loop.create_task(coro, *, name=None, context=None, eager_start=None)
|
||||||
|
|
||||||
Schedule the execution of :ref:`coroutine <coroutine>` *coro*.
|
Schedule the execution of :ref:`coroutine <coroutine>` *coro*.
|
||||||
Return a :class:`Task` object.
|
Return a :class:`Task` object.
|
||||||
|
@ -377,12 +377,20 @@ Creating Futures and Tasks
|
||||||
custom :class:`contextvars.Context` for the *coro* to run in.
|
custom :class:`contextvars.Context` for the *coro* to run in.
|
||||||
The current context copy is created when no *context* is provided.
|
The current context copy is created when no *context* is provided.
|
||||||
|
|
||||||
|
An optional keyword-only *eager_start* argument allows specifying
|
||||||
|
if the task should execute eagerly during the call to create_task,
|
||||||
|
or be scheduled later. If *eager_start* is not passed the mode set
|
||||||
|
by :meth:`loop.set_task_factory` will be used.
|
||||||
|
|
||||||
.. versionchanged:: 3.8
|
.. versionchanged:: 3.8
|
||||||
Added the *name* parameter.
|
Added the *name* parameter.
|
||||||
|
|
||||||
.. versionchanged:: 3.11
|
.. versionchanged:: 3.11
|
||||||
Added the *context* parameter.
|
Added the *context* parameter.
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
Added the *eager_start* parameter.
|
||||||
|
|
||||||
.. method:: loop.set_task_factory(factory)
|
.. method:: loop.set_task_factory(factory)
|
||||||
|
|
||||||
Set a task factory that will be used by
|
Set a task factory that will be used by
|
||||||
|
|
|
@ -459,7 +459,7 @@ class BaseEventLoop(events.AbstractEventLoop):
|
||||||
return futures.Future(loop=self)
|
return futures.Future(loop=self)
|
||||||
|
|
||||||
def create_task(self, coro, **kwargs):
|
def create_task(self, coro, **kwargs):
|
||||||
"""Schedule a coroutine object.
|
"""Schedule or begin executing a coroutine object.
|
||||||
|
|
||||||
Return a task object.
|
Return a task object.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -179,7 +179,7 @@ class TaskGroup:
|
||||||
exc = None
|
exc = None
|
||||||
|
|
||||||
|
|
||||||
def create_task(self, coro, *, name=None, context=None):
|
def create_task(self, coro, **kwargs):
|
||||||
"""Create a new task in this group and return it.
|
"""Create a new task in this group and return it.
|
||||||
|
|
||||||
Similar to `asyncio.create_task`.
|
Similar to `asyncio.create_task`.
|
||||||
|
@ -193,10 +193,7 @@ class TaskGroup:
|
||||||
if self._aborting:
|
if self._aborting:
|
||||||
coro.close()
|
coro.close()
|
||||||
raise RuntimeError(f"TaskGroup {self!r} is shutting down")
|
raise RuntimeError(f"TaskGroup {self!r} is shutting down")
|
||||||
if context is None:
|
task = self._loop.create_task(coro, **kwargs)
|
||||||
task = self._loop.create_task(coro, name=name)
|
|
||||||
else:
|
|
||||||
task = self._loop.create_task(coro, name=name, context=context)
|
|
||||||
|
|
||||||
futures.future_add_to_awaited_by(task, self._parent_task)
|
futures.future_add_to_awaited_by(task, self._parent_task)
|
||||||
|
|
||||||
|
|
|
@ -386,19 +386,13 @@ else:
|
||||||
Task = _CTask = _asyncio.Task
|
Task = _CTask = _asyncio.Task
|
||||||
|
|
||||||
|
|
||||||
def create_task(coro, *, name=None, context=None):
|
def create_task(coro, **kwargs):
|
||||||
"""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()
|
||||||
if context is None:
|
return loop.create_task(coro, **kwargs)
|
||||||
# Use legacy API if context is not needed
|
|
||||||
task = loop.create_task(coro, name=name)
|
|
||||||
else:
|
|
||||||
task = loop.create_task(coro, name=name, context=context)
|
|
||||||
|
|
||||||
return task
|
|
||||||
|
|
||||||
|
|
||||||
# wait() and as_completed() similar to those in PEP 3148.
|
# wait() and as_completed() similar to those in PEP 3148.
|
||||||
|
@ -1030,9 +1024,9 @@ def create_eager_task_factory(custom_task_constructor):
|
||||||
used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`.
|
used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def factory(loop, coro, *, name=None, context=None):
|
def factory(loop, coro, *, eager_start=True, **kwargs):
|
||||||
return custom_task_constructor(
|
return custom_task_constructor(
|
||||||
coro, loop=loop, name=name, context=context, eager_start=True)
|
coro, loop=loop, eager_start=eager_start, **kwargs)
|
||||||
|
|
||||||
return factory
|
return factory
|
||||||
|
|
||||||
|
|
|
@ -263,6 +263,24 @@ class EagerTaskFactoryLoopTests:
|
||||||
|
|
||||||
self.run_coro(run())
|
self.run_coro(run())
|
||||||
|
|
||||||
|
def test_eager_start_false(self):
|
||||||
|
name = None
|
||||||
|
|
||||||
|
async def asyncfn():
|
||||||
|
nonlocal name
|
||||||
|
name = asyncio.current_task().get_name()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
t = asyncio.get_running_loop().create_task(
|
||||||
|
asyncfn(), eager_start=False, name="example"
|
||||||
|
)
|
||||||
|
self.assertFalse(t.done())
|
||||||
|
self.assertIsNone(name)
|
||||||
|
await t
|
||||||
|
self.assertEqual(name, "example")
|
||||||
|
|
||||||
|
self.run_coro(main())
|
||||||
|
|
||||||
|
|
||||||
class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase):
|
class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase):
|
||||||
Task = tasks._PyTask
|
Task = tasks._PyTask
|
||||||
|
@ -505,5 +523,24 @@ class EagerCTaskTests(BaseEagerTaskFactoryTests, test_utils.TestCase):
|
||||||
asyncio.current_task = asyncio.tasks.current_task = self._current_task
|
asyncio.current_task = asyncio.tasks.current_task = self._current_task
|
||||||
return super().tearDown()
|
return super().tearDown()
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultTaskFactoryEagerStart(test_utils.TestCase):
|
||||||
|
def test_eager_start_true_with_default_factory(self):
|
||||||
|
name = None
|
||||||
|
|
||||||
|
async def asyncfn():
|
||||||
|
nonlocal name
|
||||||
|
name = asyncio.current_task().get_name()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
t = asyncio.get_running_loop().create_task(
|
||||||
|
asyncfn(), eager_start=True, name="example"
|
||||||
|
)
|
||||||
|
self.assertTrue(t.done())
|
||||||
|
self.assertEqual(name, "example")
|
||||||
|
await t
|
||||||
|
|
||||||
|
asyncio.run(main(), loop_factory=asyncio.EventLoop)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -89,8 +89,8 @@ class BaseTaskTests:
|
||||||
Future = None
|
Future = None
|
||||||
all_tasks = None
|
all_tasks = None
|
||||||
|
|
||||||
def new_task(self, loop, coro, name='TestTask', context=None):
|
def new_task(self, loop, coro, name='TestTask', context=None, eager_start=None):
|
||||||
return self.__class__.Task(coro, loop=loop, name=name, context=context)
|
return self.__class__.Task(coro, loop=loop, name=name, context=context, eager_start=eager_start)
|
||||||
|
|
||||||
def new_future(self, loop):
|
def new_future(self, loop):
|
||||||
return self.__class__.Future(loop=loop)
|
return self.__class__.Future(loop=loop)
|
||||||
|
@ -2686,6 +2686,35 @@ class BaseTaskTests:
|
||||||
|
|
||||||
self.assertEqual([None, 1, 2], ret)
|
self.assertEqual([None, 1, 2], ret)
|
||||||
|
|
||||||
|
def test_eager_start_true(self):
|
||||||
|
name = None
|
||||||
|
|
||||||
|
async def asyncfn():
|
||||||
|
nonlocal name
|
||||||
|
name = self.current_task().get_name()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
t = self.new_task(coro=asyncfn(), loop=asyncio.get_running_loop(), eager_start=True, name="example")
|
||||||
|
self.assertTrue(t.done())
|
||||||
|
self.assertEqual(name, "example")
|
||||||
|
await t
|
||||||
|
|
||||||
|
def test_eager_start_false(self):
|
||||||
|
name = None
|
||||||
|
|
||||||
|
async def asyncfn():
|
||||||
|
nonlocal name
|
||||||
|
name = self.current_task().get_name()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
t = self.new_task(coro=asyncfn(), loop=asyncio.get_running_loop(), eager_start=False, name="example")
|
||||||
|
self.assertFalse(t.done())
|
||||||
|
self.assertIsNone(name)
|
||||||
|
await t
|
||||||
|
self.assertEqual(name, "example")
|
||||||
|
|
||||||
|
asyncio.run(main(), loop_factory=asyncio.EventLoop)
|
||||||
|
|
||||||
def test_get_coro(self):
|
def test_get_coro(self):
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
coro = coroutine_function()
|
coro = coroutine_function()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add ``eager_start`` keyword argument to :meth:`asyncio.loop.create_task`
|
Loading…
Add table
Add a link
Reference in a new issue