Skip to content

Commit 3b60e36

Browse files
authored
Merge pull request #11696 from uranusjr/fix-link-hashes
Merge link_hash back into _hashes
2 parents a057c9b + 0233bf2 commit 3b60e36

File tree

2 files changed

+34
-36
lines changed

2 files changed

+34
-36
lines changed

src/pip/_internal/models/link.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ def split_hash_name_and_value(cls, url: str) -> Optional["LinkHash"]:
7979
name, value = match.groups()
8080
return cls(name=name, value=value)
8181

82+
def as_dict(self) -> Dict[str, str]:
83+
return {self.name: self.value}
84+
8285
def as_hashes(self) -> Hashes:
8386
"""Return a Hashes instance which checks only for the current hash."""
8487
return Hashes({self.name: [self.value]})
@@ -165,7 +168,6 @@ class Link(KeyBasedCompareMixin):
165168
"requires_python",
166169
"yanked_reason",
167170
"dist_info_metadata",
168-
"link_hash",
169171
"cache_link_parsing",
170172
"egg_fragment",
171173
]
@@ -177,7 +179,6 @@ def __init__(
177179
requires_python: Optional[str] = None,
178180
yanked_reason: Optional[str] = None,
179181
dist_info_metadata: Optional[str] = None,
180-
link_hash: Optional[LinkHash] = None,
181182
cache_link_parsing: bool = True,
182183
hashes: Optional[Mapping[str, str]] = None,
183184
) -> None:
@@ -200,16 +201,11 @@ def __init__(
200201
attribute, if present, in a simple repository HTML link. This may be parsed
201202
into its own `Link` by `self.metadata_link()`. See PEP 658 for more
202203
information and the specification.
203-
:param link_hash: a checksum for the content the link points to. If not
204-
provided, this will be extracted from the link URL, if the URL has
205-
any checksum.
206204
:param cache_link_parsing: A flag that is used elsewhere to determine
207-
whether resources retrieved from this link
208-
should be cached. PyPI index urls should
209-
generally have this set to False, for
210-
example.
205+
whether resources retrieved from this link should be cached. PyPI
206+
URLs should generally have this set to False, for example.
211207
:param hashes: A mapping of hash names to digests to allow us to
212-
determine the validity of a download.
208+
determine the validity of a download.
213209
"""
214210

215211
# url can be a UNC windows share
@@ -220,13 +216,18 @@ def __init__(
220216
# Store the url as a private attribute to prevent accidentally
221217
# trying to set a new value.
222218
self._url = url
223-
self._hashes = hashes if hashes is not None else {}
219+
220+
link_hash = LinkHash.split_hash_name_and_value(url)
221+
hashes_from_link = {} if link_hash is None else link_hash.as_dict()
222+
if hashes is None:
223+
self._hashes = hashes_from_link
224+
else:
225+
self._hashes = {**hashes, **hashes_from_link}
224226

225227
self.comes_from = comes_from
226228
self.requires_python = requires_python if requires_python else None
227229
self.yanked_reason = yanked_reason
228230
self.dist_info_metadata = dist_info_metadata
229-
self.link_hash = link_hash or LinkHash.split_hash_name_and_value(self._url)
230231

231232
super().__init__(key=url, defining_class=Link)
232233

@@ -401,29 +402,26 @@ def metadata_link(self) -> Optional["Link"]:
401402
if self.dist_info_metadata is None:
402403
return None
403404
metadata_url = f"{self.url_without_fragment}.metadata"
404-
link_hash: Optional[LinkHash] = None
405405
# If data-dist-info-metadata="true" is set, then the metadata file exists,
406406
# but there is no information about its checksum or anything else.
407407
if self.dist_info_metadata != "true":
408408
link_hash = LinkHash.split_hash_name_and_value(self.dist_info_metadata)
409-
return Link(metadata_url, link_hash=link_hash)
409+
else:
410+
link_hash = None
411+
if link_hash is None:
412+
return Link(metadata_url)
413+
return Link(metadata_url, hashes=link_hash.as_dict())
410414

411-
def as_hashes(self) -> Optional[Hashes]:
412-
if self.link_hash is not None:
413-
return self.link_hash.as_hashes()
414-
return None
415+
def as_hashes(self) -> Hashes:
416+
return Hashes({k: [v] for k, v in self._hashes.items()})
415417

416418
@property
417419
def hash(self) -> Optional[str]:
418-
if self.link_hash is not None:
419-
return self.link_hash.value
420-
return None
420+
return next(iter(self._hashes.values()), None)
421421

422422
@property
423423
def hash_name(self) -> Optional[str]:
424-
if self.link_hash is not None:
425-
return self.link_hash.name
426-
return None
424+
return next(iter(self._hashes), None)
427425

428426
@property
429427
def show_url(self) -> str:
@@ -452,15 +450,15 @@ def is_yanked(self) -> bool:
452450

453451
@property
454452
def has_hash(self) -> bool:
455-
return self.link_hash is not None
453+
return bool(self._hashes)
456454

457455
def is_hash_allowed(self, hashes: Optional[Hashes]) -> bool:
458456
"""
459457
Return True if the link has a hash and it is allowed by `hashes`.
460458
"""
461-
if self.link_hash is None:
459+
if hashes is None:
462460
return False
463-
return self.link_hash.is_hash_allowed(hashes)
461+
return any(hashes.is_hash_allowed(k, v) for k, v in self._hashes.items())
464462

465463

466464
class _CleanResult(NamedTuple):

tests/unit/test_collector.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import uuid
77
from pathlib import Path
88
from textwrap import dedent
9-
from typing import List, Optional, Tuple
9+
from typing import Dict, List, Optional, Tuple
1010
from unittest import mock
1111

1212
import pytest
@@ -538,7 +538,7 @@ def test_parse_links_json() -> None:
538538
metadata_link.url
539539
== "https://example.com/files/holygrail-1.0-py3-none-any.whl.metadata"
540540
)
541-
assert metadata_link.link_hash == LinkHash("sha512", "aabdd41")
541+
assert metadata_link._hashes == {"sha512": "aabdd41"}
542542

543543

544544
@pytest.mark.parametrize(
@@ -575,41 +575,41 @@ def test_parse_links__yanked_reason(anchor_html: str, expected: Optional[str]) -
575575

576576

577577
@pytest.mark.parametrize(
578-
"anchor_html, expected, link_hash",
578+
"anchor_html, expected, hashes",
579579
[
580580
# Test not present.
581581
(
582582
'<a href="/pkg1-1.0.tar.gz"></a>',
583583
None,
584-
None,
584+
{},
585585
),
586586
# Test with value "true".
587587
(
588588
'<a href="/pkg1-1.0.tar.gz" data-dist-info-metadata="true"></a>',
589589
"true",
590-
None,
590+
{},
591591
),
592592
# Test with a provided hash value.
593593
(
594594
'<a href="/pkg1-1.0.tar.gz" data-dist-info-metadata="sha256=aa113592bbe"></a>', # noqa: E501
595595
"sha256=aa113592bbe",
596-
None,
596+
{},
597597
),
598598
# Test with a provided hash value for both the requirement as well as metadata.
599599
(
600600
'<a href="/pkg1-1.0.tar.gz#sha512=abc132409cb" data-dist-info-metadata="sha256=aa113592bbe"></a>', # noqa: E501
601601
"sha256=aa113592bbe",
602-
LinkHash("sha512", "abc132409cb"),
602+
{"sha512": "abc132409cb"},
603603
),
604604
],
605605
)
606606
def test_parse_links__dist_info_metadata(
607607
anchor_html: str,
608608
expected: Optional[str],
609-
link_hash: Optional[LinkHash],
609+
hashes: Dict[str, str],
610610
) -> None:
611611
link = _test_parse_links_data_attribute(anchor_html, "dist_info_metadata", expected)
612-
assert link.link_hash == link_hash
612+
assert link._hashes == hashes
613613

614614

615615
def test_parse_links_caches_same_page_by_url() -> None:

0 commit comments

Comments
 (0)