How does a language ecosystem that bakes "there should be one-- and preferably only one --obvious way to do it" into the interpreter* as a statement of values end up with such a convoluted packaging story?
* Try running `python -c 'import this' | sed -n 15p`
Because packaging is a very complex problem, and it's rare that any one packaging solution can get everything right in the first try.
You will notice that every package management solution from all your favourite languages will have its own set of tradeoffs.
This is absolutely true, but I haven't seen any language ecosystems that have gotten things wrong as often as Python.
And quite a few where the tradeoffs are minor enough to be well worth some sanity & consistency.
It's because no-one is in charge anymore, and Guido never cared about packaging anyway.
If you think Guido never cared about packaging, try calling it "The Cheese Shop" in distance of his hearing. :-)
Wasn’t any better back then. Not much of a cheese shop, is it?
You haven't used Swift before I see
The recent CocoaPods SPM migration is almost as painful as py2->3 but it seems to be a clearly understood direction with end in sight.
SPM's manifests being non-declarative is also super problematic for 3P tooling but again - it's one well defined target. Decisions are clear, if a little cumbersome. There's nowhere near the mess of indecision and reduplication you see in python projects.
C++. I think Java is pretty close in nastiness but I haven't used it in a while.
Java is Maven or Gradle mostly. Neither perfectly ideal but there's clear choices by subcommunitues (e.g. Android =>Gradle) & churn is low. Not at all an awful situation.
C++ is mostly unmanaged in practice which is obviously bad (though Python is the only "modern" language where I regularly see published projects without so much as a requirements.txt so very comparable). However looking at the actual options for C++, Conan seems pretty clear cut & not awful in itself.
So... not as bad as Python by any measure imo.
Packaging is hard but it's not hard enough to wholly explain pip.
Lock files alone are a proven piece of technology that pretty much just works across all modern package managers, and yet the best that pip can recommend to date is `pip freeze > requirements.txt`, which is strictly inferior than what is available in other package managers because there's no hash verification and no distinction between transitive dependencies and explicit dependencies.
That pip still doesn't have an answer for lock files is a sign of a deep problem in the Python package management world, not the natural result of packaging being hard.
Lockfile does not work perfectly for me because it does not lock python version. Using a lock file with different python version or even same version but different OS may fail.
That’s literally his point. Other languages have solved this. It makes no sense that it’s not solved in python. (If your not sure how look at a golang go.mod file or a rust Cargo.toml file.)
There's no reason why Python version couldn't be baked into the lock file or package manifest if pip had one. package.json does this [0]. Since all pip has is requirements.txt, it's a bit of a moot point.
[0] https://docs.npmjs.com/cli/v10/configuring-npm/package-json#...
Sounds like you want a nix flake.
pip has had constraints.txt forever, it is equivalent to lock file. Your are not supposed to freeze into requirements.txt.
Hopefully uv can make this the default behavior. It seems like the majority of users are not aware of its existence because it’s an optional flag.
Somehow I've managed to go all this time without ever having heard of this feature. If this is the blessed path, can you explain why the pip docs recommend freezing to requirements.txt [0]? And why does the documentation for Constraints Files in the next section talk about them as though they're for something completely different?
Here's what they say about requirements:
Here's what they say about constraints:
This sounds like something vaguely similar to a lock file, but they seem to intend it to be used globally at the organization level, and they're certainly not pushing it as the answer to locking dependencies for a specific project (they specifically recommend requirements for that). Maybe you can use it that way—although this Stack Overflow answer says that the 2020 update broke it for this use case [1]—but even so it doesn't answer the fundamental need for lock files unless everyone is actually on board with using it for that, and even the pip maintainers don't seem to think you should.
[0] https://pip.pypa.io/en/latest/user_guide/#requirements-files
[1] https://stackoverflow.com/questions/34645821/pip-constraints...
ironic that pip freeze literally generates a requirements.txt with ==
constraints.txt certainly did not exist back when I was doing python.
Conversely Ruby packaging has been a solved problem for a decade, when the python community has been extremely resistant to conceptually similar solutions for the longest time on strange ideological grounds, and came around only recently.
Python refuses to have packages (folders don't count) or accept build steps. Everything follows from there, making it much harder to have a good solution.
Can't even rely on a package to have statically defined dependencies. You can just make setup.py generate a random selection of packages!
Well, there are languages better at incorporating the Zen of Python than Python itself, vide (full disclosure: my blog post) https://p.migdal.pl/blog/2020/03/types-test-typescript/.
When it comes to package managers, as you noted, the situation is even more ironic, as nicely depicted in https://xkcd.com/1987/.
One way to do things becomes impossible to after thirty years unless one wants to make large, breaking changes. After Python 3:
That's been around since at least Python 2.6, and I think I remember seeing it before then:
“After Python 3” doesn’t mean it arrived then. It was supposed to be read, “after Python three … not a chance.”
Haha, didn't know about this easter egg, amazing
What's your view on how Golang deals with this problem? Serious question.
Golang users don’t sit around arguing about package managers, nor do they have trouble with trying to make sure they have the right version of go installed.
Early versions of go didn’t solve things well, but go has had this fixed for a long time now. Any arguments about packaging issues are likely related to older out of date problems people had.
The only real problem people have these days is around private non open source packages. You can do it, but you need to learn how to set environment variables.
Simple: Python is old. It predates most shiny languages by decades, and so does its packaging-trip. I mean, most modern packaging can shine today, because they could learn from the imperfections of their forerunners. Additionally, python has a very wide field to cover, far wider than most other languages, which makes things more complicate and thus people are more open for experiments, which leads to so many different solutions.
Python is old, but pip itself had its 1.0 release 8 months after Ruby's Bundler did and 6 years after Apache Maven, both of which are substantially better package managers than pip and both of which are also for 90s-era programming languages, not the new shiny ones.
Age is part of the problem, but it's not the whole problem. Ruby manages to have a package manager that everyone loves, and Java has settled on a duopoly. Meanwhile Python has someone making a serious attempt at a new package manager every few years.
pip wasn't pythons first package-manager, and obviously wasn't it just created with version 1.0. There were already years of history at that point. But yes, Ruby has a better history with packaging, similar to Perl. Python was kinda always copying Perl and then Ruby in what they did, but still aiming to preserve their own identity and requirements. Which is also why nobody wanted to copy the cargo-cult-pain of the Java-Enterprise-World.
Many People have many attempts at many things in many communities. Doesn't mean they are important. Heck, vim and zsh have also dozens of different package-managers, and they have less use cases and problems to solve then python.