Excessively Adequate

Something Wrong With Your venv? Just Reset It!

Most folks developing Python applications will have experienced instances of a virtual environment (for non-snake-charmers: a directory containing a specific version of the Python interpreter and relevant libraries bound to a project, avoiding dependecy hell when working on multiple projects in parallel) that’s been chugging along nicely for months on their local development machine just kind of breaking – be it due to a botched dependency downgrade, a change in the Python setup1, or an even more arcane reason.

It’s not a common occurrence, but it happens.

The easiest way of fixing things, if you’ve been keeping track of your project’s dependencies, tends to be simply deleting the old virtual environment, creating a fresh one, and reinstalling the dependencies. That’s a sequence of three steps you need to perform in the correct order – so it’s ripe for automation!

Depending on where you keep your virtual environments (in my case: alongside each project, i.e., created via python3 -m venv .), how you install dependencies (commonly pip3 install -r requirements.txt) and any other specifics, a Bash script similar to the following should do2 the trick:

#!/bin/bash

if [ ! -z "$VIRTUAL_ENV" ]; then
    echo "Deactivating..."
    deactivate
else
    echo "No venv active, skipped 'deactivate' step."
fi
if [ -f "pyvenv.cfg" ]; then
    echo "Nuking old virtual environment..."
    rm pyvenv.cfg
    rm -r bin
    rm -r include
    rm -r lib
else
    echo "No 'pyvenv.cfg' file present, skipped nuking step."
fi
echo "Setting up a fresh virtual environment..."
python3 -m venv .
echo "Activating..."
source bin/activate
if [ -f "requirements.txt" ]; then
    echo "Reinstalling from requirements.txt..."
    pip3 install -r requirements.txt
else
    echo "No 'requirements.txt' found, skipped reinstall step."
fi

Paste these lines of code (modulo any modifications needed to match your workflow) into a file named revenv, place it in a directory that’s on3 your $PATH and make sure the file’s executable: run chmod u+x revenv, for instance. Then, when you’re in need of resetting a virtual environment, simply cd to your project’s directory and run revenv.

  1. In my case, this tends to happen when I upgrade some Homebrew package (say, yt-dlp) whose new version depends (whether technically required or not) on a newer-than-installed Python version. During this transitive upgrade process, previous Python versions sometimes end up being uninstalled (or, at the very least, relevant symlinks get borked). 

  2. Since it’s designed to skip the deletion of the old virtual environment if none is present, I’ve also found it handy for bootstrapping a new project. 

  3. A common choice of directory is ~/local/bin – which you can put on your $PATH by adding export PATH="$HOME/local/bin:$PATH to your .bashrc and/or .bash_profile – but I tend to instead maintain small utilities like this as functions in my .bashrc. To each their own.