Created
October 31, 2024 11:33
-
-
Save cholmboe/2b73068cddf55b30141cbdc53c1fb64d to your computer and use it in GitHub Desktop.
A script that wraps Python scripts to manage requirements in a virtual environment.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# This script wraps Python scripts in a virtual environment. | |
# It creates a virtual environment if one doesn't exist, installs dependencies, | |
# and runs the Python script with the same name as this wrapper. This is a hacky | |
# wrapper meant for your hacky scripts, for serious stuff you should manage | |
# dependencies seriously. | |
# | |
# Usage: | |
# 1. Create a Python script named foo.py | |
# 2. Create a symlink to this wrapper named foo | |
# 3. Run ./foo with any arguments | |
# | |
# The script will: | |
# - Create a .venv directory if it doesn't exist | |
# - Install dependencies from requirements.txt if present | |
# - Generate requirements.txt using pipreqs if missing | |
# - Run the Python script, forwarding stdin and arguments | |
set -euo pipefail | |
PYTHON_SCRIPT="$0.py" | |
ROOT_DIR="$(dirname "$PYTHON_SCRIPT")" | |
# Ensure this script is not being run directly | |
if [ "$(basename "$0")" = "pywrap.sh" ]; then | |
echo "This script should not be run directly. It should be symlinked to a Python script." | |
exit 1 | |
fi | |
# Check if the Python script exists | |
if [ ! -f "$PYTHON_SCRIPT" ]; then | |
echo "Python script $PYTHON_SCRIPT does not exist." | |
exit 1 | |
fi | |
# Set the virtual environment's name | |
VENV_DIR="$ROOT_DIR/.venv" | |
# Check if the virtual environment already exists | |
if [ ! -d "$VENV_DIR" ]; then | |
python3 -m venv "$VENV_DIR" || { echo "Failed to create virtual environment."; exit 1; } | |
fi | |
# Activate the virtual environment | |
source "$VENV_DIR/bin/activate" | |
# Quick and dirty check if the dependencies are installed | |
if [ -f "$ROOT_DIR/requirements.txt" ]; then | |
SITE_PACKAGES=$(python -c "import site; print(site.getsitepackages()[0])") | |
REQUIREMENTS=$(cat "$ROOT_DIR/requirements.txt" | awk -F'==' '{print tolower($1)}') | |
INSTALL=$(cat <(ls "$SITE_PACKAGES") <(ls "$SITE_PACKAGES") <(cat "$ROOT_DIR/requirements.txt" | awk -F'==' '{print tolower($1)}') | sort | uniq -u) | |
fi | |
# Install the dependencies if INSTALL is set or if requirements.txt is missing | |
if [[ "${INSTALL:-}" != "" ]] || [ ! -f "$ROOT_DIR/requirements.txt" ]; then | |
command -v pipreqs &> /dev/null || pip install pipreqs &> /dev/null || { echo "Failed to install pipreqs."; exit 1; } | |
pipreqs "$ROOT_DIR" --ignore "$VENV_DIR" --mode no-pin --force &> /dev/null || { echo "Failed to generate requirements.txt."; exit 1; } | |
pip install -U -r "$ROOT_DIR/requirements.txt" &> /dev/null || { echo "Failed to install dependencies."; exit 1; } | |
fi | |
# Run the Python script with forwarded stdin | |
python "$PYTHON_SCRIPT" "$@" <&0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment