{"library":"py-spy","title":"py-spy: Python Sampling Profiler","description":"py-spy is a sampling profiler for Python programs, implemented in Rust, designed for extremely low overhead. It enables visualization of Python program execution without requiring restarts or code modification, making it safe for production environments. The library actively maintains support across Linux, macOS, Windows, and FreeBSD, covering a wide range of CPython interpreter versions, with a continuous release cadence reflected by recent minor version updates.","language":"python","status":"active","last_verified":"Sat Apr 11","install":{"commands":["pip install py-spy"],"cli":{"name":"py-spy","version":"py-spy 0.4.2"}},"imports":[],"auth":{"required":false,"env_vars":[]},"quickstart":{"code":"import time\nimport subprocess\nimport os\n\n# Create a dummy Python script to profile\npython_script_content = \"\"\"\nimport time\nimport sys\n\ndef busy_loop(iterations):\n    result = 0\n    for i in range(iterations):\n        result += i * i\n    return result\n\ndef main():\n    print(f\"[{os.getpid()}] Starting my_app.py...\")\n    for _ in range(5):\n        busy_loop(1_000_000)\n        time.sleep(0.5)\n    print(f\"[{os.getpid()}] my_app.py finished.\")\n\nif __name__ == \"__main__\":\n    main()\n\"\"\"\n\nwith open(\"my_app.py\", \"w\") as f:\n    f.write(python_script_content)\n\nprint(\"Running my_app.py in the background...\")\n# Start the target Python script in the background\n# In a real scenario, you'd profile an already running process by PID\n# For quickstart, we launch it and then 'profile' it (though py-spy can launch directly too)\nprocess = subprocess.Popen([sys.executable, \"my_app.py\"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)\npid = process.pid\nprint(f\"Target Python process PID: {pid}\")\n\n# Wait a bit for the script to start\ntime.sleep(2)\n\nprint(\"Recording profile with py-spy...\")\n# Example: Record a flame graph of the running process\n# On Linux, you might need 'sudo' if attaching to an existing process (not a child)\n# On Docker, ensure --cap-add SYS_PTRACE is used\n# os.environ.get is not directly applicable here as py-spy is a CLI tool\n# but the principle for quickstarts is to show a runnable example.\ntry:\n    # Using subprocess.run for simplicity, would typically be a direct shell command\n    # For this example, we assume necessary permissions are available (e.g., running as root or correct ptrace_scope)\n    # In a real shell, you'd do: py-spy record -o profile.svg --pid <PID>\n    result = subprocess.run([\"py-spy\", \"record\", \"-o\", \"profile.svg\", \"--pid\", str(pid)], capture_output=True, text=True, check=True)\n    print(\"py-spy stdout:\", result.stdout)\n    print(\"py-spy stderr:\", result.stderr)\n    print(\"Flame graph saved to profile.svg\")\nexcept subprocess.CalledProcessError as e:\n    print(f\"Error running py-spy: {e}\")\n    print(\"py-spy stdout:\", e.stdout)\n    print(\"py-spy stderr:\", e.stderr)\n    print(\"HINT: You might need to run this with 'sudo' or ensure appropriate ptrace permissions.\")\nexcept FileNotFoundError:\n    print(\"Error: py-spy command not found. Ensure py-spy is installed and in your PATH.\")\nfinally:\n    # Clean up the background process\n    if process.poll() is None:\n        process.terminate()\n        process.wait(timeout=5)\n    # Clean up the dummy script\n    os.remove(\"my_app.py\")\n    if os.path.exists(\"profile.svg\"):\n        print(\"To view the profile, open profile.svg in a web browser.\")","lang":"python","description":"This quickstart demonstrates how to use `py-spy` to record a flame graph (`profile.svg`) of a running Python process. It first starts a simple Python script in the background, then attaches `py-spy` to its process ID (PID) to capture profiling data. For live viewing, `py-spy top --pid <PID>` is also a common command. Remember that `py-spy` often requires elevated privileges (e.g., `sudo`) or specific system capabilities (like `SYS_PTRACE` in Docker) to function correctly when attaching to existing processes.","tag":null,"tag_description":null,"last_tested":"2026-04-24","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]},"compatibility":null}