mirror of https://github.com/pypa/pip
Add handling of inconsistent root requirements
This commit is contained in:
parent
09d311594e
commit
2795742b31
|
@ -37,6 +37,10 @@ class Requirement(object):
|
|||
# type: () -> CandidateLookup
|
||||
raise NotImplementedError("Subclass should override")
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
raise NotImplementedError("Subclass should override")
|
||||
|
||||
|
||||
class Candidate(object):
|
||||
@property
|
||||
|
@ -61,3 +65,7 @@ class Candidate(object):
|
|||
def get_install_requirement(self):
|
||||
# type: () -> Optional[InstallRequirement]
|
||||
raise NotImplementedError("Override in subclass")
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
raise NotImplementedError("Subclass should override")
|
||||
|
|
|
@ -162,6 +162,14 @@ class _InstallRequirementBackedCandidate(Candidate):
|
|||
self._version = self.dist.parsed_version
|
||||
return self._version
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
return "{} {} (from {})".format(
|
||||
self.name,
|
||||
self.version,
|
||||
self.link.file_path
|
||||
)
|
||||
|
||||
def _prepare_abstract_distribution(self):
|
||||
# type: () -> AbstractDistribution
|
||||
raise NotImplementedError("Override in subclass")
|
||||
|
@ -336,6 +344,10 @@ class AlreadyInstalledCandidate(Candidate):
|
|||
# type: () -> _BaseVersion
|
||||
return self.dist.parsed_version
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
return "{} {} (Installed)".format(self.name, self.version)
|
||||
|
||||
def iter_dependencies(self):
|
||||
# type: () -> Iterable[Optional[Requirement]]
|
||||
for r in self.dist.requires():
|
||||
|
@ -413,6 +425,13 @@ class ExtrasCandidate(Candidate):
|
|||
# type: () -> _BaseVersion
|
||||
return self.base.version
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
return "{} [{}]".format(
|
||||
self.base.format_for_error(),
|
||||
", ".join(sorted(self.extras))
|
||||
)
|
||||
|
||||
@property
|
||||
def is_installed(self):
|
||||
# type: () -> _BaseVersion
|
||||
|
@ -479,6 +498,10 @@ class RequiresPythonCandidate(Candidate):
|
|||
# type: () -> _BaseVersion
|
||||
return self._version
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
return "Python {}".format(self.version)
|
||||
|
||||
def iter_dependencies(self):
|
||||
# type: () -> Iterable[Optional[Requirement]]
|
||||
return ()
|
||||
|
|
|
@ -391,23 +391,26 @@ class Factory(object):
|
|||
# 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
|
||||
])
|
||||
)
|
||||
if any(parent for _, parent in e.causes):
|
||||
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:"
|
||||
else:
|
||||
msg = "The following requirements are inconsistent:"
|
||||
|
||||
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 + req.format_for_error()
|
||||
|
||||
msg = msg + "\n\n" + \
|
||||
"There are a number of possible solutions. " + \
|
||||
|
|
|
@ -30,6 +30,10 @@ class ExplicitRequirement(Requirement):
|
|||
# No need to canonicalise - the candidate did this
|
||||
return self.candidate.name
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
return self.candidate.format_for_error()
|
||||
|
||||
def get_candidate_lookup(self):
|
||||
# type: () -> CandidateLookup
|
||||
return self.candidate, None
|
||||
|
@ -63,6 +67,10 @@ class SpecifierRequirement(Requirement):
|
|||
canonical_name = canonicalize_name(self._ireq.req.name)
|
||||
return format_name(canonical_name, self._extras)
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
return str(self)
|
||||
|
||||
def get_candidate_lookup(self):
|
||||
# type: () -> CandidateLookup
|
||||
return None, self._ireq
|
||||
|
@ -99,6 +107,10 @@ class RequiresPythonRequirement(Requirement):
|
|||
# type: () -> str
|
||||
return self._candidate.name
|
||||
|
||||
def format_for_error(self):
|
||||
# type: () -> str
|
||||
return "Python " + str(self.specifier)
|
||||
|
||||
def get_candidate_lookup(self):
|
||||
# type: () -> CandidateLookup
|
||||
if self.specifier.contains(self._candidate.version, prereleases=True):
|
||||
|
|
|
@ -925,3 +925,17 @@ def test_new_resolver_upgrade_same_version(script):
|
|||
"pkg",
|
||||
)
|
||||
assert_installed(script, pkg="2")
|
||||
|
||||
|
||||
def test_new_resolver_local_and_req(script):
|
||||
source_dir = create_test_package_with_setup(
|
||||
script,
|
||||
name="pkg",
|
||||
version="0.1.0",
|
||||
)
|
||||
script.pip(
|
||||
"install", "--unstable-feature=resolver",
|
||||
"--no-cache-dir", "--no-index",
|
||||
source_dir, "pkg!=0.1.0",
|
||||
expect_error=True,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue