# SPDX-FileCopyrightText: 2026 Bart Broere # SPDX-License-Identifier: GPL-3.0-or-later """Make sure every Python distribution in an environment ships its license text. Most wheels include their license files in ``*.dist-info``. For the ones that do not, copy its license files to ``/-/``, taking them from ``//`` when present and otherwise from the source distribution on PyPI. Run with the interpreter of the environment to inspect: ``/opt/pgadmin/bin/python collect-python-licenses.py ``. """ import io import json import re import sys import tarfile import urllib.request import zipfile from importlib import metadata from pathlib import Path LICENSE_FILE = re.compile(r"(^|/)(LICEN[CS]E|COPYING|NOTICE|AUTHORS)[^/]*$", re.IGNORECASE) def has_license_file(dist): return any(LICENSE_FILE.search(str(f)) for f in dist.files or []) def sdist_members(name, version): with urllib.request.urlopen(f"https://pypi.org/pypi/{name}/{version}/json", timeout=60) as r: urls = json.load(r)["urls"] sdist = next((u for u in urls if u["packagetype"] == "sdist"), None) if sdist is None: return {} with urllib.request.urlopen(sdist["url"], timeout=120) as r: data = r.read() found = {} if sdist["filename"].endswith(".zip"): with zipfile.ZipFile(io.BytesIO(data)) as z: for n in z.namelist(): if n.count("/") == 1 and LICENSE_FILE.search(n): found[n.split("/", 1)[1]] = z.read(n) else: with tarfile.open(fileobj=io.BytesIO(data)) as t: for m in t.getmembers(): if m.isfile() and m.name.count("/") == 1 and LICENSE_FILE.search(m.name): found[m.name.split("/", 1)[1]] = t.extractfile(m).read() return found def vendored_files(vendored, name): directory = vendored / name if not directory.is_dir(): return {} return {f.name: f.read_bytes() for f in directory.iterdir() if f.is_file()} def main(output, vendored): output, vendored = Path(output), Path(vendored) missing = [] for dist in sorted(metadata.distributions(), key=lambda d: d.metadata["Name"].lower()): if has_license_file(dist): continue name, version = dist.metadata["Name"], dist.version files = vendored_files(vendored, name) if not files: try: files = sdist_members(name, version) except Exception as e: # noqa: BLE001 - report and carry on print(f"{name} {version}: could not fetch sdist: {e}", file=sys.stderr) if not files: missing.append(f"{name} {version}") continue target = output / f"{name}-{version}" target.mkdir(parents=True, exist_ok=True) for filename, content in files.items(): (target / filename).write_bytes(content) print(f"{name} {version}: added {', '.join(files)}") for item in missing: print(f"WARNING: no license file found for {item}", file=sys.stderr) if __name__ == "__main__": main(sys.argv[1], sys.argv[2])