diff options
Diffstat (limited to 'setuptools/config.py')
-rw-r--r-- | setuptools/config.py | 66 |
1 files changed, 50 insertions, 16 deletions
diff --git a/setuptools/config.py b/setuptools/config.py index 9b9a0c45..af3a3bcb 100644 --- a/setuptools/config.py +++ b/setuptools/config.py @@ -1,22 +1,58 @@ -from __future__ import absolute_import, unicode_literals +import ast import io import os import sys import warnings import functools +import importlib from collections import defaultdict from functools import partial from functools import wraps -from importlib import import_module +import contextlib from distutils.errors import DistutilsOptionError, DistutilsFileError from setuptools.extern.packaging.version import LegacyVersion, parse from setuptools.extern.packaging.specifiers import SpecifierSet -from setuptools.extern.six import string_types, PY3 -__metaclass__ = type +class StaticModule: + """ + Attempt to load the module by the name + """ + def __init__(self, name): + spec = importlib.util.find_spec(name) + with open(spec.origin) as strm: + src = strm.read() + module = ast.parse(src) + vars(self).update(locals()) + del self.self + + def __getattr__(self, attr): + try: + return next( + ast.literal_eval(statement.value) + for statement in self.module.body + if isinstance(statement, ast.Assign) + for target in statement.targets + if isinstance(target, ast.Name) and target.id == attr + ) + except Exception as e: + raise AttributeError( + "{self.name} has no attribute {attr}".format(**locals()) + ) from e + + +@contextlib.contextmanager +def patch_path(path): + """ + Add path to front of sys.path for the duration of the context. + """ + try: + sys.path.insert(0, path) + yield + finally: + sys.path.remove(path) def read_configuration( @@ -283,7 +319,7 @@ class ConfigHandler: """ include_directive = 'file:' - if not isinstance(value, string_types): + if not isinstance(value, str): return value if not value.startswith(include_directive): @@ -344,15 +380,16 @@ class ConfigHandler: elif '' in package_dir: # A custom parent directory was specified for all root modules parent_path = os.path.join(os.getcwd(), package_dir['']) - sys.path.insert(0, parent_path) - try: - module = import_module(module_name) - value = getattr(module, attr_name) - finally: - sys.path = sys.path[1:] + with patch_path(parent_path): + try: + # attempt to load value statically + return getattr(StaticModule(module_name), attr_name) + except Exception: + # fallback to simple import + module = importlib.import_module(module_name) - return value + return getattr(module, attr_name) @classmethod def _get_parser_compound(cls, *parse_methods): @@ -517,7 +554,7 @@ class ConfigMetadataHandler(ConfigHandler): if callable(version): version = version() - if not isinstance(version, string_types): + if not isinstance(version, str): if hasattr(version, '__iter__'): version = '.'.join(map(str, version)) else: @@ -572,9 +609,6 @@ class ConfigOptionsHandler(ConfigHandler): return self._parse_list(value) findns = trimmed_value == find_directives[1] - if findns and not PY3: - raise DistutilsOptionError( - 'find_namespace: directive is unsupported on Python < 3.3') # Read function arguments from a dedicated section. find_kwargs = self.parse_section_packages__find( |