Ask HN: Why Poetry did not become a mainstream package manager for Python?
I have recently been introduced to Poetry. I am a pretty experienced Python dev with both back-end and ML in my project basket. However, I have been using pip/requirements.txt/setup.py so far for every single project I had done. But once I have tried Poetry, I do not think I will ever go back.
I was wondering why is it not more popular? What is holding it back? What do you think?
103 comments
[ 4.7 ms ] story [ 157 ms ] threadThey did mess up the python 2/3 and imho they just don't want to deal with such things anymore.
Deprecating stuff is necessary as well as it is necessary to provide an upgrade path (both documentation and tooling) and new stuff.
In what way were you being forced to use tox?
The incurable optimist in me thinks that there is a set of best practices that are emerging across multiple languages, that there is a "right way to do it" that we're converging on. Poetry seems far closer to that correct approach than anything else I've tried in Python and I hope that means it will have some longevity.
The realist in me expects that some time in the next few years there will be another new hotness I'll have to decide whether to migrate all my stuff to.
Tox automatizes the process of creating such environments.
Just out of curiosity, what exactly is your problem with tox?
I'd like to see a harmonization of packaging for 3.11.
Of course, the vibe is not strong enough for me to exit the peanut gallery and contribute, so maybe we should be thankful for what we have from the thousands of human-years already invested.
https://gist.github.com/tiran/2dec9e03c6f901814f6d1e8dad0952...
If there's no real problem with the existing tools, then people will not change their tested and trusted way of working for some fancy new tool, no matter what that new tool promises!
There's an old engineering proverb about that: if it works don't mess with it.
Is there something crucial I’m missing? I feel like package management has largely been solved in python, but I admittedly haven’t done a lot of research into what other workflows are out there.
Pip’s dependency solving strategy is not correct, especially if you install pip packages one at a time.
A real dependency solver would download the metadata for all matching versions (can be done with two seeks for a wheel but gotta run setup.py for an egg…) do an smt solve and then install the wheels.
Pip just starts installing packages, hopes for the best, sometimes backtracks, often gets stuck or does the wrong thing.
One is that the dependencies are a beast. The risk that it won't find a solution between a number of libraries that are only compatible with certain versions is high.
The other one is that ML projects themselves contain data, often large amounts of data.
For instance a "word2vec" style model might be 1 gigabyte and it might be a part of another model. (Say you turn the words to vectors then put the vectors through a CNN or RNN.) The Python packaging system might be a logically correct place to store this data (a necessary part of the the model) but it's a big file that will cause hassles if you do everything right, big hassles if you do things wrong (like compress anaconda packages with slow bzip2, use whatever algorithm that Docker uses to superamplify I/O, ...)
It is nice to pack all your "empty" models (ready to train) as python packages and maybe even your "trained models" (some data files to supplement the empty files) but it will take some iteration to make it all go smoothly.
I suspect my use cases haven't been as complicated as some of the others listed in this thread, which may be why I've never felt the need to look into poetry and others.
And plus, it's just super confusing. It's never been clear to me what the difference between pip and pip3 is. I thought pip3 was for python3 packages, but it seems like pip can also be used for python3 as well. But then sometimes it seems like if I use pip I only get the python2 version.
With npm or go get, if I install a package I know exactly where it got installed a how to mnaually remove if needed. If I install something with pip, the newly installed package goes into some mysterious directory whose location is never quite certain.
So yes, there are major problems with pip, hence why competitors are showing up like poetry.
It's pretty simple; pip3 will always be for python3, pip2 will always be for python2. pip is context dependent, for example if you are in a python2 venv, it will use py2, and vice versa.
> With npm or go get, if I install a package I know exactly where it got installed a how to mnaually remove if needed. If I install something with pip, the newly installed package goes into some mysterious directory whose location is never quite certain.
If you pip install a library, it will almost definitely be installed in pythondir/lib/site-packages, unless you have messed around with your installation
pip install "pip<22"
To check which pip is for which python:
pip --version
Pyenv is pretty great for managing multiple python versions.
pip3 is the name of the system installation of the pip executable corresponding to the python 3.x installation on linux systems (maybe Mac, too) when installed from system package managers on systems where python3 is the name of the python 3.x executable when installed from the package manager.
This is not really a pip issue, but a “how python is packaged to support side-by-side system installations” issue.
Personally, I use pipenv (manages package dependencies and sub-dependencies), pyenv (python version management), and pyenv-virtualenv (creates an isolated version of Python such as 3.8) together, in tandem, over poetry and others. Personally, I think this combination gives the best amount of versatility. This even works well with difficult installs of python packages that need to be compiled into executable software. This includes stuff that has not been recently updated.
A good guide on how to do this is here (see table comparison against poetry at the bottom of the article): https://towardsdatascience.com/python-environment-101-1d68bd...
At least that's my understanding.
To gain traction and acceptance, the offering must be several times better.
Marketing also counts.
Hence the lingering demise of python2.7: python3 didn't offer sufficient sizzle until ~3.6 or so.
And more importantly, the concepts it brings will eventually become Python standards (like pyproject.toml or the lock file): https://snarky.ca/what-the-heck-is-pyproject-toml/
For one, I think competition, there is Kenneth Reitz' pipenv and then of course conda's environment.yml. I think pipenv lost the popularity contest but somehow lead to a situation where people wondered on which horse to bet.
Conda also takes a lot of market share esp. in the machine-learning deployments while also being not a 'perfect' tool.
Pretty sure we will see more poetry in the coming years.
Last but not least Poetry sometimes also feels like a weird tool. For example, when its dumping colourful stack traces on you in case of (invalid) inputs, etc.
If pip-compile would support dev and production requirements it would still be my way to go I think.
Can you elaborate on this? I use pip-compile development.in and pip-compile production.in and both use -r base.in for shared dependencies
pip-compile production.in
then use the pinned production requirements and a dev.in to produce the dev environment.
Key point being that the dev environment needs to have the very same pinned versions for all packages that are part of the prod environment.
I also found it's insistence on doing certain things reduced my flexibility. We thought it was kind of dead for a while where there were no releases for about a year.
That said, I've generally found a rise in opinionated tooling (see: black) and that frustrated me for a while. Then i realised i can just ignore it all and still be productive with my old stack if i knew what i was doing (which i do) while people still blurt their opinions elsewhere.
It certainly was dead in that time
It supports as many separate requirements files as you want, if that's what you mean.
I use it all the time because otherwise I’d have to write my own build system.
I am not sure if poetry’s approach to solving dependencies is really correct (Personally I like downloading the metadata for the projects, SMT solving, choosing a set of wheels and installing them together. It only works for wheels since you can’t extract the dependencies for eggs w/o running setup.py)
Pip is almost right if you install all deps at once but it can’t update wrong versions of old packages incompatible with new ones you add.
Practically poetry handles cases that pip doesn’t.
My beef(s) with poetry are:
It's the other guy causing the ruckus.
Is pip freeze not solving this scenario? Or is poetry solving a different scenario?
Not trying to flame war, just not sure I’m grokking.
Let's say it's June 19th and your project exists on GitHub and you have a requirements.txt file with only `Flask==2.0.1` in it.
Now let's fast forward to October 19th and you clone the project and run a docker-compose build. You'll get Flask 2.0.1 but you might get a drastically newer version of Werkzeug, Jinja2, itsdangerous and Click because all of those dependencies are defined by Flask with the >= operator.
Suddenly you have a Docker image that's much different than what it was in June and the only thing that changed is time. This becomes a problem because now it could potentially mean running different versions in dev, CI and production.
This has bitten me in the past a few times with Werkzeug and also the Vine library with Celery where it pulled in newer versions that had backwards incompatible changes that broke my app. Things worked in the past but didn't work months in the future even when none of my top level dependencies changed.
A lock file fixes this issue and it's still necessary with Docker.
I've solved it in a slightly different way using pip directly by keeping top level deps in requirements.txt, freezing out a requirements-lock.txt file and referencing it with pip3 install using the -c flag. There's example repos at https://github.com/nickjj/docker-flask-example and https://github.com/nickjj/docker-django-example that demonstrate how it's done. It's not a 100% fool proof solution like Poetry but it works well enough where I haven't had a single issue since I started using this pattern and it mostly solves the problem.
You mean not 100% fool proof?
It is, but with the strategy above a new lock file will get generated if the requirements.txt file is newer than the lock file, so if you change 1 dependency you might get newer unexpected dependencies. This is just the limitation of how pip works without building a whole new layer of dependency tracking in (which I guess is why Poetry and similar tools exists). Fortunately in practice I'm happy with the pip solution because it's a few line shell script and hasn't been a problem yet. The important part of having the lock file is there for reproduceable builds today and in the future.
my primary concern poetry's development stagnating due to natural causes while many projects rely on it. switching costs are high. moving from pipenv -> poetry took me days across all my projects.
they're looking for developers, but also help with managing issues on the tracker.
i also raised the issue of them being funded. I think one possible outcome is seeing if PSF's Fiscal Sponsoree program (https://www.python.org/psf/fiscal-sponsorees/) would be a fit. Waiting to see what their maintainers say.
For production code I’m more worried about minimizing surprises then elegance which means it’s really hard to replace something that works. Poetry only hit 1.0 in 12/2019, so maybe I’ll try it if the api remains stable for another few years. Contrast that to JS where we’re now on webpack 5 I think and there’s really no long term support available.
pip install -r requirements.dev, reference requirements.txt in it. It will install dev packages and the main ones.
In my startup, I started to make sure that we allocate a small monthly budget to distribute between our open source dependencies, Poetry being one of them. It's always shocking to find how little support the projects are getting - the author of Poetry currently has 11 sponsors (with majority of those being individuals).
[0] https://github.com/sponsors/sdispater
However, I also maintain a number of packages with c extensions or other compiled components, and poetry has no documented way of building packages with binary components, it can only create non-any wheels.
It cannot replace all setup.py use cases, but for pure python packages it can replace it completely.
One gripe with pyproject.toml is that I can’t do editable installs (i.e ‘pip install -e path/to/package/‘) with it. Highly annoying when trying to patch packages.
[tool.poetry.dependencies] my-package = { "path" = "path/to/package", develop = true }
This way you can patch my-package and poetry will always install the latest state of it.