Skip to content

Commit

Permalink
Merge pull request #10625 from albertosottile/ignore_yanked
Browse files Browse the repository at this point in the history
  • Loading branch information
pradyunsg authored Jan 24, 2022
2 parents 79e6237 + 7057423 commit 997c5a7
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 4 deletions.
2 changes: 2 additions & 0 deletions news/10617.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Prevent pip from installing yanked releases unless
explicitely pinned via the ``==`` or ``===`` operators.
21 changes: 17 additions & 4 deletions src/pip/_internal/resolution/resolvelib/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,14 +273,27 @@ def iter_index_candidate_infos() -> Iterator[IndexCandidateInfo]:
)
icans = list(result.iter_applicable())

# PEP 592: Yanked releases must be ignored unless only yanked
# releases can satisfy the version range. So if this is false,
# all yanked icans need to be skipped.
# PEP 592: Yanked releases are ignored unless the specifier
# explicitely pins a version (via '==' or '===') that can be
# solely satisfied by a yanked release.
all_yanked = all(ican.link.is_yanked for ican in icans)

def is_pinned(specifier: SpecifierSet) -> bool:
for sp in specifier:
if sp.operator == "===":
return True
if sp.operator != "==":
continue
if sp.version.endswith(".*"):
continue
return True
return False

pinned = is_pinned(specifier)

# PackageFinder returns earlier versions first, so we reverse.
for ican in reversed(icans):
if not all_yanked and ican.link.is_yanked:
if not (all_yanked and pinned) and ican.link.is_yanked:
continue
func = functools.partial(
self._make_candidate_from_link,
Expand Down
7 changes: 7 additions & 0 deletions tests/data/indexes/yanked_all/simple/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<html>
<body>
<a data-yanked="test reason message" href="../../../packages/simple-1.0.tar.gz">simple-1.0.tar.gz</a>
<a data-yanked="test reason message" href="../../../packages/simple-2.0.tar.gz">simple-2.0.tar.gz</a>
<a data-yanked="test reason message" href="../../../packages/simple-3.0.tar.gz">simple-3.0.tar.gz</a>
</body>
</html>
18 changes: 18 additions & 0 deletions tests/functional/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -2172,6 +2172,24 @@ def test_install_yanked_file_and_print_warning(
assert "Successfully installed simple-3.0\n" in result.stdout, str(result)


def test_error_all_yanked_files_and_no_pin(script, data):
"""
Test raising an error if there are only "yanked" files available and no pin
"""
result = script.pip(
"install",
"simple",
"--index-url",
data.index_url("yanked_all"),
expect_error=True,
)
# Make sure an error is raised
assert (
result.returncode == 1
and "ERROR: No matching distribution found for simple\n" in result.stderr
), str(result)


@pytest.mark.parametrize(
"install_args",
[
Expand Down

0 comments on commit 997c5a7

Please sign in to comment.