| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 | 
							- """A PEP 517 interface to setuptools
 
- Previously, when a user or a command line tool (let's call it a "frontend")
 
- needed to make a request of setuptools to take a certain action, for
 
- example, generating a list of installation requirements, the frontend would
 
- would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line.
 
- PEP 517 defines a different method of interfacing with setuptools. Rather
 
- than calling "setup.py" directly, the frontend should:
 
-   1. Set the current directory to the directory with a setup.py file
 
-   2. Import this module into a safe python interpreter (one in which
 
-      setuptools can potentially set global variables or crash hard).
 
-   3. Call one of the functions defined in PEP 517.
 
- What each function does is defined in PEP 517. However, here is a "casual"
 
- definition of the functions (this definition should not be relied on for
 
- bug reports or API stability):
 
-   - `build_wheel`: build a wheel in the folder and return the basename
 
-   - `get_requires_for_build_wheel`: get the `setup_requires` to build
 
-   - `prepare_metadata_for_build_wheel`: get the `install_requires`
 
-   - `build_sdist`: build an sdist in the folder and return the basename
 
-   - `get_requires_for_build_sdist`: get the `setup_requires` to build
 
- Again, this is not a formal definition! Just a "taste" of the module.
 
- """
 
- import io
 
- import os
 
- import sys
 
- import tokenize
 
- import shutil
 
- import contextlib
 
- import setuptools
 
- import distutils
 
- from setuptools.py31compat import TemporaryDirectory
 
- from pkg_resources import parse_requirements
 
- __all__ = ['get_requires_for_build_sdist',
 
-            'get_requires_for_build_wheel',
 
-            'prepare_metadata_for_build_wheel',
 
-            'build_wheel',
 
-            'build_sdist',
 
-            '__legacy__',
 
-            'SetupRequirementsError']
 
- class SetupRequirementsError(BaseException):
 
-     def __init__(self, specifiers):
 
-         self.specifiers = specifiers
 
- class Distribution(setuptools.dist.Distribution):
 
-     def fetch_build_eggs(self, specifiers):
 
-         specifier_list = list(map(str, parse_requirements(specifiers)))
 
-         raise SetupRequirementsError(specifier_list)
 
-     @classmethod
 
-     @contextlib.contextmanager
 
-     def patch(cls):
 
-         """
 
-         Replace
 
-         distutils.dist.Distribution with this class
 
-         for the duration of this context.
 
-         """
 
-         orig = distutils.core.Distribution
 
-         distutils.core.Distribution = cls
 
-         try:
 
-             yield
 
-         finally:
 
-             distutils.core.Distribution = orig
 
- def _to_str(s):
 
-     """
 
-     Convert a filename to a string (on Python 2, explicitly
 
-     a byte string, not Unicode) as distutils checks for the
 
-     exact type str.
 
-     """
 
-     if sys.version_info[0] == 2 and not isinstance(s, str):
 
-         # Assume it's Unicode, as that's what the PEP says
 
-         # should be provided.
 
-         return s.encode(sys.getfilesystemencoding())
 
-     return s
 
- def _get_immediate_subdirectories(a_dir):
 
-     return [name for name in os.listdir(a_dir)
 
-             if os.path.isdir(os.path.join(a_dir, name))]
 
- def _file_with_extension(directory, extension):
 
-     matching = (
 
-         f for f in os.listdir(directory)
 
-         if f.endswith(extension)
 
-     )
 
-     file, = matching
 
-     return file
 
- def _open_setup_script(setup_script):
 
-     if not os.path.exists(setup_script):
 
-         # Supply a default setup.py
 
-         return io.StringIO(u"from setuptools import setup; setup()")
 
-     return getattr(tokenize, 'open', open)(setup_script)
 
- class _BuildMetaBackend(object):
 
-     def _fix_config(self, config_settings):
 
-         config_settings = config_settings or {}
 
-         config_settings.setdefault('--global-option', [])
 
-         return config_settings
 
-     def _get_build_requires(self, config_settings, requirements):
 
-         config_settings = self._fix_config(config_settings)
 
-         sys.argv = sys.argv[:1] + ['egg_info'] + \
 
-             config_settings["--global-option"]
 
-         try:
 
-             with Distribution.patch():
 
-                 self.run_setup()
 
-         except SetupRequirementsError as e:
 
-             requirements += e.specifiers
 
-         return requirements
 
-     def run_setup(self, setup_script='setup.py'):
 
-         # Note that we can reuse our build directory between calls
 
-         # Correctness comes first, then optimization later
 
-         __file__ = setup_script
 
-         __name__ = '__main__'
 
-         with _open_setup_script(__file__) as f:
 
-             code = f.read().replace(r'\r\n', r'\n')
 
-         exec(compile(code, __file__, 'exec'), locals())
 
-     def get_requires_for_build_wheel(self, config_settings=None):
 
-         config_settings = self._fix_config(config_settings)
 
-         return self._get_build_requires(
 
-             config_settings, requirements=['wheel'])
 
-     def get_requires_for_build_sdist(self, config_settings=None):
 
-         config_settings = self._fix_config(config_settings)
 
-         return self._get_build_requires(config_settings, requirements=[])
 
-     def prepare_metadata_for_build_wheel(self, metadata_directory,
 
-                                          config_settings=None):
 
-         sys.argv = sys.argv[:1] + ['dist_info', '--egg-base',
 
-                                    _to_str(metadata_directory)]
 
-         self.run_setup()
 
-         dist_info_directory = metadata_directory
 
-         while True:
 
-             dist_infos = [f for f in os.listdir(dist_info_directory)
 
-                           if f.endswith('.dist-info')]
 
-             if (
 
-                 len(dist_infos) == 0 and
 
-                 len(_get_immediate_subdirectories(dist_info_directory)) == 1
 
-             ):
 
-                 dist_info_directory = os.path.join(
 
-                     dist_info_directory, os.listdir(dist_info_directory)[0])
 
-                 continue
 
-             assert len(dist_infos) == 1
 
-             break
 
-         # PEP 517 requires that the .dist-info directory be placed in the
 
-         # metadata_directory. To comply, we MUST copy the directory to the root
 
-         if dist_info_directory != metadata_directory:
 
-             shutil.move(
 
-                 os.path.join(dist_info_directory, dist_infos[0]),
 
-                 metadata_directory)
 
-             shutil.rmtree(dist_info_directory, ignore_errors=True)
 
-         return dist_infos[0]
 
-     def _build_with_temp_dir(self, setup_command, result_extension,
 
-                              result_directory, config_settings):
 
-         config_settings = self._fix_config(config_settings)
 
-         result_directory = os.path.abspath(result_directory)
 
-         # Build in a temporary directory, then copy to the target.
 
-         os.makedirs(result_directory, exist_ok=True)
 
-         with TemporaryDirectory(dir=result_directory) as tmp_dist_dir:
 
-             sys.argv = (sys.argv[:1] + setup_command +
 
-                         ['--dist-dir', tmp_dist_dir] +
 
-                         config_settings["--global-option"])
 
-             self.run_setup()
 
-             result_basename = _file_with_extension(
 
-                 tmp_dist_dir, result_extension)
 
-             result_path = os.path.join(result_directory, result_basename)
 
-             if os.path.exists(result_path):
 
-                 # os.rename will fail overwriting on non-Unix.
 
-                 os.remove(result_path)
 
-             os.rename(os.path.join(tmp_dist_dir, result_basename), result_path)
 
-         return result_basename
 
-     def build_wheel(self, wheel_directory, config_settings=None,
 
-                     metadata_directory=None):
 
-         return self._build_with_temp_dir(['bdist_wheel'], '.whl',
 
-                                          wheel_directory, config_settings)
 
-     def build_sdist(self, sdist_directory, config_settings=None):
 
-         return self._build_with_temp_dir(['sdist', '--formats', 'gztar'],
 
-                                          '.tar.gz', sdist_directory,
 
-                                          config_settings)
 
- class _BuildMetaLegacyBackend(_BuildMetaBackend):
 
-     """Compatibility backend for setuptools
 
-     This is a version of setuptools.build_meta that endeavors
 
-     to maintain backwards
 
-     compatibility with pre-PEP 517 modes of invocation. It
 
-     exists as a temporary
 
-     bridge between the old packaging mechanism and the new
 
-     packaging mechanism,
 
-     and will eventually be removed.
 
-     """
 
-     def run_setup(self, setup_script='setup.py'):
 
-         # In order to maintain compatibility with scripts assuming that
 
-         # the setup.py script is in a directory on the PYTHONPATH, inject
 
-         # '' into sys.path. (pypa/setuptools#1642)
 
-         sys_path = list(sys.path)           # Save the original path
 
-         script_dir = os.path.dirname(os.path.abspath(setup_script))
 
-         if script_dir not in sys.path:
 
-             sys.path.insert(0, script_dir)
 
-         # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to
 
-         # get the directory of the source code. They expect it to refer to the
 
-         # setup.py script.
 
-         sys_argv_0 = sys.argv[0]
 
-         sys.argv[0] = setup_script
 
-         try:
 
-             super(_BuildMetaLegacyBackend,
 
-                   self).run_setup(setup_script=setup_script)
 
-         finally:
 
-             # While PEP 517 frontends should be calling each hook in a fresh
 
-             # subprocess according to the standard (and thus it should not be
 
-             # strictly necessary to restore the old sys.path), we'll restore
 
-             # the original path so that the path manipulation does not persist
 
-             # within the hook after run_setup is called.
 
-             sys.path[:] = sys_path
 
-             sys.argv[0] = sys_argv_0
 
- # The primary backend
 
- _BACKEND = _BuildMetaBackend()
 
- get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel
 
- get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist
 
- prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel
 
- build_wheel = _BACKEND.build_wheel
 
- build_sdist = _BACKEND.build_sdist
 
- # The legacy backend
 
- __legacy__ = _BuildMetaLegacyBackend()
 
 
  |