comparison lib/python3.8/site-packages/pip/_vendor/pep517/envbuild.py @ 0:9e54283cc701 draft

"planemo upload commit d12c32a45bcd441307e632fca6d9af7d60289d44"
author guerler
date Mon, 27 Jul 2020 03:47:31 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:9e54283cc701
1 """Build wheels/sdists by installing build deps to a temporary environment.
2 """
3
4 import os
5 import logging
6 import toml
7 import shutil
8 from subprocess import check_call
9 import sys
10 from sysconfig import get_paths
11 from tempfile import mkdtemp
12
13 from .wrappers import Pep517HookCaller, LoggerWrapper
14
15 log = logging.getLogger(__name__)
16
17
18 def _load_pyproject(source_dir):
19 with open(os.path.join(source_dir, 'pyproject.toml')) as f:
20 pyproject_data = toml.load(f)
21 buildsys = pyproject_data['build-system']
22 return (
23 buildsys['requires'],
24 buildsys['build-backend'],
25 buildsys.get('backend-path'),
26 )
27
28
29 class BuildEnvironment(object):
30 """Context manager to install build deps in a simple temporary environment
31
32 Based on code I wrote for pip, which is MIT licensed.
33 """
34 # Copyright (c) 2008-2016 The pip developers (see AUTHORS.txt file)
35 #
36 # Permission is hereby granted, free of charge, to any person obtaining
37 # a copy of this software and associated documentation files (the
38 # "Software"), to deal in the Software without restriction, including
39 # without limitation the rights to use, copy, modify, merge, publish,
40 # distribute, sublicense, and/or sell copies of the Software, and to
41 # permit persons to whom the Software is furnished to do so, subject to
42 # the following conditions:
43 #
44 # The above copyright notice and this permission notice shall be
45 # included in all copies or substantial portions of the Software.
46 #
47 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
48 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
50 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
51 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
52 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
53 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54
55 path = None
56
57 def __init__(self, cleanup=True):
58 self._cleanup = cleanup
59
60 def __enter__(self):
61 self.path = mkdtemp(prefix='pep517-build-env-')
62 log.info('Temporary build environment: %s', self.path)
63
64 self.save_path = os.environ.get('PATH', None)
65 self.save_pythonpath = os.environ.get('PYTHONPATH', None)
66
67 install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix'
68 install_dirs = get_paths(install_scheme, vars={
69 'base': self.path,
70 'platbase': self.path,
71 })
72
73 scripts = install_dirs['scripts']
74 if self.save_path:
75 os.environ['PATH'] = scripts + os.pathsep + self.save_path
76 else:
77 os.environ['PATH'] = scripts + os.pathsep + os.defpath
78
79 if install_dirs['purelib'] == install_dirs['platlib']:
80 lib_dirs = install_dirs['purelib']
81 else:
82 lib_dirs = install_dirs['purelib'] + os.pathsep + \
83 install_dirs['platlib']
84 if self.save_pythonpath:
85 os.environ['PYTHONPATH'] = lib_dirs + os.pathsep + \
86 self.save_pythonpath
87 else:
88 os.environ['PYTHONPATH'] = lib_dirs
89
90 return self
91
92 def pip_install(self, reqs):
93 """Install dependencies into this env by calling pip in a subprocess"""
94 if not reqs:
95 return
96 log.info('Calling pip to install %s', reqs)
97 cmd = [
98 sys.executable, '-m', 'pip', 'install', '--ignore-installed',
99 '--prefix', self.path] + list(reqs)
100 check_call(
101 cmd,
102 stdout=LoggerWrapper(log, logging.INFO),
103 stderr=LoggerWrapper(log, logging.ERROR),
104 )
105
106 def __exit__(self, exc_type, exc_val, exc_tb):
107 needs_cleanup = (
108 self._cleanup and
109 self.path is not None and
110 os.path.isdir(self.path)
111 )
112 if needs_cleanup:
113 shutil.rmtree(self.path)
114
115 if self.save_path is None:
116 os.environ.pop('PATH', None)
117 else:
118 os.environ['PATH'] = self.save_path
119
120 if self.save_pythonpath is None:
121 os.environ.pop('PYTHONPATH', None)
122 else:
123 os.environ['PYTHONPATH'] = self.save_pythonpath
124
125
126 def build_wheel(source_dir, wheel_dir, config_settings=None):
127 """Build a wheel from a source directory using PEP 517 hooks.
128
129 :param str source_dir: Source directory containing pyproject.toml
130 :param str wheel_dir: Target directory to create wheel in
131 :param dict config_settings: Options to pass to build backend
132
133 This is a blocking function which will run pip in a subprocess to install
134 build requirements.
135 """
136 if config_settings is None:
137 config_settings = {}
138 requires, backend, backend_path = _load_pyproject(source_dir)
139 hooks = Pep517HookCaller(source_dir, backend, backend_path)
140
141 with BuildEnvironment() as env:
142 env.pip_install(requires)
143 reqs = hooks.get_requires_for_build_wheel(config_settings)
144 env.pip_install(reqs)
145 return hooks.build_wheel(wheel_dir, config_settings)
146
147
148 def build_sdist(source_dir, sdist_dir, config_settings=None):
149 """Build an sdist from a source directory using PEP 517 hooks.
150
151 :param str source_dir: Source directory containing pyproject.toml
152 :param str sdist_dir: Target directory to place sdist in
153 :param dict config_settings: Options to pass to build backend
154
155 This is a blocking function which will run pip in a subprocess to install
156 build requirements.
157 """
158 if config_settings is None:
159 config_settings = {}
160 requires, backend, backend_path = _load_pyproject(source_dir)
161 hooks = Pep517HookCaller(source_dir, backend, backend_path)
162
163 with BuildEnvironment() as env:
164 env.pip_install(requires)
165 reqs = hooks.get_requires_for_build_sdist(config_settings)
166 env.pip_install(reqs)
167 return hooks.build_sdist(sdist_dir, config_settings)