Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/setuptools/dist.py
7763 views
1
# -*- coding: utf-8 -*-
2
__all__ = ['Distribution']
3
4
import io
5
import sys
6
import re
7
import os
8
import warnings
9
import numbers
10
import distutils.log
11
import distutils.core
12
import distutils.cmd
13
import distutils.dist
14
from distutils.util import strtobool
15
from distutils.debug import DEBUG
16
from distutils.fancy_getopt import translate_longopt
17
import itertools
18
19
from collections import defaultdict
20
from email import message_from_file
21
22
from distutils.errors import DistutilsOptionError, DistutilsSetupError
23
from distutils.util import rfc822_escape
24
from distutils.version import StrictVersion
25
26
from setuptools.extern import six
27
from setuptools.extern import packaging
28
from setuptools.extern import ordered_set
29
from setuptools.extern.six.moves import map, filter, filterfalse
30
31
from . import SetuptoolsDeprecationWarning
32
33
import setuptools
34
from setuptools import windows_support
35
from setuptools.monkey import get_unpatched
36
from setuptools.config import parse_configuration
37
import pkg_resources
38
39
__import__('setuptools.extern.packaging.specifiers')
40
__import__('setuptools.extern.packaging.version')
41
42
43
def _get_unpatched(cls):
44
warnings.warn("Do not call this function", DistDeprecationWarning)
45
return get_unpatched(cls)
46
47
48
def get_metadata_version(self):
49
mv = getattr(self, 'metadata_version', None)
50
51
if mv is None:
52
if self.long_description_content_type or self.provides_extras:
53
mv = StrictVersion('2.1')
54
elif (self.maintainer is not None or
55
self.maintainer_email is not None or
56
getattr(self, 'python_requires', None) is not None or
57
self.project_urls):
58
mv = StrictVersion('1.2')
59
elif (self.provides or self.requires or self.obsoletes or
60
self.classifiers or self.download_url):
61
mv = StrictVersion('1.1')
62
else:
63
mv = StrictVersion('1.0')
64
65
self.metadata_version = mv
66
67
return mv
68
69
70
def read_pkg_file(self, file):
71
"""Reads the metadata values from a file object."""
72
msg = message_from_file(file)
73
74
def _read_field(name):
75
value = msg[name]
76
if value == 'UNKNOWN':
77
return None
78
return value
79
80
def _read_list(name):
81
values = msg.get_all(name, None)
82
if values == []:
83
return None
84
return values
85
86
self.metadata_version = StrictVersion(msg['metadata-version'])
87
self.name = _read_field('name')
88
self.version = _read_field('version')
89
self.description = _read_field('summary')
90
# we are filling author only.
91
self.author = _read_field('author')
92
self.maintainer = None
93
self.author_email = _read_field('author-email')
94
self.maintainer_email = None
95
self.url = _read_field('home-page')
96
self.license = _read_field('license')
97
98
if 'download-url' in msg:
99
self.download_url = _read_field('download-url')
100
else:
101
self.download_url = None
102
103
self.long_description = _read_field('description')
104
self.description = _read_field('summary')
105
106
if 'keywords' in msg:
107
self.keywords = _read_field('keywords').split(',')
108
109
self.platforms = _read_list('platform')
110
self.classifiers = _read_list('classifier')
111
112
# PEP 314 - these fields only exist in 1.1
113
if self.metadata_version == StrictVersion('1.1'):
114
self.requires = _read_list('requires')
115
self.provides = _read_list('provides')
116
self.obsoletes = _read_list('obsoletes')
117
else:
118
self.requires = None
119
self.provides = None
120
self.obsoletes = None
121
122
123
# Based on Python 3.5 version
124
def write_pkg_file(self, file):
125
"""Write the PKG-INFO format data to a file object.
126
"""
127
version = self.get_metadata_version()
128
129
if six.PY2:
130
def write_field(key, value):
131
file.write("%s: %s\n" % (key, self._encode_field(value)))
132
else:
133
def write_field(key, value):
134
file.write("%s: %s\n" % (key, value))
135
136
write_field('Metadata-Version', str(version))
137
write_field('Name', self.get_name())
138
write_field('Version', self.get_version())
139
write_field('Summary', self.get_description())
140
write_field('Home-page', self.get_url())
141
142
if version < StrictVersion('1.2'):
143
write_field('Author', self.get_contact())
144
write_field('Author-email', self.get_contact_email())
145
else:
146
optional_fields = (
147
('Author', 'author'),
148
('Author-email', 'author_email'),
149
('Maintainer', 'maintainer'),
150
('Maintainer-email', 'maintainer_email'),
151
)
152
153
for field, attr in optional_fields:
154
attr_val = getattr(self, attr)
155
156
if attr_val is not None:
157
write_field(field, attr_val)
158
159
write_field('License', self.get_license())
160
if self.download_url:
161
write_field('Download-URL', self.download_url)
162
for project_url in self.project_urls.items():
163
write_field('Project-URL', '%s, %s' % project_url)
164
165
long_desc = rfc822_escape(self.get_long_description())
166
write_field('Description', long_desc)
167
168
keywords = ','.join(self.get_keywords())
169
if keywords:
170
write_field('Keywords', keywords)
171
172
if version >= StrictVersion('1.2'):
173
for platform in self.get_platforms():
174
write_field('Platform', platform)
175
else:
176
self._write_list(file, 'Platform', self.get_platforms())
177
178
self._write_list(file, 'Classifier', self.get_classifiers())
179
180
# PEP 314
181
self._write_list(file, 'Requires', self.get_requires())
182
self._write_list(file, 'Provides', self.get_provides())
183
self._write_list(file, 'Obsoletes', self.get_obsoletes())
184
185
# Setuptools specific for PEP 345
186
if hasattr(self, 'python_requires'):
187
write_field('Requires-Python', self.python_requires)
188
189
# PEP 566
190
if self.long_description_content_type:
191
write_field(
192
'Description-Content-Type',
193
self.long_description_content_type
194
)
195
if self.provides_extras:
196
for extra in self.provides_extras:
197
write_field('Provides-Extra', extra)
198
199
200
sequence = tuple, list
201
202
203
def check_importable(dist, attr, value):
204
try:
205
ep = pkg_resources.EntryPoint.parse('x=' + value)
206
assert not ep.extras
207
except (TypeError, ValueError, AttributeError, AssertionError) as e:
208
raise DistutilsSetupError(
209
"%r must be importable 'module:attrs' string (got %r)"
210
% (attr, value)
211
) from e
212
213
214
def assert_string_list(dist, attr, value):
215
"""Verify that value is a string list"""
216
try:
217
# verify that value is a list or tuple to exclude unordered
218
# or single-use iterables
219
assert isinstance(value, (list, tuple))
220
# verify that elements of value are strings
221
assert ''.join(value) != value
222
except (TypeError, ValueError, AttributeError, AssertionError) as e:
223
raise DistutilsSetupError(
224
"%r must be a list of strings (got %r)" % (attr, value)
225
) from e
226
227
228
def check_nsp(dist, attr, value):
229
"""Verify that namespace packages are valid"""
230
ns_packages = value
231
assert_string_list(dist, attr, ns_packages)
232
for nsp in ns_packages:
233
if not dist.has_contents_for(nsp):
234
raise DistutilsSetupError(
235
"Distribution contains no modules or packages for " +
236
"namespace package %r" % nsp
237
)
238
parent, sep, child = nsp.rpartition('.')
239
if parent and parent not in ns_packages:
240
distutils.log.warn(
241
"WARNING: %r is declared as a package namespace, but %r"
242
" is not: please correct this in setup.py", nsp, parent
243
)
244
245
246
def check_extras(dist, attr, value):
247
"""Verify that extras_require mapping is valid"""
248
try:
249
list(itertools.starmap(_check_extra, value.items()))
250
except (TypeError, ValueError, AttributeError) as e:
251
raise DistutilsSetupError(
252
"'extras_require' must be a dictionary whose values are "
253
"strings or lists of strings containing valid project/version "
254
"requirement specifiers."
255
) from e
256
257
258
def _check_extra(extra, reqs):
259
name, sep, marker = extra.partition(':')
260
if marker and pkg_resources.invalid_marker(marker):
261
raise DistutilsSetupError("Invalid environment marker: " + marker)
262
list(pkg_resources.parse_requirements(reqs))
263
264
265
def assert_bool(dist, attr, value):
266
"""Verify that value is True, False, 0, or 1"""
267
if bool(value) != value:
268
tmpl = "{attr!r} must be a boolean value (got {value!r})"
269
raise DistutilsSetupError(tmpl.format(attr=attr, value=value))
270
271
272
def check_requirements(dist, attr, value):
273
"""Verify that install_requires is a valid requirements list"""
274
try:
275
list(pkg_resources.parse_requirements(value))
276
if isinstance(value, (dict, set)):
277
raise TypeError("Unordered types are not allowed")
278
except (TypeError, ValueError) as error:
279
tmpl = (
280
"{attr!r} must be a string or list of strings "
281
"containing valid project/version requirement specifiers; {error}"
282
)
283
raise DistutilsSetupError(
284
tmpl.format(attr=attr, error=error)
285
) from error
286
287
288
def check_specifier(dist, attr, value):
289
"""Verify that value is a valid version specifier"""
290
try:
291
packaging.specifiers.SpecifierSet(value)
292
except packaging.specifiers.InvalidSpecifier as error:
293
tmpl = (
294
"{attr!r} must be a string "
295
"containing valid version specifiers; {error}"
296
)
297
raise DistutilsSetupError(
298
tmpl.format(attr=attr, error=error)
299
) from error
300
301
302
def check_entry_points(dist, attr, value):
303
"""Verify that entry_points map is parseable"""
304
try:
305
pkg_resources.EntryPoint.parse_map(value)
306
except ValueError as e:
307
raise DistutilsSetupError(e) from e
308
309
310
def check_test_suite(dist, attr, value):
311
if not isinstance(value, six.string_types):
312
raise DistutilsSetupError("test_suite must be a string")
313
314
315
def check_package_data(dist, attr, value):
316
"""Verify that value is a dictionary of package names to glob lists"""
317
if not isinstance(value, dict):
318
raise DistutilsSetupError(
319
"{!r} must be a dictionary mapping package names to lists of "
320
"string wildcard patterns".format(attr))
321
for k, v in value.items():
322
if not isinstance(k, six.string_types):
323
raise DistutilsSetupError(
324
"keys of {!r} dict must be strings (got {!r})"
325
.format(attr, k)
326
)
327
assert_string_list(dist, 'values of {!r} dict'.format(attr), v)
328
329
330
def check_packages(dist, attr, value):
331
for pkgname in value:
332
if not re.match(r'\w+(\.\w+)*', pkgname):
333
distutils.log.warn(
334
"WARNING: %r not a valid package name; please use only "
335
".-separated package names in setup.py", pkgname
336
)
337
338
339
_Distribution = get_unpatched(distutils.core.Distribution)
340
341
342
class Distribution(_Distribution):
343
"""Distribution with support for tests and package data
344
345
This is an enhanced version of 'distutils.dist.Distribution' that
346
effectively adds the following new optional keyword arguments to 'setup()':
347
348
'install_requires' -- a string or sequence of strings specifying project
349
versions that the distribution requires when installed, in the format
350
used by 'pkg_resources.require()'. They will be installed
351
automatically when the package is installed. If you wish to use
352
packages that are not available in PyPI, or want to give your users an
353
alternate download location, you can add a 'find_links' option to the
354
'[easy_install]' section of your project's 'setup.cfg' file, and then
355
setuptools will scan the listed web pages for links that satisfy the
356
requirements.
357
358
'extras_require' -- a dictionary mapping names of optional "extras" to the
359
additional requirement(s) that using those extras incurs. For example,
360
this::
361
362
extras_require = dict(reST = ["docutils>=0.3", "reSTedit"])
363
364
indicates that the distribution can optionally provide an extra
365
capability called "reST", but it can only be used if docutils and
366
reSTedit are installed. If the user installs your package using
367
EasyInstall and requests one of your extras, the corresponding
368
additional requirements will be installed if needed.
369
370
'test_suite' -- the name of a test suite to run for the 'test' command.
371
If the user runs 'python setup.py test', the package will be installed,
372
and the named test suite will be run. The format is the same as
373
would be used on a 'unittest.py' command line. That is, it is the
374
dotted name of an object to import and call to generate a test suite.
375
376
'package_data' -- a dictionary mapping package names to lists of filenames
377
or globs to use to find data files contained in the named packages.
378
If the dictionary has filenames or globs listed under '""' (the empty
379
string), those names will be searched for in every package, in addition
380
to any names for the specific package. Data files found using these
381
names/globs will be installed along with the package, in the same
382
location as the package. Note that globs are allowed to reference
383
the contents of non-package subdirectories, as long as you use '/' as
384
a path separator. (Globs are automatically converted to
385
platform-specific paths at runtime.)
386
387
In addition to these new keywords, this class also has several new methods
388
for manipulating the distribution's contents. For example, the 'include()'
389
and 'exclude()' methods can be thought of as in-place add and subtract
390
commands that add or remove packages, modules, extensions, and so on from
391
the distribution.
392
"""
393
394
_DISTUTILS_UNSUPPORTED_METADATA = {
395
'long_description_content_type': None,
396
'project_urls': dict,
397
'provides_extras': ordered_set.OrderedSet,
398
'license_files': ordered_set.OrderedSet,
399
}
400
401
_patched_dist = None
402
403
def patch_missing_pkg_info(self, attrs):
404
# Fake up a replacement for the data that would normally come from
405
# PKG-INFO, but which might not yet be built if this is a fresh
406
# checkout.
407
#
408
if not attrs or 'name' not in attrs or 'version' not in attrs:
409
return
410
key = pkg_resources.safe_name(str(attrs['name'])).lower()
411
dist = pkg_resources.working_set.by_key.get(key)
412
if dist is not None and not dist.has_metadata('PKG-INFO'):
413
dist._version = pkg_resources.safe_version(str(attrs['version']))
414
self._patched_dist = dist
415
416
def __init__(self, attrs=None):
417
have_package_data = hasattr(self, "package_data")
418
if not have_package_data:
419
self.package_data = {}
420
attrs = attrs or {}
421
self.dist_files = []
422
# Filter-out setuptools' specific options.
423
self.src_root = attrs.pop("src_root", None)
424
self.patch_missing_pkg_info(attrs)
425
self.dependency_links = attrs.pop('dependency_links', [])
426
self.setup_requires = attrs.pop('setup_requires', [])
427
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
428
vars(self).setdefault(ep.name, None)
429
_Distribution.__init__(self, {
430
k: v for k, v in attrs.items()
431
if k not in self._DISTUTILS_UNSUPPORTED_METADATA
432
})
433
434
# Fill-in missing metadata fields not supported by distutils.
435
# Note some fields may have been set by other tools (e.g. pbr)
436
# above; they are taken preferrentially to setup() arguments
437
for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items():
438
for source in self.metadata.__dict__, attrs:
439
if option in source:
440
value = source[option]
441
break
442
else:
443
value = default() if default else None
444
setattr(self.metadata, option, value)
445
446
self.metadata.version = self._normalize_version(
447
self._validate_version(self.metadata.version))
448
self._finalize_requires()
449
450
@staticmethod
451
def _normalize_version(version):
452
if isinstance(version, setuptools.sic) or version is None:
453
return version
454
455
normalized = str(packaging.version.Version(version))
456
if version != normalized:
457
tmpl = "Normalizing '{version}' to '{normalized}'"
458
warnings.warn(tmpl.format(**locals()))
459
return normalized
460
return version
461
462
@staticmethod
463
def _validate_version(version):
464
if isinstance(version, numbers.Number):
465
# Some people apparently take "version number" too literally :)
466
version = str(version)
467
468
if version is not None:
469
try:
470
packaging.version.Version(version)
471
except (packaging.version.InvalidVersion, TypeError):
472
warnings.warn(
473
"The version specified (%r) is an invalid version, this "
474
"may not work as expected with newer versions of "
475
"setuptools, pip, and PyPI. Please see PEP 440 for more "
476
"details." % version
477
)
478
return setuptools.sic(version)
479
return version
480
481
def _finalize_requires(self):
482
"""
483
Set `metadata.python_requires` and fix environment markers
484
in `install_requires` and `extras_require`.
485
"""
486
if getattr(self, 'python_requires', None):
487
self.metadata.python_requires = self.python_requires
488
489
if getattr(self, 'extras_require', None):
490
for extra in self.extras_require.keys():
491
# Since this gets called multiple times at points where the
492
# keys have become 'converted' extras, ensure that we are only
493
# truly adding extras we haven't seen before here.
494
extra = extra.split(':')[0]
495
if extra:
496
self.metadata.provides_extras.add(extra)
497
498
self._convert_extras_requirements()
499
self._move_install_requirements_markers()
500
501
def _convert_extras_requirements(self):
502
"""
503
Convert requirements in `extras_require` of the form
504
`"extra": ["barbazquux; {marker}"]` to
505
`"extra:{marker}": ["barbazquux"]`.
506
"""
507
spec_ext_reqs = getattr(self, 'extras_require', None) or {}
508
self._tmp_extras_require = defaultdict(list)
509
for section, v in spec_ext_reqs.items():
510
# Do not strip empty sections.
511
self._tmp_extras_require[section]
512
for r in pkg_resources.parse_requirements(v):
513
suffix = self._suffix_for(r)
514
self._tmp_extras_require[section + suffix].append(r)
515
516
@staticmethod
517
def _suffix_for(req):
518
"""
519
For a requirement, return the 'extras_require' suffix for
520
that requirement.
521
"""
522
return ':' + str(req.marker) if req.marker else ''
523
524
def _move_install_requirements_markers(self):
525
"""
526
Move requirements in `install_requires` that are using environment
527
markers `extras_require`.
528
"""
529
530
# divide the install_requires into two sets, simple ones still
531
# handled by install_requires and more complex ones handled
532
# by extras_require.
533
534
def is_simple_req(req):
535
return not req.marker
536
537
spec_inst_reqs = getattr(self, 'install_requires', None) or ()
538
inst_reqs = list(pkg_resources.parse_requirements(spec_inst_reqs))
539
simple_reqs = filter(is_simple_req, inst_reqs)
540
complex_reqs = filterfalse(is_simple_req, inst_reqs)
541
self.install_requires = list(map(str, simple_reqs))
542
543
for r in complex_reqs:
544
self._tmp_extras_require[':' + str(r.marker)].append(r)
545
self.extras_require = dict(
546
(k, [str(r) for r in map(self._clean_req, v)])
547
for k, v in self._tmp_extras_require.items()
548
)
549
550
def _clean_req(self, req):
551
"""
552
Given a Requirement, remove environment markers and return it.
553
"""
554
req.marker = None
555
return req
556
557
def _parse_config_files(self, filenames=None):
558
"""
559
Adapted from distutils.dist.Distribution.parse_config_files,
560
this method provides the same functionality in subtly-improved
561
ways.
562
"""
563
from setuptools.extern.six.moves.configparser import ConfigParser
564
565
# Ignore install directory options if we have a venv
566
if not six.PY2 and sys.prefix != sys.base_prefix:
567
ignore_options = [
568
'install-base', 'install-platbase', 'install-lib',
569
'install-platlib', 'install-purelib', 'install-headers',
570
'install-scripts', 'install-data', 'prefix', 'exec-prefix',
571
'home', 'user', 'root']
572
else:
573
ignore_options = []
574
575
ignore_options = frozenset(ignore_options)
576
577
if filenames is None:
578
filenames = self.find_config_files()
579
580
if DEBUG:
581
self.announce("Distribution.parse_config_files():")
582
583
parser = ConfigParser()
584
for filename in filenames:
585
with io.open(filename, encoding='utf-8') as reader:
586
if DEBUG:
587
self.announce(" reading {filename}".format(**locals()))
588
(parser.readfp if six.PY2 else parser.read_file)(reader)
589
for section in parser.sections():
590
options = parser.options(section)
591
opt_dict = self.get_option_dict(section)
592
593
for opt in options:
594
if opt != '__name__' and opt not in ignore_options:
595
val = self._try_str(parser.get(section, opt))
596
opt = opt.replace('-', '_')
597
opt_dict[opt] = (filename, val)
598
599
# Make the ConfigParser forget everything (so we retain
600
# the original filenames that options come from)
601
parser.__init__()
602
603
# If there was a "global" section in the config file, use it
604
# to set Distribution options.
605
606
if 'global' in self.command_options:
607
for (opt, (src, val)) in self.command_options['global'].items():
608
alias = self.negative_opt.get(opt)
609
try:
610
if alias:
611
setattr(self, alias, not strtobool(val))
612
elif opt in ('verbose', 'dry_run'): # ugh!
613
setattr(self, opt, strtobool(val))
614
else:
615
setattr(self, opt, val)
616
except ValueError as e:
617
raise DistutilsOptionError(e) from e
618
619
@staticmethod
620
def _try_str(val):
621
"""
622
On Python 2, much of distutils relies on string values being of
623
type 'str' (bytes) and not unicode text. If the value can be safely
624
encoded to bytes using the default encoding, prefer that.
625
626
Why the default encoding? Because that value can be implicitly
627
decoded back to text if needed.
628
629
Ref #1653
630
"""
631
if not six.PY2:
632
return val
633
try:
634
return val.encode()
635
except UnicodeEncodeError:
636
pass
637
return val
638
639
def _set_command_options(self, command_obj, option_dict=None):
640
"""
641
Set the options for 'command_obj' from 'option_dict'. Basically
642
this means copying elements of a dictionary ('option_dict') to
643
attributes of an instance ('command').
644
645
'command_obj' must be a Command instance. If 'option_dict' is not
646
supplied, uses the standard option dictionary for this command
647
(from 'self.command_options').
648
649
(Adopted from distutils.dist.Distribution._set_command_options)
650
"""
651
command_name = command_obj.get_command_name()
652
if option_dict is None:
653
option_dict = self.get_option_dict(command_name)
654
655
if DEBUG:
656
self.announce(" setting options for '%s' command:" % command_name)
657
for (option, (source, value)) in option_dict.items():
658
if DEBUG:
659
self.announce(" %s = %s (from %s)" % (option, value,
660
source))
661
try:
662
bool_opts = [translate_longopt(o)
663
for o in command_obj.boolean_options]
664
except AttributeError:
665
bool_opts = []
666
try:
667
neg_opt = command_obj.negative_opt
668
except AttributeError:
669
neg_opt = {}
670
671
try:
672
is_string = isinstance(value, six.string_types)
673
if option in neg_opt and is_string:
674
setattr(command_obj, neg_opt[option], not strtobool(value))
675
elif option in bool_opts and is_string:
676
setattr(command_obj, option, strtobool(value))
677
elif hasattr(command_obj, option):
678
setattr(command_obj, option, value)
679
else:
680
raise DistutilsOptionError(
681
"error in %s: command '%s' has no such option '%s'"
682
% (source, command_name, option))
683
except ValueError as e:
684
raise DistutilsOptionError(e) from e
685
686
def parse_config_files(self, filenames=None, ignore_option_errors=False):
687
"""Parses configuration files from various levels
688
and loads configuration.
689
690
"""
691
self._parse_config_files(filenames=filenames)
692
693
parse_configuration(self, self.command_options,
694
ignore_option_errors=ignore_option_errors)
695
self._finalize_requires()
696
697
def fetch_build_eggs(self, requires):
698
"""Resolve pre-setup requirements"""
699
resolved_dists = pkg_resources.working_set.resolve(
700
pkg_resources.parse_requirements(requires),
701
installer=self.fetch_build_egg,
702
replace_conflicting=True,
703
)
704
for dist in resolved_dists:
705
pkg_resources.working_set.add(dist, replace=True)
706
return resolved_dists
707
708
def finalize_options(self):
709
"""
710
Allow plugins to apply arbitrary operations to the
711
distribution. Each hook may optionally define a 'order'
712
to influence the order of execution. Smaller numbers
713
go first and the default is 0.
714
"""
715
group = 'setuptools.finalize_distribution_options'
716
717
def by_order(hook):
718
return getattr(hook, 'order', 0)
719
eps = map(lambda e: e.load(), pkg_resources.iter_entry_points(group))
720
for ep in sorted(eps, key=by_order):
721
ep(self)
722
723
def _finalize_setup_keywords(self):
724
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
725
value = getattr(self, ep.name, None)
726
if value is not None:
727
ep.require(installer=self.fetch_build_egg)
728
ep.load()(self, ep.name, value)
729
730
def _finalize_2to3_doctests(self):
731
if getattr(self, 'convert_2to3_doctests', None):
732
# XXX may convert to set here when we can rely on set being builtin
733
self.convert_2to3_doctests = [
734
os.path.abspath(p)
735
for p in self.convert_2to3_doctests
736
]
737
else:
738
self.convert_2to3_doctests = []
739
740
def get_egg_cache_dir(self):
741
egg_cache_dir = os.path.join(os.curdir, '.eggs')
742
if not os.path.exists(egg_cache_dir):
743
os.mkdir(egg_cache_dir)
744
windows_support.hide_file(egg_cache_dir)
745
readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
746
with open(readme_txt_filename, 'w') as f:
747
f.write('This directory contains eggs that were downloaded '
748
'by setuptools to build, test, and run plug-ins.\n\n')
749
f.write('This directory caches those eggs to prevent '
750
'repeated downloads.\n\n')
751
f.write('However, it is safe to delete this directory.\n\n')
752
753
return egg_cache_dir
754
755
def fetch_build_egg(self, req):
756
"""Fetch an egg needed for building"""
757
from setuptools.installer import fetch_build_egg
758
return fetch_build_egg(self, req)
759
760
def get_command_class(self, command):
761
"""Pluggable version of get_command_class()"""
762
if command in self.cmdclass:
763
return self.cmdclass[command]
764
765
eps = pkg_resources.iter_entry_points('distutils.commands', command)
766
for ep in eps:
767
ep.require(installer=self.fetch_build_egg)
768
self.cmdclass[command] = cmdclass = ep.load()
769
return cmdclass
770
else:
771
return _Distribution.get_command_class(self, command)
772
773
def print_commands(self):
774
for ep in pkg_resources.iter_entry_points('distutils.commands'):
775
if ep.name not in self.cmdclass:
776
# don't require extras as the commands won't be invoked
777
cmdclass = ep.resolve()
778
self.cmdclass[ep.name] = cmdclass
779
return _Distribution.print_commands(self)
780
781
def get_command_list(self):
782
for ep in pkg_resources.iter_entry_points('distutils.commands'):
783
if ep.name not in self.cmdclass:
784
# don't require extras as the commands won't be invoked
785
cmdclass = ep.resolve()
786
self.cmdclass[ep.name] = cmdclass
787
return _Distribution.get_command_list(self)
788
789
def include(self, **attrs):
790
"""Add items to distribution that are named in keyword arguments
791
792
For example, 'dist.include(py_modules=["x"])' would add 'x' to
793
the distribution's 'py_modules' attribute, if it was not already
794
there.
795
796
Currently, this method only supports inclusion for attributes that are
797
lists or tuples. If you need to add support for adding to other
798
attributes in this or a subclass, you can add an '_include_X' method,
799
where 'X' is the name of the attribute. The method will be called with
800
the value passed to 'include()'. So, 'dist.include(foo={"bar":"baz"})'
801
will try to call 'dist._include_foo({"bar":"baz"})', which can then
802
handle whatever special inclusion logic is needed.
803
"""
804
for k, v in attrs.items():
805
include = getattr(self, '_include_' + k, None)
806
if include:
807
include(v)
808
else:
809
self._include_misc(k, v)
810
811
def exclude_package(self, package):
812
"""Remove packages, modules, and extensions in named package"""
813
814
pfx = package + '.'
815
if self.packages:
816
self.packages = [
817
p for p in self.packages
818
if p != package and not p.startswith(pfx)
819
]
820
821
if self.py_modules:
822
self.py_modules = [
823
p for p in self.py_modules
824
if p != package and not p.startswith(pfx)
825
]
826
827
if self.ext_modules:
828
self.ext_modules = [
829
p for p in self.ext_modules
830
if p.name != package and not p.name.startswith(pfx)
831
]
832
833
def has_contents_for(self, package):
834
"""Return true if 'exclude_package(package)' would do something"""
835
836
pfx = package + '.'
837
838
for p in self.iter_distribution_names():
839
if p == package or p.startswith(pfx):
840
return True
841
842
def _exclude_misc(self, name, value):
843
"""Handle 'exclude()' for list/tuple attrs without a special handler"""
844
if not isinstance(value, sequence):
845
raise DistutilsSetupError(
846
"%s: setting must be a list or tuple (%r)" % (name, value)
847
)
848
try:
849
old = getattr(self, name)
850
except AttributeError as e:
851
raise DistutilsSetupError(
852
"%s: No such distribution setting" % name
853
) from e
854
if old is not None and not isinstance(old, sequence):
855
raise DistutilsSetupError(
856
name + ": this setting cannot be changed via include/exclude"
857
)
858
elif old:
859
setattr(self, name, [item for item in old if item not in value])
860
861
def _include_misc(self, name, value):
862
"""Handle 'include()' for list/tuple attrs without a special handler"""
863
864
if not isinstance(value, sequence):
865
raise DistutilsSetupError(
866
"%s: setting must be a list (%r)" % (name, value)
867
)
868
try:
869
old = getattr(self, name)
870
except AttributeError as e:
871
raise DistutilsSetupError(
872
"%s: No such distribution setting" % name
873
) from e
874
if old is None:
875
setattr(self, name, value)
876
elif not isinstance(old, sequence):
877
raise DistutilsSetupError(
878
name + ": this setting cannot be changed via include/exclude"
879
)
880
else:
881
new = [item for item in value if item not in old]
882
setattr(self, name, old + new)
883
884
def exclude(self, **attrs):
885
"""Remove items from distribution that are named in keyword arguments
886
887
For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from
888
the distribution's 'py_modules' attribute. Excluding packages uses
889
the 'exclude_package()' method, so all of the package's contained
890
packages, modules, and extensions are also excluded.
891
892
Currently, this method only supports exclusion from attributes that are
893
lists or tuples. If you need to add support for excluding from other
894
attributes in this or a subclass, you can add an '_exclude_X' method,
895
where 'X' is the name of the attribute. The method will be called with
896
the value passed to 'exclude()'. So, 'dist.exclude(foo={"bar":"baz"})'
897
will try to call 'dist._exclude_foo({"bar":"baz"})', which can then
898
handle whatever special exclusion logic is needed.
899
"""
900
for k, v in attrs.items():
901
exclude = getattr(self, '_exclude_' + k, None)
902
if exclude:
903
exclude(v)
904
else:
905
self._exclude_misc(k, v)
906
907
def _exclude_packages(self, packages):
908
if not isinstance(packages, sequence):
909
raise DistutilsSetupError(
910
"packages: setting must be a list or tuple (%r)" % (packages,)
911
)
912
list(map(self.exclude_package, packages))
913
914
def _parse_command_opts(self, parser, args):
915
# Remove --with-X/--without-X options when processing command args
916
self.global_options = self.__class__.global_options
917
self.negative_opt = self.__class__.negative_opt
918
919
# First, expand any aliases
920
command = args[0]
921
aliases = self.get_option_dict('aliases')
922
while command in aliases:
923
src, alias = aliases[command]
924
del aliases[command] # ensure each alias can expand only once!
925
import shlex
926
args[:1] = shlex.split(alias, True)
927
command = args[0]
928
929
nargs = _Distribution._parse_command_opts(self, parser, args)
930
931
# Handle commands that want to consume all remaining arguments
932
cmd_class = self.get_command_class(command)
933
if getattr(cmd_class, 'command_consumes_arguments', None):
934
self.get_option_dict(command)['args'] = ("command line", nargs)
935
if nargs is not None:
936
return []
937
938
return nargs
939
940
def get_cmdline_options(self):
941
"""Return a '{cmd: {opt:val}}' map of all command-line options
942
943
Option names are all long, but do not include the leading '--', and
944
contain dashes rather than underscores. If the option doesn't take
945
an argument (e.g. '--quiet'), the 'val' is 'None'.
946
947
Note that options provided by config files are intentionally excluded.
948
"""
949
950
d = {}
951
952
for cmd, opts in self.command_options.items():
953
954
for opt, (src, val) in opts.items():
955
956
if src != "command line":
957
continue
958
959
opt = opt.replace('_', '-')
960
961
if val == 0:
962
cmdobj = self.get_command_obj(cmd)
963
neg_opt = self.negative_opt.copy()
964
neg_opt.update(getattr(cmdobj, 'negative_opt', {}))
965
for neg, pos in neg_opt.items():
966
if pos == opt:
967
opt = neg
968
val = None
969
break
970
else:
971
raise AssertionError("Shouldn't be able to get here")
972
973
elif val == 1:
974
val = None
975
976
d.setdefault(cmd, {})[opt] = val
977
978
return d
979
980
def iter_distribution_names(self):
981
"""Yield all packages, modules, and extension names in distribution"""
982
983
for pkg in self.packages or ():
984
yield pkg
985
986
for module in self.py_modules or ():
987
yield module
988
989
for ext in self.ext_modules or ():
990
if isinstance(ext, tuple):
991
name, buildinfo = ext
992
else:
993
name = ext.name
994
if name.endswith('module'):
995
name = name[:-6]
996
yield name
997
998
def handle_display_options(self, option_order):
999
"""If there were any non-global "display-only" options
1000
(--help-commands or the metadata display options) on the command
1001
line, display the requested info and return true; else return
1002
false.
1003
"""
1004
import sys
1005
1006
if six.PY2 or self.help_commands:
1007
return _Distribution.handle_display_options(self, option_order)
1008
1009
# Stdout may be StringIO (e.g. in tests)
1010
if not isinstance(sys.stdout, io.TextIOWrapper):
1011
return _Distribution.handle_display_options(self, option_order)
1012
1013
# Don't wrap stdout if utf-8 is already the encoding. Provides
1014
# workaround for #334.
1015
if sys.stdout.encoding.lower() in ('utf-8', 'utf8'):
1016
return _Distribution.handle_display_options(self, option_order)
1017
1018
# Print metadata in UTF-8 no matter the platform
1019
encoding = sys.stdout.encoding
1020
errors = sys.stdout.errors
1021
newline = sys.platform != 'win32' and '\n' or None
1022
line_buffering = sys.stdout.line_buffering
1023
1024
sys.stdout = io.TextIOWrapper(
1025
sys.stdout.detach(), 'utf-8', errors, newline, line_buffering)
1026
try:
1027
return _Distribution.handle_display_options(self, option_order)
1028
finally:
1029
sys.stdout = io.TextIOWrapper(
1030
sys.stdout.detach(), encoding, errors, newline, line_buffering)
1031
1032
1033
class DistDeprecationWarning(SetuptoolsDeprecationWarning):
1034
"""Class for warning about deprecations in dist in
1035
setuptools. Not ignored by default, unlike DeprecationWarning."""
1036
1037