Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/pip/_internal/wheel_builder.py
811 views
1
"""Orchestrator for building wheels from InstallRequirements.
2
"""
3
4
# The following comment should be removed at some point in the future.
5
# mypy: strict-optional=False
6
7
import logging
8
import os.path
9
import re
10
import shutil
11
12
from pip._internal.models.link import Link
13
from pip._internal.operations.build.wheel import build_wheel_pep517
14
from pip._internal.operations.build.wheel_legacy import build_wheel_legacy
15
from pip._internal.utils.logging import indent_log
16
from pip._internal.utils.misc import ensure_dir, hash_file, is_wheel_installed
17
from pip._internal.utils.setuptools_build import make_setuptools_clean_args
18
from pip._internal.utils.subprocess import call_subprocess
19
from pip._internal.utils.temp_dir import TempDirectory
20
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
21
from pip._internal.utils.urls import path_to_url
22
from pip._internal.vcs import vcs
23
24
if MYPY_CHECK_RUNNING:
25
from typing import (
26
Any, Callable, Iterable, List, Optional, Pattern, Tuple,
27
)
28
29
from pip._internal.cache import WheelCache
30
from pip._internal.req.req_install import InstallRequirement
31
32
BinaryAllowedPredicate = Callable[[InstallRequirement], bool]
33
BuildResult = Tuple[List[InstallRequirement], List[InstallRequirement]]
34
35
logger = logging.getLogger(__name__)
36
37
38
def _contains_egg_info(
39
s, _egg_info_re=re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.I)):
40
# type: (str, Pattern[str]) -> bool
41
"""Determine whether the string looks like an egg_info.
42
43
:param s: The string to parse. E.g. foo-2.1
44
"""
45
return bool(_egg_info_re.search(s))
46
47
48
def _should_build(
49
req, # type: InstallRequirement
50
need_wheel, # type: bool
51
check_binary_allowed, # type: BinaryAllowedPredicate
52
):
53
# type: (...) -> bool
54
"""Return whether an InstallRequirement should be built into a wheel."""
55
if req.constraint:
56
# never build requirements that are merely constraints
57
return False
58
if req.is_wheel:
59
if need_wheel:
60
logger.info(
61
'Skipping %s, due to already being wheel.', req.name,
62
)
63
return False
64
65
if need_wheel:
66
# i.e. pip wheel, not pip install
67
return True
68
69
# From this point, this concerns the pip install command only
70
# (need_wheel=False).
71
72
if req.editable or not req.source_dir:
73
return False
74
75
if not check_binary_allowed(req):
76
logger.info(
77
"Skipping wheel build for %s, due to binaries "
78
"being disabled for it.", req.name,
79
)
80
return False
81
82
if not req.use_pep517 and not is_wheel_installed():
83
# we don't build legacy requirements if wheel is not installed
84
logger.info(
85
"Using legacy setup.py install for %s, "
86
"since package 'wheel' is not installed.", req.name,
87
)
88
return False
89
90
return True
91
92
93
def should_build_for_wheel_command(
94
req, # type: InstallRequirement
95
):
96
# type: (...) -> bool
97
return _should_build(
98
req, need_wheel=True, check_binary_allowed=_always_true
99
)
100
101
102
def should_build_for_install_command(
103
req, # type: InstallRequirement
104
check_binary_allowed, # type: BinaryAllowedPredicate
105
):
106
# type: (...) -> bool
107
return _should_build(
108
req, need_wheel=False, check_binary_allowed=check_binary_allowed
109
)
110
111
112
def _should_cache(
113
req, # type: InstallRequirement
114
):
115
# type: (...) -> Optional[bool]
116
"""
117
Return whether a built InstallRequirement can be stored in the persistent
118
wheel cache, assuming the wheel cache is available, and _should_build()
119
has determined a wheel needs to be built.
120
"""
121
if not should_build_for_install_command(
122
req, check_binary_allowed=_always_true
123
):
124
# never cache if pip install would not have built
125
# (editable mode, etc)
126
return False
127
128
if req.link and req.link.is_vcs:
129
# VCS checkout. Do not cache
130
# unless it points to an immutable commit hash.
131
assert not req.editable
132
assert req.source_dir
133
vcs_backend = vcs.get_backend_for_scheme(req.link.scheme)
134
assert vcs_backend
135
if vcs_backend.is_immutable_rev_checkout(req.link.url, req.source_dir):
136
return True
137
return False
138
139
base, ext = req.link.splitext()
140
if _contains_egg_info(base):
141
return True
142
143
# Otherwise, do not cache.
144
return False
145
146
147
def _get_cache_dir(
148
req, # type: InstallRequirement
149
wheel_cache, # type: WheelCache
150
):
151
# type: (...) -> str
152
"""Return the persistent or temporary cache directory where the built
153
wheel need to be stored.
154
"""
155
cache_available = bool(wheel_cache.cache_dir)
156
if cache_available and _should_cache(req):
157
cache_dir = wheel_cache.get_path_for_link(req.link)
158
else:
159
cache_dir = wheel_cache.get_ephem_path_for_link(req.link)
160
return cache_dir
161
162
163
def _always_true(_):
164
# type: (Any) -> bool
165
return True
166
167
168
def _build_one(
169
req, # type: InstallRequirement
170
output_dir, # type: str
171
build_options, # type: List[str]
172
global_options, # type: List[str]
173
):
174
# type: (...) -> Optional[str]
175
"""Build one wheel.
176
177
:return: The filename of the built wheel, or None if the build failed.
178
"""
179
try:
180
ensure_dir(output_dir)
181
except OSError as e:
182
logger.warning(
183
"Building wheel for %s failed: %s",
184
req.name, e,
185
)
186
return None
187
188
# Install build deps into temporary directory (PEP 518)
189
with req.build_env:
190
return _build_one_inside_env(
191
req, output_dir, build_options, global_options
192
)
193
194
195
def _build_one_inside_env(
196
req, # type: InstallRequirement
197
output_dir, # type: str
198
build_options, # type: List[str]
199
global_options, # type: List[str]
200
):
201
# type: (...) -> Optional[str]
202
with TempDirectory(kind="wheel") as temp_dir:
203
if req.use_pep517:
204
wheel_path = build_wheel_pep517(
205
name=req.name,
206
backend=req.pep517_backend,
207
metadata_directory=req.metadata_directory,
208
build_options=build_options,
209
tempd=temp_dir.path,
210
)
211
else:
212
wheel_path = build_wheel_legacy(
213
name=req.name,
214
setup_py_path=req.setup_py_path,
215
source_dir=req.unpacked_source_directory,
216
global_options=global_options,
217
build_options=build_options,
218
tempd=temp_dir.path,
219
)
220
221
if wheel_path is not None:
222
wheel_name = os.path.basename(wheel_path)
223
dest_path = os.path.join(output_dir, wheel_name)
224
try:
225
wheel_hash, length = hash_file(wheel_path)
226
shutil.move(wheel_path, dest_path)
227
logger.info('Created wheel for %s: '
228
'filename=%s size=%d sha256=%s',
229
req.name, wheel_name, length,
230
wheel_hash.hexdigest())
231
logger.info('Stored in directory: %s', output_dir)
232
return dest_path
233
except Exception as e:
234
logger.warning(
235
"Building wheel for %s failed: %s",
236
req.name, e,
237
)
238
# Ignore return, we can't do anything else useful.
239
if not req.use_pep517:
240
_clean_one_legacy(req, global_options)
241
return None
242
243
244
def _clean_one_legacy(req, global_options):
245
# type: (InstallRequirement, List[str]) -> bool
246
clean_args = make_setuptools_clean_args(
247
req.setup_py_path,
248
global_options=global_options,
249
)
250
251
logger.info('Running setup.py clean for %s', req.name)
252
try:
253
call_subprocess(clean_args, cwd=req.source_dir)
254
return True
255
except Exception:
256
logger.error('Failed cleaning build dir for %s', req.name)
257
return False
258
259
260
def build(
261
requirements, # type: Iterable[InstallRequirement]
262
wheel_cache, # type: WheelCache
263
build_options, # type: List[str]
264
global_options, # type: List[str]
265
):
266
# type: (...) -> BuildResult
267
"""Build wheels.
268
269
:return: The list of InstallRequirement that succeeded to build and
270
the list of InstallRequirement that failed to build.
271
"""
272
if not requirements:
273
return [], []
274
275
# Build the wheels.
276
logger.info(
277
'Building wheels for collected packages: %s',
278
', '.join(req.name for req in requirements),
279
)
280
281
with indent_log():
282
build_successes, build_failures = [], []
283
for req in requirements:
284
cache_dir = _get_cache_dir(req, wheel_cache)
285
wheel_file = _build_one(
286
req, cache_dir, build_options, global_options
287
)
288
if wheel_file:
289
# Update the link for this.
290
req.link = Link(path_to_url(wheel_file))
291
req.local_file_path = req.link.file_path
292
assert req.link.is_wheel
293
build_successes.append(req)
294
else:
295
build_failures.append(req)
296
297
# notify success/failure
298
if build_successes:
299
logger.info(
300
'Successfully built %s',
301
' '.join([req.name for req in build_successes]),
302
)
303
if build_failures:
304
logger.info(
305
'Failed to build %s',
306
' '.join([req.name for req in build_failures]),
307
)
308
# Return a list of requirements that failed to build
309
return build_successes, build_failures
310
311