1
1
import logging
2
2
import sys
3
3
4
+ from pip ._vendor .contextlib2 import suppress
4
5
from pip ._vendor .packaging .specifiers import InvalidSpecifier , SpecifierSet
5
6
from pip ._vendor .packaging .utils import canonicalize_name
6
7
from pip ._vendor .packaging .version import Version
7
8
8
9
from pip ._internal .exceptions import HashError , MetadataInconsistent
10
+ from pip ._internal .network .lazy_wheel import dist_from_wheel_url
9
11
from pip ._internal .req .constructors import (
10
12
install_req_from_editable ,
11
13
install_req_from_line ,
12
14
)
13
15
from pip ._internal .req .req_install import InstallRequirement
16
+ from pip ._internal .utils .logging import indent_log
14
17
from pip ._internal .utils .misc import dist_is_editable , normalize_version_info
15
18
from pip ._internal .utils .packaging import get_requires_python
16
19
from pip ._internal .utils .typing import MYPY_CHECK_RUNNING
@@ -142,6 +145,7 @@ def __init__(
142
145
self ._name = name
143
146
self ._version = version
144
147
self ._dist = None # type: Optional[Distribution]
148
+ self ._prepared = False
145
149
146
150
def __repr__ (self ):
147
151
# type: () -> str
@@ -197,11 +201,23 @@ def _prepare_abstract_distribution(self):
197
201
# type: () -> AbstractDistribution
198
202
raise NotImplementedError ("Override in subclass" )
199
203
204
+ def _check_metadata_consistency (self ):
205
+ # type: () -> None
206
+ """Check for consistency of project name and version of dist."""
207
+ # TODO: (Longer term) Rather than abort, reject this candidate
208
+ # and backtrack. This would need resolvelib support.
209
+ dist = self ._dist # type: Distribution
210
+ name = canonicalize_name (dist .project_name )
211
+ if self ._name is not None and self ._name != name :
212
+ raise MetadataInconsistent (self ._ireq , "name" , dist .project_name )
213
+ version = dist .parsed_version
214
+ if self ._version is not None and self ._version != version :
215
+ raise MetadataInconsistent (self ._ireq , "version" , dist .version )
216
+
200
217
def _prepare (self ):
201
218
# type: () -> None
202
- if self ._dist is not None :
219
+ if self ._prepared :
203
220
return
204
-
205
221
try :
206
222
abstract_dist = self ._prepare_abstract_distribution ()
207
223
except HashError as e :
@@ -210,24 +226,37 @@ def _prepare(self):
210
226
211
227
self ._dist = abstract_dist .get_pkg_resources_distribution ()
212
228
assert self ._dist is not None , "Distribution already installed"
229
+ self ._check_metadata_consistency ()
230
+ self ._prepared = True
213
231
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
- )
232
+ def _fetch_metadata (self ):
233
+ # type: () -> None
234
+ """Fetch metadata, using lazy wheel if possible."""
235
+ preparer = self ._factory .preparer
236
+ use_lazy_wheel = self ._factory .use_lazy_wheel
237
+ remote_wheel = self ._link .is_wheel and not self ._link .is_file
238
+ if use_lazy_wheel and remote_wheel and not preparer .require_hashes :
239
+ assert self ._name is not None
240
+ logger .info ('Collecting %s' , self ._ireq .req or self ._ireq )
241
+ # TODO: Rename to HTTPRangeRequestUnsupported (GH-8584)
242
+ # If RuntimeError is raised, fallback to self._prepare
243
+ with indent_log (), suppress (RuntimeError ):
244
+ logger .info (
245
+ 'Obtaining dependency information from %s %s' ,
246
+ self ._name , self ._version ,
247
+ )
248
+ url = self ._link .url .split ('#' , 1 )[0 ]
249
+ session = preparer .downloader ._session
250
+ self ._dist = dist_from_wheel_url (self ._name , url , session )
251
+ self ._check_metadata_consistency ()
252
+ if self ._dist is None :
253
+ self ._prepare ()
226
254
227
255
@property
228
256
def dist (self ):
229
257
# type: () -> Distribution
230
- self ._prepare ()
258
+ if self ._dist is None :
259
+ self ._fetch_metadata ()
231
260
return self ._dist
232
261
233
262
def _get_requires_python_specifier (self ):
0 commit comments