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.
  • --allow PACKAGE ignore findings for a package name (repeatable).
  • --format text|json|sarif choose the output format. json suits CI and editors; sarif emits SARIF 2.1.0 for GitHub code scanning and other analysis tools.

Pre-commit

pinlint ships a hook, so you can add it to .pre-commit-config.yaml:

repos:
  - repo: https://github.com/amaar-mc/pinlint
    rev: v0.2.0
    hooks:
      - id: pinlint

The hook runs on files matching requirements.*\.txt.

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.3.0.tar.gz (844.6 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.3.0-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for pinlint-0.3.0.tar.gz
Algorithm Hash digest
SHA256 6d29de5bdcc4512588ffd9cdce36a0c1fade58221f9cdc4b53f575767d62b631
MD5 c00e375a78ab7a67adb920c778b35ca0
BLAKE2b-256 f707135817f58f08928e2ef975be20f1fee915431b391605e762e97deda9407f

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pinlint-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 10.1 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.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7e407ff382d72848dd01c3c8a921ad0f4a6d5b7e6764c94a79c6b154d1ee2c22
MD5 97f93b870949b7efdfb0384a8f1c6e46
BLAKE2b-256 a3d75969686a9d890be18d43cc0b0532fcf80349554e9756ec798f913552e346

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