Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/setuptools/build_meta.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
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 | |
37 import setuptools | |
38 import distutils | |
39 | |
40 from pkg_resources import parse_requirements | |
41 | |
42 __all__ = ['get_requires_for_build_sdist', | |
43 'get_requires_for_build_wheel', | |
44 'prepare_metadata_for_build_wheel', | |
45 'build_wheel', | |
46 'build_sdist', | |
47 '__legacy__', | |
48 'SetupRequirementsError'] | |
49 | |
50 | |
51 class SetupRequirementsError(BaseException): | |
52 def __init__(self, specifiers): | |
53 self.specifiers = specifiers | |
54 | |
55 | |
56 class Distribution(setuptools.dist.Distribution): | |
57 def fetch_build_eggs(self, specifiers): | |
58 specifier_list = list(map(str, parse_requirements(specifiers))) | |
59 | |
60 raise SetupRequirementsError(specifier_list) | |
61 | |
62 @classmethod | |
63 @contextlib.contextmanager | |
64 def patch(cls): | |
65 """ | |
66 Replace | |
67 distutils.dist.Distribution with this class | |
68 for the duration of this context. | |
69 """ | |
70 orig = distutils.core.Distribution | |
71 distutils.core.Distribution = cls | |
72 try: | |
73 yield | |
74 finally: | |
75 distutils.core.Distribution = orig | |
76 | |
77 | |
78 @contextlib.contextmanager | |
79 def no_install_setup_requires(): | |
80 """Temporarily disable installing setup_requires | |
81 | |
82 Under PEP 517, the backend reports build dependencies to the frontend, | |
83 and the frontend is responsible for ensuring they're installed. | |
84 So setuptools (acting as a backend) should not try to install them. | |
85 """ | |
86 orig = setuptools._install_setup_requires | |
87 setuptools._install_setup_requires = lambda attrs: None | |
88 try: | |
89 yield | |
90 finally: | |
91 setuptools._install_setup_requires = orig | |
92 | |
93 | |
94 def _get_immediate_subdirectories(a_dir): | |
95 return [name for name in os.listdir(a_dir) | |
96 if os.path.isdir(os.path.join(a_dir, name))] | |
97 | |
98 | |
99 def _file_with_extension(directory, extension): | |
100 matching = ( | |
101 f for f in os.listdir(directory) | |
102 if f.endswith(extension) | |
103 ) | |
104 file, = matching | |
105 return file | |
106 | |
107 | |
108 def _open_setup_script(setup_script): | |
109 if not os.path.exists(setup_script): | |
110 # Supply a default setup.py | |
111 return io.StringIO(u"from setuptools import setup; setup()") | |
112 | |
113 return getattr(tokenize, 'open', open)(setup_script) | |
114 | |
115 | |
116 class _BuildMetaBackend(object): | |
117 | |
118 def _fix_config(self, config_settings): | |
119 config_settings = config_settings or {} | |
120 config_settings.setdefault('--global-option', []) | |
121 return config_settings | |
122 | |
123 def _get_build_requires(self, config_settings, requirements): | |
124 config_settings = self._fix_config(config_settings) | |
125 | |
126 sys.argv = sys.argv[:1] + ['egg_info'] + \ | |
127 config_settings["--global-option"] | |
128 try: | |
129 with Distribution.patch(): | |
130 self.run_setup() | |
131 except SetupRequirementsError as e: | |
132 requirements += e.specifiers | |
133 | |
134 return requirements | |
135 | |
136 def run_setup(self, setup_script='setup.py'): | |
137 # Note that we can reuse our build directory between calls | |
138 # Correctness comes first, then optimization later | |
139 __file__ = setup_script | |
140 __name__ = '__main__' | |
141 | |
142 with _open_setup_script(__file__) as f: | |
143 code = f.read().replace(r'\r\n', r'\n') | |
144 | |
145 exec(compile(code, __file__, 'exec'), locals()) | |
146 | |
147 def get_requires_for_build_wheel(self, config_settings=None): | |
148 config_settings = self._fix_config(config_settings) | |
149 return self._get_build_requires( | |
150 config_settings, requirements=['wheel']) | |
151 | |
152 def get_requires_for_build_sdist(self, config_settings=None): | |
153 config_settings = self._fix_config(config_settings) | |
154 return self._get_build_requires(config_settings, requirements=[]) | |
155 | |
156 def prepare_metadata_for_build_wheel(self, metadata_directory, | |
157 config_settings=None): | |
158 sys.argv = sys.argv[:1] + [ | |
159 'dist_info', '--egg-base', metadata_directory] | |
160 with no_install_setup_requires(): | |
161 self.run_setup() | |
162 | |
163 dist_info_directory = metadata_directory | |
164 while True: | |
165 dist_infos = [f for f in os.listdir(dist_info_directory) | |
166 if f.endswith('.dist-info')] | |
167 | |
168 if ( | |
169 len(dist_infos) == 0 and | |
170 len(_get_immediate_subdirectories(dist_info_directory)) == 1 | |
171 ): | |
172 | |
173 dist_info_directory = os.path.join( | |
174 dist_info_directory, os.listdir(dist_info_directory)[0]) | |
175 continue | |
176 | |
177 assert len(dist_infos) == 1 | |
178 break | |
179 | |
180 # PEP 517 requires that the .dist-info directory be placed in the | |
181 # metadata_directory. To comply, we MUST copy the directory to the root | |
182 if dist_info_directory != metadata_directory: | |
183 shutil.move( | |
184 os.path.join(dist_info_directory, dist_infos[0]), | |
185 metadata_directory) | |
186 shutil.rmtree(dist_info_directory, ignore_errors=True) | |
187 | |
188 return dist_infos[0] | |
189 | |
190 def _build_with_temp_dir(self, setup_command, result_extension, | |
191 result_directory, config_settings): | |
192 config_settings = self._fix_config(config_settings) | |
193 result_directory = os.path.abspath(result_directory) | |
194 | |
195 # Build in a temporary directory, then copy to the target. | |
196 os.makedirs(result_directory, exist_ok=True) | |
197 with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir: | |
198 sys.argv = (sys.argv[:1] + setup_command + | |
199 ['--dist-dir', tmp_dist_dir] + | |
200 config_settings["--global-option"]) | |
201 with no_install_setup_requires(): | |
202 self.run_setup() | |
203 | |
204 result_basename = _file_with_extension( | |
205 tmp_dist_dir, result_extension) | |
206 result_path = os.path.join(result_directory, result_basename) | |
207 if os.path.exists(result_path): | |
208 # os.rename will fail overwriting on non-Unix. | |
209 os.remove(result_path) | |
210 os.rename(os.path.join(tmp_dist_dir, result_basename), result_path) | |
211 | |
212 return result_basename | |
213 | |
214 def build_wheel(self, wheel_directory, config_settings=None, | |
215 metadata_directory=None): | |
216 return self._build_with_temp_dir(['bdist_wheel'], '.whl', | |
217 wheel_directory, config_settings) | |
218 | |
219 def build_sdist(self, sdist_directory, config_settings=None): | |
220 return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], | |
221 '.tar.gz', sdist_directory, | |
222 config_settings) | |
223 | |
224 | |
225 class _BuildMetaLegacyBackend(_BuildMetaBackend): | |
226 """Compatibility backend for setuptools | |
227 | |
228 This is a version of setuptools.build_meta that endeavors | |
229 to maintain backwards | |
230 compatibility with pre-PEP 517 modes of invocation. It | |
231 exists as a temporary | |
232 bridge between the old packaging mechanism and the new | |
233 packaging mechanism, | |
234 and will eventually be removed. | |
235 """ | |
236 def run_setup(self, setup_script='setup.py'): | |
237 # In order to maintain compatibility with scripts assuming that | |
238 # the setup.py script is in a directory on the PYTHONPATH, inject | |
239 # '' into sys.path. (pypa/setuptools#1642) | |
240 sys_path = list(sys.path) # Save the original path | |
241 | |
242 script_dir = os.path.dirname(os.path.abspath(setup_script)) | |
243 if script_dir not in sys.path: | |
244 sys.path.insert(0, script_dir) | |
245 | |
246 # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to | |
247 # get the directory of the source code. They expect it to refer to the | |
248 # setup.py script. | |
249 sys_argv_0 = sys.argv[0] | |
250 sys.argv[0] = setup_script | |
251 | |
252 try: | |
253 super(_BuildMetaLegacyBackend, | |
254 self).run_setup(setup_script=setup_script) | |
255 finally: | |
256 # While PEP 517 frontends should be calling each hook in a fresh | |
257 # subprocess according to the standard (and thus it should not be | |
258 # strictly necessary to restore the old sys.path), we'll restore | |
259 # the original path so that the path manipulation does not persist | |
260 # within the hook after run_setup is called. | |
261 sys.path[:] = sys_path | |
262 sys.argv[0] = sys_argv_0 | |
263 | |
264 | |
265 # The primary backend | |
266 _BACKEND = _BuildMetaBackend() | |
267 | |
268 get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel | |
269 get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist | |
270 prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel | |
271 build_wheel = _BACKEND.build_wheel | |
272 build_sdist = _BACKEND.build_sdist | |
273 | |
274 | |
275 # The legacy backend | |
276 __legacy__ = _BuildMetaLegacyBackend() |