There are som many requirements.txt files out there. Oh man. I do struggle every time somebody asks for the requirements file. There are so many options much better than that.
The old one
Poetry is probably the most known one, in particular when it comes to software development. It sets the standard on how we should move forward managing python projects.
After creating your project
poetry new mywork
You will have a basic structure to work with.
mywork
├── pyproject.toml
├── README.md
├── src
│ └── mywork
│ └── __init__.py
└── tests
└── __init__.py
The key here is the pyproject.toml
file that keeps the description of your project, required Python version, default and other groups of dependencies… everything organized.
[tool.poetry]
name = "mywork"
version = "0.1.0"
description = "My project"
authors = [
"Iraitz Montalbán <iraitzm@gmail.com>"
]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.10"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
You can keep on adding dependencies
poetry add ruff
...
[tool.poetry.dependencies]
python = "^3.10"
ruff = "^0.12.2"
...
Or create them as part of your development dependencies (not needed for the final code but you want to add them for the work in progress).
...
[tool.poetry.dependencies]
python = "^3.10"
[tool.poetry.group.dev.dependencies]
ruff = "^0.12.2"
...
The .lock
file that gets created allows to manage the version dependencies for your code to work.
My main option
I have been using PDM for a while now. It creates a basic structure and you don’t need to worry about the development dependencies. They will be installed by default while keeping everything in order on your TOML file.
pdm init
asks for the Python version to be used and guides the creation of the project using the CLI. It tells you if you would like to falg the project for creating a package (such as wheel) and which building backend to be used.
Which build backend to use?
0. pdm-backend
1. setuptools
2. flit-core
3. hatchling
It also detects the existence of a previos Poetry project or requirements.txt file and asks you if you would like to import it.
mywork
├── pyproject.toml
├── .pdm-python
├── README.md
├── src
│ └── mywork
│ └── __init__.py
└── tests
└── __init__.py
Same functionality as before, it helps you add dependencies, be it by default or to any other group you might want to create. Like for notebooks in your code:
pdm add -dG notebooks ipykernel
[project]
name = "mywork"
version = "0.1.0"
description = "Default template for PDM package"
authors = [
{name = "Iraitz Montalbán", email = "iraitzm@gmail.com"},
]
dependencies = []
requires-python = ">=3.11"
readme = "README.md"
license = {text = "MIT"}
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
[tool.pdm]
distribution = true
[dependency-groups]
notebooks = [
"ipykernel>=6.29.5",
]
Both, Poetry and PDM, allow you to create the a virtual environment that complies with the libraries that have been specified and also run anything on it by following the command
pdm run ...
It also includes other functionalities like:
- CLI script calling: https://pdm-project.org/latest/usage/scripts/#user-scripts
[project.scripts]
command = "main.cli:cli"
- Dynamic versioning: https://backend.pdm-project.org/metadata/
- Building and publishing: https://pdm-project.org/latest/usage/publish/
the new kid on the block
Astral has some cool projects going on. Ruff, is the go to linter and code formatter for many nowadays. It uses Rust under the hood which makes it really performant. They also had rye package manager for a while but its successor, uv, has become the defacto project management tool even though there are some thinks I don’t fully like.
The mean feature is… well, it is the Usain Bolt of the package installers. Soooo fast. Solves the dependency tree blazing fast and keeps the local environment up to date.
Two things that make me still prefer PDM over uv is the project initialization. PDM creates a basic folder structure that works for me
project
| - src/
| - test/
| - pyproject.toml
while uv creates a hello.py file that I have to delete all the time.
Probably the most annoying thing about uv is when you need to add all extras to you local development environment. You need to run
uv sync --all-extras --dev
it is a minor thing, but you need to remember it.
Funny this is that we have not forgot our old friend, so you might need to refresh your requirements.txt every once in a while. All previous tools know that so they all allow you to export the dependencies in that format.
uv export --no-hashes -o requirements.txt
More on this? There is a beautiful entry by Anna-Lena Popkes on her blog definitely worth checking or you can simply jump to the uv section at Python Developers Handbook.