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 ) |