One of my biggest gripes about brew is how they manage dependencies. The devs have a conflicting philosophy that creates bloat. Package maintainers must define settings, settings should always use the latest Python version. It makes no sense. Maintainers won't update unless things break so you got a bunch of Python versions running around. And it won't use system Python!
Uv seems to provide an elegant solution for this. You can build a venv for each package and rust version will only have the specified deps. Since uv finds all your Python instances (and packages) and soft links them you have way less bloat and venvs become really useful. You can also use run and other tools to handle executables
You should only be using Homebrew for installing software that happens to be written in Python, not dependencies for your own Python projects. If you do that, the Python version does not matter, it's just whatever version is required to make the package work.
I'm not doing that. Honestly I'm not sure how to do that and it sounds like a real pain.
> the Python version does not matter
This is incorrect. Go check what versions of Python brew has installed for you. It's definitely not your system version...
It's not "what works" it is "what the maintainer specified". And according to the brew devs this is supposed to be /the latest version that works/. Which was my point. People don't update just on a Python change. That's not going to happen without automation. (I even suggested we be allowed to specify the minimum version and I was told it's maintainer's responsibilities). You can trivially find packages that can be used with newer versions of Python than their brew formulas specify.
* One of the main reasons Homebrew doesn't use the "system" Python is because Apple has repeatedly indicated that they want to remove it, and that integrators should not depend on it. This, plus per-package Python version requirements makes using a single system Python a non-starter.
* The "bloat" you're noting in Homebrew around multiple Python interpreters is present in `uv` and `pyenv` as well: `uv` handles multiple interpreters transparently, so you may not even realize how many you have installed. I think this is a good pattern: disk space is cheap relative to the timesink of connecting the right Python version to the right set of packages, which is why every distribution scheme (including both Homebrew and Debian) prefers to distribute multiple Python versions.
> because Apple has repeatedly indicated that they want to remove it
That's not a reason to not use it. There's absolutely zero reason for me to have two copies of an exact same Python version (e.g 3.11.4). There is rarely reason to have a differing subversions (3.11.3 vs 3.11.4).
> is present in `uv`
Are you guessing or do you know? Try it out. Prove me wrong.
I said they search for versions on your system and link if found. Seriously, look into it
> disk space is cheap
That's not correct. It's a thing you need to consider when you have to compromise but not an infinite resource. But there's something cheaper than storage: infrequently scanning the system!
The problem is when everyone thinks this way then space is no longer cheap (especially with Apple!)
Tragedy of the commons
In fact it's a big reason I live in the terminal. Because even on a modern M2 air that bloat creeps in. My system is fast and snappy. I have plenty of storage. But this isn't true if I didn't. The creep still happens in these programs but their nature lessens the blows and the likelihood that people care about these things increases.
It is, in fact, an excellent reason not to use it. Homebrew runs on tens of millions of machines; we are absolutely not going to rely on things that we're told not to rely on unless absolutely necessary. Python is readily buildable and we already need to build multiple versions for reasons aforementioned, so this condition does not apply.
Also note, it's stronger than what I originally said: 10.15 doesn't ship with Python by default at all anymore. I only have it installed (at 3.9.6) because I also have XCode installed. Homebrew supports being used without XCode or the CLT, so that alone would be a hard blocker for system Python for us.
> Are you guessing or do you know? Try it out. Prove me wrong.
My `uv python list` shows that I have 3 uv-managed versions of Python installed, along with 5 pyenv versions and 2 Homebrew versions. I have more than most people because I test large matrices of Python versions at once, but I imagine a normal Python developer isn't too far off.
You can test this for yourself with the same command. If you're developing more than one Python library or application at a time, I strongly suspect `uv` or `pyenv` is using more space for Python versions than Homebrew is.
>> there's something cheaper than storage: infrequently scanning the system!
The solution already exists
If required python version does not exist, download.
This is already being done. The missing part is the scanning of the system. I need to make this abundantly clear: You do not need to rely on Apple for this to be a solution. Furthermore, even if Apple completely removes python, making this change would still improve brew and reduce bloat. This is why I didn't care about that comment. Because it is inconsequential to what I'm suggesting. If they remove python you're in the exact same position as not having the right version of python. It is equivalent. I'm not sure why you're harping on this.
> My `uv python list` shows
You're again missing the point. It isn't about having different versions, hell I got 3.13, 3.12, 3.11, 3.10, 3.9, and 3.8 on my system. The problem is having redundant copies of the minor (or even patch) versions. When I installed `uv` I uninstalled brew, purged everything, and reinstalled. This is because when I'm creating a new venv it isn't actually `uv` that is installing a new python version, it is linking one that was installed by brew. When I was using Anaconda, conda didn't search for existing versions (and packages), it just installed its own. You might be thinking this isn't a problem with brew and a problem with conda, but that's passing the buck. Brew is making the same error that conda was and thinking brew is better and that the solution should be fixed by others is just idiotic. Its blaming those downstream for a problem that's being created. If a "crime" is a "crime" then it doesn't matter who does it.
We're getting off topic now, since this is besides the point. But hey, here's a few things that can help look at the system and what's happening.
On my system, brew installed 3.13, 3.12, and 3.11 (you can guess when I purged). For good measure, try this instead
brew list | xargs -P8 -n1 sh -c 'brew cat "${0}" | grep "depends_on \"python@3." | sed -e "s/.*\(python@3\.[0-9]*\).*/\1/g"' 2> /dev/null | sort -u
This will go through all your brew packages and find the python depends. My output shows 3.11 and 3.12. Interestingly, no python 3.13, though brew installed this. Interesting considering brew and brew-core don't have python code (according to github). Maybe something installed it and then I removed it. I'm unsure. But let's edit our command and check only those python@3.11 instances.
I checked the formulas on github, none of those even have python 3.11 anymore. These are cryptography, libxml2, numpy, py3parser, py3cairo, python-cryptography, pygobjects3, and python-packaging. With the exception of python-cryptography and python-packaging (no GitHub formula), the brew formula on GitHub depends on both 3.12 and 3.13 for every one of these. There is no dep for 3.11! Did a `brew update` and `brew upgrade` and they're still 3.11. But hey, now the first brew list command reports 3.11, 3.12, and 3.13. Doing `brew info python-cryptography` there's a green checkmark on `python@3.12` and `python@3.13` (`python@3.11` is not shown), while `python-setuptools` has a red x despite the fact that I have setuptools installed in both 3.13 and 3.12 in different uv environments (it also isn't finding rust). So it certainly isn't finding packages and trying to reduce redundancy which is the big problem `uv` tries to solve in the first place.
Why should brew handle 3.11.3 differently from 3.11.4, just because you have another copy of it on your computer? What if apple patches it or updates the version suddenly?
That kind of magical special case behavior is not intuitive and creates more problems than it is worth.
My experience was actually the opposite -- a package I used broke because somebody did an automated "bump the python version this package uses" change without noticing that upstream for the package hadn't yet made a release with the necessary changes to make it work with that python version, so it fell over on startup. (They were quick with reverting it when I reported the problem.)
love uv <3 I will look into integrating that. Have not decided if and how to implement my own packaging / source build dsl though and will probably open a git poll for that the coming days
Awesome! I look forward to see how this progresses! It'll be nice to have a package manager that supports true multithreading and is just overall a lot faster. There's a lot of things that are needed that brew simply just can't do.
I haven't played around with this yet (will this weekend!) but I know brew is way too verbose and IO is a big slowdown. Probably doesn't matter because it is written in ruby. But it's an easy thing to miss and is quite common for people to not recognize this. Like when people use `tar xvf` instead of `tar xf`, there's a very noticeable speed difference for many packages lol. (Sorry if I'm preaching to the choir here. It's a pet peeve of mine given how common this is)
Is there uv support?[0]
One of my biggest gripes about brew is how they manage dependencies. The devs have a conflicting philosophy that creates bloat. Package maintainers must define settings, settings should always use the latest Python version. It makes no sense. Maintainers won't update unless things break so you got a bunch of Python versions running around. And it won't use system Python!
Uv seems to provide an elegant solution for this. You can build a venv for each package and rust version will only have the specified deps. Since uv finds all your Python instances (and packages) and soft links them you have way less bloat and venvs become really useful. You can also use run and other tools to handle executables
Plus is also rust so good synergy ;)
[0] https://astral.sh/blog/uv