1 # Author: David Goodger
2 # Contact: goodger@users.sourceforge.net
5 # Copyright: This module has been placed in the public domain.
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.
18 __docformat__
= 'reStructuredText'
22 import ConfigParser
as CP
24 from docutils
import optik
25 from docutils
.optik
import Values
28 def store_multiple(option
, opt
, value
, parser
, *args
, **kwargs
):
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`.
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
):
42 Read a configuration file during option processing. (Option callback.)
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):
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`.
59 base_path
= os
.getcwd()
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
):
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.
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."""
85 'General Docutils Options',
87 (('Include a "Generated by Docutils" credit and link at the end '
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 '
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 '
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
,
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
203 optik
.OptionParser
.__init
__(
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),
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:
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]
230 group
= optik
.OptionGroup(self
, title
, description
)
231 self
.add_option_group(group
)
233 group
= self
# single options
234 for (help_text
, option_strings
, kwargs
) in option_spec
:
235 group
.add_option(help=help_text
, *option_strings
,
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
,
252 def check_threshold(self
, level
):
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
266 destination
= args
.pop(0)
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
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.
307 if self
.has_section(section
):
308 for option
in self
.options(section
):
309 section_dict
[option
] = self
.get(section
, option
, raw
, vars)