~ibmcharmers/charms/xenial/ibm-cinder-flashsystem/trunk

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/setuptools/config.py

  • Committer: anitanayak at ibm
  • Date: 2017-02-10 06:46:37 UTC
  • Revision ID: anitanayak@in.ibm.com-20170210064637-h7pp0k5eu6wbt4b5
Check in after removing hardcoded values

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from __future__ import absolute_import, unicode_literals
2
 
import io
3
 
import os
4
 
import sys
5
 
from collections import defaultdict
6
 
from functools import partial
7
 
 
8
 
from distutils.errors import DistutilsOptionError, DistutilsFileError
9
 
from setuptools.py26compat import import_module
10
 
from six import string_types
11
 
 
12
 
 
13
 
def read_configuration(
14
 
        filepath, find_others=False, ignore_option_errors=False):
15
 
    """Read given configuration file and returns options from it as a dict.
16
 
 
17
 
    :param str|unicode filepath: Path to configuration file
18
 
        to get options from.
19
 
 
20
 
    :param bool find_others: Whether to search for other configuration files
21
 
        which could be on in various places.
22
 
 
23
 
    :param bool ignore_option_errors: Whether to silently ignore
24
 
        options, values of which could not be resolved (e.g. due to exceptions
25
 
        in directives such as file:, attr:, etc.).
26
 
        If False exceptions are propagated as expected.
27
 
 
28
 
    :rtype: dict
29
 
    """
30
 
    from setuptools.dist import Distribution, _Distribution
31
 
 
32
 
    filepath = os.path.abspath(filepath)
33
 
 
34
 
    if not os.path.isfile(filepath):
35
 
        raise DistutilsFileError(
36
 
            'Configuration file %s does not exist.' % filepath)
37
 
 
38
 
    current_directory = os.getcwd()
39
 
    os.chdir(os.path.dirname(filepath))
40
 
 
41
 
    try:
42
 
        dist = Distribution()
43
 
 
44
 
        filenames = dist.find_config_files() if find_others else []
45
 
        if filepath not in filenames:
46
 
            filenames.append(filepath)
47
 
 
48
 
        _Distribution.parse_config_files(dist, filenames=filenames)
49
 
 
50
 
        handlers = parse_configuration(
51
 
            dist, dist.command_options,
52
 
            ignore_option_errors=ignore_option_errors)
53
 
 
54
 
    finally:
55
 
        os.chdir(current_directory)
56
 
 
57
 
    return configuration_to_dict(handlers)
58
 
 
59
 
 
60
 
def configuration_to_dict(handlers):
61
 
    """Returns configuration data gathered by given handlers as a dict.
62
 
 
63
 
    :param list[ConfigHandler] handlers: Handlers list,
64
 
        usually from parse_configuration()
65
 
 
66
 
    :rtype: dict
67
 
    """
68
 
    config_dict = defaultdict(dict)
69
 
 
70
 
    for handler in handlers:
71
 
 
72
 
        obj_alias = handler.section_prefix
73
 
        target_obj = handler.target_obj
74
 
 
75
 
        for option in handler.set_options:
76
 
            getter = getattr(target_obj, 'get_%s' % option, None)
77
 
 
78
 
            if getter is None:
79
 
                value = getattr(target_obj, option)
80
 
 
81
 
            else:
82
 
                value = getter()
83
 
 
84
 
            config_dict[obj_alias][option] = value
85
 
 
86
 
    return config_dict
87
 
 
88
 
 
89
 
def parse_configuration(
90
 
        distribution, command_options, ignore_option_errors=False):
91
 
    """Performs additional parsing of configuration options
92
 
    for a distribution.
93
 
 
94
 
    Returns a list of used option handlers.
95
 
 
96
 
    :param Distribution distribution:
97
 
    :param dict command_options:
98
 
    :param bool ignore_option_errors: Whether to silently ignore
99
 
        options, values of which could not be resolved (e.g. due to exceptions
100
 
        in directives such as file:, attr:, etc.).
101
 
        If False exceptions are propagated as expected.
102
 
    :rtype: list
103
 
    """
104
 
    meta = ConfigMetadataHandler(
105
 
        distribution.metadata, command_options, ignore_option_errors)
106
 
    meta.parse()
107
 
 
108
 
    options = ConfigOptionsHandler(
109
 
        distribution, command_options, ignore_option_errors)
110
 
    options.parse()
111
 
 
112
 
    return [meta, options]
113
 
 
114
 
 
115
 
class ConfigHandler(object):
116
 
    """Handles metadata supplied in configuration files."""
117
 
 
118
 
    section_prefix = None
119
 
    """Prefix for config sections handled by this handler.
120
 
    Must be provided by class heirs.
121
 
 
122
 
    """
123
 
 
124
 
    aliases = {}
125
 
    """Options aliases.
126
 
    For compatibility with various packages. E.g.: d2to1 and pbr.
127
 
    Note: `-` in keys is replaced with `_` by config parser.
128
 
 
129
 
    """
130
 
 
131
 
    def __init__(self, target_obj, options, ignore_option_errors=False):
132
 
        sections = {}
133
 
 
134
 
        section_prefix = self.section_prefix
135
 
        for section_name, section_options in options.items():
136
 
            if not section_name.startswith(section_prefix):
137
 
                continue
138
 
 
139
 
            section_name = section_name.replace(section_prefix, '').strip('.')
140
 
            sections[section_name] = section_options
141
 
 
142
 
        self.ignore_option_errors = ignore_option_errors
143
 
        self.target_obj = target_obj
144
 
        self.sections = sections
145
 
        self.set_options = []
146
 
 
147
 
    @property
148
 
    def parsers(self):
149
 
        """Metadata item name to parser function mapping."""
150
 
        raise NotImplementedError(
151
 
            '%s must provide .parsers property' % self.__class__.__name__)
152
 
 
153
 
    def __setitem__(self, option_name, value):
154
 
        unknown = tuple()
155
 
        target_obj = self.target_obj
156
 
 
157
 
        # Translate alias into real name.
158
 
        option_name = self.aliases.get(option_name, option_name)
159
 
 
160
 
        current_value = getattr(target_obj, option_name, unknown)
161
 
 
162
 
        if current_value is unknown:
163
 
            raise KeyError(option_name)
164
 
 
165
 
        if current_value:
166
 
            # Already inhabited. Skipping.
167
 
            return
168
 
 
169
 
        skip_option = False
170
 
        parser = self.parsers.get(option_name)
171
 
        if parser:
172
 
            try:
173
 
                value = parser(value)
174
 
 
175
 
            except Exception:
176
 
                skip_option = True
177
 
                if not self.ignore_option_errors:
178
 
                    raise
179
 
 
180
 
        if skip_option:
181
 
            return
182
 
 
183
 
        setter = getattr(target_obj, 'set_%s' % option_name, None)
184
 
        if setter is None:
185
 
            setattr(target_obj, option_name, value)
186
 
        else:
187
 
            setter(value)
188
 
 
189
 
        self.set_options.append(option_name)
190
 
 
191
 
    @classmethod
192
 
    def _parse_list(cls, value, separator=','):
193
 
        """Represents value as a list.
194
 
 
195
 
        Value is split either by separator (defaults to comma) or by lines.
196
 
 
197
 
        :param value:
198
 
        :param separator: List items separator character.
199
 
        :rtype: list
200
 
        """
201
 
        if isinstance(value, list):  # _get_parser_compound case
202
 
            return value
203
 
 
204
 
        if '\n' in value:
205
 
            value = value.splitlines()
206
 
        else:
207
 
            value = value.split(separator)
208
 
 
209
 
        return [chunk.strip() for chunk in value if chunk.strip()]
210
 
 
211
 
    @classmethod
212
 
    def _parse_dict(cls, value):
213
 
        """Represents value as a dict.
214
 
 
215
 
        :param value:
216
 
        :rtype: dict
217
 
        """
218
 
        separator = '='
219
 
        result = {}
220
 
        for line in cls._parse_list(value):
221
 
            key, sep, val = line.partition(separator)
222
 
            if sep != separator:
223
 
                raise DistutilsOptionError(
224
 
                    'Unable to parse option value to dict: %s' % value)
225
 
            result[key.strip()] = val.strip()
226
 
 
227
 
        return result
228
 
 
229
 
    @classmethod
230
 
    def _parse_bool(cls, value):
231
 
        """Represents value as boolean.
232
 
 
233
 
        :param value:
234
 
        :rtype: bool
235
 
        """
236
 
        value = value.lower()
237
 
        return value in ('1', 'true', 'yes')
238
 
 
239
 
    @classmethod
240
 
    def _parse_file(cls, value):
241
 
        """Represents value as a string, allowing including text
242
 
        from nearest files using `file:` directive.
243
 
 
244
 
        Directive is sandboxed and won't reach anything outside
245
 
        directory with setup.py.
246
 
 
247
 
        Examples:
248
 
            include: LICENSE
249
 
            include: src/file.txt
250
 
 
251
 
        :param str value:
252
 
        :rtype: str
253
 
        """
254
 
        if not isinstance(value, string_types):
255
 
            return value
256
 
 
257
 
        include_directive = 'file:'
258
 
        if not value.startswith(include_directive):
259
 
            return value
260
 
 
261
 
        current_directory = os.getcwd()
262
 
 
263
 
        filepath = value.replace(include_directive, '').strip()
264
 
        filepath = os.path.abspath(filepath)
265
 
 
266
 
        if not filepath.startswith(current_directory):
267
 
            raise DistutilsOptionError(
268
 
                '`file:` directive can not access %s' % filepath)
269
 
 
270
 
        if os.path.isfile(filepath):
271
 
            with io.open(filepath, encoding='utf-8') as f:
272
 
                value = f.read()
273
 
 
274
 
        return value
275
 
 
276
 
    @classmethod
277
 
    def _parse_attr(cls, value):
278
 
        """Represents value as a module attribute.
279
 
 
280
 
        Examples:
281
 
            attr: package.attr
282
 
            attr: package.module.attr
283
 
 
284
 
        :param str value:
285
 
        :rtype: str
286
 
        """
287
 
        attr_directive = 'attr:'
288
 
        if not value.startswith(attr_directive):
289
 
            return value
290
 
 
291
 
        attrs_path = value.replace(attr_directive, '').strip().split('.')
292
 
        attr_name = attrs_path.pop()
293
 
 
294
 
        module_name = '.'.join(attrs_path)
295
 
        module_name = module_name or '__init__'
296
 
 
297
 
        sys.path.insert(0, os.getcwd())
298
 
        try:
299
 
            module = import_module(module_name)
300
 
            value = getattr(module, attr_name)
301
 
 
302
 
        finally:
303
 
            sys.path = sys.path[1:]
304
 
 
305
 
        return value
306
 
 
307
 
    @classmethod
308
 
    def _get_parser_compound(cls, *parse_methods):
309
 
        """Returns parser function to represents value as a list.
310
 
 
311
 
        Parses a value applying given methods one after another.
312
 
 
313
 
        :param parse_methods:
314
 
        :rtype: callable
315
 
        """
316
 
        def parse(value):
317
 
            parsed = value
318
 
 
319
 
            for method in parse_methods:
320
 
                parsed = method(parsed)
321
 
 
322
 
            return parsed
323
 
 
324
 
        return parse
325
 
 
326
 
    @classmethod
327
 
    def _parse_section_to_dict(cls, section_options, values_parser=None):
328
 
        """Parses section options into a dictionary.
329
 
 
330
 
        Optionally applies a given parser to values.
331
 
 
332
 
        :param dict section_options:
333
 
        :param callable values_parser:
334
 
        :rtype: dict
335
 
        """
336
 
        value = {}
337
 
        values_parser = values_parser or (lambda val: val)
338
 
        for key, (_, val) in section_options.items():
339
 
            value[key] = values_parser(val)
340
 
        return value
341
 
 
342
 
    def parse_section(self, section_options):
343
 
        """Parses configuration file section.
344
 
 
345
 
        :param dict section_options:
346
 
        """
347
 
        for (name, (_, value)) in section_options.items():
348
 
            try:
349
 
                self[name] = value
350
 
 
351
 
            except KeyError:
352
 
                pass  # Keep silent for a new option may appear anytime.
353
 
 
354
 
    def parse(self):
355
 
        """Parses configuration file items from one
356
 
        or more related sections.
357
 
 
358
 
        """
359
 
        for section_name, section_options in self.sections.items():
360
 
 
361
 
            method_postfix = ''
362
 
            if section_name:  # [section.option] variant
363
 
                method_postfix = '_%s' % section_name
364
 
 
365
 
            section_parser_method = getattr(
366
 
                self,
367
 
                # Dots in section names are tranlsated into dunderscores.
368
 
                ('parse_section%s' % method_postfix).replace('.', '__'),
369
 
                None)
370
 
 
371
 
            if section_parser_method is None:
372
 
                raise DistutilsOptionError(
373
 
                    'Unsupported distribution option section: [%s.%s]' % (
374
 
                        self.section_prefix, section_name))
375
 
 
376
 
            section_parser_method(section_options)
377
 
 
378
 
 
379
 
class ConfigMetadataHandler(ConfigHandler):
380
 
 
381
 
    section_prefix = 'metadata'
382
 
 
383
 
    aliases = {
384
 
        'home_page': 'url',
385
 
        'summary': 'description',
386
 
        'classifier': 'classifiers',
387
 
        'platform': 'platforms',
388
 
    }
389
 
 
390
 
    strict_mode = False
391
 
    """We need to keep it loose, to be partially compatible with
392
 
    `pbr` and `d2to1` packages which also uses `metadata` section.
393
 
 
394
 
    """
395
 
 
396
 
    @property
397
 
    def parsers(self):
398
 
        """Metadata item name to parser function mapping."""
399
 
        parse_list = self._parse_list
400
 
        parse_file = self._parse_file
401
 
 
402
 
        return {
403
 
            'platforms': parse_list,
404
 
            'keywords': parse_list,
405
 
            'provides': parse_list,
406
 
            'requires': parse_list,
407
 
            'obsoletes': parse_list,
408
 
            'classifiers': self._get_parser_compound(parse_file, parse_list),
409
 
            'license': parse_file,
410
 
            'description': parse_file,
411
 
            'long_description': parse_file,
412
 
            'version': self._parse_version,
413
 
        }
414
 
 
415
 
    def parse_section_classifiers(self, section_options):
416
 
        """Parses configuration file section.
417
 
 
418
 
        :param dict section_options:
419
 
        """
420
 
        classifiers = []
421
 
        for begin, (_, rest) in section_options.items():
422
 
            classifiers.append('%s :%s' % (begin.title(), rest))
423
 
 
424
 
        self['classifiers'] = classifiers
425
 
 
426
 
    def _parse_version(self, value):
427
 
        """Parses `version` option value.
428
 
 
429
 
        :param value:
430
 
        :rtype: str
431
 
 
432
 
        """
433
 
        version = self._parse_attr(value)
434
 
 
435
 
        if callable(version):
436
 
            version = version()
437
 
 
438
 
        if not isinstance(version, string_types):
439
 
            if hasattr(version, '__iter__'):
440
 
                version = '.'.join(map(str, version))
441
 
            else:
442
 
                version = '%s' % version
443
 
 
444
 
        return version
445
 
 
446
 
 
447
 
class ConfigOptionsHandler(ConfigHandler):
448
 
 
449
 
    section_prefix = 'options'
450
 
 
451
 
    @property
452
 
    def parsers(self):
453
 
        """Metadata item name to parser function mapping."""
454
 
        parse_list = self._parse_list
455
 
        parse_list_semicolon = partial(self._parse_list, separator=';')
456
 
        parse_bool = self._parse_bool
457
 
        parse_dict = self._parse_dict
458
 
 
459
 
        return {
460
 
            'zip_safe': parse_bool,
461
 
            'use_2to3': parse_bool,
462
 
            'include_package_data': parse_bool,
463
 
            'package_dir': parse_dict,
464
 
            'use_2to3_fixers': parse_list,
465
 
            'use_2to3_exclude_fixers': parse_list,
466
 
            'convert_2to3_doctests': parse_list,
467
 
            'scripts': parse_list,
468
 
            'eager_resources': parse_list,
469
 
            'dependency_links': parse_list,
470
 
            'namespace_packages': parse_list,
471
 
            'install_requires': parse_list_semicolon,
472
 
            'setup_requires': parse_list_semicolon,
473
 
            'tests_require': parse_list_semicolon,
474
 
            'packages': self._parse_packages,
475
 
            'entry_points': self._parse_file,
476
 
        }
477
 
 
478
 
    def _parse_packages(self, value):
479
 
        """Parses `packages` option value.
480
 
 
481
 
        :param value:
482
 
        :rtype: list
483
 
        """
484
 
        find_directive = 'find:'
485
 
 
486
 
        if not value.startswith(find_directive):
487
 
            return self._parse_list(value)
488
 
 
489
 
        # Read function arguments from a dedicated section.
490
 
        find_kwargs = self.parse_section_packages__find(
491
 
            self.sections.get('packages.find', {}))
492
 
 
493
 
        from setuptools import find_packages
494
 
 
495
 
        return find_packages(**find_kwargs)
496
 
 
497
 
    def parse_section_packages__find(self, section_options):
498
 
        """Parses `packages.find` configuration file section.
499
 
 
500
 
        To be used in conjunction with _parse_packages().
501
 
 
502
 
        :param dict section_options:
503
 
        """
504
 
        section_data = self._parse_section_to_dict(
505
 
            section_options, self._parse_list)
506
 
 
507
 
        valid_keys = ['where', 'include', 'exclude']
508
 
 
509
 
        find_kwargs = dict(
510
 
            [(k, v) for k, v in section_data.items() if k in valid_keys and v])
511
 
 
512
 
        where = find_kwargs.get('where')
513
 
        if where is not None:
514
 
            find_kwargs['where'] = where[0]  # cast list to single val
515
 
 
516
 
        return find_kwargs
517
 
 
518
 
    def parse_section_entry_points(self, section_options):
519
 
        """Parses `entry_points` configuration file section.
520
 
 
521
 
        :param dict section_options:
522
 
        """
523
 
        parsed = self._parse_section_to_dict(section_options, self._parse_list)
524
 
        self['entry_points'] = parsed
525
 
 
526
 
    def _parse_package_data(self, section_options):
527
 
        parsed = self._parse_section_to_dict(section_options, self._parse_list)
528
 
 
529
 
        root = parsed.get('*')
530
 
        if root:
531
 
            parsed[''] = root
532
 
            del parsed['*']
533
 
 
534
 
        return parsed
535
 
 
536
 
    def parse_section_package_data(self, section_options):
537
 
        """Parses `package_data` configuration file section.
538
 
 
539
 
        :param dict section_options:
540
 
        """
541
 
        self['package_data'] = self._parse_package_data(section_options)
542
 
 
543
 
    def parse_section_exclude_package_data(self, section_options):
544
 
        """Parses `exclude_package_data` configuration file section.
545
 
 
546
 
        :param dict section_options:
547
 
        """
548
 
        self['exclude_package_data'] = self._parse_package_data(
549
 
            section_options)
550
 
 
551
 
    def parse_section_extras_require(self, section_options):
552
 
        """Parses `extras_require` configuration file section.
553
 
 
554
 
        :param dict section_options:
555
 
        """
556
 
        parse_list = partial(self._parse_list, separator=';')
557
 
        self['extras_require'] = self._parse_section_to_dict(
558
 
            section_options, parse_list)