From 81056e3599bcf6b68441b9039ca9e1c2c0cebe9b Mon Sep 17 00:00:00 2001 From: Rohan Devasthale Date: Thu, 15 Oct 2026 15:49:29 -0400 Subject: [PATCH] fix(pkgmetadata): raise ValueError when no classifier maps to SPDX `_trove_to_spdx()` skipped every classifier absent from `_TROVE_SPDX`, leaving `trove_spdx` empty and calling `_parse_spdx("")`, which parses to `None` and raised `AttributeError` on `None.simplify()`. Since that is not a `ValueError`, `license_from_metadata_values()` could not catch it and fall back. It now raises `ValueError` when no classifier maps to SPDX, restoring the documented behavior so callers can fall back to `NOASSERTION`. Closes: #1372 Co-Authored-By: Claude Opus 4.8 Signed-off-by: Rohan Devasthale --- src/fromager/pkgmetadata/pep639.py | 2 ++ tests/test_pkgmetadata.py | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/fromager/pkgmetadata/pep639.py b/src/fromager/pkgmetadata/pep639.py index 53fc24a62..d01192094 100644 --- a/src/fromager/pkgmetadata/pep639.py +++ b/src/fromager/pkgmetadata/pep639.py @@ -81,6 +81,8 @@ def _trove_to_spdx(troves: list[str]) -> LicenseExpression: if mapped is None: raise ValueError(f"{trove!r} is ambiguous") trove_spdx.append(mapped) + if not trove_spdx: + raise ValueError("no classifier maps to a SPDX license expression") # join with AND return _parse_spdx(" AND ".join(trove_spdx), simplify=True) diff --git a/tests/test_pkgmetadata.py b/tests/test_pkgmetadata.py index 0eb8baac6..1bb408500 100644 --- a/tests/test_pkgmetadata.py +++ b/tests/test_pkgmetadata.py @@ -108,6 +108,18 @@ def test_license_from_metadata(metadata: Metadata, expected: str) -> None: (None, None, None), (None, "invalid", None), (None, None, ["License :: OSI Approved :: BSD License"]), + # classifiers with no entry that maps to SPDX (see issue #1372) + (None, None, ["Programming Language :: Python :: 3"]), + (None, None, ["License :: OSI Approved"]), + # non-license classifier alongside an ambiguous license classifier + ( + None, + None, + [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + ], + ), ], ) def test_license_from_metadata_errors(