|
1 | 1 | # -*- coding: utf-8 -*-
|
2 | 2 | __all__ = ['Distribution']
|
3 | 3 |
|
| 4 | +import io |
| 5 | +import sys |
4 | 6 | import re
|
5 | 7 | import os
|
6 | 8 | import warnings
|
|
9 | 11 | import distutils.core
|
10 | 12 | import distutils.cmd
|
11 | 13 | import distutils.dist
|
| 14 | +from distutils.errors import DistutilsOptionError |
| 15 | +from distutils.util import strtobool |
| 16 | +from distutils.debug import DEBUG |
| 17 | +from distutils.fancy_getopt import translate_longopt |
12 | 18 | import itertools
|
13 | 19 |
|
14 |
| - |
15 | 20 | from collections import defaultdict
|
16 | 21 | from email import message_from_file
|
17 | 22 |
|
|
31 | 36 | from setuptools import windows_support
|
32 | 37 | from setuptools.monkey import get_unpatched
|
33 | 38 | from setuptools.config import parse_configuration
|
| 39 | +from .unicode_utils import detect_encoding |
34 | 40 | import pkg_resources
|
35 |
| -from .py36compat import Distribution_parse_config_files |
36 | 41 |
|
37 | 42 | __import__('setuptools.extern.packaging.specifiers')
|
38 | 43 | __import__('setuptools.extern.packaging.version')
|
@@ -332,7 +337,7 @@ def check_packages(dist, attr, value):
|
332 | 337 | _Distribution = get_unpatched(distutils.core.Distribution)
|
333 | 338 |
|
334 | 339 |
|
335 |
| -class Distribution(Distribution_parse_config_files, _Distribution): |
| 340 | +class Distribution(_Distribution): |
336 | 341 | """Distribution with support for features, tests, and package data
|
337 | 342 |
|
338 | 343 | This is an enhanced version of 'distutils.dist.Distribution' that
|
@@ -556,12 +561,125 @@ def _clean_req(self, req):
|
556 | 561 | req.marker = None
|
557 | 562 | return req
|
558 | 563 |
|
| 564 | + def _parse_config_files(self, filenames=None): |
| 565 | + """ |
| 566 | + Adapted from distutils.dist.Distribution.parse_config_files, |
| 567 | + this method provides the same functionality in subtly-improved |
| 568 | + ways. |
| 569 | + """ |
| 570 | + from setuptools.extern.six.moves.configparser import ConfigParser |
| 571 | + |
| 572 | + # Ignore install directory options if we have a venv |
| 573 | + if six.PY3 and sys.prefix != sys.base_prefix: |
| 574 | + ignore_options = [ |
| 575 | + 'install-base', 'install-platbase', 'install-lib', |
| 576 | + 'install-platlib', 'install-purelib', 'install-headers', |
| 577 | + 'install-scripts', 'install-data', 'prefix', 'exec-prefix', |
| 578 | + 'home', 'user', 'root'] |
| 579 | + else: |
| 580 | + ignore_options = [] |
| 581 | + |
| 582 | + ignore_options = frozenset(ignore_options) |
| 583 | + |
| 584 | + if filenames is None: |
| 585 | + filenames = self.find_config_files() |
| 586 | + |
| 587 | + if DEBUG: |
| 588 | + self.announce("Distribution.parse_config_files():") |
| 589 | + |
| 590 | + parser = ConfigParser() |
| 591 | + for filename in filenames: |
| 592 | + with io.open(filename, 'rb') as fp: |
| 593 | + encoding = detect_encoding(fp) |
| 594 | + if DEBUG: |
| 595 | + self.announce(" reading %s [%s]" % ( |
| 596 | + filename, encoding or 'locale') |
| 597 | + ) |
| 598 | + reader = io.TextIOWrapper(fp, encoding=encoding) |
| 599 | + (parser.read_file if six.PY3 else parser.readfp)(reader) |
| 600 | + for section in parser.sections(): |
| 601 | + options = parser.options(section) |
| 602 | + opt_dict = self.get_option_dict(section) |
| 603 | + |
| 604 | + for opt in options: |
| 605 | + if opt != '__name__' and opt not in ignore_options: |
| 606 | + val = parser.get(section, opt) |
| 607 | + opt = opt.replace('-', '_') |
| 608 | + opt_dict[opt] = (filename, val) |
| 609 | + |
| 610 | + # Make the ConfigParser forget everything (so we retain |
| 611 | + # the original filenames that options come from) |
| 612 | + parser.__init__() |
| 613 | + |
| 614 | + # If there was a "global" section in the config file, use it |
| 615 | + # to set Distribution options. |
| 616 | + |
| 617 | + if 'global' in self.command_options: |
| 618 | + for (opt, (src, val)) in self.command_options['global'].items(): |
| 619 | + alias = self.negative_opt.get(opt) |
| 620 | + try: |
| 621 | + if alias: |
| 622 | + setattr(self, alias, not strtobool(val)) |
| 623 | + elif opt in ('verbose', 'dry_run'): # ugh! |
| 624 | + setattr(self, opt, strtobool(val)) |
| 625 | + else: |
| 626 | + setattr(self, opt, val) |
| 627 | + except ValueError as msg: |
| 628 | + raise DistutilsOptionError(msg) |
| 629 | + |
| 630 | + def _set_command_options(self, command_obj, option_dict=None): |
| 631 | + """ |
| 632 | + Set the options for 'command_obj' from 'option_dict'. Basically |
| 633 | + this means copying elements of a dictionary ('option_dict') to |
| 634 | + attributes of an instance ('command'). |
| 635 | +
|
| 636 | + 'command_obj' must be a Command instance. If 'option_dict' is not |
| 637 | + supplied, uses the standard option dictionary for this command |
| 638 | + (from 'self.command_options'). |
| 639 | +
|
| 640 | + (Adopted from distutils.dist.Distribution._set_command_options) |
| 641 | + """ |
| 642 | + command_name = command_obj.get_command_name() |
| 643 | + if option_dict is None: |
| 644 | + option_dict = self.get_option_dict(command_name) |
| 645 | + |
| 646 | + if DEBUG: |
| 647 | + self.announce(" setting options for '%s' command:" % command_name) |
| 648 | + for (option, (source, value)) in option_dict.items(): |
| 649 | + if DEBUG: |
| 650 | + self.announce(" %s = %s (from %s)" % (option, value, |
| 651 | + source)) |
| 652 | + try: |
| 653 | + bool_opts = [translate_longopt(o) |
| 654 | + for o in command_obj.boolean_options] |
| 655 | + except AttributeError: |
| 656 | + bool_opts = [] |
| 657 | + try: |
| 658 | + neg_opt = command_obj.negative_opt |
| 659 | + except AttributeError: |
| 660 | + neg_opt = {} |
| 661 | + |
| 662 | + try: |
| 663 | + is_string = isinstance(value, six.string_types) |
| 664 | + if option in neg_opt and is_string: |
| 665 | + setattr(command_obj, neg_opt[option], not strtobool(value)) |
| 666 | + elif option in bool_opts and is_string: |
| 667 | + setattr(command_obj, option, strtobool(value)) |
| 668 | + elif hasattr(command_obj, option): |
| 669 | + setattr(command_obj, option, value) |
| 670 | + else: |
| 671 | + raise DistutilsOptionError( |
| 672 | + "error in %s: command '%s' has no such option '%s'" |
| 673 | + % (source, command_name, option)) |
| 674 | + except ValueError as msg: |
| 675 | + raise DistutilsOptionError(msg) |
| 676 | + |
559 | 677 | def parse_config_files(self, filenames=None, ignore_option_errors=False):
|
560 | 678 | """Parses configuration files from various levels
|
561 | 679 | and loads configuration.
|
562 | 680 |
|
563 | 681 | """
|
564 |
| - _Distribution.parse_config_files(self, filenames=filenames) |
| 682 | + self._parse_config_files(filenames=filenames) |
565 | 683 |
|
566 | 684 | parse_configuration(self, self.command_options,
|
567 | 685 | ignore_option_errors=ignore_option_errors)
|
|
0 commit comments