~ubuntu-branches/ubuntu/hardy/python-docutils/hardy

« back to all changes in this revision

Viewing changes to docutils/frontend.py

  • Committer: Bazaar Package Importer
  • Author(s): martin f. krafft
  • Date: 2006-07-10 11:45:05 UTC
  • mfrom: (2.1.4 edgy)
  • Revision ID: james.westby@ubuntu.com-20060710114505-otkhqcslevewxmz5
Tags: 0.4-3
Added build dependency on python-central (closes: #377580).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Author: David Goodger
2
2
# Contact: goodger@users.sourceforge.net
3
 
# Revision: $Revision: 1.55 $
4
 
# Date: $Date: 2004/04/02 02:29:26 $
 
3
# Revision: $Revision: 4183 $
 
4
# Date: $Date: 2005-12-12 05:12:02 +0100 (Mon, 12 Dec 2005) $
5
5
# Copyright: This module has been placed in the public domain.
6
6
 
7
7
"""
18
18
Also exports the following functions:
19
19
 
20
20
* Option callbacks: `store_multiple`, `read_config_file`.
21
 
* Setting validators (see `OptionParser.validators`: `validate_encoding`,
22
 
  `validate_encoding_error_handler`, `validate_encoding_and_error_handler`,
23
 
  `validate_boolean`, `validate_threshold`,
24
 
  `validate_colon_separated_string_list`.
 
21
* Setting validators: `validate_encoding`,
 
22
  `validate_encoding_error_handler`,
 
23
  `validate_encoding_and_error_handler`, `validate_boolean`,
 
24
  `validate_threshold`, `validate_colon_separated_string_list`,
 
25
  `validate_dependency_file`.
25
26
* `make_paths_absolute`.
26
27
"""
27
28
 
31
32
import os.path
32
33
import sys
33
34
import types
34
 
import copy
35
35
import warnings
36
36
import ConfigParser as CP
37
37
import codecs
38
38
import docutils
39
 
 
40
39
try:
41
40
    import optparse
42
 
    from optparse import Values, SUPPRESS_HELP
 
41
    from optparse import SUPPRESS_HELP
43
42
except ImportError:
44
43
    import optik as optparse
45
 
    from optik import Values, SUPPRESS_HELP
 
44
    from optik import SUPPRESS_HELP
 
45
 
46
46
 
47
47
def store_multiple(option, opt, value, parser, *args, **kwargs):
48
48
    """
49
49
    Store multiple values in `parser.values`.  (Option callback.)
50
 
    
 
50
 
51
51
    Store `None` for each attribute named in `args`, and store the value for
52
52
    each key (attribute name) in `kwargs`.
53
53
    """
81
81
    try:
82
82
        codecs.lookup_error(value)
83
83
    except AttributeError:              # prior to Python 2.3
84
 
        if value not in ('strict', 'ignore', 'replace'):
 
84
        if value not in ('strict', 'ignore', 'replace', 'xmlcharrefreplace'):
85
85
            raise (LookupError(
86
86
                'unknown encoding error handler: "%s" (choices: '
87
 
                '"strict", "ignore", or "replace")' % value),
 
87
                '"strict", "ignore", "replace", or "xmlcharrefreplace")' % value),
88
88
                   None, sys.exc_info()[2])
89
89
    except LookupError:
90
90
        raise (LookupError(
127
127
                   None, sys.exc_info()[2])
128
128
    return value
129
129
 
 
130
def validate_nonnegative_int(setting, value, option_parser,
 
131
                             config_parser=None, config_section=None):
 
132
    value = int(value)
 
133
    if value < 0:
 
134
        raise ValueError('negative value; must be positive or zero')
 
135
    return value
 
136
 
130
137
def validate_threshold(setting, value, option_parser,
131
138
                       config_parser=None, config_section=None):
132
139
    try:
147
154
        value.extend(last.split(':'))
148
155
    return value
149
156
 
 
157
def validate_url_trailing_slash(
 
158
    setting, value, option_parser, config_parser=None, config_section=None):
 
159
    if not value:
 
160
        return './'
 
161
    elif value.endswith('/'):
 
162
        return value
 
163
    else:
 
164
        return value + '/'
 
165
 
 
166
def validate_dependency_file(
 
167
    setting, value, option_parser, config_parser=None, config_section=None):
 
168
    try:
 
169
        return docutils.utils.DependencyList(value)
 
170
    except IOError:
 
171
        return docutils.utils.DependencyList(None)
 
172
 
150
173
def make_paths_absolute(pathdict, keys, base_path=None):
151
174
    """
152
175
    Interpret filesystem path settings relative to the `base_path` given.
177
200
    Works in conjunction with the `OptionParser.lists` instance attribute.
178
201
    """
179
202
 
 
203
    def __init__(self, *args, **kwargs):
 
204
        optparse.Values.__init__(self, *args, **kwargs)
 
205
        if (not hasattr(self, 'record_dependencies')
 
206
            or self.record_dependencies is None):
 
207
            # Set up dependency list, in case it is needed.
 
208
            self.record_dependencies = docutils.utils.DependencyList()
 
209
 
180
210
    def update(self, other_dict, option_parser):
181
211
        if isinstance(other_dict, Values):
182
212
            other_dict = other_dict.__dict__
189
219
                    del other_dict[setting]
190
220
        self._update_loose(other_dict)
191
221
 
 
222
    def copy(self):
 
223
        """Return a shallow copy of `self`."""
 
224
        return self.__class__(defaults=self.__dict__)
 
225
 
192
226
 
193
227
class Option(optparse.Option):
194
228
 
 
229
    ATTRS = optparse.Option.ATTRS + ['validator', 'overrides']
 
230
 
195
231
    def process(self, opt, value, values, parser):
196
232
        """
197
 
        Call the validator function on applicable settings.
 
233
        Call the validator function on applicable settings and
 
234
        evaluate the 'overrides' option.
198
235
        Extends `optparse.Option.process`.
199
236
        """
200
237
        result = optparse.Option.process(self, opt, value, values, parser)
201
238
        setting = self.dest
202
239
        if setting:
203
 
            value = getattr(values, setting)
204
 
            validator = parser.validators.get(setting)
205
 
            if validator:
 
240
            if self.validator:
 
241
                value = getattr(values, setting)
206
242
                try:
207
 
                    new_value = validator(setting, value, parser)
 
243
                    new_value = self.validator(setting, value, parser)
208
244
                except Exception, error:
209
245
                    raise (optparse.OptionValueError(
210
246
                        'Error in option "%s":\n    %s: %s'
211
247
                        % (opt, error.__class__.__name__, error)),
212
248
                           None, sys.exc_info()[2])
213
249
                setattr(values, setting, new_value)
 
250
            if self.overrides:
 
251
                setattr(values, self.overrides, None)
214
252
        return result
215
253
 
216
254
 
251
289
    settings_spec = (
252
290
        'General Docutils Options',
253
291
        None,
254
 
        (('Include a "Generated by Docutils" credit and link at the end '
 
292
        (('Specify the document title as metadata (not part of the document '
 
293
          'body).  Overrides a document-provided title.  There is no default.',
 
294
          ['--title'], {}),
 
295
         ('Include a "Generated by Docutils" credit and link at the end '
255
296
          'of the document.',
256
297
          ['--generator', '-g'], {'action': 'store_true',
257
298
                                  'validator': validate_boolean}),
297
338
         ('Disable backlinks from footnotes and citations.',
298
339
          ['--no-footnote-backlinks'],
299
340
          {'dest': 'footnote_backlinks', 'action': 'store_false'}),
300
 
         ('Disable Docutils section numbering',
 
341
         ('Enable Docutils section numbering (default: enabled).',
 
342
          ['--section-numbering'],
 
343
          {'action': 'store_true', 'dest': 'sectnum_xform',
 
344
           'default': 1, 'validator': validate_boolean}),
 
345
         ('Disable Docutils section numbering (default: enabled).',
301
346
          ['--no-section-numbering'],
302
347
          {'action': 'store_false', 'dest': 'sectnum_xform',
303
 
           'default': 1, 'validator': validate_boolean}),
 
348
           'validator': validate_boolean}),
 
349
         ('Remove comment elements from the document tree '
 
350
          '(default: leave them).',
 
351
          ['--strip-comments'],
 
352
          {'action': 'store_true', 'validator': validate_boolean}),
 
353
         ('Leave comment elements in the document tree '
 
354
          '(this is the default).',
 
355
          ['--leave-comments'],
 
356
          {'action': 'store_false', 'dest': 'strip_comments',
 
357
           'validator': validate_boolean}),
304
358
         ('Set verbosity threshold; report system messages at or higher than '
305
359
          '<level> (by name or number: "info" or "1", warning/2, error/3, '
306
360
          'severe/4; also, "none" or "5").  Default is 2 (warning).',
309
363
                               'validator': validate_threshold}),
310
364
         ('Report all system messages, info-level and higher.  (Same as '
311
365
          '"--report=info".)',
312
 
          ['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
 
366
          ['--verbose', '-v'], {'action': 'store_const', 'const': 1,
313
367
                                'dest': 'report_level'}),
314
368
         ('Do not report any system messages.  (Same as "--report=none".)',
315
 
          ['--quiet', '-q'], {'action': 'store_const', 'const': 'none',
 
369
          ['--quiet', '-q'], {'action': 'store_const', 'const': 5,
316
370
                              'dest': 'report_level'}),
317
371
         ('Set the threshold (<level>) at or above which system messages are '
318
 
          'converted to exceptions, halting execution immediately.  Levels '
319
 
          'as in --report.  Default is 4 (severe).',
 
372
          'converted to exceptions, halting execution immediately by '
 
373
          'exiting (or propagating the exception if --traceback set).  '
 
374
          'Levels as in --report.  Default is 4 (severe).',
320
375
          ['--halt'], {'choices': threshold_choices, 'dest': 'halt_level',
321
376
                       'default': 4, 'metavar': '<level>',
322
377
                       'validator': validate_threshold}),
327
382
          'system messages (at or above <level>) were generated.  Levels as '
328
383
          'in --report.  Default is 5 (disabled).  Exit status is the maximum '
329
384
          'system message level plus 10 (11 for INFO, etc.).',
330
 
          ['--exit'], {'choices': threshold_choices, 'dest': 'exit_level',
331
 
                       'default': 5, 'metavar': '<level>',
332
 
                       'validator': validate_threshold}),
 
385
          ['--exit-status'], {'choices': threshold_choices,
 
386
                              'dest': 'exit_status_level',
 
387
                              'default': 5, 'metavar': '<level>',
 
388
                              'validator': validate_threshold}),
333
389
         ('Report debug-level system messages and generate diagnostic output.',
334
390
          ['--debug'], {'action': 'store_true', 'validator': validate_boolean}),
335
391
         ('Do not report debug-level system messages or generate diagnostic '
337
393
          ['--no-debug'], {'action': 'store_false', 'dest': 'debug'}),
338
394
         ('Send the output of system messages (warnings) to <file>.',
339
395
          ['--warnings'], {'dest': 'warning_stream', 'metavar': '<file>'}),
340
 
         ('Enable Python tracebacks when an error occurs.',
 
396
         ('Enable Python tracebacks when halt-level system messages and '
 
397
          'other exceptions occur.  Useful for debugging, and essential for '
 
398
          'issue reports.',
341
399
          ['--traceback'], {'action': 'store_true', 'default': None,
342
400
                            'validator': validate_boolean}),
343
401
         ('Disable Python tracebacks when errors occur; report just the error '
344
402
          'instead.  This is the default.',
345
403
          ['--no-traceback'], {'dest': 'traceback', 'action': 'store_false'}),
346
 
         ('Specify the encoding of input text.  Default is locale-dependent.',
 
404
         ('Specify the encoding of input text.  Default is locale-dependent.  '
 
405
          'Optionally also specify the error handler for undecodable '
 
406
          'characters, after a colon (":"); default is "strict".  (See '
 
407
          '"--intput-encoding-error-handler".)',
347
408
          ['--input-encoding', '-i'],
348
 
          {'metavar': '<name>', 'validator': validate_encoding}),
 
409
          {'metavar': '<name[:handler]>',
 
410
           'validator': validate_encoding_and_error_handler}),
 
411
         ('Specify the error handler for undecodable characters in '
 
412
          'the input.  Acceptable values include "strict", "ignore", and '
 
413
          '"replace".  Default is "strict".  '
 
414
          'Usually specified as part of --input-encoding.',
 
415
          ['--input-encoding-error-handler'],
 
416
          {'default': 'strict', 'validator': validate_encoding_error_handler}),
349
417
         ('Specify the text encoding for output.  Default is UTF-8.  '
350
 
          'Optionally also specify the encoding error handler for unencodable '
351
 
          'characters (see "--error-encoding"); default is "strict".',
 
418
          'Optionally also specify the error handler for unencodable '
 
419
          'characters, after a colon (":"); default is "strict".  (See '
 
420
          '"--output-encoding-error-handler".)',
352
421
          ['--output-encoding', '-o'],
353
422
          {'metavar': '<name[:handler]>', 'default': 'utf-8',
354
423
           'validator': validate_encoding_and_error_handler}),
355
 
         (SUPPRESS_HELP,                # usually handled by --output-encoding
 
424
         ('Specify the error handler for unencodable characters in '
 
425
          'the output.  Acceptable values include "strict", "ignore", '
 
426
          '"replace", "xmlcharrefreplace", and '
 
427
          '"backslashreplace" (in Python 2.3+).  Default is "strict".  '
 
428
          'Usually specified as part of --output-encoding.',
356
429
          ['--output-encoding-error-handler'],
357
430
          {'default': 'strict', 'validator': validate_encoding_error_handler}),
358
431
         ('Specify the text encoding for error output.  Default is ASCII.  '
359
 
          'Optionally also specify the encoding error handler for unencodable '
360
 
          'characters, after a colon (":").  Acceptable values are the same '
361
 
          'as for the "error" parameter of Python\'s ``encode`` string '
362
 
          'method.  Default is "%s".' % default_error_encoding_error_handler,
 
432
          'Optionally also specify the error handler for unencodable '
 
433
          'characters, after a colon (":"); default is "%s".  (See '
 
434
          '"--output-encoding-error-handler".)'
 
435
          % default_error_encoding_error_handler,
363
436
          ['--error-encoding', '-e'],
364
437
          {'metavar': '<name[:handler]>', 'default': 'ascii',
365
438
           'validator': validate_encoding_and_error_handler}),
366
 
         (SUPPRESS_HELP,                # usually handled by --error-encoding
 
439
         ('Specify the error handler for unencodable characters in '
 
440
          'error output.  See --output-encoding-error-handler for acceptable '
 
441
          'values.  Default is "%s".  Usually specified as part of '
 
442
          '--error-encoding.' % default_error_encoding_error_handler,
367
443
          ['--error-encoding-error-handler'],
368
444
          {'default': default_error_encoding_error_handler,
369
445
           'validator': validate_encoding_error_handler}),
371
447
          '  Default is "en" (English).',
372
448
          ['--language', '-l'], {'dest': 'language_code', 'default': 'en',
373
449
                                 'metavar': '<name>'}),
 
450
         ('Write dependencies (caused e.g. by file inclusions) to '
 
451
          '<file>.  Useful in conjunction with programs like "make".',
 
452
          ['--record-dependencies'],
 
453
          {'metavar': '<file>', 'validator': validate_dependency_file,
 
454
           'default': None}),           # default set in Values class
374
455
         ('Read configuration settings from <file>, if it exists.',
375
456
          ['--config'], {'metavar': '<file>', 'type': 'string',
376
457
                         'action': 'callback', 'callback': read_config_file}),
378
459
          ['--version', '-V'], {'action': 'version'}),
379
460
         ('Show this help message and exit.',
380
461
          ['--help', '-h'], {'action': 'help'}),
 
462
         # Typically not useful for non-programmatical use.
 
463
         (SUPPRESS_HELP, ['--id-prefix'], {'default': ''}),
 
464
         (SUPPRESS_HELP, ['--auto-id-prefix'], {'default': 'id'}),
381
465
         # Hidden options, for development use only:
382
466
         (SUPPRESS_HELP, ['--dump-settings'], {'action': 'store_true'}),
383
467
         (SUPPRESS_HELP, ['--dump-internals'], {'action': 'store_true'}),
385
469
         (SUPPRESS_HELP, ['--dump-pseudo-xml'], {'action': 'store_true'}),
386
470
         (SUPPRESS_HELP, ['--expose-internal-attribute'],
387
471
          {'action': 'append', 'dest': 'expose_internals',
388
 
           'validator': validate_colon_separated_string_list}),))
 
472
           'validator': validate_colon_separated_string_list}),
 
473
         (SUPPRESS_HELP, ['--strict-visitor'], {'action': 'store_true'}),
 
474
         ))
389
475
    """Runtime settings and command-line options common to all Docutils front
390
476
    ends.  Setting specs specific to individual Docutils components are also
391
477
    used (see `populate_from_components()`)."""
392
478
 
393
 
    settings_defaults = {'_disable_config': None}
 
479
    settings_defaults = {'_disable_config': None,
 
480
                         '_source': None,
 
481
                         '_destination': None,}
394
482
    """Defaults for settings that don't have command-line option equivalents."""
395
483
 
396
484
    relative_path_settings = ('warning_stream',)
397
485
 
398
486
    config_section = 'general'
399
487
 
400
 
    version_template = '%%prog (Docutils %s)' % docutils.__version__
 
488
    version_template = ('%%prog (Docutils %s [%s])'
 
489
                        % (docutils.__version__, docutils.__version_details__))
401
490
    """Default version message."""
402
491
 
403
492
    def __init__(self, components=(), defaults=None, read_config_files=None,
407
496
        ``.settings_spec`` attribute.  `defaults` is a mapping of setting
408
497
        default overrides.
409
498
        """
410
 
        self.validators = {}
411
 
        """{setting: validation function} mapping, used by `validate_options`.
412
 
        Validation functions take three or five parameters: setting name,
413
 
        value, an `OptionParser` (``self``), and a `ConfigParser` and config
414
 
        file section if activated from a config file.  They return a (possibly
415
 
        modified) value, or raise an exception.  Populated from the "validator"
416
 
        keyword argument dictionary entries of components' ``settings_spec``
417
 
        attribute."""
418
499
 
419
500
        self.lists = {}
420
501
        """Set of list-type settings."""
429
510
        self.relative_path_settings = list(self.relative_path_settings)
430
511
        self.components = (self,) + tuple(components)
431
512
        self.populate_from_components(self.components)
432
 
        defaults = defaults or {}
 
513
        self.set_defaults(**(defaults or {}))
433
514
        if read_config_files and not self.defaults['_disable_config']:
434
515
            try:
435
516
                config_settings = self.get_standard_config_settings()
436
517
            except ValueError, error:
437
518
                self.error(error)
438
 
            defaults.update(config_settings.__dict__)
439
 
        # Internal settings with no defaults from settings specifications;
440
 
        # initialize manually:
441
 
        self.set_defaults(_source=None, _destination=None, **defaults)
 
519
            self.set_defaults(**config_settings.__dict__)
442
520
 
443
521
    def populate_from_components(self, components):
444
522
        """
450
528
        for component in components:
451
529
            if component is None:
452
530
                continue
453
 
            i = 0
454
531
            settings_spec = component.settings_spec
455
532
            self.relative_path_settings.extend(
456
533
                component.relative_path_settings)
457
 
            while i < len(settings_spec):
 
534
            for i in range(0, len(settings_spec), 3):
458
535
                title, description, option_spec = settings_spec[i:i+3]
459
536
                if title:
460
537
                    group = optparse.OptionGroup(self, title, description)
462
539
                else:
463
540
                    group = self        # single options
464
541
                for (help_text, option_strings, kwargs) in option_spec:
465
 
                    kwargs = kwargs.copy() # to be modified, locally only
466
 
                    if kwargs.has_key('validator'):
467
 
                        validator = kwargs['validator']
468
 
                        del kwargs['validator']
469
 
                    else:
470
 
                        validator = None
471
542
                    option = group.add_option(help=help_text, *option_strings,
472
543
                                              **kwargs)
473
 
                    if validator:
474
 
                        self.validators[option.dest] = validator
475
544
                    if kwargs.get('action') == 'append':
476
545
                        self.lists[option.dest] = 1
477
546
                if component.settings_defaults:
478
547
                    self.defaults.update(component.settings_defaults)
479
 
                i += 3
480
548
        for component in components:
481
549
            if component and component.settings_default_overrides:
482
550
                self.defaults.update(component.settings_default_overrides)
543
611
        """Needed to get custom `Values` instances."""
544
612
        return Values(self.defaults)
545
613
 
 
614
    def get_option_by_dest(self, dest):
 
615
        """
 
616
        Get an option by its dest.
 
617
 
 
618
        If you're supplying a dest which is shared by several options,
 
619
        it is undefined which option of those is returned.
 
620
 
 
621
        A KeyError is raised if there is no option with the supplied
 
622
        dest.
 
623
        """
 
624
        for group in self.option_groups + [self]:
 
625
            for option in group.option_list:
 
626
                if option.dest == dest:
 
627
                    return option
 
628
        raise KeyError('No option with dest == %r.' % dest)
 
629
 
546
630
 
547
631
class ConfigParser(CP.ConfigParser):
548
632
 
556
640
    old_warning = """
557
641
The "[option]" section is deprecated.  Support for old-format configuration
558
642
files may be removed in a future Docutils release.  Please revise your
559
 
configuration files.  See <http://docutils.sf.net/docs/config.html>, section
560
 
"Old-Format Configuration Files".
 
643
configuration files.  See <http://docutils.sf.net/docs/user/config.html>,
 
644
section "Old-Format Configuration Files".
561
645
"""
562
646
 
563
647
    def read(self, filenames, option_parser):
588
672
        self.remove_section('options')
589
673
 
590
674
    def validate_settings(self, filename, option_parser):
591
 
        """Call the validator function on all applicable settings."""
 
675
        """
 
676
        Call the validator function and implement overrides on all applicable
 
677
        settings.
 
678
        """
592
679
        for section in self.sections():
593
680
            for setting in self.options(section):
594
 
                validator = option_parser.validators.get(setting)
595
 
                if validator:
 
681
                try:
 
682
                    option = option_parser.get_option_by_dest(setting)
 
683
                except KeyError:
 
684
                    continue
 
685
                if option.validator:
596
686
                    value = self.get(section, setting, raw=1)
597
687
                    try:
598
 
                        new_value = validator(
 
688
                        new_value = option.validator(
599
689
                            setting, value, option_parser,
600
690
                            config_parser=self, config_section=section)
601
691
                    except Exception, error:
605
695
                            % (filename, section, error.__class__.__name__,
606
696
                               error, setting, value)), None, sys.exc_info()[2])
607
697
                    self.set(section, setting, new_value)
 
698
                if option.overrides:
 
699
                    self.set(section, option.overrides, None)
608
700
 
609
701
    def optionxform(self, optionstr):
610
702
        """