Metadata-Version: 2.4
Name: amigpl
Version: 2026.5.2
Summary: A simple CLI to help determine whether a package has copyleft dependencies
Project-URL: Homepage, https://github.com/Julian/AmIGPL
Project-URL: Issues, https://github.com/Julian/AmIGPL/issues/
Project-URL: Funding, https://github.com/sponsors/Julian
Project-URL: Source, https://github.com/Julian/AmIGPL
Author-email: Julian Berman <Julian+amigpl@GrayVines.com>
License-Expression: MIT
License-File: COPYING
Keywords: compliance,copyleft,dependencies,gpl,license,licensing,packaging,spdx
Classifier: Development Status :: 3 - Alpha
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Python: >=3.11
Requires-Dist: click
Requires-Dist: packaging>=24.2
Description-Content-Type: text/x-rst

==========
``AmIGPL``
==========

|PyPI| |Pythons| |CI|

.. |PyPI| image:: https://img.shields.io/pypi/v/AmIGPL.svg
  :alt: PyPI version
  :target: https://pypi.org/project/AmIGPL/

.. |Pythons| image:: https://img.shields.io/pypi/pyversions/AmIGPL.svg
  :alt: Supported Python versions
  :target: https://pypi.org/project/AmIGPL/

.. |CI| image:: https://github.com/Julian/AmIGPL/workflows/CI/badge.svg
  :alt: Build status
  :target: https://github.com/Julian/AmIGPL/actions?query=workflow%3ACI


``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
------------

.. code-block:: sh

    $ uv tool install amigpl     # or: pipx install amigpl


Quickstart
----------

Run ``amigpl`` inside (or against) an environment with your project installed:

.. code-block:: sh

    $ 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``:

.. code-block:: sh

    $ 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 <https://peps.python.org/pep-0751/>`_'s ``pylock.toml``:

.. code-block:: sh

    $ 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:

.. code-block:: sh

    $ 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``:

.. code-block:: 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``:

.. code-block:: yaml

    - 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 <https://peps.python.org/pep-0639/>`_ ``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.
