Skip to main content

Static CI linter for PEP 751 pylock.toml: hash completeness, sdist-only builds, platform portability, and drift vs pyproject.toml.

Project description

pylock-lint

A pylock.toml that installs cleanly on your laptop can still be broken: wheels with no hashes, packages that only ship an sdist (so CI silently builds from source), or a lock generated on Linux that has no wheels for the Windows runner it'll actually run on. Nothing in the standard toolchain flags any of that before it reaches a teammate's machine.

pylock-lint is a static CI check for PEP 751 lockfiles. It reads a committed pylock.toml, reports the reproducibility and portability gaps, and exits non-zero so a bad lock fails the build instead of the deploy.

$ pylock-lint
pylock.toml [numpy]: ERROR PL001 wheel numpy-2.1.0-...-manylinux_2_17_x86_64.whl has no hashes
pylock.toml [somepkg]: WARNING PL002 sdist-only (no wheels): install must build from source...
pylock.toml: WARNING PL020 single-environment lock (no 'environments' declared) but it pins
  platform-specific wheels (numpy); installs on another OS/Python will fail or fall back to source

2 error(s), 1 warning(s) across 1 file(s)
$ echo $?
1

Why this exists

pip 26.1 (April 2026) shipped pip install -r pylock.toml, and pip's own generated locks are single-platform and single-Python — it "avoids some advanced features (like environment markers) for now." uv and PDM export cross-platform locks; Poetry has none. So teams are starting to commit pylock.toml to their repos, and the file's failure modes are exactly the kind that don't show up until someone on a different OS runs pip install. packaging parses the schema and pip-audit scans for CVEs; neither answers "is this lock actually reproducible and portable?"

Install

pip install pylock-lint

Or run it without installing:

pipx run pylock-lint

Usage

pylock-lint                          # lint ./pylock.toml (and pylock.*.toml)
pylock-lint path/to/pylock.toml      # lint a specific file or glob
pylock-lint --pyproject pyproject.toml   # also check the lock is in sync with declared deps
pylock-lint --require-cross-platform     # fail if wheels cover only one platform
pylock-lint --strict                 # treat warnings as failures too
pylock-lint --format json            # machine-readable output
pylock-lint --ignore PL002,PL020     # skip specific rules

Default exit code is 1 when any error-level finding is present, 0 otherwise. --strict also fails on warnings.

Checks

Code Severity What it catches
PL001 error An sdist, wheel, or archive with no hashes — the lock can't verify integrity.
PL002 warning A package with an sdist but no wheels — install builds from source, which isn't byte-reproducible and needs a toolchain.
PL003 error A package with no installable source at all.
PL010 error A package entry missing its required name.
PL011 error Mutually-exclusive source types on one package (PEP 751 allows exactly one).
PL012 error Missing or unsupported lock-version.
PL013 warning Missing created-by (provenance).
PL014 warning Lockfile declares no packages.
PL015 error A package with sdist/wheels missing its required version.
PL020 warning Single-environment lock that pins platform-specific wheels — non-portable.
PL021 error With --require-cross-platform: wheels cover only one platform.
PL030 error With --pyproject: a dependency declared in pyproject.toml is absent from the lock.
PL031 warning With --pyproject: requires-python disagrees between the two files.

GitHub Action

- uses: fernforge/pylock-lint@v1
  with:
    paths: pylock.toml
    pyproject: pyproject.toml
    strict: "false"

The action installs the package and runs it against your committed lock on every push.

What it does not do

No network calls. It won't fetch the referenced wheels or re-resolve your dependency graph — it reads what's committed and checks the file against the spec and your pyproject.toml. That keeps it fast and safe to run on untrusted branches, but it means PL030 checks presence, not that every locked version satisfies every declared constraint.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pylock_lint-0.1.0.tar.gz (35.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pylock_lint-0.1.0-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

File details

Details for the file pylock_lint-0.1.0.tar.gz.

File metadata

  • Download URL: pylock_lint-0.1.0.tar.gz
  • Upload date:
  • Size: 35.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for pylock_lint-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bf80418f9986493fbadc758058ef023fadbcac85fe4dc7eff075931c940cb7b7
MD5 cd4999690b2ab2062c08c733a9f9bcda
BLAKE2b-256 b99a2f97dfdffd26013c2f021f9c167943243bd9eb49a18e0dea9357fa940796

See more details on using hashes here.

File details

Details for the file pylock_lint-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pylock_lint-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for pylock_lint-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 17681d01bc4e345c37fe33a8db11efbd95c40034f8c1a7e7232052d8d995dd4b
MD5 1fbe57e8b28e8e219fc2c63f23cb1633
BLAKE2b-256 f14e22b85e7461e1fd354421fd6ca097f457a22fa903f97e7d98437d7845dc48

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page