1 __all__ = ['Distribution']
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
13 def _get_unpatched(cls):
14 """Protect against re-patching the distutils if reloaded
16 Also ensures that no other distutils extension monkeypatched the distutils
19 while cls.__module__.startswith('setuptools'):
21 if not cls.__module__.startswith('distutils'):
23 "distutils has already been patched by %r" % cls
27 _Distribution = _get_unpatched(_Distribution)
29 sequence = tuple, list
31 def check_importable(dist, attr, value):
33 ep = pkg_resources.EntryPoint.parse('x='+value)
35 except (TypeError,ValueError,AttributeError,AssertionError):
36 raise DistutilsSetupError(
37 "%r must be importable 'module:attrs' string (got %r)"
42 def assert_string_list(dist, attr, value):
43 """Verify that value is a string list or None"""
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)
51 def check_nsp(dist, attr, value):
52 """Verify that namespace packages are valid"""
53 assert_string_list(dist,attr,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
61 parent = '.'.join(nsp.split('.')[:-1])
62 if parent not in value:
64 "WARNING: %r is declared as a package namespace, but %r"
65 " is not: please correct this in setup.py", nsp, parent
68 def check_extras(dist, attr, value):
69 """Verify that extras_require mapping is valid"""
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."
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)
89 def check_requirements(dist, attr, value):
90 """Verify that install_requires is a valid requirements list"""
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,)
98 def check_entry_points(dist, attr, value):
99 """Verify that entry_points map is parseable"""
101 pkg_resources.EntryPoint.parse_map(value)
102 except ValueError, e:
103 raise DistutilsSetupError(e)
105 def check_test_suite(dist, attr, value):
106 if not isinstance(value,basestring):
107 raise DistutilsSetupError("test_suite must be a string")
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
119 raise DistutilsSetupError(
120 attr+" must be a dictionary mapping package names to lists of "
124 def check_packages(dist, attr, value):
125 for pkgname in value:
126 if not re.match(r'\w+(\.\w+)*', pkgname):
128 "WARNING: %r not a valid package name; please use only"
129 ".-separated package names in setup.py", pkgname
165 class Distribution(_Distribution):
166 """Distribution with support for features, tests, and package data
168 This is an enhanced version of 'distutils.dist.Distribution' that
169 effectively adds the following new optional keyword arguments to 'setup()':
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
181 'extras_require' -- a dictionary mapping names of optional "extras" to the
182 additional requirement(s) that using those extras incurs. For example,
185 extras_require = dict(reST = ["docutils>=0.3", "reSTedit"])
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.
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
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.
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.)
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.
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
239 if not attrs or 'name' not in attrs or 'version' not in attrs:
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
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 = []
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)
269 def parse_command_line(self):
270 """Process features after parsing command line options"""
271 result = _Distribution.parse_command_line(self)
273 self._finalize_features()
276 def _feature_attrname(self,name):
277 """Convert feature name to corresponding option attribute name"""
278 return 'with_'+name.replace('-','_')
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
286 working_set.add(dist)
288 def finalize_options(self):
289 _Distribution.finalize_options(self)
291 self._set_global_opts_from_features()
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)
299 def fetch_build_egg(self, req):
300 """Fetch an egg needed for building"""
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')
309 'find_links', 'site_dirs', 'index_url', 'optimize',
310 'site_dirs', 'allow_hosts'
312 for key in opts.keys():
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)
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
325 cmd.ensure_finalized()
326 self._egg_fetcher = cmd
327 return cmd.easy_install(req)
329 def _set_global_opts_from_features(self):
330 """Add --with-X/--without-X options based on optional features"""
333 no = self.negative_opt.copy()
335 for name,feature in self.features.items():
336 self._set_feature(name,None)
337 feature.validate(self)
340 descr = feature.description
341 incdef = ' (default)'
343 if not feature.include_by_default():
344 excdef, incdef = incdef, excdef
346 go.append(('with-'+name, None, 'include '+descr+incdef))
347 go.append(('without-'+name, None, 'exclude '+descr+excdef))
348 no['without-'+name] = 'with-'+name
350 self.global_options = self.feature_options = go + self.global_options
351 self.negative_opt = self.feature_negopt = no
370 def _finalize_features(self):
371 """Add/remove features and resolve dependencies between them"""
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)
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)
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]
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()
398 return _Distribution.get_command_class(self, command)
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)
411 def _set_feature(self,name,status):
412 """Set feature's inclusion status"""
413 setattr(self,self._feature_attrname(name),status)
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))
419 def include_feature(self,name):
420 """Request inclusion of feature named 'name'"""
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"
427 self.features[name].include_in(self)
428 self._set_feature(name,1)
430 def include(self,**attrs):
431 """Add items to distribution that are named in keyword arguments
433 For example, 'dist.exclude(py_modules=["x"])' would add 'x' to
434 the distribution's 'py_modules' attribute, if it was not already
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.
445 for k,v in attrs.items():
446 include = getattr(self, '_include_'+k, None)
450 self._include_misc(k,v)
452 def exclude_package(self,package):
453 """Remove packages, modules, and extensions in named package"""
458 p for p in self.packages
459 if p!=package and not p.startswith(pfx)
464 p for p in self.py_modules
465 if p!=package and not p.startswith(pfx)
470 p for p in self.ext_modules
471 if p.name!=package and not p.name.startswith(pfx)
475 def has_contents_for(self,package):
476 """Return true if 'exclude_package(package)' would do something"""
480 for p in self.iter_distribution_names():
481 if p==package or p.startswith(pfx):
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)
500 old = getattr(self,name)
501 except AttributeError:
502 raise DistutilsSetupError(
503 "%s: No such distribution setting" % name
505 if old is not None and not isinstance(old,sequence):
506 raise DistutilsSetupError(
507 name+": this setting cannot be changed via include/exclude"
510 setattr(self,name,[item for item in old if item not in value])
512 def _include_misc(self,name,value):
513 """Handle 'include()' for list/tuple attrs without a special handler"""
515 if not isinstance(value,sequence):
516 raise DistutilsSetupError(
517 "%s: setting must be a list (%r)" % (name, value)
520 old = getattr(self,name)
521 except AttributeError:
522 raise DistutilsSetupError(
523 "%s: No such distribution setting" % name
526 setattr(self,name,value)
527 elif not isinstance(old,sequence):
528 raise DistutilsSetupError(
529 name+": this setting cannot be changed via include/exclude"
532 setattr(self,name,old+[item for item in value if item not in old])
534 def exclude(self,**attrs):
535 """Remove items from distribution that are named in keyword arguments
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.
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.
550 for k,v in attrs.items():
551 exclude = getattr(self, '_exclude_'+k, None)
555 self._exclude_misc(k,v)
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,)
562 map(self.exclude_package, packages)
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
580 # First, expand any aliases
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!
587 args[:1] = shlex.split(alias,True)
590 nargs = _Distribution._parse_command_opts(self, parser, args)
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:
616 def get_cmdline_options(self):
617 """Return a '{cmd: {opt:val}}' map of all command-line options
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'.
623 Note that options provided by config files are intentionally excluded.
628 for cmd,opts in self.command_options.items():
630 for opt,(src,val) in opts.items():
632 if src != "command line":
635 opt = opt.replace('_','-')
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():
647 raise AssertionError("Shouldn't be able to get here")
652 d.setdefault(cmd,{})[opt] = val
657 def iter_distribution_names(self):
658 """Yield all packages, modules, and extension names in distribution"""
660 for pkg in self.packages or ():
663 for module in self.py_modules or ():
666 for ext in self.ext_modules or ():
667 if isinstance(ext,tuple):
668 name, buildinfo = ext
671 if name.endswith('module'):
675 # Install it throughout the distutils
676 for module in distutils.dist, distutils.core, distutils.cmd:
677 module.Distribution = Distribution
699 """A subset of the distribution that can be excluded if unneeded/wanted
701 Features are created using these keyword arguments:
703 'description' -- a short, human readable description of the feature, to
704 be used in error messages, and option help messages.
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'.
711 'available' -- if true, the feature is available for installation on the
712 current system. The default setting is 'True'.
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'.
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.
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.)
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.
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'.
748 def __init__(self, description, standard=False, available=True,
749 optional=True, require_features=(), remove=(), **extras
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,
759 self.require_features = [
760 r for r in require_features if isinstance(r,str)
762 er = [r for r in require_features if not isinstance(r,str)]
763 if er: extras['require_features'] = er
765 if isinstance(remove,str):
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."
776 def include_by_default(self):
777 """Should this feature be included by default?"""
778 return self.available and self.standard
780 def include_in(self,dist):
782 """Ensure feature and its requirements are included in distribution
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.
790 if not self.available:
791 raise DistutilsPlatformError(
792 self.description+" is required,"
793 "but is not available on this platform"
796 dist.include(**self.extras)
798 for f in self.require_features:
799 dist.include_feature(f)
803 def exclude_from(self,dist):
805 """Ensure feature is excluded from distribution
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
813 dist.exclude(**self.extras)
816 for item in self.remove:
817 dist.exclude_package(item)
821 def validate(self,dist):
823 """Verify that feature makes sense in context of distribution
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.
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)