Managing Multiple Python Versions with pyenv

As Python developers we often need to work with multiple versions of Python. pyenv lets us easily install, manage and switch between multiple versions of Python.

In this post I will provide an overview of the installation and usage of pyenv. The installation instructions are for Mac OS X and Homebrew. If you are not on Mac OS X or don't use Homebrew, refer to the pyenv documentation for installation instructions specific to your system. The rest of the post is about the usage of pyenv and is applicable to everyone.

Python versions installed using pyenv can coexist with other Pythons installed via Homebrew or the system Python. If you have already installed Python using Homebrew, you don't need to uninstall it. See the How pyenv Works? section below to understand how all the different Python versions coexist on the same system.

Installing pyenv

Installing pyenv on Mac OS X is very simple with Homebrew.

$ brew update
$ brew install pyenv

After installation, add the following at the bottom of your profile (~/.bash_profile or ~/.zshenv)

if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi

pyenv uses ~/.pyenv as its root directory by default. This is the directory where pyenv installs its shims, the different Python versions and its plugins. The default location is absolutely fine, but if you want to use the directory suggested by Homebrew then add the following to your profile.

export PYENV_ROOT=/usr/local/var/pyenv

Finally, restart your shell so the profile changes can take effect.

Using pyenv

pyenv provides various commands to manage the different Python versions.

pyenv install

Installing new Python versions is very straightforward. All Python versions are installed in the versions directory under the pyenv root.

$ pyenv install 2.7.10
$ pyenv install 3.4.3
$ pyenv install 3.5.0

pyenv uninstall

If you no longer need a Python version installed using pyenv, you can easily uninstall it.

$ pyenv uninstall 3.5.0

pyenv versions

Lists all the currently installed Python versions. The asterisk indicates the currently active version. The system version is the one that already existed in your system and was not installed by pyenv.

$ pyenv versions
* system (set by /Users/akbar/.pyenv/version)

pyenv version

Displays the currently active Python version.

$ pyenv version
system (set by /Users/akbar/.pyenv/version)

pyenv global

Sets the global version of Python to be used in all shells. This command writes the specified version number to the version file under the pyenv root.

$ pyenv global 2.7.10

When run without a version number, it displays the currently configured global version.

pyenv local

Sets the Python version to be used by a specific application. This command writes the specified version number to the .python-version file in the in the current directory. This version overrides the global version and is used for the current directory and all its sub-directories.

$ pyenv local system

You can also unset the local version with the following command. This deletes the .python-version file from the current directory.

$ pyenv local --unset

When run without a version number, it displays the currently configured local version.

$ pyenv local

pyenv shell

Sets a version of Python for the current shell session. This command sets the PYENV_VERSION environment variable in your shell to the specified version. This setting overrides the local and global versions of Python.

$ pyenv shell 3.4.3

You can reset the Python to a different version by executing this command again with the required version.

$ pyenv shell 2.7.10

You can also unset the shell version with the following command.

$ pyenv shell --unset

When run without a version number, it displays the current version configured for the shell.

$ pyenv shell

pyenv which

Displays the full path of the executable which will be invoked when a command is run.

$ pyenv which pydoc

pyenv whence

Lists all Python versions that have the given command installed.

$ pyenv whence pydoc

How pyenv Works?

The fundamental concept behind pyenv is a shim.

A shim is a small library or program that transparently intercepts calls and changes the arguments passed, handles the operation itself or redirects the operation elsewhere.

When installed pyenv creates a directory of shim commands that have the same names as all the executables (such as python, pydoc, pip) distributed with all the installed Python versions. The directory of shims is kept up to date every time a new Python version or a new library is installed.

The directory of shims is then inserted at the front of your PATH. So when you run a command, say python or pip, the following happens.

  1. The shell searches your PATH for an executable file matching the command name.
  2. Since the shim directory is at the front of the PATH, the shim executable with the same name as the command is matched first.
  3. The shell then runs the shim executable, which passes the command to pyenv.
  4. pyenv chooses the correct Python version and then executes the command in that Python version.

How pyenv choses a Python version?

pyenv uses the first Python version found by looking at the following sources in the specified order.

  1. The shell Python specified by the PYENV_VERSION environment variable.
  2. The local Python specified by the .python-version file in the current directory or the parent directories of the current directory.
  3. The global Python specified by the version file under the pyenv root.
  4. The system Python.