ยง Activating poetry venvs with fzf
More often than not I find myself wanting to reuse a python virtual environment
with packages I use frequently already installed. For instance, I might want to
do some quick calculations and plotting in a scratch directory with numpy
,
scipy
, pandas
, matplotlib
, etc. With my current python workflow, it is
easy to lie on a Procrustean bed and create a new virtual environment in each
and every new scratch directory. Alternatively, one could create a base virtual
environment, install the aforementioned packages and source the virtual
environment from where ever it is located and carry on with one’s calculations
and plots.
This latter option is slightly less cumbersome than the former, but it still
requires you to know where the base virtual environment is located. With
poetry
and fzf
we can lift the mental overhead of having to knowing where
the base virtual environment is. To this end, I wrote a smol script that uses
fzf
to source a poetry virtual environment from anywhere.
#!/usr/bin/env bash
# Constants
VENV_BASE_DIR="${HOME}/.local/share/pyproject/virtualenvs"
# Error handling
if [ ! -d "$VENV_BASE_DIR" ]; then
echo "Error: Poetry virtualenvs directory not found at $VENV_BASE_DIR" >&2
exit 1
fi
# Check for fzf
if ! command -v fzf >/dev/null 2>&1; then
echo "Error: fzf is not installed. Please install it first." >&2
exit 1
fi
# Function to extract project name from virtualenv path
get_project_name() {
local venv_name="$1"
basename "$venv_name" | sed -E 's/-[^-]*-py[0-9.]+$//'
}
# Function to list and format virtualenvs
list_virtualenvs() {
local venv_dir
while IFS= read -r venv_dir; do
# Skip if not a directory
[ ! -d "$venv_dir" ] && continue
# Skip if no activation script exists
[ ! -f "$venv_dir/bin/activate" ] && continue
# Get and output project name
get_project_name "$venv_dir"
done < <(find "$VENV_BASE_DIR" -mindepth 1 -maxdepth 1 -type d)
}
# Function to find virtualenv path from project name
find_venv_path() {
local project_name="$1"
local venv_dir
while IFS= read -r venv_dir; do
[ ! -d "$venv_dir" ] && continue
if [ "$(get_project_name "$venv_dir")" = "$project_name" ]; then
echo "$venv_dir"
return 0
fi
done < <(find "$VENV_BASE_DIR" -mindepth 1 -maxdepth 1 -type d)
return 1
}
# Main execution
main() {
# Get list of projects and select with fzf
local selected_project
selected_project=$(list_virtualenvs | sort | fzf --prompt="Select virtualenv: ")
# Exit if nothing selected
[ -z "$selected_project" ] && exit 0
# Find corresponding virtualenv path
local venv_path
venv_path=$(find_venv_path "$selected_project")
if [ -z "$venv_path" ]; then
echo "Error: Could not find virtualenv for $selected_project" >&2
exit 1
fi
# Check if activation script exists
if [ ! -f "$venv_path/bin/activate" ]; then
echo "Error: Activation script not found in $venv_path" >&2
exit 1
fi
# Activate virtualenv and start new shell
. "$venv_path/bin/activate"
exec "$SHELL"
}
main
From here you can dump this into $HOME/.local/bin
and/or bind the execution
of the script to a shell keyboard shortcut.