[Python-checkins] python/nondist/peps/docutils/parsers/rst/directives .cvsignore,NONE,1.1 __init__.py,NONE,1.1 admonitions.py,NONE,1.1 body.py,NONE,1.1 html.py,NONE,1.1 images.py,NONE,1.1 misc.py,NONE,1.1 parts.py,NONE,1.1 references.py,NONE,1.1

goodger@users.sourceforge.net goodger@users.sourceforge.net
Fri, 08 Nov 2002 15:47:54 -0800


Update of /cvsroot/python/python/nondist/peps/docutils/parsers/rst/directives
In directory usw-pr-cvs1:/tmp/cvs-serv8387/docutils/parsers/rst/directives

Added Files:
	.cvsignore __init__.py admonitions.py body.py html.py 
	images.py misc.py parts.py references.py 
Log Message:
local copy of Docutils for PEP processing

--- NEW FILE: .cvsignore ---
*.pyc

--- NEW FILE: __init__.py ---
# Author: David Goodger
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# 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.

- ``arguments`` is a list of positional arguments.

- ``options`` is a dictionary mapping option names to values.

- ``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.

- ``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/spec/howto/rst-directives.html
"""

__docformat__ = 'reStructuredText'

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'),
      'topic': ('body', 'topic'),
      'line-block': ('body', 'line_block'),
      'parsed-literal': ('body', 'parsed_literal'),
      #'questions': ('body', 'question_list'),
      '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'),
      '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.
    """
    normname = directive_name.lower()
    messages = []
    if _directives.has_key(normname):
        return _directives[normname], messages
    try:
        canonicalname = language_module.directives[normname]
    except (KeyError, AttributeError):
        msg_text = ('No directive entry for "%s" in module "%s".'
                    % (directive_name, language_module.__name__))
        try:
            canonicalname = _fallback_language_module.directives[normname]
            msg_text += ('\nUsing English fallback for directive "%s".'
                         % directive_name)
        except KeyError:
            msg_text += ('\nTrying "%s" as canonical directive name.'
                         % directive_name)
            # The canonical name should be an English name, but just in case:
            canonicalname = normname
        warning = document.reporter.warning(
            msg_text, line=document.current_line)
        messages.append(warning)
    try:
        modulename, functionname = _directive_registry[canonicalname]
    except KeyError:
        return None, messages
    if _modules.has_key(modulename):
        module = _modules[modulename]
    else:
        try:
            module = __import__(modulename, globals(), locals())
        except ImportError:
            return None, messages
    try:
        function = getattr(module, functionname)
        _directives[normname] = function
    except AttributeError:
        return None, messages
    return function, messages

def flag(argument):
    """
    Check for a valid flag option (no argument) and return ``None``.

    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(argument):
    """
    Return the argument, unchanged.

    Raise ``ValueError`` if no argument is found.
    """
    if argument is None:
        raise ValueError('argument required but none supplied')
    else:
        return argument  # unchanged!

def path(argument):
    """
    Return the path argument unwrapped (with newlines removed).

    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.
    """
    value = int(argument)
    if value < 0:
        raise ValueError('negative value; must be positive or zero')
    return value

def format_values(values):
    return '%s, or "%s"' % (', '.join(['"%s"' % s for s in values[:-1]]),
                            values[-1])

def choice(argument, values):
    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)))

--- NEW FILE: admonitions.py ---
# Author: David Goodger
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# Copyright: This module has been placed in the public domain.

"""
Admonition directives.
"""

__docformat__ = 'reStructuredText'


from docutils.parsers.rst import states
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:
        error = state_machine.reporter.error(
            'The "%s" admonition is empty; content required.' % (name),
            nodes.literal_block(block_text, block_text), line=lineno)
        return [error]

def attention(*args):
    return admonition(nodes.attention, *args)

attention.content = 1

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

caution.content = 1

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

danger.content = 1

def error(*args):
    return admonition(nodes.error, *args)

error.content = 1

def important(*args):
    return admonition(nodes.important, *args)

important.content = 1

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

note.content = 1

def tip(*args):
    return 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)

warning.content = 1

--- NEW FILE: body.py ---
# Author: David Goodger
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# Copyright: This module has been placed in the public domain.

"""
Directives for additional body elements.
"""

__docformat__ = 'reStructuredText'


import sys
from docutils import nodes


def topic(name, arguments, options, content, lineno,
          content_offset, block_text, state, state_machine):
    if not state_machine.match_titles:
        error = state_machine.reporter.error(
              'Topics may not be nested within topics or body elements.',
              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)
    title = nodes.title(title_text, '', *textnodes)
    text = '\n'.join(content)
    topic_node = nodes.topic(text, title, *messages)
    if text:
        state.nested_parse(content, content_offset, topic_node)
    return [topic_node]

topic.arguments = (1, 0, 1)
topic.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)
    return [node] + messages

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.content = 1

--- NEW FILE: html.py ---
# Author: David Goodger
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# 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,)}

--- NEW FILE: images.py ---
# Author: David Goodger
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# 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


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):
    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
    image_node = nodes.image(block_text, **options)
    return [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}

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

figure.arguments = (1, 0, 1)
figure.options = image.options
figure.content = 1

--- NEW FILE: misc.py ---
# Authors: David Goodger, Dethe Elza
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# Copyright: This module has been placed in the public domain.

"""Miscellaneous directives."""

__docformat__ = 'reStructuredText'

import sys
import os.path
from urllib2 import urlopen, URLError
from docutils import nodes, statemachine, utils
from docutils.parsers.rst import directives, states


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_dir = os.path.dirname(
        os.path.abspath(state.document.current_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 = 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]
    include_text = include_file.read()
    include_file.close()
    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'):
        try:
            raw_file = urlopen(options['url'])
        except (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 directive_test_function(name, arguments, options, content, lineno,
                            content_offset, block_text, state, state_machine):
    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}
directive_test_function.content = 1

--- NEW FILE: parts.py ---
# Author: David Goodger, Dmitry Jemerov
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# Copyright: This module has been placed in the public domain.

"""
Directives for document parts.
"""

__docformat__ = 'reStructuredText'

from docutils import nodes
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."""
    if arguments:
        title_text = arguments[0]
        text_nodes, messages = state.inline_text(title_text, lineno)
        title = nodes.title(title_text, '', *text_nodes)
    else:
        messages = []
        title = None
    pending = nodes.pending(parts.Contents, {'title': title}, block_text)
    pending.details.update(options)
    state_machine.document.note_pending(pending)
    return [pending] + messages

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

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}

--- NEW FILE: references.py ---
# Author: David Goodger, Dmitry Jemerov
# Contact: goodger@users.sourceforge.net
# Revision: $Revision: 1.1 $
# Date: $Date: 2002/11/08 23:47:52 $
# 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