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