From 23d2c421fe81825037c7e63a1d91c7bec8e265d6 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sat, 28 Dec 2024 10:51:42 +0000 Subject: [PATCH 01/10] support eager_start kwarg in create_eager_task_factory --- Doc/library/asyncio-eventloop.rst | 10 +++++- Lib/asyncio/base_events.py | 3 +- Lib/asyncio/tasks.py | 4 +-- .../test_asyncio/test_eager_task_factory.py | 18 ++++++++++ Lib/test/test_asyncio/test_tasks.py | 33 +++++++++++++++++-- 5 files changed, 61 insertions(+), 7 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 15ef33e195904d..701b8084db7a8d 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -363,7 +363,7 @@ Creating Futures and Tasks .. 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 ` *coro*. Return a :class:`Task` object. @@ -379,12 +379,20 @@ Creating Futures and Tasks custom :class:`contextvars.Context` for the *coro* to run in. 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 the default ``None`` is passed the mode set + by :meth:`loop.set_task_factory` will be used. + .. versionchanged:: 3.8 Added the *name* parameter. .. versionchanged:: 3.11 Added the *context* parameter. + .. versionchanged:: next + Added the *eager_start* parameter. + .. method:: loop.set_task_factory(factory) Set a task factory that will be used by diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index ed852421e44212..405c70d3b7fca4 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -459,8 +459,7 @@ def create_future(self): return futures.Future(loop=self) def create_task(self, coro, **kwargs): - """Schedule a coroutine object. - + """Schedule or begin executing a coroutine object. Return a task object. """ self._check_closed() diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 2112dd4b99d17f..83e62608b885a0 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -1008,9 +1008,9 @@ def create_eager_task_factory(custom_task_constructor): 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( - coro, loop=loop, name=name, context=context, eager_start=True) + coro, loop=loop, eager_start=eager_start, **kwargs) return factory diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py index 10450c11b68279..d82de3da5fb2d9 100644 --- a/Lib/test/test_asyncio/test_eager_task_factory.py +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -263,6 +263,24 @@ async def 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): Task = tasks._PyTask diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 7a052817766a07..4d4cac1b26d7d0 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -89,8 +89,8 @@ class BaseTaskTests: Future = None all_tasks = None - def new_task(self, loop, coro, name='TestTask', context=None): - return self.__class__.Task(coro, loop=loop, name=name, context=context) + def new_task(self, loop, coro, name='TestTask', context=None, eager_start=None): + return self.__class__.Task(coro, loop=loop, name=name, context=context, eager_start=eager_start) def new_future(self, loop): return self.__class__.Future(loop=loop) @@ -2667,6 +2667,35 @@ async def main(): self.assertEqual([None, 1, 2], ret) + def test_eager_start_true(self): + name = None + + async def asyncfn(): + nonlocal name + name = asyncio.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 = asyncio.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): loop = asyncio.new_event_loop() coro = coroutine_function() From da5cab36d0e36835e13794ee5aee37d1d7847c1d Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 28 Dec 2024 11:01:44 +0000 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst diff --git a/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst new file mode 100644 index 00000000000000..3eb92b31078a52 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst @@ -0,0 +1 @@ +Add `eager_start` keyword argument to :func:`asyncio.create_task` From 7bce40107ba868d0c8edf76c880ad79d9a33c34f Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sat, 28 Dec 2024 11:08:57 +0000 Subject: [PATCH 03/10] Update Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst --- .../next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst index 3eb92b31078a52..1d127197305a13 100644 --- a/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst +++ b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst @@ -1 +1 @@ -Add `eager_start` keyword argument to :func:`asyncio.create_task` +Add ``eager_start`` keyword argument to :func:`loop.create_task` From 8ad26fc8f177531d5d3b813a20c3369f7c3313b5 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 21 Jan 2025 09:27:54 +0000 Subject: [PATCH 04/10] Update Lib/asyncio/base_events.py --- Lib/asyncio/base_events.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 405c70d3b7fca4..00d6ac017e67a6 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -460,6 +460,7 @@ def create_future(self): def create_task(self, coro, **kwargs): """Schedule or begin executing a coroutine object. + Return a task object. """ self._check_closed() From 90f9ef206db419ccd1173eecd12759ab1968c1c2 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 21 Jan 2025 09:28:54 +0000 Subject: [PATCH 05/10] Update Lib/asyncio/tasks.py --- Lib/asyncio/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 83e62608b885a0..8850e2dc947f74 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -1008,7 +1008,7 @@ def create_eager_task_factory(custom_task_constructor): used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`. """ - def factory(loop, coro, eager_start=True, **kwargs): + def factory(loop, coro, *, eager_start=True, **kwargs): return custom_task_constructor( coro, loop=loop, eager_start=eager_start, **kwargs) From 11076083087f8d577aed0d448ba7b9bf64ef3eb3 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 21 Jan 2025 09:34:04 +0000 Subject: [PATCH 06/10] use presense rather than None-ness to determine default eager_start behaviour --- Doc/library/asyncio-eventloop.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 701b8084db7a8d..a4a1c0786a6730 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -363,7 +363,7 @@ Creating Futures and Tasks .. versionadded:: 3.5.2 -.. method:: loop.create_task(coro, *, name=None, context=None, eager_start=None) +.. method:: loop.create_task(coro, *, name=None, context=None, eager_start=...) Schedule the execution of :ref:`coroutine ` *coro*. Return a :class:`Task` object. @@ -381,7 +381,7 @@ Creating Futures and Tasks 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 the default ``None`` is passed the mode set + or be scheduled later. If the *eager_start* is not passed the mode set by :meth:`loop.set_task_factory` will be used. .. versionchanged:: 3.8 From ec3bd1409542538a124d2df4f0cbf0a4a3f496e5 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 21 Jan 2025 09:34:29 +0000 Subject: [PATCH 07/10] Update Doc/library/asyncio-eventloop.rst --- Doc/library/asyncio-eventloop.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index a4a1c0786a6730..be97e7dc21936a 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -381,7 +381,7 @@ Creating Futures and Tasks 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 the *eager_start* is not passed the mode set + 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 From d24d43b9803c12c8cc11b609b015c2f7e0ce20e6 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 21 Jan 2025 09:48:33 +0000 Subject: [PATCH 08/10] Update Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst --- .../next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst index 1d127197305a13..8d662d6a8d659c 100644 --- a/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst +++ b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst @@ -1 +1 @@ -Add ``eager_start`` keyword argument to :func:`loop.create_task` +Add ``eager_start`` keyword argument to :meth:`loop.create_task` From 4a4ad1beb377b72ddb3b2b07013c53d0b78b5ba8 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sun, 26 Jan 2025 09:36:46 +0000 Subject: [PATCH 09/10] Apply suggestions from code review --- .../next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst index 8d662d6a8d659c..93b2a74019d2aa 100644 --- a/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst +++ b/Misc/NEWS.d/next/Library/2024-12-28-11-01-36.gh-issue-128307.BRCYTA.rst @@ -1 +1 @@ -Add ``eager_start`` keyword argument to :meth:`loop.create_task` +Add ``eager_start`` keyword argument to :meth:`asyncio.loop.create_task` From 3175aae0e4812388c64aee72f8cef6331842e99e Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 25 Mar 2025 08:44:48 +0000 Subject: [PATCH 10/10] use self.current_task --- Lib/test/test_asyncio/test_tasks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 65945c9dbcb6c7..0735a4867dd654 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -2691,7 +2691,7 @@ def test_eager_start_true(self): async def asyncfn(): nonlocal name - name = asyncio.current_task().get_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") @@ -2704,7 +2704,7 @@ def test_eager_start_false(self): async def asyncfn(): nonlocal name - name = asyncio.current_task().get_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")