β python-is-python3 with macOS homebrew
β’ 494 words β’ 3 min β’ updated
I face this annoyance all the time:
thiago@thiagoperrotta-MacBook-Pro ~
% python
zsh: command not found: python
127 thiago@thiagoperrotta-MacBook-Pro ~
% python3
Python 3.14.0 (main, Oct 7 2025, 09:34:52) [Clang 17.0.0 (clang-1700.0.13.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>The python executable is not available on macOS natively.
It is not available on homebrew either, even with brew install python.
python3 is there though:
% which -a python3
/opt/homebrew/bin/python3
/usr/bin/python3I want to be able to run python without having to remember I am running
Python 3. Python 3 is the de facto standard in the 2020s, there should be no
need to remember this explicitly, we take it as gospel already.
There are various ways to resolve this:
alias python=python3Classic. I hate it. Now you’ll have a python alias even if python3 is not
available. This is not elegant at all. You could make it a bit better, sure:
command -v python3 >/dev/null 2>&1 && alias python=python3Or even a bit more idiomatically if using zsh:
(( $+commands[python3] )) && alias python=python3Still, this is not a problem the shell should own. It just feels wrong. This is a package management problem. The shell remedy is just a cheap band-aid. Can we do better than this?
What about a wrapper script in /usr/local/bin?
#!/usr/bin/env bash
exec python3 "$@"This is better. Much better. However, why not make it even simpler?
% sudo ln -s /usr/bin/python3 /usr/local/bin/pythonA symlink suffices. You just need to decide whether to point it out to python3
in homebrew or in the system.
A symlink is not reproducible1 though. If you reinstall your system, or acquire a new one, now you’ll have to remember to re-create it.
Sure, you could script it in your .dotfiles installation script, or add it to the system installation notes section in your second brain app. Who am I to tell you what to do?
Here is my favorite way to address the issue: install a package!
For example, there was a time in Debian and Ubuntu that the
python-is-python3 package
did exactly that:
This is a convenience package which ships a symlink to point the /usr/bin/python interpreter at the current default python3. It may improve compatibility with other modern systems, whilst breaking some obsolete or 3rd-party software.
Now you can guess what the source of my inspiration was. I created a homebrew formula to do the same:
class PythonIsPython3 < Formula
desc "Make python point to python3"
homepage "https://github.com/thiagowfx/homebrew-taps"
url "file:///dev/null"
version "1.0"
sha256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
depends_on "python"
def install
bin.install_symlink Formula["python"].opt_bin/"python3" => "python"
bin.install_symlink Formula["python"].opt_bin/"pip3" => "pip"
end
endAnd now that I have a formula, I need to create a tap to host it somewhere.
Hence https://github.com/thiagowfx/homebrew-taps is born.
To install it:
brew tap thiagowfx/taps
brew install python-is-python3Enjoy peace!
% which python
/opt/homebrew/bin/python-
This is a very loose usage of “reproducible”. Sorry Nix folks, I meant no harm! ↩︎