Skip to content

Add packaging guide entry on dependency locking#669

Open
alexarmstrongvi wants to merge 11 commits into
pyOpenSci:mainfrom
alexarmstrongvi:docs/491-add-packaging-guide-entry-on-dependency-locking
Open

Add packaging guide entry on dependency locking#669
alexarmstrongvi wants to merge 11 commits into
pyOpenSci:mainfrom
alexarmstrongvi:docs/491-add-packaging-guide-entry-on-dependency-locking

Conversation

@alexarmstrongvi
Copy link
Copy Markdown

@alexarmstrongvi alexarmstrongvi commented May 23, 2026

Addresses Issue #491. First PR to the project. Open to feedback if I am missing general style and teaching philosophy or if it's preferred that this be shorter/longer.

@alexarmstrongvi alexarmstrongvi changed the title Docs/491 add packaging guide entry on dependency locking Add packaging guide entry on dependency locking May 23, 2026
Comment on lines +518 to +519
* `pyproject.toml`: provides the range of requirements for others to
use your package in their project.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe "specifies all the possible versions that can be used with the package"

so it can be contrasted more easily with "the exact set of versions used during development"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed: 51df0f9


### How to work with lock files?

Lock files are not maintained manually. Package managers and IDEs provide tools
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe not "written" manually - their maintenance can be automated but you do have to do it

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. "written" makes more sense. Changed 185b382

Comment on lines +536 to +537
to create, update, and reformat lock files as needed. Below are common package
manager CLI workflows for lock files:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe before the examples, we give a sense of the kinds of operations that need to be done in prose:

  • create the lockfile
  • update the lockfile
  • update a single package in the lockfile
  • creating different forms of the lockfile for different python versions, OSes, etc.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed: cd2c12f
Doesn't seem like PDM supports updating a single package in the lockfile like uv and poetry apart from some workaround using the --constraint arg so I left that out of the examples. I figure people will go to the linked docs if they really are going to use lock files and want to see tool specific workflows.


### Should I use a lock file?

Most package managers will maintain a lock file automatically for you (e.g. uv,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Most package managers will maintain a lock file automatically for you (e.g. uv,
Most package managers will generate a lock file automatically for you (e.g. uv,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed: 7ad8080

Comment on lines +602 to +610
:::{admonition} Rule of Thumb
:class: tip
If your project is an application others use directly, include a lock file as
the recommended environment.

If your project is a library to be used in other projects and it is mature
enough to have CI, include a lock file for CI and contributors.

:::
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two options that are both "use a lockfile" could probably just be simplified to:

"yes, you should version the lockfile

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intended carve out here is a sole maintainer library with limited users and potentially no testing set up yet (e.g. grad student trying to share their library within their university).

I was also trying to address the points raised by @ucodery in the original issue: "it should be noted that locking is not a always-yes". It may be worth them elaborating on the cases they had in mind. The above is the main one I can think of.

Comment on lines +612 to +620
There is some maintenance cost from lock files. Maintainers should aim to update
the lock file neither too rarely nor too often.
* Too rarely means you risk missing updates with bugfixes, security patches,
performance improvements, etc.
* Too often means you may introduce bugs or even security vulnerablilites before
maintainers of your dependencies catch them. Package managers are starting to
support [dependency cooldowns](
https://blog.pypi.org/posts/2026-04-02-incident-report-litellm-telnyx-supply-chain-attack/#dependency-cooldowns
) to mitigate this.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with dep cooldowns, i think only the 'too rare' case is a problem. I would probably frame this as "one risk when developing using lockfiles is that your lockfile will fall too far behind the most recent versions of your dependencies. When people install your package, they typically will not be using your lockfile, and will install the latest versions of the packages supported by their environment. If your dependencies update and break something you rely on, you might not notice it until someone reports it to you."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be more specific, i basically think we should just say "you should use dependency cooldowns" as an unambiguous recommendation, but then on the other end give a bit of discussion to build intuition about why not updating frequently would be bad, which is the more common problem to have.

Copy link
Copy Markdown
Author

@alexarmstrongvi alexarmstrongvi May 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree "too rare" is the more likely situation. As far as falling behind on package updates, is there anything beyond bugfixes, security patches, and performance improvements that should be mentioned as reasons to update?

Regarding people installing your package and ignoring lock files (presumably for the case of a library), I intended the tip at the end about CI testing different environments to address this.

A discussion on dependency cooldowns seems best added into sections on building packages and CI as it's something that should be added to tool configs instead of invoked when generating a lock file

Comment on lines +622 to +625
When you decide to update a lock file, consider what changed before committing
it to the project. Good changes to focus on are
1) major version updates (e.g. `pandas 2.X.X` -> `pandas 3.X.X`)
2) new transitive dependencies (i.e. not part of your `pyproject.toml`)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't read the lockfile when it updates, and so we might not want to give the impression to newbies that it's normal to read lockfile changes since it can be daunting. My pattern is basically "update the lockfile, run the tests." maybe i'll keep a loose eye for transitive dependencies if e.g. something suddenly starts pulling in a huge dep like scipy or something. maybe the thing to communicate is like "what to do if you update and a new version breaks your stuff" and how to handle adding e.g. temporary version caps

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified its not necessary and that testing is more important: a1664bc

Comment on lines +627 to +637
:::{tip}
A lock file captures one tested environment, not the full compatibility range
declared in `pyproject.toml`. Projects that use lock files should still have CI
test other environments such as

1) the latest packages consistent with your `pyproject.toml`, subject to
dependency cooldowns. This lets you know if a dependency update breaks your
package.
2) older supported versions of Python to let you know if a recent change to your
package no longer works with an older Python release.
:::
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have done this, where i have one branch of the tests run with a pip install and the rest run with the lockfile as a sentinel, we might want to add a bit more scaffolding in the form of an example CI action for this. Usually I just to that on linux with latest python.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems good to reference the testing section here and then add an example there. To avoid the combinatoric explosion of maintaining guides on local vs CI testing, for various tools (e.g. nox, hatch, GitHub Actions), with and without lock files, what are your thoughts on making a high level point that testing can setup environments from a lock files instead of resolving at runtime, showing one example replacing run: python -m pip install ... with run: uv sync --frozen, and the linking to documentation for various tools?

for up-to-date formatting info on `pylock.toml`
:::

### How to work with lock files?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think right above this we need a section like "why are lockfiles good" or "why do they exist" to orient people to what they are doing and why before getting into how to work with them.

something like "lockfiles create a predictable development environment that helps reduce problems where code runs on one person's machine but crashes on another. together with CI result logs, they are a versioned record of the exact set of code that passed or failed the tests. for applications (as opposed to libraries) that are intended to be used as-is rather than depended on by other packages, they allow someone to install and run it and be confident that it will work, without accidentally installing a more recent version of some dependency that is incompatible"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added more motivation for lock files in line with your points in the intro paragraph: 88d6b78

Comment on lines +658 to +659
* Packages can get updated without a version update for both legitimate and
malicious reasons. Lock files specify exact hashes to catch this.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this need a bit more explanation, folks might not know what a hash is. maybe show a comparison of the information in requirements.txt and a lockfile first, and then say "those hashes are a unique signature for the code. if you only specified the version, then anything could tell you that it's that package at that version, but if you have a locked hash, you can compute the hash of the thing you're about to install and be positive that it's exactly the thing that is specified." (modulo hash collisions)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified: 71190c2

Comment on lines +656 to +657
* The versions satisfying `pyproject.toml` may differ between your MacOS and the
Linux server your CI runs on. Lock files contain platform-specific resolutions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

platform and python version deps are the main things that my lockfiles vary by: maybe generalized like "lockfiles can be customized to include all the different versions that are applicable across different operating systems, python versions, and other platform markers, while that information can only be stored in requirements.txt files through file naming conventions."

idk that text isn't very clear either, but something like that

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified: 88f7445

@sneakers-the-rat
Copy link
Copy Markdown
Contributor

nice, thank you for drafting this! we have needed this for sure. i think the main thing that's TODO here is providing a recommended workflow, getting a lockfile updating setup can have some weird pitfalls that aren't obvious. i am pretty bad about doing this across all my packages because usually i am very stingy with deps in the first place, and otherwise will be touching them frequently enough that i relock, but the thing that i end up doing is doing a weekly automated PR that just updates the lockfiles and runs the tests. check for any added dependencies, if no new deps, merge it if tests pass. if there are new deps, list them in the PR.

I am not sure the current state of the tooling but the final straw for me that pushed me to switch away from using poetry was when i requested and drafted a command that would just print the deps that would change from a lock update, but they didn't want to do that for some reason, so i just ended up writing some heinous bash scripts for it, but if it's more reasonable now we should include an example CI workflow for that. Not saying mine is correct or the best, so that can look like anything, but i think that's sort of the major thing that is a pain in the ass about lockfiles and so would be one of the main things we want to provide in the guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants