Skip to content

Commit e4b65d6

Browse files
committed
utils.link: add PEP 658 (metadata) support
1 parent 26f2f5d commit e4b65d6

File tree

2 files changed

+105
-9
lines changed

2 files changed

+105
-9
lines changed

src/poetry/core/packages/utils/link.py

+33
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def __init__(
1616
url: str,
1717
comes_from: Any | None = None,
1818
requires_python: str | None = None,
19+
metadata: str | None = None,
1920
) -> None:
2021
"""
2122
Object representing a parsed link from https://pypi.python.org/simple/*
@@ -28,6 +29,11 @@ def __init__(
2829
String containing the `Requires-Python` metadata field, specified
2930
in PEP 345. This may be specified by a data-requires-python
3031
attribute in the HTML link tag, as described in PEP 503.
32+
metadata:
33+
String of the syntax `<hashname>=<hashvalue>` representing the hash
34+
of the Core Metadata file. This may be specified by a
35+
data-dist-info-metadata attribute in the HTML link tag, as described
36+
in PEP 658.
3137
"""
3238

3339
# url can be a UNC windows share
@@ -37,6 +43,7 @@ def __init__(
3743
self.url = url
3844
self.comes_from = comes_from
3945
self.requires_python = requires_python if requires_python else None
46+
self._metadata = metadata
4047

4148
def __str__(self) -> str:
4249
if self.requires_python:
@@ -136,6 +143,32 @@ def subdirectory_fragment(self) -> str | None:
136143

137144
_hash_re = re.compile(r"(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)")
138145

146+
@property
147+
def has_metadata(self) -> bool:
148+
return self._metadata is not None and (self.is_wheel or self.is_sdist)
149+
150+
@property
151+
def metadata(self) -> str | None:
152+
if self.has_metadata:
153+
return f"{self.url_without_fragment.split('?', 1)[0]}.metadata"
154+
return None
155+
156+
@property
157+
def metadata_hash(self) -> str | None:
158+
if self.has_metadata:
159+
match = self._hash_re.search(self._metadata or "")
160+
if match:
161+
return match.group(2)
162+
return None
163+
164+
@property
165+
def metadata_hash_name(self) -> str | None:
166+
if self.has_metadata:
167+
match = self._hash_re.search(self._metadata or "")
168+
if match:
169+
return match.group(1)
170+
return None
171+
139172
@property
140173
def hash(self) -> str | None:
141174
match = self._hash_re.search(self.url)

tests/packages/utils/test_utils_link.py

+72-9
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,83 @@
44

55
from hashlib import sha256
66

7+
import pytest
8+
79
from poetry.core.packages.utils.link import Link
810

911

10-
def make_url(ext: str) -> Link:
11-
checksum = sha256(str(uuid.uuid4()).encode())
12+
def make_checksum() -> str:
13+
return sha256(str(uuid.uuid4()).encode()).hexdigest()
14+
15+
16+
@pytest.fixture()
17+
def file_checksum() -> str:
18+
return make_checksum()
19+
20+
21+
@pytest.fixture()
22+
def metadata_checksum() -> str:
23+
return make_checksum()
24+
25+
26+
def make_url(
27+
ext: str, file_checksum: str = None, metadata_checksum: str = None
28+
) -> Link:
29+
file_checksum = file_checksum or make_checksum()
1230
return Link(
1331
"https://files.pythonhosted.org/packages/16/52/dead/"
14-
f"demo-1.0.0.{ext}#sha256={checksum}"
32+
f"demo-1.0.0.{ext}#sha256={file_checksum}",
33+
metadata=f"sha256={metadata_checksum}" if metadata_checksum else None,
1534
)
1635

1736

18-
def test_package_link_is_checks():
19-
assert make_url("egg").is_egg
20-
assert make_url("tar.gz").is_sdist
21-
assert make_url("zip").is_sdist
22-
assert make_url("exe").is_wininst
23-
assert make_url("cp36-cp36m-manylinux1_x86_64.whl").is_wheel
37+
def test_package_link_hash(file_checksum: str) -> None:
38+
link = make_url(ext="whl", file_checksum=file_checksum)
39+
assert link.hash_name == "sha256"
40+
assert link.hash == file_checksum
41+
assert link.show_url == "demo-1.0.0.whl"
42+
43+
44+
@pytest.mark.parametrize(
45+
("ext", "check"),
46+
[
47+
("whl", "wheel"),
48+
("egg", "egg"),
49+
("tar.gz", "sdist"),
50+
("zip", "sdist"),
51+
("cp36-cp36m-manylinux1_x86_64.whl", "wheel"),
52+
],
53+
)
54+
def test_package_link_is_checks(ext: str, check: str) -> None:
55+
link = make_url(ext=ext)
56+
assert getattr(link, f"is_{check}")
57+
58+
59+
@pytest.mark.parametrize(
60+
("ext", "has_metadata"),
61+
[("whl", True), ("egg", False), ("tar.gz", True), ("zip", True)],
62+
)
63+
def test_package_link_pep658(
64+
ext: str, has_metadata: bool, metadata_checksum: str
65+
) -> None:
66+
link = make_url(ext=ext, metadata_checksum=metadata_checksum)
67+
68+
if has_metadata:
69+
assert link.has_metadata
70+
assert link.metadata == f"{link.url_without_fragment}.metadata"
71+
assert link.metadata_hash == metadata_checksum
72+
assert link.metadata_hash_name == "sha256"
73+
else:
74+
assert not link.has_metadata
75+
assert not link.metadata
76+
assert not link.metadata_hash
77+
assert not link.metadata_hash_name
78+
79+
80+
def test_package_link_pep658_no_default_metadata() -> None:
81+
link = make_url(ext="whl")
82+
83+
assert not link.has_metadata
84+
assert not link.metadata
85+
assert not link.metadata_hash
86+
assert not link.metadata_hash_name

0 commit comments

Comments
 (0)