Customzing Pyenv Behavior with Hooks
Daan Debie / November 28, 2021
2 min read
I use pyenv to manage different Python versions on my laptop. It also comes with an official plugin that lets you manage virtualenvs through pyenv, which I find very convenient. Basically, virtualenvs are treated as just different Python versions by pyenv.
One thing that bothered me is that, whenever I create a new virtualenv and use pip in it, I am
inevitably greeted by a message telling me pip is out-of-date:
WARNING: You are using pip version 21.2.3; however, version 21.3.1 is available.
You should consider upgrading via the '~/.pyenv/versions/3.10.0/envs/test/bin/python3.10 -m pip install --upgrade pip' command.
So I end up always having to upgrade pip after creating a new virtualenv. Wouldn’t it be nice if this could be automated?
Turns out, we actually can by leveraging pyenv hooks.
Pyenv Hooks
pyenv hooks are scripts that are executed by pyenv whenever certain commands are run. These can be
regular pyenv commands like pyenv install or pyenv rehash for example. But what is not
apparent from the pyenv documentation, is that you can also create hooks for plugins, like
pyenv virtualenv.
You can create a hook by creating a script at the following location:
$PYENV_ROOT/pyenv.d/<hook-name>/<whatever>.bash
hook-name here can be any of: exec, rehash, which, install — which are all regular pyenv
commands — but it can also be a plugin command, like virtualenv. The filename of the script doesn’t
matter, and neither does the extension. I use .bash here to make it explicit that this is a bash
script, but pyenv hooks can be written in any language.
To create a hook that upgrades pip and some other default packages, you can create a new script
as follows:
mkdir -p $PYENV_ROOT/pyenv.d/virtualenv/
$EDITOR $PYENV_ROOT/pyenv.d/virtualenv/after.bash
Where $EDITOR is your favorite editor (like vim, RIGHT?!)
Then add the following contents:
after_virtualenv 'PYENV_VERSION="$VIRTUALENV_NAME" pyenv-exec pip install --upgrade pip setuptools wheel'
after_virtualenv is the command that tells pyenv when to execute the following command. In this
case its defined by the pyenv virtualenv plugin. First we set the pyenv version to the name
of the virtualenv we just created. This is set by pyenv virtualenv as $VIRTUALENV_NAME. Then we
install/upgrade pip itself and setuptools and wheel.
That is all there is to it! Now any time you create a new virtualenv using pyenv virtualenv, the
aforementioned packages will be automatically upgraded after the virtualenv was created.