comparison venv/lib/python2.7/site-packages/setuptools/dist.py @ 0:d67268158946 draft

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