Build a Recipe Runner Mock in Python

A Python script that mocks a command runner recipe system: maps recipe names to shell commands, executes them with subprocess, and prints the output and exit code.

Easy Python 3.9+ Aug 9, 2026 Modern tooling 13 views 0 copies

Python code

27 lines
Python 3.9+
import subprocess
import sys


def run_recipe(recipe: str) -> None:
    """Simulate a command runner recipe by printing the command and exit code."""
    print(f"Running recipe: {recipe}")
    result = subprocess.run(recipe, shell=True, capture_output=True, text=True)
    print(f"Exit code: {result.returncode}")
    if result.stdout:
        print("stdout:", result.stdout.strip())
    if result.stderr:
        print("stderr:", result.stderr.strip())


if __name__ == "__main__":
    recipes = {
        "greet": "echo 'Hello from recipe runner!'",
        "list-files": "ls -la",
        "python-version": "python3 --version",
    }

    recipe_key = sys.argv[1] if len(sys.argv) > 1 else "greet"
    if recipe_key in recipes:
        run_recipe(recipes[recipe_key])
    else:
        print(f"Unknown recipe '{recipe_key}'. Available: {', '.join(recipes)}")

Output

stdout
Running recipe: greet
Exit code: 0
stdout: Hello from recipe runner!

How it works

This script uses subprocess.run() to execute shell commands safely with capture. It maps recipe keys to command strings in a dictionary, then calls a helper function that prints the command and its result. The shell=True flag allows the command to be interpreted by the shell, while capture_output=True and text=True capture stdout/stderr as strings. The main guard reads the recipe from sys.argv, falling back to 'greet'. This structure models how real command runners, like task runners or Makefiles, dispatch actions.

Common mistakes

  • Using `shell=True` with untrusted input can lead to command injection.
  • Not setting `capture_output=True` results in output being printed directly to the console.
  • Forgetting to handle unknown recipe keys gracefully.

Variations

  1. Use `shlex.split()` to avoid `shell=True` and pass a list of arguments.
  2. Add a `--list` flag to display all available recipes without executing them.

Real-world use cases

  • Creating a lightweight task runner for development workflows, similar to `invoke` or `just`.
  • Prototyping a CI pipeline step that executes different commands based on a parameter.
  • Building a mock service for testing CLIs that interact with a command execution layer.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Modern tooling

Related tutorials and quizzes for this topic.