Introduction
As the pyenv Github page states:
pyenv lets you easily switch between multiple versions of Python. It's simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well. ... pyenv does...
- Let you change the global Python version on a per-user basis.
- Provide support for per-project Python versions.
- Allow you to override the Python version with an environment variable.
- Search commands from multiple versions of Python at a time. This may be helpful to test across Python versions with tox.
In contrast with pythonbrew and pythonz, pyenv does not...
- Depend on Python itself. pyenv was made from pure shell scripts. There is no bootstrap problem of Python.
- Need to be loaded into your shell. Instead, pyenv's shim approach works by adding a directory to your $PATH.
- Manage virtualenv. Of course, you can create virtualenv yourself, or pyenv-virtualenv to automate the process.
One element of the pyenv configuration is setting the environment variable PYENV-ROOT
to ~/.pyenv. All of its tools and Python versions it installs located in this directory.
The pyenv-root directory.
One element of the pyenv configuration is setting the environment variable PYENV-ROOT
to ~/.pyenv. The screenshot shows the contents of this directory.
Note:The additions to bash configuration files to configure pyenv and pyenv-virtualenv are specific to bash. For the fish sell and zsh, see the respective tools' Github pages, linked in the references section below.
Install and Configure pyenv
Install pyenv
pyenv is available in the repositories of common distributions such as Arch Linux and openSUSE Tumbleweed. It can be installed the default package management tools of the distributions.
On Arch:
[brook:~/DataEXT4/example.com] 4s $ sudo pacman -S pyenv
The above command with its output:
[brook:~/DataEXT4/example.com] 4s $ sudo pacman -S pyenv
resolving dependencies...
looking for conflicting packages...
Package (1) New Version Net Change Download Size
community/pyenv 1.2.13-1 2.20 MiB 0.17 MiB
Total Download Size: 0.17 MiB
Total Installed Size: 2.20 MiB
:: Proceed with installation? [Y/n]
:: Retrieving packages...
pyenv-1.2.13-1-any 171.9 KiB 204K/s 00:01 [##############################################] 100%
(1/1) checking keys in keyring [##############################################] 100%
(1/1) checking package integrity [##############################################] 100%
(1/1) loading package files [##############################################] 100%
(1/1) checking for file conflicts [##############################################] 100%
(1/1) checking available disk space [##############################################] 100%
:: Processing package changes...
(1/1) installing pyenv [##############################################] 100%
Optional dependencies for pyenv
git: installing development versions [installed]
:: Running post-transaction hooks...
(1/1) Arming ConditionNeedsUpdate...
On openSUSE Tumbleweed:
22:02:46 [brook@G5-openSUSE:~] 4s $ sudo zypper in pyenv
The above command with its output:
22:02:46 [brook@G5-openSUSE:~] 4s $ sudo zypper in pyenv
Loading repository data...
Reading installed packages...
Resolving package dependencies...
The following 3 NEW packages are going to be installed:
pyenv pyenv-bash-completion pyenv-zsh-completion
3 new packages to install.
Overall download size: 256.5 KiB. Already cached: 0 B. After the operation, additional 772.2 KiB will be used.
Continue? [y/n/v/...? shows all options] (y): y
Retrieving package pyenv-1.2.9-1.4.x86_64 (1/3), 233.1 KiB (771.5 KiB unpacked)
Retrieving: pyenv-1.2.9-1.4.x86_64.rpm .................................................................................................................................................................................................[done]
Retrieving package pyenv-zsh-completion-1.2.9-1.4.noarch (2/3), 11.7 KiB ( 298 B unpacked)
Retrieving: pyenv-zsh-completion-1.2.9-1.4.noarch.rpm ......................................................................................................................................................................[done (9.1 KiB/s)]
Retrieving package pyenv-bash-completion-1.2.9-1.4.noarch (3/3), 11.7 KiB ( 406 B unpacked)
Retrieving: pyenv-bash-completion-1.2.9-1.4.noarch.rpm .................................................................................................................................................................................[done]
Checking for file conflicts: ...........................................................................................................................................................................................................[done]
(1/3) Installing: pyenv-1.2.9-1.4.x86_64 ...............................................................................................................................................................................................[done]
(2/3) Installing: pyenv-zsh-completion-1.2.9-1.4.noarch ................................................................................................................................................................................[done]
(3/3) Installing: pyenv-bash-completion-1.2.9-1.4.noarch ...............................................................................................................................................................................[done]
Configure pyenv
Configuring pyenv is a matter of setting environment variables that pyenv needs to operate. This is done by using export
statements in the user's bash at ~/.bash_profile or in certain distributions in the user's bash configuration at ~/.bashrc. Using the echo command can be used to insert the export statements at the end of these files as shown below.
On Arch and openSUSE Tumbleweed:
22:03:18 [brook@G5-openSUSE:~] 15s $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
22:06:07 [brook@G5-openSUSE:~] $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
22:06:38 [brook@G5-openSUSE:~] $ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bash_profile
The newly set environment variables can be used immediately in the current shell session without restarting the terminal with:
[brook:~/DataEXT4/example.com] $ exec "$SHELL"
pyenv's help lists the available commands.
[brook:~/DataEXT4/example.com] $ pyenv --help
The above command with its output:
[brook:~/DataEXT4/example.com] $ pyenv --help
Usage: pyenv []
Some useful pyenv commands are:
commands List all available pyenv commands
local Set or show the local application-specific Python version
global Set or show the global Python version
shell Set or show the shell-specific Python version
install Install a Python version using python-build
uninstall Uninstall a specific Python version
rehash Rehash pyenv shims (run this after installing executables)
version Show the current Python version and its origin
versions List all Python versions available to pyenv
which Display the full path to an executable
whence List all Python versions that contain the given executable
See `pyenv help ' for information on a specific command.
For full documentation, see: https://github.com/pyenv/pyenv#readme
Installing Specific Python Version
At this point pyenv is installed and configured but the only available Python version is that installed by the distribution. This can be verified with
pyenv versions
which shows Python versions available to
pyenv.
The above command with its output on Arch:
[brook:~/DataEXT4/example.com] $ pyenv versions
* system (set by /home/brook/.pyenv/version)
and on openSUSE Tumbleweed:
22:10:02 [brook@G5-openSUSE:~/DataEXT4/example.com] master(+0/-814,7)* ± pyenv versions
pyenv: version `3.5.7' is not installed (set by /home/brook/DataEXT4/example.com/.python-version)
system
Installing Needed Version
From the output of pyenv versions, above we can see that ony the system Python version is available on both Arch and openSUSE. The openSUSE output is different because the command outputs shown from openSUSE were performed later than the Arch ones and after I had already created a virtualenv based on Python 3.5.7. The virtualenv configuration expected Python 3.5.7, resulting in the error message. Below we install specific versions of Python we need for the project. But first in the two following outputs, we see what happens when we try to install a Python version without specifying the minor version. pyenv informs us available versions that partially match the requested version.
On Arch:
[brook:~/DataEXT4/example.com] $ pyenv install 3.5
The above command with its output:
[brook:~/DataEXT4/example.com] $ pyenv install 3.5
python-build: definition not found: 3.5
The following versions contain `3.5' in the name:
3.3.5
3.5.0
3.5-dev
3.5.1
3.5.2
3.5.3
3.5.4
3.5.5
3.5.6
3.5.7
activepython-3.5.4
pypy3.5-c-jit-latest
pypy3.5-5.7-beta-src
pypy3.5-5.7-beta
pypy3.5-5.7.1-beta-src
pypy3.5-5.7.1-beta
pypy3.5-5.8.0-src
pypy3.5-5.8.0
pypy3.5-5.9.0-src
pypy3.5-5.9.0
pypy3.5-5.10.0-src
pypy3.5-5.10.0
pypy3.5-5.10.1-src
pypy3.5-5.10.1
pypy3.5-6.0.0-src
pypy3.5-6.0.0
pypy3.5-7.0.0-src
pypy3.5-7.0.0
stackless-3.3.5
stackless-3.5.4
See all available versions with `pyenv install --list'.
If the version you need is missing, try upgrading pyenv.
On openSUSE Tumbleweed:
22:10:35 [brook@G5-openSUSE:~/DataEXT4/example.com] master(+0/-814,7)* ± pyenv install 3.5
The above command with its output:
22:10:35 [brook@G5-openSUSE:~/DataEXT4/example.com] master(+0/-814,7)* ± pyenv install 3.5
python-build: definition not found: 3.5
The following versions contain `3.5' in the name:
3.3.5
3.5.0
3.5-dev
3.5.1
3.5.2
3.5.3
3.5.4
3.5.5
3.5.6
activepython-3.5.4
pypy3.5-c-jit-latest
pypy3.5-5.7-beta-src
pypy3.5-5.7-beta
pypy3.5-5.7.1-beta-src
pypy3.5-5.7.1-beta
pypy3.5-5.8.0-src
pypy3.5-5.8.0
pypy3.5-5.9.0-src
pypy3.5-5.9.0
pypy3.5-5.10.0-src
pypy3.5-5.10.0
pypy3.5-5.10.1-src
pypy3.5-5.10.1
pypy3.5-6.0.0-src
pypy3.5-6.0.0
stackless-3.3.5
stackless-3.5.4
See all available versions with `pyenv install --list'.
If the version you need is missing, try upgrading pyenv.
Note that the available versions of Python 3.5 listed when running the above pyenv command on openSUSE are different than on Arch, meaning I will have to install the common version on Arch later, and use that as the virtualenv version when accessing the project in either Arch or openSUSE.
Below we see an installation specifying the complete Python version.
On Arch:
[brook:~/DataEXT4/example.com] 2 $ pyenv install 3.5.7
The above command with its output:
[brook:~/DataEXT4/example.com] 2 $ pyenv install 3.5.7
[brook:~/DataEXT4/example.com] 2 $ pyenv install 3.5.7
Downloading Python-3.5.7.tar.xz...
-> https://www.python.org/ftp/python/3.5.7/Python-3.5.7.tar.xz
Installing Python-3.5.7...
Installed Python-3.5.7 to /home/brook/.pyenv/versions/3.5.7
On openSUSE:
22:12:40 [brook@G5-openSUSE:~/DataEXT4/example.com] master(+0/-814,7)* ± pyenv install 3.5.6
The above command with its output:
22:12:40 [brook@G5-openSUSE:~/DataEXT4/example.com] master(+0/-814,7)* ± pyenv install 3.5.6
Downloading Python-3.5.6.tar.xz...
-> https://www.python.org/ftp/python/3.5.6/Python-3.5.6.tar.xz
Installing Python-3.5.6...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?
WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
Installed Python-3.5.6 to /home/brook/.pyenv/versions/3.5.6
The above openSUSE problems can be solved by installing prerequisites:
zypper in zlib-devel bzip2 libbz2-devel libffi-devel libopenssl-devel readline-devel sqlite3 sqlite3-devel xz xz-devel
Install and Configure pyenv-virtualenv Plugin
Install pyenv-virtualenv Plugin
The pyenv-virtualenv plugin for pyenv can optionally be installed to create and manage virtual environments. The installation is a simple cloning of its github repository.
On all distributions
[brook:~/.pyenv] $ git clone --branch v1.1.5 https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
The above command with its output:
[brook:~/.pyenv] $ git clone --branch v1.1.5 https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
Cloning into '/home/brook/.pyenv/plugins/pyenv-virtualenv'...
remote: Enumerating objects: 2064, done.
remote: Total 2064 (delta 0), reused 0 (delta 0), pack-reused 2064
Receiving objects: 100% (2064/2064), 580.31 KiB | 2.08 MiB/s, done.
Resolving deltas: 100% (1413/1413), done.
Note: checking out '294f64f76b6b7fbf1a22a4ebba7710faa75c21f7'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b
Configure pyenv-virtualenv Plugin
[brook:~/.pyenv] 127 $ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
Setting Python Version
Unlike when running pyenv versions previously, we can now see there are other versions available.
[brook:~/DataEXT4/example.com] $ pyenv versions
The above command with its output:
[brook:~/DataEXT4/example.com] $ pyenv versions
* system (set by /home/brook/.pyenv/version)
3.5.7
The command pyenv local will display the active Python version for the local directory, if set, or a message to indicating that it is not set.
[brook:~/DataEXT4/example.com] $ pyenv local
The above command with its output:
[brook:~/DataEXT4/example.com] $ pyenv local
pyenv: no local version configured for this directory
Setting the version uses the same command but with the desired version specified as below.
[brook:~/DataEXT4/example.com] 1 $ pyenv local 3.5.7
Now pyenv local will show the version set for the local directory.
[brook:~/DataEXT4/example.com] $ pyenv local
3.5.7
Conclusion
In the last section we saw that a version of Python unavailable before installing pyenv and using it to install the desired Python version is set as the Python version for the directory. This Python version will be used in subsequent commands in this directory. It can also be used to create a Python virtual environment using the built in Python 3 method, virtualenv, or pipenv.