Nick George
all/

Pre- activate scripts for pip and virtualenvwrapper

First published: October 6, 2021
Last updated: January 8, 2023

Pip and virtualenv

$ mkvirtualenv newenv
...
WARNING: You are using pip version 21.1.3; however, version 21.2.4 is available.
You should consider upgrading via the '/Users/nick/.ve/newenv/bin/python -m pip install --upgrade pip' command.

Ever seen that error after making a new virtual environment with virtualenvwrapper?

I have several versions of Python installed on my MacOS laptop, all of them are installed from the Python.org installer, so they all live under /Library/Frameworks/Python.framework/Versions/.

Here is a simple bash script to keep your pip installations in all of your python files up to date:

#!/bin/bash
# update all pip versions in Python.framework

pythons=/Library/Frameworks/Python.framework/Versions/
versions=$(ls $pythons)
pip="-m pip install --upgrade pip"
for version in $versions;
do
        if [[ "$version" == "Current" ]]; then
                continue
        fi
        cmd="$pythons$version/bin/python3 $pip"
        $cmd
done
echo "[INFO] Done"

First, we create some variables to make the command building a little easier:

pythons=/Library/Frameworks/Python.framework/Versions/
versions=$(ls $pythons)
pip="-m pip install --upgrade pip"

When you ls $pythons, you'll see all of your python versions, for me:

$ ls /Library/Frameworks/Python.framework/Versions/
3.10    3.7     3.8     3.9     Current

Current points to the 'current' or default python version installed.

We then loop through the versions and run the command /Library/Frameworks/Python.framework/Versions/<python-version>/bin/python3 -m pip install --upgrade pip for each <python-version> in the directory.

Automating pip updates with virtualenvwrapper

virtualenvwrapper is an excellent and simple tool for organizing and using python virtual environments.

Once installed and configured, you can create virtual environment using:

mkvirtualenv env-name

virtualenvwrapper allows you to run commands before virtualenv activation (preactivate), after activation (postactivate), before deactivation (predeactivate), after deactivation (postdeactivate) and a number of other options (see https://virtualenvwrapper.readthedocs.io/en/latest/scripts.html).

So if we wanted to ensure that pip was up to date (or we wanted to run another command) before activating an environment, we can edit the $WORKON_HOME/preactivate script.

If we wanted to ensure an up-to-date pip every time we activate an environment, we could use the following:

#!/bin/bash
# This hook is run before every virtualenv is activated.
# argument: environment name
pipcmd="python3 -m pip install --upgrade pip"
cmd=$WORKON_HOME/$1/bin/$pipcmd
$cmd

$1 is the name of the virtual environment, which is the first argument passed to preactivate. Similarly, we could add this to predeactivate if we didn't want to take the pip update startup hit.

Pip updater built in

Of course, updating pip (or something else) in a number of environments is a very common action, and of course virtualenvwrapper has a built in tool for this, so we don't need any of the scripts we just wrote. The virtualenvwrapper command is allvirtualenv. allvirtualenv runs some command in all of the environments in $WORKON_HOME. For example:

allvirtualenv pip install --upgrade pip

will iterate through all of your virtual environments and upgrade pip in each.

Wrapping up

It is important to realize that virtual environments and the various wrappers and tools to deal with them are not magic. Most are just making symlinks and re-arranging your path. Some, like virtualenvwrapper provide some really nice mechanisms to add arbitrary commands and customization's to your environments. The more you understand, the more productive you can be.