Skip to main content

Static linter that checks a requirements file is fully version-pinned and hash-pinned, for CI and pre-commit.

Project description

pinlint

pinlint logo

PyPI CI License: MIT

A static linter that checks a requirements file is fully version-pinned and hash-pinned. Built for CI and pre-commit, so unpinned or unhashed dependencies fail review before anything is installed.

Install

pip install pinlint

30-second example

pinlint requirements.txt
requirements.txt:3: unpinned: requests is not pinned to an exact version (use ==)
requirements.txt:7: missing-hash: flask has no --hash
2 issue(s) found

Exit code is 1 when there are findings, 0 when the file is clean, so it drops straight into CI or a pre-commit hook.

As a library:

from pinlint import lint_file

findings = lint_file(
    "requirements.txt", require_hashes=True, allow_unpinned=False, follow_includes=True
)
for f in findings:
    print(f.file, f.line, f.code, f.message)

Why this exists

Reproducible, tamper-evident installs need every requirement pinned to an exact version and carrying a hash. The existing tools each do something adjacent: pip-compile --generate-hashes generates such a file, pip install --require-hashes enforces hashes at install time, and requirements-txt-fixer tidies formatting. None of them is a fast, static check you can run in review to assert that an arbitrary requirements file is fully pinned and hashed. pinlint is that check.

Comparison

pinlint pip-compile pip --require-hashes requirements-txt-fixer
Static check, no install yes n/a no (install time) yes
Flags unpinned versions yes generates at install no
Flags missing hashes yes generates at install no
CI / pre-commit gate yes partial no yes (formatting only)

Checks

  • unpinned: the requirement is not pinned with == or === to an exact version.
  • missing-hash: the requirement has no --hash (unless --no-hashes).
  • unpinnable: an editable, URL, or VCS install that cannot be version-pinned.
  • parse-error: the line could not be parsed as a requirement.

It understands comments, blank lines, backslash line continuations, --hash options, environment markers and extras, and -r and -c includes (followed with cycle protection). The only dependency is packaging, the canonical PEP 508 parser.

Options

  • --allow-unpinned do not require exact version pins.
  • --no-hashes do not require --hash entries.
  • --no-follow do not follow -r and -c includes.

Testing

pip install -e ".[dev]"
pytest

Tests use golden requirements files for each rule, including includes, cycles, line continuations, and the CLI exit codes.

Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md.

License

MIT. See LICENSE.

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

pinlint-0.1.0.tar.gz (841.5 kB view details)

Uploaded Source

Built Distribution

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

pinlint-0.1.0-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for pinlint-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f53723322de4932974f168085715d1edc83975401433fbbae50b1a482031c98d
MD5 f7b7e01f84426d7ca09f32048cef9394
BLAKE2b-256 c892d568e9189b709bb16cee3370f80beedac721fdb056bbefd1cc466a22ba82

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for pinlint-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f50ea4c9a6201290555849c414ed817aaeddf4d87b432b3d9bbca128a3e67944
MD5 1f5725adb48200e9c208ddccfcbd35d6
BLAKE2b-256 589d8b7dfcc86afbd8a215626cd21522fd38d7c81d41a9b2c459de1ad5049c77

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