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:


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.

All posts by topicArchive

Copyright 2021 - Daan Debie