comparison env/lib/python3.7/site-packages/setuptools/dist.py @ 0:26e78fe6e8c4 draft

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