Source code for rs_files_templates.external.spdx

"""Resolve SPDX license identifiers to authoritative full license text."""

from __future__ import annotations

import json
from functools import lru_cache
from urllib.error import HTTPError, URLError
from urllib.parse import quote
from urllib.request import urlopen

SPDX_LICENSE_URL = "https://spdx.org/licenses/{identifier}.json"


[docs] class UnknownSpdxLicense(ValueError): """Raised when SPDX does not recognize a supplied identifier."""
[docs] @lru_cache(maxsize=64) def fetch_spdx_license_text(identifier: str, timeout: float = 15.0) -> str: """Fetch and cache the full text for one SPDX license identifier.""" normalized = identifier.strip() url = SPDX_LICENSE_URL.format(identifier=quote(normalized, safe="")) try: with urlopen(url, timeout=timeout) as response: payload = json.loads(response.read()) except HTTPError as error: if error.code == 404: raise UnknownSpdxLicense(normalized) from error raise RuntimeError(f"Could not fetch SPDX license {normalized!r}") from error except (OSError, URLError, json.JSONDecodeError) as error: raise RuntimeError(f"Could not fetch SPDX license {normalized!r}") from error if payload.get("licenseId") != normalized or not payload.get("licenseText"): raise RuntimeError(f"SPDX returned invalid license data for {normalized!r}") return str(payload["licenseText"]).rstrip()
[docs] def resolve_license_text(value: str | None) -> str: """Resolve an SPDX identifier, or preserve unrecognized input as custom text.""" supplied = str(value or "").strip() if not supplied: return "REPLACE_WITH_LICENSE_TEXT" if "\n" in supplied: return supplied try: return fetch_spdx_license_text(supplied) except UnknownSpdxLicense: return supplied