~ubuntu-branches/ubuntu/karmic/python-docutils/karmic

« back to all changes in this revision

Viewing changes to docutils/parsers/rst/directives/misc.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
# Authors: David Goodger, Dethe Elza
2
2
# Contact: goodger@users.sourceforge.net
3
 
# Revision: $Revision: 1.22 $
4
 
# Date: $Date: 2004/04/27 19:48:37 $
 
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
"""Miscellaneous directives."""
11
11
import sys
12
12
import os.path
13
13
import re
 
14
import time
14
15
from docutils import io, nodes, statemachine, utils
15
16
from docutils.parsers.rst import directives, roles, states
16
17
from docutils.transforms import misc
21
22
    urllib2 = None
22
23
 
23
24
 
 
25
standard_include_path = os.path.join(os.path.dirname(states.__file__),
 
26
                                     'include')
 
27
 
24
28
def include(name, arguments, options, content, lineno,
25
29
            content_offset, block_text, state, state_machine):
26
30
    """Include a reST file as part of the content of this reST file."""
 
31
    if not state.document.settings.file_insertion_enabled:
 
32
        warning = state_machine.reporter.warning(
 
33
              '"%s" directive disabled.' % name,
 
34
              nodes.literal_block(block_text, block_text), line=lineno)
 
35
        return [warning]
27
36
    source = state_machine.input_lines.source(
28
37
        lineno - state_machine.input_offset - 1)
29
38
    source_dir = os.path.dirname(os.path.abspath(source))
30
 
    path = ''.join(arguments[0].splitlines())
31
 
    if path.find(' ') != -1:
32
 
        error = state_machine.reporter.error(
33
 
              '"%s" directive path contains whitespace.' % name,
34
 
              nodes.literal_block(block_text, block_text), line=lineno)
35
 
        return [error]
 
39
    path = directives.path(arguments[0])
 
40
    if path.startswith('<') and  path.endswith('>'):
 
41
        path = os.path.join(standard_include_path, path[1:-1])
36
42
    path = os.path.normpath(os.path.join(source_dir, path))
37
43
    path = utils.relative_path(None, path)
 
44
    encoding = options.get('encoding', state.document.settings.input_encoding)
38
45
    try:
 
46
        state.document.settings.record_dependencies.add(path)
39
47
        include_file = io.FileInput(
40
 
            source_path=path, encoding=state.document.settings.input_encoding,
 
48
            source_path=path, encoding=encoding,
 
49
            error_handler=state.document.settings.input_encoding_error_handler,
41
50
            handle_io_errors=None)
42
51
    except IOError, error:
43
52
        severe = state_machine.reporter.severe(
45
54
              % (name, error.__class__.__name__, error),
46
55
              nodes.literal_block(block_text, block_text), line=lineno)
47
56
        return [severe]
48
 
    include_text = include_file.read()
 
57
    try:
 
58
        include_text = include_file.read()
 
59
    except UnicodeError, error:
 
60
        severe = state_machine.reporter.severe(
 
61
              'Problem with "%s" directive:\n%s: %s'
 
62
              % (name, error.__class__.__name__, error),
 
63
              nodes.literal_block(block_text, block_text), line=lineno)
 
64
        return [severe]
49
65
    if options.has_key('literal'):
50
66
        literal_block = nodes.literal_block(include_text, include_text,
51
67
                                            source=path)
58
74
        return []
59
75
 
60
76
include.arguments = (1, 0, 1)
61
 
include.options = {'literal': directives.flag}
 
77
include.options = {'literal': directives.flag,
 
78
                   'encoding': directives.encoding}
62
79
 
63
80
def raw(name, arguments, options, content, lineno,
64
81
        content_offset, block_text, state, state_machine):
70
87
    Content may be included inline (content section of directive) or
71
88
    imported from a file or url.
72
89
    """
73
 
    attributes = {'format': arguments[0]}
 
90
    if ( not state.document.settings.raw_enabled
 
91
         or (not state.document.settings.file_insertion_enabled
 
92
             and (options.has_key('file') or options.has_key('url'))) ):
 
93
        warning = state_machine.reporter.warning(
 
94
              '"%s" directive disabled.' % name,
 
95
              nodes.literal_block(block_text, block_text), line=lineno)
 
96
        return [warning]
 
97
    attributes = {'format': ' '.join(arguments[0].lower().split())}
 
98
    encoding = options.get('encoding', state.document.settings.input_encoding)
74
99
    if content:
75
100
        if options.has_key('file') or options.has_key('url'):
76
101
            error = state_machine.reporter.error(
91
116
        path = os.path.normpath(os.path.join(source_dir, options['file']))
92
117
        path = utils.relative_path(None, path)
93
118
        try:
94
 
            raw_file = open(path)
 
119
            state.document.settings.record_dependencies.add(path)
 
120
            raw_file = io.FileInput(
 
121
                source_path=path, encoding=encoding,
 
122
                error_handler=state.document.settings.input_encoding_error_handler,
 
123
                handle_io_errors=None)
95
124
        except IOError, error:
96
125
            severe = state_machine.reporter.severe(
97
126
                  'Problems with "%s" directive path:\n%s.' % (name, error),
98
127
                  nodes.literal_block(block_text, block_text), line=lineno)
99
128
            return [severe]
100
 
        text = raw_file.read()
101
 
        raw_file.close()
 
129
        try:
 
130
            text = raw_file.read()
 
131
        except UnicodeError, error:
 
132
            severe = state_machine.reporter.severe(
 
133
                  'Problem with "%s" directive:\n%s: %s'
 
134
                  % (name, error.__class__.__name__, error),
 
135
                  nodes.literal_block(block_text, block_text), line=lineno)
 
136
            return [severe]
102
137
        attributes['source'] = path
103
138
    elif options.has_key('url'):
104
139
        if not urllib2:
108
143
                  '"urllib2" module).' % name,
109
144
                  nodes.literal_block(block_text, block_text), line=lineno)
110
145
            return [severe]
 
146
        source = options['url']
111
147
        try:
112
 
            raw_file = urllib2.urlopen(options['url'])
 
148
            raw_text = urllib2.urlopen(source).read()
113
149
        except (urllib2.URLError, IOError, OSError), error:
114
150
            severe = state_machine.reporter.severe(
115
151
                  'Problems with "%s" directive URL "%s":\n%s.'
116
152
                  % (name, options['url'], error),
117
153
                  nodes.literal_block(block_text, block_text), line=lineno)
118
154
            return [severe]
119
 
        text = raw_file.read()
120
 
        raw_file.close()        
121
 
        attributes['source'] = options['file']
 
155
        raw_file = io.StringInput(
 
156
            source=raw_text, source_path=source, encoding=encoding,
 
157
            error_handler=state.document.settings.input_encoding_error_handler)
 
158
        try:
 
159
            text = raw_file.read()
 
160
        except UnicodeError, error:
 
161
            severe = state_machine.reporter.severe(
 
162
                  'Problem with "%s" directive:\n%s: %s'
 
163
                  % (name, error.__class__.__name__, error),
 
164
                  nodes.literal_block(block_text, block_text), line=lineno)
 
165
            return [severe]
 
166
        attributes['source'] = source
122
167
    else:
123
168
        error = state_machine.reporter.warning(
124
169
            'The "%s" directive requires content; none supplied.' % (name),
129
174
 
130
175
raw.arguments = (1, 0, 1)
131
176
raw.options = {'file': directives.path,
132
 
               'url': directives.path}
 
177
               'url': directives.uri,
 
178
               'encoding': directives.encoding}
133
179
raw.content = 1
134
180
 
135
181
def replace(name, arguments, options, content, lineno,
148
194
            messages = []
149
195
            for node in element:
150
196
                if isinstance(node, nodes.system_message):
151
 
                    if node.has_key('backrefs'):
152
 
                        del node['backrefs']
 
197
                    node['backrefs'] = []
153
198
                    messages.append(node)
154
199
            error = state_machine.reporter.error(
155
200
                'Error in "%s" directive: may contain a single paragraph '
167
212
replace.content = 1
168
213
 
169
214
def unicode_directive(name, arguments, options, content, lineno,
170
 
                         content_offset, block_text, state, state_machine):
 
215
                      content_offset, block_text, state, state_machine):
171
216
    r"""
172
217
    Convert Unicode character codes (numbers) to characters.  Codes may be
173
218
    decimal numbers, hexadecimal numbers (prefixed by ``0x``, ``x``, ``\x``,
181
226
            'substitution definition.' % (name),
182
227
            nodes.literal_block(block_text, block_text), line=lineno)
183
228
        return [error]
 
229
    substitution_definition = state_machine.node
 
230
    if options.has_key('trim'):
 
231
        substitution_definition.attributes['ltrim'] = 1
 
232
        substitution_definition.attributes['rtrim'] = 1
 
233
    if options.has_key('ltrim'):
 
234
        substitution_definition.attributes['ltrim'] = 1
 
235
    if options.has_key('rtrim'):
 
236
        substitution_definition.attributes['rtrim'] = 1
184
237
    codes = unicode_comment_pattern.split(arguments[0])[0].split()
185
238
    element = nodes.Element()
186
239
    for code in codes:
187
240
        try:
188
 
            if code.isdigit():
189
 
                element += nodes.Text(unichr(int(code)))
190
 
            else:
191
 
                match = unicode_pattern.match(code)
192
 
                if match:
193
 
                    value = match.group(1) or match.group(2)
194
 
                    element += nodes.Text(unichr(int(value, 16)))
195
 
                else:
196
 
                    element += nodes.Text(code)
197
 
        except (ValueError, OverflowError), err:
 
241
            decoded = directives.unicode_code(code)
 
242
        except ValueError, err:
198
243
            error = state_machine.reporter.error(
199
244
                'Invalid character code: %s\n%s: %s'
200
245
                % (code, err.__class__.__name__, err),
201
246
                nodes.literal_block(block_text, block_text), line=lineno)
202
247
            return [error]
 
248
        element += nodes.Text(decoded)
203
249
    return element.children
204
250
 
205
251
unicode_directive.arguments = (1, 0, 1)
206
 
unicode_pattern = re.compile(
207
 
    r'(?:0x|x|\\x|U\+?|\\u)([0-9a-f]+)$|&#x([0-9a-f]+);$', re.IGNORECASE)
208
 
unicode_comment_pattern = re.compile(r'( |\n|^).. ')
209
 
 
 
252
unicode_directive.options = {'trim': directives.flag,
 
253
                             'ltrim': directives.flag,
 
254
                             'rtrim': directives.flag}
 
255
unicode_comment_pattern = re.compile(r'( |\n|^)\.\. ')
210
256
 
211
257
def class_directive(name, arguments, options, content, lineno,
212
258
                       content_offset, block_text, state, state_machine):
213
 
    """"""
214
 
    class_value = nodes.make_id(arguments[0])
215
 
    if class_value:
 
259
    """
 
260
    Set a "class" attribute on the directive content or the next element.
 
261
    When applied to the next element, a "pending" element is inserted, and a
 
262
    transform does the work later.
 
263
    """
 
264
    try:
 
265
        class_value = directives.class_option(arguments[0])
 
266
    except ValueError:
 
267
        error = state_machine.reporter.error(
 
268
            'Invalid class attribute value for "%s" directive: "%s".'
 
269
            % (name, arguments[0]),
 
270
            nodes.literal_block(block_text, block_text), line=lineno)
 
271
        return [error]
 
272
    node_list = []
 
273
    if content:
 
274
        container = nodes.Element()
 
275
        state.nested_parse(content, content_offset, container)
 
276
        for node in container:
 
277
            node['classes'].extend(class_value)
 
278
        node_list.extend(container.children)
 
279
    else:
216
280
        pending = nodes.pending(misc.ClassAttribute,
217
281
                                {'class': class_value, 'directive': name},
218
282
                                block_text)
219
283
        state_machine.document.note_pending(pending)
220
 
        return [pending]
221
 
    else:
222
 
        error = state_machine.reporter.error(
223
 
            'Invalid class attribute value for "%s" directive: "%s".'
224
 
            % (name, arguments[0]),
225
 
            nodes.literal_block(block_text, block_text), line=lineno)
226
 
        return [error]
 
284
        node_list.append(pending)
 
285
    return node_list
227
286
 
228
 
class_directive.arguments = (1, 0, 0)
 
287
class_directive.arguments = (1, 0, 1)
229
288
class_directive.content = 1
230
289
 
231
290
role_arg_pat = re.compile(r'(%s)\s*(\(\s*(%s)\s*\)\s*)?$'
259
318
            return messages + [error]
260
319
    else:
261
320
        base_role = roles.generic_custom_role
262
 
    assert not hasattr(base_role, 'arguments'), ( 
 
321
    assert not hasattr(base_role, 'arguments'), (
263
322
        'Supplemental directive arguments for "%s" directive not supported'
264
323
        '(specified by "%r" role).' % (name, base_role))
265
324
    try:
286
345
 
287
346
role.content = 1
288
347
 
 
348
def default_role(name, arguments, options, content, lineno,
 
349
                 content_offset, block_text, state, state_machine):
 
350
    """Set the default interpreted text role."""
 
351
    if not arguments:
 
352
        if roles._roles.has_key(''):
 
353
            # restore the "default" default role
 
354
            del roles._roles['']
 
355
        return []
 
356
    role_name = arguments[0]
 
357
    role, messages = roles.role(
 
358
        role_name, state_machine.language, lineno, state.reporter)
 
359
    if role is None:
 
360
        error = state.reporter.error(
 
361
            'Unknown interpreted text role "%s".' % role_name,
 
362
            nodes.literal_block(block_text, block_text), line=lineno)
 
363
        return messages + [error]
 
364
    roles._roles[''] = role
 
365
    # @@@ should this be local to the document, not the parser?
 
366
    return messages
 
367
 
 
368
default_role.arguments = (0, 1, 0)
 
369
 
 
370
def title(name, arguments, options, content, lineno,
 
371
          content_offset, block_text, state, state_machine):
 
372
    state_machine.document['title'] = arguments[0]
 
373
    return []
 
374
 
 
375
title.arguments = (1, 0, 1)
 
376
 
 
377
def date(name, arguments, options, content, lineno,
 
378
         content_offset, block_text, state, state_machine):
 
379
    if not isinstance(state, states.SubstitutionDef):
 
380
        error = state_machine.reporter.error(
 
381
            'Invalid context: the "%s" directive can only be used within a '
 
382
            'substitution definition.' % (name),
 
383
            nodes.literal_block(block_text, block_text), line=lineno)
 
384
        return [error]
 
385
    format = '\n'.join(content) or '%Y-%m-%d'
 
386
    text = time.strftime(format)
 
387
    return [nodes.Text(text)]
 
388
 
 
389
date.content = 1
 
390
 
289
391
def directive_test_function(name, arguments, options, content, lineno,
290
392
                            content_offset, block_text, state, state_machine):
291
393
    """This directive is useful only for testing purposes."""