I’ve just migrated from Ubuntu to macOS for work and am still in the process of setting up the machine. I’ve been a lifelong Linux user and this is the first time I’ve picked up an OS that’s not just another flavor of Debian. Primarily, I work with Python, NodeJS, and a tiny bit of Go. Previously, any time I had to install these language runtimes, I’d execute a bespoke script that’d install:

  • Python via deadsnake1 ppa.
  • NodeJS via nvm2.
  • Go from the official binary source3.

Along with the hassle of having to manage three version managers, setting up multiple versions of Python almost always felt like a chore. I’ve used pyenv4 before which kind of feels like nvm and works quite well in practice. However, on Twitter, I came across this5 reply by Adam Johnson which mentions that asdf6 can manage multiple runtimes of different languages—one version manager to rule them all. Also, it’s written in pure bash so there’s no external dependency required for the tool to work. Since I’m starting from scratch on a new OS, I wanted to give this a tool to try. Spoiler alert, it works with zero drama. Here, I’ll quickly explain how to get up and running with multiple versions of Python and make them work seamlessly.

Prerequisites

For this to work, I’m assuming that you’ve got homebrew7 installed on your system. Install asdf with the following command:

brew install asdf

Once asdf is installed, you’ll need to install the Python plugin8. Run this:

asdf plugin-add python

Also, you’ll need to make sure that your system has these9 plugin-specific dependencies in place.

Bootstrapping Python

Once the prerequisites are fulfilled, you’re ready to install the Python versions from the source. Let’s say you want to install Python 3.11. To do so, run:

asdf install python 3.11.0

This will install Python in the /Users/$USER/.asdf/shims/python3.11 location. Just concat the command to install multiple versions of Python:

asdf install 3.10.15 && asdf install 3.9.9

Selecting a specific Python version

Once you’ve installed your desired Python versions with asdf, if you try to invoke global Python with python or python3 command, you’ll encounter the following error:

No version is set for command python3
Consider adding one of the following versions in your config file at
python 3.8.15
python 3.11.0
python 3.10.8

To address this, you can run the next command to select the latest available version of Python (here it’s 3.11.0) as the global default runtime:

asdf global python latest

Running this will add a $HOME/.tool-versions file with the following content:

python 3.11.0

You can also select other Python versions as the global runtime like this:

asdf global python <python-version>

In a project, if you want to use a specific Python version other than the global one, you can run:

asdf local python <python-version>

This will add a $PATH/.tool-versions similar to the global file. Now you can just go ahead and start using that specific version of Python. Running this command will create a virtual environment using the locally specified Python runtime and start the interpreter inside that:

python -m venv .venv && source .venv/bin/activate && python

Removing a runtime

Running asdf uninstall python <python-version> will do the trick.

Recent posts

  • Protobuffed contracts
  • TypeIs does what I thought TypeGuard would do in Python
  • ETag and HTTP caching
  • Crossing the CORS crossroad
  • Dysfunctional options pattern in Go
  • Einstellung effect
  • Strategy pattern in Go
  • Anemic stack traces in Go
  • Retry function in Go
  • Type assertion vs type switches in Go