Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/pip/_internal/operations/freeze.py
811 views
1
# The following comment should be removed at some point in the future.
2
# mypy: strict-optional=False
3
# mypy: disallow-untyped-defs=False
4
5
from __future__ import absolute_import
6
7
import collections
8
import logging
9
import os
10
11
from pip._vendor import six
12
from pip._vendor.packaging.utils import canonicalize_name
13
from pip._vendor.pkg_resources import RequirementParseError
14
15
from pip._internal.exceptions import BadCommand, InstallationError
16
from pip._internal.req.constructors import (
17
install_req_from_editable,
18
install_req_from_line,
19
)
20
from pip._internal.req.req_file import COMMENT_RE
21
from pip._internal.utils.direct_url_helpers import (
22
direct_url_as_pep440_direct_reference,
23
dist_get_direct_url,
24
)
25
from pip._internal.utils.misc import (
26
dist_is_editable,
27
get_installed_distributions,
28
)
29
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
30
31
if MYPY_CHECK_RUNNING:
32
from typing import (
33
Iterator, Optional, List, Container, Set, Dict, Tuple, Iterable, Union
34
)
35
from pip._internal.cache import WheelCache
36
from pip._vendor.pkg_resources import (
37
Distribution, Requirement
38
)
39
40
RequirementInfo = Tuple[Optional[Union[str, Requirement]], bool, List[str]]
41
42
43
logger = logging.getLogger(__name__)
44
45
46
def freeze(
47
requirement=None, # type: Optional[List[str]]
48
find_links=None, # type: Optional[List[str]]
49
local_only=None, # type: Optional[bool]
50
user_only=None, # type: Optional[bool]
51
paths=None, # type: Optional[List[str]]
52
isolated=False, # type: bool
53
wheel_cache=None, # type: Optional[WheelCache]
54
exclude_editable=False, # type: bool
55
skip=() # type: Container[str]
56
):
57
# type: (...) -> Iterator[str]
58
find_links = find_links or []
59
60
for link in find_links:
61
yield '-f {}'.format(link)
62
installations = {} # type: Dict[str, FrozenRequirement]
63
for dist in get_installed_distributions(local_only=local_only,
64
skip=(),
65
user_only=user_only,
66
paths=paths):
67
try:
68
req = FrozenRequirement.from_dist(dist)
69
except RequirementParseError as exc:
70
# We include dist rather than dist.project_name because the
71
# dist string includes more information, like the version and
72
# location. We also include the exception message to aid
73
# troubleshooting.
74
logger.warning(
75
'Could not generate requirement for distribution %r: %s',
76
dist, exc
77
)
78
continue
79
if exclude_editable and req.editable:
80
continue
81
installations[req.canonical_name] = req
82
83
if requirement:
84
# the options that don't get turned into an InstallRequirement
85
# should only be emitted once, even if the same option is in multiple
86
# requirements files, so we need to keep track of what has been emitted
87
# so that we don't emit it again if it's seen again
88
emitted_options = set() # type: Set[str]
89
# keep track of which files a requirement is in so that we can
90
# give an accurate warning if a requirement appears multiple times.
91
req_files = collections.defaultdict(list) # type: Dict[str, List[str]]
92
for req_file_path in requirement:
93
with open(req_file_path) as req_file:
94
for line in req_file:
95
if (not line.strip() or
96
line.strip().startswith('#') or
97
line.startswith((
98
'-r', '--requirement',
99
'-Z', '--always-unzip',
100
'-f', '--find-links',
101
'-i', '--index-url',
102
'--pre',
103
'--trusted-host',
104
'--process-dependency-links',
105
'--extra-index-url'))):
106
line = line.rstrip()
107
if line not in emitted_options:
108
emitted_options.add(line)
109
yield line
110
continue
111
112
if line.startswith('-e') or line.startswith('--editable'):
113
if line.startswith('-e'):
114
line = line[2:].strip()
115
else:
116
line = line[len('--editable'):].strip().lstrip('=')
117
line_req = install_req_from_editable(
118
line,
119
isolated=isolated,
120
)
121
else:
122
line_req = install_req_from_line(
123
COMMENT_RE.sub('', line).strip(),
124
isolated=isolated,
125
)
126
127
if not line_req.name:
128
logger.info(
129
"Skipping line in requirement file [%s] because "
130
"it's not clear what it would install: %s",
131
req_file_path, line.strip(),
132
)
133
logger.info(
134
" (add #egg=PackageName to the URL to avoid"
135
" this warning)"
136
)
137
else:
138
line_req_canonical_name = canonicalize_name(
139
line_req.name)
140
if line_req_canonical_name not in installations:
141
# either it's not installed, or it is installed
142
# but has been processed already
143
if not req_files[line_req.name]:
144
logger.warning(
145
"Requirement file [%s] contains %s, but "
146
"package %r is not installed",
147
req_file_path,
148
COMMENT_RE.sub('', line).strip(),
149
line_req.name
150
)
151
else:
152
req_files[line_req.name].append(req_file_path)
153
else:
154
yield str(installations[
155
line_req_canonical_name]).rstrip()
156
del installations[line_req_canonical_name]
157
req_files[line_req.name].append(req_file_path)
158
159
# Warn about requirements that were included multiple times (in a
160
# single requirements file or in different requirements files).
161
for name, files in six.iteritems(req_files):
162
if len(files) > 1:
163
logger.warning("Requirement %s included multiple times [%s]",
164
name, ', '.join(sorted(set(files))))
165
166
yield(
167
'## The following requirements were added by '
168
'pip freeze:'
169
)
170
for installation in sorted(
171
installations.values(), key=lambda x: x.name.lower()):
172
if installation.canonical_name not in skip:
173
yield str(installation).rstrip()
174
175
176
def get_requirement_info(dist):
177
# type: (Distribution) -> RequirementInfo
178
"""
179
Compute and return values (req, editable, comments) for use in
180
FrozenRequirement.from_dist().
181
"""
182
if not dist_is_editable(dist):
183
return (None, False, [])
184
185
location = os.path.normcase(os.path.abspath(dist.location))
186
187
from pip._internal.vcs import vcs, RemoteNotFoundError
188
vcs_backend = vcs.get_backend_for_dir(location)
189
190
if vcs_backend is None:
191
req = dist.as_requirement()
192
logger.debug(
193
'No VCS found for editable requirement "%s" in: %r', req,
194
location,
195
)
196
comments = [
197
'# Editable install with no version control ({})'.format(req)
198
]
199
return (location, True, comments)
200
201
try:
202
req = vcs_backend.get_src_requirement(location, dist.project_name)
203
except RemoteNotFoundError:
204
req = dist.as_requirement()
205
comments = [
206
'# Editable {} install with no remote ({})'.format(
207
type(vcs_backend).__name__, req,
208
)
209
]
210
return (location, True, comments)
211
212
except BadCommand:
213
logger.warning(
214
'cannot determine version of editable source in %s '
215
'(%s command not found in path)',
216
location,
217
vcs_backend.name,
218
)
219
return (None, True, [])
220
221
except InstallationError as exc:
222
logger.warning(
223
"Error when trying to get requirement for VCS system %s, "
224
"falling back to uneditable format", exc
225
)
226
else:
227
if req is not None:
228
return (req, True, [])
229
230
logger.warning(
231
'Could not determine repository location of %s', location
232
)
233
comments = ['## !! Could not determine repository location']
234
235
return (None, False, comments)
236
237
238
class FrozenRequirement(object):
239
def __init__(self, name, req, editable, comments=()):
240
# type: (str, Union[str, Requirement], bool, Iterable[str]) -> None
241
self.name = name
242
self.canonical_name = canonicalize_name(name)
243
self.req = req
244
self.editable = editable
245
self.comments = comments
246
247
@classmethod
248
def from_dist(cls, dist):
249
# type: (Distribution) -> FrozenRequirement
250
# TODO `get_requirement_info` is taking care of editable requirements.
251
# TODO This should be refactored when we will add detection of
252
# editable that provide .dist-info metadata.
253
req, editable, comments = get_requirement_info(dist)
254
if req is None and not editable:
255
# if PEP 610 metadata is present, attempt to use it
256
direct_url = dist_get_direct_url(dist)
257
if direct_url:
258
req = direct_url_as_pep440_direct_reference(
259
direct_url, dist.project_name
260
)
261
comments = []
262
if req is None:
263
# name==version requirement
264
req = dist.as_requirement()
265
266
return cls(dist.project_name, req, editable, comments=comments)
267
268
def __str__(self):
269
req = self.req
270
if self.editable:
271
req = '-e {}'.format(req)
272
return '\n'.join(list(self.comments) + [str(req)]) + '\n'
273
274