Eliminado venv y www del repositorio, agrege un requirements igual
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Wrappers to build Python packages using PEP 517 hooks
|
||||
"""
|
||||
|
||||
__version__ = '0.5.0'
|
||||
__version__ = '0.8.2'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,7 +2,9 @@
|
||||
|
||||
It expects:
|
||||
- Command line args: hook_name, control_dir
|
||||
- Environment variable: PEP517_BUILD_BACKEND=entry.point:spec
|
||||
- Environment variables:
|
||||
PEP517_BUILD_BACKEND=entry.point:spec
|
||||
PEP517_BACKEND_PATH=paths (separated with os.pathsep)
|
||||
- control_dir/input.json:
|
||||
- {"kwargs": {...}}
|
||||
|
||||
@@ -12,28 +14,86 @@ Results:
|
||||
"""
|
||||
from glob import glob
|
||||
from importlib import import_module
|
||||
import json
|
||||
import os
|
||||
import os.path
|
||||
from os.path import join as pjoin
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
# This is run as a script, not a module, so it can't do a relative import
|
||||
import compat
|
||||
# This file is run as a script, and `import compat` is not zip-safe, so we
|
||||
# include write_json() and read_json() from compat.py.
|
||||
#
|
||||
# Handle reading and writing JSON in UTF-8, on Python 3 and 2.
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
# Python 3
|
||||
def write_json(obj, path, **kwargs):
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
json.dump(obj, f, **kwargs)
|
||||
|
||||
def read_json(path):
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
else:
|
||||
# Python 2
|
||||
def write_json(obj, path, **kwargs):
|
||||
with open(path, 'wb') as f:
|
||||
json.dump(obj, f, encoding='utf-8', **kwargs)
|
||||
|
||||
def read_json(path):
|
||||
with open(path, 'rb') as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
class BackendUnavailable(Exception):
|
||||
"""Raised if we cannot import the backend"""
|
||||
def __init__(self, traceback):
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
class BackendInvalid(Exception):
|
||||
"""Raised if the backend is invalid"""
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
|
||||
class HookMissing(Exception):
|
||||
"""Raised if a hook is missing and we are not executing the fallback"""
|
||||
|
||||
|
||||
def contained_in(filename, directory):
|
||||
"""Test if a file is located within the given directory."""
|
||||
filename = os.path.normcase(os.path.abspath(filename))
|
||||
directory = os.path.normcase(os.path.abspath(directory))
|
||||
return os.path.commonprefix([filename, directory]) == directory
|
||||
|
||||
|
||||
def _build_backend():
|
||||
"""Find and load the build backend"""
|
||||
# Add in-tree backend directories to the front of sys.path.
|
||||
backend_path = os.environ.get('PEP517_BACKEND_PATH')
|
||||
if backend_path:
|
||||
extra_pathitems = backend_path.split(os.pathsep)
|
||||
sys.path[:0] = extra_pathitems
|
||||
|
||||
ep = os.environ['PEP517_BUILD_BACKEND']
|
||||
mod_path, _, obj_path = ep.partition(':')
|
||||
try:
|
||||
obj = import_module(mod_path)
|
||||
except ImportError:
|
||||
raise BackendUnavailable
|
||||
raise BackendUnavailable(traceback.format_exc())
|
||||
|
||||
if backend_path:
|
||||
if not any(
|
||||
contained_in(obj.__file__, path)
|
||||
for path in extra_pathitems
|
||||
):
|
||||
raise BackendInvalid("Backend was not loaded from backend-path")
|
||||
|
||||
if obj_path:
|
||||
for path_part in obj_path.split('.'):
|
||||
obj = getattr(obj, path_part)
|
||||
@@ -54,15 +114,19 @@ def get_requires_for_build_wheel(config_settings):
|
||||
return hook(config_settings)
|
||||
|
||||
|
||||
def prepare_metadata_for_build_wheel(metadata_directory, config_settings):
|
||||
def prepare_metadata_for_build_wheel(
|
||||
metadata_directory, config_settings, _allow_fallback):
|
||||
"""Invoke optional prepare_metadata_for_build_wheel
|
||||
|
||||
Implements a fallback by building a wheel if the hook isn't defined.
|
||||
Implements a fallback by building a wheel if the hook isn't defined,
|
||||
unless _allow_fallback is False in which case HookMissing is raised.
|
||||
"""
|
||||
backend = _build_backend()
|
||||
try:
|
||||
hook = backend.prepare_metadata_for_build_wheel
|
||||
except AttributeError:
|
||||
if not _allow_fallback:
|
||||
raise HookMissing()
|
||||
return _get_wheel_metadata_from_wheel(backend, metadata_directory,
|
||||
config_settings)
|
||||
else:
|
||||
@@ -161,6 +225,8 @@ class _DummyException(Exception):
|
||||
|
||||
class GotUnsupportedOperation(Exception):
|
||||
"""For internal use when backend raises UnsupportedOperation"""
|
||||
def __init__(self, traceback):
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
def build_sdist(sdist_directory, config_settings):
|
||||
@@ -169,7 +235,7 @@ def build_sdist(sdist_directory, config_settings):
|
||||
try:
|
||||
return backend.build_sdist(sdist_directory, config_settings)
|
||||
except getattr(backend, 'UnsupportedOperation', _DummyException):
|
||||
raise GotUnsupportedOperation
|
||||
raise GotUnsupportedOperation(traceback.format_exc())
|
||||
|
||||
|
||||
HOOK_NAMES = {
|
||||
@@ -190,17 +256,24 @@ def main():
|
||||
sys.exit("Unknown hook: %s" % hook_name)
|
||||
hook = globals()[hook_name]
|
||||
|
||||
hook_input = compat.read_json(pjoin(control_dir, 'input.json'))
|
||||
hook_input = read_json(pjoin(control_dir, 'input.json'))
|
||||
|
||||
json_out = {'unsupported': False, 'return_val': None}
|
||||
try:
|
||||
json_out['return_val'] = hook(**hook_input['kwargs'])
|
||||
except BackendUnavailable:
|
||||
except BackendUnavailable as e:
|
||||
json_out['no_backend'] = True
|
||||
except GotUnsupportedOperation:
|
||||
json_out['traceback'] = e.traceback
|
||||
except BackendInvalid as e:
|
||||
json_out['backend_invalid'] = True
|
||||
json_out['backend_error'] = e.message
|
||||
except GotUnsupportedOperation as e:
|
||||
json_out['unsupported'] = True
|
||||
json_out['traceback'] = e.traceback
|
||||
except HookMissing:
|
||||
json_out['hook_missing'] = True
|
||||
|
||||
compat.write_json(json_out, pjoin(control_dir, 'output.json'), indent=2)
|
||||
write_json(json_out, pjoin(control_dir, 'output.json'), indent=2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -3,25 +3,56 @@
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import contextlib
|
||||
from pip._vendor import pytoml
|
||||
from pip._vendor import toml
|
||||
import shutil
|
||||
import errno
|
||||
import tempfile
|
||||
|
||||
from .envbuild import BuildEnvironment
|
||||
from .wrappers import Pep517HookCaller
|
||||
from .dirtools import tempdir, mkdir_p
|
||||
from .compat import FileNotFoundError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def tempdir():
|
||||
td = tempfile.mkdtemp()
|
||||
def validate_system(system):
|
||||
"""
|
||||
Ensure build system has the requisite fields.
|
||||
"""
|
||||
required = {'requires', 'build-backend'}
|
||||
if not (required <= set(system)):
|
||||
message = "Missing required fields: {missing}".format(
|
||||
missing=required-set(system),
|
||||
)
|
||||
raise ValueError(message)
|
||||
|
||||
|
||||
def load_system(source_dir):
|
||||
"""
|
||||
Load the build system from a source dir (pyproject.toml).
|
||||
"""
|
||||
pyproject = os.path.join(source_dir, 'pyproject.toml')
|
||||
with open(pyproject) as f:
|
||||
pyproject_data = toml.load(f)
|
||||
return pyproject_data['build-system']
|
||||
|
||||
|
||||
def compat_system(source_dir):
|
||||
"""
|
||||
Given a source dir, attempt to get a build system backend
|
||||
and requirements from pyproject.toml. Fallback to
|
||||
setuptools but only if the file was not found or a build
|
||||
system was not indicated.
|
||||
"""
|
||||
try:
|
||||
yield td
|
||||
finally:
|
||||
shutil.rmtree(td)
|
||||
system = load_system(source_dir)
|
||||
except (FileNotFoundError, KeyError):
|
||||
system = {}
|
||||
system.setdefault(
|
||||
'build-backend',
|
||||
'setuptools.build_meta:__legacy__',
|
||||
)
|
||||
system.setdefault('requires', ['setuptools', 'wheel'])
|
||||
return system
|
||||
|
||||
|
||||
def _do_build(hooks, env, dist, dest):
|
||||
@@ -42,33 +73,18 @@ def _do_build(hooks, env, dist, dest):
|
||||
shutil.move(source, os.path.join(dest, os.path.basename(filename)))
|
||||
|
||||
|
||||
def mkdir_p(*args, **kwargs):
|
||||
"""Like `mkdir`, but does not raise an exception if the
|
||||
directory already exists.
|
||||
"""
|
||||
try:
|
||||
return os.mkdir(*args, **kwargs)
|
||||
except OSError as exc:
|
||||
if exc.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
|
||||
def build(source_dir, dist, dest=None):
|
||||
pyproject = os.path.join(source_dir, 'pyproject.toml')
|
||||
def build(source_dir, dist, dest=None, system=None):
|
||||
system = system or load_system(source_dir)
|
||||
dest = os.path.join(source_dir, dest or 'dist')
|
||||
mkdir_p(dest)
|
||||
|
||||
with open(pyproject) as f:
|
||||
pyproject_data = pytoml.load(f)
|
||||
# Ensure the mandatory data can be loaded
|
||||
buildsys = pyproject_data['build-system']
|
||||
requires = buildsys['requires']
|
||||
backend = buildsys['build-backend']
|
||||
|
||||
hooks = Pep517HookCaller(source_dir, backend)
|
||||
validate_system(system)
|
||||
hooks = Pep517HookCaller(
|
||||
source_dir, system['build-backend'], system.get('backend-path')
|
||||
)
|
||||
|
||||
with BuildEnvironment() as env:
|
||||
env.pip_install(requires)
|
||||
env.pip_install(system['requires'])
|
||||
_do_build(hooks, env, dist, dest)
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import argparse
|
||||
import logging
|
||||
import os
|
||||
from os.path import isfile, join as pjoin
|
||||
from pip._vendor.pytoml import TomlError, load as toml_load
|
||||
from pip._vendor.toml import TomlDecodeError, load as toml_load
|
||||
import shutil
|
||||
from subprocess import CalledProcessError
|
||||
import sys
|
||||
@@ -147,12 +147,13 @@ def check(source_dir):
|
||||
buildsys = pyproject_data['build-system']
|
||||
requires = buildsys['requires']
|
||||
backend = buildsys['build-backend']
|
||||
backend_path = buildsys.get('backend-path')
|
||||
log.info('Loaded pyproject.toml')
|
||||
except (TomlError, KeyError):
|
||||
except (TomlDecodeError, KeyError):
|
||||
log.error("Invalid pyproject.toml", exc_info=True)
|
||||
return False
|
||||
|
||||
hooks = Pep517HookCaller(source_dir, backend)
|
||||
hooks = Pep517HookCaller(source_dir, backend, backend_path)
|
||||
|
||||
sdist_ok = check_build_sdist(hooks, requires)
|
||||
wheel_ok = check_build_wheel(hooks, requires)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
"""Handle reading and writing JSON in UTF-8, on Python 3 and 2."""
|
||||
"""Python 2/3 compatibility"""
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
# Handle reading and writing JSON in UTF-8, on Python 3 and 2.
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
# Python 3
|
||||
def write_json(obj, path, **kwargs):
|
||||
@@ -21,3 +24,11 @@ else:
|
||||
def read_json(path):
|
||||
with open(path, 'rb') as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
# FileNotFoundError
|
||||
|
||||
try:
|
||||
FileNotFoundError = FileNotFoundError
|
||||
except NameError:
|
||||
FileNotFoundError = IOError
|
||||
|
||||
@@ -3,23 +3,27 @@
|
||||
|
||||
import os
|
||||
import logging
|
||||
from pip._vendor import pytoml
|
||||
from pip._vendor import toml
|
||||
import shutil
|
||||
from subprocess import check_call
|
||||
import sys
|
||||
from sysconfig import get_paths
|
||||
from tempfile import mkdtemp
|
||||
|
||||
from .wrappers import Pep517HookCaller
|
||||
from .wrappers import Pep517HookCaller, LoggerWrapper
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _load_pyproject(source_dir):
|
||||
with open(os.path.join(source_dir, 'pyproject.toml')) as f:
|
||||
pyproject_data = pytoml.load(f)
|
||||
pyproject_data = toml.load(f)
|
||||
buildsys = pyproject_data['build-system']
|
||||
return buildsys['requires'], buildsys['build-backend']
|
||||
return (
|
||||
buildsys['requires'],
|
||||
buildsys['build-backend'],
|
||||
buildsys.get('backend-path'),
|
||||
)
|
||||
|
||||
|
||||
class BuildEnvironment(object):
|
||||
@@ -90,9 +94,14 @@ class BuildEnvironment(object):
|
||||
if not reqs:
|
||||
return
|
||||
log.info('Calling pip to install %s', reqs)
|
||||
check_call([
|
||||
cmd = [
|
||||
sys.executable, '-m', 'pip', 'install', '--ignore-installed',
|
||||
'--prefix', self.path] + list(reqs))
|
||||
'--prefix', self.path] + list(reqs)
|
||||
check_call(
|
||||
cmd,
|
||||
stdout=LoggerWrapper(log, logging.INFO),
|
||||
stderr=LoggerWrapper(log, logging.ERROR),
|
||||
)
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
needs_cleanup = (
|
||||
@@ -126,8 +135,8 @@ def build_wheel(source_dir, wheel_dir, config_settings=None):
|
||||
"""
|
||||
if config_settings is None:
|
||||
config_settings = {}
|
||||
requires, backend = _load_pyproject(source_dir)
|
||||
hooks = Pep517HookCaller(source_dir, backend)
|
||||
requires, backend, backend_path = _load_pyproject(source_dir)
|
||||
hooks = Pep517HookCaller(source_dir, backend, backend_path)
|
||||
|
||||
with BuildEnvironment() as env:
|
||||
env.pip_install(requires)
|
||||
@@ -148,8 +157,8 @@ def build_sdist(source_dir, sdist_dir, config_settings=None):
|
||||
"""
|
||||
if config_settings is None:
|
||||
config_settings = {}
|
||||
requires, backend = _load_pyproject(source_dir)
|
||||
hooks = Pep517HookCaller(source_dir, backend)
|
||||
requires, backend, backend_path = _load_pyproject(source_dir)
|
||||
hooks = Pep517HookCaller(source_dir, backend, backend_path)
|
||||
|
||||
with BuildEnvironment() as env:
|
||||
env.pip_install(requires)
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
import threading
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
from os.path import dirname, abspath, join as pjoin
|
||||
import shutil
|
||||
from subprocess import check_call
|
||||
from subprocess import check_call, check_output, STDOUT
|
||||
import sys
|
||||
from tempfile import mkdtemp
|
||||
|
||||
from . import compat
|
||||
|
||||
_in_proc_script = pjoin(dirname(abspath(__file__)), '_in_process.py')
|
||||
|
||||
try:
|
||||
import importlib.resources as resources
|
||||
|
||||
def _in_proc_script_path():
|
||||
return resources.path(__package__, '_in_process.py')
|
||||
except ImportError:
|
||||
@contextmanager
|
||||
def _in_proc_script_path():
|
||||
yield pjoin(dirname(abspath(__file__)), '_in_process.py')
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -22,10 +32,29 @@ def tempdir():
|
||||
|
||||
class BackendUnavailable(Exception):
|
||||
"""Will be raised if the backend cannot be imported in the hook process."""
|
||||
def __init__(self, traceback):
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
class BackendInvalid(Exception):
|
||||
"""Will be raised if the backend is invalid."""
|
||||
def __init__(self, backend_name, backend_path, message):
|
||||
self.backend_name = backend_name
|
||||
self.backend_path = backend_path
|
||||
self.message = message
|
||||
|
||||
|
||||
class HookMissing(Exception):
|
||||
"""Will be raised on missing hooks."""
|
||||
def __init__(self, hook_name):
|
||||
super(HookMissing, self).__init__(hook_name)
|
||||
self.hook_name = hook_name
|
||||
|
||||
|
||||
class UnsupportedOperation(Exception):
|
||||
"""May be raised by build_sdist if the backend indicates that it can't."""
|
||||
def __init__(self, traceback):
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
def default_subprocess_runner(cmd, cwd=None, extra_environ=None):
|
||||
@@ -37,25 +66,86 @@ def default_subprocess_runner(cmd, cwd=None, extra_environ=None):
|
||||
check_call(cmd, cwd=cwd, env=env)
|
||||
|
||||
|
||||
def quiet_subprocess_runner(cmd, cwd=None, extra_environ=None):
|
||||
"""A method of calling the wrapper subprocess while suppressing output."""
|
||||
env = os.environ.copy()
|
||||
if extra_environ:
|
||||
env.update(extra_environ)
|
||||
|
||||
check_output(cmd, cwd=cwd, env=env, stderr=STDOUT)
|
||||
|
||||
|
||||
def norm_and_check(source_tree, requested):
|
||||
"""Normalise and check a backend path.
|
||||
|
||||
Ensure that the requested backend path is specified as a relative path,
|
||||
and resolves to a location under the given source tree.
|
||||
|
||||
Return an absolute version of the requested path.
|
||||
"""
|
||||
if os.path.isabs(requested):
|
||||
raise ValueError("paths must be relative")
|
||||
|
||||
abs_source = os.path.abspath(source_tree)
|
||||
abs_requested = os.path.normpath(os.path.join(abs_source, requested))
|
||||
# We have to use commonprefix for Python 2.7 compatibility. So we
|
||||
# normalise case to avoid problems because commonprefix is a character
|
||||
# based comparison :-(
|
||||
norm_source = os.path.normcase(abs_source)
|
||||
norm_requested = os.path.normcase(abs_requested)
|
||||
if os.path.commonprefix([norm_source, norm_requested]) != norm_source:
|
||||
raise ValueError("paths must be inside source tree")
|
||||
|
||||
return abs_requested
|
||||
|
||||
|
||||
class Pep517HookCaller(object):
|
||||
"""A wrapper around a source directory to be built with a PEP 517 backend.
|
||||
|
||||
source_dir : The path to the source directory, containing pyproject.toml.
|
||||
backend : The build backend spec, as per PEP 517, from pyproject.toml.
|
||||
build_backend : The build backend spec, as per PEP 517, from
|
||||
pyproject.toml.
|
||||
backend_path : The backend path, as per PEP 517, from pyproject.toml.
|
||||
runner : A callable that invokes the wrapper subprocess.
|
||||
|
||||
The 'runner', if provided, must expect the following:
|
||||
cmd : a list of strings representing the command and arguments to
|
||||
execute, as would be passed to e.g. 'subprocess.check_call'.
|
||||
cwd : a string representing the working directory that must be
|
||||
used for the subprocess. Corresponds to the provided source_dir.
|
||||
extra_environ : a dict mapping environment variable names to values
|
||||
which must be set for the subprocess execution.
|
||||
"""
|
||||
def __init__(self, source_dir, build_backend):
|
||||
def __init__(
|
||||
self,
|
||||
source_dir,
|
||||
build_backend,
|
||||
backend_path=None,
|
||||
runner=None,
|
||||
):
|
||||
if runner is None:
|
||||
runner = default_subprocess_runner
|
||||
|
||||
self.source_dir = abspath(source_dir)
|
||||
self.build_backend = build_backend
|
||||
self._subprocess_runner = default_subprocess_runner
|
||||
if backend_path:
|
||||
backend_path = [
|
||||
norm_and_check(self.source_dir, p) for p in backend_path
|
||||
]
|
||||
self.backend_path = backend_path
|
||||
self._subprocess_runner = runner
|
||||
|
||||
# TODO: Is this over-engineered? Maybe frontends only need to
|
||||
# set this when creating the wrapper, not on every call.
|
||||
@contextmanager
|
||||
def subprocess_runner(self, runner):
|
||||
"""A context manager for temporarily overriding the default subprocess
|
||||
runner.
|
||||
"""
|
||||
prev = self._subprocess_runner
|
||||
self._subprocess_runner = runner
|
||||
yield
|
||||
self._subprocess_runner = prev
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
self._subprocess_runner = prev
|
||||
|
||||
def get_requires_for_build_wheel(self, config_settings=None):
|
||||
"""Identify packages required for building a wheel
|
||||
@@ -72,18 +162,21 @@ class Pep517HookCaller(object):
|
||||
})
|
||||
|
||||
def prepare_metadata_for_build_wheel(
|
||||
self, metadata_directory, config_settings=None):
|
||||
self, metadata_directory, config_settings=None,
|
||||
_allow_fallback=True):
|
||||
"""Prepare a *.dist-info folder with metadata for this project.
|
||||
|
||||
Returns the name of the newly created folder.
|
||||
|
||||
If the build backend defines a hook with this name, it will be called
|
||||
in a subprocess. If not, the backend will be asked to build a wheel,
|
||||
and the dist-info extracted from that.
|
||||
and the dist-info extracted from that (unless _allow_fallback is
|
||||
False).
|
||||
"""
|
||||
return self._call_hook('prepare_metadata_for_build_wheel', {
|
||||
'metadata_directory': abspath(metadata_directory),
|
||||
'config_settings': config_settings,
|
||||
'_allow_fallback': _allow_fallback,
|
||||
})
|
||||
|
||||
def build_wheel(
|
||||
@@ -139,25 +232,77 @@ class Pep517HookCaller(object):
|
||||
# letters, digits and _, . and : characters, and will be used as a
|
||||
# Python identifier, so non-ASCII content is wrong on Python 2 in
|
||||
# any case).
|
||||
# For backend_path, we use sys.getfilesystemencoding.
|
||||
if sys.version_info[0] == 2:
|
||||
build_backend = self.build_backend.encode('ASCII')
|
||||
else:
|
||||
build_backend = self.build_backend
|
||||
extra_environ = {'PEP517_BUILD_BACKEND': build_backend}
|
||||
|
||||
if self.backend_path:
|
||||
backend_path = os.pathsep.join(self.backend_path)
|
||||
if sys.version_info[0] == 2:
|
||||
backend_path = backend_path.encode(sys.getfilesystemencoding())
|
||||
extra_environ['PEP517_BACKEND_PATH'] = backend_path
|
||||
|
||||
with tempdir() as td:
|
||||
compat.write_json({'kwargs': kwargs}, pjoin(td, 'input.json'),
|
||||
hook_input = {'kwargs': kwargs}
|
||||
compat.write_json(hook_input, pjoin(td, 'input.json'),
|
||||
indent=2)
|
||||
|
||||
# Run the hook in a subprocess
|
||||
self._subprocess_runner(
|
||||
[sys.executable, _in_proc_script, hook_name, td],
|
||||
cwd=self.source_dir,
|
||||
extra_environ={'PEP517_BUILD_BACKEND': build_backend}
|
||||
)
|
||||
with _in_proc_script_path() as script:
|
||||
self._subprocess_runner(
|
||||
[sys.executable, str(script), hook_name, td],
|
||||
cwd=self.source_dir,
|
||||
extra_environ=extra_environ
|
||||
)
|
||||
|
||||
data = compat.read_json(pjoin(td, 'output.json'))
|
||||
if data.get('unsupported'):
|
||||
raise UnsupportedOperation
|
||||
raise UnsupportedOperation(data.get('traceback', ''))
|
||||
if data.get('no_backend'):
|
||||
raise BackendUnavailable
|
||||
raise BackendUnavailable(data.get('traceback', ''))
|
||||
if data.get('backend_invalid'):
|
||||
raise BackendInvalid(
|
||||
backend_name=self.build_backend,
|
||||
backend_path=self.backend_path,
|
||||
message=data.get('backend_error', '')
|
||||
)
|
||||
if data.get('hook_missing'):
|
||||
raise HookMissing(hook_name)
|
||||
return data['return_val']
|
||||
|
||||
|
||||
class LoggerWrapper(threading.Thread):
|
||||
"""
|
||||
Read messages from a pipe and redirect them
|
||||
to a logger (see python's logging module).
|
||||
"""
|
||||
|
||||
def __init__(self, logger, level):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
|
||||
self.logger = logger
|
||||
self.level = level
|
||||
|
||||
# create the pipe and reader
|
||||
self.fd_read, self.fd_write = os.pipe()
|
||||
self.reader = os.fdopen(self.fd_read)
|
||||
|
||||
self.start()
|
||||
|
||||
def fileno(self):
|
||||
return self.fd_write
|
||||
|
||||
@staticmethod
|
||||
def remove_newline(msg):
|
||||
return msg[:-1] if msg.endswith(os.linesep) else msg
|
||||
|
||||
def run(self):
|
||||
for line in self.reader:
|
||||
self._write(self.remove_newline(line))
|
||||
|
||||
def _write(self, message):
|
||||
self.logger.log(self.level, message)
|
||||
|
||||
Reference in New Issue
Block a user