python_script_runner 1.7.10

Execute Python scripts from Rust with path traversal prevention and environment isolation
Documentation

PYTHON_SCRIPT_RUNNER

Execute Python scripts from Rust with automatic project-relative path resolution, retry logic, and real-time output streaming.

Installation

Add to your Cargo.toml:

[dependencies]
python_script_runner = "0.1"

Or use local path:

python_script_runner = { path = "path/to/python_script_runner" }

Quick Start

Set environment variables in .env

PROJECT_DIRECTORY=/path/to/your/project

Import and use

use python_script_runner::python_script_runner::{PythonExecutor, run_python_script};

let executor = PythonExecutor::new();
executor.execute_script("scripts/my_script.py").await?;

run_python_script("/absolute/path/to/script.py").await?;

Configuration

Environment Variables

Variable Required Default Description
PROJECT_DIRECTORY Yes Root directory for script path resolution

Key Features

  1. Automated Python Script Execution — Runs Python scripts via tokio::process::Command with async output capture — non-blocking
  2. Robust Retry Mechanism — 3-attempt retry loop with fixed 3-second delay between attempts — covers transient failures (interpreter startup, temp file locks)
  3. Real-Time Output Streaming — Captures and writes both stdout and stderr via tokio::io async writers — operator sees script progress immediately
  4. Project-Aware Path Management — Resolves relative paths using PROJECT_DIRECTORY environment variable — portable across machines and CI
  5. Early File Validation — Pre-validates script existence before entering the retry loop — fails fast rather than waiting 9 seconds for a missing file

API Reference

PythonExecutor::new() -> Result

Create a new executor, loading PROJECT_DIRECTORY from .env.

  • Returns: Ok(PythonExecutor) on success

PythonExecutor::execute_script(&self, relative_path: &str) -> Result<()>

Execute a Python script given a project-relative path.

  • relative_path: Path relative to PROJECT_DIRECTORY (e.g. "scripts/my_script.py")
  • Returns: Ok(()) on success

run_python_script(script_path: &str) -> Result<()>

Execute a Python script at the given absolute path with retry and output streaming.

  • script_path: Absolute path to the Python script
  • Returns: Ok(()) on success

Output

Both stdout and stderr are streamed to the respective streams in real-time:

  • stdout: Written to the executor's stdout
  • stderr: Written to the executor's stderr

The script exit code is captured and returned as part of the Result.

Error Handling

The library returns anyhow::Result<T>:

  • anyhow::anyhow!("PROJECT_DIRECTORY not set") if not set
  • anyhow::anyhow!("Script file not found") if the script doesn't exist
  • anyhow::anyhow!("Python interpreter not found") if python or python3 is not available
  • anyhow::anyhow!("Script execution failed with exit code N") if the script fails

Retry Policy

Script execution uses a 3-attempt retry loop:

  • Max attempts: 3
  • Delay: Fixed 3-second delay between attempts
  • Retryable: All execution failures
  • Not retried: Missing script file (fail fast)

Note: Performance is dominated by the external Python interpreter and script execution time. In-crate benchmarks are not meaningful.

Test Coverage

cargo test --lib
Function Tier Tests What is tested
PythonExecutor::new() 1 3 success, missing PROJECT_DIRECTORY, missing .env
execute_script() 1 4 relative path, absolute path, retry on failure, output streaming
run_python_script() 1 3 success, missing script, python not found
Path resolution 2 2 relative path construction, fallback

Note: Tests that require a Python interpreter will skip gracefully if python/python3 is not available on the system PATH.

Dependencies

[dependencies]
dotenvy = "0.15"
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"