Skip to content

Commit 4bb29ac

Browse files
committed
Use lazy wheel to obtain dep info for new resolver
1 parent 8db4fc8 commit 4bb29ac

File tree

1 file changed

+50
-21
lines changed

1 file changed

+50
-21
lines changed

src/pip/_internal/resolution/resolvelib/candidates.py

+50-21
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import logging
22
import sys
33

4+
from pip._vendor.contextlib2 import suppress
45
from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet
56
from pip._vendor.packaging.utils import canonicalize_name
67
from pip._vendor.packaging.version import Version
78

89
from pip._internal.exceptions import HashError, MetadataInconsistent
10+
from pip._internal.network.lazy_wheel import dist_from_wheel_url
911
from pip._internal.req.constructors import (
1012
install_req_from_editable,
1113
install_req_from_line,
1214
)
1315
from pip._internal.req.req_install import InstallRequirement
16+
from pip._internal.utils.logging import indent_log
1417
from pip._internal.utils.misc import normalize_version_info
1518
from pip._internal.utils.packaging import get_requires_python
1619
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@@ -197,6 +200,18 @@ def _prepare_abstract_distribution(self):
197200
# type: () -> AbstractDistribution
198201
raise NotImplementedError("Override in subclass")
199202

203+
def _check_metadata_consistency(self, dist):
204+
# type: (Distribution) -> None
205+
"""Check for consistency of project name and version of dist."""
206+
# TODO: (Longer term) Rather than abort, reject this candidate
207+
# and backtrack. This would need resolvelib support.
208+
name = canonicalize_name(dist.project_name)
209+
if self._name is not None and self._name != name:
210+
raise MetadataInconsistent(self._ireq, "name", dist.project_name)
211+
version = dist.parsed_version
212+
if self._version is not None and self._version != version:
213+
raise MetadataInconsistent(self._ireq, "version", dist.version)
214+
200215
def _prepare(self):
201216
# type: () -> None
202217
if self._dist is not None:
@@ -210,50 +225,43 @@ def _prepare(self):
210225

211226
self._dist = abstract_dist.get_pkg_resources_distribution()
212227
assert self._dist is not None, "Distribution already installed"
213-
214-
# TODO: (Longer term) Rather than abort, reject this candidate
215-
# and backtrack. This would need resolvelib support.
216-
name = canonicalize_name(self._dist.project_name)
217-
if self._name is not None and self._name != name:
218-
raise MetadataInconsistent(
219-
self._ireq, "name", self._dist.project_name,
220-
)
221-
version = self._dist.parsed_version
222-
if self._version is not None and self._version != version:
223-
raise MetadataInconsistent(
224-
self._ireq, "version", self._dist.version,
225-
)
228+
self._check_metadata_consistency(self._dist)
226229

227230
@property
228231
def dist(self):
229232
# type: () -> Distribution
230233
self._prepare()
231234
return self._dist
232235

233-
def _get_requires_python_specifier(self):
234-
# type: () -> Optional[SpecifierSet]
235-
requires_python = get_requires_python(self.dist)
236+
def _get_requires_python_specifier(self, dist):
237+
# type: (Distribution) -> Optional[SpecifierSet]
238+
requires_python = get_requires_python(dist)
236239
if requires_python is None:
237240
return None
238241
try:
239242
spec = SpecifierSet(requires_python)
240243
except InvalidSpecifier as e:
244+
name = canonicalize_name(dist.project_name)
241245
logger.warning(
242-
"Package %r has an invalid Requires-Python: %s", self.name, e,
246+
"Package %r has an invalid Requires-Python: %s", name, e,
243247
)
244248
return None
245249
return spec
246250

247-
def iter_dependencies(self):
248-
# type: () -> Iterable[Optional[Requirement]]
249-
for r in self.dist.requires():
251+
def _iter_dependencies(self, dist):
252+
# type: (Distribution) -> Iterable[Optional[Requirement]]
253+
for r in dist.requires():
250254
yield self._factory.make_requirement_from_spec(str(r), self._ireq)
251255
python_dep = self._factory.make_requires_python_requirement(
252-
self._get_requires_python_specifier(),
256+
self._get_requires_python_specifier(dist),
253257
)
254258
if python_dep:
255259
yield python_dep
256260

261+
def iter_dependencies(self):
262+
# type: () -> Iterable[Optional[Requirement]]
263+
return self._iter_dependencies(self.dist)
264+
257265
def get_install_requirement(self):
258266
# type: () -> Optional[InstallRequirement]
259267
self._prepare()
@@ -291,6 +299,27 @@ def __init__(
291299
version=version,
292300
)
293301

302+
def iter_dependencies(self):
303+
# type: () -> Iterable[Optional[Requirement]]
304+
dist = None # type: Optional[Distribution]
305+
preparer, req = self._factory.preparer, self._ireq
306+
remote_wheel = self._link.is_wheel and not self._link.is_file
307+
# TODO: Opt-in as unstable feature.
308+
if remote_wheel and not preparer.require_hashes:
309+
assert self._name is not None
310+
logger.info('Collecting %s', req.req or req)
311+
# If RuntimeError is raised, fallback to self.dist.
312+
with indent_log(), suppress(RuntimeError):
313+
logger.info(
314+
'Obtaining dependency information from %s %s',
315+
self._name, self._version,
316+
)
317+
url = self._link.url.split('#', 1)[0]
318+
session = preparer.downloader._session
319+
dist = dist_from_wheel_url(self._name, url, session)
320+
self._check_metadata_consistency(dist)
321+
return self._iter_dependencies(dist or self.dist)
322+
294323
def _prepare_abstract_distribution(self):
295324
# type: () -> AbstractDistribution
296325
return self._factory.preparer.prepare_linked_requirement(

0 commit comments

Comments
 (0)