Unathi's personal website

HomePostsActivating Poetry Venvs With Fzf

Activating poetry venvs with fzf

Published Oct 29, 2024
Updated Nov 30, 2024
2 minutes read

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
 
VENV_BASE_DIR="${HOME}/.local/share/pyproject/virtualenvs"
 
# Check if venv base directory exists
if [ ! -d "$VENV_BASE_DIR" ]; then
    echo "Error: Poetry virtualenvs directory not found at $VENV_BASE_DIR" >&2
    exit 1
fi
 
# Check if fzf is installed
if ! command -v fzf >/dev/null 2>&1; then
    echo "Error: fzf is not installed. Please install it first." >&2
    exit 1
fi
 
# Helper function to extract project name from virtualenv path
get_project_name() {
    local venv_name="$1"
    basename "$venv_name" | sed -E 's/-[^-]*-py[0-9.]+$//'
}
 
# Helper 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)
}
 
# Helper 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
}
 
# 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"

From here you can dump this into $HOME/.local/bin and/or bind the execution of the script to a shell keyboard shortcut.

Fin.