We've got about 15 repos, with the largest repo containing about 1575 files and 34MBytes of .py source, 14 current developers (with about 40 over the last 10 years) - and they really are quite proficient, but haven't demonstrated any interest at looking at anything outside pip/virtualenv.
Is there a reason to look at poetry if you've got the pip/virtualenv combination working fine?
People who use poetry seem to love it - so I'm interested in whether it provides any new abilities / flexibility that pip doesn't.
Package management is terrible work. Nobody appreciates it. It's extremely complex, it has to work in enormous numbers of configurations, and very minor errors can have catastrophic impact to security or availability of systems.
I'm in the same boat as you in that I'd like to keep using pip but the lack of a lock file is very dangerous because it doesn't guarantee reproduceable builds (even if you use Docker).
In Ruby, Elixir and Node the official package managers have the idea of a lock file. That is the only reason I ever look into maybe switching away from pip.
Running a pip freeze to generate a requirements.txt file doesn't work nicely when you use a requirements.txt file to define your top level dependencies.
I've been bitten by issues like this so many times in the past with Python where I forgot to define and pin some inner dependency of a tool. Like werkzeug when using Flask. Or a recent issue with Celery 4.3.0 where they forgot to version lock a dependency of their own and suddenly builds that worked one day started to break the next day. These sets of problems go away with a lock file.
> [The new resolver] will reduce inconsistency: it will no longer install a combination of packages that is mutually inconsistent. At the moment, it is possible for pip to install a package which does not satisfy the declared requirements of another installed package. For example, right now, pip install "six<1.12" "virtualenv==20.0.2" does the wrong thing, “successfully” installing six==1.11, even though virtualenv==20.0.2 requires six>=1.12.0,<2 (defined here). The new resolver would, instead, outright reject installing anything if it got that input.
[0]: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-rol...
Though, poetry is actually quite good. There are still some things that I wish it had, like plugin support (for example I really miss setuptools_scm) or being able to use it for C packages.
But if your code is pure python it is great from my experience. The dependency resolver is especially good.
1. Packages are downloaded in parallel. This means dramatically quicker dependency resolution and download times.
2. Packages can be separated for development versions production environments.
3. Poetry only pins the packages you actually care about, unlike a pip freeze. One application I work on has 15 dependencies, which yields a little over 115 packages download. pip freeze makes it impossible to track actual dependencies, whereas poetry tracks my dependencies - and the non-pinned packages are in the poetry.lock file.
The rest is nice, but the above is essential.
The methodology of specifying your core dependencies, but also having locked version of your dependency's dependencies works really well.
AND you can easily export to requirements.txt if you prefer to use that in production.
At the macro level, this seems like a bit of a self-fulfilling prophecy: if all the senior and principal engineers using Python don't care to take a look at something else, then it's not too surprising that new solutions don't end up sticking around. That isn't too say that there does necessarily need to be a change in the Python community's choice of package manager, but the rationale for not even considering looking at other options doesn't seem super compelling.
Also I can use it for all software regardless of what laguage it's written in, not to mention having to learn multiple half-baked package managers per laguage!
And lastly any non trivial software project will need dependencies outside of the world of its own package manager anyway, so why not go all in properly with rmp/deb & make everything easier for your users & your future self.
You probably have a bunch of scripts that do what poetry does (either that, or you repeat the same commands over and over A LOT).
Switching to poetry might have some initial overhead, but a big upside is that you stop using custom, internal tooling, and use something industry-standard. Importantly, it makes it easier for you to understand external projects (since you're familiar with the standard tooling), and faster to onboard newcomers.
pip + venv + requirements.txt doesn’t solve this out of the box while most languages have common tools that do. Either they’ve rolled their own way to manage these things, or they’re rolling the dice every time they deploy.
Poetry is still rough around the edges but I think the core experience is great and it's well on its way to be a very popular tool.
Before using it at work, we are waiting on waiting on https://github.com/python-poetry/poetry/issues/2610 (alternate repository not getting used for transitive dependencies) and ideally this https://github.com/python-poetry/poetry/issues/1556 (disable SSL verify for alternate repositories)
If you don't use your own PyPi for a bunch of internal packages, it works great imo. One more wish item would be having absolute path dependencies instead of only relative path.
Internal doesn’t mean secure
Switched to poetry for one of my libraries as a test a few weeks ago, noticeably more painless!
One other thing I liked about it is the community, I distinctly remember digging into the setuptools source code once to find something that was undocumented. With poetry, that was one Discord message away.
The poetry lock file also seems to get ignored for git dependencies. Say I depend on package Foo, on branch Bar, as a git dependency. At install time I get revision 1, which gets added to the lock file. Now let's say the head of branch Bar moves to revision 2. If I re-run poetry install, I now get revision 2, even though revision 1 is still mentioned in the lock file. The solution is simple: depend on revisions / tags, rather than on branches (and this sounds like good practice anyway), but it is surprising behavior.
As a fan of pip's simplicity, I hope this won't become the case.
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
call me security paranoid, but curl | interpreter
is not an installation method.Which uses pip-tools under the hood. It even has a pre-commit-hook to make sure your packages lock files are up to date
The Python ecosystem is older than our modern conception of how a package manager should behave. Any new package manager must build on top of that chaotic history. Absent a time machine, your comment just seems like a vague lament about the state of the world.
It is also very possible to write code to completely work around old issues so the newest version of your package manager just works or at least outputs clear error messages with mitigation steps, but instead what you get is obscure stack traces when you run pip install.
It’s also not universal: it’s been a decade since I’ve had to worry at all about that and even before then it was uncommon except on projects which weren’t trying to be very clever. If you had a clean setup this really hasn’t been the rule for a long time.
Unfortunately I don't live in that world :(
I have had FAR more issues with performing Bundler/Ruby upgrades than I've ever had with Python.
https://github.com/pypa/setuptools/issues/2352
I've also had to play the pip version pinning game a few times in the past.
Contrast this with a language like Rust or JS, where you run one command once to install everything
I'm a big Python fan; it was my first language and still by far my most-used and the one I know best. But the "developer experience" is undoubtedly a giant mess compared to something like Go or Rust. (Rust also appears to be having some growing pains related to async, but everything else seems way more solid.)
Despite Python's catchphrase "there should be one, and preferably only one, way to do it", Go really embodies this across every dimension. One way to install the runtime, one way to format, one way to package, one way to do concurrency, one way to test, one way to write most things. And every version is almost completely backwards compatible.
It's kind of crazy that a language that (justifiably) prides itself in its programming simplicity also makes you deal with tangled messes like https://xkcd.com/1987/
My one solace is that some all-in-one third-party tooling is finally close to the level of convenience you get with Rust. pyenv and poetry save a ton of headache when it comes to managing Python versions and packages, and "just work" in a pretty similar way as rustup and cargo.
There are zero package managers from any environment for which these requirements are met.
I think it depends a lot upon the culture of the ecosystem, maven being fairly conservative is a natural consequence of Java being very enterprise focused.
C#, C++ (Conan) and Java, Linux(apt, yum, etc) and most certainly JS/TS.
What is so hard about "installing code, packages" in python for you?
Did you go create a test case? Or at least link to a specific issue?
https://github.com/pypa/pip/blob/master/.azure-pipelines/scr...
I'm very surprised. Is this common?
Let's say you have 200 JS libraries that you need to install dependencies, build and test for each commit. Making the JS dependencies install into a common cache directory into /dev/shm will easily speed up the install phase (and make the projects share dependencies cache fairly easily), and you could also make the test data (like fixtures) go through /dev/shm if you need it to.
conn = sqlite3.connect(":memory:")
But also run against your prod-like database (Postgres/MySQL etc.) later in the CI pipe to catch idiosyncratic database problems.
https://dev.to/thejessleigh/speed-up-your-postgresql-unit-te...
In my environment unpacking a 200MB .tar.gz containing node_modules from previous runs takes half the time on RAM disk vs. SSD local storage. Python doesn't gain as much, packages tend to have fewer small files but there still is a small gain.
How much tests benefit from using a RAM disk depends heavily on what they do, I have seen 10% for React apps.
We also use other simple tricks like running databases with disabled fsync, mv instead of rm, cache whatever can be cached between CI runs, shallow checkouts and so on. Nothing ground breaking but it all adds up.
However, for pipelines which run for five minutes twice a day I don't even bother.
The drawbacks are that memory is kinda expensive in high amounts, and compilers love memory.
On the other hand I would love to use the shiny new feature, but explaining it to my manager would be like talking to a tree.
Versions ≥ 18 refer to the years 2018+; they don't refer to the number of versions released anymore.
me: ooo... new shiny toys.
new version of pip comes out. again.
me: :( this will probably break something. again.
I now just tell people to use conda.
Yeah. No.
most recently (october?) they vendored some package that was a system dependency before, and it broke the vendored versions of pip (eg. on debian).
I get, “not their fault” debian goes and modifies packages... but from a user perspective: it broke.
I would say my experience is roughly on every six months something to do with pip breaks for me... but I really cant be bothered trying to keep track of it.
I just try to avoid using it now. Down vote all you like, I don't care. Pip has broken my CI enough times its lost any good will it ever had with me.
I remember issues when they changed their caching mechanism, or when a couple of libraries I was using were importing internal stuff from pip which got changed in a new version.
Also some packages for some reason need to be installed in the correct order and it's not immediately clear until pip tweaks their installation procedure.
> The new resolver now resolves packages in a deterministic order. (https://github.com/pypa/pip/pull/9100)
$ pip install "six<1.12" "virtualenv==20.0.2" -q
ERROR: Cannot install six<1.12 and virtualenv==20.0.2
because these package versions have conflicting
dependencies.
ERROR: ResolutionImpossible: for help visit
https://pip.pypa.io/en/latest/user_guide/#fixing-conflicting-dependenciesPermalink to the release notes: https://github.com/pypa/pip/blob/c31c148a5b1d87591862c715adc...
I'm surprised I never ran into the issue, but I suppose it mainly show up if you have a large number of dependencies?
If it's just the order, then that's really lame.
There are two kinds of dependencies:
- fluid ones, where you specify immediate dependencies of your application with version ranges (typically versions that are api compatible with your app) - locked versions (this is what requirements.txt supposed to be)
You get can get this kind of behavior if you define packages in setup.cfg in install_requires and then use pip-compile (from pip-tools) to generate requirements.txt based on it. pip-sync can then synchronize packages to requirements.txt.
Alternatively you could just use poetry which does all of this with a nicer interface.
Most Python devs don't seem to realize that the packaging problem is now solved:
Frankly I would still be using it if it wasn't that PyPA really trying hard to kill it.
This forced me to try poetry though and is quite decent frankly. I wish it would support building C packages though and I'm missing plugins like setuptools_scm which generates package version from SCM (e.g. git) tags.
https://pypi.org/project/pip-review/
> pip-review Faker==4.18.0 is available (you have 4.17.1) pip==20.3 is available (you have 20.2.4)
> pip-review --auto --verbose Collecting Faker==4.18.0 Downloading Faker-4.18.0-py3-none-any.whl (1.1 MB) || 1.1 MB 730 kB/s Collecting pip==20.3 Downloading pip-20.3-py2.py3-none-any.whl (1.5 MB) || 1.5 MB 2.0 MB/s Requirement already satisfied: python-dateutil>=2.4 in /usr/local/lib/python3.8/site-packages (from Faker==4.18.0) (2.8.1) Requirement already satisfied: text-unidecode==1.3 in /usr/local/lib/python3.8/site-packages (from Faker==4.18.0) (1.3) Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.8/site-packages (from python-dateutil>=2.4->Faker==4.18.0) (1.15.0) Installing collected packages: Faker, pip Attempting uninstall: Faker Found existing installation: Faker 4.17.1 Uninstalling Faker-4.17.1: Successfully uninstalled Faker-4.17.1 Attempting uninstall: pip Found existing installation: pip 20.2.4 Uninstalling pip-20.2.4: Successfully uninstalled pip-20.2.4 ERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts.
We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.
lektor 3.2.0 requires Werkzeug<1, but you'll have werkzeug 1.0.1 which is incompatible. Successfully installed Faker-4.18.0 pip-20.3
With this, it's a lot easier to upgrade everything without getting conflicts: pip freeze | cut -d= -f1 | xargs pip install --upgrade.