This rule raises when a TaskGroup or Nursery body contains only a single call to .start or .start_soon without passing itself as a parameter.

Why is this an issue?

TaskGroup and Nursery are powerful tools for structured concurrency that automatically manage the lifecycle of multiple concurrent tasks. However, when they are used to spawn only a single task that doesn’t need the nursery/TaskGroup instance itself, they add unnecessary overhead and complexity.

The main issues with using TaskGroup and Nursery for single tasks are:

What is the potential impact?

How to fix it in Asyncio

Replace the TaskGroup with a direct function call when the TaskGroup body contains only a single create_task() call.

Code examples

Noncompliant code example

import asyncio

async def worker_task():
    await asyncio.sleep(1)

async def main():
    # Unnecessary TaskGroup for a single task
    async with asyncio.TaskGroup() as tg:
        tg.create_task(worker_task())

Compliant solution

import asyncio

async def worker_task():
    await asyncio.sleep(1)

async def main():
    # Direct function call is simpler and more efficient
    await worker_task()

How to fix it in Trio

Replace the nursery with a direct function call when the nursery body contains only a single start_soon() or start() call.

Code examples

Noncompliant code example

import trio

async def worker_task():
    await trio.sleep(1)

async def main():
    # Unnecessary nursery for a single task
    async with trio.open_nursery() as nursery:
        nursery.start_soon(worker_task)

Compliant solution

import trio

async def worker_task():
    await trio.sleep(1)

async def main():
    # Direct function call is simpler and more efficient
    await worker_task()

How to fix it in AnyIO

Replace the task group with a direct function call when the task group body contains only a single start_soon() or start() call.

Code examples

Noncompliant code example

import anyio

async def worker_task():
    await anyio.sleep(1)

async def main():
    # Unnecessary task group for a single task
    async with anyio.create_task_group() as tg:
        tg.start_soon(worker_task)

Compliant solution

import anyio

async def worker_task():
    await anyio.sleep(1)

async def main():
    # Direct function call is simpler and more efficient
    await worker_task()

Resources

Documentation