Python virtual environment management with pyenv

Virtual environments are great for dependency management and can be created without any extra tool. A python virtual environment can be created with python 3 with the command:

python -m venv venv

This will create a new directory called venv on the current directory with the new virtual environment. The virtual environment can then be activated with:

source venv/bin/activate

This is pretty much all that is needed to work with virtual environments. However, there are two major downsides to this approach:

  • New virtual environments are created all over the directory tree, making it hard to keep track of all of them.
  • Without a python version manager, it is difficult to maintain multiple python versions.

For these two reason I use pyenv.

Managing python versions

Pyenv improves the python version management. You can see all the python versions installed with pyenv by running:

pyenv versions

To see all the available versions which can be installed run:

pyenv install --list

Aside from the standard implementation of python, others are available. Implementations such as: anaconda, jython, miniconda, pypy, and more.

A version from the list can be installed with:

pyenv install 3.12

By only specifying the major and minor version numbers, the latest version of 3.12 will be installed.

Managing virtual environments

The pyenv-virtualenv plugin provides a better support. After installing it a venv can be created from any directory with the command:

pyenv virtualenv <python_version> <venv_name>

This will create a new venv with name venv_name and python version python_version. The venv will be created inside the pyenv default directory. This is great to keep track of them.

The existing virtual environments can be listed with the command:

pyenv versions

In order to activate the new virtual environment just run:

pyenv activate <venv_name>

A nice improvement is that it can be run from any directory, without need to search for the venv directory.

If you are like me and forget which venv belongs to which project, worry not, pyenv has your back. On the project directory run the command:

pyenv local <venv_name>

This will create a file named .python-version with the name of the venv. And once you cd into the directory, the venv will be activated. Such a nice feature, no need to source the venv anymore.

To deactivate the venv just run:

pyenv deactivate

Note this will not be enough if you want to stay in the directory containing the python-version file. On that case you will have to remove the file and then run the deactivate command.

To remove unused venv just run the command:

pyenv uninstall <venv_name>

Bonus

This is something I did not realize until we needed/wanted to update our work code to the latest python version. Pyenv also helps decoupling the available python versions from the operating system version.

Our servers at the time were running ubuntu 20, which comes with python 3.8 by default. A colleague got into the task of updating the version and gave up when it was not possible to apt-get install python3.11. He then stated that in order to made the update we would have to updated the os to ubuntu 22. This basically means that the python version is coupled to the os version.

I had never run into the problem, even though I also run ubuntu 20 locally, because I have been using pyenv to manage my local python versions. We then proceed to discover that leveraging pyenv in our docker images was rather simple.