Updating Python on macOS

Today it was announced that StarkNet 0.10.0 was released to the Goerli testnet. This update means that there’s a new version of the cairo-lang python package (version 0.10.0) whose release notes mentions that it depends on python 3.9 instead of 3.7.

I haven’t used python in a long time as I have relied mostly on node (javascript) for backend development so I’ve found myself re-learning the basics of python. One of those basic skills that I have to familiarize myself with is how to properly update the python binary.

When I installed python a few months ago I used homebrew given how convenient it is as a macOS package manager. You can of course install python directly from source but I wanted to find a method to keep upgrading my python binary using homebrew.

Managing Multiple Binaries

I started off by checking what version of python I had installed.

$ python --version
>>>
zsh: command not found: python

Interestingly, my system didn’t have a python binary. I’m guessing this might be by design as there was a binary for python3 instead.

$ python3 --version
>>>
Python 3.8.9

My first attempt was to update all the packages managed by homebrew hoping to get python 3.9.

$ brew update && brew upgrade

Once it was done, I checked again the version returned by the python3 binary.

$ python3 --version
>>>
Python 3.10.6

Upgrading the package through homebrew gave me the latest minor version available, in this case 3.10. This is most likely fine as minor versions don’t introduce breaking changes (in theory) but I still wanted to make sure to have the same package referenced by the release note, python 3.9. For that end I had to ask homebrew to install that particular version of the binary.

$ brew install python@3.9

At that point my system had two different binaries: python3 using version 3.10.6 and python3.9 using version 3.9.13.

$ python3 --version
>>>
Python 3.10.6

$ python3.9 --version
>>>
Python 3.9.13

My plan was to create a symlink that allowed me to use the command python (without the version at the end) but that actually executes the python3.9 binary. For that I had to find out where those binaries are stored.

$ which python3
>>>
/usr/local/bin/python3

$ which python3.9
>>>
/usr/local/bin/python3.9

Once I had located the folder where binaries are stored, creating the symlink was easy.

$ cd /usr/local/bin
bin $ ln -s python3.9 python
bin $ ls -al python
>>>
python -> python3.9

I can now invoke the python binary and under the hood use python 3.9.13 as it was my initial goal.

bin $ python --version
>>>
Python 3.9.13

While I was at it, I did the same for pip, python’s package manager.

bin $ ln -s pip3.9 pip
bin $ ls -al pip
>>>
pip -> pip3.9

bin $ pip --version
>>>
pip 22.2.2 from /usr/local/lib/python3.9/site-packages/pip (python 3.9)

Now both python and pip binaries are pointing to the version I was looking for.

Updating the Virtual Environment

Updating your global installation of python doesn’t automatically update the binary used on your cairo virtual environment as you can see below.

$ source ~/cairo_venv/bin/activate
(cairo_venv) $ python --version
>>>
Python 3.8.9

Normally, you can update the binary inside the virtual environment by using the upgrade flag for the venv command. Because you must run this command from outside the venv I had to deactivate the active virtual environment (cairo_venv) first.

$ deactivate
$ python -m venv --upgrade ~/cairo_venv

This unfortunately didn’t quite work for me because I used the python3 binary (v3.8.9) when I created the venv for the first time. To understand what happened I went back to the cairo_venv virtual environment to find out where the python binaries are stored.

$ source ~/cairo_venv/bin/activate
(cairo_venv) $ which python
>>>
/Users/david/cairo_venv/bin/python

Navigating to that path and listing all the python binaries available we can see the problem.

(cairo_venv) $ cd /Users/david/cairo_venv/bin
(cairo_venv) bin $ ls -al | grep python
>>>
...
python -> python3
python3 -> /Library/Developer/CommandLineTools/usr/bin/python3
python3.9 -> /usr/local/opt/python@3.9/bin/python3.9
...

Running the upgrade command for the venv didn’t update the version used by the python3 binary that is referenced (symlink) by the python binary, it instead added a new python3.9 binary that has the version we are looking for inside the virtual environment.

(cairo_venv) bin $ python3.9 --version
>>>
Python 3.9.13

To update the symlink for the python binary we can use the flag -f to the ln command.

(cairo_venv) bin $ ln -sf python3.9 python
(cairo_venv) bin $ ls -al | grep python
>>>
...
python -> python3.9
...

With the symlink now the python binary inside the venv points to the version I wanted.

(cairo_venv) bin $ python --version
>>>
Python 3.9.13

Strangely, I didn’t have the same issue with pip inside the venv as it was already pointing to the correct version.

(cairo_venv) bin $ pip --version
>>>
pip 22.2.2 from /Users/david/cairo_venv/lib/python3.9/site-packages/pip (python 3.9)

Updating and managing the python and pip binaries was way more work than I expected but at least now I know how to do it properly.

1 thought on “Updating Python on macOS”

So, what do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.