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 gitbrew install openssl readline xzAs 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 | bashPitfall: 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/Cellarwith 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/bintakes precedence in your$PATHover thebinsub-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 rehashor 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
globalandsystemPython do not refer to the same thing in pyenv. YoursystemPython is the one distributed by your OS or package manager (located somewhere in/usr), while yourglobalPython is just a pointer to the Python currently selected by pyenv. This pointer is most often pointing to some sub-directory of the.pyenvdirectory in your$HOME, but can also refer to thesystemPython. 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.1that 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 ~/.pyenvNow that you are familiar with pyenv, you can learn about Python tooling isolation in Part 3 of the tutorial.