Advanced

Dependency ranges in a lock file

A lock file is the resolved answer to a range. Reading it tells you exactly which versions you tested against, and diffing two lock files tells you exactly which dependencies moved. That diff is the release note for dependencies.

What you will see

Any hits are unpinned fetches that make the build non-reproducible. Pin each before shipping.

About 1 min of reading

Try It

Prove which versions you actually tested

1

Generate a lock

pip freeze > requirements.lock

Before you run it, say out loud what it will print. Then open the answer.

What it prints
A file of exact pinned versions, one per dependency in the environment.
2

Commit it

git add requirements.lock && git commit -m 'lock for v1.4.2'

Before you run it, say out loud what it will print. Then open the answer.

What it prints
The lock is now part of the release's record.
3

Diff two releases

git diff --unified=0 HEAD~1 HEAD -- requirements.lock

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Only the lines that moved. Each one is a dependency change that belongs in the changelog.
4

Find an unpinned fetch

grep -nE '^(FROM [^:]+$|RUN pip install (?!.*==))' Dockerfile

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Any hits are unpinned fetches that make the build non-reproducible. Pin each before shipping.
pip freeze records what is installed, not what you asked for. If something was installed by hand, it appears here and will not appear on a fresh build. Regenerate from the recipe instead.

Data Flow

Manifest to lock to diff
1 Declare ranges in the manifest
↓
2 Resolve against the registry
↓
3 Write the resolved points to the lock
↓
4 Diff locks between releases
Why this works
Commit the lock

For an app, commit the lock so a rebuild on another machine resolves the same versions. For a library, you may not ship a lock; then the range and the CI check are the substitute.

When a range is too wide

If the upper bound is missing, a future major can be resolved silently. Add the upper bound at the major you last tested against, so the next major fails at resolve time.

Examples

Range in, point out

The manifest says >=1.4,<2. The lock says ==1.4.7. Both are committed: the range is the intent, the lock is the fact. Only the second one is reproducible.

Diff the locks

git diff --stat on the lock file between two releases lists the dependencies that moved. Each moved line is a candidate for a changelog entry, and each one needs a test.

Regenerate, do not hand-edit

A hand-edited lock is a lie: the resolver will disagree on the next build. Delete the lock and regenerate it, then commit the result.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Migrating data alongside the box
Previous Lesson
Migrating data alongside the box
Next Lesson
Yanking a release that must not be used
Yanking a release that must not be used →