mirror of https://github.com/pypa/pip
Merge pull request #8340 from uranusjr/new-resolver-yanked-warning
New resolver yanked warning
This commit is contained in:
commit
14c8989f84
|
@ -7,6 +7,7 @@ if MYPY_CHECK_RUNNING:
|
|||
|
||||
from pip._vendor.packaging.version import _BaseVersion
|
||||
|
||||
from pip._internal.models.link import Link
|
||||
from pip._internal.req.req_install import InstallRequirement
|
||||
|
||||
CandidateLookup = Tuple[
|
||||
|
@ -54,6 +55,11 @@ class Candidate(object):
|
|||
# type: () -> bool
|
||||
raise NotImplementedError("Override in subclass")
|
||||
|
||||
@property
|
||||
def source_link(self):
|
||||
# type: () -> Optional[Link]
|
||||
raise NotImplementedError("Override in subclass")
|
||||
|
||||
def iter_dependencies(self):
|
||||
# type: () -> Iterable[Optional[Requirement]]
|
||||
raise NotImplementedError("Override in subclass")
|
||||
|
|
|
@ -106,19 +106,34 @@ def make_install_req_from_dist(dist, template):
|
|||
|
||||
|
||||
class _InstallRequirementBackedCandidate(Candidate):
|
||||
# These are not installed
|
||||
"""A candidate backed by an ``InstallRequirement``.
|
||||
|
||||
This represents a package request with the target not being already
|
||||
in the environment, and needs to be fetched and installed. The backing
|
||||
``InstallRequirement`` is responsible for most of the leg work; this
|
||||
class exposes appropriate information to the resolver.
|
||||
|
||||
:param link: The link passed to the ``InstallRequirement``. The backing
|
||||
``InstallRequirement`` will use this link to fetch the distribution.
|
||||
:param source_link: The link this candidate "originates" from. This is
|
||||
different from ``link`` when the link is found in the wheel cache.
|
||||
``link`` would point to the wheel cache, while this points to the
|
||||
found remote link (e.g. from pypi.org).
|
||||
"""
|
||||
is_installed = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
link, # type: Link
|
||||
source_link, # type: Link
|
||||
ireq, # type: InstallRequirement
|
||||
factory, # type: Factory
|
||||
name=None, # type: Optional[str]
|
||||
version=None, # type: Optional[_BaseVersion]
|
||||
):
|
||||
# type: (...) -> None
|
||||
self.link = link
|
||||
self._link = link
|
||||
self._source_link = source_link
|
||||
self._factory = factory
|
||||
self._ireq = ireq
|
||||
self._name = name
|
||||
|
@ -129,17 +144,17 @@ class _InstallRequirementBackedCandidate(Candidate):
|
|||
# type: () -> str
|
||||
return "{class_name}({link!r})".format(
|
||||
class_name=self.__class__.__name__,
|
||||
link=str(self.link),
|
||||
link=str(self._link),
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
# type: () -> int
|
||||
return hash((self.__class__, self.link))
|
||||
return hash((self.__class__, self._link))
|
||||
|
||||
def __eq__(self, other):
|
||||
# type: (Any) -> bool
|
||||
if isinstance(other, self.__class__):
|
||||
return self.link == other.link
|
||||
return self._link == other._link
|
||||
return False
|
||||
|
||||
# Needed for Python 2, which does not implement this by default
|
||||
|
@ -147,6 +162,11 @@ class _InstallRequirementBackedCandidate(Candidate):
|
|||
# type: (Any) -> bool
|
||||
return not self.__eq__(other)
|
||||
|
||||
@property
|
||||
def source_link(self):
|
||||
# type: () -> Optional[Link]
|
||||
return self._source_link
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
# type: () -> str
|
||||
|
@ -234,6 +254,7 @@ class LinkCandidate(_InstallRequirementBackedCandidate):
|
|||
version=None, # type: Optional[_BaseVersion]
|
||||
):
|
||||
# type: (...) -> None
|
||||
source_link = link
|
||||
cache_entry = factory.get_wheel_cache_entry(link, name)
|
||||
if cache_entry is not None:
|
||||
logger.debug("Using cached wheel link: %s", cache_entry.link)
|
||||
|
@ -247,6 +268,7 @@ class LinkCandidate(_InstallRequirementBackedCandidate):
|
|||
|
||||
super(LinkCandidate, self).__init__(
|
||||
link=link,
|
||||
source_link=source_link,
|
||||
ireq=ireq,
|
||||
factory=factory,
|
||||
name=name,
|
||||
|
@ -272,6 +294,7 @@ class EditableCandidate(_InstallRequirementBackedCandidate):
|
|||
# type: (...) -> None
|
||||
super(EditableCandidate, self).__init__(
|
||||
link=link,
|
||||
source_link=link,
|
||||
ireq=make_install_req_from_editable(link, template),
|
||||
factory=factory,
|
||||
name=name,
|
||||
|
@ -285,6 +308,7 @@ class EditableCandidate(_InstallRequirementBackedCandidate):
|
|||
|
||||
class AlreadyInstalledCandidate(Candidate):
|
||||
is_installed = True
|
||||
source_link = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -418,6 +442,11 @@ class ExtrasCandidate(Candidate):
|
|||
# type: () -> _BaseVersion
|
||||
return self.base.is_installed
|
||||
|
||||
@property
|
||||
def source_link(self):
|
||||
# type: () -> Optional[Link]
|
||||
return self.base.source_link
|
||||
|
||||
def iter_dependencies(self):
|
||||
# type: () -> Iterable[Optional[Requirement]]
|
||||
factory = self.base._factory
|
||||
|
@ -455,6 +484,7 @@ class ExtrasCandidate(Candidate):
|
|||
|
||||
class RequiresPythonCandidate(Candidate):
|
||||
is_installed = False
|
||||
source_link = None
|
||||
|
||||
def __init__(self, py_version_info):
|
||||
# type: (Optional[Tuple[int, ...]]) -> None
|
||||
|
|
|
@ -167,6 +167,21 @@ class Resolver(BaseResolver):
|
|||
ireq = candidate.get_install_requirement()
|
||||
if ireq is None:
|
||||
continue
|
||||
link = candidate.source_link
|
||||
if link and link.is_yanked:
|
||||
# The reason can contain non-ASCII characters, Unicode
|
||||
# is required for Python 2.
|
||||
msg = (
|
||||
u'The candidate selected for download or install is a '
|
||||
u'yanked version: {name!r} candidate (version {version} '
|
||||
u'at {link})\nReason for being yanked: {reason}'
|
||||
).format(
|
||||
name=candidate.name,
|
||||
version=candidate.version,
|
||||
link=link,
|
||||
reason=link.yanked_reason or u'<none given>',
|
||||
)
|
||||
logger.warning(msg)
|
||||
ireq.should_reinstall = self.factory.should_reinstall(candidate)
|
||||
req_set.add_named_requirement(ireq)
|
||||
|
||||
|
|
|
@ -1797,7 +1797,6 @@ def test_valid_index_url_argument(script, shared_data):
|
|||
assert 'Successfully installed Dinner' in result.stdout, str(result)
|
||||
|
||||
|
||||
@pytest.mark.fails_on_new_resolver
|
||||
def test_install_yanked_file_and_print_warning(script, data):
|
||||
"""
|
||||
Test install a "yanked" file and print a warning.
|
||||
|
|
Loading…
Reference in New Issue