mirror of https://github.com/pypa/pip
Prefer candidates with allowed hashes when sorting.
This commit is contained in:
parent
9ddc89a21d
commit
74504fff6c
|
@ -0,0 +1,2 @@
|
|||
When choosing candidates to install, prefer candidates with a hash matching
|
||||
one of the user-provided hashes.
|
|
@ -54,7 +54,7 @@ if MYPY_CHECK_RUNNING:
|
|||
|
||||
BuildTag = Tuple[Any, ...] # either empty tuple or Tuple[int, str]
|
||||
CandidateSortingKey = (
|
||||
Tuple[int, int, _BaseVersion, BuildTag, Optional[int]]
|
||||
Tuple[int, int, int, _BaseVersion, BuildTag, Optional[int]]
|
||||
)
|
||||
HTMLElement = xml.etree.ElementTree.Element
|
||||
SecureOrigin = Tuple[str, str, Optional[str]]
|
||||
|
@ -624,8 +624,14 @@ class CandidateEvaluator(object):
|
|||
|
||||
The preference is as follows:
|
||||
|
||||
First and foremost, yanked candidates (in the sense of PEP 592) are
|
||||
always less preferred than candidates that haven't been yanked. Then:
|
||||
First and foremost, candidates with allowed (matching) hashes are
|
||||
always preferred over candidates without matching hashes. This is
|
||||
because e.g. if the only candidate with an allowed hash is yanked,
|
||||
we still want to use that candidate.
|
||||
|
||||
Second, excepting hash considerations, candidates that have been
|
||||
yanked (in the sense of PEP 592) are always less preferred than
|
||||
candidates that haven't been yanked. Then:
|
||||
|
||||
If not finding wheels, they are sorted by version only.
|
||||
If finding wheels, then the sort order is by version, then:
|
||||
|
@ -660,9 +666,11 @@ class CandidateEvaluator(object):
|
|||
build_tag = (int(build_tag_groups[0]), build_tag_groups[1])
|
||||
else: # sdist
|
||||
pri = -(support_num)
|
||||
has_allowed_hash = int(link.is_hash_allowed(self._hashes))
|
||||
yank_value = -1 * int(link.is_yanked) # -1 for yanked.
|
||||
return (
|
||||
yank_value, binary_preference, candidate.version, build_tag, pri,
|
||||
has_allowed_hash, yank_value, binary_preference, candidate.version,
|
||||
build_tag, pri,
|
||||
)
|
||||
|
||||
def get_best_candidate(
|
||||
|
|
|
@ -302,6 +302,29 @@ class TestCandidateEvaluator:
|
|||
]
|
||||
assert found_candidates._applicable_candidates == expected_applicable
|
||||
|
||||
@pytest.mark.parametrize('hex_digest, expected', [
|
||||
# Test a link with no hash.
|
||||
(None, 0),
|
||||
# Test a link with an allowed hash.
|
||||
(64 * 'a', 1),
|
||||
# Test a link with a hash that isn't allowed.
|
||||
(64 * 'b', 0),
|
||||
])
|
||||
def test_sort_key__hash(self, hex_digest, expected):
|
||||
"""
|
||||
Test the effect of the link's hash on _sort_key()'s return value.
|
||||
"""
|
||||
candidate = make_mock_candidate('1.0', hex_digest=hex_digest)
|
||||
hashes_data = {
|
||||
'sha256': [64 * 'a'],
|
||||
}
|
||||
hashes = Hashes(hashes_data)
|
||||
evaluator = CandidateEvaluator.create(hashes=hashes)
|
||||
sort_value = evaluator._sort_key(candidate)
|
||||
# The hash is reflected in the first element of the tuple.
|
||||
actual = sort_value[0]
|
||||
assert actual == expected
|
||||
|
||||
@pytest.mark.parametrize('yanked_reason, expected', [
|
||||
# Test a non-yanked file.
|
||||
(None, 0),
|
||||
|
@ -312,14 +335,11 @@ class TestCandidateEvaluator:
|
|||
"""
|
||||
Test the effect of is_yanked on _sort_key()'s return value.
|
||||
"""
|
||||
url = 'https://example.com/mypackage.tar.gz'
|
||||
link = Link(url, yanked_reason=yanked_reason)
|
||||
candidate = InstallationCandidate('mypackage', '1.0', link)
|
||||
|
||||
candidate = make_mock_candidate('1.0', yanked_reason=yanked_reason)
|
||||
evaluator = CandidateEvaluator.create()
|
||||
sort_value = evaluator._sort_key(candidate)
|
||||
# Yanked / non-yanked is reflected in the first element of the tuple.
|
||||
actual = sort_value[0]
|
||||
# Yanked / non-yanked is reflected in the second element of the tuple.
|
||||
actual = sort_value[1]
|
||||
assert actual == expected
|
||||
|
||||
def test_get_best_candidate__no_candidates(self):
|
||||
|
|
Loading…
Reference in New Issue