| """Extensions to the 'distutils' for large or complex distributions""" |
| |
| import functools |
| import os |
| import re |
| import warnings |
| |
| import _distutils_hack.override # noqa: F401 |
| |
| import distutils.core |
| from distutils.errors import DistutilsOptionError |
| from distutils.util import convert_path as _convert_path |
| |
| from ._deprecation_warning import SetuptoolsDeprecationWarning |
| |
| import setuptools.version |
| from setuptools.extension import Extension |
| from setuptools.dist import Distribution |
| from setuptools.depends import Require |
| from setuptools.discovery import PackageFinder, PEP420PackageFinder |
| from . import monkey |
| from . import logging |
| |
| |
| __all__ = [ |
| 'setup', |
| 'Distribution', |
| 'Command', |
| 'Extension', |
| 'Require', |
| 'SetuptoolsDeprecationWarning', |
| 'find_packages', |
| 'find_namespace_packages', |
| ] |
| |
| __version__ = setuptools.version.__version__ |
| |
| bootstrap_install_from = None |
| |
| |
| find_packages = PackageFinder.find |
| find_namespace_packages = PEP420PackageFinder.find |
| |
| |
| def _install_setup_requires(attrs): |
| # Note: do not use `setuptools.Distribution` directly, as |
| # our PEP 517 backend patch `distutils.core.Distribution`. |
| class MinimalDistribution(distutils.core.Distribution): |
| """ |
| A minimal version of a distribution for supporting the |
| fetch_build_eggs interface. |
| """ |
| |
| def __init__(self, attrs): |
| _incl = 'dependency_links', 'setup_requires' |
| filtered = {k: attrs[k] for k in set(_incl) & set(attrs)} |
| super().__init__(filtered) |
| # Prevent accidentally triggering discovery with incomplete set of attrs |
| self.set_defaults._disable() |
| |
| def _get_project_config_files(self, filenames=None): |
| """Ignore ``pyproject.toml``, they are not related to setup_requires""" |
| try: |
| cfg, toml = super()._split_standard_project_metadata(filenames) |
| return cfg, () |
| except Exception: |
| return filenames, () |
| |
| def finalize_options(self): |
| """ |
| Disable finalize_options to avoid building the working set. |
| Ref #2158. |
| """ |
| |
| dist = MinimalDistribution(attrs) |
| |
| # Honor setup.cfg's options. |
| dist.parse_config_files(ignore_option_errors=True) |
| if dist.setup_requires: |
| dist.fetch_build_eggs(dist.setup_requires) |
| |
| |
| def setup(**attrs): |
| # Make sure we have any requirements needed to interpret 'attrs'. |
| logging.configure() |
| _install_setup_requires(attrs) |
| return distutils.core.setup(**attrs) |
| |
| |
| setup.__doc__ = distutils.core.setup.__doc__ |
| |
| |
| _Command = monkey.get_unpatched(distutils.core.Command) |
| |
| |
| class Command(_Command): |
| __doc__ = _Command.__doc__ |
| |
| command_consumes_arguments = False |
| |
| def __init__(self, dist, **kw): |
| """ |
| Construct the command for dist, updating |
| vars(self) with any keyword parameters. |
| """ |
| super().__init__(dist) |
| vars(self).update(kw) |
| |
| def _ensure_stringlike(self, option, what, default=None): |
| val = getattr(self, option) |
| if val is None: |
| setattr(self, option, default) |
| return default |
| elif not isinstance(val, str): |
| raise DistutilsOptionError( |
| "'%s' must be a %s (got `%s`)" % (option, what, val) |
| ) |
| return val |
| |
| def ensure_string_list(self, option): |
| r"""Ensure that 'option' is a list of strings. If 'option' is |
| currently a string, we split it either on /,\s*/ or /\s+/, so |
| "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become |
| ["foo", "bar", "baz"]. |
| """ |
| val = getattr(self, option) |
| if val is None: |
| return |
| elif isinstance(val, str): |
| setattr(self, option, re.split(r',\s*|\s+', val)) |
| else: |
| if isinstance(val, list): |
| ok = all(isinstance(v, str) for v in val) |
| else: |
| ok = False |
| if not ok: |
| raise DistutilsOptionError( |
| "'%s' must be a list of strings (got %r)" % (option, val) |
| ) |
| |
| def reinitialize_command(self, command, reinit_subcommands=0, **kw): |
| cmd = _Command.reinitialize_command(self, command, reinit_subcommands) |
| vars(cmd).update(kw) |
| return cmd |
| |
| |
| def _find_all_simple(path): |
| """ |
| Find all files under 'path' |
| """ |
| results = ( |
| os.path.join(base, file) |
| for base, dirs, files in os.walk(path, followlinks=True) |
| for file in files |
| ) |
| return filter(os.path.isfile, results) |
| |
| |
| def findall(dir=os.curdir): |
| """ |
| Find all files under 'dir' and return the list of full filenames. |
| Unless dir is '.', return full filenames with dir prepended. |
| """ |
| files = _find_all_simple(dir) |
| if dir == os.curdir: |
| make_rel = functools.partial(os.path.relpath, start=dir) |
| files = map(make_rel, files) |
| return list(files) |
| |
| |
| @functools.wraps(_convert_path) |
| def convert_path(pathname): |
| from inspect import cleandoc |
| |
| msg = """ |
| The function `convert_path` is considered internal and not part of the public API. |
| Its direct usage by 3rd-party packages is considered deprecated and the function |
| may be removed in the future. |
| """ |
| warnings.warn(cleandoc(msg), SetuptoolsDeprecationWarning) |
| return _convert_path(pathname) |
| |
| |
| class sic(str): |
| """Treat this string as-is (https://en.wikipedia.org/wiki/Sic)""" |
| |
| |
| # Apply monkey patches |
| monkey.patch_all() |