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