diff options
Diffstat (limited to 'setuptools/dist.py')
-rw-r--r-- | setuptools/dist.py | 126 |
1 files changed, 122 insertions, 4 deletions
diff --git a/setuptools/dist.py b/setuptools/dist.py index 7062ae8d..b8551228 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- __all__ = ['Distribution'] +import io +import sys import re import os import warnings @@ -9,9 +11,12 @@ import distutils.log import distutils.core import distutils.cmd import distutils.dist +from distutils.errors import DistutilsOptionError +from distutils.util import strtobool +from distutils.debug import DEBUG +from distutils.fancy_getopt import translate_longopt import itertools - from collections import defaultdict from email import message_from_file @@ -31,8 +36,8 @@ from setuptools.depends import Require from setuptools import windows_support from setuptools.monkey import get_unpatched from setuptools.config import parse_configuration +from .unicode_utils import detect_encoding import pkg_resources -from .py36compat import Distribution_parse_config_files __import__('setuptools.extern.packaging.specifiers') __import__('setuptools.extern.packaging.version') @@ -332,7 +337,7 @@ def check_packages(dist, attr, value): _Distribution = get_unpatched(distutils.core.Distribution) -class Distribution(Distribution_parse_config_files, _Distribution): +class Distribution(_Distribution): """Distribution with support for features, tests, and package data This is an enhanced version of 'distutils.dist.Distribution' that @@ -556,12 +561,125 @@ class Distribution(Distribution_parse_config_files, _Distribution): req.marker = None return req + def _parse_config_files(self, filenames=None): + """ + Adapted from distutils.dist.Distribution.parse_config_files, + this method provides the same functionality in subtly-improved + ways. + """ + from setuptools.extern.six.moves.configparser import ConfigParser + + # Ignore install directory options if we have a venv + if six.PY3 and sys.prefix != sys.base_prefix: + ignore_options = [ + 'install-base', 'install-platbase', 'install-lib', + 'install-platlib', 'install-purelib', 'install-headers', + 'install-scripts', 'install-data', 'prefix', 'exec-prefix', + 'home', 'user', 'root'] + else: + ignore_options = [] + + ignore_options = frozenset(ignore_options) + + if filenames is None: + filenames = self.find_config_files() + + if DEBUG: + self.announce("Distribution.parse_config_files():") + + parser = ConfigParser() + for filename in filenames: + with io.open(filename, 'rb') as fp: + encoding = detect_encoding(fp) + if DEBUG: + self.announce(" reading %s [%s]" % ( + filename, encoding or 'locale') + ) + reader = io.TextIOWrapper(fp, encoding=encoding) + (parser.read_file if six.PY3 else parser.readfp)(reader) + for section in parser.sections(): + options = parser.options(section) + opt_dict = self.get_option_dict(section) + + for opt in options: + if opt != '__name__' and opt not in ignore_options: + val = parser.get(section, opt) + opt = opt.replace('-', '_') + opt_dict[opt] = (filename, val) + + # Make the ConfigParser forget everything (so we retain + # the original filenames that options come from) + parser.__init__() + + # If there was a "global" section in the config file, use it + # to set Distribution options. + + if 'global' in self.command_options: + for (opt, (src, val)) in self.command_options['global'].items(): + alias = self.negative_opt.get(opt) + try: + if alias: + setattr(self, alias, not strtobool(val)) + elif opt in ('verbose', 'dry_run'): # ugh! + setattr(self, opt, strtobool(val)) + else: + setattr(self, opt, val) + except ValueError as msg: + raise DistutilsOptionError(msg) + + def _set_command_options(self, command_obj, option_dict=None): + """ + Set the options for 'command_obj' from 'option_dict'. Basically + this means copying elements of a dictionary ('option_dict') to + attributes of an instance ('command'). + + 'command_obj' must be a Command instance. If 'option_dict' is not + supplied, uses the standard option dictionary for this command + (from 'self.command_options'). + + (Adopted from distutils.dist.Distribution._set_command_options) + """ + command_name = command_obj.get_command_name() + if option_dict is None: + option_dict = self.get_option_dict(command_name) + + if DEBUG: + self.announce(" setting options for '%s' command:" % command_name) + for (option, (source, value)) in option_dict.items(): + if DEBUG: + self.announce(" %s = %s (from %s)" % (option, value, + source)) + try: + bool_opts = [translate_longopt(o) + for o in command_obj.boolean_options] + except AttributeError: + bool_opts = [] + try: + neg_opt = command_obj.negative_opt + except AttributeError: + neg_opt = {} + + try: + is_string = isinstance(value, six.string_types) + if option in neg_opt and is_string: + setattr(command_obj, neg_opt[option], not strtobool(value)) + elif option in bool_opts and is_string: + setattr(command_obj, option, strtobool(value)) + elif hasattr(command_obj, option): + setattr(command_obj, option, value) + else: + raise DistutilsOptionError( + "error in %s: command '%s' has no such option '%s'" + % (source, command_name, option)) + except ValueError as msg: + raise DistutilsOptionError(msg) + def parse_config_files(self, filenames=None, ignore_option_errors=False): """Parses configuration files from various levels and loads configuration. """ - _Distribution.parse_config_files(self, filenames=filenames) + self._parse_config_files(filenames=filenames) parse_configuration(self, self.command_options, ignore_option_errors=ignore_option_errors) |