common.py


Overview

common.py is a utility module providing a safe and convenient way to run shell commands asynchronously within an asyncio event loop environment. It defines a single asynchronous function async_run_command which executes an external command with a specified timeout, capturing its output (stdout and stderr) and exit code. The function handles common errors such as timeouts and unexpected process termination reliably.

This module is useful in applications that require non-blocking execution of shell commands, such as network automation, system orchestration, or any async Python program that interacts with external processes without stalling the main event loop.


Detailed Description

Function: async_run_command

async def async_run_command(*args, timeout: float = 5) -> Tuple[int, str, str]:

Purpose

Runs an external command asynchronously, waits for it to complete or the timeout to expire, and returns the process's exit code along with its stdout and stderr outputs decoded as strings.

Parameters

Returns

Raises

Usage Example

import asyncio
from common import async_run_command

async def main():
    try:
        retcode, out, err = await async_run_command("ls", "-l", timeout=3)
        print(f"Exit code: {retcode}")
        print(f"Output:\n{out}")
        if err:
            print(f"Errors:\n{err}")
    except RuntimeError as e:
        print(f"Command failed: {e}")

asyncio.run(main())

Implementation Details


Interaction with Other System Components


Visual Diagram

The following flowchart illustrates the workflow of the async_run_command function:

flowchart TD
    A[Start async_run_command(*args, timeout)] --> B[Create subprocess with asyncio.create_subprocess_exec]
    B --> C[Wait for process completion with asyncio.wait_for(timeout)]
    C -->|Success| D{Is proc.returncode None?}
    D -->|Yes| E[Raise RuntimeError("Process finished but returncode is None")]
    D -->|No| F[Decode stdout and stderr]
    F --> G[Return (returncode, stdout, stderr)]
    C -->|TimeoutError| H[Kill process]
    H --> I[Await process termination]
    I --> J[Raise RuntimeError("Command timed out")]
    C -->|Other Exception| K[Kill process]
    K --> L[Await process termination]
    L --> M[Re-raise exception]

Summary

common.py is a concise but critical utility that ensures asynchronous execution of shell commands with proper timeout handling and output collection. Its robust error handling and non-blocking design make it suitable for integration into complex asynchronous Python applications that interact with the system shell or external binaries.