Snapshot linter errors and track only new issues — perfect for incremental linter adoption on large codebases
Project description
snaplint
Snapshot your linter errors and track only new issues in CI — perfect for adopting linters incrementally on large codebases without breaking existing workflows.
snaplint captures a baseline of current linter findings and lets you diff future runs against it. Only new errors cause CI failures, while existing issues are tracked separately.
Quick Start
Install via pip or uv:
pip install snaplint
# or
uv tool install snaplint
Basic Workflow
- Create a baseline snapshot of your current linter output:
flake8 src/ | snaplint take-snapshot
# Creates .snaplint/snapshot.flake8.json.gz
- Check for new issues in CI or locally:
flake8 src/ | snaplint diff
# Exit code 0: no new issues ✓
# Exit code 1: new issues found ✗
The diff command shows you:
- ✗ New errors (red) — will fail CI
- ✓ Removed errors (green) — improvements!
- File-level changes — error count and ordering changes per file
Auto-Detection
snaplint automatically detects your linter (ruff, flake8, mypy, pylint, or generic format) and creates appropriately named snapshots in .snaplint/:
# Each linter gets its own snapshot
ruff check . --output-format concise | snaplint take-snapshot # → .snaplint/snapshot.ruff.json.gz
flake8 . | snaplint take-snapshot # → .snaplint/snapshot.flake8.json.gz
mypy . | snaplint take-snapshot # → .snaplint/snapshot.mypy.json.gz
pylint src/ | snaplint take-snapshot # → .snaplint/snapshot.pylint.json.gz
Custom Snapshot Paths
Specify a custom path if needed:
flake8 . | snaplint take-snapshot snapshots/baseline.json
flake8 . | snaplint diff snapshots/baseline.json
Exit Codes
0— No new issues (safe to merge)1— New issues detected (CI should fail)2— Usage error (missing snapshot, no input, etc.)3— Unexpected internal error
How It Works
snaplint creates SHA1 fingerprints of each error by hashing the error type + source code line. This makes error tracking resilient to:
- Line number changes (refactoring, adding imports)
- File reorganization
- Whitespace changes in unrelated code
When comparing snapshots:
- Per-file tracking shows which files improved or regressed
- Order changes are detected when errors move within a file
- Count changes show if the total number of issues changed
- File-level errors (line 0) are fully supported
Snapshots are stored as gzip-compressed JSON (.json.gz) with version metadata for forward compatibility.
CI Integration
GitHub Actions
- name: Check for new linter issues
run: |
flake8 . | snaplint diff || {
echo "❌ New linting issues detected"
exit 1
}
Pre-commit Hook
Add to .pre-commit-config.yaml:
- repo: local
hooks:
- id: snaplint
name: Check linting snapshot
entry: bash -c 'flake8 . | snaplint diff'
language: system
pass_filenames: false
Supported Linters
snaplint automatically recognizes output from:
- ruff (use
--output-format concise) - flake8 and compatible tools (flake9, etc.)
- mypy
- pylint
- Generic format — any tool outputting
path:line:col: message
Unrecognized lines are skipped with a warning to stderr.
Working with Older Python Versions
If your project needs to support older Python versions (e.g., Python 3.8) but snaplint requires Python 3.10+, you can run the linter with your target Python version and snaplint with a newer interpreter:
# Run linter with Python 3.8
python3.8 -m flake8 src/ > /tmp/lint_output.txt
# Process with snaplint using Python 3.10+
python3.10 -m snaplint take-snapshot < /tmp/lint_output.txt
python3.10 -m snaplint diff < /tmp/lint_output.txt
Or use separate virtual environments:
# Create venv for linting with old Python
python3.8 -m venv .venv-lint
.venv-lint/bin/pip install flake8
# Create venv for snaplint with new Python
python3.10 -m venv .venv-snaplint
.venv-snaplint/bin/pip install snaplint
# Use them together
.venv-lint/bin/flake8 src/ | .venv-snaplint/bin/snaplint diff
This approach lets you maintain compatibility with older Python versions in your codebase while using modern tooling for CI/CD workflows.
Development
Setup
# Clone the repository
git clone https://github.com/GENWAY-AI/snaplint.git
cd snaplint
# Install with uv (recommended)
uv sync
# Or with pip
pip install -e ".[dev]"
Running Tests
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=snaplint --cov-report=html
# Run specific test file
uv run pytest tests/test_e2e.py -v
Local Installation
Install as a global command for testing:
uv tool install -e .
snaplint --version
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file snaplint-1.0.1.tar.gz.
File metadata
- Download URL: snaplint-1.0.1.tar.gz
- Upload date:
- Size: 60.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f224f92e54ca4223f0d82f7279d8c3d3761e3faf0caa9a852f4b6727068ac201
|
|
| MD5 |
64cf0b936eeec9dcd5cceea61b3ed086
|
|
| BLAKE2b-256 |
3f3b1de6c466a31f9a479e4866ac27082090d556a334a65c5312b0261009d77c
|
Provenance
The following attestation bundles were made for snaplint-1.0.1.tar.gz:
Publisher:
ci.yml on GENWAY-AI/snaplint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snaplint-1.0.1.tar.gz -
Subject digest:
f224f92e54ca4223f0d82f7279d8c3d3761e3faf0caa9a852f4b6727068ac201 - Sigstore transparency entry: 954502143
- Sigstore integration time:
-
Permalink:
GENWAY-AI/snaplint@bc5b9fc452088e0cce79702d57dc68af716b2c6e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/GENWAY-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@bc5b9fc452088e0cce79702d57dc68af716b2c6e -
Trigger Event:
push
-
Statement type:
File details
Details for the file snaplint-1.0.1-py3-none-any.whl.
File metadata
- Download URL: snaplint-1.0.1-py3-none-any.whl
- Upload date:
- Size: 14.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab734a9127620e28e8f8c6e45b8dcf5c1f3eefd02e6729fed8c2f317c24deb67
|
|
| MD5 |
75b8a5a64511c13ff736e5a1d0d0dcdb
|
|
| BLAKE2b-256 |
6b93fd69d26ebbfb14b29378cea492fca204f7d049d0cb4cfee3855fa4bef4ae
|
Provenance
The following attestation bundles were made for snaplint-1.0.1-py3-none-any.whl:
Publisher:
ci.yml on GENWAY-AI/snaplint
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
snaplint-1.0.1-py3-none-any.whl -
Subject digest:
ab734a9127620e28e8f8c6e45b8dcf5c1f3eefd02e6729fed8c2f317c24deb67 - Sigstore transparency entry: 954502159
- Sigstore integration time:
-
Permalink:
GENWAY-AI/snaplint@bc5b9fc452088e0cce79702d57dc68af716b2c6e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/GENWAY-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@bc5b9fc452088e0cce79702d57dc68af716b2c6e -
Trigger Event:
push
-
Statement type: