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:
[]
= "0.1"
Or use local path:
= { = "path/to/python_script_runner" }
Quick Start
Set environment variables in .env
PROJECT_DIRECTORY=/path/to/your/project
Import and use
use ;
let executor = new;
executor.execute_script.await?;
run_python_script.await?;
Configuration
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
PROJECT_DIRECTORY |
Yes | — | Root directory for script path resolution |
Key Features
- Automated Python Script Execution — Runs Python scripts via
tokio::process::Commandwith async output capture — non-blocking - Robust Retry Mechanism — 3-attempt retry loop with fixed 3-second delay between attempts — covers transient failures (interpreter startup, temp file locks)
- Real-Time Output Streaming — Captures and writes both stdout and stderr via
tokio::ioasync writers — operator sees script progress immediately - Project-Aware Path Management — Resolves relative paths using
PROJECT_DIRECTORYenvironment variable — portable across machines and CI - 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 toPROJECT_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 setanyhow::anyhow!("Script file not found")if the script doesn't existanyhow::anyhow!("Python interpreter not found")ifpythonorpython3is not availableanyhow::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
| 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
[]
= "0.15"
= { = "1", = ["full"] }
= "1.0"