comparison lib/python3.8/site-packages/setuptools/dist.py @ 0:9e54283cc701 draft

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