Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions scripts/licensing/attributions_lockfile_md.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,14 +702,20 @@ def _declared_wheel_license_texts(


def _heuristic_wheel_license_texts(
zf: zipfile.ZipFile, dist_info_dir: str
zf: zipfile.ZipFile, dist_info_dir: str, package_name: str
) -> list[tuple[str, str]]:
"""Return a fallback wheel license file when metadata does not declare one."""
normalized_package = _normalize_package_name(package_name)
heuristic_paths = _common_license_candidates(
[
name
for name in zf.namelist()
if name.startswith(f"{dist_info_dir}/licenses/") or name.startswith(f"{dist_info_dir}/")
if name.startswith(f"{dist_info_dir}/licenses/")
or name.startswith(f"{dist_info_dir}/")
or (
name.count("/") == 1
and _normalize_package_name(name.split("/", 1)[0]) == normalized_package
)
]
)
heuristic_candidates: list[tuple[str, str, str]] = []
Expand Down Expand Up @@ -739,7 +745,7 @@ def _wheel_metadata_from_bytes(
)
if not license_texts:
# Older wheels often omit License-File entries but still bundle a LICENSE-like file.
license_texts = _heuristic_wheel_license_texts(zf, dist_info_dir)
license_texts = _heuristic_wheel_license_texts(zf, dist_info_dir, package_name)
return license_name, license_texts


Expand Down
19 changes: 19 additions & 0 deletions tests/test_attributions.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,25 @@ def test_wheel_license_is_rendered_in_relay_format():
assert license_text in text


def test_wheel_license_can_live_at_the_import_package_root():
data = io.BytesIO()
license_text = "Copyright Example Authors\nPermission granted.\n"
with zipfile.ZipFile(data, "w") as wheel:
wheel.writestr(
"example-1.0.dist-info/METADATA",
"Name: example\nVersion: 1.0\nLicense-Expression: MIT\n",
)
wheel.writestr("example/LICENSE", license_text)
wheel.writestr("unrelated/LICENSE", "Unrelated dependency license")

license_name, texts = attribution._wheel_metadata_from_bytes(
data.getvalue(), package_name="example"
)

assert license_name == "MIT"
assert texts == [("LICENSE", license_text.rstrip())]


def test_rust_upstream_fallback_uses_publication_commit(tmp_path, monkeypatch):
import json

Expand Down
Loading