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

Andreas Jung andreas at andreas-jung.com
Fri Oct 29 15:08:23 EDT 2004


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

Added Files:
      Tag: Zope-2_7-branch
	__init__.py admonitions.py body.py html.py images.py misc.py 
	parts.py references.py tables.py 
Log Message:
moved docutils to lib/python/third_party


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/__init__.py ===
# Author: David Goodger
# Contact: goodger at python.org
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
This package contains directive implementation modules.

The interface for directive functions is as follows::

    def directive_fn(name, arguments, options, content, lineno,
                     content_offset, block_text, state, state_machine):
        code...

    # Set function attributes:
    directive_fn.arguments = ...
    directive_fn.options = ...
    direcitve_fn.content = ...

Parameters:

- ``name`` is the directive type or name (string).

- ``arguments`` is a list of positional arguments (strings).

- ``options`` is a dictionary mapping option names (strings) to values (type
  depends on option conversion functions; see below).

- ``content`` is a list of strings, the directive content.

- ``lineno`` is the line number of the first line of the directive.

- ``content_offset`` is the line offset of the first line of the content from
  the beginning of the current input.  Used when initiating a nested parse.

- ``block_text`` is a string containing the entire directive.  Include it as
  the content of a literal block in a system message if there is a problem.

- ``state`` is the state which called the directive function.

- ``state_machine`` is the state machine which controls the state which called
  the directive function.

Function attributes, interpreted by the directive parser (which calls the
directive function):

- ``arguments``: A 3-tuple specifying the expected positional arguments, or
  ``None`` if the directive has no arguments.  The 3 items in the tuple are
  ``(required, optional, whitespace OK in last argument)``:

  1. The number of required arguments.
  2. The number of optional arguments.
  3. A boolean, indicating if the final argument may contain whitespace.

  Arguments are normally single whitespace-separated words.  The final
  argument may contain whitespace if the third item in the argument spec tuple
  is 1/True.  If the form of the arguments is more complex, specify only one
  argument (either required or optional) and indicate that final whitespace is
  OK; the client code must do any context-sensitive parsing.

- ``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.  Several directive option conversion functions are defined
  in this module.

  Option conversion functions take a single parameter, the option argument (a
  string or ``None``), validate it and/or convert it to the appropriate form.
  Conversion functions may raise ``ValueError`` and ``TypeError`` exceptions.

- ``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
  will be supplied).

Directive functions return a list of nodes which will be inserted into the
document tree at the point where the directive was encountered (can be an
empty list).

See `Creating reStructuredText Directives`_ for more information.

.. _Creating reStructuredText Directives:
   http://docutils.sourceforge.net/docs/howto/rst-directives.html
"""

__docformat__ = 'reStructuredText'

import re
from docutils import nodes
from docutils.parsers.rst.languages import en as _fallback_language_module


_directive_registry = {
      'attention': ('admonitions', 'attention'),
      'caution': ('admonitions', 'caution'),
      'danger': ('admonitions', 'danger'),
      'error': ('admonitions', 'error'),
      'important': ('admonitions', 'important'),
      'note': ('admonitions', 'note'),
      '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'),
      'table': ('tables', 'table'),
      'csv-table': ('tables', 'csv_table'),
      'image': ('images', 'image'),
      'figure': ('images', 'figure'),
      'contents': ('parts', 'contents'),
      'sectnum': ('parts', 'sectnum'),
      #'footnotes': ('parts', 'footnotes'),
      #'citations': ('parts', 'citations'),
      'target-notes': ('references', 'target_notes'),
      'meta': ('html', 'meta'),
      #'imagemap': ('html', 'imagemap'),
      'raw': ('misc', 'raw'),
      'include': ('misc', 'include'),
      'replace': ('misc', 'replace'),
      'unicode': ('misc', 'unicode_directive'),
      'class': ('misc', 'class_directive'),
      'role': ('misc', 'role'),
      '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
in the ``language`` subpackage."""

_modules = {}
"""Cache of imported directive modules."""

_directives = {}
"""Cache of imported directive functions."""

def directive(directive_name, language_module, document):
    """
    Locate and return a directive function from its language-dependent name.
    If not found in the current language, check English.  Return None if the
    named directive cannot be found.
    """
    normname = directive_name.lower()
    messages = []
    msg_text = []
    if _directives.has_key(normname):
        return _directives[normname], messages
    canonicalname = None
    try:
        canonicalname = language_module.directives[normname]
    except AttributeError, error:
        msg_text.append('Problem retrieving directive entry from language '
                        'module %r: %s.' % (language_module, error))
    except KeyError:
        msg_text.append('No directive entry for "%s" in module "%s".'
                        % (directive_name, language_module.__name__))
    if not canonicalname:
        try:
            canonicalname = _fallback_language_module.directives[normname]
            msg_text.append('Using English fallback for directive "%s".'
                            % directive_name)
        except KeyError:
            msg_text.append('Trying "%s" as canonical directive name.'
                            % directive_name)
            # The canonical name should be an English name, but just in case:
            canonicalname = normname
    if msg_text:
        message = document.reporter.info(
            '\n'.join(msg_text), line=document.current_line)
        messages.append(message)
    try:
        modulename, functionname = _directive_registry[canonicalname]
    except KeyError:
        messages.append(document.reporter.error(
            'Directive "%s" not registered (canonical name "%s").'
            % (directive_name, canonicalname), line=document.current_line))
        return None, messages
    if _modules.has_key(modulename):
        module = _modules[modulename]
    else:
        try:
            module = __import__(modulename, globals(), locals())
        except ImportError, detail:
            messages.append(document.reporter.error(
                'Error importing directive module "%s" (directive "%s"):\n%s'
                % (modulename, directive_name, detail),
                line=document.current_line))
            return None, messages
    try:
        function = getattr(module, functionname)
        _directives[normname] = function
    except AttributeError:
        messages.append(document.reporter.error(
            'No function "%s" in module "%s" (directive "%s").'
            % (functionname, modulename, directive_name),
            line=document.current_line))
        return None, messages
    return function, messages

def register_directive(name, directive_function):
    """
    Register a nonstandard application-defined directive function.
    Language lookups are not needed for such functions.
    """
    _directives[name] = directive_function

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.
    """
    if argument and argument.strip():
        raise ValueError('no argument is allowed; "%s" supplied' % argument)
    else:
        return None

def unchanged_required(argument):
    """
    Return the argument text, unchanged.
    (Directive option conversion function.)

    Raise ``ValueError`` if no argument is found.
    """
    if argument is None:
        raise ValueError('argument required but none supplied')
    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.
    """
    if argument is None:
        raise ValueError('argument required but none supplied')
    else:
        path = ''.join([s.strip() for s in argument.splitlines()])
        if path.find(' ') == -1:
            return path
        else:
            raise ValueError('path contains whitespace')

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')
    class_name = nodes.make_id(argument)
    if not class_name:
        raise ValueError('cannot make "%s" into a class name' % argument)
    return class_name

unicode_pattern = re.compile(
    r'(?:0x|x|\\x|U\+?|\\u)([0-9a-f]+)$|&#x([0-9a-f]+);$', re.IGNORECASE)

def unicode_code(code):
    r"""
    Convert a Unicode character code to a Unicode character.

    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;``).  Other text remains as-is.
    """
    try:
        if code.isdigit():                  # decimal number
            return unichr(int(code))
        else:
            match = unicode_pattern.match(code)
            if match:                       # hex number
                value = match.group(1) or match.group(2)
                return unichr(int(value, 16))
            else:                           # other text
                return code
    except OverflowError, detail:
        raise ValueError('code too large (%s)' % detail)


def single_char_or_unicode(argument):
    char = unicode_code(argument)
    if len(char) > 1:
        raise ValueError('%r invalid; must be a single character or '
                         'a Unicode code' % char)
    return char

def single_char_or_whitespace_or_unicode(argument):
    if argument == 'tab':
        char = '\t'
    elif argument == 'space':
        char = ' '
    else:
        char = single_char_or_unicode(argument)
    return char

def positive_int(argument):
    value = int(argument)
    if value < 1:
        raise ValueError('negative or zero value; must be positive')
    return value

def positive_int_list(argument):
    if ',' in argument:
        entries = argument.split(',')
    else:
        entries = argument.split()
    return [positive_int(entry) for entry in entries]

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:
        raise ValueError('must supply an argument; choose from %s'
                         % format_values(values))
    if value in values:
        return value
    else:
        raise ValueError('"%s" unknown; choose from %s'
                         % (argument, format_values(values)))


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/admonitions.py ===
# Author: David Goodger
# Contact: goodger at users.sourceforge.net
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
Admonition directives.
"""

__docformat__ = 'reStructuredText'


from docutils.parsers.rst import states, directives
from docutils import nodes


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 make_admonition(nodes.attention, *args)

attention.content = 1

def caution(*args):
    return make_admonition(nodes.caution, *args)

caution.content = 1

def danger(*args):
    return make_admonition(nodes.danger, *args)

danger.content = 1

def 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 make_admonition(nodes.important, *args)

important.content = 1

def note(*args):
    return make_admonition(nodes.note, *args)

note.content = 1

def tip(*args):
    return make_admonition(nodes.tip, *args)

tip.content = 1

def warning(*args):
    return make_admonition(nodes.warning, *args)

warning.content = 1


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/body.py ===
# Author: David Goodger
# Contact: goodger at python.org
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
Directives for additional body elements.

See `docutils.parsers.rst.directives` for API details.
"""

__docformat__ = 'reStructuredText'


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,
          node_class=nodes.topic):
    if not state_machine.match_titles:
        error = state_machine.reporter.error(
              '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:
        warning = state_machine.reporter.warning(
            'Content block expected for the "%s" directive; none found.'
            % name, nodes.literal_block(block_text, block_text),
            line=lineno)
        return [warning]
    title_text = arguments[0]
    textnodes, messages = state.inline_text(title_text, lineno)
    titles = [nodes.title(title_text, '', *textnodes)]
    # sidebar uses this code
    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)
    node = node_class(text, *(titles + messages))
    if options.has_key('class'):
        node.set_class(options['class'])
    if text:
        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):
    if not content:
        warning = state_machine.reporter.warning(
            'Content block expected for the "%s" directive; none found.'
            % name, nodes.literal_block(block_text, block_text), line=lineno)
        return [warning]
    text = '\n'.join(content)
    text_nodes, messages = state.inline_text(text, lineno)
    node = node_class(text, '', *text_nodes, **options)
    node.line = content_offset + 1
    return [node] + messages

line_block.options = {'class': directives.class_option}
line_block.content = 1

def parsed_literal(name, arguments, options, content, lineno,
                   content_offset, block_text, state, state_machine):
    return line_block(name, arguments, options, content, lineno,
                      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


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/html.py ===
# Author: David Goodger
# Contact: goodger at users.sourceforge.net
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
Directives for typically HTML-specific constructs.
"""

__docformat__ = 'reStructuredText'

import sys
from docutils import nodes, utils
from docutils.parsers.rst import states
from docutils.transforms import components


def meta(name, arguments, options, content, lineno,
         content_offset, block_text, state, state_machine):
    node = nodes.Element()
    if content:
        new_line_offset, blank_finish = state.nested_list_parse(
              content, content_offset, node, initial_state='MetaBody',
              blank_finish=1, state_machine_kwargs=metaSMkwargs)
        if (new_line_offset - content_offset) != len(content):
            # incomplete parse of block?
            error = state_machine.reporter.error(
                'Invalid meta directive.',
                nodes.literal_block(block_text, block_text), line=lineno)
            node += error
    else:
        error = state_machine.reporter.error(
            'Empty meta directive.',
            nodes.literal_block(block_text, block_text), line=lineno)
        node += error
    return node.get_children()

meta.content = 1

def imagemap(name, arguments, options, content, lineno,
             content_offset, block_text, state, state_machine):
    return []


class MetaBody(states.SpecializedBody):

    class meta(nodes.Special, nodes.PreBibliographic, nodes.Element):
        """HTML-specific "meta" element."""
        pass

    def field_marker(self, match, context, next_state):
        """Meta element."""
        node, blank_finish = self.parsemeta(match)
        self.parent += node
        return [], next_state, []

    def parsemeta(self, match):
        name = self.parse_field_marker(match)
        indented, indent, line_offset, blank_finish = \
              self.state_machine.get_first_known_indented(match.end())
        node = self.meta()
        pending = nodes.pending(components.Filter,
                                {'component': 'writer',
                                 'format': 'html',
                                 'nodes': [node]})
        node['content'] = ' '.join(indented)
        if not indented:
            line = self.state_machine.line
            msg = self.reporter.info(
                  'No content for meta tag "%s".' % name,
                  nodes.literal_block(line, line),
                  line=self.state_machine.abs_line_number())
            return msg, blank_finish
        tokens = name.split()
        try:
            attname, val = utils.extract_name_value(tokens[0])[0]
            node[attname.lower()] = val
        except utils.NameValueError:
            node['name'] = tokens[0]
        for token in tokens[1:]:
            try:
                attname, val = utils.extract_name_value(token)[0]
                node[attname.lower()] = val
            except utils.NameValueError, detail:
                line = self.state_machine.line
                msg = self.reporter.error(
                      'Error parsing meta tag attribute "%s": %s.'
                      % (token, detail), nodes.literal_block(line, line),
                      line=self.state_machine.abs_line_number())
                return msg, blank_finish
        self.document.note_pending(pending)
        return pending, blank_finish


metaSMkwargs = {'state_classes': (MetaBody,)}


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/images.py ===
# Author: David Goodger
# Contact: goodger at users.sourceforge.net
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
Directives for figures and simple images.
"""

__docformat__ = 'reStructuredText'


import sys
from docutils import nodes, utils
from docutils.parsers.rst import directives, states
from docutils.nodes import whitespace_normalize_name

try:
    import Image                        # PIL
except ImportError:
    Image = None

align_values = ('top', 'middle', 'bottom', 'left', 'center', 'right')

def align(argument):
    return directives.choice(argument, align_values)

def image(name, arguments, options, content, lineno,
          content_offset, block_text, state, state_machine):
    messages = []
    reference = ''.join(arguments[0].split('\n'))
    if reference.find(' ') != -1:
        error = state_machine.reporter.error(
              'Image URI contains whitespace.',
              nodes.literal_block(block_text, block_text), line=lineno)
        return [error]
    options['uri'] = reference
    reference_node = None
    if options.has_key('target'):
        block = states.escape2null(options['target']).splitlines()
        block = [line for line in block]
        target_type, data = state.parse_target(block, block_text, lineno)
        if target_type == 'refuri':
            reference_node = nodes.reference(refuri=data)
        elif target_type == 'refname':
            reference_node = nodes.reference(
                refname=data, name=whitespace_normalize_name(options['target']))
            state.document.note_refname(reference_node)
        else:                           # malformed target
            messages.append(data)       # data is a system message
        del options['target']
    image_node = nodes.image(block_text, **options)
    if reference_node:
        reference_node += image_node
        return messages + [reference_node]
    else:
        return messages + [image_node]

image.arguments = (1, 0, 1)
image.options = {'alt': directives.unchanged,
                 'height': directives.nonnegative_int,
                 'width': directives.nonnegative_int,
                 'scale': directives.nonnegative_int,
                 'align': align,
                 'target': directives.unchanged_required,
                 '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)
        first_node = node[0]
        if isinstance(first_node, nodes.paragraph):
            caption = nodes.caption(first_node.rawsource, '',
                                    *first_node.children)
            figure_node += caption
        elif not (isinstance(first_node, nodes.comment)
                  and len(first_node) == 0):
            error = state_machine.reporter.error(
                  'Figure caption must be a paragraph or empty comment.',
                  nodes.literal_block(block_text, block_text), line=lineno)
            return [figure_node, error]
        if len(node) > 1:
            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 = {'figwidth': figwidth_value,
                  'figclass': directives.class_option}
figure.options.update(image.options)
figure.content = 1


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/misc.py ===
# Authors: David Goodger, Dethe Elza
# Contact: goodger at users.sourceforge.net
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""Miscellaneous directives."""

__docformat__ = 'reStructuredText'

import sys
import os.path
import re
from docutils import io, nodes, statemachine, utils
from docutils.parsers.rst import directives, roles, states
from docutils.transforms import misc

try:
    import urllib2
except ImportError:
    urllib2 = None


def include(name, arguments, options, content, lineno,
            content_offset, block_text, state, state_machine):
    """Include a reST file as part of the content of this reST file."""
    source = state_machine.input_lines.source(
        lineno - state_machine.input_offset - 1)
    source_dir = os.path.dirname(os.path.abspath(source))
    path = ''.join(arguments[0].splitlines())
    if path.find(' ') != -1:
        error = state_machine.reporter.error(
              '"%s" directive path contains whitespace.' % name,
              nodes.literal_block(block_text, block_text), line=lineno)
        return [error]
    path = os.path.normpath(os.path.join(source_dir, path))
    path = utils.relative_path(None, path)
    try:
        include_file = io.FileInput(
            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: %s.'
              % (name, error.__class__.__name__, error),
              nodes.literal_block(block_text, block_text), line=lineno)
        return [severe]
    include_text = include_file.read()
    if options.has_key('literal'):
        literal_block = nodes.literal_block(include_text, include_text,
                                            source=path)
        literal_block.line = 1
        return literal_block
    else:
        include_lines = statemachine.string2lines(include_text,
                                                  convert_whitespace=1)
        state_machine.insert_input(include_lines, path)
        return []

include.arguments = (1, 0, 1)
include.options = {'literal': directives.flag}

def raw(name, arguments, options, content, lineno,
        content_offset, block_text, state, state_machine):
    """
    Pass through content unchanged

    Content is included in output based on type argument

    Content may be included inline (content section of directive) or
    imported from a file or url.
    """
    attributes = {'format': arguments[0]}
    if content:
        if options.has_key('file') or options.has_key('url'):
            error = state_machine.reporter.error(
                  '"%s" directive may not both specify an external file and '
                  'have content.' % name,
                  nodes.literal_block(block_text, block_text), line=lineno)
            return [error]
        text = '\n'.join(content)
    elif options.has_key('file'):
        if options.has_key('url'):
            error = state_machine.reporter.error(
                  'The "file" and "url" options may not be simultaneously '
                  'specified for the "%s" directive.' % name,
                  nodes.literal_block(block_text, block_text), line=lineno)
            return [error]
        source_dir = os.path.dirname(
            os.path.abspath(state.document.current_source))
        path = os.path.normpath(os.path.join(source_dir, options['file']))
        path = utils.relative_path(None, path)
        try:
            raw_file = open(path)
        except IOError, error:
            severe = state_machine.reporter.severe(
                  'Problems with "%s" directive path:\n%s.' % (name, error),
                  nodes.literal_block(block_text, block_text), line=lineno)
            return [severe]
        text = raw_file.read()
        raw_file.close()
        attributes['source'] = path
    elif options.has_key('url'):
        if not urllib2:
            severe = state_machine.reporter.severe(
                  'Problems with the "%s" directive and its "url" option: '
                  'unable to access the required functionality (from the '
                  '"urllib2" module).' % name,
                  nodes.literal_block(block_text, block_text), line=lineno)
            return [severe]
        try:
            raw_file = urllib2.urlopen(options['url'])
        except (urllib2.URLError, IOError, OSError), error:
            severe = state_machine.reporter.severe(
                  'Problems with "%s" directive URL "%s":\n%s.'
                  % (name, options['url'], error),
                  nodes.literal_block(block_text, block_text), line=lineno)
            return [severe]
        text = raw_file.read()
        raw_file.close()
        attributes['source'] = options['file']
    else:
        error = state_machine.reporter.warning(
            'The "%s" directive requires content; none supplied.' % (name),
            nodes.literal_block(block_text, block_text), line=lineno)
        return [error]
    raw_node = nodes.raw('', text, **attributes)
    return [raw_node]

raw.arguments = (1, 0, 1)
raw.options = {'file': directives.path,
               'url': directives.path}
raw.content = 1

def replace(name, arguments, options, content, lineno,
            content_offset, block_text, state, state_machine):
    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]
    text = '\n'.join(content)
    element = nodes.Element(text)
    if text:
        state.nested_parse(content, content_offset, element)
        if len(element) != 1 or not isinstance(element[0], nodes.paragraph):
            messages = []
            for node in element:
                if isinstance(node, nodes.system_message):
                    if node.has_key('backrefs'):
                        del node['backrefs']
                    messages.append(node)
            error = state_machine.reporter.error(
                'Error in "%s" directive: may contain a single paragraph '
                'only.' % (name), line=lineno)
            messages.append(error)
            return messages
        else:
            return element[0].children
    else:
        error = state_machine.reporter.error(
            'The "%s" directive is empty; content required.' % (name),
            line=lineno)
        return [error]

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 = unicode_comment_pattern.split(arguments[0])[0].split()
    element = nodes.Element()
    for code in codes:
        try:
            decoded = directives.unicode_code(code)
        except ValueError, err:
            error = state_machine.reporter.error(
                'Invalid character code: %s\n%s: %s'
                % (code, err.__class__.__name__, err),
                nodes.literal_block(block_text, block_text), line=lineno)
            return [error]
        element += nodes.Text(decoded)
    return element.children

unicode_directive.arguments = (1, 0, 1)
unicode_comment_pattern = re.compile(r'( |\n|^)\.\. ')

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

role_arg_pat = re.compile(r'(%s)\s*(\(\s*(%s)\s*\)\s*)?$'
                          % ((states.Inliner.simplename,) * 2))
def role(name, arguments, options, content, lineno,
         content_offset, block_text, state, state_machine):
    """Dynamically create and register a custom interpreted text role."""
    if content_offset > lineno or not content:
        error = state_machine.reporter.error(
            '"%s" directive requires arguments on the first line.'
            % name, nodes.literal_block(block_text, block_text), line=lineno)
        return [error]
    args = content[0]
    match = role_arg_pat.match(args)
    if not match:
        error = state_machine.reporter.error(
            '"%s" directive arguments not valid role names: "%s".'
            % (name, args), nodes.literal_block(block_text, block_text),
            line=lineno)
        return [error]
    new_role_name = match.group(1)
    base_role_name = match.group(3)
    messages = []
    if base_role_name:
        base_role, messages = roles.role(
            base_role_name, state_machine.language, lineno, state.reporter)
        if base_role is None:
            error = state.reporter.error(
                'Unknown interpreted text role "%s".' % base_role_name,
                nodes.literal_block(block_text, block_text), line=lineno)
            return messages + [error]
    else:
        base_role = roles.generic_custom_role
    assert not hasattr(base_role, 'arguments'), (
        'Supplemental directive arguments for "%s" directive not supported'
        '(specified by "%r" role).' % (name, base_role))
    try:
        (arguments, options, content, content_offset) = (
            state.parse_directive_block(content[1:], content_offset, base_role,
                                        option_presets={}))
    except states.MarkupError, detail:
        error = state_machine.reporter.error(
            'Error in "%s" directive:\n%s.' % (name, detail),
            nodes.literal_block(block_text, block_text), line=lineno)
        return messages + [error]
    if not options.has_key('class'):
        try:
            options['class'] = directives.class_option(new_role_name)
        except ValueError, detail:
            error = state_machine.reporter.error(
                'Invalid argument for "%s" directive:\n%s.'
                % (name, detail),
                nodes.literal_block(block_text, block_text), line=lineno)
            return messages + [error]
    role = roles.CustomRole(new_role_name, base_role, options, content)
    roles.register_local_role(new_role_name, role)
    return messages

role.content = 1

def directive_test_function(name, arguments, options, content, lineno,
                            content_offset, block_text, state, state_machine):
    """This directive is useful only for testing purposes."""
    if content:
        text = '\n'.join(content)
        info = state_machine.reporter.info(
            'Directive processed. Type="%s", arguments=%r, options=%r, '
            'content:' % (name, arguments, options),
            nodes.literal_block(text, text), line=lineno)
    else:
        info = state_machine.reporter.info(
            'Directive processed. Type="%s", arguments=%r, options=%r, '
            'content: None' % (name, arguments, options), line=lineno)
    return [info]

directive_test_function.arguments = (0, 1, 1)
directive_test_function.options = {'option': directives.unchanged_required}
directive_test_function.content = 1


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/parts.py ===
# Author: David Goodger, Dmitry Jemerov
# Contact: goodger at users.sourceforge.net
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
Directives for document parts.
"""

__docformat__ = 'reStructuredText'

from docutils import nodes, languages
from docutils.transforms import parts
from docutils.parsers.rst import directives


backlinks_values = ('top', 'entry', 'none')

def backlinks(arg):
    value = directives.choice(arg, backlinks_values)
    if value == 'none':
        return None
    else:
        return value

def contents(name, arguments, options, content, lineno,
             content_offset, block_text, state, state_machine):
    """Table of contents."""
    document = state_machine.document
    language = languages.get_language(document.settings.language_code)

    if arguments:
        title_text = arguments[0]
        text_nodes, messages = state.inline_text(title_text, lineno)
        title = nodes.title(title_text, '', *text_nodes)
    else:
        messages = []
        if options.has_key('local'):
            title = None
        else:
            title = nodes.title('', language.labels['contents'])

    topic = nodes.topic(CLASS='contents')

    cls = options.get('class')
    if cls:
        topic.set_class(cls)

    if title:
        name = title.astext()
        topic += title
    else:
        name = language.labels['contents']

    name = nodes.fully_normalize_name(name)
    if not document.has_name(name):
        topic['name'] = name
    document.note_implicit_target(topic)

    pending = nodes.pending(parts.Contents, rawsource=block_text)
    pending.details.update(options)
    document.note_pending(pending)
    topic += pending
    return [topic] + messages

contents.arguments = (0, 1, 1)
contents.options = {'depth': directives.nonnegative_int,
                    'local': directives.flag,
                    'backlinks': backlinks,
                    'class': directives.class_option}

def sectnum(name, arguments, options, content, lineno,
            content_offset, block_text, state, state_machine):
    """Automatic section numbering."""
    pending = nodes.pending(parts.SectNum)
    pending.details.update(options)
    state_machine.document.note_pending(pending)
    return [pending]

sectnum.options = {'depth': int}


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/references.py ===
# Author: David Goodger, Dmitry Jemerov
# Contact: goodger at users.sourceforge.net
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
Directives for references and targets.
"""

__docformat__ = 'reStructuredText'

from docutils import nodes
from docutils.transforms import references


def target_notes(name, arguments, options, content, lineno,
                 content_offset, block_text, state, state_machine):
    """Target footnote generation."""
    pending = nodes.pending(references.TargetNotes)
    state_machine.document.note_pending(pending)
    nodelist = [pending]
    return nodelist


=== Added File Zope/lib/python/third_party/docutils/docutils/parsers/rst/directives/tables.py ===
# Authors: David Goodger, David Priest
# Contact: goodger at python.org
# Revision: $Revision: 1.1.4.1 $
# Date: $Date: 2004/10/29 19:08:22 $
# Copyright: This module has been placed in the public domain.

"""
Directives for table elements.
"""

__docformat__ = 'reStructuredText'


import sys
import os.path
from docutils import nodes, statemachine, utils
from docutils.utils import SystemMessagePropagation
from docutils.parsers.rst import directives

try:
    import csv                          # new in Python 2.3
except ImportError:
    csv = None

try:
    import urllib2
except ImportError:
    urllib2 = None

try:
    True
except NameError:                       # Python 2.2 & 2.1 compatibility
    True = not 0
    False = not 1


def table(name, arguments, options, content, lineno,
          content_offset, block_text, state, state_machine):
    if not content:
        warning = state_machine.reporter.warning(
            'Content block expected for the "%s" directive; none found.'
            % name, nodes.literal_block(block_text, block_text),
            line=lineno)
        return [warning]
    title, messages = make_title(arguments, state, lineno)
    node = nodes.Element()          # anonymous container for parsing
    text = '\n'.join(content)
    state.nested_parse(content, content_offset, node)
    if len(node) != 1 or not isinstance(node[0], nodes.table):
        error = state_machine.reporter.error(
            'Error parsing content block for the "%s" directive: '
            'exactly one table expected.'
            % name, nodes.literal_block(block_text, block_text),
            line=lineno)
        return [error]
    table_node = node[0]
    if options.has_key('class'):
        table_node.set_class(options['class'])
    if title:
        table_node.insert(0, title)
    return [table_node] + messages

table.arguments = (0, 1, 1)
table.options = {'class': directives.class_option}
table.content = 1

def make_title(arguments, state, lineno):
    if arguments:
        title_text = arguments[0]
        text_nodes, messages = state.inline_text(title_text, lineno)
        title = nodes.title(title_text, '', *text_nodes)
    else:
        title = None
        messages = []
    return title, messages


if csv:
    class DocutilsDialect(csv.Dialect):

        """CSV dialect for `csv_table` directive function."""

        delimiter = ','
        quotechar = '"'
        doublequote = True
        skipinitialspace = True
        lineterminator = '\n'
        quoting = csv.QUOTE_MINIMAL

        def __init__(self, options):
            if options.has_key('delim'):
                self.delimiter = str(options['delim'])
            if options.has_key('keepspace'):
                self.skipinitialspace = False
            if options.has_key('quote'):
                self.quotechar = str(options['quote'])
            if options.has_key('escape'):
                self.doublequote = False
                self.escapechar = str(options['escape'])
            csv.Dialect.__init__(self)


    class HeaderDialect(csv.Dialect):

        """CSV dialect to use for the "header" option data."""

        delimiter = ','
        quotechar = '"'
        escapechar = '\\'
        doublequote = False
        skipinitialspace = True
        lineterminator = '\n'
        quoting = csv.QUOTE_MINIMAL


def csv_table(name, arguments, options, content, lineno,
             content_offset, block_text, state, state_machine):
    try:
        check_requirements(name, lineno, block_text, state_machine)
        title, messages = make_title(arguments, state, lineno)
        csv_data, source = get_csv_data(
            name, options, content, lineno, block_text, state, state_machine)
        table_head, max_header_cols = process_header_option(
            options, state_machine, lineno)
        rows, max_cols = parse_csv_data_into_rows(
            csv_data, DocutilsDialect(options), source, options)
        max_cols = max(max_cols, max_header_cols)
        header_rows = options.get('header-rows', 0) # default 0
        check_table_dimensions(
            rows, header_rows, name, lineno, block_text, state_machine)
        table_head.extend(rows[:header_rows])
        table_body = rows[header_rows:]
        col_widths = get_column_widths(
            max_cols, name, options, lineno, block_text, state_machine)
        extend_short_rows_with_empty_cells(max_cols, (table_head, table_body))
    except SystemMessagePropagation, detail:
        return [detail.args[0]]
    except csv.Error, detail:
        error = state_machine.reporter.error(
            'Error with CSV data in "%s" directive:\n%s' % (name, detail),
            nodes.literal_block(block_text, block_text), line=lineno)
        return [error]
    table = (col_widths, table_head, table_body)
    table_node = state.build_table(table, content_offset)
    if options.has_key('class'):
        table_node.set_class(options['class'])
    if title:
        table_node.insert(0, title)
    return [table_node] + messages

csv_table.arguments = (0, 1, 1)
csv_table.options = {'header-rows': directives.nonnegative_int,
                     'header': directives.unchanged,
                     'widths': directives.positive_int_list,
                     'file': directives.path,
                     'url': directives.path,
                     'class': directives.class_option,
                     # field delimiter char
                     'delim': directives.single_char_or_whitespace_or_unicode,
                     # treat whitespace after delimiter as significant
                     'keepspace': directives.flag,
                     # text field quote/unquote char:
                     'quote': directives.single_char_or_unicode,
                     # char used to escape delim & quote as-needed:
                     'escape': directives.single_char_or_unicode,}
csv_table.content = 1

def check_requirements(name, lineno, block_text, state_machine):
    if not csv:
        error = state_machine.reporter.error(
            'The "%s" directive is not compatible with this version of '
            'Python (%s).  Requires the "csv" module, new in Python 2.3.'
            % (name, sys.version.split()[0]),
            nodes.literal_block(block_text, block_text), line=lineno)
        raise SystemMessagePropagation(error)

def get_csv_data(name, options, content, lineno, block_text,
                 state, state_machine):
    """
    CSV data can come from the directive content, from an external file, or
    from a URL reference.
    """
    if content:                         # CSV data is from directive content
        if options.has_key('file') or options.has_key('url'):
            error = state_machine.reporter.error(
                  '"%s" directive may not both specify an external file and '
                  'have content.' % name,
                  nodes.literal_block(block_text, block_text), line=lineno)
            raise SystemMessagePropagation(error)
        source = content.source(0)
        csv_data = content
    elif options.has_key('file'):       # CSV data is from an external file
        if options.has_key('url'):
            error = state_machine.reporter.error(
                  'The "file" and "url" options may not be simultaneously '
                  'specified for the "%s" directive.' % name,
                  nodes.literal_block(block_text, block_text), line=lineno)
            raise SystemMessagePropagation(error)
        source_dir = os.path.dirname(
            os.path.abspath(state.document.current_source))
        source = os.path.normpath(os.path.join(source_dir, options['file']))
        source = utils.relative_path(None, source)
        try:
            csv_file = open(source, 'rb')
            try:
                csv_data = csv_file.read().splitlines()
            finally:
                csv_file.close()
        except IOError, error:
            severe = state_machine.reporter.severe(
                  'Problems with "%s" directive path:\n%s.' % (name, error),
                  nodes.literal_block(block_text, block_text), line=lineno)
            raise SystemMessagePropagation(severe)
    elif options.has_key('url'):        # CSV data is from a URL
        if not urllib2:
            severe = state_machine.reporter.severe(
                  'Problems with the "%s" directive and its "url" option: '
                  'unable to access the required functionality (from the '
                  '"urllib2" module).' % name,
                  nodes.literal_block(block_text, block_text), line=lineno)
            raise SystemMessagePropagation(severe)
        source = options['url']
        try:
            csv_data = urllib2.urlopen(source).read().splitlines()
        except (urllib2.URLError, IOError, OSError, ValueError), error:
            severe = state_machine.reporter.severe(
                  'Problems with "%s" directive URL "%s":\n%s.'
                  % (name, options['url'], error),
                  nodes.literal_block(block_text, block_text), line=lineno)
            raise SystemMessagePropagation(severe)
    else:
        error = state_machine.reporter.warning(
            'The "%s" directive requires content; none supplied.' % (name),
            nodes.literal_block(block_text, block_text), line=lineno)
        raise SystemMessagePropagation(error)
    return csv_data, source

def process_header_option(options, state_machine, lineno):
    source = state_machine.get_source(lineno - 1)
    table_head = []
    max_header_cols = 0
    if options.has_key('header'):       # separate table header in option
        rows, max_header_cols = parse_csv_data_into_rows(
            options['header'].split('\n'), HeaderDialect(), source, options)
        table_head.extend(rows)
    return table_head, max_header_cols

def parse_csv_data_into_rows(csv_data, dialect, source, options):
    csv_reader = csv.reader(csv_data, dialect=dialect)
    rows = []
    max_cols = 0
    for row in csv_reader:
        row_data = []
        for cell in row:
            cell_data = (0, 0, 0, statemachine.StringList(cell.splitlines(),
                                                          source=source))
            row_data.append(cell_data)
        rows.append(row_data)
        max_cols = max(max_cols, len(row))
    return rows, max_cols

def check_table_dimensions(rows, header_rows, name, lineno, block_text,
                           state_machine):
    if len(rows) < header_rows:
        error = state_machine.reporter.error(
            '%s header row(s) specified but only %s row(s) of data supplied '
            '("%s" directive).' % (header_rows, len(rows), name),
            nodes.literal_block(block_text, block_text), line=lineno)
        raise SystemMessagePropagation(error)
    elif len(rows) == header_rows > 0:
        error = state_machine.reporter.error(
            'Insufficient data supplied (%s row(s)); no data remaining for '
            'table body, required by "%s" directive.' % (len(rows), name),
            nodes.literal_block(block_text, block_text), line=lineno)
        raise SystemMessagePropagation(error)

def get_column_widths(max_cols, name, options, lineno, block_text,
                      state_machine):
    if options.has_key('widths'):
        col_widths = options['widths']
        if len(col_widths) != max_cols:
            error = state_machine.reporter.error(
              '"%s" widths do not match the number of columns in table (%s).'
              % (name, max_cols),
              nodes.literal_block(block_text, block_text), line=lineno)
            raise SystemMessagePropagation(error)
    else:
        col_widths = [100 / max_cols] * max_cols
    return col_widths

def extend_short_rows_with_empty_cells(columns, parts):
    for part in parts:
        for row in part:
            if len(row) < columns:
                row.extend([(0, 0, 0, [])] * (columns - len(row)))



More information about the Zope-Checkins mailing list