I’ve written previously about virtualenvwrapper
which I use to manage my Python Virtual Environments and mentioned the possibility of using hooks but didn’t go into detail.
Introduction
Just like the various hooks available in Git, virtualenvwrapper
also supports hooks that allow scripts to be run in response to various events. These reside under your $VIRTUALENVWRAPPER_HOOK_DIR
which by default is the same as your $WORKON_HOME
directory and in a typical standard installation will be ~/.virtualenvs
.
The available scripts that are recognised are…
get_env_details
initialize
premkvirtualenv
postmkvirtualenv
precpvirtualenv
postcpvirtualenv
preactivate
postactivate
Each of these is a simple shell script and will start with the scripting language to use e.g. #!/usr/bin/bash
or #!/usr/bin/zsh
depending on your shell. You can then script the actions you wish to take when the script is executed.
Install minimal requirements
I’m a big fan of dotfiles1, mine are hosted on GitLab, it’s a repository of my configuration files and scripts that I use regularly across multiple computers. Because I’m lazy I wrote a couple of requirements.txt
files for installing packages in my virtual environments.
requirements.txt
: holds everything I might ever want to use in Python.python-lsp-requirements.txt
- Install packages for setting up a Python Language Server (which I use from Emacs).
venv_minimal_requirements.txt
- a minimal set of the most common Python packages I am likely to want when creating a new virtual environment.
Because I have my dotfiles
cloned to the same location on every computer (~/dotfiles
) I added the following to the ~/.virtualenvs/postmkvirtualenv
2 which will install all of the packages listed in ~/dotfiles/python/venv_minimal_requirements.txt
whenever a create a new virtual environment, whether that is with mkvritualenv
or mktmpenv
.
pip install --no-cache-dir -r ~/dotfiles/python/venv_minimal_requirements.txt
This ensured the latest versions of each packages listed in ~/dotfiles/python/venv_minimal_requirements.txt
were downloaded and installed as the --no-cache-dir
prevents using cached versions of packages.
A smarter script
This served me well for a time, but occasionally I found I didn’t want to install any packages in a new virtual environment (most often when testing new branches using mktmpenv
) and I’d have to remember to comment out the line in the hook file (~/.virtualenvs/postmkvirtualenv
) before creating the environment. Typically though I’d forget to do this and would have to halt installation of required packages, deactivate the environment, then comment it out and create a new environment.
This quickly became irksome.
But ~/.virtualenvs/postmkvirtualenv
is just a script and so we can use a bit of scripting knowledge to make it interactive and ask the user if they want to install the packages listed in venv_minimal_requirements.txt
. I found a really useful answer on StackOverflow in the How do I prompt for yes/no/cancel input in a Linux shell script that showed several different ways to prompt the user for a response as to whether they want to do something.
I therefore updated my ~/.virtualenvs/postmkvirtualenv
to the following which prompts for a numeric response, 1
for Yes
and 2
for No
and takes the appropriate action, installing using my original invocation of pip
if I want to install packages and enter 1
or installing nothing if I enter 2
.
#!/usr/bin/zsh
# This hook is sourced after a new virtualenv is activated.
echo "Do you wish to install minimal requirements (from venv_minimal_requirements.txt)? "
select yn in "Yes" "No"; do
case $yn in
Yes ) pip install --no-cache-dir -r ~/dotfiles/python/venv_minimal_requirements.txt; break;;
No ) echo "No packages installed. install packages with 'pip'.\n"; break;;
esac
done
NB You may want to tweak the opening shebang if you use the Bash shell.
Conclusion
A little bit of shell scripting knowledge can be really powerful when used in conjunction with “hooks”. This is true of virtualenvwrapper
as well as of Git and the pre-commit framework.
Footnotes
There is a wealth of information on what you can do with your
dotfiles
but that is an article in itself and I’m yet to write it. A useful set of different aliases you could use can be found here↩︎Actually I create the script in
~/dotfiles/python/postmkvirtualenv
and made a symbolic link at~/.virtualenv/postmkvirtualenv
that points to it so that whenever I update or improve this script it is updated across my computers.↩︎
Reuse
Citation
@online{shephard2024,
author = {Shephard, Neil},
title = {Virtualenvwrapper Hooks},
date = {2024-07-31},
url = {https://blog.nshephard.dev/posts/virtualenv-hooks/},
langid = {en}
}