pin-versions
A CLI tool and pre-commit hook that pins all unpinned dependencies in pyproject.toml to their currently installed versions.
Why pin versions?
Unpinned dependencies (e.g. requests instead of requests==2.31.0) mean your project silently picks up whatever version happens to be newest at install time. This causes real problems:
- Broken builds -- a new release of a dependency can introduce breaking changes or bugs that suddenly fail your CI or production deploys, even though your code hasn't changed.
- "Works on my machine" -- different team members install at different times and get different versions, leading to bugs that are impossible to reproduce.
- Non-reproducible deployments -- deploying the same commit twice can produce different behavior if a dependency was updated between deploys.
- Silent security risk -- without knowing exactly what you're running, auditing your dependency tree for vulnerabilities is guesswork.
Pinning gives you control: upgrades happen when you choose, not when a package author publishes.
How versions are resolved
pin-versions first checks what is currently installed in your virtual environment. For any unpinned package that isn't installed locally, the latest version is automatically fetched from PyPI.
A dependency will remain unpinned if:
- The package name doesn't match -- the name in
pyproject.tomldiffers from the distribution name (underscores vs hyphens, etc.) and can't be matched to an installed package. - PyPI lookup fails -- if the network request to PyPI errors out, the package is left as-is rather than guessing.
In all of these cases, pin-versions reports the unpinned packages so you can address them.
Pre-release versions
When fetching versions from PyPI, only stable (non-pre-release) versions are considered by default. Pre-release versions (alpha, beta, release candidates, dev builds) are filtered out. If you need to pin to a pre-release version, pass the --prereleases flag:
pin-versions --prereleases --fix
If a package has only pre-release versions on PyPI, pin-versions will fall back to the latest available version regardless of the --prereleases flag.
Installation
pip install pin-versions
Or with uv:
uv add pin-versions
Usage
Run in a project directory with a pyproject.toml and a virtual environment:
pin-versions
This pins dependencies in [project].dependencies, [project.optional-dependencies], and [dependency-groups].
By default, pin-versions runs in dry-run mode — it shows what would change without modifying the file. Use --fix to apply the pins.
Options
| Flag | Description |
|---|---|
--fix |
Apply changes to pyproject.toml (default is dry run) |
--operator, -o |
Version pin operator (default: ==). Supports >=, ~=, etc. |
--pyproject, -p |
Path to pyproject.toml (default: ./pyproject.toml) |
--venv |
Path to the virtual environment (default: .venv) |
--prereleases |
Include pre-release versions when fetching from PyPI |
Pre-commit hook
Add to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/kjaymiller/pin-versions
rev: v0.1.0
hooks:
- id: pin-versions
Contributing
- Fork the repo and clone it locally.
- Create a virtual environment and install the project in editable mode:
uv venv && uv pip install -e ".[dev]"
- Create a branch for your changes:
git checkout -b my-feature
- Make your changes and ensure they work by running:
pin-versions --dry-run - Open a pull request against
main.
Metadata
Release files for pin-versions 2026.3.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pin_versions-2026.3.6.tar.gz | 23.6 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pin_versions-2026.3.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.8 kB
Release files / pin_versions-2026.3.6.tar.gz
| Download URL | pin_versions-2026.3.6.tar.gz |
|---|---|
| Size | 23.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
27084daf47f8a078c860a0ae3e701ad62cc350028d878002b2882a8a2fed5a13
|
|
BLAKE2b-256 checksum How to use checksums |
91e42aa002d9c6353125df7fa80bf1874dd680e41c76802e22ffe165d0d66007
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 22, 2026.
Transparency logRelease files / pin_versions-2026.3.6-py3-none-any.whl
| Download URL | pin_versions-2026.3.6-py3-none-any.whl |
|---|---|
| Size | 7.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1548224ca29ed66aad8468fe787311646cdfa253c7942b1777faa83ae2912f9e
|
|
BLAKE2b-256 checksum How to use checksums |
f6d4db231ddf8f7b90178b65bb63bb608820395feb3d9505fbcddd20cbdedf85
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 22, 2026.
Transparency logSecurity for pin-versions 2026.3.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pin_versions-2026.3.6.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.