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