pyenv is a command-line tool that enables you to manage different Python environments in your $HOME
, in isolation from interpreters located in root-owned directory /usr
, typically called "system" Python interpreters.
That is, it enables you to mess with your Python environment without breaking the Python environment of your operating system or of other users. The core ideas behind pyenv are similar to the ones behind nvm for JavaScript, or rbenv for Ruby.
Note: This tutorial is part of a series about Python environments. You can go back to the first part with this link: Sane Python environment Part 1, isolation.
In this tutorial, we will assume that you are using Ubuntu or macOS. If you are using macOS, you should make sure to install the Xcode Command Line Tools (xcode-select --install
) and Homebrew.
The installation of pyenv requires some dependencies, so please install those first:
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl git
brew install openssl readline xz
As pyenv is independent of your OS Python, it does not use Python for installation, and relies on a Bash script instead. This Bash script (bin/pyenv-installer
) is provided in the pyenv-installer repo. Install it using the following command:
curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
Pitfall: DO NOT use your system package manager to install pyenv! Indeed, your package manager is tightly coupled to other components of your system and this goes against isolation. Moreover, your package manager usually writes files to sub-directories of root-owned directory
/usr
(e.g./usr/local/Cellar
with Homebrew on macOS), which will almost always cause permissions issues later. While a poweruser will be able to deal with potential regressions introduced by the system package manager, the ordinary user most likely won't. To be convinced that dealing with the OS package manager in Python is difficult, you can googlesite:stackoverflow.com brew python
, which at time of writing returns 32'000 results.
After downloading pyenv and installing it to ~/.pyenv
, you will need to add a few initialization lines to your Shell config file (e.g. ~/.zshrc
or ~/.bashrc
):
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
These initialization lines include a modification of your $PATH
, which enforces the precedence of pyenv's bin
directory of your $HOME
over the other registered directories, which usually include the bin
sub-directories of /usr
such as /usr/local/bin
. This "precedence trick" is called a shim and enables pyenv to intercept all Python-related commands such as pip
or python
.
After updating your Shell config, exit/logout from your terminal (e.g. with exit
) and then open it again. Please note that it's not enough to just source
your Shell config file in many cases!
Pitfall: If your Shell config files contain some lines with
export PATH="SOME_DIR:$PATH"
already, make sure the pyenv initialization lines are added afterwards, to make sure$HOME/.pyenv/bin
takes precedence in your$PATH
over thebin
sub-directories of/usr
(e.g./usr/local/bin
).
After opening the new terminal, the pyenv
command should be available, and you should be able to run pyenv versions
. This command will show you all the Python environments installed on your computer. As no new environment was installed yet, you should just see the "system" Python of your OS:
➜ pyenv versions
* system (set by /home/pierre/.pyenv/version)
Before attempting to install a Python version, first check that your machine is ready for it:
➜ pyenv doctor
Cloning /home/pierre/.pyenv/plugins/pyenv-doctor/bin/.....
Installing python-pyenv-doctor...
Installed python-pyenv-doctor to /tmp/pyenv-doctor.20191103204543.28966/prefix
Congratulations! You are ready to build pythons!
If pyenv doctor
fails, fix the missing installations that it found. Once pyenv doctor
succeeds, we can check which Python versions are available for installation, and install one of them:
➜ pyenv install --list | grep 3.8
3.8.0
3.8-dev
3.8.1
miniconda-3.8.3
miniconda3-3.8.3
➜ pyenv install 3.8.1
Downloading Python-3.8.1.tar.xz...
-> https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tar.xz
Installing Python-3.8.1...
Installed Python-3.8.1 to /home/pierre/.pyenv/versions/3.8.1
# Make sure the shims are up-to-date
➜ pyenv rehash
➜ pyenv versions
* system (set by /home/pierre/.pyenv/version)
3.8.1
As you can see, our new Python version was installed successfully in ~/.pyenv/versions
. In the output of the pyenv versions
command, the little star next to the version name indicates the current global version of Python, which is initially system
. Thanks to pyenv, your system Python is still active and fully functional. It was not destroyed by your new Python 3.8.1
installation.
To make sure our shims are up-to-date, we also ran pyenv rehash
after installing the interpreter. If you don't run pyenv rehash
, your new interpreter might not be installed correctly, as the GitHub member "dangitall" commented on the project issue tracker. I personally encountered the same issue on on macOS, Ubuntu 18.04 and Ubuntu 19.04 with pyenv 1.2.15.
➜ python
Python 2.7.12 (default, Dec 4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
After screaming out of joy for your preserved system, you can switch to your new version of Python using the pyenv global
command:
➜ pyenv global 3.8.1
➜ python
Python 3.8.1 (default, Jan 7 2020, 23:51:55)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Pitfall: In case your Python version is not updated after running
pyenv global
, runpyenv rehash
or exit and re-enter your terminal.
You can then switch back and forth between your versions using the same command:
➜ pyenv global system
➜ python
Python 2.7.12 (default, Dec 4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
➜ pyenv global 3.8.1
➜ python
Python 3.8.1 (default, Jan 7 2020, 23:51:55)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Finally, be aware that pyenv has the ability to select multiple global Pythons at the same time, even though it is not required for common development use cases. That is, you may see other tutorials on the Internet where there is more than one single star in the output of pyenv versions
.
Pitfall: As you can see, the notions of
global
andsystem
Python do not refer to the same thing in pyenv. Yoursystem
Python is the one distributed by your OS or package manager (located somewhere in/usr
), while yourglobal
Python is just a pointer to the Python currently selected by pyenv. This pointer is most often pointing to some sub-directory of the.pyenv
directory in your$HOME
, but can also refer to thesystem
Python. To avoid messing up your system Python, you should always have your global Python pointing to a version installed using pyenv. In our case, the global Python should be pointing to the version3.8.1
that was installed earlier.
If you run into issues with the $PATH
manipulations of pyenv, these StackOverflow answers might help you:
How to correctly set the $PATH? by Gilles and Stéphane Chazelas on StackOverflow Unix
What should/shouldn't go in .zshenv, .zshrc, ...? by Smith Jon on StackOverflow Unix
Choosing between .bashrc, .profile, etc... by Dan Rabinowitz and Gilles on StackOverflow SuperUser
pyenv is self-contained, so it can be removed fairly easily if needed:
pipx
from the next part of the tutorial, make sure to uninstall it first before uninstalling pyenv.export PATH=...
line containing pyenvpyenv init
linesrm -rf ~/.pyenv
Now that you are familiar with pyenv, you can learn about Python tooling isolation in Part 3 of the tutorial.