Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: third_party/google-endpoints/setuptools/dist.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 __all__ = ['Distribution']
2
3 import re
4 import os
5 import warnings
6 import numbers
7 import distutils.log
8 import distutils.core
9 import distutils.cmd
10 import distutils.dist
11 from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
12 DistutilsSetupError)
13 from distutils.util import rfc822_escape
14
15 import six
16 from six.moves import map
17 import packaging
18
19 from setuptools.depends import Require
20 from setuptools import windows_support
21 from setuptools.monkey import get_unpatched
22 from setuptools.config import parse_configuration
23 import pkg_resources
24 from .py36compat import Distribution_parse_config_files
25
26
27 def _get_unpatched(cls):
28 warnings.warn("Do not call this function", DeprecationWarning)
29 return get_unpatched(cls)
30
31
32 # Based on Python 3.5 version
33 def write_pkg_file(self, file):
34 """Write the PKG-INFO format data to a file object.
35 """
36 version = '1.0'
37 if (self.provides or self.requires or self.obsoletes or
38 self.classifiers or self.download_url):
39 version = '1.1'
40 # Setuptools specific for PEP 345
41 if hasattr(self, 'python_requires'):
42 version = '1.2'
43
44 file.write('Metadata-Version: %s\n' % version)
45 file.write('Name: %s\n' % self.get_name())
46 file.write('Version: %s\n' % self.get_version())
47 file.write('Summary: %s\n' % self.get_description())
48 file.write('Home-page: %s\n' % self.get_url())
49 file.write('Author: %s\n' % self.get_contact())
50 file.write('Author-email: %s\n' % self.get_contact_email())
51 file.write('License: %s\n' % self.get_license())
52 if self.download_url:
53 file.write('Download-URL: %s\n' % self.download_url)
54
55 long_desc = rfc822_escape(self.get_long_description())
56 file.write('Description: %s\n' % long_desc)
57
58 keywords = ','.join(self.get_keywords())
59 if keywords:
60 file.write('Keywords: %s\n' % keywords)
61
62 self._write_list(file, 'Platform', self.get_platforms())
63 self._write_list(file, 'Classifier', self.get_classifiers())
64
65 # PEP 314
66 self._write_list(file, 'Requires', self.get_requires())
67 self._write_list(file, 'Provides', self.get_provides())
68 self._write_list(file, 'Obsoletes', self.get_obsoletes())
69
70 # Setuptools specific for PEP 345
71 if hasattr(self, 'python_requires'):
72 file.write('Requires-Python: %s\n' % self.python_requires)
73
74
75 # from Python 3.4
76 def write_pkg_info(self, base_dir):
77 """Write the PKG-INFO file into the release tree.
78 """
79 with open(os.path.join(base_dir, 'PKG-INFO'), 'w',
80 encoding='UTF-8') as pkg_info:
81 self.write_pkg_file(pkg_info)
82
83
84 sequence = tuple, list
85
86
87 def check_importable(dist, attr, value):
88 try:
89 ep = pkg_resources.EntryPoint.parse('x=' + value)
90 assert not ep.extras
91 except (TypeError, ValueError, AttributeError, AssertionError):
92 raise DistutilsSetupError(
93 "%r must be importable 'module:attrs' string (got %r)"
94 % (attr, value)
95 )
96
97
98 def assert_string_list(dist, attr, value):
99 """Verify that value is a string list or None"""
100 try:
101 assert ''.join(value) != value
102 except (TypeError, ValueError, AttributeError, AssertionError):
103 raise DistutilsSetupError(
104 "%r must be a list of strings (got %r)" % (attr, value)
105 )
106
107
108 def check_nsp(dist, attr, value):
109 """Verify that namespace packages are valid"""
110 ns_packages = value
111 assert_string_list(dist, attr, ns_packages)
112 for nsp in ns_packages:
113 if not dist.has_contents_for(nsp):
114 raise DistutilsSetupError(
115 "Distribution contains no modules or packages for " +
116 "namespace package %r" % nsp
117 )
118 parent, sep, child = nsp.rpartition('.')
119 if parent and parent not in ns_packages:
120 distutils.log.warn(
121 "WARNING: %r is declared as a package namespace, but %r"
122 " is not: please correct this in setup.py", nsp, parent
123 )
124
125
126 def check_extras(dist, attr, value):
127 """Verify that extras_require mapping is valid"""
128 try:
129 for k, v in value.items():
130 if ':' in k:
131 k, m = k.split(':', 1)
132 if pkg_resources.invalid_marker(m):
133 raise DistutilsSetupError("Invalid environment marker: " + m )
134 list(pkg_resources.parse_requirements(v))
135 except (TypeError, ValueError, AttributeError):
136 raise DistutilsSetupError(
137 "'extras_require' must be a dictionary whose values are "
138 "strings or lists of strings containing valid project/version "
139 "requirement specifiers."
140 )
141
142
143 def assert_bool(dist, attr, value):
144 """Verify that value is True, False, 0, or 1"""
145 if bool(value) != value:
146 tmpl = "{attr!r} must be a boolean value (got {value!r})"
147 raise DistutilsSetupError(tmpl.format(attr=attr, value=value))
148
149
150 def check_requirements(dist, attr, value):
151 """Verify that install_requires is a valid requirements list"""
152 try:
153 list(pkg_resources.parse_requirements(value))
154 except (TypeError, ValueError) as error:
155 tmpl = (
156 "{attr!r} must be a string or list of strings "
157 "containing valid project/version requirement specifiers; {error}"
158 )
159 raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
160
161
162 def check_specifier(dist, attr, value):
163 """Verify that value is a valid version specifier"""
164 try:
165 packaging.specifiers.SpecifierSet(value)
166 except packaging.specifiers.InvalidSpecifier as error:
167 tmpl = (
168 "{attr!r} must be a string or list of strings "
169 "containing valid version specifiers; {error}"
170 )
171 raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
172
173
174 def check_entry_points(dist, attr, value):
175 """Verify that entry_points map is parseable"""
176 try:
177 pkg_resources.EntryPoint.parse_map(value)
178 except ValueError as e:
179 raise DistutilsSetupError(e)
180
181
182 def check_test_suite(dist, attr, value):
183 if not isinstance(value, six.string_types):
184 raise DistutilsSetupError("test_suite must be a string")
185
186
187 def check_package_data(dist, attr, value):
188 """Verify that value is a dictionary of package names to glob lists"""
189 if isinstance(value, dict):
190 for k, v in value.items():
191 if not isinstance(k, str):
192 break
193 try:
194 iter(v)
195 except TypeError:
196 break
197 else:
198 return
199 raise DistutilsSetupError(
200 attr + " must be a dictionary mapping package names to lists of "
201 "wildcard patterns"
202 )
203
204
205 def check_packages(dist, attr, value):
206 for pkgname in value:
207 if not re.match(r'\w+(\.\w+)*', pkgname):
208 distutils.log.warn(
209 "WARNING: %r not a valid package name; please use only "
210 ".-separated package names in setup.py", pkgname
211 )
212
213
214 _Distribution = get_unpatched(distutils.core.Distribution)
215
216
217 class Distribution(Distribution_parse_config_files, _Distribution):
218 """Distribution with support for features, tests, and package data
219
220 This is an enhanced version of 'distutils.dist.Distribution' that
221 effectively adds the following new optional keyword arguments to 'setup()':
222
223 'install_requires' -- a string or sequence of strings specifying project
224 versions that the distribution requires when installed, in the format
225 used by 'pkg_resources.require()'. They will be installed
226 automatically when the package is installed. If you wish to use
227 packages that are not available in PyPI, or want to give your users an
228 alternate download location, you can add a 'find_links' option to the
229 '[easy_install]' section of your project's 'setup.cfg' file, and then
230 setuptools will scan the listed web pages for links that satisfy the
231 requirements.
232
233 'extras_require' -- a dictionary mapping names of optional "extras" to the
234 additional requirement(s) that using those extras incurs. For example,
235 this::
236
237 extras_require = dict(reST = ["docutils>=0.3", "reSTedit"])
238
239 indicates that the distribution can optionally provide an extra
240 capability called "reST", but it can only be used if docutils and
241 reSTedit are installed. If the user installs your package using
242 EasyInstall and requests one of your extras, the corresponding
243 additional requirements will be installed if needed.
244
245 'features' **deprecated** -- a dictionary mapping option names to
246 'setuptools.Feature'
247 objects. Features are a portion of the distribution that can be
248 included or excluded based on user options, inter-feature dependencies,
249 and availability on the current system. Excluded features are omitted
250 from all setup commands, including source and binary distributions, so
251 you can create multiple distributions from the same source tree.
252 Feature names should be valid Python identifiers, except that they may
253 contain the '-' (minus) sign. Features can be included or excluded
254 via the command line options '--with-X' and '--without-X', where 'X' is
255 the name of the feature. Whether a feature is included by default, and
256 whether you are allowed to control this from the command line, is
257 determined by the Feature object. See the 'Feature' class for more
258 information.
259
260 'test_suite' -- the name of a test suite to run for the 'test' command.
261 If the user runs 'python setup.py test', the package will be installed,
262 and the named test suite will be run. The format is the same as
263 would be used on a 'unittest.py' command line. That is, it is the
264 dotted name of an object to import and call to generate a test suite.
265
266 'package_data' -- a dictionary mapping package names to lists of filenames
267 or globs to use to find data files contained in the named packages.
268 If the dictionary has filenames or globs listed under '""' (the empty
269 string), those names will be searched for in every package, in addition
270 to any names for the specific package. Data files found using these
271 names/globs will be installed along with the package, in the same
272 location as the package. Note that globs are allowed to reference
273 the contents of non-package subdirectories, as long as you use '/' as
274 a path separator. (Globs are automatically converted to
275 platform-specific paths at runtime.)
276
277 In addition to these new keywords, this class also has several new methods
278 for manipulating the distribution's contents. For example, the 'include()'
279 and 'exclude()' methods can be thought of as in-place add and subtract
280 commands that add or remove packages, modules, extensions, and so on from
281 the distribution. They are used by the feature subsystem to configure the
282 distribution for the included and excluded features.
283 """
284
285 _patched_dist = None
286
287 def patch_missing_pkg_info(self, attrs):
288 # Fake up a replacement for the data that would normally come from
289 # PKG-INFO, but which might not yet be built if this is a fresh
290 # checkout.
291 #
292 if not attrs or 'name' not in attrs or 'version' not in attrs:
293 return
294 key = pkg_resources.safe_name(str(attrs['name'])).lower()
295 dist = pkg_resources.working_set.by_key.get(key)
296 if dist is not None and not dist.has_metadata('PKG-INFO'):
297 dist._version = pkg_resources.safe_version(str(attrs['version']))
298 self._patched_dist = dist
299
300 def __init__(self, attrs=None):
301 have_package_data = hasattr(self, "package_data")
302 if not have_package_data:
303 self.package_data = {}
304 _attrs_dict = attrs or {}
305 if 'features' in _attrs_dict or 'require_features' in _attrs_dict:
306 Feature.warn_deprecated()
307 self.require_features = []
308 self.features = {}
309 self.dist_files = []
310 self.src_root = attrs and attrs.pop("src_root", None)
311 self.patch_missing_pkg_info(attrs)
312 # Make sure we have any eggs needed to interpret 'attrs'
313 if attrs is not None:
314 self.dependency_links = attrs.pop('dependency_links', [])
315 assert_string_list(self, 'dependency_links', self.dependency_links)
316 if attrs and 'setup_requires' in attrs:
317 self.fetch_build_eggs(attrs['setup_requires'])
318 for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
319 vars(self).setdefault(ep.name, None)
320 _Distribution.__init__(self, attrs)
321 if isinstance(self.metadata.version, numbers.Number):
322 # Some people apparently take "version number" too literally :)
323 self.metadata.version = str(self.metadata.version)
324
325 if self.metadata.version is not None:
326 try:
327 ver = packaging.version.Version(self.metadata.version)
328 normalized_version = str(ver)
329 if self.metadata.version != normalized_version:
330 warnings.warn(
331 "Normalizing '%s' to '%s'" % (
332 self.metadata.version,
333 normalized_version,
334 )
335 )
336 self.metadata.version = normalized_version
337 except (packaging.version.InvalidVersion, TypeError):
338 warnings.warn(
339 "The version specified (%r) is an invalid version, this "
340 "may not work as expected with newer versions of "
341 "setuptools, pip, and PyPI. Please see PEP 440 for more "
342 "details." % self.metadata.version
343 )
344 if getattr(self, 'python_requires', None):
345 self.metadata.python_requires = self.python_requires
346
347 def parse_config_files(self, filenames=None):
348 """Parses configuration files from various levels
349 and loads configuration.
350
351 """
352 _Distribution.parse_config_files(self, filenames=filenames)
353
354 parse_configuration(self, self.command_options)
355
356 def parse_command_line(self):
357 """Process features after parsing command line options"""
358 result = _Distribution.parse_command_line(self)
359 if self.features:
360 self._finalize_features()
361 return result
362
363 def _feature_attrname(self, name):
364 """Convert feature name to corresponding option attribute name"""
365 return 'with_' + name.replace('-', '_')
366
367 def fetch_build_eggs(self, requires):
368 """Resolve pre-setup requirements"""
369 resolved_dists = pkg_resources.working_set.resolve(
370 pkg_resources.parse_requirements(requires),
371 installer=self.fetch_build_egg,
372 replace_conflicting=True,
373 )
374 for dist in resolved_dists:
375 pkg_resources.working_set.add(dist, replace=True)
376 return resolved_dists
377
378 def finalize_options(self):
379 _Distribution.finalize_options(self)
380 if self.features:
381 self._set_global_opts_from_features()
382
383 for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
384 value = getattr(self, ep.name, None)
385 if value is not None:
386 ep.require(installer=self.fetch_build_egg)
387 ep.load()(self, ep.name, value)
388 if getattr(self, 'convert_2to3_doctests', None):
389 # XXX may convert to set here when we can rely on set being builtin
390 self.convert_2to3_doctests = [os.path.abspath(p) for p in self.conve rt_2to3_doctests]
391 else:
392 self.convert_2to3_doctests = []
393
394 def get_egg_cache_dir(self):
395 egg_cache_dir = os.path.join(os.curdir, '.eggs')
396 if not os.path.exists(egg_cache_dir):
397 os.mkdir(egg_cache_dir)
398 windows_support.hide_file(egg_cache_dir)
399 readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
400 with open(readme_txt_filename, 'w') as f:
401 f.write('This directory contains eggs that were downloaded '
402 'by setuptools to build, test, and run plug-ins.\n\n')
403 f.write('This directory caches those eggs to prevent '
404 'repeated downloads.\n\n')
405 f.write('However, it is safe to delete this directory.\n\n')
406
407 return egg_cache_dir
408
409 def fetch_build_egg(self, req):
410 """Fetch an egg needed for building"""
411
412 try:
413 cmd = self._egg_fetcher
414 cmd.package_index.to_scan = []
415 except AttributeError:
416 from setuptools.command.easy_install import easy_install
417 dist = self.__class__({'script_args': ['easy_install']})
418 dist.parse_config_files()
419 opts = dist.get_option_dict('easy_install')
420 keep = (
421 'find_links', 'site_dirs', 'index_url', 'optimize',
422 'site_dirs', 'allow_hosts'
423 )
424 for key in list(opts):
425 if key not in keep:
426 del opts[key] # don't use any other settings
427 if self.dependency_links:
428 links = self.dependency_links[:]
429 if 'find_links' in opts:
430 links = opts['find_links'][1].split() + links
431 opts['find_links'] = ('setup', links)
432 install_dir = self.get_egg_cache_dir()
433 cmd = easy_install(
434 dist, args=["x"], install_dir=install_dir, exclude_scripts=True,
435 always_copy=False, build_directory=None, editable=False,
436 upgrade=False, multi_version=True, no_report=True, user=False
437 )
438 cmd.ensure_finalized()
439 self._egg_fetcher = cmd
440 return cmd.easy_install(req)
441
442 def _set_global_opts_from_features(self):
443 """Add --with-X/--without-X options based on optional features"""
444
445 go = []
446 no = self.negative_opt.copy()
447
448 for name, feature in self.features.items():
449 self._set_feature(name, None)
450 feature.validate(self)
451
452 if feature.optional:
453 descr = feature.description
454 incdef = ' (default)'
455 excdef = ''
456 if not feature.include_by_default():
457 excdef, incdef = incdef, excdef
458
459 go.append(('with-' + name, None, 'include ' + descr + incdef))
460 go.append(('without-' + name, None, 'exclude ' + descr + excdef) )
461 no['without-' + name] = 'with-' + name
462
463 self.global_options = self.feature_options = go + self.global_options
464 self.negative_opt = self.feature_negopt = no
465
466 def _finalize_features(self):
467 """Add/remove features and resolve dependencies between them"""
468
469 # First, flag all the enabled items (and thus their dependencies)
470 for name, feature in self.features.items():
471 enabled = self.feature_is_included(name)
472 if enabled or (enabled is None and feature.include_by_default()):
473 feature.include_in(self)
474 self._set_feature(name, 1)
475
476 # Then disable the rest, so that off-by-default features don't
477 # get flagged as errors when they're required by an enabled feature
478 for name, feature in self.features.items():
479 if not self.feature_is_included(name):
480 feature.exclude_from(self)
481 self._set_feature(name, 0)
482
483 def get_command_class(self, command):
484 """Pluggable version of get_command_class()"""
485 if command in self.cmdclass:
486 return self.cmdclass[command]
487
488 for ep in pkg_resources.iter_entry_points('distutils.commands', command) :
489 ep.require(installer=self.fetch_build_egg)
490 self.cmdclass[command] = cmdclass = ep.load()
491 return cmdclass
492 else:
493 return _Distribution.get_command_class(self, command)
494
495 def print_commands(self):
496 for ep in pkg_resources.iter_entry_points('distutils.commands'):
497 if ep.name not in self.cmdclass:
498 # don't require extras as the commands won't be invoked
499 cmdclass = ep.resolve()
500 self.cmdclass[ep.name] = cmdclass
501 return _Distribution.print_commands(self)
502
503 def get_command_list(self):
504 for ep in pkg_resources.iter_entry_points('distutils.commands'):
505 if ep.name not in self.cmdclass:
506 # don't require extras as the commands won't be invoked
507 cmdclass = ep.resolve()
508 self.cmdclass[ep.name] = cmdclass
509 return _Distribution.get_command_list(self)
510
511 def _set_feature(self, name, status):
512 """Set feature's inclusion status"""
513 setattr(self, self._feature_attrname(name), status)
514
515 def feature_is_included(self, name):
516 """Return 1 if feature is included, 0 if excluded, 'None' if unknown"""
517 return getattr(self, self._feature_attrname(name))
518
519 def include_feature(self, name):
520 """Request inclusion of feature named 'name'"""
521
522 if self.feature_is_included(name) == 0:
523 descr = self.features[name].description
524 raise DistutilsOptionError(
525 descr + " is required, but was excluded or is not available"
526 )
527 self.features[name].include_in(self)
528 self._set_feature(name, 1)
529
530 def include(self, **attrs):
531 """Add items to distribution that are named in keyword arguments
532
533 For example, 'dist.exclude(py_modules=["x"])' would add 'x' to
534 the distribution's 'py_modules' attribute, if it was not already
535 there.
536
537 Currently, this method only supports inclusion for attributes that are
538 lists or tuples. If you need to add support for adding to other
539 attributes in this or a subclass, you can add an '_include_X' method,
540 where 'X' is the name of the attribute. The method will be called with
541 the value passed to 'include()'. So, 'dist.include(foo={"bar":"baz"})'
542 will try to call 'dist._include_foo({"bar":"baz"})', which can then
543 handle whatever special inclusion logic is needed.
544 """
545 for k, v in attrs.items():
546 include = getattr(self, '_include_' + k, None)
547 if include:
548 include(v)
549 else:
550 self._include_misc(k, v)
551
552 def exclude_package(self, package):
553 """Remove packages, modules, and extensions in named package"""
554
555 pfx = package + '.'
556 if self.packages:
557 self.packages = [
558 p for p in self.packages
559 if p != package and not p.startswith(pfx)
560 ]
561
562 if self.py_modules:
563 self.py_modules = [
564 p for p in self.py_modules
565 if p != package and not p.startswith(pfx)
566 ]
567
568 if self.ext_modules:
569 self.ext_modules = [
570 p for p in self.ext_modules
571 if p.name != package and not p.name.startswith(pfx)
572 ]
573
574 def has_contents_for(self, package):
575 """Return true if 'exclude_package(package)' would do something"""
576
577 pfx = package + '.'
578
579 for p in self.iter_distribution_names():
580 if p == package or p.startswith(pfx):
581 return True
582
583 def _exclude_misc(self, name, value):
584 """Handle 'exclude()' for list/tuple attrs without a special handler"""
585 if not isinstance(value, sequence):
586 raise DistutilsSetupError(
587 "%s: setting must be a list or tuple (%r)" % (name, value)
588 )
589 try:
590 old = getattr(self, name)
591 except AttributeError:
592 raise DistutilsSetupError(
593 "%s: No such distribution setting" % name
594 )
595 if old is not None and not isinstance(old, sequence):
596 raise DistutilsSetupError(
597 name + ": this setting cannot be changed via include/exclude"
598 )
599 elif old:
600 setattr(self, name, [item for item in old if item not in value])
601
602 def _include_misc(self, name, value):
603 """Handle 'include()' for list/tuple attrs without a special handler"""
604
605 if not isinstance(value, sequence):
606 raise DistutilsSetupError(
607 "%s: setting must be a list (%r)" % (name, value)
608 )
609 try:
610 old = getattr(self, name)
611 except AttributeError:
612 raise DistutilsSetupError(
613 "%s: No such distribution setting" % name
614 )
615 if old is None:
616 setattr(self, name, value)
617 elif not isinstance(old, sequence):
618 raise DistutilsSetupError(
619 name + ": this setting cannot be changed via include/exclude"
620 )
621 else:
622 setattr(self, name, old + [item for item in value if item not in old ])
623
624 def exclude(self, **attrs):
625 """Remove items from distribution that are named in keyword arguments
626
627 For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from
628 the distribution's 'py_modules' attribute. Excluding packages uses
629 the 'exclude_package()' method, so all of the package's contained
630 packages, modules, and extensions are also excluded.
631
632 Currently, this method only supports exclusion from attributes that are
633 lists or tuples. If you need to add support for excluding from other
634 attributes in this or a subclass, you can add an '_exclude_X' method,
635 where 'X' is the name of the attribute. The method will be called with
636 the value passed to 'exclude()'. So, 'dist.exclude(foo={"bar":"baz"})'
637 will try to call 'dist._exclude_foo({"bar":"baz"})', which can then
638 handle whatever special exclusion logic is needed.
639 """
640 for k, v in attrs.items():
641 exclude = getattr(self, '_exclude_' + k, None)
642 if exclude:
643 exclude(v)
644 else:
645 self._exclude_misc(k, v)
646
647 def _exclude_packages(self, packages):
648 if not isinstance(packages, sequence):
649 raise DistutilsSetupError(
650 "packages: setting must be a list or tuple (%r)" % (packages,)
651 )
652 list(map(self.exclude_package, packages))
653
654 def _parse_command_opts(self, parser, args):
655 # Remove --with-X/--without-X options when processing command args
656 self.global_options = self.__class__.global_options
657 self.negative_opt = self.__class__.negative_opt
658
659 # First, expand any aliases
660 command = args[0]
661 aliases = self.get_option_dict('aliases')
662 while command in aliases:
663 src, alias = aliases[command]
664 del aliases[command] # ensure each alias can expand only once!
665 import shlex
666 args[:1] = shlex.split(alias, True)
667 command = args[0]
668
669 nargs = _Distribution._parse_command_opts(self, parser, args)
670
671 # Handle commands that want to consume all remaining arguments
672 cmd_class = self.get_command_class(command)
673 if getattr(cmd_class, 'command_consumes_arguments', None):
674 self.get_option_dict(command)['args'] = ("command line", nargs)
675 if nargs is not None:
676 return []
677
678 return nargs
679
680 def get_cmdline_options(self):
681 """Return a '{cmd: {opt:val}}' map of all command-line options
682
683 Option names are all long, but do not include the leading '--', and
684 contain dashes rather than underscores. If the option doesn't take
685 an argument (e.g. '--quiet'), the 'val' is 'None'.
686
687 Note that options provided by config files are intentionally excluded.
688 """
689
690 d = {}
691
692 for cmd, opts in self.command_options.items():
693
694 for opt, (src, val) in opts.items():
695
696 if src != "command line":
697 continue
698
699 opt = opt.replace('_', '-')
700
701 if val == 0:
702 cmdobj = self.get_command_obj(cmd)
703 neg_opt = self.negative_opt.copy()
704 neg_opt.update(getattr(cmdobj, 'negative_opt', {}))
705 for neg, pos in neg_opt.items():
706 if pos == opt:
707 opt = neg
708 val = None
709 break
710 else:
711 raise AssertionError("Shouldn't be able to get here")
712
713 elif val == 1:
714 val = None
715
716 d.setdefault(cmd, {})[opt] = val
717
718 return d
719
720 def iter_distribution_names(self):
721 """Yield all packages, modules, and extension names in distribution"""
722
723 for pkg in self.packages or ():
724 yield pkg
725
726 for module in self.py_modules or ():
727 yield module
728
729 for ext in self.ext_modules or ():
730 if isinstance(ext, tuple):
731 name, buildinfo = ext
732 else:
733 name = ext.name
734 if name.endswith('module'):
735 name = name[:-6]
736 yield name
737
738 def handle_display_options(self, option_order):
739 """If there were any non-global "display-only" options
740 (--help-commands or the metadata display options) on the command
741 line, display the requested info and return true; else return
742 false.
743 """
744 import sys
745
746 if six.PY2 or self.help_commands:
747 return _Distribution.handle_display_options(self, option_order)
748
749 # Stdout may be StringIO (e.g. in tests)
750 import io
751 if not isinstance(sys.stdout, io.TextIOWrapper):
752 return _Distribution.handle_display_options(self, option_order)
753
754 # Don't wrap stdout if utf-8 is already the encoding. Provides
755 # workaround for #334.
756 if sys.stdout.encoding.lower() in ('utf-8', 'utf8'):
757 return _Distribution.handle_display_options(self, option_order)
758
759 # Print metadata in UTF-8 no matter the platform
760 encoding = sys.stdout.encoding
761 errors = sys.stdout.errors
762 newline = sys.platform != 'win32' and '\n' or None
763 line_buffering = sys.stdout.line_buffering
764
765 sys.stdout = io.TextIOWrapper(
766 sys.stdout.detach(), 'utf-8', errors, newline, line_buffering)
767 try:
768 return _Distribution.handle_display_options(self, option_order)
769 finally:
770 sys.stdout = io.TextIOWrapper(
771 sys.stdout.detach(), encoding, errors, newline, line_buffering)
772
773
774 class Feature:
775 """
776 **deprecated** -- The `Feature` facility was never completely implemented
777 or supported, `has reported issues
778 <https://github.com/pypa/setuptools/issues/58>`_ and will be removed in
779 a future version.
780
781 A subset of the distribution that can be excluded if unneeded/wanted
782
783 Features are created using these keyword arguments:
784
785 'description' -- a short, human readable description of the feature, to
786 be used in error messages, and option help messages.
787
788 'standard' -- if true, the feature is included by default if it is
789 available on the current system. Otherwise, the feature is only
790 included if requested via a command line '--with-X' option, or if
791 another included feature requires it. The default setting is 'False'.
792
793 'available' -- if true, the feature is available for installation on the
794 current system. The default setting is 'True'.
795
796 'optional' -- if true, the feature's inclusion can be controlled from the
797 command line, using the '--with-X' or '--without-X' options. If
798 false, the feature's inclusion status is determined automatically,
799 based on 'availabile', 'standard', and whether any other feature
800 requires it. The default setting is 'True'.
801
802 'require_features' -- a string or sequence of strings naming features
803 that should also be included if this feature is included. Defaults to
804 empty list. May also contain 'Require' objects that should be
805 added/removed from the distribution.
806
807 'remove' -- a string or list of strings naming packages to be removed
808 from the distribution if this feature is *not* included. If the
809 feature *is* included, this argument is ignored. This argument exists
810 to support removing features that "crosscut" a distribution, such as
811 defining a 'tests' feature that removes all the 'tests' subpackages
812 provided by other features. The default for this argument is an empty
813 list. (Note: the named package(s) or modules must exist in the base
814 distribution when the 'setup()' function is initially called.)
815
816 other keywords -- any other keyword arguments are saved, and passed to
817 the distribution's 'include()' and 'exclude()' methods when the
818 feature is included or excluded, respectively. So, for example, you
819 could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be
820 added or removed from the distribution as appropriate.
821
822 A feature must include at least one 'requires', 'remove', or other
823 keyword argument. Otherwise, it can't affect the distribution in any way.
824 Note also that you can subclass 'Feature' to create your own specialized
825 feature types that modify the distribution in other ways when included or
826 excluded. See the docstrings for the various methods here for more detail.
827 Aside from the methods, the only feature attributes that distributions look
828 at are 'description' and 'optional'.
829 """
830
831 @staticmethod
832 def warn_deprecated():
833 warnings.warn(
834 "Features are deprecated and will be removed in a future "
835 "version. See https://github.com/pypa/setuptools/issues/65.",
836 DeprecationWarning,
837 stacklevel=3,
838 )
839
840 def __init__(self, description, standard=False, available=True,
841 optional=True, require_features=(), remove=(), **extras):
842 self.warn_deprecated()
843
844 self.description = description
845 self.standard = standard
846 self.available = available
847 self.optional = optional
848 if isinstance(require_features, (str, Require)):
849 require_features = require_features,
850
851 self.require_features = [
852 r for r in require_features if isinstance(r, str)
853 ]
854 er = [r for r in require_features if not isinstance(r, str)]
855 if er:
856 extras['require_features'] = er
857
858 if isinstance(remove, str):
859 remove = remove,
860 self.remove = remove
861 self.extras = extras
862
863 if not remove and not require_features and not extras:
864 raise DistutilsSetupError(
865 "Feature %s: must define 'require_features', 'remove', or at lea st one"
866 " of 'packages', 'py_modules', etc."
867 )
868
869 def include_by_default(self):
870 """Should this feature be included by default?"""
871 return self.available and self.standard
872
873 def include_in(self, dist):
874 """Ensure feature and its requirements are included in distribution
875
876 You may override this in a subclass to perform additional operations on
877 the distribution. Note that this method may be called more than once
878 per feature, and so should be idempotent.
879
880 """
881
882 if not self.available:
883 raise DistutilsPlatformError(
884 self.description + " is required, "
885 "but is not available on this platform"
886 )
887
888 dist.include(**self.extras)
889
890 for f in self.require_features:
891 dist.include_feature(f)
892
893 def exclude_from(self, dist):
894 """Ensure feature is excluded from distribution
895
896 You may override this in a subclass to perform additional operations on
897 the distribution. This method will be called at most once per
898 feature, and only after all included features have been asked to
899 include themselves.
900 """
901
902 dist.exclude(**self.extras)
903
904 if self.remove:
905 for item in self.remove:
906 dist.exclude_package(item)
907
908 def validate(self, dist):
909 """Verify that feature makes sense in context of distribution
910
911 This method is called by the distribution just before it parses its
912 command line. It checks to ensure that the 'remove' attribute, if any,
913 contains only valid package/module names that are present in the base
914 distribution when 'setup()' is called. You may override it in a
915 subclass to perform any other required validation of the feature
916 against a target distribution.
917 """
918
919 for item in self.remove:
920 if not dist.has_contents_for(item):
921 raise DistutilsSetupError(
922 "%s wants to be able to remove %s, but the distribution"
923 " doesn't contain any packages or modules under %s"
924 % (self.description, item, item)
925 )
OLDNEW
« no previous file with comments | « third_party/google-endpoints/setuptools/depends.py ('k') | third_party/google-endpoints/setuptools/extension.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698