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/setuptools/build_meta.py
4798 views
1
"""A PEP 517 interface to setuptools
2
3
Previously, when a user or a command line tool (let's call it a "frontend")
4
needed to make a request of setuptools to take a certain action, for
5
example, generating a list of installation requirements, the frontend would
6
would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line.
7
8
PEP 517 defines a different method of interfacing with setuptools. Rather
9
than calling "setup.py" directly, the frontend should:
10
11
1. Set the current directory to the directory with a setup.py file
12
2. Import this module into a safe python interpreter (one in which
13
setuptools can potentially set global variables or crash hard).
14
3. Call one of the functions defined in PEP 517.
15
16
What each function does is defined in PEP 517. However, here is a "casual"
17
definition of the functions (this definition should not be relied on for
18
bug reports or API stability):
19
20
- `build_wheel`: build a wheel in the folder and return the basename
21
- `get_requires_for_build_wheel`: get the `setup_requires` to build
22
- `prepare_metadata_for_build_wheel`: get the `install_requires`
23
- `build_sdist`: build an sdist in the folder and return the basename
24
- `get_requires_for_build_sdist`: get the `setup_requires` to build
25
26
Again, this is not a formal definition! Just a "taste" of the module.
27
"""
28
29
import io
30
import os
31
import sys
32
import tokenize
33
import shutil
34
import contextlib
35
import tempfile
36
import warnings
37
38
import setuptools
39
import distutils
40
from ._reqs import parse_strings
41
from .extern.more_itertools import always_iterable
42
43
44
__all__ = ['get_requires_for_build_sdist',
45
'get_requires_for_build_wheel',
46
'prepare_metadata_for_build_wheel',
47
'build_wheel',
48
'build_sdist',
49
'__legacy__',
50
'SetupRequirementsError']
51
52
53
class SetupRequirementsError(BaseException):
54
def __init__(self, specifiers):
55
self.specifiers = specifiers
56
57
58
class Distribution(setuptools.dist.Distribution):
59
def fetch_build_eggs(self, specifiers):
60
specifier_list = list(parse_strings(specifiers))
61
62
raise SetupRequirementsError(specifier_list)
63
64
@classmethod
65
@contextlib.contextmanager
66
def patch(cls):
67
"""
68
Replace
69
distutils.dist.Distribution with this class
70
for the duration of this context.
71
"""
72
orig = distutils.core.Distribution
73
distutils.core.Distribution = cls
74
try:
75
yield
76
finally:
77
distutils.core.Distribution = orig
78
79
80
@contextlib.contextmanager
81
def no_install_setup_requires():
82
"""Temporarily disable installing setup_requires
83
84
Under PEP 517, the backend reports build dependencies to the frontend,
85
and the frontend is responsible for ensuring they're installed.
86
So setuptools (acting as a backend) should not try to install them.
87
"""
88
orig = setuptools._install_setup_requires
89
setuptools._install_setup_requires = lambda attrs: None
90
try:
91
yield
92
finally:
93
setuptools._install_setup_requires = orig
94
95
96
def _get_immediate_subdirectories(a_dir):
97
return [name for name in os.listdir(a_dir)
98
if os.path.isdir(os.path.join(a_dir, name))]
99
100
101
def _file_with_extension(directory, extension):
102
matching = (
103
f for f in os.listdir(directory)
104
if f.endswith(extension)
105
)
106
try:
107
file, = matching
108
except ValueError:
109
raise ValueError(
110
'No distribution was found. Ensure that `setup.py` '
111
'is not empty and that it calls `setup()`.')
112
return file
113
114
115
def _open_setup_script(setup_script):
116
if not os.path.exists(setup_script):
117
# Supply a default setup.py
118
return io.StringIO(u"from setuptools import setup; setup()")
119
120
return getattr(tokenize, 'open', open)(setup_script)
121
122
123
@contextlib.contextmanager
124
def suppress_known_deprecation():
125
with warnings.catch_warnings():
126
warnings.filterwarnings('ignore', 'setup.py install is deprecated')
127
yield
128
129
130
class _BuildMetaBackend:
131
132
@staticmethod
133
def _fix_config(config_settings):
134
"""
135
Ensure config settings meet certain expectations.
136
137
>>> fc = _BuildMetaBackend._fix_config
138
>>> fc(None)
139
{'--global-option': []}
140
>>> fc({})
141
{'--global-option': []}
142
>>> fc({'--global-option': 'foo'})
143
{'--global-option': ['foo']}
144
>>> fc({'--global-option': ['foo']})
145
{'--global-option': ['foo']}
146
"""
147
config_settings = config_settings or {}
148
config_settings['--global-option'] = list(always_iterable(
149
config_settings.get('--global-option')))
150
return config_settings
151
152
def _get_build_requires(self, config_settings, requirements):
153
config_settings = self._fix_config(config_settings)
154
155
sys.argv = sys.argv[:1] + ['egg_info'] + \
156
config_settings["--global-option"]
157
try:
158
with Distribution.patch():
159
self.run_setup()
160
except SetupRequirementsError as e:
161
requirements += e.specifiers
162
163
return requirements
164
165
def run_setup(self, setup_script='setup.py'):
166
# Note that we can reuse our build directory between calls
167
# Correctness comes first, then optimization later
168
__file__ = setup_script
169
__name__ = '__main__'
170
171
with _open_setup_script(__file__) as f:
172
code = f.read().replace(r'\r\n', r'\n')
173
174
exec(compile(code, __file__, 'exec'), locals())
175
176
def get_requires_for_build_wheel(self, config_settings=None):
177
return self._get_build_requires(
178
config_settings, requirements=['wheel'])
179
180
def get_requires_for_build_sdist(self, config_settings=None):
181
return self._get_build_requires(config_settings, requirements=[])
182
183
def prepare_metadata_for_build_wheel(self, metadata_directory,
184
config_settings=None):
185
sys.argv = sys.argv[:1] + [
186
'dist_info', '--egg-base', metadata_directory]
187
with no_install_setup_requires():
188
self.run_setup()
189
190
dist_info_directory = metadata_directory
191
while True:
192
dist_infos = [f for f in os.listdir(dist_info_directory)
193
if f.endswith('.dist-info')]
194
195
if (
196
len(dist_infos) == 0 and
197
len(_get_immediate_subdirectories(dist_info_directory)) == 1
198
):
199
200
dist_info_directory = os.path.join(
201
dist_info_directory, os.listdir(dist_info_directory)[0])
202
continue
203
204
assert len(dist_infos) == 1
205
break
206
207
# PEP 517 requires that the .dist-info directory be placed in the
208
# metadata_directory. To comply, we MUST copy the directory to the root
209
if dist_info_directory != metadata_directory:
210
shutil.move(
211
os.path.join(dist_info_directory, dist_infos[0]),
212
metadata_directory)
213
shutil.rmtree(dist_info_directory, ignore_errors=True)
214
215
return dist_infos[0]
216
217
def _build_with_temp_dir(self, setup_command, result_extension,
218
result_directory, config_settings):
219
config_settings = self._fix_config(config_settings)
220
result_directory = os.path.abspath(result_directory)
221
222
# Build in a temporary directory, then copy to the target.
223
os.makedirs(result_directory, exist_ok=True)
224
with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir:
225
sys.argv = (sys.argv[:1] + setup_command +
226
['--dist-dir', tmp_dist_dir] +
227
config_settings["--global-option"])
228
with no_install_setup_requires():
229
self.run_setup()
230
231
result_basename = _file_with_extension(
232
tmp_dist_dir, result_extension)
233
result_path = os.path.join(result_directory, result_basename)
234
if os.path.exists(result_path):
235
# os.rename will fail overwriting on non-Unix.
236
os.remove(result_path)
237
os.rename(os.path.join(tmp_dist_dir, result_basename), result_path)
238
239
return result_basename
240
241
def build_wheel(self, wheel_directory, config_settings=None,
242
metadata_directory=None):
243
with suppress_known_deprecation():
244
return self._build_with_temp_dir(['bdist_wheel'], '.whl',
245
wheel_directory, config_settings)
246
247
def build_sdist(self, sdist_directory, config_settings=None):
248
return self._build_with_temp_dir(['sdist', '--formats', 'gztar'],
249
'.tar.gz', sdist_directory,
250
config_settings)
251
252
253
class _BuildMetaLegacyBackend(_BuildMetaBackend):
254
"""Compatibility backend for setuptools
255
256
This is a version of setuptools.build_meta that endeavors
257
to maintain backwards
258
compatibility with pre-PEP 517 modes of invocation. It
259
exists as a temporary
260
bridge between the old packaging mechanism and the new
261
packaging mechanism,
262
and will eventually be removed.
263
"""
264
def run_setup(self, setup_script='setup.py'):
265
# In order to maintain compatibility with scripts assuming that
266
# the setup.py script is in a directory on the PYTHONPATH, inject
267
# '' into sys.path. (pypa/setuptools#1642)
268
sys_path = list(sys.path) # Save the original path
269
270
script_dir = os.path.dirname(os.path.abspath(setup_script))
271
if script_dir not in sys.path:
272
sys.path.insert(0, script_dir)
273
274
# Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to
275
# get the directory of the source code. They expect it to refer to the
276
# setup.py script.
277
sys_argv_0 = sys.argv[0]
278
sys.argv[0] = setup_script
279
280
try:
281
super(_BuildMetaLegacyBackend,
282
self).run_setup(setup_script=setup_script)
283
finally:
284
# While PEP 517 frontends should be calling each hook in a fresh
285
# subprocess according to the standard (and thus it should not be
286
# strictly necessary to restore the old sys.path), we'll restore
287
# the original path so that the path manipulation does not persist
288
# within the hook after run_setup is called.
289
sys.path[:] = sys_path
290
sys.argv[0] = sys_argv_0
291
292
293
# The primary backend
294
_BACKEND = _BuildMetaBackend()
295
296
get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel
297
get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist
298
prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel
299
build_wheel = _BACKEND.build_wheel
300
build_sdist = _BACKEND.build_sdist
301
302
303
# The legacy backend
304
__legacy__ = _BuildMetaLegacyBackend()
305
306