zaojun 1.6.0

- zaojun can now optionally check the licenses of your dependencies for compliance with your project's own license.

#Python #PyPI #CLI #OpenSource
License compliance checking is new — and it is off by default. No surprises, no noise if you don't need it. When you're ready, enable it with a single line in `pyproject.toml`:

```toml
[tool.zaojun]
check-licenses = true
```

Or pass `--check-licenses` on the command line for a one-off check. From that point on, every dependency run also tells you whether each package's license is compatible with your project.
Before zaojun can check anything, it needs to know what your project's own license is. It reads `project.license` straight from your `pyproject.toml` — no extra config required. If your project follows the PEP 639 SPDX string form (`license = "MIT"` or `license = "AGPL-3.0-or-later"`), zaojun picks it up automatically.

When a check runs, zaojun tells you what it found right at the top of the output, before the dependency list:

```
License check: AGPL-3.0-or-later (auto-derived)
  Allowed: 0BSD, AGPL-3.0-only, AGPL-3.0-or-later, Apache-2.0, ...
```

No guessing. You can see at a glance what zaojun is working with.
Once zaojun knows your license, it derives a compatible set of dependency licenses automatically, based on the well-understood tier structure of open source licensing. A permissive project (MIT, Apache-2.0, BSD) can only safely depend on other permissive packages. An LGPL or AGPL project has more freedom — it can pull in copyleft dependencies too, because the licenses are designed to be compatible upwards.

There is one notable edge case worth knowing about: GPL-2.0-only projects cannot use Apache-2.0 dependencies, because the Apache-2.0 patent termination clause is incompatible with GPL 2. zaojun handles this correctly out of the box — Apache-2.0 is excluded from the GPL-2.0-only allowed set, even though it is otherwise considered permissive.
The auto-derived set covers the common case, but not every situation fits neatly into a tier. If your project has specific requirements — a narrow allow list for a company policy, or a broader one for a project with unusual licensing arrangements — you can specify exactly which licenses are acceptable:

```toml
[tool.zaojun]
allowed-licenses = ["MIT", "Apache-2.0", "BSD-2-Clause"]
```

Setting `allowed-licenses` automatically enables license checking, so you don't need `check-licenses = true` as well. zaojun uses your list verbatim — no auto-derivation, no surprises.
Not every package on PyPI has clean, machine-readable license metadata. When zaojun cannot determine a dependency's license, it warns you by default rather than failing the run — because an unknown license is not necessarily a bad one, just an opaque one.

You can tune this behaviour with `unknown-license`:

```toml
[tool.zaojun]
unknown-license = "warn"   # default — print a warning, do not fail
unknown-license = "fail"   # treat unknown as a violation, exit 1
unknown-license = "allow"  # ignore silently
```
Some packages are a known quantity even if their metadata is imperfect, or they fall outside the auto-derived set for reasons you've already thought through. For those, `license-ignore` lets you exempt a specific package from the check:

```toml
[[tool.zaojun.license-ignore]]
package = "some-package"
reason = "Manually reviewed — BSD-compatible despite classifier gap"
```

The `reason` field is required. This is deliberate: six months from now, a reason in the config is the difference between a documented decision and a mystery exemption.
Many packages on PyPI are dual-licensed — `packaging` is `Apache-2.0 OR BSD-2-Clause`, `uv` is `MIT OR Apache-2.0`. A raw string comparison would flag both as violations even when one of the alternatives is clearly acceptable. zaojun parses SPDX expressions properly: for `OR`, any one matching alternative is enough; for `AND`, all components must be in the allowed set (because all apply simultaneously); `WITH` exception clauses like `GPL-2.0-only WITH Classpath-exception-2.0` are evaluated against the base license ID. Real-world dual-licensed packages work correctly without any manual exemptions.
Install / upgrade:

  uv tool install zaojun
  uv tool upgrade zaojun

Docs: https://marvin8.codeberg.page/zaojun/latest/
Redirecting