This rule raises an issue when synchronous OS calls like os.wait() are used within asynchronous functions.

Why is this an issue?

Using synchronous operating system calls like os.wait(), os.waitpid(), or similar functions in asynchronous code blocks the entire event loop. This undermines the primary advantage of asynchronous programming - the ability to perform concurrent operations without blocking execution.

When an async function makes a synchronous OS call:

Instead, async libraries provide mechanisms to run blocking operations in separate threads without blocking the event loop:

Using these constructs allows other tasks to continue executing while waiting for the blocking OS call to complete.

How to fix it in Asyncio

Use asyncio.loop.run_in_executor() to run blocking OS calls in a separate thread pool.

Code examples

Noncompliant code example

import os

async def wait_for_child_process(pid):
    pid, status = os.waitpid(pid, 0)  # Noncompliant
    return status

Compliant solution

import asyncio
import os

async def wait_for_child_process(pid):
    loop = asyncio.get_running_loop()
    pid, status = await loop.run_in_executor(
        None,
        os.waitpid, pid, 0
    )
    return status

How to fix it in Trio

Use trio.to_thread.run_sync() to run blocking OS calls in a worker thread.

Code examples

Noncompliant code example

import os

async def wait_for_child_process(pid):
    pid, status = os.waitpid(pid, 0)  # Noncompliant
    return status

Compliant solution

import trio
import os

async def wait_for_child_process(pid):
    pid, status = await trio.to_thread.run_sync(
        os.waitpid, pid, 0
    )
    return status

How to fix it in AnyIO

Use anyio.to_thread.run_sync() to run blocking OS calls in a worker thread.

Code examples

Noncompliant code example

import os

async def wait_for_child_process(pid):
    pid, status = os.waitpid(pid, 0)  # Noncompliant
    return status

Compliant solution

import anyio
import os

async def wait_for_child_process(pid):
    pid, status = await anyio.to_thread.run_sync(
        os.waitpid, pid, 0
    )
    return status

Resources

Documentation

Articles & blog posts