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

« back to all changes in this revision

Viewing changes to docutils/parsers/rst/directives/__init__.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
 
# Contact: goodger@users.sourceforge.net
3
 
# Revision: $Revision: 1.26 $
4
 
# Date: $Date: 2004/04/17 22:49:40 $
 
2
# Contact: goodger@python.org
 
3
# Revision: $Revision: 4229 $
 
4
# Date: $Date: 2005-12-23 00:46:16 +0100 (Fri, 23 Dec 2005) $
5
5
# Copyright: This module has been placed in the public domain.
6
6
 
7
7
"""
20
20
 
21
21
Parameters:
22
22
 
23
 
- ``name`` is the directive type or name.
24
 
 
25
 
- ``arguments`` is a list of positional arguments.
26
 
 
27
 
- ``options`` is a dictionary mapping option names to values.
 
23
- ``name`` is the directive type or name (string).
 
24
 
 
25
- ``arguments`` is a list of positional arguments (strings).
 
26
 
 
27
- ``options`` is a dictionary mapping option names (strings) to values (type
 
28
  depends on option conversion functions; see below).
28
29
 
29
30
- ``content`` is a list of strings, the directive content.
30
31
 
63
64
  options to parse.  Several directive option conversion functions are defined
64
65
  in this module.
65
66
 
 
67
  Option conversion functions take a single parameter, the option argument (a
 
68
  string or ``None``), validate it and/or convert it to the appropriate form.
 
69
  Conversion functions may raise ``ValueError`` and ``TypeError`` exceptions.
 
70
 
66
71
- ``content``: A boolean; true if content is allowed.  Client code must handle
67
72
  the case where content is required but not supplied (an empty content list
68
73
  will be supplied).
74
79
See `Creating reStructuredText Directives`_ for more information.
75
80
 
76
81
.. _Creating reStructuredText Directives:
77
 
   http://docutils.sourceforge.net/spec/howto/rst-directives.html
 
82
   http://docutils.sourceforge.net/docs/howto/rst-directives.html
78
83
"""
79
84
 
80
85
__docformat__ = 'reStructuredText'
81
86
 
 
87
import re
 
88
import codecs
82
89
from docutils import nodes
83
90
from docutils.parsers.rst.languages import en as _fallback_language_module
84
91
 
102
109
      'epigraph': ('body', 'epigraph'),
103
110
      'highlights': ('body', 'highlights'),
104
111
      'pull-quote': ('body', 'pull_quote'),
105
 
      'table': ('body', 'table'),
 
112
      'compound': ('body', 'compound'),
 
113
      'container': ('body', 'container'),
106
114
      #'questions': ('body', 'question_list'),
 
115
      'table': ('tables', 'table'),
 
116
      'csv-table': ('tables', 'csv_table'),
 
117
      'list-table': ('tables', 'list_table'),
107
118
      'image': ('images', 'image'),
108
119
      'figure': ('images', 'figure'),
109
120
      'contents': ('parts', 'contents'),
110
121
      'sectnum': ('parts', 'sectnum'),
 
122
      'header': ('parts', 'header'),
 
123
      'footer': ('parts', 'footer'),
111
124
      #'footnotes': ('parts', 'footnotes'),
112
125
      #'citations': ('parts', 'citations'),
113
126
      'target-notes': ('references', 'target_notes'),
119
132
      'unicode': ('misc', 'unicode_directive'),
120
133
      'class': ('misc', 'class_directive'),
121
134
      'role': ('misc', 'role'),
 
135
      'default-role': ('misc', 'default_role'),
 
136
      'title': ('misc', 'title'),
 
137
      'date': ('misc', 'date'),
122
138
      'restructuredtext-test-directive': ('misc', 'directive_test_function'),}
123
139
"""Mapping of directive name to (module name, function name).  The directive
124
140
name is canonical & must be lowercase.  Language-dependent names are defined
167
183
    try:
168
184
        modulename, functionname = _directive_registry[canonicalname]
169
185
    except KeyError:
170
 
        messages.append(document.reporter.error(
171
 
            'Directive "%s" not registered (canonical name "%s").'
172
 
            % (directive_name, canonicalname), line=document.current_line))
 
186
        # Error handling done by caller.
173
187
        return None, messages
174
188
    if _modules.has_key(modulename):
175
189
        module = _modules[modulename]
193
207
        return None, messages
194
208
    return function, messages
195
209
 
196
 
def register_directive(name, directive):
 
210
def register_directive(name, directive_function):
197
211
    """
198
212
    Register a nonstandard application-defined directive function.
199
213
    Language lookups are not needed for such functions.
200
214
    """
201
 
    _directives[name] = directive
 
215
    _directives[name] = directive_function
202
216
 
203
217
def flag(argument):
204
218
    """
241
255
    Return the path argument unwrapped (with newlines removed).
242
256
    (Directive option conversion function.)
243
257
 
244
 
    Raise ``ValueError`` if no argument is found or if the path contains
245
 
    internal whitespace.
 
258
    Raise ``ValueError`` if no argument is found.
246
259
    """
247
260
    if argument is None:
248
261
        raise ValueError('argument required but none supplied')
249
262
    else:
250
263
        path = ''.join([s.strip() for s in argument.splitlines()])
251
 
        if path.find(' ') == -1:
252
 
            return path
253
 
        else:
254
 
            raise ValueError('path contains whitespace')
 
264
        return path
 
265
 
 
266
def uri(argument):
 
267
    """
 
268
    Return the URI argument with whitespace removed.
 
269
    (Directive option conversion function.)
 
270
 
 
271
    Raise ``ValueError`` if no argument is found.
 
272
    """
 
273
    if argument is None:
 
274
        raise ValueError('argument required but none supplied')
 
275
    else:
 
276
        uri = ''.join(argument.split())
 
277
        return uri
255
278
 
256
279
def nonnegative_int(argument):
257
280
    """
263
286
        raise ValueError('negative value; must be positive or zero')
264
287
    return value
265
288
 
 
289
length_units = ['em', 'ex', 'px', 'in', 'cm', 'mm', 'pt', 'pc']
 
290
 
 
291
def get_measure(argument, units):
 
292
    """
 
293
    Check for a positive argument of one of the units and return a
 
294
    normalized string of the form "<value><unit>" (without space in
 
295
    between).
 
296
    
 
297
    To be called from directive option conversion functions.
 
298
    """
 
299
    match = re.match(r'^([0-9.]+) *(%s)$' % '|'.join(units), argument)
 
300
    try:
 
301
        assert match is not None
 
302
        float(match.group(1))
 
303
    except (AssertionError, ValueError):
 
304
        raise ValueError(
 
305
            'not a positive measure of one of the following units:\n%s'
 
306
            % ' '.join(['"%s"' % i for i in units]))
 
307
    return match.group(1) + match.group(2)
 
308
 
 
309
def length_or_unitless(argument):
 
310
    return get_measure(argument, length_units + [''])
 
311
 
 
312
def length_or_percentage_or_unitless(argument):
 
313
    return get_measure(argument, length_units + ['%', ''])
266
314
 
267
315
def class_option(argument):
268
316
    """
269
 
    Convert the argument into an ID-compatible string and return it.
 
317
    Convert the argument into a list of ID-compatible strings and return it.
270
318
    (Directive option conversion function.)
271
319
 
272
320
    Raise ``ValueError`` if no argument is found.
273
321
    """
274
322
    if argument is None:
275
323
        raise ValueError('argument required but none supplied')
276
 
    class_name = nodes.make_id(argument)
277
 
    if not class_name:
278
 
        raise ValueError('cannot make "%s" into a class name' % argument)
279
 
    return class_name
280
 
 
281
 
def format_values(values):
282
 
    return '%s, or "%s"' % (', '.join(['"%s"' % s for s in values[:-1]]),
283
 
                            values[-1])
 
324
    names = argument.split()
 
325
    class_names = []
 
326
    for name in names:
 
327
        class_name = nodes.make_id(name)
 
328
        if not class_name:
 
329
            raise ValueError('cannot make "%s" into a class name' % name)
 
330
        class_names.append(class_name)
 
331
    return class_names
 
332
 
 
333
unicode_pattern = re.compile(
 
334
    r'(?:0x|x|\\x|U\+?|\\u)([0-9a-f]+)$|&#x([0-9a-f]+);$', re.IGNORECASE)
 
335
 
 
336
def unicode_code(code):
 
337
    r"""
 
338
    Convert a Unicode character code to a Unicode character.
 
339
    (Directive option conversion function.)
 
340
 
 
341
    Codes may be decimal numbers, hexadecimal numbers (prefixed by ``0x``,
 
342
    ``x``, ``\x``, ``U+``, ``u``, or ``\u``; e.g. ``U+262E``), or XML-style
 
343
    numeric character entities (e.g. ``&#x262E;``).  Other text remains as-is.
 
344
 
 
345
    Raise ValueError for illegal Unicode code values.
 
346
    """
 
347
    try:
 
348
        if code.isdigit():                  # decimal number
 
349
            return unichr(int(code))
 
350
        else:
 
351
            match = unicode_pattern.match(code)
 
352
            if match:                       # hex number
 
353
                value = match.group(1) or match.group(2)
 
354
                return unichr(int(value, 16))
 
355
            else:                           # other text
 
356
                return code
 
357
    except OverflowError, detail:
 
358
        raise ValueError('code too large (%s)' % detail)
 
359
 
 
360
def single_char_or_unicode(argument):
 
361
    """
 
362
    A single character is returned as-is.  Unicode characters codes are
 
363
    converted as in `unicode_code`.  (Directive option conversion function.)
 
364
    """
 
365
    char = unicode_code(argument)
 
366
    if len(char) > 1:
 
367
        raise ValueError('%r invalid; must be a single character or '
 
368
                         'a Unicode code' % char)
 
369
    return char
 
370
 
 
371
def single_char_or_whitespace_or_unicode(argument):
 
372
    """
 
373
    As with `single_char_or_unicode`, but "tab" and "space" are also supported.
 
374
    (Directive option conversion function.)
 
375
    """
 
376
    if argument == 'tab':
 
377
        char = '\t'
 
378
    elif argument == 'space':
 
379
        char = ' '
 
380
    else:
 
381
        char = single_char_or_unicode(argument)
 
382
    return char
 
383
 
 
384
def positive_int(argument):
 
385
    """
 
386
    Converts the argument into an integer.  Raises ValueError for negative,
 
387
    zero, or non-integer values.  (Directive option conversion function.)
 
388
    """
 
389
    value = int(argument)
 
390
    if value < 1:
 
391
        raise ValueError('negative or zero value; must be positive')
 
392
    return value
 
393
 
 
394
def positive_int_list(argument):
 
395
    """
 
396
    Converts a space- or comma-separated list of values into a Python list
 
397
    of integers.
 
398
    (Directive option conversion function.)
 
399
 
 
400
    Raises ValueError for non-positive-integer values.
 
401
    """
 
402
    if ',' in argument:
 
403
        entries = argument.split(',')
 
404
    else:
 
405
        entries = argument.split()
 
406
    return [positive_int(entry) for entry in entries]
 
407
 
 
408
def encoding(argument):
 
409
    """
 
410
    Verfies the encoding argument by lookup.
 
411
    (Directive option conversion function.)
 
412
 
 
413
    Raises ValueError for unknown encodings.
 
414
    """
 
415
    try:
 
416
        codecs.lookup(argument)
 
417
    except LookupError:
 
418
        raise ValueError('unknown encoding: "%s"' % argument)
 
419
    return argument
284
420
 
285
421
def choice(argument, values):
286
422
    """
307
443
    else:
308
444
        raise ValueError('"%s" unknown; choose from %s'
309
445
                         % (argument, format_values(values)))
 
446
 
 
447
def format_values(values):
 
448
    return '%s, or "%s"' % (', '.join(['"%s"' % s for s in values[:-1]]),
 
449
                            values[-1])