Install and configure pyenv on a Mac

December 15, 2024  [python]  [mac] 

It is well-known that the built-in Python on macOS is not the one you want to use. As an alternative, you could think of Anaconda/Miniconda or Python installed via Homebrew. The latter option can seem like a good choice, but it has a big downside in a sense that Homebrew Python is being quite eagerly updated, and you don’t really have a good control over the version of the interpreter. A nice argument about this issue can be found in “Homebrew Python Is Not For You”. A bottom line is that Homebrew Python is more of a dependency for other Homebrew packages rather than a stable development environment.

A pretty cool feature of sticking with a certain LTS version of a Linux distribution is that you deal with a pre-installed Python of a certain version that remains stable as long as you are on the same version of the LTS. For example, Ubuntu has the the following Pythons (see DistroWatch):

If you want to achieve something similar (or even better) on a Mac, a nice tool for that is pyenv. It is a Python version management system, allowing you to have one or more specific versions of the interpreter. Below you can find some of my notes for installing and configuring Python with a single specific Python version.

Install pyenv via brew:

$ brew install pyenv

Add the following to your ~/.zhsrc:

export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)" 

Now, having ~/.zhsrc sourced, we can start installing Python of certain version. We can start by browsing what versions are available in general:

$ pyenv install -l

Let’s say we want to have an exactly same version as on Ubuntu 24.04, namely Python 3.12.3:

$ pyenv install 3.12.3

Then, if we want this version to be our global default, run the following command:

$ pyenv global 3.12.3

Once this is done, when you cat $HOME/.pyenv/version, you will see this file containing “3.12.3”, and the python command will point to the pyenv-managed interpreter of exactly this version.

Then you can go ahead and create “vanilla” virtual environments inside you projects, which will link to this “default” Python:

$ python -m venv .venv

I often like having a separate virtual environment with a lot of the important libraries installed that I keep up-to-date and use for quick tinkering. Let’s say we call this environment main_venv and we put it inside a directory named code:

$ cd code
$ python -m venv main_venv
$ main_venv/bin/activate
(main_venv) $ pip install numpy scipy pandas matplotlib ipython

To activate such environment from any directory, the following shell script function (added to ~/.zshrc) can be used:

main_env_activate() {
	cd $PATH_TO_CODE # (absolute path to the `code` directory)
	source main_venv/bin/activate
	cd - > /dev/null # back to the original directory without anything being printed
}

I have an earlier blog post, where I show how to keep such an environment updated.

There are much more use cases of using pyenv, like using it to actually manage several Python versions, and having “local” configuration per directory. Some more resources about pyenv:

comments powered by Disqus