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]
|
BuildTag = Tuple[Any, ...] # either empty tuple or Tuple[int, str]
|
||||||
CandidateSortingKey = (
|
CandidateSortingKey = (
|
||||||
Tuple[int, int, _BaseVersion, BuildTag, Optional[int]]
|
Tuple[int, int, int, _BaseVersion, BuildTag, Optional[int]]
|
||||||
)
|
)
|
||||||
HTMLElement = xml.etree.ElementTree.Element
|
HTMLElement = xml.etree.ElementTree.Element
|
||||||
SecureOrigin = Tuple[str, str, Optional[str]]
|
SecureOrigin = Tuple[str, str, Optional[str]]
|
||||||
|
@ -624,8 +624,14 @@ class CandidateEvaluator(object):
|
||||||
|
|
||||||
The preference is as follows:
|
The preference is as follows:
|
||||||
|
|
||||||
First and foremost, yanked candidates (in the sense of PEP 592) are
|
First and foremost, candidates with allowed (matching) hashes are
|
||||||
always less preferred than candidates that haven't been yanked. Then:
|
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 not finding wheels, they are sorted by version only.
|
||||||
If finding wheels, then the sort order is by version, then:
|
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])
|
build_tag = (int(build_tag_groups[0]), build_tag_groups[1])
|
||||||
else: # sdist
|
else: # sdist
|
||||||
pri = -(support_num)
|
pri = -(support_num)
|
||||||
|
has_allowed_hash = int(link.is_hash_allowed(self._hashes))
|
||||||
yank_value = -1 * int(link.is_yanked) # -1 for yanked.
|
yank_value = -1 * int(link.is_yanked) # -1 for yanked.
|
||||||
return (
|
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(
|
def get_best_candidate(
|
||||||
|
|
|
@ -302,6 +302,29 @@ class TestCandidateEvaluator:
|
||||||
]
|
]
|
||||||
assert found_candidates._applicable_candidates == expected_applicable
|
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', [
|
@pytest.mark.parametrize('yanked_reason, expected', [
|
||||||
# Test a non-yanked file.
|
# Test a non-yanked file.
|
||||||
(None, 0),
|
(None, 0),
|
||||||
|
@ -312,14 +335,11 @@ class TestCandidateEvaluator:
|
||||||
"""
|
"""
|
||||||
Test the effect of is_yanked on _sort_key()'s return value.
|
Test the effect of is_yanked on _sort_key()'s return value.
|
||||||
"""
|
"""
|
||||||
url = 'https://example.com/mypackage.tar.gz'
|
candidate = make_mock_candidate('1.0', yanked_reason=yanked_reason)
|
||||||
link = Link(url, yanked_reason=yanked_reason)
|
|
||||||
candidate = InstallationCandidate('mypackage', '1.0', link)
|
|
||||||
|
|
||||||
evaluator = CandidateEvaluator.create()
|
evaluator = CandidateEvaluator.create()
|
||||||
sort_value = evaluator._sort_key(candidate)
|
sort_value = evaluator._sort_key(candidate)
|
||||||
# Yanked / non-yanked is reflected in the first element of the tuple.
|
# Yanked / non-yanked is reflected in the second element of the tuple.
|
||||||
actual = sort_value[0]
|
actual = sort_value[1]
|
||||||
assert actual == expected
|
assert actual == expected
|
||||||
|
|
||||||
def test_get_best_candidate__no_candidates(self):
|
def test_get_best_candidate__no_candidates(self):
|
||||||
|
|
Loading…
Reference in New Issue