Documentation for stylesheet usage.
[docutils.git] / docutils / frontend.py
blob029f2763a92d7e60d045ce5d6aa0c04f8fe39366
1 # Author: David Goodger
2 # Contact: goodger@users.sourceforge.net
3 # Revision: $Revision$
4 # Date: $Date$
5 # Copyright: This module has been placed in the public domain.
7 """
8 Command-line and common processing for Docutils front-end tools.
10 Exports the following classes:
12 - `OptionParser`: Standard Docutils command-line processing.
13 - `Values`: Runtime settings; objects are simple structs
14 (``object.attribute``).
15 - `ConfigParser`: Standard Docutils config file processing.
16 """
18 __docformat__ = 'reStructuredText'
20 import os
21 import os.path
22 import ConfigParser as CP
23 import docutils
24 from docutils import optik
25 from docutils.optik import Values
28 def store_multiple(option, opt, value, parser, *args, **kwargs):
29 """
30 Store multiple values in `parser.values`. (Option callback.)
32 Store `None` for each attribute named in `args`, and store the value for
33 each key (attribute name) in `kwargs`.
34 """
35 for attribute in args:
36 setattr(parser.values, attribute, None)
37 for key, value in kwargs.items():
38 setattr(parser.values, key, value)
40 def read_config_file(option, opt, value, parser):
41 """
42 Read a configuration file during option processing. (Option callback.)
43 """
44 config_parser = ConfigParser()
45 config_parser.read(value)
46 settings = config_parser.get_section('options')
47 make_paths_absolute(settings, parser.relative_path_settings,
48 os.path.dirname(value))
49 parser.values.__dict__.update(settings)
51 def make_paths_absolute(pathdict, keys, base_path=None):
52 """
53 Interpret filesystem path settings relative to the `base_path` given.
55 Paths are values in `pathdict` whose keys are in `keys`. Get `keys` from
56 `OptionParser.relative_path_settings`.
57 """
58 if base_path is None:
59 base_path = os.getcwd()
60 for key in keys:
61 if pathdict.has_key(key) and pathdict[key]:
62 pathdict[key] = os.path.normpath(
63 os.path.abspath(os.path.join(base_path, pathdict[key])))
66 class OptionParser(optik.OptionParser, docutils.SettingsSpec):
68 """
69 Parser for command-line and library use. The `settings_spec`
70 specification here and in other Docutils components are merged to build
71 the set of command-line options and runtime settings for this process.
73 Common settings (defined below) and component-specific settings must not
74 conflict. Short options are reserved for common settings, and components
75 are restrict to using long options.
76 """
78 threshold_choices = 'info 1 warning 2 error 3 severe 4 none 5'.split()
79 """Possible inputs for for --report and --halt threshold values."""
81 thresholds = {'info': 1, 'warning': 2, 'error': 3, 'severe': 4, 'none': 5}
82 """Lookup table for --report and --halt threshold values."""
84 settings_spec = (
85 'General Docutils Options',
86 None,
87 (('Include a "Generated by Docutils" credit and link at the end '
88 'of the document.',
89 ['--generator', '-g'], {'action': 'store_true'}),
90 ('Do not include a generator credit.',
91 ['--no-generator'], {'action': 'store_false', 'dest': 'generator'}),
92 ('Include the date at the end of the document (UTC).',
93 ['--date', '-d'], {'action': 'store_const', 'const': '%Y-%m-%d',
94 'dest': 'datestamp'}),
95 ('Include the time & date at the end of the document (UTC).',
96 ['--time', '-t'], {'action': 'store_const',
97 'const': '%Y-%m-%d %H:%M UTC',
98 'dest': 'datestamp'}),
99 ('Do not include a datestamp of any kind.',
100 ['--no-datestamp'], {'action': 'store_const', 'const': None,
101 'dest': 'datestamp'}),
102 ('Include a "View document source" link (relative to destination).',
103 ['--source-link', '-s'], {'action': 'store_true'}),
104 ('Use the supplied <URL> verbatim for a "View document source" '
105 'link; implies --source-link.',
106 ['--source-url'], {'metavar': '<URL>'}),
107 ('Do not include a "View document source" link.',
108 ['--no-source-link'],
109 {'action': 'callback', 'callback': store_multiple,
110 'callback_args': ('source_link', 'source_url')}),
111 ('Enable backlinks from section headers to table of contents '
112 'entries. This is the default.',
113 ['--toc-entry-backlinks'],
114 {'dest': 'toc_backlinks', 'action': 'store_const', 'const': 'entry',
115 'default': 'entry'}),
116 ('Enable backlinks from section headers to the top of the table of '
117 'contents.',
118 ['--toc-top-backlinks'],
119 {'dest': 'toc_backlinks', 'action': 'store_const', 'const': 'top'}),
120 ('Disable backlinks to the table of contents.',
121 ['--no-toc-backlinks'],
122 {'dest': 'toc_backlinks', 'action': 'store_false'}),
123 ('Enable backlinks from footnotes and citations to their '
124 'references. This is the default.',
125 ['--footnote-backlinks'],
126 {'action': 'store_true', 'default': 1}),
127 ('Disable backlinks from footnotes and citations.',
128 ['--no-footnote-backlinks'],
129 {'dest': 'footnote_backlinks', 'action': 'store_false'}),
130 ('Set verbosity threshold; report system messages at or higher than '
131 '<level> (by name or number: "info" or "1", warning/2, error/3, '
132 'severe/4; also, "none" or "5"). Default is 2 (warning).',
133 ['--report', '-r'], {'choices': threshold_choices, 'default': 2,
134 'dest': 'report_level', 'metavar': '<level>'}),
135 ('Report all system messages, info-level and higher. (Same as '
136 '"--report=info".)',
137 ['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
138 'dest': 'report_level'}),
139 ('Do not report any system messages. (Same as "--report=none".)',
140 ['--quiet', '-q'], {'action': 'store_const', 'const': 'none',
141 'dest': 'report_level'}),
142 ('Set the threshold (<level>) at or above which system messages are '
143 'converted to exceptions, halting execution immediately. Levels '
144 'as in --report. Default is 4 (severe).',
145 ['--halt'], {'choices': threshold_choices, 'dest': 'halt_level',
146 'default': 4, 'metavar': '<level>'}),
147 ('Same as "--halt=info": halt processing at the slightest problem.',
148 ['--strict'], {'action': 'store_const', 'const': 'info',
149 'dest': 'halt_level'}),
150 ('Report debug-level system messages.',
151 ['--debug'], {'action': 'store_true'}),
152 ('Do not report debug-level system messages.',
153 ['--no-debug'], {'action': 'store_false', 'dest': 'debug'}),
154 ('Send the output of system messages (warnings) to <file>.',
155 ['--warnings'], {'dest': 'warning_stream', 'metavar': '<file>'}),
156 ('Specify the encoding of input text. Default is locale-dependent.',
157 ['--input-encoding', '-i'], {'metavar': '<name>'}),
158 ('Specify the encoding for output. Default is UTF-8.',
159 ['--output-encoding', '-o'],
160 {'metavar': '<name>', 'default': 'utf-8'}),
161 ('Specify the language of input text (ISO 639 2-letter identifier).'
162 ' Default is "en" (English).',
163 ['--language', '-l'], {'dest': 'language_code', 'default': 'en',
164 'metavar': '<name>'}),
165 ('Read configuration settings from <file>, if it exists.',
166 ['--config'], {'metavar': '<file>', 'type': 'string',
167 'action': 'callback', 'callback': read_config_file}),
168 ("Show this program's version number and exit.",
169 ['--version', '-V'], {'action': 'version'}),
170 ('Show this help message and exit.',
171 ['--help', '-h'], {'action': 'help'}),
172 # Hidden options, for development use only:
173 (optik.SUPPRESS_HELP,
174 ['--dump-settings'],
175 {'action': 'store_true'}),
176 (optik.SUPPRESS_HELP,
177 ['--dump-internals'],
178 {'action': 'store_true'}),
179 (optik.SUPPRESS_HELP,
180 ['--dump-transforms'],
181 {'action': 'store_true'}),
182 (optik.SUPPRESS_HELP,
183 ['--dump-pseudo-xml'],
184 {'action': 'store_true'}),
185 (optik.SUPPRESS_HELP,
186 ['--expose-internal-attribute'],
187 {'action': 'append', 'dest': 'expose_internals'}),))
188 """Runtime settings and command-line options common to all Docutils front
189 ends. Setting specs specific to individual Docutils components are also
190 used (see `populate_from_components()`)."""
192 relative_path_settings = ('warning_stream',)
194 version_template = '%%prog (Docutils %s)' % docutils.__version__
195 """Default version message."""
197 def __init__(self, components=(), *args, **kwargs):
199 `components` is a list of Docutils components each containing a
200 ``.settings_spec`` attribute. `defaults` is a mapping of setting
201 default overrides.
203 optik.OptionParser.__init__(
204 self, help=None,
205 format=optik.Titled(),
206 # Needed when Optik is updated (replaces above 2 lines):
207 #self, add_help=None,
208 #formatter=optik.TitledHelpFormatter(width=78),
209 *args, **kwargs)
210 if not self.version:
211 self.version = self.version_template
212 # Internal settings with no defaults from settings specifications;
213 # initialize manually:
214 self.set_defaults(_source=None, _destination=None)
215 # Make an instance copy (it will be modified):
216 self.relative_path_settings = list(self.relative_path_settings)
217 self.populate_from_components(tuple(components) + (self,))
219 def populate_from_components(self, components):
220 for component in components:
221 if component is None:
222 continue
223 i = 0
224 settings_spec = component.settings_spec
225 self.relative_path_settings.extend(
226 component.relative_path_settings)
227 while i < len(settings_spec):
228 title, description, option_spec = settings_spec[i:i+3]
229 if title:
230 group = optik.OptionGroup(self, title, description)
231 self.add_option_group(group)
232 else:
233 group = self # single options
234 for (help_text, option_strings, kwargs) in option_spec:
235 group.add_option(help=help_text, *option_strings,
236 **kwargs)
237 i += 3
238 for component in components:
239 if component and component.settings_default_overrides:
240 self.defaults.update(component.settings_default_overrides)
242 def check_values(self, values, args):
243 if hasattr(values, 'report_level'):
244 values.report_level = self.check_threshold(values.report_level)
245 if hasattr(values, 'halt_level'):
246 values.halt_level = self.check_threshold(values.halt_level)
247 values._source, values._destination = self.check_args(args)
248 make_paths_absolute(values.__dict__, self.relative_path_settings,
249 os.getcwd())
250 return values
252 def check_threshold(self, level):
253 try:
254 return int(level)
255 except ValueError:
256 try:
257 return self.thresholds[level.lower()]
258 except (KeyError, AttributeError):
259 self.error('Unknown threshold: %r.' % level)
261 def check_args(self, args):
262 source = destination = None
263 if args:
264 source = args.pop(0)
265 if args:
266 destination = args.pop(0)
267 if args:
268 self.error('Maximum 2 arguments allowed.')
269 if source and source == destination:
270 self.error('Do not specify the same file for both source and '
271 'destination. It will clobber the source file.')
272 return source, destination
275 class ConfigParser(CP.ConfigParser):
277 standard_config_files = (
278 '/etc/docutils.conf', # system-wide
279 './docutils.conf', # project-specific
280 os.path.expanduser('~/.docutils')) # user-specific
281 """Docutils configuration files, using ConfigParser syntax (section
282 'options'). Later files override earlier ones."""
284 def read_standard_files(self):
285 self.read(self.standard_config_files)
287 def optionxform(self, optionstr):
289 Transform '-' to '_' so the cmdline form of option names can be used.
291 return optionstr.lower().replace('-', '_')
293 def get_section(self, section, raw=0, vars=None):
295 Return a given section as a dictionary (empty if the section
296 doesn't exist).
298 All % interpolations are expanded in the return values, based on the
299 defaults passed into the constructor, unless the optional argument
300 `raw` is true. Additional substitutions may be provided using the
301 `vars` argument, which must be a dictionary whose contents overrides
302 any pre-existing defaults.
304 The section DEFAULT is special.
306 section_dict = {}
307 if self.has_section(section):
308 for option in self.options(section):
309 section_dict[option] = self.get(section, option, raw, vars)
310 return section_dict