From ffe553638c035292e17657cbacbfb48e189a9221 Mon Sep 17 00:00:00 2001
From: Paul Moore
Date: Thu, 19 Mar 2020 10:53:15 +0000
Subject: [PATCH] Address review requirements
---
.../resolution/resolvelib/candidates.py | 18 +++++++++++++++---
.../resolution/resolvelib/provider.py | 8 ++++++++
.../resolution/resolvelib/requirements.py | 1 +
3 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/src/pip/_internal/resolution/resolvelib/candidates.py b/src/pip/_internal/resolution/resolvelib/candidates.py
index a8e1aa903..08eff0ddf 100644
--- a/src/pip/_internal/resolution/resolvelib/candidates.py
+++ b/src/pip/_internal/resolution/resolvelib/candidates.py
@@ -7,7 +7,7 @@ from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from .base import Candidate
if MYPY_CHECK_RUNNING:
- from typing import Dict, Optional, Sequence
+ from typing import Any, Dict, Optional, Sequence
from pip._internal.models.link import Link
from pip._internal.operations.prepare import RequirementPreparer
@@ -17,7 +17,6 @@ if MYPY_CHECK_RUNNING:
from pip._vendor.pkg_resources import Distribution
-# Dummy to make lint pass
_CANDIDATE_CACHE = {} # type: Dict[Link, Candidate]
@@ -74,9 +73,21 @@ class LinkCandidate(Candidate):
self._version = None # type: Optional[_BaseVersion]
self._dist = None # type: Optional[Distribution]
+ def __eq__(self, other):
+ # type: (Any) -> bool
+ if isinstance(other, self.__class__):
+ return self.link == other.link
+ return False
+
+ # Needed for Python 2, which does not implement this by default
+ def __ne__(self, other):
+ # type: (Any) -> bool
+ return not self.__eq__(other)
+
@property
def name(self):
# type: () -> str
+ """The normalised name of the project the candidate refers to"""
if self._name is None:
self._name = canonicalize_name(self.dist.project_name)
return self._name
@@ -101,7 +112,8 @@ class LinkCandidate(Candidate):
# These should be "proper" errors, not just asserts, as they
# can result from user errors like a requirement "foo @ URL"
# when the project at URL has a name of "bar" in its metadata.
- assert self._name is None or self._name == self._dist.project_name
+ assert (self._name is None or
+ self._name == canonicalize_name(self._dist.project_name))
assert (self._version is None or
self._version == self.dist.parsed_version)
return self._dist
diff --git a/src/pip/_internal/resolution/resolvelib/provider.py b/src/pip/_internal/resolution/resolvelib/provider.py
index 21c3ecbb6..981646ea9 100644
--- a/src/pip/_internal/resolution/resolvelib/provider.py
+++ b/src/pip/_internal/resolution/resolvelib/provider.py
@@ -38,6 +38,14 @@ class PipProvider(AbstractProvider):
def get_install_requirement(self, c):
# type: (Candidate) -> InstallRequirement
+
+ # The base Candidate class does not have an _ireq attribute, so we
+ # fetch it dynamically here, to satisfy mypy. In practice, though, we
+ # only ever deal with LinkedCandidate objects at the moment, which do
+ # have an _ireq attribute. When we have a candidate type for installed
+ # requirements we should probably review this.
+ #
+ # TODO: Longer term, make a proper interface for this on the candidate.
return getattr(c, "_ireq", None)
def identify(self, dependency):
diff --git a/src/pip/_internal/resolution/resolvelib/requirements.py b/src/pip/_internal/resolution/resolvelib/requirements.py
index d5965e3e1..4adc8a09a 100644
--- a/src/pip/_internal/resolution/resolvelib/requirements.py
+++ b/src/pip/_internal/resolution/resolvelib/requirements.py
@@ -48,6 +48,7 @@ class ExplicitRequirement(Requirement):
@property
def name(self):
# type: () -> str
+ # No need to canonicalise - the candidate did this
return self.candidate.name
def find_matches(self):