licsniff
Audit your dependencies' licenses, offline. Point it at a virtualenv and get
a clean table of every installed package, its license, and a risk tier —
permissive, weak-copyleft, strong-copyleft, proprietary, or unknown —
so a stray GPL transitive dep can't sneak into your closed-source product.
No account. No network. No config. Zero dependencies (pure standard library).
pipx run licsniff
PACKAGE VERSION LICENSE RISK
some-gpl-lib 2.1.0 GPL-3.0 strong-copyleft
mystery-pkg 0.0.3 (none) unknown
copyleft-utils 1.4.0 LGPL-2.1 weak-copyleft
requests 2.32.3 Apache-2.0 permissive
packaging 24.1 Apache-2.0 OR BSD-2-Clause permissive
Riskiest first, so the line you need to worry about is at the top.
Why another license tool?
The hosted options — Snyk, FOSSA, Black Duck — all want a signup, a token, and a
network round-trip before they'll tell you something your site-packages
already knows. The Node ecosystem's go-to,
license-checker, has been
unmaintained for years and doesn't read Python anyway.
licsniff is the gap: it reads the *.dist-info/METADATA files already on your
disk, classifies each license locally, and exits. Nothing leaves the machine.
It also does the part those tools are vague about — tiering by actual risk.
Knowing a dep is "GPL-3.0" only helps if you know GPL is strong copyleft and
MPL is weak. licsniff bakes that in, understands SPDX expressions
((MIT OR Apache-2.0) → least-restrictive, GPL-3.0 AND MIT →
most-restrictive), and normalizes the messy variants (GPLv3, GPL-3.0+,
GPL-3.0-only, Apache License 2.0).
Install
pipx run licsniff # no install, run on demand
pip install licsniff # or install the `licsniff` command
There's an identical Node build too: npx licsniff / npm i -g licsniff
(see licsniff) — it audits a Node project's
node_modules instead of site-packages. Both ports share the exact same
classifier, tested against the same vectors, so they tier licenses byte-for-byte
the same.
Usage
licsniff [options] # scans the active venv's site-packages
licsniff --path <dir> [options] # scan a specific site-packages folder
By default licsniff resolves your $VIRTUAL_ENV site-packages, falling back to
./.venv/lib/python*/site-packages. Pass --path to point it anywhere.
| Option | Description |
|---|---|
--path <dir> |
site-packages dir to scan. |
--summary |
Print counts per risk tier instead of the full table. |
--json |
Machine-readable JSON ({path, total, counts, packages[]}). |
--fail-on <tier> |
Exit 1 if any package is at or above <tier>. CI gate. |
--no-color |
Disable ANSI color. |
-h, --help |
Show help. |
-v, --version |
Print version. |
Risk tiers
| Tier | Examples | What it means |
|---|---|---|
permissive |
MIT, ISC, BSD-2/3-Clause, Apache-2.0, 0BSD, Unlicense, CC0 | Use freely, just keep the notice. |
weak-copyleft |
LGPL-*, MPL-2.0, EPL-*, CDDL-* | File-level / linking obligations. |
strong-copyleft |
GPL-*, AGPL-* | Can force you to open-source your code. |
proprietary |
UNLICENSED, "SEE LICENSE IN …" | Not open source — read the terms. |
unknown |
missing / unrecognized | No idea — investigate manually. |
Examples
# counts at a glance
licsniff --summary
# CI gate: fail the build if anything copyleft-or-worse slipped in
licsniff --fail-on strong-copyleft
# pipe to jq
licsniff --json | jq '.packages[] | select(.tier=="unknown") | .name'
# audit a specific environment
licsniff --path /path/to/venv/lib/python3.11/site-packages
Design notes
- One pure function at the core.
classify_license(id_or_name)→{tier, spdx}has no I/O, no clock, no globals. The CLI is a thinsite-packagesreader wrapped around it. That's what makes the Node and Python ports verifiably identical — they share one test table. - It reads the real METADATA fields. The modern PEP 639
License-Expression:(SPDX), the legacyLicense:field, and theLicense :: …trove classifiers — preferring the classifier when theLicense:field is empty,UNKNOWN, or a pasted-in wall of license text. - SPDX expressions are evaluated, not guessed.
ORpicks the least restrictive option (you get to choose),ANDpicks the most restrictive (you must satisfy all).WITHexception clauses fall back to the base license. - Fully offline, read-only. It never writes anything and never opens a socket. Safe to run anywhere, including air-gapped CI.
License
MIT
Metadata
Release files for licsniff 0.1.0
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 | Actions |
|---|---|---|---|---|
| licsniff-0.1.0.tar.gz | 16.4 kB | Without provenance | Details for licsniff-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| licsniff-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for licsniff-0.1.0-py3-none-any.whl |
Total release size: 30.4 kB
Release files / licsniff-0.1.0.tar.gz
| Download URL | licsniff-0.1.0.tar.gz |
|---|---|
| Size | 16.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
653a12c378518099ade6a3146a1f847130fddc94b6aa9f299b541b6a7a37a17f
|
|
BLAKE2b-256 checksum How to use checksums |
6b2c400034acba1c216f76c10d7953ecce08a49009c9c86a190dfafdf8225c80
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|
Release files / licsniff-0.1.0-py3-none-any.whl
| Download URL | licsniff-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cbf546b375c663ff3585b5d3fb097d435f9e9d8d8bdf8566807c860e93c4a44c
|
|
BLAKE2b-256 checksum How to use checksums |
b2c8d0d68190ca30a0db390abe0f765069cafe7a31701474e9295135b30b4189
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.7
|
Security for licsniff 0.1.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.