Skip to content

create_task(name=...) silently fails to set name with custom task_factory after gh-128308 #132593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
sergiosacj opened this issue Apr 16, 2025 · 4 comments
Labels
stdlib Python modules in the Lib dir topic-asyncio type-bug An unexpected behavior, bug, or error

Comments

@sergiosacj
Copy link

sergiosacj commented Apr 16, 2025

Bug report

Bug description:

During a rebuild of all packages in Debian unstable, the uvloop test suite failed due to a new behavior in asyncio.

This suite runs each test twice: once with uvloop implementation (which passes) and once with Python’s asyncio implementation (which fails).

Since

Commit: 38a99568763604ccec5d5027f0658100ad76876f
PR: https://github.com/python/cpython/pull/128768

asyncio.BaseEventLoop.create_task() no longer calls set_name(name). This breaks compatibility with any factory that does not set the name manually.

Expected behavior

When using create_task(..., name="example name"), the task's name should always be set - even when using a custom task factory - as it was before the regression.

Actual behavior

With a custom factory that returns a subclassed asyncio.Task, the task name is None unless the factory manually calls set_name(name). This is a silent behavioral change that breaks code relying on set_name() being called by the event loop.

My Environment

Python version: 3.13.2
Debian testing

Script to reproduce

import asyncio

async def main():
    names = []

    async def get_name():
        names.append(asyncio.current_task().get_name())

    async with asyncio.TaskGroup() as tg:
        tg.create_task(get_name(), name="example name")

    print(names)

asyncio.run(main())  # Output: ['example name']

def factory():
    loop = asyncio.new_event_loop()
    loop.set_task_factory(asyncio.eager_task_factory)
    return loop

asyncio.run(main(), loop_factory=factory)  # Output: ['example name']

# Fails silently with custom task_factory
result = None

class MyTask(asyncio.Task):
    def set_name(self, name):
        global result
        print(name) # never reached
        result = name + "!"

    def get_name(self):
        global result
        return result

def loop_factory():
    loop = asyncio.new_event_loop()
    loop.set_task_factory(asyncio.create_eager_task_factory(MyTask))
    return loop

asyncio.run(main(), loop_factory=loop_factory)  # Output: ['None']

CPython versions tested on:

3.13

Operating systems tested on:

Linux

@sergiosacj sergiosacj added the type-bug An unexpected behavior, bug, or error label Apr 16, 2025
@github-project-automation github-project-automation bot moved this to Todo in asyncio Apr 16, 2025
@kthreadd
Copy link

Hi @sergiosacj

Yes, from #128308 on, the asyncio.BaseEventLoop.create_task() no longer calls set_name().

The name setting operation is actually done in the C function during calling create_task(..., name="example name"), not set by `set_name.

And by the way, from the code you supplied, the function get_name overwritten by MyTask, so it seems that it's the reason why names.append(asyncio.current_task().get_name()) gets None.

So, you could get correct name example name if you have a correct get_name, even you didn't set name manually via set_name(), because the name will be set by calling create_task(..., name="example name").

@sergiosacj
Copy link
Author

The name setting operation is actually done in the C function during calling create_task(..., name="example name"), not set by `set_name.

Thanks @kthreadd, I misinterpreted then.

When I read the documentation, I thought set_name should be called in this scenario. Maybe the sentence below should be updated?

"If name is not None, it is set as the name of the task using Task.set_name()"

And by the way, from the code you supplied, the function get_name overwritten by MyTask, so it seems that it's the reason why names.append(asyncio.current_task().get_name()) gets None.

That's right, this code assumed that set_name was called inside create_task. I made this example based on this test here.

@kthreadd
Copy link

kthreadd commented Apr 17, 2025

@sergiosacj, ok, I also noticed that the out of date description in document asyncio.create_task, for the same, test case is also out of date test_set_task_name

Both of them need to be updated I believe.

@picnixz picnixz added the stdlib Python modules in the Lib dir label Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir topic-asyncio type-bug An unexpected behavior, bug, or error
Projects
Status: Todo
Development

No branches or pull requests

4 participants