And it was never the case (and still isn't) for projects relying on the standard library and a few popular stalwars (requests, psycopg, pandas, and so on), with conservative adoption of new language features.
There's also the fact that 2.7 and before Python seldom added new language systax, whereas 3+ is hell-bent on doing that with every release.
Language toolchain.
You have to do this for all the languages, not just Python. Hence nix and other tools were made.
No, you only have to do this for all popular languages. Unpopular but stable long term languages exist and they are much better for system administration. I guess my point is that the pythons aren't for system admin anymore, they're for writting bleeding edge applications. A Perl interpreter from 2003 can run most Perl applications written today and a .pl script from 2003 will definitely run on a 2024 Perl.
The pythons' roles have changed and are different from the former role of Python. They have lost the stable properties it once had.
For my entire life Perl 5 has been Perl and Perl code just works no matter when the OS system Perl is from. This is the pragmatic reality: it just works. And that's an amazing property for system administration and software distribution.
Use cases evolve over time. "System Python" is a great example. One of the primary Python use cases in its 2.7 days was sysadmin scripts. For that, it made sense to have a "python" command that Just Worked that sysadmins could expect to be on any box when they SSH'd into it. These days, I suspect Python for sysadmin uses is significantly smaller than Python usage in web applications or Python for Jupyter notebooks. Those are two very different use cases, and that's why things like virtual environments, pip, poetry, conda, etc. got created.
There are many languages that are very stable over long periods of time. It's just that Python was a terrible language to begin with that got rushed designs and features tacked on to it over time. Even if you're a "lover" of something like asyncio, there's like three distinct "eras" of asyncio that have you write it in three different ways. Not only that, Python's asyncio is the worst implementation of it that I've seen. That's a common theme in Python packages.
The dependencies thing is due to Maven repositories being The Repository standard for JVM languages. It's a low-key superpower of the JVM ecosystem, warts and all.
The core of the problem is that libraries and even the language itself have to make non backwards compatible changes over time. No system can fix this.
What? People are just making decisions about how they want the language to evolve, how they want to coordinate production-grade releases, and how they approach backwards compatibility in those contexts.
Nothing about those decisions is necessitated or even strongly pressured. They're just an artifact of the Python community's particular engineering culture, and it's one that's uncommonly hostile to streamlined distribution or to shelving application code as stable and "done".
There are C++ libraries that require C++11. As a result if you have an older compiler that does not support C++11 it will just not compile.
Same if you try to compile with C++11 compiler a super old project with old libraries. More likely than not it will break.
The fact that other languages ignore the problem, it does not make the problem go away.
At least python is pragmatist and comes with virtual environments instead of requiring me to set up containers or VMs to deal with package compatibility.