1# -*- coding: utf-8 -*-
2__all__ = ['Distribution']
3
4import io
5import sys
6import re
7import os
8import warnings
9import numbers
10import distutils.log
11import distutils.core
12import distutils.cmd
13import distutils.dist
14from distutils.util import strtobool
15from distutils.debug import DEBUG
16from distutils.fancy_getopt import translate_longopt
17import itertools
18
19from collections import defaultdict
20from email import message_from_file
21
22from distutils.errors import (
23    DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError,
24)
25from distutils.util import rfc822_escape
26from distutils.version import StrictVersion
27
28from setuptools.extern import six
29from setuptools.extern import packaging
30from setuptools.extern import ordered_set
31from setuptools.extern.six.moves import map, filter, filterfalse
32
33from . import SetuptoolsDeprecationWarning
34
35from setuptools.depends import Require
36from setuptools import windows_support
37from setuptools.monkey import get_unpatched
38from setuptools.config import parse_configuration
39import pkg_resources
40
41__import__('setuptools.extern.packaging.specifiers')
42__import__('setuptools.extern.packaging.version')
43
44
45def _get_unpatched(cls):
46    warnings.warn("Do not call this function", DistDeprecationWarning)
47    return get_unpatched(cls)
48
49
50def get_metadata_version(self):
51    mv = getattr(self, 'metadata_version', None)
52
53    if mv is None:
54        if self.long_description_content_type or self.provides_extras:
55            mv = StrictVersion('2.1')
56        elif (self.maintainer is not None or
57              self.maintainer_email is not None or
58              getattr(self, 'python_requires', None) is not None or
59              self.project_urls):
60            mv = StrictVersion('1.2')
61        elif (self.provides or self.requires or self.obsoletes or
62                self.classifiers or self.download_url):
63            mv = StrictVersion('1.1')
64        else:
65            mv = StrictVersion('1.0')
66
67        self.metadata_version = mv
68
69    return mv
70
71
72def read_pkg_file(self, file):
73    """Reads the metadata values from a file object."""
74    msg = message_from_file(file)
75
76    def _read_field(name):
77        value = msg[name]
78        if value == 'UNKNOWN':
79            return None
80        return value
81
82    def _read_list(name):
83        values = msg.get_all(name, None)
84        if values == []:
85            return None
86        return values
87
88    self.metadata_version = StrictVersion(msg['metadata-version'])
89    self.name = _read_field('name')
90    self.version = _read_field('version')
91    self.description = _read_field('summary')
92    # we are filling author only.
93    self.author = _read_field('author')
94    self.maintainer = None
95    self.author_email = _read_field('author-email')
96    self.maintainer_email = None
97    self.url = _read_field('home-page')
98    self.license = _read_field('license')
99
100    if 'download-url' in msg:
101        self.download_url = _read_field('download-url')
102    else:
103        self.download_url = None
104
105    self.long_description = _read_field('description')
106    self.description = _read_field('summary')
107
108    if 'keywords' in msg:
109        self.keywords = _read_field('keywords').split(',')
110
111    self.platforms = _read_list('platform')
112    self.classifiers = _read_list('classifier')
113
114    # PEP 314 - these fields only exist in 1.1
115    if self.metadata_version == StrictVersion('1.1'):
116        self.requires = _read_list('requires')
117        self.provides = _read_list('provides')
118        self.obsoletes = _read_list('obsoletes')
119    else:
120        self.requires = None
121        self.provides = None
122        self.obsoletes = None
123
124
125# Based on Python 3.5 version
126def write_pkg_file(self, file):
127    """Write the PKG-INFO format data to a file object.
128    """
129    version = self.get_metadata_version()
130
131    if six.PY2:
132        def write_field(key, value):
133            file.write("%s: %s\n" % (key, self._encode_field(value)))
134    else:
135        def write_field(key, value):
136            file.write("%s: %s\n" % (key, value))
137
138    write_field('Metadata-Version', str(version))
139    write_field('Name', self.get_name())
140    write_field('Version', self.get_version())
141    write_field('Summary', self.get_description())
142    write_field('Home-page', self.get_url())
143
144    if version < StrictVersion('1.2'):
145        write_field('Author', self.get_contact())
146        write_field('Author-email', self.get_contact_email())
147    else:
148        optional_fields = (
149            ('Author', 'author'),
150            ('Author-email', 'author_email'),
151            ('Maintainer', 'maintainer'),
152            ('Maintainer-email', 'maintainer_email'),
153        )
154
155        for field, attr in optional_fields:
156            attr_val = getattr(self, attr)
157
158            if attr_val is not None:
159                write_field(field, attr_val)
160
161    write_field('License', self.get_license())
162    if self.download_url:
163        write_field('Download-URL', self.download_url)
164    for project_url in self.project_urls.items():
165        write_field('Project-URL',  '%s, %s' % project_url)
166
167    long_desc = rfc822_escape(self.get_long_description())
168    write_field('Description', long_desc)
169
170    keywords = ','.join(self.get_keywords())
171    if keywords:
172        write_field('Keywords', keywords)
173
174    if version >= StrictVersion('1.2'):
175        for platform in self.get_platforms():
176            write_field('Platform', platform)
177    else:
178        self._write_list(file, 'Platform', self.get_platforms())
179
180    self._write_list(file, 'Classifier', self.get_classifiers())
181
182    # PEP 314
183    self._write_list(file, 'Requires', self.get_requires())
184    self._write_list(file, 'Provides', self.get_provides())
185    self._write_list(file, 'Obsoletes', self.get_obsoletes())
186
187    # Setuptools specific for PEP 345
188    if hasattr(self, 'python_requires'):
189        write_field('Requires-Python', self.python_requires)
190
191    # PEP 566
192    if self.long_description_content_type:
193        write_field(
194            'Description-Content-Type',
195            self.long_description_content_type
196        )
197    if self.provides_extras:
198        for extra in self.provides_extras:
199            write_field('Provides-Extra', extra)
200
201
202sequence = tuple, list
203
204
205def check_importable(dist, attr, value):
206    try:
207        ep = pkg_resources.EntryPoint.parse('x=' + value)
208        assert not ep.extras
209    except (TypeError, ValueError, AttributeError, AssertionError):
210        raise DistutilsSetupError(
211            "%r must be importable 'module:attrs' string (got %r)"
212            % (attr, value)
213        )
214
215
216def assert_string_list(dist, attr, value):
217    """Verify that value is a string list"""
218    try:
219        # verify that value is a list or tuple to exclude unordered
220        # or single-use iterables
221        assert isinstance(value, (list, tuple))
222        # verify that elements of value are strings
223        assert ''.join(value) != value
224    except (TypeError, ValueError, AttributeError, AssertionError):
225        raise DistutilsSetupError(
226            "%r must be a list of strings (got %r)" % (attr, value)
227        )
228
229
230def check_nsp(dist, attr, value):
231    """Verify that namespace packages are valid"""
232    ns_packages = value
233    assert_string_list(dist, attr, ns_packages)
234    for nsp in ns_packages:
235        if not dist.has_contents_for(nsp):
236            raise DistutilsSetupError(
237                "Distribution contains no modules or packages for " +
238                "namespace package %r" % nsp
239            )
240        parent, sep, child = nsp.rpartition('.')
241        if parent and parent not in ns_packages:
242            distutils.log.warn(
243                "WARNING: %r is declared as a package namespace, but %r"
244                " is not: please correct this in setup.py", nsp, parent
245            )
246
247
248def check_extras(dist, attr, value):
249    """Verify that extras_require mapping is valid"""
250    try:
251        list(itertools.starmap(_check_extra, value.items()))
252    except (TypeError, ValueError, AttributeError):
253        raise DistutilsSetupError(
254            "'extras_require' must be a dictionary whose values are "
255            "strings or lists of strings containing valid project/version "
256            "requirement specifiers."
257        )
258
259
260def _check_extra(extra, reqs):
261    name, sep, marker = extra.partition(':')
262    if marker and pkg_resources.invalid_marker(marker):
263        raise DistutilsSetupError("Invalid environment marker: " + marker)
264    list(pkg_resources.parse_requirements(reqs))
265
266
267def assert_bool(dist, attr, value):
268    """Verify that value is True, False, 0, or 1"""
269    if bool(value) != value:
270        tmpl = "{attr!r} must be a boolean value (got {value!r})"
271        raise DistutilsSetupError(tmpl.format(attr=attr, value=value))
272
273
274def check_requirements(dist, attr, value):
275    """Verify that install_requires is a valid requirements list"""
276    try:
277        list(pkg_resources.parse_requirements(value))
278        if isinstance(value, (dict, set)):
279            raise TypeError("Unordered types are not allowed")
280    except (TypeError, ValueError) as error:
281        tmpl = (
282            "{attr!r} must be a string or list of strings "
283            "containing valid project/version requirement specifiers; {error}"
284        )
285        raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
286
287
288def check_specifier(dist, attr, value):
289    """Verify that value is a valid version specifier"""
290    try:
291        packaging.specifiers.SpecifierSet(value)
292    except packaging.specifiers.InvalidSpecifier as error:
293        tmpl = (
294            "{attr!r} must be a string "
295            "containing valid version specifiers; {error}"
296        )
297        raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
298
299
300def check_entry_points(dist, attr, value):
301    """Verify that entry_points map is parseable"""
302    try:
303        pkg_resources.EntryPoint.parse_map(value)
304    except ValueError as e:
305        raise DistutilsSetupError(e)
306
307
308def check_test_suite(dist, attr, value):
309    if not isinstance(value, six.string_types):
310        raise DistutilsSetupError("test_suite must be a string")
311
312
313def check_package_data(dist, attr, value):
314    """Verify that value is a dictionary of package names to glob lists"""
315    if not isinstance(value, dict):
316        raise DistutilsSetupError(
317            "{!r} must be a dictionary mapping package names to lists of "
318            "string wildcard patterns".format(attr))
319    for k, v in value.items():
320        if not isinstance(k, six.string_types):
321            raise DistutilsSetupError(
322                "keys of {!r} dict must be strings (got {!r})"
323                .format(attr, k)
324            )
325        assert_string_list(dist, 'values of {!r} dict'.format(attr), v)
326
327
328def check_packages(dist, attr, value):
329    for pkgname in value:
330        if not re.match(r'\w+(\.\w+)*', pkgname):
331            distutils.log.warn(
332                "WARNING: %r not a valid package name; please use only "
333                ".-separated package names in setup.py", pkgname
334            )
335
336
337_Distribution = get_unpatched(distutils.core.Distribution)
338
339
340class Distribution(_Distribution):
341    """Distribution with support for features, tests, and package data
342
343    This is an enhanced version of 'distutils.dist.Distribution' that
344    effectively adds the following new optional keyword arguments to 'setup()':
345
346     'install_requires' -- a string or sequence of strings specifying project
347        versions that the distribution requires when installed, in the format
348        used by 'pkg_resources.require()'.  They will be installed
349        automatically when the package is installed.  If you wish to use
350        packages that are not available in PyPI, or want to give your users an
351        alternate download location, you can add a 'find_links' option to the
352        '[easy_install]' section of your project's 'setup.cfg' file, and then
353        setuptools will scan the listed web pages for links that satisfy the
354        requirements.
355
356     'extras_require' -- a dictionary mapping names of optional "extras" to the
357        additional requirement(s) that using those extras incurs. For example,
358        this::
359
360            extras_require = dict(reST = ["docutils>=0.3", "reSTedit"])
361
362        indicates that the distribution can optionally provide an extra
363        capability called "reST", but it can only be used if docutils and
364        reSTedit are installed.  If the user installs your package using
365        EasyInstall and requests one of your extras, the corresponding
366        additional requirements will be installed if needed.
367
368     'features' **deprecated** -- a dictionary mapping option names to
369        'setuptools.Feature'
370        objects.  Features are a portion of the distribution that can be
371        included or excluded based on user options, inter-feature dependencies,
372        and availability on the current system.  Excluded features are omitted
373        from all setup commands, including source and binary distributions, so
374        you can create multiple distributions from the same source tree.
375        Feature names should be valid Python identifiers, except that they may
376        contain the '-' (minus) sign.  Features can be included or excluded
377        via the command line options '--with-X' and '--without-X', where 'X' is
378        the name of the feature.  Whether a feature is included by default, and
379        whether you are allowed to control this from the command line, is
380        determined by the Feature object.  See the 'Feature' class for more
381        information.
382
383     'test_suite' -- the name of a test suite to run for the 'test' command.
384        If the user runs 'python setup.py test', the package will be installed,
385        and the named test suite will be run.  The format is the same as
386        would be used on a 'unittest.py' command line.  That is, it is the
387        dotted name of an object to import and call to generate a test suite.
388
389     'package_data' -- a dictionary mapping package names to lists of filenames
390        or globs to use to find data files contained in the named packages.
391        If the dictionary has filenames or globs listed under '""' (the empty
392        string), those names will be searched for in every package, in addition
393        to any names for the specific package.  Data files found using these
394        names/globs will be installed along with the package, in the same
395        location as the package.  Note that globs are allowed to reference
396        the contents of non-package subdirectories, as long as you use '/' as
397        a path separator.  (Globs are automatically converted to
398        platform-specific paths at runtime.)
399
400    In addition to these new keywords, this class also has several new methods
401    for manipulating the distribution's contents.  For example, the 'include()'
402    and 'exclude()' methods can be thought of as in-place add and subtract
403    commands that add or remove packages, modules, extensions, and so on from
404    the distribution.  They are used by the feature subsystem to configure the
405    distribution for the included and excluded features.
406    """
407
408    _DISTUTILS_UNSUPPORTED_METADATA = {
409        'long_description_content_type': None,
410        'project_urls': dict,
411        'provides_extras': ordered_set.OrderedSet,
412        'license_files': ordered_set.OrderedSet,
413    }
414
415    _patched_dist = None
416
417    def patch_missing_pkg_info(self, attrs):
418        # Fake up a replacement for the data that would normally come from
419        # PKG-INFO, but which might not yet be built if this is a fresh
420        # checkout.
421        #
422        if not attrs or 'name' not in attrs or 'version' not in attrs:
423            return
424        key = pkg_resources.safe_name(str(attrs['name'])).lower()
425        dist = pkg_resources.working_set.by_key.get(key)
426        if dist is not None and not dist.has_metadata('PKG-INFO'):
427            dist._version = pkg_resources.safe_version(str(attrs['version']))
428            self._patched_dist = dist
429
430    def __init__(self, attrs=None):
431        have_package_data = hasattr(self, "package_data")
432        if not have_package_data:
433            self.package_data = {}
434        attrs = attrs or {}
435        if 'features' in attrs or 'require_features' in attrs:
436            Feature.warn_deprecated()
437        self.require_features = []
438        self.features = {}
439        self.dist_files = []
440        # Filter-out setuptools' specific options.
441        self.src_root = attrs.pop("src_root", None)
442        self.patch_missing_pkg_info(attrs)
443        self.dependency_links = attrs.pop('dependency_links', [])
444        self.setup_requires = attrs.pop('setup_requires', [])
445        for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
446            vars(self).setdefault(ep.name, None)
447        _Distribution.__init__(self, {
448            k: v for k, v in attrs.items()
449            if k not in self._DISTUTILS_UNSUPPORTED_METADATA
450        })
451
452        # Fill-in missing metadata fields not supported by distutils.
453        # Note some fields may have been set by other tools (e.g. pbr)
454        # above; they are taken preferrentially to setup() arguments
455        for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items():
456            for source in self.metadata.__dict__, attrs:
457                if option in source:
458                    value = source[option]
459                    break
460            else:
461                value = default() if default else None
462            setattr(self.metadata, option, value)
463
464        if isinstance(self.metadata.version, numbers.Number):
465            # Some people apparently take "version number" too literally :)
466            self.metadata.version = str(self.metadata.version)
467
468        if self.metadata.version is not None:
469            try:
470                ver = packaging.version.Version(self.metadata.version)
471                normalized_version = str(ver)
472                if self.metadata.version != normalized_version:
473                    warnings.warn(
474                        "Normalizing '%s' to '%s'" % (
475                            self.metadata.version,
476                            normalized_version,
477                        )
478                    )
479                    self.metadata.version = normalized_version
480            except (packaging.version.InvalidVersion, TypeError):
481                warnings.warn(
482                    "The version specified (%r) is an invalid version, this "
483                    "may not work as expected with newer versions of "
484                    "setuptools, pip, and PyPI. Please see PEP 440 for more "
485                    "details." % self.metadata.version
486                )
487        self._finalize_requires()
488
489    def _finalize_requires(self):
490        """
491        Set `metadata.python_requires` and fix environment markers
492        in `install_requires` and `extras_require`.
493        """
494        if getattr(self, 'python_requires', None):
495            self.metadata.python_requires = self.python_requires
496
497        if getattr(self, 'extras_require', None):
498            for extra in self.extras_require.keys():
499                # Since this gets called multiple times at points where the
500                # keys have become 'converted' extras, ensure that we are only
501                # truly adding extras we haven't seen before here.
502                extra = extra.split(':')[0]
503                if extra:
504                    self.metadata.provides_extras.add(extra)
505
506        self._convert_extras_requirements()
507        self._move_install_requirements_markers()
508
509    def _convert_extras_requirements(self):
510        """
511        Convert requirements in `extras_require` of the form
512        `"extra": ["barbazquux; {marker}"]` to
513        `"extra:{marker}": ["barbazquux"]`.
514        """
515        spec_ext_reqs = getattr(self, 'extras_require', None) or {}
516        self._tmp_extras_require = defaultdict(list)
517        for section, v in spec_ext_reqs.items():
518            # Do not strip empty sections.
519            self._tmp_extras_require[section]
520            for r in pkg_resources.parse_requirements(v):
521                suffix = self._suffix_for(r)
522                self._tmp_extras_require[section + suffix].append(r)
523
524    @staticmethod
525    def _suffix_for(req):
526        """
527        For a requirement, return the 'extras_require' suffix for
528        that requirement.
529        """
530        return ':' + str(req.marker) if req.marker else ''
531
532    def _move_install_requirements_markers(self):
533        """
534        Move requirements in `install_requires` that are using environment
535        markers `extras_require`.
536        """
537
538        # divide the install_requires into two sets, simple ones still
539        # handled by install_requires and more complex ones handled
540        # by extras_require.
541
542        def is_simple_req(req):
543            return not req.marker
544
545        spec_inst_reqs = getattr(self, 'install_requires', None) or ()
546        inst_reqs = list(pkg_resources.parse_requirements(spec_inst_reqs))
547        simple_reqs = filter(is_simple_req, inst_reqs)
548        complex_reqs = filterfalse(is_simple_req, inst_reqs)
549        self.install_requires = list(map(str, simple_reqs))
550
551        for r in complex_reqs:
552            self._tmp_extras_require[':' + str(r.marker)].append(r)
553        self.extras_require = dict(
554            (k, [str(r) for r in map(self._clean_req, v)])
555            for k, v in self._tmp_extras_require.items()
556        )
557
558    def _clean_req(self, req):
559        """
560        Given a Requirement, remove environment markers and return it.
561        """
562        req.marker = None
563        return req
564
565    def _parse_config_files(self, filenames=None):
566        """
567        Adapted from distutils.dist.Distribution.parse_config_files,
568        this method provides the same functionality in subtly-improved
569        ways.
570        """
571        from setuptools.extern.six.moves.configparser import ConfigParser
572
573        # Ignore install directory options if we have a venv
574        if not six.PY2 and sys.prefix != sys.base_prefix:
575            ignore_options = [
576                'install-base', 'install-platbase', 'install-lib',
577                'install-platlib', 'install-purelib', 'install-headers',
578                'install-scripts', 'install-data', 'prefix', 'exec-prefix',
579                'home', 'user', 'root']
580        else:
581            ignore_options = []
582
583        ignore_options = frozenset(ignore_options)
584
585        if filenames is None:
586            filenames = self.find_config_files()
587
588        if DEBUG:
589            self.announce("Distribution.parse_config_files():")
590
591        parser = ConfigParser()
592        for filename in filenames:
593            with io.open(filename, encoding='utf-8') as reader:
594                if DEBUG:
595                    self.announce("  reading {filename}".format(**locals()))
596                (parser.readfp if six.PY2 else parser.read_file)(reader)
597            for section in parser.sections():
598                options = parser.options(section)
599                opt_dict = self.get_option_dict(section)
600
601                for opt in options:
602                    if opt != '__name__' and opt not in ignore_options:
603                        val = self._try_str(parser.get(section, opt))
604                        opt = opt.replace('-', '_')
605                        opt_dict[opt] = (filename, val)
606
607            # Make the ConfigParser forget everything (so we retain
608            # the original filenames that options come from)
609            parser.__init__()
610
611        # If there was a "global" section in the config file, use it
612        # to set Distribution options.
613
614        if 'global' in self.command_options:
615            for (opt, (src, val)) in self.command_options['global'].items():
616                alias = self.negative_opt.get(opt)
617                try:
618                    if alias:
619                        setattr(self, alias, not strtobool(val))
620                    elif opt in ('verbose', 'dry_run'):  # ugh!
621                        setattr(self, opt, strtobool(val))
622                    else:
623                        setattr(self, opt, val)
624                except ValueError as msg:
625                    raise DistutilsOptionError(msg)
626
627    @staticmethod
628    def _try_str(val):
629        """
630        On Python 2, much of distutils relies on string values being of
631        type 'str' (bytes) and not unicode text. If the value can be safely
632        encoded to bytes using the default encoding, prefer that.
633
634        Why the default encoding? Because that value can be implicitly
635        decoded back to text if needed.
636
637        Ref #1653
638        """
639        if not six.PY2:
640            return val
641        try:
642            return val.encode()
643        except UnicodeEncodeError:
644            pass
645        return val
646
647    def _set_command_options(self, command_obj, option_dict=None):
648        """
649        Set the options for 'command_obj' from 'option_dict'.  Basically
650        this means copying elements of a dictionary ('option_dict') to
651        attributes of an instance ('command').
652
653        'command_obj' must be a Command instance.  If 'option_dict' is not
654        supplied, uses the standard option dictionary for this command
655        (from 'self.command_options').
656
657        (Adopted from distutils.dist.Distribution._set_command_options)
658        """
659        command_name = command_obj.get_command_name()
660        if option_dict is None:
661            option_dict = self.get_option_dict(command_name)
662
663        if DEBUG:
664            self.announce("  setting options for '%s' command:" % command_name)
665        for (option, (source, value)) in option_dict.items():
666            if DEBUG:
667                self.announce("    %s = %s (from %s)" % (option, value,
668                                                         source))
669            try:
670                bool_opts = [translate_longopt(o)
671                             for o in command_obj.boolean_options]
672            except AttributeError:
673                bool_opts = []
674            try:
675                neg_opt = command_obj.negative_opt
676            except AttributeError:
677                neg_opt = {}
678
679            try:
680                is_string = isinstance(value, six.string_types)
681                if option in neg_opt and is_string:
682                    setattr(command_obj, neg_opt[option], not strtobool(value))
683                elif option in bool_opts and is_string:
684                    setattr(command_obj, option, strtobool(value))
685                elif hasattr(command_obj, option):
686                    setattr(command_obj, option, value)
687                else:
688                    raise DistutilsOptionError(
689                        "error in %s: command '%s' has no such option '%s'"
690                        % (source, command_name, option))
691            except ValueError as msg:
692                raise DistutilsOptionError(msg)
693
694    def parse_config_files(self, filenames=None, ignore_option_errors=False):
695        """Parses configuration files from various levels
696        and loads configuration.
697
698        """
699        self._parse_config_files(filenames=filenames)
700
701        parse_configuration(self, self.command_options,
702                            ignore_option_errors=ignore_option_errors)
703        self._finalize_requires()
704
705    def parse_command_line(self):
706        """Process features after parsing command line options"""
707        result = _Distribution.parse_command_line(self)
708        if self.features:
709            self._finalize_features()
710        return result
711
712    def _feature_attrname(self, name):
713        """Convert feature name to corresponding option attribute name"""
714        return 'with_' + name.replace('-', '_')
715
716    def fetch_build_eggs(self, requires):
717        """Resolve pre-setup requirements"""
718        resolved_dists = pkg_resources.working_set.resolve(
719            pkg_resources.parse_requirements(requires),
720            installer=self.fetch_build_egg,
721            replace_conflicting=True,
722        )
723        for dist in resolved_dists:
724            pkg_resources.working_set.add(dist, replace=True)
725        return resolved_dists
726
727    def finalize_options(self):
728        """
729        Allow plugins to apply arbitrary operations to the
730        distribution. Each hook may optionally define a 'order'
731        to influence the order of execution. Smaller numbers
732        go first and the default is 0.
733        """
734        group = 'setuptools.finalize_distribution_options'
735
736        def by_order(hook):
737            return getattr(hook, 'order', 0)
738        eps = map(lambda e: e.load(), pkg_resources.iter_entry_points(group))
739        for ep in sorted(eps, key=by_order):
740            ep(self)
741
742    def _finalize_setup_keywords(self):
743        for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
744            value = getattr(self, ep.name, None)
745            if value is not None:
746                ep.require(installer=self.fetch_build_egg)
747                ep.load()(self, ep.name, value)
748
749    def _finalize_2to3_doctests(self):
750        if getattr(self, 'convert_2to3_doctests', None):
751            # XXX may convert to set here when we can rely on set being builtin
752            self.convert_2to3_doctests = [
753                os.path.abspath(p)
754                for p in self.convert_2to3_doctests
755            ]
756        else:
757            self.convert_2to3_doctests = []
758
759    def get_egg_cache_dir(self):
760        egg_cache_dir = os.path.join(os.curdir, '.eggs')
761        if not os.path.exists(egg_cache_dir):
762            os.mkdir(egg_cache_dir)
763            windows_support.hide_file(egg_cache_dir)
764            readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
765            with open(readme_txt_filename, 'w') as f:
766                f.write('This directory contains eggs that were downloaded '
767                        'by setuptools to build, test, and run plug-ins.\n\n')
768                f.write('This directory caches those eggs to prevent '
769                        'repeated downloads.\n\n')
770                f.write('However, it is safe to delete this directory.\n\n')
771
772        return egg_cache_dir
773
774    def fetch_build_egg(self, req):
775        """Fetch an egg needed for building"""
776        from setuptools.installer import fetch_build_egg
777        return fetch_build_egg(self, req)
778
779    def _finalize_feature_opts(self):
780        """Add --with-X/--without-X options based on optional features"""
781
782        if not self.features:
783            return
784
785        go = []
786        no = self.negative_opt.copy()
787
788        for name, feature in self.features.items():
789            self._set_feature(name, None)
790            feature.validate(self)
791
792            if feature.optional:
793                descr = feature.description
794                incdef = ' (default)'
795                excdef = ''
796                if not feature.include_by_default():
797                    excdef, incdef = incdef, excdef
798
799                new = (
800                    ('with-' + name, None, 'include ' + descr + incdef),
801                    ('without-' + name, None, 'exclude ' + descr + excdef),
802                )
803                go.extend(new)
804                no['without-' + name] = 'with-' + name
805
806        self.global_options = self.feature_options = go + self.global_options
807        self.negative_opt = self.feature_negopt = no
808
809    def _finalize_features(self):
810        """Add/remove features and resolve dependencies between them"""
811
812        # First, flag all the enabled items (and thus their dependencies)
813        for name, feature in self.features.items():
814            enabled = self.feature_is_included(name)
815            if enabled or (enabled is None and feature.include_by_default()):
816                feature.include_in(self)
817                self._set_feature(name, 1)
818
819        # Then disable the rest, so that off-by-default features don't
820        # get flagged as errors when they're required by an enabled feature
821        for name, feature in self.features.items():
822            if not self.feature_is_included(name):
823                feature.exclude_from(self)
824                self._set_feature(name, 0)
825
826    def get_command_class(self, command):
827        """Pluggable version of get_command_class()"""
828        if command in self.cmdclass:
829            return self.cmdclass[command]
830
831        eps = pkg_resources.iter_entry_points('distutils.commands', command)
832        for ep in eps:
833            ep.require(installer=self.fetch_build_egg)
834            self.cmdclass[command] = cmdclass = ep.load()
835            return cmdclass
836        else:
837            return _Distribution.get_command_class(self, command)
838
839    def print_commands(self):
840        for ep in pkg_resources.iter_entry_points('distutils.commands'):
841            if ep.name not in self.cmdclass:
842                # don't require extras as the commands won't be invoked
843                cmdclass = ep.resolve()
844                self.cmdclass[ep.name] = cmdclass
845        return _Distribution.print_commands(self)
846
847    def get_command_list(self):
848        for ep in pkg_resources.iter_entry_points('distutils.commands'):
849            if ep.name not in self.cmdclass:
850                # don't require extras as the commands won't be invoked
851                cmdclass = ep.resolve()
852                self.cmdclass[ep.name] = cmdclass
853        return _Distribution.get_command_list(self)
854
855    def _set_feature(self, name, status):
856        """Set feature's inclusion status"""
857        setattr(self, self._feature_attrname(name), status)
858
859    def feature_is_included(self, name):
860        """Return 1 if feature is included, 0 if excluded, 'None' if unknown"""
861        return getattr(self, self._feature_attrname(name))
862
863    def include_feature(self, name):
864        """Request inclusion of feature named 'name'"""
865
866        if self.feature_is_included(name) == 0:
867            descr = self.features[name].description
868            raise DistutilsOptionError(
869                descr + " is required, but was excluded or is not available"
870            )
871        self.features[name].include_in(self)
872        self._set_feature(name, 1)
873
874    def include(self, **attrs):
875        """Add items to distribution that are named in keyword arguments
876
877        For example, 'dist.include(py_modules=["x"])' would add 'x' to
878        the distribution's 'py_modules' attribute, if it was not already
879        there.
880
881        Currently, this method only supports inclusion for attributes that are
882        lists or tuples.  If you need to add support for adding to other
883        attributes in this or a subclass, you can add an '_include_X' method,
884        where 'X' is the name of the attribute.  The method will be called with
885        the value passed to 'include()'.  So, 'dist.include(foo={"bar":"baz"})'
886        will try to call 'dist._include_foo({"bar":"baz"})', which can then
887        handle whatever special inclusion logic is needed.
888        """
889        for k, v in attrs.items():
890            include = getattr(self, '_include_' + k, None)
891            if include:
892                include(v)
893            else:
894                self._include_misc(k, v)
895
896    def exclude_package(self, package):
897        """Remove packages, modules, and extensions in named package"""
898
899        pfx = package + '.'
900        if self.packages:
901            self.packages = [
902                p for p in self.packages
903                if p != package and not p.startswith(pfx)
904            ]
905
906        if self.py_modules:
907            self.py_modules = [
908                p for p in self.py_modules
909                if p != package and not p.startswith(pfx)
910            ]
911
912        if self.ext_modules:
913            self.ext_modules = [
914                p for p in self.ext_modules
915                if p.name != package and not p.name.startswith(pfx)
916            ]
917
918    def has_contents_for(self, package):
919        """Return true if 'exclude_package(package)' would do something"""
920
921        pfx = package + '.'
922
923        for p in self.iter_distribution_names():
924            if p == package or p.startswith(pfx):
925                return True
926
927    def _exclude_misc(self, name, value):
928        """Handle 'exclude()' for list/tuple attrs without a special handler"""
929        if not isinstance(value, sequence):
930            raise DistutilsSetupError(
931                "%s: setting must be a list or tuple (%r)" % (name, value)
932            )
933        try:
934            old = getattr(self, name)
935        except AttributeError:
936            raise DistutilsSetupError(
937                "%s: No such distribution setting" % name
938            )
939        if old is not None and not isinstance(old, sequence):
940            raise DistutilsSetupError(
941                name + ": this setting cannot be changed via include/exclude"
942            )
943        elif old:
944            setattr(self, name, [item for item in old if item not in value])
945
946    def _include_misc(self, name, value):
947        """Handle 'include()' for list/tuple attrs without a special handler"""
948
949        if not isinstance(value, sequence):
950            raise DistutilsSetupError(
951                "%s: setting must be a list (%r)" % (name, value)
952            )
953        try:
954            old = getattr(self, name)
955        except AttributeError:
956            raise DistutilsSetupError(
957                "%s: No such distribution setting" % name
958            )
959        if old is None:
960            setattr(self, name, value)
961        elif not isinstance(old, sequence):
962            raise DistutilsSetupError(
963                name + ": this setting cannot be changed via include/exclude"
964            )
965        else:
966            new = [item for item in value if item not in old]
967            setattr(self, name, old + new)
968
969    def exclude(self, **attrs):
970        """Remove items from distribution that are named in keyword arguments
971
972        For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from
973        the distribution's 'py_modules' attribute.  Excluding packages uses
974        the 'exclude_package()' method, so all of the package's contained
975        packages, modules, and extensions are also excluded.
976
977        Currently, this method only supports exclusion from attributes that are
978        lists or tuples.  If you need to add support for excluding from other
979        attributes in this or a subclass, you can add an '_exclude_X' method,
980        where 'X' is the name of the attribute.  The method will be called with
981        the value passed to 'exclude()'.  So, 'dist.exclude(foo={"bar":"baz"})'
982        will try to call 'dist._exclude_foo({"bar":"baz"})', which can then
983        handle whatever special exclusion logic is needed.
984        """
985        for k, v in attrs.items():
986            exclude = getattr(self, '_exclude_' + k, None)
987            if exclude:
988                exclude(v)
989            else:
990                self._exclude_misc(k, v)
991
992    def _exclude_packages(self, packages):
993        if not isinstance(packages, sequence):
994            raise DistutilsSetupError(
995                "packages: setting must be a list or tuple (%r)" % (packages,)
996            )
997        list(map(self.exclude_package, packages))
998
999    def _parse_command_opts(self, parser, args):
1000        # Remove --with-X/--without-X options when processing command args
1001        self.global_options = self.__class__.global_options
1002        self.negative_opt = self.__class__.negative_opt
1003
1004        # First, expand any aliases
1005        command = args[0]
1006        aliases = self.get_option_dict('aliases')
1007        while command in aliases:
1008            src, alias = aliases[command]
1009            del aliases[command]  # ensure each alias can expand only once!
1010            import shlex
1011            args[:1] = shlex.split(alias, True)
1012            command = args[0]
1013
1014        nargs = _Distribution._parse_command_opts(self, parser, args)
1015
1016        # Handle commands that want to consume all remaining arguments
1017        cmd_class = self.get_command_class(command)
1018        if getattr(cmd_class, 'command_consumes_arguments', None):
1019            self.get_option_dict(command)['args'] = ("command line", nargs)
1020            if nargs is not None:
1021                return []
1022
1023        return nargs
1024
1025    def get_cmdline_options(self):
1026        """Return a '{cmd: {opt:val}}' map of all command-line options
1027
1028        Option names are all long, but do not include the leading '--', and
1029        contain dashes rather than underscores.  If the option doesn't take
1030        an argument (e.g. '--quiet'), the 'val' is 'None'.
1031
1032        Note that options provided by config files are intentionally excluded.
1033        """
1034
1035        d = {}
1036
1037        for cmd, opts in self.command_options.items():
1038
1039            for opt, (src, val) in opts.items():
1040
1041                if src != "command line":
1042                    continue
1043
1044                opt = opt.replace('_', '-')
1045
1046                if val == 0:
1047                    cmdobj = self.get_command_obj(cmd)
1048                    neg_opt = self.negative_opt.copy()
1049                    neg_opt.update(getattr(cmdobj, 'negative_opt', {}))
1050                    for neg, pos in neg_opt.items():
1051                        if pos == opt:
1052                            opt = neg
1053                            val = None
1054                            break
1055                    else:
1056                        raise AssertionError("Shouldn't be able to get here")
1057
1058                elif val == 1:
1059                    val = None
1060
1061                d.setdefault(cmd, {})[opt] = val
1062
1063        return d
1064
1065    def iter_distribution_names(self):
1066        """Yield all packages, modules, and extension names in distribution"""
1067
1068        for pkg in self.packages or ():
1069            yield pkg
1070
1071        for module in self.py_modules or ():
1072            yield module
1073
1074        for ext in self.ext_modules or ():
1075            if isinstance(ext, tuple):
1076                name, buildinfo = ext
1077            else:
1078                name = ext.name
1079            if name.endswith('module'):
1080                name = name[:-6]
1081            yield name
1082
1083    def handle_display_options(self, option_order):
1084        """If there were any non-global "display-only" options
1085        (--help-commands or the metadata display options) on the command
1086        line, display the requested info and return true; else return
1087        false.
1088        """
1089        import sys
1090
1091        if six.PY2 or self.help_commands:
1092            return _Distribution.handle_display_options(self, option_order)
1093
1094        # Stdout may be StringIO (e.g. in tests)
1095        if not isinstance(sys.stdout, io.TextIOWrapper):
1096            return _Distribution.handle_display_options(self, option_order)
1097
1098        # Don't wrap stdout if utf-8 is already the encoding. Provides
1099        #  workaround for #334.
1100        if sys.stdout.encoding.lower() in ('utf-8', 'utf8'):
1101            return _Distribution.handle_display_options(self, option_order)
1102
1103        # Print metadata in UTF-8 no matter the platform
1104        encoding = sys.stdout.encoding
1105        errors = sys.stdout.errors
1106        newline = sys.platform != 'win32' and '\n' or None
1107        line_buffering = sys.stdout.line_buffering
1108
1109        sys.stdout = io.TextIOWrapper(
1110            sys.stdout.detach(), 'utf-8', errors, newline, line_buffering)
1111        try:
1112            return _Distribution.handle_display_options(self, option_order)
1113        finally:
1114            sys.stdout = io.TextIOWrapper(
1115                sys.stdout.detach(), encoding, errors, newline, line_buffering)
1116
1117
1118class Feature:
1119    """
1120    **deprecated** -- The `Feature` facility was never completely implemented
1121    or supported, `has reported issues
1122    <https://github.com/pypa/setuptools/issues/58>`_ and will be removed in
1123    a future version.
1124
1125    A subset of the distribution that can be excluded if unneeded/wanted
1126
1127    Features are created using these keyword arguments:
1128
1129      'description' -- a short, human readable description of the feature, to
1130         be used in error messages, and option help messages.
1131
1132      'standard' -- if true, the feature is included by default if it is
1133         available on the current system.  Otherwise, the feature is only
1134         included if requested via a command line '--with-X' option, or if
1135         another included feature requires it.  The default setting is 'False'.
1136
1137      'available' -- if true, the feature is available for installation on the
1138         current system.  The default setting is 'True'.
1139
1140      'optional' -- if true, the feature's inclusion can be controlled from the
1141         command line, using the '--with-X' or '--without-X' options.  If
1142         false, the feature's inclusion status is determined automatically,
1143         based on 'availabile', 'standard', and whether any other feature
1144         requires it.  The default setting is 'True'.
1145
1146      'require_features' -- a string or sequence of strings naming features
1147         that should also be included if this feature is included.  Defaults to
1148         empty list.  May also contain 'Require' objects that should be
1149         added/removed from the distribution.
1150
1151      'remove' -- a string or list of strings naming packages to be removed
1152         from the distribution if this feature is *not* included.  If the
1153         feature *is* included, this argument is ignored.  This argument exists
1154         to support removing features that "crosscut" a distribution, such as
1155         defining a 'tests' feature that removes all the 'tests' subpackages
1156         provided by other features.  The default for this argument is an empty
1157         list.  (Note: the named package(s) or modules must exist in the base
1158         distribution when the 'setup()' function is initially called.)
1159
1160      other keywords -- any other keyword arguments are saved, and passed to
1161         the distribution's 'include()' and 'exclude()' methods when the
1162         feature is included or excluded, respectively.  So, for example, you
1163         could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be
1164         added or removed from the distribution as appropriate.
1165
1166    A feature must include at least one 'requires', 'remove', or other
1167    keyword argument.  Otherwise, it can't affect the distribution in any way.
1168    Note also that you can subclass 'Feature' to create your own specialized
1169    feature types that modify the distribution in other ways when included or
1170    excluded.  See the docstrings for the various methods here for more detail.
1171    Aside from the methods, the only feature attributes that distributions look
1172    at are 'description' and 'optional'.
1173    """
1174
1175    @staticmethod
1176    def warn_deprecated():
1177        msg = (
1178            "Features are deprecated and will be removed in a future "
1179            "version. See https://github.com/pypa/setuptools/issues/65."
1180        )
1181        warnings.warn(msg, DistDeprecationWarning, stacklevel=3)
1182
1183    def __init__(
1184            self, description, standard=False, available=True,
1185            optional=True, require_features=(), remove=(), **extras):
1186        self.warn_deprecated()
1187
1188        self.description = description
1189        self.standard = standard
1190        self.available = available
1191        self.optional = optional
1192        if isinstance(require_features, (str, Require)):
1193            require_features = require_features,
1194
1195        self.require_features = [
1196            r for r in require_features if isinstance(r, str)
1197        ]
1198        er = [r for r in require_features if not isinstance(r, str)]
1199        if er:
1200            extras['require_features'] = er
1201
1202        if isinstance(remove, str):
1203            remove = remove,
1204        self.remove = remove
1205        self.extras = extras
1206
1207        if not remove and not require_features and not extras:
1208            raise DistutilsSetupError(
1209                "Feature %s: must define 'require_features', 'remove', or "
1210                "at least one of 'packages', 'py_modules', etc."
1211            )
1212
1213    def include_by_default(self):
1214        """Should this feature be included by default?"""
1215        return self.available and self.standard
1216
1217    def include_in(self, dist):
1218        """Ensure feature and its requirements are included in distribution
1219
1220        You may override this in a subclass to perform additional operations on
1221        the distribution.  Note that this method may be called more than once
1222        per feature, and so should be idempotent.
1223
1224        """
1225
1226        if not self.available:
1227            raise DistutilsPlatformError(
1228                self.description + " is required, "
1229                "but is not available on this platform"
1230            )
1231
1232        dist.include(**self.extras)
1233
1234        for f in self.require_features:
1235            dist.include_feature(f)
1236
1237    def exclude_from(self, dist):
1238        """Ensure feature is excluded from distribution
1239
1240        You may override this in a subclass to perform additional operations on
1241        the distribution.  This method will be called at most once per
1242        feature, and only after all included features have been asked to
1243        include themselves.
1244        """
1245
1246        dist.exclude(**self.extras)
1247
1248        if self.remove:
1249            for item in self.remove:
1250                dist.exclude_package(item)
1251
1252    def validate(self, dist):
1253        """Verify that feature makes sense in context of distribution
1254
1255        This method is called by the distribution just before it parses its
1256        command line.  It checks to ensure that the 'remove' attribute, if any,
1257        contains only valid package/module names that are present in the base
1258        distribution when 'setup()' is called.  You may override it in a
1259        subclass to perform any other required validation of the feature
1260        against a target distribution.
1261        """
1262
1263        for item in self.remove:
1264            if not dist.has_contents_for(item):
1265                raise DistutilsSetupError(
1266                    "%s wants to be able to remove %s, but the distribution"
1267                    " doesn't contain any packages or modules under %s"
1268                    % (self.description, item, item)
1269                )
1270
1271
1272class DistDeprecationWarning(SetuptoolsDeprecationWarning):
1273    """Class for warning about deprecations in dist in
1274    setuptools. Not ignored by default, unlike DeprecationWarning."""
1275