[Zope-Checkins] CVS: Zope/lib/python/docutils/parsers/rst/directives - __init__.py:1.3 admonitions.py:1.3 body.py:1.3 html.py:1.3 images.py:1.3 misc.py:1.3 parts.py:1.3 references.py:1.3

Andreas Jung andreas@andreas-jung.com
Thu, 10 Jul 2003 11:50:24 -0400


Update of /cvs-repository/Zope/lib/python/docutils/parsers/rst/directives
In directory cvs.zope.org:/tmp/cvs-serv8556/parsers/rst/directives

Modified Files:
	__init__.py admonitions.py body.py html.py images.py misc.py 
	parts.py references.py 
Log Message:
docutils update


=== Zope/lib/python/docutils/parsers/rst/directives/__init__.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/__init__.py:1.2	Sat Feb  1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/__init__.py	Thu Jul 10 11:49:44 2003
@@ -60,7 +60,8 @@
 
 - ``options``: A dictionary, mapping known option names to conversion
   functions such as `int` or `float`.  ``None`` or an empty dict implies no
-  options to parse.
+  options to parse.  Several directive option conversion functions are defined
+  in this module.
 
 - ``content``: A boolean; true if content is allowed.  Client code must handle
   the case where content is required but not supplied (an empty content list
@@ -92,9 +93,15 @@
       'tip': ('admonitions', 'tip'),
       'hint': ('admonitions', 'hint'),
       'warning': ('admonitions', 'warning'),
+      'admonition': ('admonitions', 'admonition'),
+      'sidebar': ('body', 'sidebar'),
       'topic': ('body', 'topic'),
       'line-block': ('body', 'line_block'),
       'parsed-literal': ('body', 'parsed_literal'),
+      'rubric': ('body', 'rubric'),
+      'epigraph': ('body', 'epigraph'),
+      'highlights': ('body', 'highlights'),
+      'pull-quote': ('body', 'pull_quote'),
       #'questions': ('body', 'question_list'),
       'image': ('images', 'image'),
       'figure': ('images', 'figure'),
@@ -108,6 +115,8 @@
       'raw': ('misc', 'raw'),
       'include': ('misc', 'include'),
       'replace': ('misc', 'replace'),
+      'unicode': ('misc', 'unicode_directive'),
+      'class': ('misc', 'class_directive'),
       'restructuredtext-test-directive': ('misc', 'directive_test_function'),}
 """Mapping of directive name to (module name, function name).  The directive
 name is canonical & must be lowercase.  Language-dependent names are defined
@@ -171,9 +180,14 @@
         return None, messages
     return function, messages
 
+def register_directive(name, directive):
+    """Register a nonstandard application-defined directive function."""
+    _directives[name] = directive
+
 def flag(argument):
     """
     Check for a valid flag option (no argument) and return ``None``.
+    (Directive option conversion function.)
 
     Raise ``ValueError`` if an argument is found.
     """
@@ -182,9 +196,10 @@
     else:
         return None
 
-def unchanged(argument):
+def unchanged_required(argument):
     """
-    Return the argument, unchanged.
+    Return the argument text, unchanged.
+    (Directive option conversion function.)
 
     Raise ``ValueError`` if no argument is found.
     """
@@ -193,9 +208,22 @@
     else:
         return argument  # unchanged!
 
+def unchanged(argument):
+    """
+    Return the argument text, unchanged.
+    (Directive option conversion function.)
+
+    No argument implies empty string ("").
+    """
+    if argument is None:
+        return u''
+    else:
+        return argument  # unchanged!
+
 def path(argument):
     """
     Return the path argument unwrapped (with newlines removed).
+    (Directive option conversion function.)
 
     Raise ``ValueError`` if no argument is found or if the path contains
     internal whitespace.
@@ -212,17 +240,44 @@
 def nonnegative_int(argument):
     """
     Check for a nonnegative integer argument; raise ``ValueError`` if not.
+    (Directive option conversion function.)
     """
     value = int(argument)
     if value < 0:
         raise ValueError('negative value; must be positive or zero')
     return value
 
+
+def class_option(argument):
+    """
+    Convert the argument into an ID-compatible string and return it.
+    (Directive option conversion function.)
+
+    Raise ``ValueError`` if no argument is found.
+    """
+    if argument is None:
+        raise ValueError('argument required but none supplied')
+    return nodes.make_id(argument)
+
 def format_values(values):
     return '%s, or "%s"' % (', '.join(['"%s"' % s for s in values[:-1]]),
                             values[-1])
 
 def choice(argument, values):
+    """
+    Directive option utility function, supplied to enable options whose
+    argument must be a member of a finite set of possible values (must be
+    lower case).  A custom conversion function must be written to use it.  For
+    example::
+
+        from docutils.parsers.rst import directives
+
+        def yesno(argument):
+            return directives.choice(argument, ('yes', 'no'))
+
+    Raise ``ValueError`` if no argument is found or if the argument's value is
+    not valid (not an entry in the supplied list).
+    """
     try:
         value = argument.lower().strip()
     except AttributeError:


=== Zope/lib/python/docutils/parsers/rst/directives/admonitions.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/admonitions.py:1.2	Sat Feb  1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/admonitions.py	Thu Jul 10 11:49:44 2003
@@ -11,64 +11,80 @@
 __docformat__ = 'reStructuredText'
 
 
-from docutils.parsers.rst import states
+from docutils.parsers.rst import states, directives
 from docutils import nodes
 
 
-def admonition(node_class, name, arguments, options, content, lineno,
-               content_offset, block_text, state, state_machine):
-    text = '\n'.join(content)
-    admonition_node = node_class(text)
-    if text:
-        state.nested_parse(content, content_offset, admonition_node)
-        return [admonition_node]
-    else:
+def make_admonition(node_class, name, arguments, options, content, lineno,
+                       content_offset, block_text, state, state_machine):
+    if not content:
         error = state_machine.reporter.error(
             'The "%s" admonition is empty; content required.' % (name),
             nodes.literal_block(block_text, block_text), line=lineno)
         return [error]
+    text = '\n'.join(content)
+    admonition_node = node_class(text)
+    if arguments:
+        title_text = arguments[0]
+        textnodes, messages = state.inline_text(title_text, lineno)
+        admonition_node += nodes.title(title_text, '', *textnodes)
+        admonition_node += messages
+        if options.has_key('class'):
+            class_value = options['class']
+        else:
+            class_value = 'admonition-' + nodes.make_id(title_text)
+        admonition_node.set_class(class_value)
+    state.nested_parse(content, content_offset, admonition_node)
+    return [admonition_node]
+
+def admonition(*args):
+    return make_admonition(nodes.admonition, *args)
+
+admonition.arguments = (1, 0, 1)
+admonition.options = {'class': directives.class_option}
+admonition.content = 1
 
 def attention(*args):
-    return admonition(nodes.attention, *args)
+    return make_admonition(nodes.attention, *args)
 
 attention.content = 1
 
 def caution(*args):
-    return admonition(nodes.caution, *args)
+    return make_admonition(nodes.caution, *args)
 
 caution.content = 1
 
 def danger(*args):
-    return admonition(nodes.danger, *args)
+    return make_admonition(nodes.danger, *args)
 
 danger.content = 1
 
 def error(*args):
-    return admonition(nodes.error, *args)
+    return make_admonition(nodes.error, *args)
 
 error.content = 1
 
+def hint(*args):
+    return make_admonition(nodes.hint, *args)
+
+hint.content = 1
+
 def important(*args):
-    return admonition(nodes.important, *args)
+    return make_admonition(nodes.important, *args)
 
 important.content = 1
 
 def note(*args):
-    return admonition(nodes.note, *args)
+    return make_admonition(nodes.note, *args)
 
 note.content = 1
 
 def tip(*args):
-    return admonition(nodes.tip, *args)
+    return make_admonition(nodes.tip, *args)
 
 tip.content = 1
 
-def hint(*args):
-    return admonition(nodes.hint, *args)
-
-hint.content = 1
-
 def warning(*args):
-    return admonition(nodes.warning, *args)
+    return make_admonition(nodes.warning, *args)
 
 warning.content = 1


=== Zope/lib/python/docutils/parsers/rst/directives/body.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/body.py:1.2	Sat Feb  1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/body.py	Thu Jul 10 11:49:44 2003
@@ -13,13 +13,16 @@
 
 import sys
 from docutils import nodes
+from docutils.parsers.rst import directives
 
 
 def topic(name, arguments, options, content, lineno,
-          content_offset, block_text, state, state_machine):
+          content_offset, block_text, state, state_machine,
+          node_class=nodes.topic):
     if not state_machine.match_titles:
         error = state_machine.reporter.error(
-              'Topics may not be nested within topics or body elements.',
+              'The "%s" directive may not be used within topics, sidebars, '
+              'or body elements.' % name,
               nodes.literal_block(block_text, block_text), line=lineno)
         return [error]
     if not content:
@@ -30,16 +33,35 @@
         return [warning]
     title_text = arguments[0]
     textnodes, messages = state.inline_text(title_text, lineno)
-    title = nodes.title(title_text, '', *textnodes)
+    titles = [nodes.title(title_text, '', *textnodes)]
+    if options.has_key('subtitle'):
+        textnodes, more_messages = state.inline_text(options['subtitle'],
+                                                     lineno)
+        titles.append(nodes.subtitle(options['subtitle'], '', *textnodes))
+        messages.extend(more_messages)
     text = '\n'.join(content)
-    topic_node = nodes.topic(text, title, *messages)
+    node = node_class(text, *(titles + messages))
+    if options.has_key('class'):
+        node.set_class(options['class'])
     if text:
-        state.nested_parse(content, content_offset, topic_node)
-    return [topic_node]
+        state.nested_parse(content, content_offset, node)
+    return [node]
 
 topic.arguments = (1, 0, 1)
+topic.options = {'class': directives.class_option}
 topic.content = 1
 
+def sidebar(name, arguments, options, content, lineno,
+            content_offset, block_text, state, state_machine):
+    return topic(name, arguments, options, content, lineno,
+                 content_offset, block_text, state, state_machine,
+                 node_class=nodes.sidebar)
+
+sidebar.arguments = (1, 0, 1)
+sidebar.options = {'subtitle': directives.unchanged_required,
+                   'class': directives.class_option}
+sidebar.content = 1
+
 def line_block(name, arguments, options, content, lineno,
                content_offset, block_text, state, state_machine,
                node_class=nodes.line_block):
@@ -50,9 +72,10 @@
         return [warning]
     text = '\n'.join(content)
     text_nodes, messages = state.inline_text(text, lineno)
-    node = node_class(text, '', *text_nodes)
+    node = node_class(text, '', *text_nodes, **options)
     return [node] + messages
 
+line_block.options = {'class': directives.class_option}
 line_block.content = 1
 
 def parsed_literal(name, arguments, options, content, lineno,
@@ -61,4 +84,39 @@
                       content_offset, block_text, state, state_machine,
                       node_class=nodes.literal_block)
 
+parsed_literal.options = {'class': directives.class_option}
 parsed_literal.content = 1
+
+def rubric(name, arguments, options, content, lineno,
+             content_offset, block_text, state, state_machine):
+    rubric_text = arguments[0]
+    textnodes, messages = state.inline_text(rubric_text, lineno)
+    rubric = nodes.rubric(rubric_text, '', *textnodes, **options)
+    return [rubric] + messages
+
+rubric.arguments = (1, 0, 1)
+rubric.options = {'class': directives.class_option}
+
+def epigraph(name, arguments, options, content, lineno,
+             content_offset, block_text, state, state_machine):
+    block_quote, messages = state.block_quote(content, content_offset)
+    block_quote.set_class('epigraph')
+    return [block_quote] + messages
+
+epigraph.content = 1
+
+def highlights(name, arguments, options, content, lineno,
+             content_offset, block_text, state, state_machine):
+    block_quote, messages = state.block_quote(content, content_offset)
+    block_quote.set_class('highlights')
+    return [block_quote] + messages
+
+highlights.content = 1
+
+def pull_quote(name, arguments, options, content, lineno,
+             content_offset, block_text, state, state_machine):
+    block_quote, messages = state.block_quote(content, content_offset)
+    block_quote.set_class('pull-quote')
+    return [block_quote] + messages
+
+pull_quote.content = 1


=== Zope/lib/python/docutils/parsers/rst/directives/html.py 1.2 => 1.3 ===


=== Zope/lib/python/docutils/parsers/rst/directives/images.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/images.py:1.2	Sat Feb  1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/images.py	Thu Jul 10 11:49:44 2003
@@ -15,6 +15,10 @@
 from docutils import nodes, utils
 from docutils.parsers.rst import directives
 
+try:
+    import Image                        # PIL
+except ImportError:
+    Image = None
 
 align_values = ('top', 'middle', 'bottom', 'left', 'center', 'right')
 
@@ -38,15 +42,33 @@
                  'height': directives.nonnegative_int,
                  'width': directives.nonnegative_int,
                  'scale': directives.nonnegative_int,
-                 'align': align}
+                 'align': align,
+                 'class': directives.class_option}
 
 def figure(name, arguments, options, content, lineno,
            content_offset, block_text, state, state_machine):
+    figwidth = options.setdefault('figwidth')
+    figclass = options.setdefault('figclass')
+    del options['figwidth']
+    del options['figclass']
     (image_node,) = image(name, arguments, options, content, lineno,
                          content_offset, block_text, state, state_machine)
     if isinstance(image_node, nodes.system_message):
         return [image_node]
     figure_node = nodes.figure('', image_node)
+    if figwidth == 'image':
+        if Image:
+            # PIL doesn't like Unicode paths:
+            try:
+                i = Image.open(str(image_node['uri']))
+            except (IOError, UnicodeError):
+                pass
+            else:
+                figure_node['width'] = i.size[0]
+    elif figwidth is not None:
+        figure_node['width'] = figwidth
+    if figclass:
+        figure_node.set_class(figclass)
     if content:
         node = nodes.Element()          # anonymous container for parsing
         state.nested_parse(content, content_offset, node)
@@ -65,6 +87,14 @@
             figure_node += nodes.legend('', *node[1:])
     return [figure_node]
 
+def figwidth_value(argument):
+    if argument.lower() == 'image':
+        return 'image'
+    else:
+        return directives.nonnegative_int(argument)
+
 figure.arguments = (1, 0, 1)
-figure.options = image.options
+figure.options = {'figwidth': figwidth_value,
+                  'figclass': directives.class_option}
+figure.options.update(image.options)
 figure.content = 1


=== Zope/lib/python/docutils/parsers/rst/directives/misc.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/misc.py:1.2	Sat Feb  1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/misc.py	Thu Jul 10 11:49:44 2003
@@ -10,9 +10,11 @@
 
 import sys
 import os.path
+import re
 from urllib2 import urlopen, URLError
 from docutils import io, nodes, statemachine, utils
 from docutils.parsers.rst import directives, states
+from docutils.transforms import misc
 
 
 def include(name, arguments, options, content, lineno,
@@ -31,10 +33,12 @@
     path = utils.relative_path(None, path)
     try:
         include_file = io.FileInput(
-            source_path=path, encoding=state.document.settings.input_encoding)
+            source_path=path, encoding=state.document.settings.input_encoding,
+            handle_io_errors=None)
     except IOError, error:
         severe = state_machine.reporter.severe(
-              'Problems with "%s" directive path:\n%s.' % (name, error),
+              'Problems with "%s" directive path:\n%s: %s.'
+              % (name, error.__class__.__name__, error),
               nodes.literal_block(block_text, block_text), line=lineno)
         return [severe]
     include_text = include_file.read()
@@ -151,6 +155,65 @@
 
 replace.content = 1
 
+def unicode_directive(name, arguments, options, content, lineno,
+                         content_offset, block_text, state, state_machine):
+    r"""
+    Convert Unicode character codes (numbers) to characters.  Codes may be
+    decimal numbers, hexadecimal numbers (prefixed by ``0x``, ``x``, ``\x``,
+    ``U+``, ``u``, or ``\u``; e.g. ``U+262E``), or XML-style numeric character
+    entities (e.g. ``&#x262E;``).  Text following ".." is a comment and is
+    ignored.  Spaces are ignored, and any other text remains as-is.
+    """
+    if not isinstance(state, states.SubstitutionDef):
+        error = state_machine.reporter.error(
+            'Invalid context: the "%s" directive can only be used within a '
+            'substitution definition.' % (name),
+            nodes.literal_block(block_text, block_text), line=lineno)
+        return [error]
+    codes = arguments[0].split('.. ')[0].split()
+    element = nodes.Element()
+    for code in codes:
+        try:
+            if code.isdigit():
+                element += nodes.Text(unichr(int(code)))
+            else:
+                match = unicode_pattern.match(code)
+                if match:
+                    value = match.group(1) or match.group(2)
+                    element += nodes.Text(unichr(int(value, 16)))
+                else:
+                    element += nodes.Text(code)
+        except ValueError, err:
+            error = state_machine.reporter.error(
+                'Invalid character code: %s\n%s' % (code, err),
+                nodes.literal_block(block_text, block_text), line=lineno)
+            return [error]
+    return element.children
+
+unicode_directive.arguments = (1, 0, 1)
+unicode_pattern = re.compile(
+    r'(?:0x|x|\x00x|U\+?|\x00u)([0-9a-f]+)$|&#x([0-9a-f]+);$', re.IGNORECASE)
+
+def class_directive(name, arguments, options, content, lineno,
+                       content_offset, block_text, state, state_machine):
+    """"""
+    class_value = nodes.make_id(arguments[0])
+    if class_value:
+        pending = nodes.pending(misc.ClassAttribute,
+                                {'class': class_value, 'directive': name},
+                                block_text)
+        state_machine.document.note_pending(pending)
+        return [pending]
+    else:
+        error = state_machine.reporter.error(
+            'Invalid class attribute value for "%s" directive: %s'
+            % (name, arguments[0]),
+            nodes.literal_block(block_text, block_text), line=lineno)
+        return [error]
+
+class_directive.arguments = (1, 0, 0)
+class_directive.content = 1
+
 def directive_test_function(name, arguments, options, content, lineno,
                             content_offset, block_text, state, state_machine):
     if content:
@@ -166,5 +229,5 @@
     return [info]
 
 directive_test_function.arguments = (0, 1, 1)
-directive_test_function.options = {'option': directives.unchanged}
+directive_test_function.options = {'option': directives.unchanged_required}
 directive_test_function.content = 1


=== Zope/lib/python/docutils/parsers/rst/directives/parts.py 1.2 => 1.3 ===
--- Zope/lib/python/docutils/parsers/rst/directives/parts.py:1.2	Sat Feb  1 04:26:09 2003
+++ Zope/lib/python/docutils/parsers/rst/directives/parts.py	Thu Jul 10 11:49:44 2003
@@ -42,7 +42,8 @@
 contents.arguments = (0, 1, 1)
 contents.options = {'depth': directives.nonnegative_int,
                     'local': directives.flag,
-                    'backlinks': backlinks}
+                    'backlinks': backlinks,
+                    'class': directives.class_option}
 
 def sectnum(name, arguments, options, content, lineno,
             content_offset, block_text, state, state_machine):


=== Zope/lib/python/docutils/parsers/rst/directives/references.py 1.2 => 1.3 ===