Managing Python Versions with pyenv

With pyenv configured, we can install any Python version from its registry, set a global default, and override it on a per-project basis.

Listing Available Versions

Below command shows the list of all available versions of python that can be installed and managed with pyenv.

% pyenv install -l
Available versions:
  2.1.3
  2.2.3
  ...
  3.9.4
  3.9.5
  ...
  stackless-3.5.4
  stackless-3.7.5

Installing Python Versions

From the output list above, we can pick the version of python that we want to install. Here, we pick two different versions — one from the 3.8 line and one from 3.9 — for better comparative understanding of virtual environments in later chapters:

% pyenv install 3.8.10
python-build: use openssl@1.1 from homebrew
Downloading Python-3.8.10.tar.xz...
Installing Python-3.8.10...
Installed Python-3.8.10 to /Users/username/.pyenv/versions/3.8.10
 
% pyenv install 3.9.5
Downloading Python-3.9.5.tar.xz...
Installing Python-3.9.5...
Installed Python-3.9.5 to /Users/username/.pyenv/versions/3.9.5

Troubleshooting: Missing lzma Module (Python 3.10+)

Python versions in the 3.10+ family may print a ModuleNotFoundError for _lzma during installation. This occurs when the lzma compression library is absent at compile time. We can fix it by installing xz via Homebrew and re-installing the Python version:

% brew install xz
% pyenv uninstall 3.11.3
% pyenv install 3.11.3

Setting Global and Local Defaults

Now, there are 3 versions of python installed in the system — The default system python itself (Python 3.8.2) and two versions that we installed (Python 3.8.10 and Python 3.9.5). Since, we are not supposed to touch system Python at all, we start with setting Python 3.8.10 as the global default. This global default ensures that whenever any user runs a script from terminal (outside of a specifically configured project directory), running the python command will execute Python 3.8.10. Further, we create a Projects directory for managing all projects, and set Python 3.9.5 as local default for this directory.

% pyenv global 3.8.10
% mkdir Projects && cd Projects
% pyenv local 3.9.5
 
% pyenv versions
  system
  3.8.10
* 3.9.5 (set by /Users/username/Projects/.python-version)
 
% cd ..
% pyenv versions
  system
* 3.8.10 (set by /Users/username/.pyenv/version)
  3.9.5

We see different versions of Python are set as default across different directories - one at global level and one locally to ~/Projects. This is managed by pyenv by creating a hidden .python-version file in each directory where pyenv local is run. When we navigate into that directory, pyenv activates the corresponding Python version automatically.