7
7
Iterable ,
8
8
Iterator ,
9
9
List ,
10
+ NamedTuple ,
10
11
Optional ,
11
12
Set ,
12
- Tuple ,
13
13
Union ,
14
14
)
15
15
16
+ from pip ._vendor .packaging .requirements import Requirement
16
17
from pip ._vendor .packaging .utils import canonicalize_name
17
- from pip ._vendor .pkg_resources import Distribution , Requirement , RequirementParseError
18
+ from pip ._vendor .packaging . version import Version
18
19
19
20
from pip ._internal .exceptions import BadCommand , InstallationError
21
+ from pip ._internal .metadata import BaseDistribution , get_environment
20
22
from pip ._internal .req .constructors import (
21
23
install_req_from_editable ,
22
24
install_req_from_line ,
23
25
)
24
26
from pip ._internal .req .req_file import COMMENT_RE
25
- from pip ._internal .utils .direct_url_helpers import (
26
- direct_url_as_pep440_direct_reference ,
27
- dist_get_direct_url ,
28
- )
29
- from pip ._internal .utils .misc import dist_is_editable , get_installed_distributions
27
+ from pip ._internal .utils .direct_url_helpers import direct_url_as_pep440_direct_reference
30
28
31
29
logger = logging .getLogger (__name__ )
32
30
33
- RequirementInfo = Tuple [Optional [Union [str , Requirement ]], bool , List [str ]]
31
+
32
+ class _EditableInfo (NamedTuple ):
33
+ requirement : Optional [str ]
34
+ editable : bool
35
+ comments : List [str ]
34
36
35
37
36
38
def freeze (
@@ -45,24 +47,13 @@ def freeze(
45
47
# type: (...) -> Iterator[str]
46
48
installations = {} # type: Dict[str, FrozenRequirement]
47
49
48
- for dist in get_installed_distributions (
49
- local_only = local_only ,
50
- skip = (),
51
- user_only = user_only ,
52
- paths = paths
53
- ):
54
- try :
55
- req = FrozenRequirement .from_dist (dist )
56
- except RequirementParseError as exc :
57
- # We include dist rather than dist.project_name because the
58
- # dist string includes more information, like the version and
59
- # location. We also include the exception message to aid
60
- # troubleshooting.
61
- logger .warning (
62
- 'Could not generate requirement for distribution %r: %s' ,
63
- dist , exc
64
- )
65
- continue
50
+ dists = get_environment (paths ).iter_installed_distributions (
51
+ local_only = local_only ,
52
+ skip = (),
53
+ user_only = user_only ,
54
+ )
55
+ for dist in dists :
56
+ req = FrozenRequirement .from_dist (dist )
66
57
if exclude_editable and req .editable :
67
58
continue
68
59
installations [req .canonical_name ] = req
@@ -160,49 +151,68 @@ def freeze(
160
151
yield str (installation ).rstrip ()
161
152
162
153
163
- def get_requirement_info (dist ):
164
- # type: (Distribution) -> RequirementInfo
154
+ def _format_as_name_version (dist : BaseDistribution ) -> str :
155
+ if isinstance (dist .version , Version ):
156
+ return f"{ dist .raw_name } =={ dist .version } "
157
+ return f"{ dist .raw_name } ==={ dist .version } "
158
+
159
+
160
+ def _get_editable_info (dist : BaseDistribution ) -> _EditableInfo :
165
161
"""
166
162
Compute and return values (req, editable, comments) for use in
167
163
FrozenRequirement.from_dist().
168
164
"""
169
- if not dist_is_editable (dist ):
170
- return (None , False , [])
165
+ if not dist .editable :
166
+ return _EditableInfo (requirement = None , editable = False , comments = [])
167
+ if dist .location is None :
168
+ display = _format_as_name_version (dist )
169
+ logger .warning ("Editable requirement not found on disk: %s" , display )
170
+ return _EditableInfo (
171
+ requirement = None ,
172
+ editable = True ,
173
+ comments = [f"# Editable install not found ({ display } )" ],
174
+ )
171
175
172
176
location = os .path .normcase (os .path .abspath (dist .location ))
173
177
174
178
from pip ._internal .vcs import RemoteNotFoundError , RemoteNotValidError , vcs
179
+
175
180
vcs_backend = vcs .get_backend_for_dir (location )
176
181
177
182
if vcs_backend is None :
178
- req = dist . as_requirement ( )
183
+ display = _format_as_name_version ( dist )
179
184
logger .debug (
180
- 'No VCS found for editable requirement "%s" in: %r' , req ,
185
+ 'No VCS found for editable requirement "%s" in: %r' , display ,
181
186
location ,
182
187
)
183
- comments = [
184
- f'# Editable install with no version control ({ req } )'
185
- ]
186
- return (location , True , comments )
188
+ return _EditableInfo (
189
+ requirement = location ,
190
+ editable = True ,
191
+ comments = [f'# Editable install with no version control ({ display } )' ],
192
+ )
193
+
194
+ vcs_name = type (vcs_backend ).__name__
187
195
188
196
try :
189
- req = vcs_backend .get_src_requirement (location , dist .project_name )
197
+ req = vcs_backend .get_src_requirement (location , dist .raw_name )
190
198
except RemoteNotFoundError :
191
- req = dist .as_requirement ()
192
- comments = [
193
- '# Editable {} install with no remote ({})' .format (
194
- type (vcs_backend ).__name__ , req ,
195
- )
196
- ]
197
- return (location , True , comments )
199
+ display = _format_as_name_version (dist )
200
+ return _EditableInfo (
201
+ requirement = location ,
202
+ editable = True ,
203
+ comments = [f'# Editable { vcs_name } install with no remote ({ display } )' ],
204
+ )
198
205
except RemoteNotValidError as ex :
199
- req = dist .as_requirement ()
200
- comments = [
201
- f"# Editable { type (vcs_backend ).__name__ } install ({ req } ) with "
202
- f"either a deleted local remote or invalid URI:" ,
203
- f"# '{ ex .url } '" ,
204
- ]
205
- return (location , True , comments )
206
+ display = _format_as_name_version (dist )
207
+ return _EditableInfo (
208
+ requirement = location ,
209
+ editable = True ,
210
+ comments = [
211
+ f"# Editable { vcs_name } install ({ display } ) with either a deleted "
212
+ f"local remote or invalid URI:" ,
213
+ f"# '{ ex .url } '" ,
214
+ ],
215
+ )
206
216
207
217
except BadCommand :
208
218
logger .warning (
@@ -211,22 +221,23 @@ def get_requirement_info(dist):
211
221
location ,
212
222
vcs_backend .name ,
213
223
)
214
- return ( None , True , [])
224
+ return _EditableInfo ( requirement = None , editable = True , comments = [])
215
225
216
226
except InstallationError as exc :
217
227
logger .warning (
218
228
"Error when trying to get requirement for VCS system %s, "
219
229
"falling back to uneditable format" , exc
220
230
)
221
231
else :
222
- return ( req , True , [])
232
+ return _EditableInfo ( requirement = req , editable = True , comments = [])
223
233
224
- logger .warning (
225
- 'Could not determine repository location of %s' , location
226
- )
227
- comments = ['## !! Could not determine repository location' ]
234
+ logger .warning ('Could not determine repository location of %s' , location )
228
235
229
- return (None , False , comments )
236
+ return _EditableInfo (
237
+ requirement = None ,
238
+ editable = False ,
239
+ comments = ['## !! Could not determine repository location' ],
240
+ )
230
241
231
242
232
243
class FrozenRequirement :
@@ -239,25 +250,24 @@ def __init__(self, name, req, editable, comments=()):
239
250
self .comments = comments
240
251
241
252
@classmethod
242
- def from_dist (cls , dist ):
243
- # type: (Distribution) -> FrozenRequirement
253
+ def from_dist (cls , dist : BaseDistribution ) -> "FrozenRequirement" :
244
254
# TODO `get_requirement_info` is taking care of editable requirements.
245
255
# TODO This should be refactored when we will add detection of
246
256
# editable that provide .dist-info metadata.
247
- req , editable , comments = get_requirement_info (dist )
257
+ req , editable , comments = _get_editable_info (dist )
248
258
if req is None and not editable :
249
259
# if PEP 610 metadata is present, attempt to use it
250
- direct_url = dist_get_direct_url ( dist )
260
+ direct_url = dist . direct_url
251
261
if direct_url :
252
262
req = direct_url_as_pep440_direct_reference (
253
- direct_url , dist .project_name
263
+ direct_url , dist .raw_name
254
264
)
255
265
comments = []
256
266
if req is None :
257
267
# name==version requirement
258
- req = dist . as_requirement ( )
268
+ req = _format_as_name_version ( dist )
259
269
260
- return cls (dist .project_name , req , editable , comments = comments )
270
+ return cls (dist .raw_name , req , editable , comments = comments )
261
271
262
272
def __str__ (self ):
263
273
# type: () -> str
0 commit comments