summaryrefslogtreecommitdiff
path: root/setuptools/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/config.py')
-rw-r--r--setuptools/config.py66
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(