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. ↩