Requirements¶
TLDR
When you
importa package for the first time in your application code, add its name torequirements.inin alphabetical order.When you
importa package for the first time in your test code, that is never imported in your application code, add its name torequirements_dev.inin alphabetical order.After updating a
.infile, update the.txtfiles with:uv pip compile requirements.in -o requirements.txt uv pip compile requirements_dev.in -o requirements_dev.txt
To update your local environment, run:
uv pip sync requirements_dev.txt
Now that you have a directory layout, you can declare the project’s requirements.
The requirements of applications (not packages) are managed by four files:
requirements.innames all direct requirements needed in the production environment, i.e. all packagesimport’ed by the application.If the application is incompatible with older or newer versions of a requirement, use the least specific version specifier possible, for example:
Newer versions:
foo>=1.2, notfoo>=1.2.3Older versions:
foo<2Versions range:
foo>=1.2,<2
requirements_dev.innames all direct requirements needed exclusively in the development environment, and not in the production environment, e.g.pytest.This file should include the direct requirements needed in the production environment, by having a first line of
-r requirements.txt.
requirements.txtnames all direct and indirect requirements needed in the production environment, all locked to specific versions by uv.requirements_dev.txtnames all direct and indirect requirements needed in the development environment, all locked to specific versions byuv.
This ensures that:
All environments use the same versions of production requirements, to ensure consistent and replicable deployments and to avoid errors or surprises during or after deployment due to differences between versions (e.g. a new version of Django requires upgrading application code).
Different developers and continuous integration use the same versions of development requirements, to avoid test failures due to differences between versions (e.g. a new version of pytest requires upgrading test code, or a new version of ruff has stricter linting rules).
Get started¶
Virtual environment¶
Create a .python-version file (for example, containing 3.11), then run:
uv venv
Requirements files¶
A common starter requirements.in for Django is:
dj-database-url
django<6
gunicorn[setproctitle]
psycopg2
sentry-sdk
A common starter requirements_dev.in is:
-r requirements.txt
coverage
If not using Django, add:
pytest
Dependency cooldown¶
To protect against supply chain attacks, configure uv to only resolve package versions uploaded more than one week ago. In pyproject.toml:
[tool.uv.pip]
exclude-newer = "1 week"
Add a requirement¶
Add the requirement in alphabetical order to the appropriate .in file. Then, run:
uv pip compile requirements.in -o requirements.txt
uv pip compile requirements_dev.in -o requirements_dev.txt
See also
psycopg2¶
psycopg2 is recommended for production. However, installing psycopg2 for development can be difficult on operating systems like macOS. In that case, you can:
Put
psycopg2inrequirements.inPut
psycopg2-binaryinrequirements_dev.inRun:
pip install psycopg2-binary
Note
You must keep the locked versions of psycopg2 and psycopg2-binary in sync.
Install requirements¶
uv pip sync requirements_dev.txt
Tip
If a package with C extensions fails to install, try installing from source, for example:
uv pip install --reinstall --no-cache --no-binary :all: lxml
Upgrade requirements¶
Requirements should be periodically updated, both for security updates and to better distribute the maintenance burden of upgrading versions over time.
Upgrade one requirement in requirements.in, for example:
uv pip compile -P requests requirements.in -o requirements.txt
uv pip compile requirements_dev.in -o requirements_dev.txt
Upgrade one requirement in requirements_dev.in, for example:
uv pip compile -P pytest requirements_dev.in -o requirements_dev.txt
Upgrade all requirements (rare):
uv pip compile -U requirements.in -o requirements.txt
uv pip compile -U requirements_dev.in -o requirements_dev.txt
Linting¶
Continuous integration runs test_requirements.py, which checks whether any requirements are missing or unused.
If a requirement is reported as unused but is required:
Make sure that a related package sets extras correctly. For example, moto has optional dependencies for each AWS service. You must do, for example:
moto[s3]
If the package is optional – for example, it is imported in a
tryandexcept ImportErrorblock – use theSTANDARD_MAINTENANCE_SCRIPTS_IGNOREenvironment variable.If the package is used exclusively outside of application code – for example, as a command in the production environment or in a GitHub workflow, or in an entry point or as a Sphinx extension – use the
STANDARD_MAINTENANCE_SCRIPTS_IGNOREenvironment variable.