A simple CLI to help determine whether a package has copyleft dependencies
Project description
amigpl is a small CLI that reads the license metadata of every distribution in your active Python environment and tells you whether any of them are licensed under the GPL or another copyleft license you’ve asked it to flag.
It is purely a discovery tool. It takes no position on whether copyleft licenses are good or bad — it just helps package authors who, for whatever reason, need to know whether their dependency tree contains them.
Installation
$ uv tool install amigpl # or: pipx install amigpl
Quickstart
Run amigpl inside (or against) an environment with your project installed:
$ amigpl
No disallowed copyleft licenses found.
The bare invocation is shorthand for amigpl check. It scans every installed distribution and exits:
0 if nothing in the disallow set was found,
1 if any disallowed license was found,
2 if any package had no parseable license metadata (suppress with --ignore-unknown).
To see what’s installed and the license each package claims, use list:
$ amigpl list
attrs 25.4.0 ok MIT
click 8.2.1 ok BSD-3-Clause
requests 2.32.5 ok Apache-2.0
some-copyleft-pkg 1.0 disallowed GPL-3.0-only
Scanning a lockfile
Pre-install audits work against uv.lock or PEP 751’s pylock.toml:
$ amigpl lockfile check uv.lock
$ amigpl lockfile list pylock.toml
Lockfiles don’t themselves carry license metadata, so amigpl fetches each package’s record from PyPI on demand. Responses are cached on disk ($XDG_CACHE_HOME/amigpl or ~/.cache/amigpl) so subsequent runs are fast; pass --no-pypi-cache to opt out.
The lockfile check and lockfile list commands accept every option the env-scanning check and list do, including --disallow-license, --allow-license, --ignore, and --format.
What counts as “disallowed”
By default amigpl flags packages licensed under the GPL, AGPL, or EUPL families — the strong copyleft licenses which typically require a project depending on them to adopt the same license.
Other copyleft-flavored licenses are not flagged by default:
LGPL packages can usually be depended on from a non-LGPL project, since Python import is treated as dynamic linking.
MPL, EPL, and CDDL are file-level copyleft; only modifications to those files inherit the license.
If you want to flag any of them, opt in:
$ amigpl --disallow-license LGPL # add a whole family
$ amigpl --disallow-license LGPL-3.0-only # or a specific SPDX id
The argument accepts either a family alias (GPL, LGPL, AGPL, EUPL, MPL, EPL, CDDL) or any SPDX identifier. --allow-license does the inverse — removing a license from the disallow list — and is applied after --disallow-license, so you can subtract individual variants from a family you’ve opted into.
Configuration
A project’s policy lives in its pyproject.toml:
[tool.amigpl]
disallow-license = ["LGPL"]
allow-license = ["LGPL-2.1-or-later"]
ignore = ["some-package"]
ignore-unknown = true
ignore skips specific packages by name — useful when a transitive dependency has an unusual or unparseable license you’ve already vetted by hand and don’t want failing CI. Names are matched canonically, so hyphens, underscores, and case don’t matter.
CLI flags combine additively with config: --disallow-license, --allow-license, and --ignore each add to whatever the config already specified. --ignore-unknown (a boolean) overrides the config value when given.
CI integration
--format json and --format markdown exist for scripting and CI use. The markdown table is convenient for GITHUB_STEP_SUMMARY:
- name: License audit
run: amigpl --format markdown >> "$GITHUB_STEP_SUMMARY"
The exit code is meaningful to CI regardless of format: 0 means clean, 1 means a disallowed license was found, 2 means a package’s license could not be determined.
How licenses are detected
amigpl reads PEP 639 License-Expression metadata when available — this is the modern, unambiguous form — and falls back to legacy Trove Classifier entries and the free-text License field for older packages.
The text reported for each package is exactly what the package itself claims. A package whose only license metadata is the Trove classifier License :: OSI Approved :: BSD License is reported as BSD-licensed, verbatim; amigpl never invents precision the package didn’t supply (it won’t decide for you that it’s BSD-2-Clause rather than BSD-3-Clause).
That ambiguity only matters when your disallow set is more specific than the package’s claim. With the default disallow set — GPL, AGPL, EUPL — no BSD variant is disallowed regardless of which one was meant, so the package is reported ok. If you --disallow-license BSD-3-Clause specifically, a package that only claims “BSD License” via the Trove classifier becomes unknown: it might or might not be the variant you disallowed, and amigpl won’t guess.
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 amigpl-2026.5.2.tar.gz.
File metadata
- Download URL: amigpl-2026.5.2.tar.gz
- Upload date:
- Size: 34.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22ec2d88836e0f9d4d2df111e6083129d500c30b9e51004e7bb38094a38749fa
|
|
| MD5 |
aa75b36441d04a07972f6df7c745b0cc
|
|
| BLAKE2b-256 |
11050c389ad6c7eb2de2d8d6e2b2e62e5e7a424a4d8c525574fa6e01dd03d926
|
Provenance
The following attestation bundles were made for amigpl-2026.5.2.tar.gz:
Publisher:
ci.yml on Julian/AmIGPL
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
amigpl-2026.5.2.tar.gz -
Subject digest:
22ec2d88836e0f9d4d2df111e6083129d500c30b9e51004e7bb38094a38749fa - Sigstore transparency entry: 1563397649
- Sigstore integration time:
-
Permalink:
Julian/AmIGPL@fe1e7488ff478162a0915e264862bd49b1d6b972 -
Branch / Tag:
refs/tags/v2026.5.2 - Owner: https://github.com/Julian
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@fe1e7488ff478162a0915e264862bd49b1d6b972 -
Trigger Event:
push
-
Statement type:
File details
Details for the file amigpl-2026.5.2-py3-none-any.whl.
File metadata
- Download URL: amigpl-2026.5.2-py3-none-any.whl
- Upload date:
- Size: 32.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6100ffb7de19484065d9f1b16b20f76b8bf4581416b25ee8aa244a0d4ee6e7a
|
|
| MD5 |
30a3643a4acce7378590389acfa43314
|
|
| BLAKE2b-256 |
7e17716240f4d4de52547fdb07b1c6e5f9ba8860f4ed3d327812fbffdb6c3c81
|
Provenance
The following attestation bundles were made for amigpl-2026.5.2-py3-none-any.whl:
Publisher:
ci.yml on Julian/AmIGPL
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
amigpl-2026.5.2-py3-none-any.whl -
Subject digest:
e6100ffb7de19484065d9f1b16b20f76b8bf4581416b25ee8aa244a0d4ee6e7a - Sigstore transparency entry: 1563398792
- Sigstore integration time:
-
Permalink:
Julian/AmIGPL@fe1e7488ff478162a0915e264862bd49b1d6b972 -
Branch / Tag:
refs/tags/v2026.5.2 - Owner: https://github.com/Julian
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@fe1e7488ff478162a0915e264862bd49b1d6b972 -
Trigger Event:
push
-
Statement type: