Don't use Poetry, if you don't have to.
In my brain the title translates to »basically never use Python Poetry«. But why?
Python Poetry is a neat tool. It fixes the majority of dependency issues, adds some bells and whistles at the side and seems to be “hip”. But my gut says: just don’t. Huh? »Why?« I might ask back, but the thing with gut feelings is that you cannot really get this question answered. I need to find the answer in a different way.
Let the search begin.
A good starting point is »Why not tell people to “simply” use pyenv, poetry or anaconda«. It outlines some major reasons for avoiding it, for me the two main reasons are:
- using Poetry is not simple: it is another layer of abstraction on top of existing tooling. It comes with its own quirks and issues. You need to read the docs before you can use it as first time user.
- not more, but less dependencies: Poetry is itself already dependency-heavy. So you now have your project’s dependencies plus all dependencies of Poetry. That needs to be installed, maintained and updated. The episode »It dependencies« of the Podcast changelog reminded me of this.
- it is a maintenance burden: developers need to update the lock file from time to time, which is just extra work nobody is waiting for!
- it clutters your git commits with lock file changes
- onboarding new devs is more work
- Setting up CI/CD and Docker containers is more work
Additionally, it sometimes feels as if Poetry is trying to fix problems I did not have
in the first place. Honestly, I cannot remember where the requirements specs in
requirements.txt
or pyproject.toml
were not enough. Very strange to say this as the
best practice is:
In building your Python application and its dependencies for production, you want to make sure that your builds are predictable and deterministic. – pip-tools README
So I question myself: do I? I’m not so sure. Probably not. To make it bold:
It is not essential to have .lock
file for your application or library in
production. Most Java applications don’t use it and a fairly large percentage of the
world’s production code is based on Java & Maven.
The alternative: my standard setup
I conclude: it is sufficient to keep a normal requirements.txt
(or pyproject.toml
)
with versions pinned to the minor version or whatever suits you. The default
ingredients are
Python packages
If possible I try to group my code (even if it is only for internal use) into Python
packages. I use a fairly standard combination of pyproject.toml
and .flake8
config. Of course you can also use
ruff as drop-in replacement for Flake8, isort, and
Black. I’ve noticed that in small projects it doesn’t matter that much.
I have a slight aversion to pre-commit, so I skip it. The
aversion stems from the belief that developers should be able to choose their own
workflow. All sorts of pre-commits, hooks, etc. work against that. My workflow falls
into the category: first make a mess, then make it clean. Having my messy commits
checked against all types of syntax and formatting rules slows me down. Instead I
usually »refactor« my commits before I create a PR. So I don’t use hooks or pre-commits.
I put everything into a Makefile
:
(for a more sophisticated Python Makefile
check out
»Managing your Python project with a Makefile«
Setup for a (web)app
Even simpler here, I use requirements.txt
with .flake8
and pyproject.toml
(for
Black settings) orchestrated by a Makefile
in a virtual environment.
Done.