Mercurial > repos > bcclaywell > argo_navis
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 ) |
