提交 09d31159 编写于 作者: P Paul Moore

Move error handling to factory.get_installation_error()

上级 c827f296
......@@ -5,6 +5,7 @@ from pip._vendor import six
from pip._vendor.packaging.utils import canonicalize_name
from pip._internal.exceptions import (
DistributionNotFound,
InstallationError,
UnsupportedPythonVersion,
)
......@@ -343,11 +344,79 @@ class Factory(object):
return UnsupportedPythonVersion(message)
def get_installation_error(self, e):
# type: (ResolutionImpossible) -> Optional[InstallationError]
# type: (ResolutionImpossible) -> InstallationError
assert e.causes, "Installation error reported with no cause"
# If one of the things we can't solve is "we need Python X.Y",
# that is what we report.
for cause in e.causes:
if isinstance(cause.requirement, RequiresPythonRequirement):
return self._report_requires_python_error(
cause.requirement,
cause.parent,
)
return None
# Otherwise, we have a set of causes which can't all be satisfied
# at once.
# The simplest case is when we have *one* cause that can't be
# satisfied. We just report that case.
if len(e.causes) == 1:
req, parent = e.causes[0]
logger.critical(
"Could not find a version that satisfies " +
"the requirement " +
str(req) +
("" if parent is None else " (from {})".format(
parent.name
))
)
return DistributionNotFound(
'No matching distribution found for {}'.format(req)
)
# OK, we now have a list of requirements that can't all be
# satisfied at once.
# A couple of formatting helpers
def text_join(parts):
# type: (List[str]) -> str
if len(parts) == 1:
return parts[0]
return ", ".join(parts[:-1]) + " and " + parts[-1]
def readable_form(cand):
# type: (Candidate) -> str
return "{} {}".format(cand.name, cand.version)
msg = "Cannot install {} because these package versions " \
"have conflicting dependencies.".format(
text_join([
readable_form(parent)
for req, parent in e.causes
if parent
])
)
msg = msg + "\nThe conflict is caused by:"
for req, parent in e.causes:
msg = msg + "\n "
if parent:
msg = msg + readable_form(parent) + " depends on "
else:
msg = msg + "The user requested "
msg = msg + str(req)
msg = msg + "\n\n" + \
"There are a number of possible solutions. " + \
"For instructions on how to do these steps visit: " + \
"https://pypa.io/SomeLink"
logger.critical(msg)
return DistributionNotFound(
"No matching distribution found for " +
", ".join(sorted(set(r.name for r, _ in e.causes)))
)
......@@ -6,7 +6,7 @@ from pip._vendor.packaging.utils import canonicalize_name
from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible
from pip._vendor.resolvelib import Resolver as RLResolver
from pip._internal.exceptions import DistributionNotFound, InstallationError
from pip._internal.exceptions import InstallationError
from pip._internal.req.req_set import RequirementSet
from pip._internal.resolution.base import BaseResolver
from pip._internal.resolution.resolvelib.provider import PipProvider
......@@ -142,53 +142,6 @@ class Resolver(BaseResolver):
except ResolutionImpossible as e:
error = self.factory.get_installation_error(e)
if not error:
# > pip install ward==0.44.1b0 py2neo==4.3.0 --unstable-feature=resolver
#
# ERROR: Cannot install ward v0.44.1b0 and py2neo v4.3.0 because these package versions have conflicting dependencies.
# The conflict is caused by:
# ward 0.44.1b0 depends on pygments <3.0.0,>=2.4.2
# py2neo 4.3.0 depends on pygments ~=2.3.1
#
# There are a number of possible solutions. For instructions on how to do these steps visit: https://pypa.io/SomeLink
def text_join(parts):
# type: (List[str]) -> str
return ", ".join(parts[:-1]) + " and " + parts[-1]
def readable_form(req):
# type: (InstallRequirement) -> str
return "{} {}".format(req.name, req.version)
# TODO: I haven't considered what happens if `parent` is None.
# I'm not even sure how that case arises...
logger.critical(
"Cannot install " +
text_join([
readable_form(parent)
for req, parent in e.causes
if parent
]) +
" because these package versions" +
" have conflicting dependencies."
)
logger.info("The conflict is caused by: ")
for req, parent in e.causes:
logger.info(
" " +
readable_form(parent) +
" depends on " +
str(req)
)
logger.info(
"There are a number of possible solutions. " +
"For instructions on how to do these steps visit: " +
"https://pypa.io/SomeLink"
)
raise DistributionNotFound(
"No matching distribution found for " +
", ".join(sorted(set(r.name for r, _ in e.causes)))
)
six.raise_from(error, e)
req_set = RequirementSet(check_supported_wheels=check_supported_wheels)
......
......@@ -282,9 +282,7 @@ def test_new_resolver_no_dist_message(script):
assert "Could not find a version that satisfies the requirement B" \
in result.stderr, str(result)
# TODO: This reports the canonical name of the project. But the current
# resolver reports the originally specified name (i.e. uppercase B)
assert "No matching distribution found for b" in result.stderr, str(result)
assert "No matching distribution found for B" in result.stderr, str(result)
def test_new_resolver_installs_editable(script):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册