')
if node.hasattr('backrefs'):
backrefs = node['backrefs']
if len(backrefs) == 1:
- self.body.append('%s '
- '(level %s system message)
\n'
+ self.body.append('%s '
+ '(level %s system message)\n'
% (backrefs[0], node['type'], node['level']))
else:
i = 1
backlinks = []
for backref in backrefs:
- backlinks.append('%s' % (backref, i))
+ backlinks.append('%s' % (backref, i))
i += 1
- self.body.append('%s (%s; level %s system message)\n'
+ self.body.append('%s (%s; level %s system message)\n'
% (node['type'], '|'.join(backlinks),
node['level']))
else:
- self.body.append('%s (level %s system message)\n'
+ self.body.append('%s (level %s system message)\n'
% (node['type'], node['level']))
def depart_system_message(self, node):
- self.body.append('\n')
+ self.body.append('\n')
def visit_table(self, node):
self.body.append(
self.starttag(node, 'table', frame='border', rules='all'))
def depart_table(self, node):
- self.body.append('\n')
+ self.body.append('\n')
def visit_target(self, node):
if not (node.has_key('refuri') or node.has_key('refid')
or node.has_key('refname')):
self.body.append(self.starttag(node, 'a', '', CLASS='target'))
- self.context.append('')
+ self.context.append('')
else:
self.context.append('')
@@ -668,11 +689,11 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append(self.context.pop())
def visit_tbody(self, node):
- self.body.append(self.context.pop()) # '\n' or ''
+ self.body.append(self.context.pop()) # '\n' or ''
self.body.append(self.starttag(node, 'tbody', valign='top'))
def depart_tbody(self, node):
- self.body.append('\n')
+ self.body.append('\n')
def visit_term(self, node):
self.body.append(self.starttag(node, 'dt', ''))
@@ -686,18 +707,18 @@ class HTMLTranslator(nodes.NodeVisitor):
def visit_tgroup(self, node):
self.body.append(self.starttag(node, 'colgroup'))
- self.context.append('\n')
+ self.context.append('\n')
def depart_tgroup(self, node):
pass
def visit_thead(self, node):
- self.body.append(self.context.pop()) # '\n'
+ self.body.append(self.context.pop()) # '\n'
self.context.append('')
self.body.append(self.starttag(node, 'thead', valign='bottom'))
def depart_thead(self, node):
- self.body.append('\n')
+ self.body.append('\n')
def visit_tip(self, node):
self.visit_admonition(node, 'tip')
@@ -709,21 +730,21 @@ class HTMLTranslator(nodes.NodeVisitor):
"""Only 6 section levels are supported by HTML."""
if isinstance(node.parent, nodes.topic):
self.body.append(
- self.starttag(node, 'P', '', CLASS='topic-title'))
- self.context.append('\n')
+ self.starttag(node, 'p', '', CLASS='topic-title'))
+ self.context.append('\n')
elif self.sectionlevel == 0:
- self.head.append('%s\n'
+ self.head.append('%s\n'
% self.encode(node.astext()))
- self.body.append(self.starttag(node, 'H1', '', CLASS='title'))
- self.context.append('\n')
+ self.body.append(self.starttag(node, 'h1', '', CLASS='title'))
+ self.context.append('\n')
else:
self.body.append(
- self.starttag(node, 'H%s' % self.sectionlevel, ''))
+ self.starttag(node, 'h%s' % self.sectionlevel, ''))
context = ''
if node.hasattr('refid'):
- self.body.append('' % node['refid'])
- context = ''
- self.context.append('%s\n' % (context, self.sectionlevel))
+ self.body.append('' % node['refid'])
+ context = ''
+ self.context.append('%s\n' % (context, self.sectionlevel))
def depart_title(self, node):
self.body.append(self.context.pop())
@@ -733,11 +754,11 @@ class HTMLTranslator(nodes.NodeVisitor):
self.topic_class = node.get('class')
def depart_topic(self, node):
- self.body.append('\n')
+ self.body.append('\n')
self.topic_class = ''
def visit_transition(self, node):
- self.body.append(self.starttag(node, 'hr'))
+ self.body.append(self.emptytag(node, 'hr'))
def depart_transition(self, node):
pass
--
cgit v1.2.1
From 54237d053858226234c32fdd8a3faa00e2a849df Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 14:47:14 +0000
Subject: - Added ``ApplicationError`` and ``DataError``, for use throughout
the package. - Added ``Component`` base class for Docutils components;
implements the ``supports`` method.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@69 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index 0ee88d94a..e70a33167 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -49,3 +49,20 @@ Subpackages:
"""
__docformat__ = 'reStructuredText'
+
+
+class ApplicationError(StandardError): pass
+class DataError(ApplicationError): pass
+
+
+class Component:
+
+ """
+ Base class for Docutils components.
+ """
+
+ names = ()
+ """Names for this component. Override in subclasses."""
+
+ def supports(self, format):
+ return format in self.supported
--
cgit v1.2.1
From a99117d36a613c76c4cea42c04f29d3cb41c1ad2 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 14:49:10 +0000
Subject: - Added ``TreeCopyVisitor`` class. - Added a ``copy`` method to
``Node`` and subclasses. - Added a ``SkipDeparture`` exception for
visitors.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@70 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 163 ++++++++++++++++++++++++++++++++++++------------------
1 file changed, 110 insertions(+), 53 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index ece182c85..803fbc82e 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -16,7 +16,7 @@ element classes.
Classes in lower_case_with_underscores are element classes, matching the XML
element generic identifiers in the DTD_.
-.. _DTD: http://docstring.sourceforge.net/spec/gpdi.dtd
+.. _DTD: http://docutils.sourceforge.net/spec/docutils.dtd
"""
import sys, os
@@ -50,6 +50,10 @@ class Node:
"""Return an indented pseudo-XML representation, for test purposes."""
raise NotImplementedError
+ def copy(self):
+ """Return a copy of self."""
+ raise NotImplementedError
+
def walk(self, visitor):
"""
Traverse a tree of `Node` objects, calling ``visit_...`` methods of
@@ -65,16 +69,18 @@ class Node:
"""
name = 'visit_' + self.__class__.__name__
method = getattr(visitor, name, visitor.unknown_visit)
- visitor.doctree.reporter.debug(name, category='nodes.Node.walk')
+ visitor.document.reporter.debug(name, category='nodes.Node.walk')
try:
method(self)
- children = self.getchildren()
- try:
- for i in range(len(children)):
- children[i].walk(visitor)
- except SkipSiblings:
- pass
except (SkipChildren, SkipNode):
+ return
+ except SkipDeparture: # not applicable; ignore
+ pass
+ children = self.getchildren()
+ try:
+ for i in range(len(children)):
+ children[i].walk(visitor)
+ except SkipSiblings:
pass
def walkabout(self, visitor):
@@ -87,11 +93,17 @@ class Node:
Parameter `visitor`: A `NodeVisitor` object, containing ``visit_...``
and ``depart_...`` methods for each `Node` subclass encountered.
"""
+ call_depart = 1
name = 'visit_' + self.__class__.__name__
method = getattr(visitor, name, visitor.unknown_visit)
- visitor.doctree.reporter.debug(name, category='nodes.Node.walkabout')
+ visitor.document.reporter.debug(name, category='nodes.Node.walkabout')
try:
- method(self)
+ try:
+ method(self)
+ except SkipNode:
+ return
+ except SkipDeparture:
+ call_depart = 0
children = self.getchildren()
try:
for i in range(len(children)):
@@ -100,12 +112,12 @@ class Node:
pass
except SkipChildren:
pass
- except SkipNode:
- return
- name = 'depart_' + self.__class__.__name__
- method = getattr(visitor, name, visitor.unknown_departure)
- visitor.doctree.reporter.debug(name, category='nodes.Node.walkabout')
- method(self)
+ if call_depart:
+ name = 'depart_' + self.__class__.__name__
+ method = getattr(visitor, name, visitor.unknown_departure)
+ visitor.document.reporter.debug(
+ name, category='nodes.Node.walkabout')
+ method(self)
class Text(Node, MutableString):
@@ -133,6 +145,9 @@ class Text(Node, MutableString):
def astext(self):
return self.data
+ def copy(self):
+ return self.__class__(self.data)
+
def pformat(self, indent=' ', level=0):
result = []
indent = indent * level
@@ -186,7 +201,7 @@ class Element(Node):
self.children = []
"""List of child nodes (elements and/or `Text`)."""
- self.extend(children) # extend self.children w/ attributes
+ self.extend(children) # maintain parent info
self.attributes = {}
"""Dictionary of attribute {name: value}."""
@@ -425,6 +440,9 @@ class Element(Node):
"""Return this element's children."""
return self.children
+ def copy(self):
+ return self.__class__(**self.attributes)
+
class TextElement(Element):
@@ -489,11 +507,11 @@ class Admonition(Body): pass
class Special(Body):
- """Special internal body elements, not true document components."""
+ """Special internal body elements."""
pass
-class Component: pass
+class Part: pass
class Inline: pass
@@ -513,13 +531,13 @@ class Targetable(Resolvable):
class document(Root, Structural, Element):
- def __init__(self, reporter, languagecode, *args, **kwargs):
+ def __init__(self, reporter, language_code, *args, **kwargs):
Element.__init__(self, *args, **kwargs)
self.reporter = reporter
"""System message generator."""
- self.languagecode = languagecode
+ self.language_code = language_code
"""ISO 639 2-letter language identifier."""
self.explicit_targets = {}
@@ -763,6 +781,10 @@ class document(Root, Structural, Element):
def note_pending(self, pending):
self.pending.append(pending)
+ def copy(self):
+ return self.__class__(self.reporter, self.language_code,
+ **self.attributes)
+
# ================
# Title Elements
@@ -820,31 +842,31 @@ class transition(Structural, Element): pass
class paragraph(General, TextElement): pass
class bullet_list(Sequential, Element): pass
class enumerated_list(Sequential, Element): pass
-class list_item(Component, Element): pass
+class list_item(Part, Element): pass
class definition_list(Sequential, Element): pass
-class definition_list_item(Component, Element): pass
-class term(Component, TextElement): pass
-class classifier(Component, TextElement): pass
-class definition(Component, Element): pass
+class definition_list_item(Part, Element): pass
+class term(Part, TextElement): pass
+class classifier(Part, TextElement): pass
+class definition(Part, Element): pass
class field_list(Sequential, Element): pass
-class field(Component, Element): pass
-class field_name(Component, TextElement): pass
-class field_argument(Component, TextElement): pass
-class field_body(Component, Element): pass
+class field(Part, Element): pass
+class field_name(Part, TextElement): pass
+class field_argument(Part, TextElement): pass
+class field_body(Part, Element): pass
-class option(Component, Element):
+class option(Part, Element):
child_text_separator = ''
-class option_argument(Component, TextElement):
+class option_argument(Part, TextElement):
def astext(self):
return self.get('delimiter', ' ') + TextElement.astext(self)
-class option_group(Component, Element):
+class option_group(Part, Element):
child_text_separator = ', '
@@ -852,13 +874,13 @@ class option_group(Component, Element):
class option_list(Sequential, Element): pass
-class option_list_item(Component, Element):
+class option_list_item(Part, Element):
child_text_separator = ' '
-class option_string(Component, TextElement): pass
-class description(Component, Element): pass
+class option_string(Part, TextElement): pass
+class description(Part, Element): pass
class literal_block(General, TextElement): pass
class block_quote(General, Element): pass
class doctest_block(General, TextElement): pass
@@ -876,17 +898,17 @@ class substitution_definition(Special, TextElement): pass
class target(Special, Inline, TextElement, Targetable): pass
class footnote(General, Element, BackLinkable): pass
class citation(General, Element, BackLinkable): pass
-class label(Component, TextElement): pass
+class label(Part, TextElement): pass
class figure(General, Element): pass
-class caption(Component, TextElement): pass
-class legend(Component, Element): pass
+class caption(Part, TextElement): pass
+class legend(Part, Element): pass
class table(General, Element): pass
-class tgroup(Component, Element): pass
-class colspec(Component, Element): pass
-class thead(Component, Element): pass
-class tbody(Component, Element): pass
-class row(Component, Element): pass
-class entry(Component, Element): pass
+class tgroup(Part, Element): pass
+class colspec(Part, Element): pass
+class thead(Part, Element): pass
+class tbody(Part, Element): pass
+class row(Part, Element): pass
+class entry(Part, Element): pass
class system_message(Special, PreBibliographic, Element, BackLinkable):
@@ -956,12 +978,22 @@ class pending(Special, PreBibliographic, Element):
internals.append('%7s%s:' % ('', key))
internals.extend(['%9s%s' % ('', line)
for line in value.pformat().splitlines()])
+ elif value and type(value) == ListType \
+ and isinstance(value[0], Node):
+ internals.append('%7s%s:' % ('', key))
+ for v in value:
+ internals.extend(['%9s%s' % ('', line)
+ for line in v.pformat().splitlines()])
else:
internals.append('%7s%s: %r' % ('', key, value))
return (Element.pformat(self, indent, level)
+ ''.join([(' %s%s\n' % (indent * level, line))
for line in internals]))
+ def copy(self):
+ return self.__class__(self.transform, self.stage, self.details,
+ **self.attributes)
+
class raw(Special, Inline, PreBibliographic, TextElement):
@@ -991,7 +1023,7 @@ class image(General, Inline, TextElement):
def astext(self):
return self.get('alt', '')
-
+
class problematic(Inline, TextElement): pass
@@ -1043,8 +1075,8 @@ class NodeVisitor:
1995.
"""
- def __init__(self, doctree):
- self.doctree = doctree
+ def __init__(self, document):
+ self.document = document
def unknown_visit(self, node):
"""
@@ -1078,12 +1110,12 @@ class GenericNodeVisitor(NodeVisitor):
Unless overridden, each ``visit_...`` method calls `default_visit()`, and
each ``depart_...`` method (when using `Node.walkabout()`) calls
- `default_departure()`. `default_visit()` (`default_departure()`) must be
- overridden in subclasses.
+ `default_departure()`. `default_visit()` (and `default_departure()`) must
+ be overridden in subclasses.
- Define fully generic visitors by overriding `default_visit()`
- (`default_departure()`) only. Define semi-generic visitors by overriding
- individual ``visit_...()`` (``depart_...()``) methods also.
+ Define fully generic visitors by overriding `default_visit()` (and
+ `default_departure()`) only. Define semi-generic visitors by overriding
+ individual ``visit_...()`` (and ``depart_...()``) methods also.
`NodeVisitor.unknown_visit()` (`NodeVisitor.unknown_departure()`) should
be overridden for default behavior.
@@ -1110,3 +1142,28 @@ class VisitorException(Exception): pass
class SkipChildren(VisitorException): pass
class SkipSiblings(VisitorException): pass
class SkipNode(VisitorException): pass
+class SkipDeparture(VisitorException): pass
+
+
+class TreeCopyVisitor(GenericNodeVisitor):
+
+ """
+ Make a complete copy of a tree or branch, including element attributes.
+ """
+
+ def __init__(self, document):
+ GenericNodeVisitor.__init__(self, document)
+ self.parent_stack = [[]]
+
+ def get_tree_copy(self):
+ return self.parent_stack[0][0]
+
+ def default_visit(self, node):
+ """"""
+ newnode = node.copy()
+ self.parent_stack[-1].append(newnode)
+ self.parent_stack.append(newnode)
+
+ def default_departure(self, node):
+ """"""
+ self.parent_stack.pop()
--
cgit v1.2.1
From 73710935431dbf51b075781b9a5409eea6c41393 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:15:54 +0000
Subject: renamed parts.py from compontents.py
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@71 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/components.py | 59 -------------------------
docutils/parsers/rst/directives/parts.py | 62 +++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 59 deletions(-)
delete mode 100644 docutils/parsers/rst/directives/components.py
create mode 100644 docutils/parsers/rst/directives/parts.py
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/components.py b/docutils/parsers/rst/directives/components.py
deleted file mode 100644
index 8463f41b0..000000000
--- a/docutils/parsers/rst/directives/components.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#! /usr/bin/env python
-
-"""
-:Author: David Goodger
-:Contact: goodger@users.sourceforge.net
-:Revision: $Revision$
-:Date: $Date$
-:Copyright: This module has been placed in the public domain.
-
-Document component directives.
-"""
-
-__docformat__ = 'reStructuredText'
-
-
-from docutils import nodes
-import docutils.transforms.components
-
-
-contents_attribute_spec = {'depth': int,
- 'local': (lambda x: x)}
-
-def contents(match, typename, data, state, statemachine, attributes):
- lineno = statemachine.abslineno()
- lineoffset = statemachine.lineoffset
- datablock, indent, offset, blankfinish = \
- statemachine.getfirstknownindented(match.end(), uptoblank=1)
- blocktext = '\n'.join(statemachine.inputlines[
- lineoffset : lineoffset + len(datablock) + 1])
- for i in range(len(datablock)):
- if datablock[i][:1] == ':':
- attlines = datablock[i:]
- datablock = datablock[:i]
- break
- else:
- attlines = []
- i = 0
- titletext = ' '.join([line.strip() for line in datablock])
- if titletext:
- textnodes, messages = state.inline_text(titletext, lineno)
- title = nodes.title(titletext, '', *textnodes)
- else:
- messages = []
- title = None
- pending = nodes.pending(docutils.transforms.components.Contents,
- 'last_reader', {'title': title}, blocktext)
- if attlines:
- success, data, blankfinish = state.parse_extension_attributes(
- contents_attribute_spec, attlines, blankfinish)
- if success: # data is a dict of attributes
- pending.details.update(data)
- else: # data is an error string
- error = statemachine.memo.reporter.error(
- 'Error in "%s" directive attributes at line %s:\n%s.'
- % (match.group(1), lineno, data), '',
- nodes.literal_block(blocktext, blocktext))
- return [error] + messages, blankfinish
- statemachine.memo.document.note_pending(pending)
- return [pending] + messages, blankfinish
diff --git a/docutils/parsers/rst/directives/parts.py b/docutils/parsers/rst/directives/parts.py
new file mode 100644
index 000000000..7b3d63697
--- /dev/null
+++ b/docutils/parsers/rst/directives/parts.py
@@ -0,0 +1,62 @@
+#! /usr/bin/env python
+
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+: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
+
+
+def unchanged(arg):
+ return arg # unchanged!
+
+contents_attribute_spec = {'depth': int,
+ 'local': unchanged,
+ 'qa': unchanged}
+
+def contents(match, type_name, data, state, state_machine, attributes):
+ lineno = state_machine.abs_line_number()
+ line_offset = state_machine.line_offset
+ datablock, indent, offset, blank_finish = \
+ state_machine.get_first_known_indented(match.end(), until_blank=1)
+ blocktext = '\n'.join(state_machine.input_lines[
+ line_offset : line_offset + len(datablock) + 1])
+ for i in range(len(datablock)):
+ if datablock[i][:1] == ':':
+ attlines = datablock[i:]
+ datablock = datablock[:i]
+ break
+ else:
+ attlines = []
+ i = 0
+ titletext = ' '.join([line.strip() for line in datablock])
+ if titletext:
+ textnodes, messages = state.inline_text(titletext, lineno)
+ title = nodes.title(titletext, '', *textnodes)
+ else:
+ messages = []
+ title = None
+ pending = nodes.pending(parts.Contents, 'last reader', {'title': title},
+ blocktext)
+ if attlines:
+ success, data, blank_finish = state.parse_extension_attributes(
+ contents_attribute_spec, attlines, blank_finish)
+ if success: # data is a dict of attributes
+ pending.details.update(data)
+ else: # data is an error string
+ error = state_machine.reporter.error(
+ 'Error in "%s" directive attributes at line %s:\n%s.'
+ % (match.group(1), lineno, data), '',
+ nodes.literal_block(blocktext, blocktext))
+ return [error] + messages, blank_finish
+ state_machine.document.note_pending(pending)
+ return [pending] + messages, blank_finish
--
cgit v1.2.1
From f51354f5a1a68947246017a9c0e27644419d49bf Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:16:56 +0000
Subject: Changed the ``meta`` directive to use a ``pending`` element, used
only by HTML writers.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@72 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/html.py | 74 ++++++++++++++++++---------------
1 file changed, 40 insertions(+), 34 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/html.py b/docutils/parsers/rst/directives/html.py
index d971300e0..262a124c8 100644
--- a/docutils/parsers/rst/directives/html.py
+++ b/docutils/parsers/rst/directives/html.py
@@ -15,32 +15,33 @@ __docformat__ = 'reStructuredText'
from docutils import nodes, utils
from docutils.parsers.rst import states
+from docutils.transforms import components
-def meta(match, typename, data, state, statemachine, attributes):
- lineoffset = statemachine.lineoffset
- block, indent, offset, blankfinish = \
- statemachine.getfirstknownindented(match.end(), uptoblank=1)
+def meta(match, type_name, data, state, state_machine, attributes):
+ line_offset = state_machine.line_offset
+ block, indent, offset, blank_finish = \
+ state_machine.get_first_known_indented(match.end(), until_blank=1)
node = nodes.Element()
if block:
- newlineoffset, blankfinish = state.nestedlistparse(
- block, offset, node, initialstate='MetaBody',
- blankfinish=blankfinish, statemachinekwargs=metaSMkwargs)
- if (newlineoffset - offset) != len(block): # incomplete parse of block?
- blocktext = '\n'.join(statemachine.inputlines[
- lineoffset : statemachine.lineoffset+1])
- msg = statemachine.memo.reporter.error(
+ new_line_offset, blank_finish = state.nested_list_parse(
+ block, offset, node, initial_state='MetaBody',
+ blank_finish=blank_finish, state_machine_kwargs=metaSMkwargs)
+ if (new_line_offset - offset) != len(block): # incomplete parse of block?
+ blocktext = '\n'.join(state_machine.input_lines[
+ line_offset : state_machine.line_offset+1])
+ msg = state_machine.reporter.error(
'Invalid meta directive at line %s.'
- % statemachine.abslineno(), '',
+ % state_machine.abs_line_number(), '',
nodes.literal_block(blocktext, blocktext))
node += msg
else:
- msg = statemachine.memo.reporter.error(
- 'Empty meta directive at line %s.' % statemachine.abslineno())
+ msg = state_machine.reporter.error('Empty meta directive at line %s.'
+ % state_machine.abs_line_number())
node += msg
- return node.getchildren(), blankfinish
+ return node.getchildren(), blank_finish
-def imagemap(match, typename, data, state, statemachine, attributes):
+def imagemap(match, type_name, data, state, state_machine, attributes):
return [], 0
@@ -50,24 +51,27 @@ class MetaBody(states.SpecializedBody):
"""HTML-specific "meta" element."""
pass
- def field_marker(self, match, context, nextstate):
+ def field_marker(self, match, context, next_state):
"""Meta element."""
- node, blankfinish = self.parsemeta(match)
- self.statemachine.node += node
- return [], nextstate, []
+ node, blank_finish = self.parsemeta(match)
+ self.parent += node
+ return [], next_state, []
def parsemeta(self, match):
name, args = self.parse_field_marker(match)
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
node = self.meta()
+ pending = nodes.pending(components.Filter, 'first writer',
+ {'writer': 'html', 'nodes': [node]})
node['content'] = ' '.join(indented)
if not indented:
- line = self.statemachine.line
- msg = self.statemachine.memo.reporter.info(
- 'No content for meta tag "%s".' % name, '',
- nodes.literal_block(line, line))
- self.statemachine.node += msg
+ line = self.state_machine.line
+ msg = self.reporter.info(
+ 'No content for meta tag "%s" at line %s.'
+ % (name, self.state_machine.abs_line_number()),
+ '', nodes.literal_block(line, line))
+ return msg, blank_finish
try:
attname, val = utils.extract_name_value(name)[0]
node[attname.lower()] = val
@@ -78,12 +82,14 @@ class MetaBody(states.SpecializedBody):
attname, val = utils.extract_name_value(arg)[0]
node[attname.lower()] = val
except utils.NameValueError, detail:
- line = self.statemachine.line
- msg = self.statemachine.memo.reporter.error(
- 'Error parsing meta tag attribute "%s": %s'
- % (arg, detail), '', nodes.literal_block(line, line))
- self.statemachine.node += msg
- return node, blankfinish
+ line = self.state_machine.line
+ msg = self.reporter.error(
+ 'Error parsing meta tag attribute "%s" at line %s: %s.'
+ % (arg, self.state_machine.abs_line_number(), detail),
+ '', nodes.literal_block(line, line))
+ return msg, blank_finish
+ self.document.note_pending(pending)
+ return pending, blank_finish
-metaSMkwargs = {'stateclasses': (MetaBody,)}
+metaSMkwargs = {'state_classes': (MetaBody,)}
--
cgit v1.2.1
From e13920cf12052d05709108e6c787817b8b36c42e Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:19:18 +0000
Subject: refactored; improved compound names
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@73 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 63 ++++++++++++++------------
docutils/languages/__init__.py | 10 ++--
docutils/parsers/__init__.py | 25 +++++-----
docutils/parsers/rst/__init__.py | 38 +++++++++-------
docutils/parsers/rst/directives/__init__.py | 19 ++++----
docutils/parsers/rst/directives/admonitions.py | 12 ++---
docutils/parsers/rst/directives/images.py | 60 ++++++++++++------------
docutils/parsers/rst/directives/misc.py | 22 ++++-----
8 files changed, 130 insertions(+), 119 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index b553b07b7..a578fef5f 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -7,27 +7,30 @@
:Date: $Date$
:Copyright: This module has been placed in the public domain.
-
+Calling the `publish` convenience function (or instantiating a
+`Publisher` object) with component names will result in default
+behavior. For custom behavior (setting component options), create
+custom component objects first, and pass *them* to
+`publish`/`Publisher`.
"""
__docformat__ = 'reStructuredText'
-
import readers, parsers, writers, utils
class Publisher:
"""
- Publisher encapsulates the high-level logic of a Docutils system.
+ A facade encapsulating the high-level logic of a Docutils system.
"""
reporter = None
"""A `utils.Reporter` instance used for all document processing."""
def __init__(self, reader=None, parser=None, writer=None, reporter=None,
- languagecode='en', warninglevel=2, errorlevel=4,
- warningstream=None, debug=0):
+ language_code='en', warning_level=2, error_level=4,
+ warning_stream=None, debug=0):
"""
Initial setup. If any of `reader`, `parser`, or `writer` are
not specified, the corresponding 'set*' method should be
@@ -37,26 +40,27 @@ class Publisher:
self.parser = parser
self.writer = writer
if not reporter:
- reporter = utils.Reporter(warninglevel, errorlevel, warningstream,
- debug)
+ reporter = utils.Reporter(warning_level, error_level,
+ warning_stream, debug)
self.reporter = reporter
- self.languagecode = languagecode
+ self.language_code = language_code
- def setreader(self, readername, languagecode=None):
+ def set_reader(self, reader_name, parser, parser_name,
+ language_code=None):
"""Set `self.reader` by name."""
- readerclass = readers.get_reader_class(readername)
- self.reader = readerclass(self.reporter,
- languagecode or self.languagecode)
+ reader_class = readers.get_reader_class(reader_name)
+ self.reader = reader_class(self.reporter, parser, parser_name,
+ language_code or self.language_code)
- def setparser(self, parsername):
+ def set_parser(self, parser_name):
"""Set `self.parser` by name."""
- parserclass = parsers.get_parser_class(parsername)
- self.parser = parserclass()
+ parser_class = parsers.get_parser_class(parser_name)
+ self.parser = parser_class()
- def setwriter(self, writername):
+ def set_writer(self, writer_name):
"""Set `self.writer` by name."""
- writerclass = writers.get_writer_class(writername)
- self.writer = writerclass()
+ writer_class = writers.get_writer_class(writer_name)
+ self.writer = writer_class()
def publish(self, source, destination):
"""
@@ -68,18 +72,17 @@ class Publisher:
def publish(source=None, destination=None,
- reader=None, readername='standalone',
- parser=None, parsername='restructuredtext',
- writer=None, writername='pprint',
- reporter=None, languagecode='en',
- warninglevel=2, errorlevel=4, warningstream=None, debug=0):
- """Set up & run a `Publisher`."""
- pub = Publisher(reader, parser, writer, reporter, languagecode,
- warninglevel, errorlevel, warningstream, debug)
+ reader=None, reader_name='standalone',
+ parser=None, parser_name='restructuredtext',
+ writer=None, writer_name='pseudoxml',
+ reporter=None, language_code='en',
+ warning_level=2, error_level=4, warning_stream=None, debug=0):
+ """A convenience function; set up & run a `Publisher`."""
+ pub = Publisher(reader, parser, writer, reporter, language_code,
+ warning_level, error_level, warning_stream, debug)
if reader is None:
- pub.setreader(readername)
- if parser is None:
- pub.setparser(parsername)
+ pub.set_reader(reader_name, parser, parser_name)
if writer is None:
- pub.setwriter(writername)
+ pub.set_writer(writer_name)
pub.publish(source, destination)
+
diff --git a/docutils/languages/__init__.py b/docutils/languages/__init__.py
index 4c10d9124..0de3674d7 100644
--- a/docutils/languages/__init__.py
+++ b/docutils/languages/__init__.py
@@ -14,9 +14,9 @@ __docformat__ = 'reStructuredText'
_languages = {}
-def getlanguage(languagecode):
- if _languages.has_key(languagecode):
- return _languages[languagecode]
- module = __import__(languagecode, globals(), locals())
- _languages[languagecode] = module
+def getlanguage(language_code):
+ if _languages.has_key(language_code):
+ return _languages[language_code]
+ module = __import__(language_code, globals(), locals())
+ _languages[language_code] = module
return module
diff --git a/docutils/parsers/__init__.py b/docutils/parsers/__init__.py
index 72e2e4e49..0294da0f8 100644
--- a/docutils/parsers/__init__.py
+++ b/docutils/parsers/__init__.py
@@ -10,28 +10,31 @@
__docformat__ = 'reStructuredText'
+from docutils import Component
-class Parser:
- def parse(self, inputstring, docroot):
- """Override to parse `inputstring` into document tree `docroot`."""
+class Parser(Component):
+
+ def parse(self, inputstring, document):
+ """Override to parse `inputstring` into document tree `document`."""
raise NotImplementedError('subclass must override this method')
- def setup_parse(self, inputstring, docroot):
+ def setup_parse(self, inputstring, document):
"""Initial setup, used by `parse()`."""
self.inputstring = inputstring
- self.docroot = docroot
+ self.document = document
_parser_aliases = {
'restructuredtext': 'rst',
'rest': 'rst',
+ 'restx': 'rst',
'rtxt': 'rst',}
-def get_parser_class(parsername):
- """Return the Parser class from the `parsername` module."""
- parsername = parsername.lower()
- if _parser_aliases.has_key(parsername):
- parsername = _parser_aliases[parsername]
- module = __import__(parsername, globals(), locals())
+def get_parser_class(parser_name):
+ """Return the Parser class from the `parser_name` module."""
+ parser_name = parser_name.lower()
+ if _parser_aliases.has_key(parser_name):
+ parser_name = _parser_aliases[parser_name]
+ module = __import__(parser_name, globals(), locals())
return module.Parser
diff --git a/docutils/parsers/rst/__init__.py b/docutils/parsers/rst/__init__.py
index bbe7dfee6..506a9e9fb 100644
--- a/docutils/parsers/rst/__init__.py
+++ b/docutils/parsers/rst/__init__.py
@@ -7,8 +7,7 @@
:Date: $Date$
:Copyright: This module has been placed in the public domain.
-This is ``the docutils.parsers.restructuredtext`` package. It exports a single
-class, `Parser`.
+This is ``docutils.parsers.rst`` package. It exports a single class, `Parser`.
Usage
=====
@@ -27,13 +26,13 @@ Usage
3. Create a new empty `docutils.nodes.document` tree::
- docroot = docutils.utils.newdocument()
+ document = docutils.utils.new_document()
- See `docutils.utils.newdocument()` for parameter details.
+ See `docutils.utils.new_document()` for parameter details.
4. Run the parser, populating the document tree::
- document = parser.parse(input, docroot)
+ parser.parse(input, document)
Parser Overview
===============
@@ -56,20 +55,25 @@ class Parser(docutils.parsers.Parser):
"""The reStructuredText parser."""
- def __init__(self, rfc2822=None):
+ supported = ('restructuredtext', 'rst', 'rest', 'restx', 'rtxt', 'rstx')
+ """Aliases this parser supports."""
+
+ def __init__(self, rfc2822=None, inliner=None):
if rfc2822:
- self.initialstate = 'RFC2822Body'
+ self.initial_state = 'RFC2822Body'
else:
- self.initialstate = 'Body'
-
- def parse(self, inputstring, docroot):
- """Parse `inputstring` and populate `docroot`, a document tree."""
- self.setup_parse(inputstring, docroot)
- debug = docroot.reporter[''].debug
+ self.initial_state = 'Body'
+ self.state_classes = states.state_classes
+ self.inliner = inliner
+
+ def parse(self, inputstring, document):
+ """Parse `inputstring` and populate `document`, a document tree."""
+ self.setup_parse(inputstring, document)
+ debug = document.reporter[''].debug
self.statemachine = states.RSTStateMachine(
- stateclasses=states.stateclasses,
- initialstate=self.initialstate,
+ state_classes=self.state_classes,
+ initial_state=self.initial_state,
debug=debug)
inputlines = docutils.statemachine.string2lines(
- inputstring, convertwhitespace=1)
- self.statemachine.run(inputlines, docroot)
+ inputstring, convert_whitespace=1)
+ self.statemachine.run(inputlines, document, inliner=self.inliner)
diff --git a/docutils/parsers/rst/directives/__init__.py b/docutils/parsers/rst/directives/__init__.py
index 43b0c1dd3..89d273651 100644
--- a/docutils/parsers/rst/directives/__init__.py
+++ b/docutils/parsers/rst/directives/__init__.py
@@ -11,17 +11,17 @@ This package contains directive implementation modules.
The interface for directive functions is as follows::
- def directivefn(match, type, data, state, statemachine, attributes)
+ def directivefn(match, type_name, data, state, state_machine, attributes)
Where:
- ``match`` is a regular expression match object which matched the first line
of the directive. ``match.group(1)`` gives the directive name.
-- ``type`` is the directive type or name.
+- ``type_name`` is the directive type or name.
- ``data`` contains the remainder of the first line of the directive after the
"::".
- ``state`` is the state which called the directive function.
-- ``statemachine`` is the state machine which controls the state which called
+- ``state_machine`` is the state machine which controls the state which called
the directive function.
- ``attributes`` is a dictionary of extra attributes which may be added to the
element the directive produces. Currently, only an "alt" attribute is passed
@@ -42,15 +42,16 @@ _directive_registry = {
'tip': ('admonitions', 'tip'),
'hint': ('admonitions', 'hint'),
'warning': ('admonitions', 'warning'),
+ 'questions': ('body', 'question_list'),
'image': ('images', 'image'),
'figure': ('images', 'figure'),
- 'contents': ('components', 'contents'),
- 'footnotes': ('components', 'footnotes'),
- 'citations': ('components', 'citations'),
- 'topic': ('components', 'topic'),
+ 'contents': ('parts', 'contents'),
+ #'footnotes': ('parts', 'footnotes'),
+ #'citations': ('parts', 'citations'),
+ #'topic': ('parts', 'topic'),
'meta': ('html', 'meta'),
- 'imagemap': ('html', 'imagemap'),
- 'raw': ('misc', 'raw'),
+ #'imagemap': ('html', 'imagemap'),
+ #'raw': ('misc', 'raw'),
'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
diff --git a/docutils/parsers/rst/directives/admonitions.py b/docutils/parsers/rst/directives/admonitions.py
index f594cd431..9e6b0ebf7 100644
--- a/docutils/parsers/rst/directives/admonitions.py
+++ b/docutils/parsers/rst/directives/admonitions.py
@@ -17,15 +17,15 @@ from docutils.parsers.rst import states
from docutils import nodes
-def admonition(nodeclass, match, typename, data, state, statemachine,
+def admonition(node_class, match, type_name, data, state, state_machine,
attributes):
- indented, indent, lineoffset, blankfinish \
- = statemachine.getfirstknownindented(match.end())
+ indented, indent, line_offset, blank_finish \
+ = state_machine.get_first_known_indented(match.end())
text = '\n'.join(indented)
- admonitionnode = nodeclass(text)
+ admonition_node = node_class(text)
if text:
- state.nestedparse(indented, lineoffset, admonitionnode)
- return [admonitionnode], blankfinish
+ state.nested_parse(indented, line_offset, admonition_node)
+ return [admonition_node], blank_finish
def attention(*args, **kwargs):
return admonition(nodes.attention, *args, **kwargs)
diff --git a/docutils/parsers/rst/directives/images.py b/docutils/parsers/rst/directives/images.py
index 7a719333b..76e5d6f47 100644
--- a/docutils/parsers/rst/directives/images.py
+++ b/docutils/parsers/rst/directives/images.py
@@ -25,13 +25,13 @@ image_attribute_spec = {'alt': unchanged,
'width': int,
'scale': int}
-def image(match, typename, data, state, statemachine, attributes):
- lineno = statemachine.abslineno()
- lineoffset = statemachine.lineoffset
- datablock, indent, offset, blankfinish = \
- statemachine.getfirstknownindented(match.end(), uptoblank=1)
- blocktext = '\n'.join(statemachine.inputlines[
- lineoffset : lineoffset + len(datablock) + 1])
+def image(match, type_name, data, state, state_machine, attributes):
+ lineno = state_machine.abs_line_number()
+ line_offset = state_machine.line_offset
+ datablock, indent, offset, blank_finish = \
+ state_machine.get_first_known_indented(match.end(), until_blank=1)
+ blocktext = '\n'.join(state_machine.input_lines[
+ line_offset : line_offset + len(datablock) + 1])
for i in range(len(datablock)):
if datablock[i][:1] == ':':
attlines = datablock[i:]
@@ -40,58 +40,58 @@ def image(match, typename, data, state, statemachine, attributes):
else:
attlines = []
if not datablock:
- error = statemachine.memo.reporter.error(
+ error = state_machine.reporter.error(
'Missing image URI argument at line %s.' % lineno, '',
nodes.literal_block(blocktext, blocktext))
- return [error], blankfinish
- attoffset = lineoffset + i
+ return [error], blank_finish
+ attoffset = line_offset + i
reference = ''.join([line.strip() for line in datablock])
if reference.find(' ') != -1:
- error = statemachine.memo.reporter.error(
+ error = state_machine.reporter.error(
'Image URI at line %s contains whitespace.' % lineno, '',
nodes.literal_block(blocktext, blocktext))
- return [error], blankfinish
+ return [error], blank_finish
if attlines:
- success, data, blankfinish = state.parse_extension_attributes(
- image_attribute_spec, attlines, blankfinish)
+ success, data, blank_finish = state.parse_extension_attributes(
+ image_attribute_spec, attlines, blank_finish)
if success: # data is a dict of attributes
attributes.update(data)
else: # data is an error string
- error = statemachine.memo.reporter.error(
+ error = state_machine.reporter.error(
'Error in "%s" directive attributes at line %s:\n%s.'
% (match.group(1), lineno, data), '',
nodes.literal_block(blocktext, blocktext))
- return [error], blankfinish
+ return [error], blank_finish
attributes['uri'] = reference
imagenode = nodes.image(blocktext, **attributes)
- return [imagenode], blankfinish
+ return [imagenode], blank_finish
-def figure(match, typename, data, state, statemachine, attributes):
- lineoffset = statemachine.lineoffset
- (imagenode,), blankfinish = image(match, typename, data, state,
- statemachine, attributes)
- indented, indent, offset, blankfinish \
- = statemachine.getfirstknownindented(sys.maxint)
- blocktext = '\n'.join(statemachine.inputlines[lineoffset:
- statemachine.lineoffset+1])
+def figure(match, type_name, data, state, state_machine, attributes):
+ line_offset = state_machine.line_offset
+ (imagenode,), blank_finish = image(match, type_name, data, state,
+ state_machine, attributes)
+ indented, indent, offset, blank_finish \
+ = state_machine.get_first_known_indented(sys.maxint)
+ blocktext = '\n'.join(state_machine.input_lines[line_offset:
+ state_machine.line_offset+1])
if isinstance(imagenode, nodes.system_message):
if indented:
imagenode[-1] = nodes.literal_block(blocktext, blocktext)
- return [imagenode], blankfinish
+ return [imagenode], blank_finish
figurenode = nodes.figure('', imagenode)
if indented:
node = nodes.Element() # anonymous container for parsing
- state.nestedparse(indented, lineoffset, node)
+ state.nested_parse(indented, line_offset, node)
firstnode = node[0]
if isinstance(firstnode, nodes.paragraph):
caption = nodes.caption(firstnode.rawsource, '',
*firstnode.children)
figurenode += caption
elif not (isinstance(firstnode, nodes.comment) and len(firstnode) == 0):
- error = statemachine.memo.reporter.error(
+ error = state_machine.reporter.error(
'Figure caption must be a paragraph or empty comment.', '',
nodes.literal_block(blocktext, blocktext))
- return [figurenode, error], blankfinish
+ return [figurenode, error], blank_finish
if len(node) > 1:
figurenode += nodes.legend('', *node[1:])
- return [figurenode], blankfinish
+ return [figurenode], blank_finish
diff --git a/docutils/parsers/rst/directives/misc.py b/docutils/parsers/rst/directives/misc.py
index f8a9d5217..3a23f9226 100644
--- a/docutils/parsers/rst/directives/misc.py
+++ b/docutils/parsers/rst/directives/misc.py
@@ -16,24 +16,24 @@ __docformat__ = 'reStructuredText'
from docutils import nodes
-def raw(match, typename, data, state, statemachine, attributes):
+def raw(match, type_name, data, state, state_machine, attributes):
return [], 1
-def directive_test_function(match, typename, data, state, statemachine,
+def directive_test_function(match, type_name, data, state, state_machine,
attributes):
try:
- statemachine.nextline()
- indented, indent, offset, blankfinish = statemachine.getindented()
+ state_machine.next_line()
+ indented, indent, offset, blank_finish = state_machine.get_indented()
text = '\n'.join(indented)
except IndexError:
text = ''
- blankfinish = 1
+ blank_finish = 1
if text:
- info = statemachine.memo.reporter.info(
+ info = state_machine.reporter.info(
'Directive processed. Type="%s", data="%s", directive block:'
- % (typename, data), '', nodes.literal_block(text, text))
+ % (type_name, data), '', nodes.literal_block(text, text))
else:
- info = statemachine.memo.reporter.info(
- 'Directive processed. Type="%s", data="%s", directive block: None'
- % (typename, data))
- return [info], blankfinish
+ info = state_machine.reporter.info(
+ 'Directive processed. Type="%s", data="%s", directive block: '
+ 'None' % (type_name, data))
+ return [info], blank_finish
--
cgit v1.2.1
From 409668ba1ca8fbe197893dd7874acdf5f81c41eb Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:19:26 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@74 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/tableparser.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/tableparser.py b/docutils/parsers/rst/tableparser.py
index 7bacf99cd..3f7575040 100644
--- a/docutils/parsers/rst/tableparser.py
+++ b/docutils/parsers/rst/tableparser.py
@@ -19,9 +19,10 @@ __docformat__ = 'reStructuredText'
import re
+from docutils import DataError
-class TableMarkupError(Exception): pass
+class TableMarkupError(DataError): pass
class TableParser:
--
cgit v1.2.1
From c854d0803dd10573ea908840b85d12499904b060 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:22:30 +0000
Subject: - Added underscores to improve many awkward names. - Extracted
the inline parsing code from ``RSTState`` to a separate class,
``Inliner``, which will allow easy subclassing. - Made local bindings for
``memo`` container & often-used contents (reduces code complexity a lot).
See ``RSTState.runtime_init()``. - ``RSTState.parent`` replaces
``RSTState.statemachine.node``. - Added ``MarkupMismatch`` exception; for
late corrections.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@75 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 1787 +++++++++++++++++++++-------------------
1 file changed, 919 insertions(+), 868 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index efce3b4f1..d2a133198 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -31,13 +31,14 @@ the reStructuredText parser. It defines the following:
:Exception classes:
- `MarkupError`
- `ParserError`
+ - `MarkupMismatch`
:Functions:
- `escape2null()`: Return a string, escape-backslashes converted to nulls.
- `unescape()`: Return a string, nulls removed or restored to backslashes.
:Attributes:
- - `stateclasses`: set of State classes used with `RSTStateMachine`.
+ - `state_classes`: set of State classes used with `RSTStateMachine`.
Parser Overview
===============
@@ -102,15 +103,17 @@ __docformat__ = 'reStructuredText'
import sys, re, string
-from docutils import nodes, statemachine, utils, roman, urischemes
+from docutils import nodes, statemachine, utils, roman, urischemes, \
+ ApplicationError, DataError
from docutils.statemachine import StateMachineWS, StateWS
-from docutils.utils import normname
+from docutils.utils import normalize_name
import directives, languages
from tableparser import TableParser, TableMarkupError
-class MarkupError(Exception): pass
-class ParserError(Exception): pass
+class MarkupError(DataError): pass
+class ParserError(ApplicationError): pass
+class MarkupMismatch(Exception): pass
class Stuff:
@@ -129,24 +132,30 @@ class RSTStateMachine(StateMachineWS):
The entry point to reStructuredText parsing is the `run()` method.
"""
- def run(self, inputlines, docroot, inputoffset=0, matchtitles=1):
+ def run(self, input_lines, document, input_offset=0, match_titles=1,
+ inliner=None):
"""
- Parse `inputlines` and return a `docutils.nodes.document` instance.
+ Parse `input_lines` and return a `docutils.nodes.document` instance.
Extend `StateMachineWS.run()`: set up parse-global data, run the
StateMachine, and return the resulting
document.
"""
- self.language = languages.getlanguage(docroot.languagecode)
- self.matchtitles = matchtitles
- self.memo = Stuff(document=docroot,
- reporter=docroot.reporter,
+ self.language = languages.getlanguage(document.language_code)
+ self.match_titles = match_titles
+ if inliner is None:
+ inliner = Inliner()
+ self.memo = Stuff(document=document,
+ reporter=document.reporter,
language=self.language,
- titlestyles=[],
- sectionlevel=0)
- self.node = docroot
- results = StateMachineWS.run(self, inputlines, inputoffset)
- assert results == [], 'RSTStateMachine.run() results should be empty.'
+ title_styles=[],
+ section_level=0,
+ inliner=inliner)
+ self.document = self.memo.document
+ self.reporter = self.memo.reporter
+ self.node = document
+ results = StateMachineWS.run(self, input_lines, input_offset)
+ assert results == [], 'RSTStateMachine.run() results should be empty!'
self.node = self.memo = None # remove unneeded references
@@ -157,17 +166,20 @@ class NestedStateMachine(StateMachineWS):
document structures.
"""
- def run(self, inputlines, inputoffset, memo, node, matchtitles=1):
+ def run(self, input_lines, input_offset, memo, node, match_titles=1):
"""
- Parse `inputlines` and populate a `docutils.nodes.document` instance.
+ Parse `input_lines` and populate a `docutils.nodes.document` instance.
Extend `StateMachineWS.run()`: set up document-wide data.
"""
- self.matchtitles = matchtitles
+ self.match_titles = match_titles
self.memo = memo
+ self.document = memo.document
+ self.reporter = memo.reporter
self.node = node
- results = StateMachineWS.run(self, inputlines, inputoffset)
- assert results == [], 'NestedStateMachine.run() results should be empty'
+ results = StateMachineWS.run(self, input_lines, input_offset)
+ assert results == [], ('NestedStateMachine.run() results should be '
+ 'empty!')
return results
@@ -179,17 +191,28 @@ class RSTState(StateWS):
Contains methods used by all State subclasses.
"""
- nestedSM = NestedStateMachine
+ nested_sm = NestedStateMachine
- def __init__(self, statemachine, debug=0):
- self.nestedSMkwargs = {'stateclasses': stateclasses,
- 'initialstate': 'Body'}
- StateWS.__init__(self, statemachine, debug)
+ def __init__(self, state_machine, debug=0):
+ self.nested_sm_kwargs = {'state_classes': state_classes,
+ 'initial_state': 'Body'}
+ StateWS.__init__(self, state_machine, debug)
- def gotoline(self, abslineoffset):
- """Jump to input line `abslineoffset`, ignoring jumps past the end."""
+ def runtime_init(self):
+ StateWS.runtime_init(self)
+ memo = self.state_machine.memo
+ self.memo = memo
+ self.reporter = memo.reporter
+ self.inliner = memo.inliner
+ self.document = memo.document
+ self.parent = self.state_machine.node
+
+ def goto_line(self, abs_line_offset):
+ """
+ Jump to input line `abs_line_offset`, ignoring jumps past the end.
+ """
try:
- self.statemachine.gotoline(abslineoffset)
+ self.state_machine.goto_line(abs_line_offset)
except IndexError:
pass
@@ -197,126 +220,131 @@ class RSTState(StateWS):
"""Called at beginning of file."""
return [], []
- def nestedparse(self, block, inputoffset, node, matchtitles=0,
- statemachineclass=None, statemachinekwargs=None):
+ def nested_parse(self, block, input_offset, node, match_titles=0,
+ state_machine_class=None, state_machine_kwargs=None):
"""
Create a new StateMachine rooted at `node` and run it over the input
`block`.
"""
- if statemachineclass is None:
- statemachineclass = self.nestedSM
- if statemachinekwargs is None:
- statemachinekwargs = self.nestedSMkwargs
- statemachine = statemachineclass(debug=self.debug, **statemachinekwargs)
- statemachine.run(block, inputoffset, memo=self.statemachine.memo,
- node=node, matchtitles=matchtitles)
- statemachine.unlink()
- return statemachine.abslineoffset()
-
- def nestedlistparse(self, block, inputoffset, node, initialstate,
- blankfinish, blankfinishstate=None, extrasettings={},
- matchtitles=0, statemachineclass=None,
- statemachinekwargs=None):
+ if state_machine_class is None:
+ state_machine_class = self.nested_sm
+ if state_machine_kwargs is None:
+ state_machine_kwargs = self.nested_sm_kwargs
+ state_machine = state_machine_class(debug=self.debug,
+ **state_machine_kwargs)
+ state_machine.run(block, input_offset, memo=self.memo,
+ node=node, match_titles=match_titles)
+ state_machine.unlink()
+ return state_machine.abs_line_offset()
+
+ def nested_list_parse(self, block, input_offset, node, initial_state,
+ blank_finish,
+ blank_finish_state=None,
+ extra_settings={},
+ match_titles=0,
+ state_machine_class=None,
+ state_machine_kwargs=None):
"""
Create a new StateMachine rooted at `node` and run it over the input
`block`. Also keep track of optional intermdediate blank lines and the
required final one.
"""
- if statemachineclass is None:
- statemachineclass = self.nestedSM
- if statemachinekwargs is None:
- statemachinekwargs = self.nestedSMkwargs.copy()
- statemachinekwargs['initialstate'] = initialstate
- statemachine = statemachineclass(debug=self.debug, **statemachinekwargs)
- if blankfinishstate is None:
- blankfinishstate = initialstate
- statemachine.states[blankfinishstate].blankfinish = blankfinish
- for key, value in extrasettings.items():
- setattr(statemachine.states[initialstate], key, value)
- statemachine.run(block, inputoffset, memo=self.statemachine.memo,
- node=node, matchtitles=matchtitles)
- blankfinish = statemachine.states[blankfinishstate].blankfinish
- statemachine.unlink()
- return statemachine.abslineoffset(), blankfinish
+ if state_machine_class is None:
+ state_machine_class = self.nested_sm
+ if state_machine_kwargs is None:
+ state_machine_kwargs = self.nested_sm_kwargs.copy()
+ state_machine_kwargs['initial_state'] = initial_state
+ state_machine = state_machine_class(debug=self.debug,
+ **state_machine_kwargs)
+ if blank_finish_state is None:
+ blank_finish_state = initial_state
+ state_machine.states[blank_finish_state].blank_finish = blank_finish
+ for key, value in extra_settings.items():
+ setattr(state_machine.states[initial_state], key, value)
+ state_machine.run(block, input_offset, memo=self.memo,
+ node=node, match_titles=match_titles)
+ blank_finish = state_machine.states[blank_finish_state].blank_finish
+ state_machine.unlink()
+ return state_machine.abs_line_offset(), blank_finish
def section(self, title, source, style, lineno):
+ """Check for a valid subsection and create one if it checks out."""
+ if self.check_subsection(source, style, lineno):
+ self.new_subsection(title, lineno)
+
+ def check_subsection(self, source, style, lineno):
"""
+ Check for a valid subsection header. Return 1 (true) or None (false).
+
When a new section is reached that isn't a subsection of the current
- section, back up the line count (use previousline(-x)), then raise
- EOFError. The current StateMachine will finish, then the calling
- StateMachine can re-examine the title. This will work its way back up
- the calling chain until the correct section level isreached.
+ section, back up the line count (use ``previous_line(-x)``), then
+ ``raise EOFError``. The current StateMachine will finish, then the
+ calling StateMachine can re-examine the title. This will work its way
+ back up the calling chain until the correct section level isreached.
- Alternative: Evaluate the title, store the title info & level, and
- back up the chain until that level is reached. Store in memo? Or
+ @@@ Alternative: Evaluate the title, store the title info & level, and
+ back up the chain until that level is reached. Store in memo? Or
return in results?
- """
- if self.checksubsection(source, style, lineno):
- self.newsubsection(title, lineno)
-
- def checksubsection(self, source, style, lineno):
- """
- Check for a valid subsection header. Return 1 (true) or None (false).
:Exception: `EOFError` when a sibling or supersection encountered.
"""
- memo = self.statemachine.memo
- titlestyles = memo.titlestyles
- mylevel = memo.sectionlevel
+ memo = self.memo
+ title_styles = memo.title_styles
+ mylevel = memo.section_level
try: # check for existing title style
- level = titlestyles.index(style) + 1
+ level = title_styles.index(style) + 1
except ValueError: # new title style
- if len(titlestyles) == memo.sectionlevel: # new subsection
- titlestyles.append(style)
+ if len(title_styles) == memo.section_level: # new subsection
+ title_styles.append(style)
return 1
else: # not at lowest level
- self.statemachine.node += self.titleinconsistent(source, lineno)
+ self.parent += self.title_inconsistent(source, lineno)
return None
if level <= mylevel: # sibling or supersection
- memo.sectionlevel = level # bubble up to parent section
+ memo.section_level = level # bubble up to parent section
# back up 2 lines for underline title, 3 for overline title
- self.statemachine.previousline(len(style) + 1)
+ self.state_machine.previous_line(len(style) + 1)
raise EOFError # let parent section re-evaluate
if level == mylevel + 1: # immediate subsection
return 1
else: # invalid subsection
- self.statemachine.node += self.titleinconsistent(source, lineno)
+ self.parent += self.title_inconsistent(source, lineno)
return None
- def titleinconsistent(self, sourcetext, lineno):
+ def title_inconsistent(self, sourcetext, lineno):
literalblock = nodes.literal_block('', sourcetext)
- error = self.statemachine.memo.reporter.severe(
- 'Title level inconsistent at line %s:' % lineno, '', literalblock)
+ error = self.reporter.severe('Title level inconsistent at line %s:'
+ % lineno, '', literalblock)
return error
- def newsubsection(self, title, lineno):
+ def new_subsection(self, title, lineno):
"""Append new subsection to document tree. On return, check level."""
- memo = self.statemachine.memo
- mylevel = memo.sectionlevel
- memo.sectionlevel += 1
+ memo = self.memo
+ mylevel = memo.section_level
+ memo.section_level += 1
sectionnode = nodes.section()
- self.statemachine.node += sectionnode
+ self.parent += sectionnode
textnodes, messages = self.inline_text(title, lineno)
titlenode = nodes.title(title, '', *textnodes)
- name = normname(titlenode.astext())
+ name = normalize_name(titlenode.astext())
sectionnode['name'] = name
sectionnode += titlenode
sectionnode += messages
- memo.document.note_implicit_target(sectionnode, sectionnode)
- offset = self.statemachine.lineoffset + 1
- absoffset = self.statemachine.abslineoffset() + 1
- newabsoffset = self.nestedparse(
- self.statemachine.inputlines[offset:], inputoffset=absoffset,
- node=sectionnode, matchtitles=1)
- self.gotoline(newabsoffset)
- if memo.sectionlevel <= mylevel: # can't handle next section?
+ self.document.note_implicit_target(sectionnode, sectionnode)
+ offset = self.state_machine.line_offset + 1
+ absoffset = self.state_machine.abs_line_offset() + 1
+ newabsoffset = self.nested_parse(
+ self.state_machine.input_lines[offset:], input_offset=absoffset,
+ node=sectionnode, match_titles=1)
+ self.goto_line(newabsoffset)
+ if memo.section_level <= mylevel: # can't handle next section?
raise EOFError # bubble up to supersection
- # reset sectionlevel; next pass will detect it properly
- memo.sectionlevel = mylevel
+ # reset section_level; next pass will detect it properly
+ memo.section_level = mylevel
def paragraph(self, lines, lineno):
"""
- Return a list (paragraph & messages) and a boolean: literal_block next?
+ Return a list (paragraph & messages) & a boolean: literal_block next?
"""
data = '\n'.join(lines).rstrip()
if data[-2:] == '::':
@@ -334,143 +362,203 @@ class RSTState(StateWS):
p = nodes.paragraph(data, '', *textnodes)
return [p] + messages, literalnext
- inline = Stuff()
- """Patterns and constants used for inline markup recognition."""
-
- inline.openers = '\'"([{<'
- inline.closers = '\'")]}>'
- inline.start_string_prefix = (r'(?:(?<=^)|(?<=[ \n%s]))'
- % re.escape(inline.openers))
- inline.end_string_suffix = (r'(?:(?=$)|(?=[- \n.,:;!?%s]))'
- % re.escape(inline.closers))
- inline.non_whitespace_before = r'(?'
+ start_string_prefix = (r'(?:(?<=^)|(?<=[ \n%s]))'
+ % re.escape(openers))
+ end_string_suffix = (r'(?:(?=$)|(?=[- \n.,:;!?%s]))'
+ % re.escape(closers))
+ non_whitespace_before = r'(? 0:
- textnodes.append(nodes.Text(unescape(
- remainder[:match.start(whole)])))
- if match.group(email):
- addscheme = 'mailto:'
- else:
- addscheme = ''
- text = match.group(whole)
- unescaped = unescape(text, 0)
- textnodes.append(
- nodes.reference(unescape(text, 1), unescaped,
- refuri=addscheme + unescaped))
- remainder = remainder[match.end(whole):]
- start = 0
- else: # not a valid scheme
- start = match.end(whole)
+ def standalone_uri(self, match, lineno):
+ scheme = self.groups.uri.scheme
+ if not match.group(scheme) or urischemes.schemes.has_key(
+ match.group(scheme).lower()):
+ if match.group(self.groups.uri.email):
+ addscheme = 'mailto:'
else:
- if remainder:
- textnodes.append(nodes.Text(unescape(remainder)))
- break
- return textnodes
-
- inline.dispatch = {'*': emphasis,
- '**': strong,
- '`': interpreted_or_phrase_ref,
- '``': literal,
- '_`': inline_target,
- ']_': footnote_reference,
- '|': substitution_reference,
- '_': reference,
- '__': anonymous_reference}
-
- def inline_text(self, text, lineno):
+ addscheme = ''
+ text = match.group(self.groups.uri.whole)
+ unescaped = unescape(text, 0)
+ return [nodes.reference(unescape(text, 1), unescaped,
+ refuri=addscheme + unescaped)]
+ else: # not a valid scheme
+ raise MarkupMismatch
+
+ implicit = ((patterns.uri, standalone_uri),)
+ """List of (pattern, dispatch method) pairs."""
+
+ def implicit_inline(self, text, lineno):
"""
- Return 2 lists: nodes (text and inline elements), and system_messages.
-
- Using a `pattern` matching start-strings (for emphasis, strong,
- interpreted, phrase reference, literal, substitution reference, and
- inline target) or complete constructs (simple reference, footnote
- reference) we search for a candidate. When one is found, we check for
- validity (e.g., not a quoted '*' character). If valid, search for the
- corresponding end string if applicable, and check for validity. If not
- found or invalid, generate a warning and ignore the start-string.
- Standalone hyperlinks are found last.
+ Check each of the patterns in `self.implicit` for a match, and
+ dispatch to the stored method for the pattern. Recursively check the
+ text before and after the match.
"""
- pattern = self.inline.patterns.initial
- dispatch = self.inline.dispatch
- start = self.inline.groups.initial.start - 1
- backquote = self.inline.groups.initial.backquote - 1
- refend = self.inline.groups.initial.refend - 1
- fnend = self.inline.groups.initial.fnend - 1
- remaining = escape2null(text)
- processed = []
- unprocessed = []
- messages = []
- while remaining:
- match = pattern.search(remaining)
+ if not text:
+ return []
+ for pattern, dispatch in self.implicit:
+ match = pattern.search(text)
if match:
- groups = match.groups()
- before, inlines, remaining, sysmessages = \
- dispatch[groups[start] or groups[backquote]
- or groups[refend]
- or groups[fnend]](self, match, lineno)
- unprocessed.append(before)
- messages += sysmessages
- if inlines:
- processed += self.standalone_uri(''.join(unprocessed),
- lineno)
- processed += inlines
- unprocessed = []
- else:
- break
- remaining = ''.join(unprocessed) + remaining
- if remaining:
- processed += self.standalone_uri(remaining, lineno)
- return processed, messages
-
- def unindent_warning(self, node_name):
- return self.statemachine.memo.reporter.warning(
- ('%s ends without a blank line; unexpected unindent at line %s.'
- % (node_name, self.statemachine.abslineno() + 1)))
+ try:
+ return (self.implicit_inline(text[:match.start()], lineno)
+ + dispatch(self, match, lineno) +
+ self.implicit_inline(text[match.end():], lineno))
+ except MarkupMismatch:
+ pass
+ return [nodes.Text(unescape(text))]
+
+ dispatch = {'*': emphasis,
+ '**': strong,
+ '`': interpreted_or_phrase_ref,
+ '``': literal,
+ '_`': inline_target,
+ ']_': footnote_reference,
+ '|': substitution_reference,
+ '_': reference,
+ '__': anonymous_reference}
class Body(RSTState):
@@ -830,10 +870,10 @@ class Body(RSTState):
enum.sequenceregexps = {}
for sequence in enum.sequences:
- enum.sequenceregexps[sequence] = re.compile(enum.sequencepats[sequence]
- + '$')
+ enum.sequenceregexps[sequence] = re.compile(
+ enum.sequencepats[sequence] + '$')
- tabletoppat = re.compile(r'\+-[-+]+-\+ *$')
+ table_top_pat = re.compile(r'\+-[-+]+-\+ *$')
"""Matches the top (& bottom) of a table)."""
tableparser = TableParser()
@@ -856,114 +896,116 @@ class Body(RSTState):
format, re.escape(enum.formatinfo[format].prefix),
pats['enum'], re.escape(enum.formatinfo[format].suffix))
- patterns = {'bullet': r'[-+*]( +|$)',
- 'enumerator': r'(%(parens)s|%(rparen)s|%(period)s)( +|$)'
- % pats,
- 'field_marker': r':[^: ]([^:]*[^: ])?:( +|$)',
- 'option_marker': r'%(option)s(, %(option)s)*( +| ?$)' % pats,
- 'doctest': r'>>>( +|$)',
- 'tabletop': tabletoppat,
- 'explicit_markup': r'\.\.( +|$)',
- 'anonymous': r'__( +|$)',
- 'line': r'(%(nonalphanum7bit)s)\1\1\1+ *$' % pats,
- 'text': r''}
- initialtransitions = ['bullet',
- 'enumerator',
- 'field_marker',
- 'option_marker',
- 'doctest',
- 'tabletop',
- 'explicit_markup',
- 'anonymous',
- 'line',
- 'text']
-
- def indent(self, match, context, nextstate):
+ patterns = {
+ 'bullet': r'[-+*]( +|$)',
+ 'enumerator': r'(%(parens)s|%(rparen)s|%(period)s)( +|$)' % pats,
+ 'field_marker': r':[^: ]([^:]*[^: ])?:( +|$)',
+ 'option_marker': r'%(option)s(, %(option)s)*( +| ?$)' % pats,
+ 'doctest': r'>>>( +|$)',
+ 'table_top': table_top_pat,
+ 'explicit_markup': r'\.\.( +|$)',
+ 'anonymous': r'__( +|$)',
+ 'line': r'(%(nonalphanum7bit)s)\1\1\1+ *$' % pats,
+ 'text': r''}
+ initial_transitions = (
+ 'bullet',
+ 'enumerator',
+ 'field_marker',
+ 'option_marker',
+ 'doctest',
+ 'table_top',
+ 'explicit_markup',
+ 'anonymous',
+ 'line',
+ 'text')
+
+ def indent(self, match, context, next_state):
"""Block quote."""
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getindented()
- blockquote = self.block_quote(indented, lineoffset)
- self.statemachine.node += blockquote
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Block quote')
- return context, nextstate, []
-
- def block_quote(self, indented, lineoffset):
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_indented()
+ blockquote = self.block_quote(indented, line_offset)
+ self.parent += blockquote
+ if not blank_finish:
+ self.parent += self.unindent_warning('Block quote')
+ return context, next_state, []
+
+ def block_quote(self, indented, line_offset):
blockquote = nodes.block_quote()
- self.nestedparse(indented, lineoffset, blockquote)
+ self.nested_parse(indented, line_offset, blockquote)
return blockquote
- def bullet(self, match, context, nextstate):
+ def bullet(self, match, context, next_state):
"""Bullet list item."""
bulletlist = nodes.bullet_list()
- self.statemachine.node += bulletlist
+ self.parent += bulletlist
bulletlist['bullet'] = match.string[0]
- i, blankfinish = self.list_item(match.end())
+ i, blank_finish = self.list_item(match.end())
bulletlist += i
- offset = self.statemachine.lineoffset + 1 # next line
- newlineoffset, blankfinish = self.nestedlistparse(
- self.statemachine.inputlines[offset:],
- inputoffset=self.statemachine.abslineoffset() + 1,
- node=bulletlist, initialstate='BulletList',
- blankfinish=blankfinish)
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Bullet list')
- self.gotoline(newlineoffset)
- return [], nextstate, []
+ offset = self.state_machine.line_offset + 1 # next line
+ newline_offset, blank_finish = self.nested_list_parse(
+ self.state_machine.input_lines[offset:],
+ input_offset=self.state_machine.abs_line_offset() + 1,
+ node=bulletlist, initial_state='BulletList',
+ blank_finish=blank_finish)
+ if not blank_finish:
+ self.parent += self.unindent_warning('Bullet list')
+ self.goto_line(newline_offset)
+ return [], next_state, []
def list_item(self, indent):
- indented, lineoffset, blankfinish = \
- self.statemachine.getknownindented(indent)
+ indented, line_offset, blank_finish = \
+ self.state_machine.get_known_indented(indent)
listitem = nodes.list_item('\n'.join(indented))
if indented:
- self.nestedparse(indented, inputoffset=lineoffset, node=listitem)
- return listitem, blankfinish
+ self.nested_parse(indented, input_offset=line_offset,
+ node=listitem)
+ return listitem, blank_finish
- def enumerator(self, match, context, nextstate):
+ def enumerator(self, match, context, next_state):
"""Enumerated List Item"""
format, sequence, text, ordinal = self.parse_enumerator(match)
if ordinal is None:
- msg = self.statemachine.memo.reporter.error(
+ msg = self.reporter.error(
('Enumerated list start value invalid at line %s: '
- '%r (sequence %r)' % (self.statemachine.abslineno(),
+ '%r (sequence %r)' % (self.state_machine.abs_line_number(),
text, sequence)))
- self.statemachine.node += msg
- indented, lineoffset, blankfinish = \
- self.statemachine.getknownindented(match.end())
- bq = self.block_quote(indented, lineoffset)
- self.statemachine.node += bq
- if not blankfinish:
- self.statemachine.node += self.unindent_warning(
+ self.parent += msg
+ indented, line_offset, blank_finish = \
+ self.state_machine.get_known_indented(match.end())
+ bq = self.block_quote(indented, line_offset)
+ self.parent += bq
+ if not blank_finish:
+ self.parent += self.unindent_warning(
'Enumerated list')
- return [], nextstate, []
+ return [], next_state, []
if ordinal != 1:
- msg = self.statemachine.memo.reporter.info(
+ msg = self.reporter.info(
('Enumerated list start value not ordinal-1 at line %s: '
- '%r (ordinal %s)' % (self.statemachine.abslineno(),
- text, ordinal)))
- self.statemachine.node += msg
+ '%r (ordinal %s)' % (self.state_machine.abs_line_number(),
+ text, ordinal)))
+ self.parent += msg
enumlist = nodes.enumerated_list()
- self.statemachine.node += enumlist
+ self.parent += enumlist
enumlist['enumtype'] = sequence
if ordinal != 1:
enumlist['start'] = ordinal
enumlist['prefix'] = self.enum.formatinfo[format].prefix
enumlist['suffix'] = self.enum.formatinfo[format].suffix
- listitem, blankfinish = self.list_item(match.end())
+ listitem, blank_finish = self.list_item(match.end())
enumlist += listitem
- offset = self.statemachine.lineoffset + 1 # next line
- newlineoffset, blankfinish = self.nestedlistparse(
- self.statemachine.inputlines[offset:],
- inputoffset=self.statemachine.abslineoffset() + 1,
- node=enumlist, initialstate='EnumeratedList',
- blankfinish=blankfinish,
- extrasettings={'lastordinal': ordinal, 'format': format})
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Enumerated list')
- self.gotoline(newlineoffset)
- return [], nextstate, []
-
- def parse_enumerator(self, match, expectedsequence=None):
+ offset = self.state_machine.line_offset + 1 # next line
+ newline_offset, blank_finish = self.nested_list_parse(
+ self.state_machine.input_lines[offset:],
+ input_offset=self.state_machine.abs_line_offset() + 1,
+ node=enumlist, initial_state='EnumeratedList',
+ blank_finish=blank_finish,
+ extra_settings={'lastordinal': ordinal, 'format': format})
+ if not blank_finish:
+ self.parent += self.unindent_warning('Enumerated list')
+ self.goto_line(newline_offset)
+ return [], next_state, []
+
+ def parse_enumerator(self, match, expected_sequence=None):
"""
Analyze an enumerator and return the results.
@@ -975,7 +1017,7 @@ class Body(RSTState):
``None`` is returned for invalid enumerator text).
The enumerator format has already been determined by the regular
- expression match. If `expectedsequence` is given, that sequence is
+ expression match. If `expected_sequence` is given, that sequence is
tried first. If not, we check for Roman numeral 1. This way,
single-character Roman numerals (which are also alphabetical) can be
matched. If no sequence has been matched, all sequences are checked in
@@ -990,10 +1032,10 @@ class Body(RSTState):
raise ParserError, 'enumerator format not matched'
text = groupdict[format][self.enum.formatinfo[format].start
:self.enum.formatinfo[format].end]
- if expectedsequence:
+ if expected_sequence:
try:
- if self.enum.sequenceregexps[expectedsequence].match(text):
- sequence = expectedsequence
+ if self.enum.sequenceregexps[expected_sequence].match(text):
+ sequence = expected_sequence
except KeyError: # shouldn't happen
raise ParserError, 'unknown sequence: %s' % sequence
else:
@@ -1013,27 +1055,27 @@ class Body(RSTState):
ordinal = None
return format, sequence, text, ordinal
- def field_marker(self, match, context, nextstate):
+ def field_marker(self, match, context, next_state):
"""Field list item."""
fieldlist = nodes.field_list()
- self.statemachine.node += fieldlist
- field, blankfinish = self.field(match)
+ self.parent += fieldlist
+ field, blank_finish = self.field(match)
fieldlist += field
- offset = self.statemachine.lineoffset + 1 # next line
- newlineoffset, blankfinish = self.nestedlistparse(
- self.statemachine.inputlines[offset:],
- inputoffset=self.statemachine.abslineoffset() + 1,
- node=fieldlist, initialstate='FieldList',
- blankfinish=blankfinish)
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Field list')
- self.gotoline(newlineoffset)
- return [], nextstate, []
+ offset = self.state_machine.line_offset + 1 # next line
+ newline_offset, blank_finish = self.nested_list_parse(
+ self.state_machine.input_lines[offset:],
+ input_offset=self.state_machine.abs_line_offset() + 1,
+ node=fieldlist, initial_state='FieldList',
+ blank_finish=blank_finish)
+ if not blank_finish:
+ self.parent += self.unindent_warning('Field list')
+ self.goto_line(newline_offset)
+ return [], next_state, []
def field(self, match):
name, args = self.parse_field_marker(match)
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
fieldnode = nodes.field()
fieldnode += nodes.field_name(name, name)
for arg in args:
@@ -1041,8 +1083,9 @@ class Body(RSTState):
fieldbody = nodes.field_body('\n'.join(indented))
fieldnode += fieldbody
if indented:
- self.nestedparse(indented, inputoffset=lineoffset, node=fieldbody)
- return fieldnode, blankfinish
+ self.nested_parse(indented, input_offset=line_offset,
+ node=fieldbody)
+ return fieldnode, blank_finish
def parse_field_marker(self, match):
"""Extract & return name & argument list from a field marker match."""
@@ -1051,48 +1094,50 @@ class Body(RSTState):
tokens = field.split()
return tokens[0], tokens[1:] # first == name, others == args
- def option_marker(self, match, context, nextstate):
+ def option_marker(self, match, context, next_state):
"""Option list item."""
optionlist = nodes.option_list()
try:
- listitem, blankfinish = self.option_list_item(match)
- except MarkupError, detail: # shouldn't happen; won't match pattern
- msg = self.statemachine.memo.reporter.error(
+ listitem, blank_finish = self.option_list_item(match)
+ except MarkupError, detail: # shouldn't happen; won't match pattern
+ msg = self.reporter.error(
('Invalid option list marker at line %s: %s'
- % (self.statemachine.abslineno(), detail)))
- self.statemachine.node += msg
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
- blockquote = self.block_quote(indented, lineoffset)
- self.statemachine.node += blockquote
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Option list')
- return [], nextstate, []
- self.statemachine.node += optionlist
+ % (self.state_machine.abs_line_number(), detail)))
+ self.parent += msg
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
+ blockquote = self.block_quote(indented, line_offset)
+ self.parent += blockquote
+ if not blank_finish:
+ self.parent += self.unindent_warning('Option list')
+ return [], next_state, []
+ self.parent += optionlist
optionlist += listitem
- offset = self.statemachine.lineoffset + 1 # next line
- newlineoffset, blankfinish = self.nestedlistparse(
- self.statemachine.inputlines[offset:],
- inputoffset=self.statemachine.abslineoffset() + 1,
- node=optionlist, initialstate='OptionList',
- blankfinish=blankfinish)
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Option list')
- self.gotoline(newlineoffset)
- return [], nextstate, []
+ offset = self.state_machine.line_offset + 1 # next line
+ newline_offset, blank_finish = self.nested_list_parse(
+ self.state_machine.input_lines[offset:],
+ input_offset=self.state_machine.abs_line_offset() + 1,
+ node=optionlist, initial_state='OptionList',
+ blank_finish=blank_finish)
+ if not blank_finish:
+ self.parent += self.unindent_warning('Option list')
+ self.goto_line(newline_offset)
+ return [], next_state, []
def option_list_item(self, match):
options = self.parse_option_marker(match)
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
if not indented: # not an option list item
raise statemachine.TransitionCorrection('text')
option_group = nodes.option_group('', *options)
description = nodes.description('\n'.join(indented))
- option_list_item = nodes.option_list_item('', option_group, description)
+ option_list_item = nodes.option_list_item('', option_group,
+ description)
if indented:
- self.nestedparse(indented, inputoffset=lineoffset, node=description)
- return option_list_item, blankfinish
+ self.nested_parse(indented, input_offset=line_offset,
+ node=description)
+ return option_list_item, blank_finish
def parse_option_marker(self, match):
"""
@@ -1123,84 +1168,85 @@ class Body(RSTState):
optionstring))
return optlist
- def doctest(self, match, context, nextstate):
- data = '\n'.join(self.statemachine.gettextblock())
- self.statemachine.node += nodes.doctest_block(data, data)
- return [], nextstate, []
+ def doctest(self, match, context, next_state):
+ data = '\n'.join(self.state_machine.get_text_block())
+ self.parent += nodes.doctest_block(data, data)
+ return [], next_state, []
- def tabletop(self, match, context, nextstate):
+ def table_top(self, match, context, next_state):
"""Top border of a table."""
- nodelist, blankfinish = self.table()
- self.statemachine.node += nodelist
- if not blankfinish:
- msg = self.statemachine.memo.reporter.warning(
+ nodelist, blank_finish = self.table()
+ self.parent += nodelist
+ if not blank_finish:
+ msg = self.reporter.warning(
'Blank line required after table at line %s.'
- % (self.statemachine.abslineno() + 1))
- self.statemachine.node += msg
- return [], nextstate, []
+ % (self.state_machine.abs_line_number() + 1))
+ self.parent += msg
+ return [], next_state, []
def table(self):
"""Parse a table."""
- block, messages, blankfinish = self.isolatetable()
+ block, messages, blank_finish = self.isolate_table()
if block:
try:
tabledata = self.tableparser.parse(block)
- tableline = self.statemachine.abslineno() - len(block) + 1
- table = self.buildtable(tabledata, tableline)
+ tableline = (self.state_machine.abs_line_number() - len(block)
+ + 1)
+ table = self.build_table(tabledata, tableline)
nodelist = [table] + messages
except TableMarkupError, detail:
- nodelist = self.malformedtable(block, str(detail)) + messages
+ nodelist = self.malformed_table(block, str(detail)) + messages
else:
nodelist = messages
- return nodelist, blankfinish
+ return nodelist, blank_finish
- def isolatetable(self):
+ def isolate_table(self):
messages = []
- blankfinish = 1
+ blank_finish = 1
try:
- block = self.statemachine.getunindented()
+ block = self.state_machine.get_text_block(flush_left=1)
except statemachine.UnexpectedIndentationError, instance:
block, lineno = instance.args
- messages.append(self.statemachine.memo.reporter.error(
+ messages.append(self.reporter.error(
'Unexpected indentation at line %s.' % lineno))
- blankfinish = 0
+ blank_finish = 0
width = len(block[0].strip())
for i in range(len(block)):
block[i] = block[i].strip()
if block[i][0] not in '+|': # check left edge
- blankfinish = 0
- self.statemachine.previousline(len(block) - i)
+ blank_finish = 0
+ self.state_machine.previous_line(len(block) - i)
del block[i:]
break
- if not self.tabletoppat.match(block[-1]): # find bottom
- blankfinish = 0
+ if not self.table_top_pat.match(block[-1]): # find bottom
+ blank_finish = 0
# from second-last to third line of table:
for i in range(len(block) - 2, 1, -1):
- if self.tabletoppat.match(block[i]):
- self.statemachine.previousline(len(block) - i + 1)
+ if self.table_top_pat.match(block[i]):
+ self.state_machine.previous_line(len(block) - i + 1)
del block[i+1:]
break
else:
- messages.extend(self.malformedtable(block))
- return [], messages, blankfinish
+ messages.extend(self.malformed_table(block))
+ return [], messages, blank_finish
for i in range(len(block)): # check right edge
if len(block[i]) != width or block[i][-1] not in '+|':
- messages.extend(self.malformedtable(block))
- return [], messages, blankfinish
- return block, messages, blankfinish
+ messages.extend(self.malformed_table(block))
+ return [], messages, blank_finish
+ return block, messages, blank_finish
- def malformedtable(self, block, detail=''):
+ def malformed_table(self, block, detail=''):
data = '\n'.join(block)
message = 'Malformed table at line %s; formatting as a ' \
- 'literal block.' % (self.statemachine.abslineno()
+ 'literal block.' % (self.state_machine.abs_line_number()
- len(block) + 1)
if detail:
message += '\n' + detail
- nodelist = [self.statemachine.memo.reporter.error(message),
+ nodelist = [self.reporter.error(message),
nodes.literal_block(data, data)]
return nodelist
- def buildtable(self, tabledata, tableline):
+ def build_table(self, tabledata, tableline):
colspecs, headrows, bodyrows = tabledata
table = nodes.table()
tgroup = nodes.tgroup(cols=len(colspecs))
@@ -1211,14 +1257,14 @@ class Body(RSTState):
thead = nodes.thead()
tgroup += thead
for row in headrows:
- thead += self.buildtablerow(row, tableline)
+ thead += self.build_table_row(row, tableline)
tbody = nodes.tbody()
tgroup += tbody
for row in bodyrows:
- tbody += self.buildtablerow(row, tableline)
+ tbody += self.build_table_row(row, tableline)
return table
- def buildtablerow(self, rowdata, tableline):
+ def build_table_row(self, rowdata, tableline):
row = nodes.row()
for cell in rowdata:
if cell is None:
@@ -1232,8 +1278,8 @@ class Body(RSTState):
entry = nodes.entry(**attributes)
row += entry
if ''.join(cellblock):
- self.nestedparse(cellblock, inputoffset=tableline+offset,
- node=entry)
+ self.nested_parse(cellblock, input_offset=tableline+offset,
+ node=entry)
return row
@@ -1257,8 +1303,8 @@ class Body(RSTState):
: # end of reference name
(?:[ ]+|$) # followed by whitespace
"""
- % (RSTState.inline.non_whitespace_escape_before,
- RSTState.inline.non_whitespace_escape_before),
+ % (Inliner.non_whitespace_escape_before,
+ Inliner.non_whitespace_escape_before),
re.VERBOSE),
reference=re.compile(r"""
(?:
@@ -1268,12 +1314,12 @@ class Body(RSTState):
(?![ ]) # not space
(.+?) # hyperlink phrase
%s # not whitespace or escape
- `_ # close backquote & reference mark
+ `_ # close backquote, reference mark
)
$ # end of string
""" %
- (RSTState.inline.simplename,
- RSTState.inline.non_whitespace_escape_before,),
+ (Inliner.simplename,
+ Inliner.non_whitespace_escape_before,),
re.VERBOSE),
substitution=re.compile(r"""
(?:
@@ -1284,7 +1330,7 @@ class Body(RSTState):
)
(?:[ ]+|$) # followed by whitespace
""" %
- RSTState.inline.non_whitespace_escape_before,
+ Inliner.non_whitespace_escape_before,
re.VERBOSE),)
explicit.groups = Stuff(
target=Stuff(quote=1, name=2),
@@ -1292,53 +1338,53 @@ class Body(RSTState):
substitution=Stuff(name=1))
def footnote(self, match):
- indented, indent, offset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
+ indented, indent, offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
label = match.group(1)
- name = normname(label)
+ name = normalize_name(label)
footnote = nodes.footnote('\n'.join(indented))
if name[0] == '#': # auto-numbered
name = name[1:] # autonumber label
footnote['auto'] = 1
if name:
footnote['name'] = name
- self.statemachine.memo.document.note_autofootnote(footnote)
+ self.document.note_autofootnote(footnote)
elif name == '*': # auto-symbol
name = ''
footnote['auto'] = '*'
- self.statemachine.memo.document.note_symbol_footnote(footnote)
+ self.document.note_symbol_footnote(footnote)
else: # manually numbered
footnote += nodes.label('', label)
footnote['name'] = name
- self.statemachine.memo.document.note_footnote(footnote)
+ self.document.note_footnote(footnote)
if name:
- self.statemachine.memo.document.note_explicit_target(footnote,
+ self.document.note_explicit_target(footnote,
footnote)
if indented:
- self.nestedparse(indented, inputoffset=offset, node=footnote)
- return [footnote], blankfinish
+ self.nested_parse(indented, input_offset=offset, node=footnote)
+ return [footnote], blank_finish
def citation(self, match):
- indented, indent, offset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
+ indented, indent, offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
label = match.group(1)
- name = normname(label)
+ name = normalize_name(label)
citation = nodes.citation('\n'.join(indented))
citation += nodes.label('', label)
citation['name'] = name
- self.statemachine.memo.document.note_citation(citation)
- self.statemachine.memo.document.note_explicit_target(citation, citation)
+ self.document.note_citation(citation)
+ self.document.note_explicit_target(citation, citation)
if indented:
- self.nestedparse(indented, inputoffset=offset, node=citation)
- return [citation], blankfinish
+ self.nested_parse(indented, input_offset=offset, node=citation)
+ return [citation], blank_finish
def hyperlink_target(self, match):
pattern = self.explicit.patterns.target
namegroup = self.explicit.groups.target.name
- lineno = self.statemachine.abslineno()
- block, indent, offset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end(), uptoblank=1,
- stripindent=0)
+ lineno = self.state_machine.abs_line_number()
+ block, indent, offset, blank_finish = \
+ self.state_machine.get_first_known_indented(
+ match.end(), until_blank=1, strip_indent=0)
blocktext = match.string[:match.end()] + '\n'.join(block)
block = [escape2null(line) for line in block]
escaped = block[0]
@@ -1357,58 +1403,58 @@ class Body(RSTState):
block[0] = (block[0] + ' ')[targetmatch.end()-len(escaped)-1:].strip()
if block and block[-1].strip()[-1:] == '_': # possible indirect target
reference = ' '.join([line.strip() for line in block])
- refname = self.isreference(reference)
+ refname = self.is_reference(reference)
if refname:
target = nodes.target(blocktext, '', refname=refname)
- self.addtarget(targetmatch.group(namegroup), '', target)
- self.statemachine.memo.document.note_indirect_target(target)
- return [target], blankfinish
+ self.add_target(targetmatch.group(namegroup), '', target)
+ self.document.note_indirect_target(target)
+ return [target], blank_finish
nodelist = []
reference = ''.join([line.strip() for line in block])
if reference.find(' ') != -1:
- warning = self.statemachine.memo.reporter.warning(
+ warning = self.reporter.warning(
'Hyperlink target at line %s contains whitespace. '
'Perhaps a footnote was intended?'
- % (self.statemachine.abslineno() - len(block) + 1), '',
- nodes.literal_block(blocktext, blocktext))
+ % (self.state_machine.abs_line_number() - len(block) + 1),
+ '', nodes.literal_block(blocktext, blocktext))
nodelist.append(warning)
else:
unescaped = unescape(reference)
target = nodes.target(blocktext, '')
- self.addtarget(targetmatch.group(namegroup), unescaped, target)
+ self.add_target(targetmatch.group(namegroup), unescaped, target)
nodelist.append(target)
- return nodelist, blankfinish
+ return nodelist, blank_finish
- def isreference(self, reference):
- match = self.explicit.patterns.reference.match(normname(reference))
+ def is_reference(self, reference):
+ match = self.explicit.patterns.reference.match(normalize_name(reference))
if not match:
return None
return unescape(match.group(self.explicit.groups.reference.simple)
or match.group(self.explicit.groups.reference.phrase))
- def addtarget(self, targetname, refuri, target):
+ def add_target(self, targetname, refuri, target):
if targetname:
- name = normname(unescape(targetname))
+ name = normalize_name(unescape(targetname))
target['name'] = name
if refuri:
target['refuri'] = refuri
- self.statemachine.memo.document.note_external_target(target)
+ self.document.note_external_target(target)
else:
- self.statemachine.memo.document.note_internal_target(target)
- self.statemachine.memo.document.note_explicit_target(
- target, self.statemachine.node)
+ self.document.note_internal_target(target)
+ self.document.note_explicit_target(
+ target, self.parent)
else: # anonymous target
if refuri:
target['refuri'] = refuri
target['anonymous'] = 1
- self.statemachine.memo.document.note_anonymous_target(target)
+ self.document.note_anonymous_target(target)
- def substitutiondef(self, match):
+ def substitution_def(self, match):
pattern = self.explicit.patterns.substitution
- lineno = self.statemachine.abslineno()
- block, indent, offset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end(),
- stripindent=0)
+ lineno = self.state_machine.abs_line_number()
+ block, indent, offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end(),
+ strip_indent=0)
blocktext = (match.string[:match.end()] + '\n'.join(block))
block = [escape2null(line) for line in block]
escaped = block[0].rstrip()
@@ -1429,65 +1475,66 @@ class Body(RSTState):
del block[0]
offset += 1
subname = subdefmatch.group(self.explicit.groups.substitution.name)
- name = normname(subname)
+ name = normalize_name(subname)
substitutionnode = nodes.substitution_definition(
blocktext, name=name, alt=subname)
if block:
block[0] = block[0].strip()
- newabsoffset, blankfinish = self.nestedlistparse(
- block, inputoffset=offset, node=substitutionnode,
- initialstate='SubstitutionDef', blankfinish=blankfinish)
- self.statemachine.previousline(
+ newabsoffset, blank_finish = self.nested_list_parse(
+ block, input_offset=offset, node=substitutionnode,
+ initial_state='SubstitutionDef', blank_finish=blank_finish)
+ self.state_machine.previous_line(
len(block) + offset - newabsoffset - 1)
i = 0
for node in substitutionnode[:]:
if not (isinstance(node, nodes.Inline) or
isinstance(node, nodes.Text)):
- self.statemachine.node += substitutionnode[i]
+ self.parent += substitutionnode[i]
del substitutionnode[i]
else:
i += 1
if len(substitutionnode) == 0:
- msg = self.statemachine.memo.reporter.warning(
+ msg = self.reporter.warning(
'Substitution definition "%s" empty or invalid at line '
- '%s.' % (subname, self.statemachine.abslineno()), '',
- nodes.literal_block(blocktext, blocktext))
- self.statemachine.node += msg
+ '%s.' % (subname, self.state_machine.abs_line_number()),
+ '', nodes.literal_block(blocktext, blocktext))
+ self.parent += msg
else:
del substitutionnode['alt']
- self.statemachine.memo.document.note_substitution_def(
- substitutionnode, self.statemachine.node)
- return [substitutionnode], blankfinish
+ self.document.note_substitution_def(
+ substitutionnode, self.parent)
+ return [substitutionnode], blank_finish
else:
- msg = self.statemachine.memo.reporter.warning(
+ msg = self.reporter.warning(
'Substitution definition "%s" missing contents at line %s.'
- % (subname, self.statemachine.abslineno()), '',
+ % (subname, self.state_machine.abs_line_number()), '',
nodes.literal_block(blocktext, blocktext))
- self.statemachine.node += msg
- return [], blankfinish
+ self.parent += msg
+ return [], blank_finish
def directive(self, match, **attributes):
- typename = match.group(1)
- directivefunction = directives.directive(
- typename, self.statemachine.memo.language)
+ type_name = match.group(1)
+ directivefunction = directives.directive(type_name,
+ self.memo.language)
data = match.string[match.end():].strip()
if directivefunction:
- return directivefunction(match, typename, data, self,
- self.statemachine, attributes)
+ return directivefunction(match, type_name, data, self,
+ self.state_machine, attributes)
else:
- return self.unknowndirective(typename, data)
+ return self.unknown_directive(type_name, data)
- def unknowndirective(self, typename, data):
- lineno = self.statemachine.abslineno()
- indented, indent, offset, blankfinish = \
- self.statemachine.getfirstknownindented(0, stripindent=0)
+ def unknown_directive(self, type_name, data):
+ lineno = self.state_machine.abs_line_number()
+ indented, indent, offset, blank_finish = \
+ self.state_machine.get_first_known_indented(0, strip_indent=0)
text = '\n'.join(indented)
- error = self.statemachine.memo.reporter.error(
- 'Unknown directive type "%s" at line %s.' % (typename, lineno),
+ error = self.reporter.error(
+ 'Unknown directive type "%s" at line %s.' % (type_name, lineno),
'', nodes.literal_block(text, text))
- return [error], blankfinish
+ return [error], blank_finish
- def parse_extension_attributes(self, attribute_spec, datalines, blankfinish):
+ def parse_extension_attributes(self, attribute_spec, datalines,
+ blank_finish):
"""
Parse `datalines` for a field list containing extension attributes
matching `attribute_spec`.
@@ -1496,37 +1543,38 @@ class Body(RSTState):
- `attribute_spec`: a mapping of attribute name to conversion
function, which should raise an exception on bad input.
- `datalines`: a list of input strings.
- - `blankfinish`:
+ - `blank_finish`:
:Return:
- Success value, 1 or 0.
- An attribute dictionary on success, an error string on failure.
- - Updated `blankfinish` flag.
+ - Updated `blank_finish` flag.
"""
node = nodes.field_list()
- newlineoffset, blankfinish = self.nestedlistparse(
- datalines, 0, node, initialstate='FieldList',
- blankfinish=blankfinish)
- if newlineoffset != len(datalines): # incomplete parse of block
- return 0, 'invalid attribute block', blankfinish
+ newline_offset, blank_finish = self.nested_list_parse(
+ datalines, 0, node, initial_state='FieldList',
+ blank_finish=blank_finish)
+ if newline_offset != len(datalines): # incomplete parse of block
+ return 0, 'invalid attribute block', blank_finish
try:
- attributes = utils.extract_extension_attributes(node, attribute_spec)
+ attributes = utils.extract_extension_attributes(node,
+ attribute_spec)
except KeyError, detail:
- return 0, ('unknown attribute: "%s"' % detail), blankfinish
+ return 0, ('unknown attribute: "%s"' % detail), blank_finish
except (ValueError, TypeError), detail:
- return 0, ('invalid attribute value:\n%s' % detail), blankfinish
+ return 0, ('invalid attribute value:\n%s' % detail), blank_finish
except utils.ExtensionAttributeError, detail:
- return 0, ('invalid attribute data: %s' % detail), blankfinish
- return 1, attributes, blankfinish
+ return 0, ('invalid attribute data: %s' % detail), blank_finish
+ return 1, attributes, blank_finish
def comment(self, match):
if not match.string[match.end():].strip() \
- and self.statemachine.nextlineblank(): # an empty comment?
+ and self.state_machine.is_next_line_blank(): # an empty comment?
return [nodes.comment()], 1 # "A tiny but practical wart."
- indented, indent, offset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
+ indented, indent, offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
text = '\n'.join(indented)
- return [nodes.comment(text, text)], blankfinish
+ return [nodes.comment(text, text)], blank_finish
explicit.constructs = [
(footnote,
@@ -1544,20 +1592,20 @@ class Body(RSTState):
)
\]
(?:[ ]+|$) # whitespace or end of line
- """ % RSTState.inline.simplename, re.VERBOSE)),
+ """ % Inliner.simplename, re.VERBOSE)),
(citation,
re.compile(r"""
\.\.[ ]+ # explicit markup start
\[(%s)\] # citation label
(?:[ ]+|$) # whitespace or end of line
- """ % RSTState.inline.simplename, re.VERBOSE)),
+ """ % Inliner.simplename, re.VERBOSE)),
(hyperlink_target,
re.compile(r"""
\.\.[ ]+ # explicit markup start
_ # target indicator
(?![ ]) # first char. not space
""", re.VERBOSE)),
- (substitutiondef,
+ (substitution_def,
re.compile(r"""
\.\.[ ]+ # explicit markup start
\| # substitution indicator
@@ -1569,14 +1617,14 @@ class Body(RSTState):
(%s) # directive name
:: # directive delimiter
(?:[ ]+|$) # whitespace or end of line
- """ % RSTState.inline.simplename, re.VERBOSE))]
+ """ % Inliner.simplename, re.VERBOSE))]
- def explicit_markup(self, match, context, nextstate):
+ def explicit_markup(self, match, context, next_state):
"""Footnotes, hyperlink targets, directives, comments."""
- nodelist, blankfinish = self.explicit_construct(match)
- self.statemachine.node += nodelist
- self.explicitlist(blankfinish)
- return [], nextstate, []
+ nodelist, blank_finish = self.explicit_construct(match)
+ self.parent += nodelist
+ self.explicit_list(blank_finish)
+ return [], next_state, []
def explicit_construct(self, match):
"""Determine which explicit construct this is, parse & return it."""
@@ -1588,80 +1636,81 @@ class Body(RSTState):
return method(self, expmatch)
except MarkupError, detail: # never reached?
errors.append(
- self.statemachine.memo.reporter.warning('%s: %s'
+ self.reporter.warning('%s: %s'
% (detail.__class__.__name__, detail)))
break
- nodelist, blankfinish = self.comment(match)
- return nodelist + errors, blankfinish
+ nodelist, blank_finish = self.comment(match)
+ return nodelist + errors, blank_finish
- def explicitlist(self, blankfinish):
+ def explicit_list(self, blank_finish):
"""
Create a nested state machine for a series of explicit markup
constructs (including anonymous hyperlink targets).
"""
- offset = self.statemachine.lineoffset + 1 # next line
- newlineoffset, blankfinish = self.nestedlistparse(
- self.statemachine.inputlines[offset:],
- inputoffset=self.statemachine.abslineoffset() + 1,
- node=self.statemachine.node, initialstate='Explicit',
- blankfinish=blankfinish)
- self.gotoline(newlineoffset)
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Explicit markup')
-
- def anonymous(self, match, context, nextstate):
+ offset = self.state_machine.line_offset + 1 # next line
+ newline_offset, blank_finish = self.nested_list_parse(
+ self.state_machine.input_lines[offset:],
+ input_offset=self.state_machine.abs_line_offset() + 1,
+ node=self.parent, initial_state='Explicit',
+ blank_finish=blank_finish)
+ self.goto_line(newline_offset)
+ if not blank_finish:
+ self.parent += self.unindent_warning('Explicit markup')
+
+ def anonymous(self, match, context, next_state):
"""Anonymous hyperlink targets."""
- nodelist, blankfinish = self.anonymous_target(match)
- self.statemachine.node += nodelist
- self.explicitlist(blankfinish)
- return [], nextstate, []
+ nodelist, blank_finish = self.anonymous_target(match)
+ self.parent += nodelist
+ self.explicit_list(blank_finish)
+ return [], next_state, []
def anonymous_target(self, match):
- block, indent, offset, blankfinish \
- = self.statemachine.getfirstknownindented(match.end(),
- uptoblank=1)
+ block, indent, offset, blank_finish \
+ = self.state_machine.get_first_known_indented(match.end(),
+ until_blank=1)
blocktext = match.string[:match.end()] + '\n'.join(block)
if block and block[-1].strip()[-1:] == '_': # possible indirect target
- reference = escape2null(' '.join([line.strip() for line in block]))
- refname = self.isreference(reference)
+ reference = escape2null(' '.join([line.strip()
+ for line in block]))
+ refname = self.is_reference(reference)
if refname:
target = nodes.target(blocktext, '', refname=refname,
anonymous=1)
- self.statemachine.memo.document.note_anonymous_target(target)
- self.statemachine.memo.document.note_indirect_target(target)
- return [target], blankfinish
+ self.document.note_anonymous_target(target)
+ self.document.note_indirect_target(target)
+ return [target], blank_finish
nodelist = []
reference = escape2null(''.join([line.strip() for line in block]))
if reference.find(' ') != -1:
- warning = self.statemachine.memo.reporter.warning(
- 'Anonymous hyperlink target at line %s contains whitespace. '
- 'Perhaps a footnote was intended?'
- % (self.statemachine.abslineno() - len(block) + 1), '',
- nodes.literal_block(blocktext, blocktext))
+ warning = self.reporter.warning(
+ 'Anonymous hyperlink target at line %s contains '
+ 'whitespace. Perhaps a footnote was intended?'
+ % (self.state_machine.abs_line_number() - len(block) + 1),
+ '', nodes.literal_block(blocktext, blocktext))
nodelist.append(warning)
else:
target = nodes.target(blocktext, '', anonymous=1)
if reference:
unescaped = unescape(reference)
target['refuri'] = unescaped
- self.statemachine.memo.document.note_anonymous_target(target)
+ self.document.note_anonymous_target(target)
nodelist.append(target)
- return nodelist, blankfinish
+ return nodelist, blank_finish
- def line(self, match, context, nextstate):
+ def line(self, match, context, next_state):
"""Section title overline or transition marker."""
- if self.statemachine.matchtitles:
+ if self.state_machine.match_titles:
return [match.string], 'Line', []
else:
- blocktext = self.statemachine.line
- msg = self.statemachine.memo.reporter.severe(
+ blocktext = self.state_machine.line
+ msg = self.reporter.severe(
'Unexpected section title or transition at line %s.'
- % self.statemachine.abslineno(), '',
+ % self.state_machine.abs_line_number(), '',
nodes.literal_block(blocktext, blocktext))
- self.statemachine.node += msg
- return [], nextstate, []
+ self.parent += msg
+ return [], next_state, []
- def text(self, match, context, nextstate):
+ def text(self, match, context, next_state):
"""Titles, definition lists, paragraphs."""
return [match.string], 'Text', []
@@ -1675,38 +1724,40 @@ class RFC2822Body(Body):
patterns = Body.patterns.copy() # can't modify the original
patterns['rfc2822'] = r'[!-9;-~]+:( +|$)'
- initialtransitions = [(name, 'Body') for name in Body.initialtransitions]
- initialtransitions.insert(-1, ('rfc2822', 'Body')) # just before 'text'
+ initial_transitions = [(name, 'Body')
+ for name in Body.initial_transitions]
+ initial_transitions.insert(-1, ('rfc2822', 'Body')) # just before 'text'
- def rfc2822(self, match, context, nextstate):
+ def rfc2822(self, match, context, next_state):
"""RFC2822-style field list item."""
- fieldlist = nodes.field_list()
- self.statemachine.node += fieldlist
- field, blankfinish = self.rfc2822_field(match)
+ fieldlist = nodes.field_list(CLASS='rfc2822')
+ self.parent += fieldlist
+ field, blank_finish = self.rfc2822_field(match)
fieldlist += field
- offset = self.statemachine.lineoffset + 1 # next line
- newlineoffset, blankfinish = self.nestedlistparse(
- self.statemachine.inputlines[offset:],
- inputoffset=self.statemachine.abslineoffset() + 1,
- node=fieldlist, initialstate='RFC2822List',
- blankfinish=blankfinish)
- if not blankfinish:
- self.statemachine.node += self.unindent_warning(
+ offset = self.state_machine.line_offset + 1 # next line
+ newline_offset, blank_finish = self.nested_list_parse(
+ self.state_machine.input_lines[offset:],
+ input_offset=self.state_machine.abs_line_offset() + 1,
+ node=fieldlist, initial_state='RFC2822List',
+ blank_finish=blank_finish)
+ if not blank_finish:
+ self.parent += self.unindent_warning(
'RFC2822-style field list')
- self.gotoline(newlineoffset)
- return [], nextstate, []
+ self.goto_line(newline_offset)
+ return [], next_state, []
def rfc2822_field(self, match):
name = match.string[:match.string.find(':')]
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
fieldnode = nodes.field()
fieldnode += nodes.field_name(name, name)
fieldbody = nodes.field_body('\n'.join(indented))
fieldnode += fieldbody
if indented:
- self.nestedparse(indented, inputoffset=lineoffset, node=fieldbody)
- return fieldnode, blankfinish
+ self.nested_parse(indented, input_offset=line_offset,
+ node=fieldbody)
+ return fieldnode, blank_finish
class SpecializedBody(Body):
@@ -1718,9 +1769,9 @@ class SpecializedBody(Body):
subclasses to re-enable.
"""
- def invalid_input(self, match=None, context=None, nextstate=None):
+ def invalid_input(self, match=None, context=None, next_state=None):
"""Not a compound element member. Abort this state machine."""
- self.statemachine.previousline() # back up so parent SM can reassess
+ self.state_machine.previous_line() # back up so parent SM can reassess
raise EOFError
indent = invalid_input
@@ -1729,7 +1780,7 @@ class SpecializedBody(Body):
field_marker = invalid_input
option_marker = invalid_input
doctest = invalid_input
- tabletop = invalid_input
+ table_top = invalid_input
explicit_markup = invalid_input
anonymous = invalid_input
line = invalid_input
@@ -1740,14 +1791,14 @@ class BulletList(SpecializedBody):
"""Second and subsequent bullet_list list_items."""
- def bullet(self, match, context, nextstate):
+ def bullet(self, match, context, next_state):
"""Bullet list item."""
- if match.string[0] != self.statemachine.node['bullet']:
+ if match.string[0] != self.parent['bullet']:
# different bullet: new list
self.invalid_input()
- listitem, blankfinish = self.list_item(match.end())
- self.statemachine.node += listitem
- self.blankfinish = blankfinish
+ listitem, blank_finish = self.list_item(match.end())
+ self.parent += listitem
+ self.blank_finish = blank_finish
return [], 'BulletList', []
@@ -1755,7 +1806,7 @@ class DefinitionList(SpecializedBody):
"""Second and subsequent definition_list_items."""
- def text(self, match, context, nextstate):
+ def text(self, match, context, next_state):
"""Definition lists."""
return [match.string], 'Definition', []
@@ -1764,18 +1815,18 @@ class EnumeratedList(SpecializedBody):
"""Second and subsequent enumerated_list list_items."""
- def enumerator(self, match, context, nextstate):
+ def enumerator(self, match, context, next_state):
"""Enumerated list item."""
format, sequence, text, ordinal = self.parse_enumerator(
- match, self.statemachine.node['enumtype'])
- if (sequence != self.statemachine.node['enumtype'] or
+ match, self.parent['enumtype'])
+ if (sequence != self.parent['enumtype'] or
format != self.format or
ordinal != self.lastordinal + 1):
# different enumeration: new list
self.invalid_input()
- listitem, blankfinish = self.list_item(match.end())
- self.statemachine.node += listitem
- self.blankfinish = blankfinish
+ listitem, blank_finish = self.list_item(match.end())
+ self.parent += listitem
+ self.blank_finish = blank_finish
self.lastordinal = ordinal
return [], 'EnumeratedList', []
@@ -1784,11 +1835,11 @@ class FieldList(SpecializedBody):
"""Second and subsequent field_list fields."""
- def field_marker(self, match, context, nextstate):
+ def field_marker(self, match, context, next_state):
"""Field list field."""
- field, blankfinish = self.field(match)
- self.statemachine.node += field
- self.blankfinish = blankfinish
+ field, blank_finish = self.field(match)
+ self.parent += field
+ self.blank_finish = blank_finish
return [], 'FieldList', []
@@ -1796,14 +1847,14 @@ class OptionList(SpecializedBody):
"""Second and subsequent option_list option_list_items."""
- def option_marker(self, match, context, nextstate):
+ def option_marker(self, match, context, next_state):
"""Option list item."""
try:
- option_list_item, blankfinish = self.option_list_item(match)
+ option_list_item, blank_finish = self.option_list_item(match)
except MarkupError, detail:
self.invalid_input()
- self.statemachine.node += option_list_item
- self.blankfinish = blankfinish
+ self.parent += option_list_item
+ self.blank_finish = blank_finish
return [], 'OptionList', []
@@ -1812,13 +1863,13 @@ class RFC2822List(SpecializedBody, RFC2822Body):
"""Second and subsequent RFC2822-style field_list fields."""
patterns = RFC2822Body.patterns
- initialtransitions = RFC2822Body.initialtransitions
+ initial_transitions = RFC2822Body.initial_transitions
- def rfc2822(self, match, context, nextstate):
+ def rfc2822(self, match, context, next_state):
"""RFC2822-style field list item."""
- field, blankfinish = self.rfc2822_field(match)
- self.statemachine.node += field
- self.blankfinish = blankfinish
+ field, blank_finish = self.rfc2822_field(match)
+ self.parent += field
+ self.blank_finish = blank_finish
return [], 'RFC2822List', []
blank = SpecializedBody.invalid_input
@@ -1828,19 +1879,19 @@ class Explicit(SpecializedBody):
"""Second and subsequent explicit markup construct."""
- def explicit_markup(self, match, context, nextstate):
+ def explicit_markup(self, match, context, next_state):
"""Footnotes, hyperlink targets, directives, comments."""
- nodelist, blankfinish = self.explicit_construct(match)
- self.statemachine.node += nodelist
- self.blankfinish = blankfinish
- return [], nextstate, []
+ nodelist, blank_finish = self.explicit_construct(match)
+ self.parent += nodelist
+ self.blank_finish = blank_finish
+ return [], next_state, []
- def anonymous(self, match, context, nextstate):
+ def anonymous(self, match, context, next_state):
"""Anonymous hyperlink targets."""
- nodelist, blankfinish = self.anonymous_target(match)
- self.statemachine.node += nodelist
- self.blankfinish = blankfinish
- return [], nextstate, []
+ nodelist, blank_finish = self.anonymous_target(match)
+ self.parent += nodelist
+ self.blank_finish = blank_finish
+ return [], next_state, []
class SubstitutionDef(Body):
@@ -1850,24 +1901,24 @@ class SubstitutionDef(Body):
"""
patterns = {
- 'embedded_directive': r'(%s)::( +|$)' % RSTState.inline.simplename,
+ 'embedded_directive': r'(%s)::( +|$)' % Inliner.simplename,
'text': r''}
- initialtransitions = ['embedded_directive', 'text']
+ initial_transitions = ['embedded_directive', 'text']
- def embedded_directive(self, match, context, nextstate):
- if self.statemachine.node.has_key('alt'):
- attributes = {'alt': self.statemachine.node['alt']}
+ def embedded_directive(self, match, context, next_state):
+ if self.parent.has_key('alt'):
+ attributes = {'alt': self.parent['alt']}
else:
attributes = {}
- nodelist, blankfinish = self.directive(match, **attributes)
- self.statemachine.node += nodelist
- if not self.statemachine.ateof():
- self.blankfinish = blankfinish
+ nodelist, blank_finish = self.directive(match, **attributes)
+ self.parent += nodelist
+ if not self.state_machine.at_eof():
+ self.blank_finish = blank_finish
raise EOFError
- def text(self, match, context, nextstate):
- if not self.statemachine.ateof():
- self.blankfinish = self.statemachine.nextlineblank()
+ def text(self, match, context, next_state):
+ if not self.state_machine.at_eof():
+ self.blank_finish = self.state_machine.is_next_line_blank()
raise EOFError
@@ -1881,123 +1932,123 @@ class Text(RSTState):
patterns = {'underline': Body.patterns['line'],
'text': r''}
- initialtransitions = [('underline', 'Body'), ('text', 'Body')]
+ initial_transitions = [('underline', 'Body'), ('text', 'Body')]
- def blank(self, match, context, nextstate):
+ def blank(self, match, context, next_state):
"""End of paragraph."""
paragraph, literalnext = self.paragraph(
- context, self.statemachine.abslineno() - 1)
- self.statemachine.node += paragraph
+ context, self.state_machine.abs_line_number() - 1)
+ self.parent += paragraph
if literalnext:
- self.statemachine.node += self.literal_block()
+ self.parent += self.literal_block()
return [], 'Body', []
def eof(self, context):
if context:
paragraph, literalnext = self.paragraph(
- context, self.statemachine.abslineno() - 1)
- self.statemachine.node += paragraph
+ context, self.state_machine.abs_line_number() - 1)
+ self.parent += paragraph
if literalnext:
- self.statemachine.node += self.literal_block()
+ self.parent += self.literal_block()
return []
- def indent(self, match, context, nextstate):
+ def indent(self, match, context, next_state):
"""Definition list item."""
definitionlist = nodes.definition_list()
- definitionlistitem, blankfinish = self.definition_list_item(context)
+ definitionlistitem, blank_finish = self.definition_list_item(context)
definitionlist += definitionlistitem
- self.statemachine.node += definitionlist
- offset = self.statemachine.lineoffset + 1 # next line
- newlineoffset, blankfinish = self.nestedlistparse(
- self.statemachine.inputlines[offset:],
- inputoffset=self.statemachine.abslineoffset() + 1,
- node=definitionlist, initialstate='DefinitionList',
- blankfinish=blankfinish, blankfinishstate='Definition')
- if not blankfinish:
- self.statemachine.node += self.unindent_warning('Definition list')
- self.gotoline(newlineoffset)
+ self.parent += definitionlist
+ offset = self.state_machine.line_offset + 1 # next line
+ newline_offset, blank_finish = self.nested_list_parse(
+ self.state_machine.input_lines[offset:],
+ input_offset=self.state_machine.abs_line_offset() + 1,
+ node=definitionlist, initial_state='DefinitionList',
+ blank_finish=blank_finish, blank_finish_state='Definition')
+ if not blank_finish:
+ self.parent += self.unindent_warning('Definition list')
+ self.goto_line(newline_offset)
return [], 'Body', []
- def underline(self, match, context, nextstate):
+ def underline(self, match, context, next_state):
"""Section title."""
- lineno = self.statemachine.abslineno()
- if not self.statemachine.matchtitles:
- blocktext = context[0] + '\n' + self.statemachine.line
- msg = self.statemachine.memo.reporter.severe(
+ lineno = self.state_machine.abs_line_number()
+ if not self.state_machine.match_titles:
+ blocktext = context[0] + '\n' + self.state_machine.line
+ msg = self.reporter.severe(
'Unexpected section title at line %s.' % lineno, '',
nodes.literal_block(blocktext, blocktext))
- self.statemachine.node += msg
- return [], nextstate, []
+ self.parent += msg
+ return [], next_state, []
title = context[0].rstrip()
underline = match.string.rstrip()
source = title + '\n' + underline
if len(title) > len(underline):
- blocktext = context[0] + '\n' + self.statemachine.line
- msg = self.statemachine.memo.reporter.info(
+ blocktext = context[0] + '\n' + self.state_machine.line
+ msg = self.reporter.info(
'Title underline too short at line %s.' % lineno, '',
nodes.literal_block(blocktext, blocktext))
- self.statemachine.node += msg
+ self.parent += msg
style = underline[0]
context[:] = []
self.section(title, source, style, lineno - 1)
- return [], nextstate, []
+ return [], next_state, []
- def text(self, match, context, nextstate):
+ def text(self, match, context, next_state):
"""Paragraph."""
- startline = self.statemachine.abslineno() - 1
+ startline = self.state_machine.abs_line_number() - 1
msg = None
try:
- block = self.statemachine.getunindented()
+ block = self.state_machine.get_text_block(flush_left=1)
except statemachine.UnexpectedIndentationError, instance:
block, lineno = instance.args
- msg = self.statemachine.memo.reporter.error(
+ msg = self.reporter.error(
'Unexpected indentation at line %s.' % lineno)
lines = context + block
paragraph, literalnext = self.paragraph(lines, startline)
- self.statemachine.node += paragraph
- self.statemachine.node += msg
+ self.parent += paragraph
+ self.parent += msg
if literalnext:
try:
- self.statemachine.nextline()
+ self.state_machine.next_line()
except IndexError:
pass
- self.statemachine.node += self.literal_block()
- return [], nextstate, []
+ self.parent += self.literal_block()
+ return [], next_state, []
def literal_block(self):
"""Return a list of nodes."""
- indented, indent, offset, blankfinish = \
- self.statemachine.getindented()
+ indented, indent, offset, blank_finish = \
+ self.state_machine.get_indented()
nodelist = []
while indented and not indented[-1].strip():
indented.pop()
if indented:
data = '\n'.join(indented)
nodelist.append(nodes.literal_block(data, data))
- if not blankfinish:
+ if not blank_finish:
nodelist.append(self.unindent_warning('Literal block'))
else:
- nodelist.append(self.statemachine.memo.reporter.warning(
+ nodelist.append(self.reporter.warning(
'Literal block expected at line %s; none found.'
- % self.statemachine.abslineno()))
+ % self.state_machine.abs_line_number()))
return nodelist
def definition_list_item(self, termline):
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getindented()
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_indented()
definitionlistitem = nodes.definition_list_item('\n'.join(termline
+ indented))
- termlist, messages = self.term(termline,
- self.statemachine.abslineno() - 1)
+ termlist, messages = self.term(
+ termline, self.state_machine.abs_line_number() - 1)
definitionlistitem += termlist
definition = nodes.definition('', *messages)
definitionlistitem += definition
if termline[0][-2:] == '::':
- definition += self.statemachine.memo.reporter.info(
+ definition += self.reporter.info(
'Blank line missing before literal block? Interpreted as a '
- 'definition list item. At line %s.' % (lineoffset + 1))
- self.nestedparse(indented, inputoffset=lineoffset, node=definition)
- return definitionlistitem, blankfinish
+ 'definition list item. At line %s.' % (line_offset + 1))
+ self.nested_parse(indented, input_offset=line_offset, node=definition)
+ return definitionlistitem, blank_finish
def term(self, lines, lineno):
"""Return a definition_list's term and optional classifier."""
@@ -2028,7 +2079,7 @@ class SpecializedText(Text):
"""Incomplete construct."""
return []
- def invalid_input(self, match=None, context=None, nextstate=None):
+ def invalid_input(self, match=None, context=None, next_state=None):
"""Not a compound element member. Abort this state machine."""
raise EOFError
@@ -2044,14 +2095,14 @@ class Definition(SpecializedText):
def eof(self, context):
"""Not a definition."""
- self.statemachine.previousline(2) # back up so parent SM can reassess
+ self.state_machine.previous_line(2) # so parent SM can reassess
return []
- def indent(self, match, context, nextstate):
+ def indent(self, match, context, next_state):
"""Definition list item."""
- definitionlistitem, blankfinish = self.definition_list_item(context)
- self.statemachine.node += definitionlistitem
- self.blankfinish = blankfinish
+ definitionlistitem, blank_finish = self.definition_list_item(context)
+ self.parent += definitionlistitem
+ self.blank_finish = blank_finish
return [], 'DefinitionList', []
@@ -2066,67 +2117,67 @@ class Line(SpecializedText):
"""Transition marker at end of section or document."""
if self.eofcheck: # ignore EOFError with sections
transition = nodes.transition(context[0])
- self.statemachine.node += transition
- msg = self.statemachine.memo.reporter.error(
+ self.parent += transition
+ msg = self.reporter.error(
'Document or section may not end with a transition '
- '(line %s).' % (self.statemachine.abslineno() - 1))
- self.statemachine.node += msg
+ '(line %s).' % (self.state_machine.abs_line_number() - 1))
+ self.parent += msg
self.eofcheck = 1
return []
- def blank(self, match, context, nextstate):
+ def blank(self, match, context, next_state):
"""Transition marker."""
transition = nodes.transition(context[0])
- if len(self.statemachine.node) == 0:
- msg = self.statemachine.memo.reporter.error(
+ if len(self.parent) == 0:
+ msg = self.reporter.error(
'Document or section may not begin with a transition '
- '(line %s).' % (self.statemachine.abslineno() - 1))
- self.statemachine.node += msg
- elif isinstance(self.statemachine.node[-1], nodes.transition):
- msg = self.statemachine.memo.reporter.error(
+ '(line %s).' % (self.state_machine.abs_line_number() - 1))
+ self.parent += msg
+ elif isinstance(self.parent[-1], nodes.transition):
+ msg = self.reporter.error(
'At least one body element must separate transitions; '
'adjacent transitions at line %s.'
- % (self.statemachine.abslineno() - 1))
- self.statemachine.node += msg
- self.statemachine.node += transition
+ % (self.state_machine.abs_line_number() - 1))
+ self.parent += msg
+ self.parent += transition
return [], 'Body', []
- def text(self, match, context, nextstate):
+ def text(self, match, context, next_state):
"""Potential over- & underlined title."""
- lineno = self.statemachine.abslineno() - 1
+ lineno = self.state_machine.abs_line_number() - 1
overline = context[0]
title = match.string
underline = ''
try:
- underline = self.statemachine.nextline()
+ underline = self.state_machine.next_line()
except IndexError:
blocktext = overline + '\n' + title
- msg = self.statemachine.memo.reporter.severe(
+ msg = self.reporter.severe(
'Incomplete section title at line %s.' % lineno, '',
nodes.literal_block(blocktext, blocktext))
- self.statemachine.node += msg
+ self.parent += msg
return [], 'Body', []
source = '%s\n%s\n%s' % (overline, title, underline)
overline = overline.rstrip()
underline = underline.rstrip()
if not self.transitions['underline'][0].match(underline):
- msg = self.statemachine.memo.reporter.severe(
+ msg = self.reporter.severe(
'Missing underline for overline at line %s.' % lineno, '',
nodes.literal_block(source, source))
- self.statemachine.node += msg
+ self.parent += msg
return [], 'Body', []
elif overline != underline:
- msg = self.statemachine.memo.reporter.severe(
- 'Title overline & underline mismatch at ' 'line %s.' % lineno,
- '', nodes.literal_block(source, source))
- self.statemachine.node += msg
+ msg = self.reporter.severe(
+ 'Title overline & underline mismatch at ' 'line %s.'
+ % lineno, '', nodes.literal_block(source, source))
+ self.parent += msg
return [], 'Body', []
title = title.rstrip()
if len(title) > len(overline):
- msg = self.statemachine.memo.reporter.info(
+ msg = self.reporter.info(
'Title overline too short at line %s.'% lineno, '',
nodes.literal_block(source, source))
- self.statemachine.node += msg
+ self.parent += msg
style = (overline[0], underline[0])
self.eofcheck = 0 # @@@ not sure this is correct
self.section(title.lstrip(), source, style, lineno + 1)
@@ -2135,19 +2186,19 @@ class Line(SpecializedText):
indent = text # indented title
- def underline(self, match=None, context=None, nextstate=None):
- blocktext = context[0] + '\n' + self.statemachine.line
- msg = self.statemachine.memo.reporter.error(
+ def underline(self, match=None, context=None, next_state=None):
+ blocktext = context[0] + '\n' + self.state_machine.line
+ msg = self.reporter.error(
'Invalid section title or transition marker at line %s.'
- % (self.statemachine.abslineno() - 1), '',
+ % (self.state_machine.abs_line_number() - 1), '',
nodes.literal_block(blocktext, blocktext))
- self.statemachine.node += msg
+ self.parent += msg
return [], 'Body', []
-stateclasses = [Body, BulletList, DefinitionList, EnumeratedList, FieldList,
- OptionList, Explicit, Text, Definition, Line, SubstitutionDef,
- RFC2822Body, RFC2822List]
+state_classes = (Body, BulletList, DefinitionList, EnumeratedList, FieldList,
+ OptionList, Explicit, Text, Definition, Line,
+ SubstitutionDef, RFC2822Body, RFC2822List)
"""Standard set of State classes used to start `RSTStateMachine`."""
@@ -2164,9 +2215,9 @@ def escape2null(text):
parts.append('\x00' + text[found+1:found+2])
start = found + 2 # skip character after escape
-def unescape(text, restorebackslashes=0):
+def unescape(text, restore_backslashes=0):
"""Return a string with nulls removed or restored to backslashes."""
- if restorebackslashes:
- return text.translate(RSTState.inline.null2backslash)
+ if restore_backslashes:
+ return text.translate(Inliner.null2backslash)
else:
- return text.translate(RSTState.inline.identity, '\x00')
+ return text.translate(Inliner.identity, '\x00')
--
cgit v1.2.1
From 9f85d5f3a15e46003ea3228608373d639a2e67e3 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:24:19 +0000
Subject: renamed parts.py from old components.py
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@76 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/components.py | 85 ---------------------------
docutils/transforms/parts.py | 117 ++++++++++++++++++++++++++++++++++++++
2 files changed, 117 insertions(+), 85 deletions(-)
delete mode 100644 docutils/transforms/components.py
create mode 100644 docutils/transforms/parts.py
(limited to 'docutils')
diff --git a/docutils/transforms/components.py b/docutils/transforms/components.py
deleted file mode 100644
index 2cfe4d2a8..000000000
--- a/docutils/transforms/components.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#! /usr/bin/env python
-"""
-:Authors: David Goodger, Ueli Schlaepfer
-:Contact: goodger@users.sourceforge.net
-:Revision: $Revision$
-:Date: $Date$
-:Copyright: This module has been placed in the public domain.
-
-Transforms related to document components.
-
-- `Contents`: Used to build a table of contents.
-"""
-
-__docformat__ = 'reStructuredText'
-
-
-import re
-from docutils import nodes, utils
-from docutils.transforms import TransformError, Transform
-
-
-class Contents(Transform):
-
- """
- This transform generates a table of contents from the entire document tree
- or from a single branch. It locates "section" elements and builds them
- into a nested bullet list, which is placed within a "topic". A title is
- either explicitly specified, taken from the appropriate language module,
- or omitted (local table of contents). The depth may be specified.
- Two-way references between the table of contents and section titles are
- generated (requires Writer support).
-
- This transform requires a startnode, which which contains generation
- options and provides the location for the generated table of contents (the
- startnode is replaced by the table of contents "topic").
- """
-
- def transform(self):
- topic = nodes.topic(CLASS='contents')
- title = self.startnode.details['title']
- if self.startnode.details.has_key('local'):
- startnode = self.startnode.parent
- # @@@ generate an error if the startnode (directive) not at
- # section/document top-level? Drag it up until it is?
- while not isinstance(startnode, nodes.Structural):
- startnode = startnode.parent
- if not title:
- title = []
- else:
- startnode = self.doctree
- if not title:
- title = nodes.title('', self.language.labels['contents'])
- contents = self.build_contents(startnode)
- if len(contents):
- topic += title
- topic += contents
- self.startnode.parent.replace(self.startnode, topic)
- else:
- self.startnode.parent.remove(self.startnode)
-
- def build_contents(self, node, level=0):
- level += 1
- sections = []
- i = len(node) - 1
- while i >= 0 and isinstance(node[i], nodes.section):
- sections.append(node[i])
- i -= 1
- sections.reverse()
- entries = []
- for section in sections:
- title = section[0]
- reference = nodes.reference('', '', refid=section['id'],
- *title.getchildren())
- entry = nodes.paragraph('', '', reference)
- item = nodes.list_item('', entry)
- itemid = self.doctree.set_id(item)
- title['refid'] = itemid
- if (not self.startnode.details.has_key('depth')) \
- or level < self.startnode.details['depth']:
- subsects = self.build_contents(section, level)
- item += subsects
- entries.append(item)
- if entries:
- entries = nodes.bullet_list('', *entries)
- return entries
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
new file mode 100644
index 000000000..50667a1fa
--- /dev/null
+++ b/docutils/transforms/parts.py
@@ -0,0 +1,117 @@
+#! /usr/bin/env python
+"""
+:Authors: David Goodger, Ueli Schlaepfer
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Transforms related to document parts.
+
+- `Contents`: Used to build a table of contents.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import re, sys
+from docutils import nodes, utils
+from docutils.transforms import TransformError, Transform
+
+
+class Contents(Transform):
+
+ """
+ This transform generates a table of contents from the entire document tree
+ or from a single branch. It locates "section" elements and builds them
+ into a nested bullet list, which is placed within a "topic". A title is
+ either explicitly specified, taken from the appropriate language module,
+ or omitted (local table of contents). The depth may be specified.
+ Two-way references between the table of contents and section titles are
+ generated (requires Writer support).
+
+ This transform requires a startnode, which which contains generation
+ options and provides the location for the generated table of contents (the
+ startnode is replaced by the table of contents "topic").
+ """
+
+ def transform(self):
+ topic = nodes.topic(CLASS='contents')
+ title = self.startnode.details['title']
+ if self.startnode.details.has_key('local'):
+ startnode = self.startnode.parent
+ # @@@ generate an error if the startnode (directive) not at
+ # section/document top-level? Drag it up until it is?
+ while not isinstance(startnode, nodes.Structural):
+ startnode = startnode.parent
+ if not title:
+ title = []
+ else:
+ startnode = self.document
+ if not title:
+ title = nodes.title('', self.language.labels['contents'])
+ contents = self.build_contents(startnode)
+ if len(contents):
+ topic += title
+ topic += contents
+ self.startnode.parent.replace(self.startnode, topic)
+ else:
+ self.startnode.parent.remove(self.startnode)
+
+ def build_contents(self, node, level=0):
+ level += 1
+ sections = []
+ i = len(node) - 1
+ while i >= 0 and isinstance(node[i], nodes.section):
+ sections.append(node[i])
+ i -= 1
+ sections.reverse()
+ entries = []
+ depth = self.startnode.details.get('depth', sys.maxint)
+ for section in sections:
+ title = section[0]
+ entrytext = self.copy_and_filter(title)
+ reference = nodes.reference('', '', refid=section['id'],
+ *entrytext)
+ entry = nodes.paragraph('', '', reference)
+ item = nodes.list_item('', entry)
+ itemid = self.document.set_id(item)
+ title['refid'] = itemid
+ if level < depth:
+ subsects = self.build_contents(section, level)
+ item += subsects
+ entries.append(item)
+ if entries:
+ entries = nodes.bullet_list('', *entries)
+ return entries
+
+ def copy_and_filter(self, node):
+ """Return a copy of a title, with references, images, etc. removed."""
+ visitor = ContentsFilter(self.document)
+ node.walkabout(visitor)
+ return visitor.get_entry_text()
+
+
+class ContentsFilter(nodes.TreeCopyVisitor):
+
+ def get_entry_text(self):
+ return self.get_tree_copy().getchildren()
+
+ def visit_citation_reference(self, node):
+ raise nodes.SkipNode
+
+ def visit_footnote_reference(self, node):
+ raise nodes.SkipNode
+
+ def visit_image(self, node):
+ if node.hasattr('alt'):
+ self.parent_stack[-1].append(nodes.Text(node['alt']))
+ raise nodes.SkipNode
+
+ def ignore_node_but_process_children(self, node):
+ raise nodes.SkipDeparture
+
+ visit_interpreted = ignore_node_but_process_children
+ visit_problematic = ignore_node_but_process_children
+ visit_reference = ignore_node_but_process_children
+ visit_target = ignore_node_but_process_children
--
cgit v1.2.1
From 82bf628c5790a1cc17855199c88d07094b4dbbfa Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:26:09 +0000
Subject: Docutils component-related transforms.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@77 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/components.py | 45 +++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 docutils/transforms/components.py
(limited to 'docutils')
diff --git a/docutils/transforms/components.py b/docutils/transforms/components.py
new file mode 100644
index 000000000..b0d1ae48f
--- /dev/null
+++ b/docutils/transforms/components.py
@@ -0,0 +1,45 @@
+#! /usr/bin/env python
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Docutils component-related transforms.
+"""
+
+__docformat__ = 'reStructuredText'
+
+import sys, os, re, time
+from docutils import nodes, utils, ApplicationError, DataError
+from docutils.transforms import Transform, TransformError
+
+
+class Filter(Transform):
+
+ """
+ Include or exclude elements which depend on a specific Docutils component.
+
+ For use with `nodes.pending` elements. A "pending" element's dictionary
+ attribute ``details`` must contain a key matching the dependency component
+ type (e.g. ``details['writer']`` for a "pending" element whose ``stage``
+ attribute is 'last writer'). The value is the name of a specific format
+ or context of that component (e.g. ``details['writer'] = 'html'``). If
+ the Docutils component which called this transform supports that format or
+ context, the "pending" element is replaced by the nodes in
+ ``details['nodes']``; otherwise, the "pending" element is removed.
+
+ For example, the reStructuredText "meta" directive creates a "pending"
+ element containing a "meta" element. Only writers supporting the "html"
+ format will include the "meta" element; it will be deleted from the output
+ of all other writers.
+ """
+
+ def transform(self):
+ pending = self.startnode
+ component_name = pending.details[pending.stage.split()[-1]]
+ if self.component.supports(component_name):
+ pending.parent.replace(pending, pending.details['nodes'])
+ else:
+ pending.parent.remove(pending)
--
cgit v1.2.1
From 913e7e2cbd89dee2e8ba5fccca1e3ed774577911 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:26:53 +0000
Subject: Transforms for PEP processing.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@78 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/peps.py | 99 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 docutils/transforms/peps.py
(limited to 'docutils')
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
new file mode 100644
index 000000000..d3dca5b0e
--- /dev/null
+++ b/docutils/transforms/peps.py
@@ -0,0 +1,99 @@
+#! /usr/bin/env python
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Transforms for PEP processing.
+
+- `Headers`: Used to transform a PEP's initial RFC-2822 header. It remains a
+ field list, but some entries get processed.
+"""
+
+__docformat__ = 'reStructuredText'
+
+import sys, os, re, time
+from docutils import nodes, utils, ApplicationError, DataError
+from docutils.transforms import Transform, TransformError
+import mypdb as pdb
+
+
+class Headers(Transform):
+
+ """
+ """
+
+ pep_cvs_url = ('http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/'
+ 'python/nondist/peps/pep-%04d.txt')
+ rcs_keyword_substitutions = (
+ (re.compile(r'\$' r'RCSfile: (.+),v \$$', re.IGNORECASE), r'\1'),
+ (re.compile(r'\$[a-zA-Z]+: (.+) \$$'), r'\1'),)
+
+ def transform(self):
+ if not len(self.document):
+ raise DataError('Document tree is empty.')
+ header = self.document[0]
+ if not isinstance(header, nodes.field_list) or \
+ header.get('class') != 'rfc2822':
+ raise DataError('Document does not begin with an RFC-2822 '
+ 'header; it is not a PEP.')
+ pep = title = None
+ #pdb.set_trace()
+ for field in header:
+ if field[0].astext().lower() == 'pep': # should be the first field
+ pep = int(field[1].astext())
+ break
+ if pep is None:
+ raise DataError('Document does not contain an RFC-2822 "PEP" '
+ 'header.')
+ for field in header:
+ name = field[0].astext().lower()
+ body = field[1]
+ print >>sys.stderr, 'name=%s, body=%s' % (name, body.astext()) ; sys.stderr.flush()
+ if len(body) > 1:
+ raise DataError('PEP header field body contains multiple '
+ 'elements:\n%s' % field.pformat(level=1))
+ elif len(body):
+ if not isinstance(body[0], nodes.paragraph):
+ raise DataError('PEP header field body may only contain '
+ 'a single paragraph:\n%s'
+ % field.pformat(level=1))
+ elif name == 'last-modified':
+ date = time.strftime(
+ '%d-%b-%Y',
+ time.localtime(os.stat(self.document['source'])[8]))
+ body += nodes.paragraph()
+ uri = self.pep_cvs_url % int(pep)
+ body[0][:] = [nodes.reference('', date, refuri=uri)]
+ else:
+ continue
+ para = body[0]
+ if name == 'title':
+ title = body.astext()
+ # @@@ Insert a "pending" element here, since we don't really want a separate document title?
+ elif name in ('author', 'discussions-to'):
+ for node in para:
+ if isinstance(node, nodes.reference) \
+ and node.has_key('refuri') \
+ and node['refuri'][:7] == 'mailto:':
+ node['refuri'] += '?subject=PEP%%20%s' % pep
+ elif name in ('replaces', 'replaced-by'):
+ newbody = []
+ space = nodes.Text(' ')
+ for refpep in body.astext().split():
+ pepno = int(refpep)
+ newbody.append(nodes.reference(
+ refpep, refpep, refuri='pep-%04d.html' % pepno))
+ newbody.append(space)
+ para[:] = newbody[:-1] # drop trailing space
+ elif name == 'last-modified':
+ #pdb.set_trace()
+ utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
+ date = para.astext()
+ uri = self.pep_cvs_url % int(pep)
+ para[:] = [nodes.reference('', date, refuri=uri)]
+ elif name == 'version' and len(body):
+ utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
+ print >>sys.stderr, 'name=%s, body=%s' % (name, body.astext()) ; sys.stderr.flush()
--
cgit v1.2.1
From 9f927b22539072acd91336c84dbd2e120bfe6d28 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:27:34 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@79 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/languages/en.py | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/languages/en.py b/docutils/parsers/rst/languages/en.py
index 2b1c52649..370c34d12 100644
--- a/docutils/parsers/rst/languages/en.py
+++ b/docutils/parsers/rst/languages/en.py
@@ -24,15 +24,18 @@ directives = {
'note': 'note',
'tip': 'tip',
'warning': 'warning',
+ 'questions': 'questions',
+ 'qa': 'questions',
+ 'faq': 'questions',
+ 'meta': 'meta',
+ #'imagemap': 'imagemap',
'image': 'image',
'figure': 'figure',
+ #'raw': 'raw',
'contents': 'contents',
- 'footnotes': 'footnotes',
- 'citations': 'citations',
- 'topic': 'topic',
- 'meta': 'meta',
- 'imagemap': 'imagemap',
- 'raw': 'raw',
+ #'footnotes': 'footnotes',
+ #'citations': 'citations',
+ #'topic': 'topic',
'restructuredtext-test-directive': 'restructuredtext-test-directive'}
"""English name to registered (in directives/__init__.py) directive name
mapping."""
--
cgit v1.2.1
From dd4471f257e8b3119631d076171fa5eba77a55cf Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:28:32 +0000
Subject: Python Enhancement Proposal (PEP) Reader.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@80 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/readers/pep.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 docutils/readers/pep.py
(limited to 'docutils')
diff --git a/docutils/readers/pep.py b/docutils/readers/pep.py
new file mode 100644
index 000000000..113b2705e
--- /dev/null
+++ b/docutils/readers/pep.py
@@ -0,0 +1,77 @@
+#! /usr/bin/env python
+
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Python Enhancement Proposal (PEP) Reader.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+import sys, os, re
+from docutils import nodes
+from docutils.readers import standalone
+from docutils.transforms import peps, references
+from docutils.parsers import rst
+
+
+class Reader(standalone.Reader):
+
+ supported = ('pep',)
+ """Contexts this reader supports."""
+
+ transforms = (references.Substitutions,
+ peps.Headers,
+ references.Footnotes,
+ references.Hyperlinks,)
+
+ def __init__(self, reporter, parser, parser_name, language_code):
+ """`parser` should be ``None``."""
+ if parser is None:
+ parser = rst.Parser(rfc2822=1, inliner=Inliner())
+ standalone.Reader.__init__(
+ self, reporter, parser, '', language_code)
+
+
+class Inliner(rst.states.Inliner):
+
+ """
+ Extend `rst.Inliner` to also parse standalone PEP & RFC references.
+ """
+
+ rfc_url = 'http://www.faqs.org/rfcs/rfc%d.html'
+ pep_url = 'pep-%04d.html'
+ pep_ref_pattern = re.compile(r"""
+ (
+ (pep-\d+(.txt)?)
+ |
+ (PEP\s+(?P\d+))
+ |
+ (RFC(-|\s+)?(?P\d+))
+ )
+ """, re.VERBOSE)
+
+ def standalone_refs(self, match, lineno):
+ text = match.group(0)
+ if text.startswith('pep-'):
+ ref = os.path.splitext(text)[0] + ".html"
+ elif text.startswith('PEP'):
+ pepnum = int(match.group('pepnum'))
+ ref = self.pep_url % pepnum
+ elif text.startswith('RFC'):
+ rfcnum = int(match.group('rfcnum'))
+ ref = self.rfc_url % rfcnum
+ else:
+ raise MarkupMismatch
+ unescaped = rst.states.unescape(text, 0)
+ return [nodes.reference(rst.states.unescape(text, 1), unescaped,
+ refuri=ref)]
+
+ implicit = (rst.states.Inliner.implicit
+ + ((pep_ref_pattern, standalone_refs),))
+ """PEP-specific list of (pattern, dispatch method) pairs."""
--
cgit v1.2.1
From da7652441d6e9b5480a3d02363e3463fea0a6390 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:29:39 +0000
Subject: Gave Readers more control over choosing and instantiating Parsers.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@81 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/readers/__init__.py | 54 ++++++++++++++++++++++++++++----------------
1 file changed, 34 insertions(+), 20 deletions(-)
(limited to 'docutils')
diff --git a/docutils/readers/__init__.py b/docutils/readers/__init__.py
index 9b8d38654..0ade6dbe3 100644
--- a/docutils/readers/__init__.py
+++ b/docutils/readers/__init__.py
@@ -14,11 +14,11 @@ __docformat__ = 'reStructuredText'
import sys
-from docutils import nodes, utils
+from docutils import nodes, utils, parsers, Component
from docutils.transforms import universal
-class Reader:
+class Reader(Component):
"""
Abstract base class for docutils Readers.
@@ -33,7 +33,7 @@ class Reader:
"""Ordered tuple of transform classes (each with a ``transform()`` method).
Populated by subclasses. `Reader.transform()` instantiates & runs them."""
- def __init__(self, reporter, languagecode):
+ def __init__(self, reporter, parser, parser_name, language_code):
"""
Initialize the Reader instance.
@@ -41,12 +41,19 @@ class Reader:
Subclasses may use these attributes as they wish.
"""
- self.languagecode = languagecode
+ self.language_code = language_code
"""Default language for new documents."""
self.reporter = reporter
"""A `utils.Reporter` instance shared by all doctrees."""
+ self.parser = parser
+ """A `parsers.Parser` instance shared by all doctrees. May be left
+ unspecified if the document source determines the parser."""
+
+ if parser is None and parser_name:
+ self.set_parser(parser_name)
+
self.source = None
"""Path to the source of raw input."""
@@ -54,12 +61,15 @@ class Reader:
"""Raw text input; either a single string or, for more complex cases,
a collection of strings."""
- self.transforms = tuple(self.transforms)
- """Instance copy of `Reader.transforms`; may be modified by client."""
+ def set_parser(self, parser_name):
+ """Set `self.parser` by name."""
+ parser_class = parsers.get_parser_class(parser_name)
+ self.parser = parser_class()
def read(self, source, parser):
self.source = source
- self.parser = parser
+ if not self.parser:
+ self.parser = parser
self.scan() # may modify self.parser, depending on input
self.parse()
self.transform()
@@ -69,7 +79,7 @@ class Reader:
"""Override to read `self.input` from `self.source`."""
raise NotImplementedError('subclass must override this method')
- def scanfile(self, source):
+ def scan_file(self, source):
"""
Scan a single file and return the raw data.
@@ -87,7 +97,7 @@ class Reader:
def parse(self):
"""Parse `self.input` into a document tree."""
- self.document = self.newdocument()
+ self.document = self.new_document()
self.parser.parse(self.input, self.document)
def transform(self):
@@ -95,24 +105,28 @@ class Reader:
for xclass in (universal.first_reader_transforms
+ tuple(self.transforms)
+ universal.last_reader_transforms):
- xclass(self.document).transform()
+ xclass(self.document, self).transform()
- def newdocument(self, languagecode=None):
+ def new_document(self, language_code=None):
"""Create and return a new empty document tree (root node)."""
document = nodes.document(
- languagecode=(languagecode or self.languagecode),
+ language_code=(language_code or self.language_code),
reporter=self.reporter)
document['source'] = self.source
return document
-_reader_aliases = {'rtxt': 'standalone',
- 'restructuredtext': 'standalone'}
+_reader_aliases = {
+ 'rst': 'standalone',
+ 'rest': 'standalone',
+ 'restx': 'standalone',
+ 'rtxt': 'standalone',
+ 'restructuredtext': 'standalone'}
-def get_reader_class(readername):
- """Return the Reader class from the `readername` module."""
- readername = readername.lower()
- if _reader_aliases.has_key(readername):
- readername = _reader_aliases[readername]
- module = __import__(readername, globals(), locals())
+def get_reader_class(reader_name):
+ """Return the Reader class from the `reader_name` module."""
+ reader_name = reader_name.lower()
+ if _reader_aliases.has_key(reader_name):
+ reader_name = _reader_aliases[reader_name]
+ module = __import__(reader_name, globals(), locals())
return module.Reader
--
cgit v1.2.1
From 6a9b95ff6113f2c57b5f64817072a571cb8fe829 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:30:19 +0000
Subject: - Added ``runtime_init`` method to ``StateMachine`` and ``State``.
- Added underscores to improve many awkward names.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@82 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/statemachine.py | 581 ++++++++++++++++++++++++-----------------------
1 file changed, 300 insertions(+), 281 deletions(-)
(limited to 'docutils')
diff --git a/docutils/statemachine.py b/docutils/statemachine.py
index 9410cb956..8c4cddb81 100644
--- a/docutils/statemachine.py
+++ b/docutils/statemachine.py
@@ -3,7 +3,6 @@
"""
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
-:Version: 1.3
:Revision: $Revision$
:Date: $Date$
:Copyright: This module has been placed in the public domain.
@@ -32,7 +31,7 @@ Exception classes:
Functions:
- `string2lines()`: split a multi-line string into a list of one-line strings
-- `extractindented()`: return indented lines with minimum indentation removed
+- `extract_indented()`: return indented lines with minimum indentation removed
How To Use This Module
======================
@@ -53,18 +52,18 @@ How To Use This Module
patterns = {'atransition': r'pattern', ...}
b) Include a list of initial transitions to be set up automatically, in
- `State.initialtransitions`::
+ `State.initial_transitions`::
- initialtransitions = ['atransition', ...]
+ initial_transitions = ['atransition', ...]
c) Define a method for each transition, with the same name as the
transition pattern::
- def atransition(self, match, context, nextstate):
+ def atransition(self, match, context, next_state):
# do something
result = [...] # a list
- return context, nextstate, result
- # context, nextstate may be altered
+ return context, next_state, result
+ # context, next_state may be altered
Transition methods may raise an `EOFError` to cut processing short.
@@ -72,31 +71,32 @@ How To Use This Module
transition methods, which handle the beginning- and end-of-file.
e) In order to handle nested processing, you may wish to override the
- attributes `State.nestedSM` and/or `State.nestedSMkwargs`.
+ attributes `State.nested_sm` and/or `State.nested_sm_kwargs`.
If you are using `StateWS` as a base class, in order to handle nested
indented blocks, you may wish to:
- - override the attributes `StateWS.indentSM`, `StateWS.indentSMkwargs`,
- `StateWS.knownindentSM`, and/or `StateWS.knownindentSMkwargs`;
+ - override the attributes `StateWS.indent_sm`, `StateWS.indent_sm_kwargs`,
+ `StateWS.known_indent_sm`, and/or `StateWS.known_indent_sm_kwargs`;
- override the `StateWS.blank()` method; and/or
- - override or extend the `StateWS.indent()`, `StateWS.knownindent()`,
- and/or `StateWS.firstknownindent()` methods.
+ - override or extend the `StateWS.indent()`, `StateWS.known_indent()`,
+ and/or `StateWS.firstknown_indent()` methods.
3. Create a state machine object::
- sm = StateMachine(stateclasses=[MyState, ...], initialstate='MyState')
+ sm = StateMachine(state_classes=[MyState, ...],
+ initial_state='MyState')
4. Obtain the input text, which needs to be converted into a tab-free list of
one-line strings. For example, to read text from a file called
'inputfile'::
- inputstring = open('inputfile').read()
- inputlines = statemachine.string2lines(inputstring)
+ input_string = open('inputfile').read()
+ input_lines = statemachine.string2lines(input_string)
6. Run the state machine on the input text and collect the results, a list::
- results = sm.run(inputlines)
+ results = sm.run(input_lines)
7. Remove any lingering circular references::
@@ -122,42 +122,42 @@ class StateMachine:
results of processing in a list.
"""
- def __init__(self, stateclasses, initialstate, debug=0):
+ def __init__(self, state_classes, initial_state, debug=0):
"""
Initialize a `StateMachine` object; add state objects.
Parameters:
- - `stateclasses`: a list of `State` (sub)classes.
- - `initialstate`: a string, the class name of the initial state.
+ - `state_classes`: a list of `State` (sub)classes.
+ - `initial_state`: a string, the class name of the initial state.
- `debug`: a boolean; produce verbose output if true (nonzero).
"""
- self.inputlines = None
+ self.input_lines = None
"""List of strings (without newlines). Filled by `self.run()`."""
- self.inputoffset = 0
- """Offset of `self.inputlines` from the beginning of the file."""
+ self.input_offset = 0
+ """Offset of `self.input_lines` from the beginning of the file."""
self.line = None
"""Current input line."""
- self.lineoffset = None
- """Current input line offset from beginning of `self.inputlines`."""
+ self.line_offset = None
+ """Current input line offset from beginning of `self.input_lines`."""
self.debug = debug
"""Debugging mode on/off."""
- self.initialstate = initialstate
+ self.initial_state = initial_state
"""The name of the initial state (key to `self.states`)."""
- self.currentstate = initialstate
+ self.current_state = initial_state
"""The name of the current state (key to `self.states`)."""
self.states = {}
"""Mapping of {state_name: State_object}."""
- self.addstates(stateclasses)
+ self.add_states(state_classes)
def unlink(self):
"""Remove circular references to objects no longer required."""
@@ -165,11 +165,11 @@ class StateMachine:
state.unlink()
self.states = None
- def run(self, inputlines, inputoffset=0):
+ def run(self, input_lines, input_offset=0):
"""
- Run the state machine on `inputlines`. Return results (a list).
+ Run the state machine on `input_lines`. Return results (a list).
- Reset `self.lineoffset` and `self.currentstate`. Run the
+ Reset `self.line_offset` and `self.current_state`. Run the
beginning-of-file transition. Input one line at a time and check for a
matching transition. If a match is found, call the transition method
and possibly change the state. Store the context returned by the
@@ -180,20 +180,21 @@ class StateMachine:
Parameters:
- - `inputlines`: a list of strings without newlines.
- - `inputoffset`: the line offset of `inputlines` from the beginning of
- the file.
+ - `input_lines`: a list of strings without newlines.
+ - `input_offset`: the line offset of `input_lines` from the beginning
+ of the file.
"""
- self.inputlines = inputlines
- self.inputoffset = inputoffset
- self.lineoffset = -1
- self.currentstate = self.initialstate
+ self.runtime_init()
+ self.input_lines = input_lines
+ self.input_offset = input_offset
+ self.line_offset = -1
+ self.current_state = self.initial_state
if self.debug:
- print >>sys.stderr, ('\nStateMachine.run: inputlines:\n| %s' %
- '\n| '.join(self.inputlines))
+ print >>sys.stderr, ('\nStateMachine.run: input_lines:\n| %s' %
+ '\n| '.join(self.input_lines))
context = None
results = []
- state = self.getstate()
+ state = self.get_state()
try:
if self.debug:
print >>sys.stderr, ('\nStateMachine.run: bof transition')
@@ -201,17 +202,18 @@ class StateMachine:
results.extend(result)
while 1:
try:
- self.nextline()
+ self.next_line()
if self.debug:
print >>sys.stderr, ('\nStateMachine.run: line:\n| %s'
% self.line)
except IndexError:
break
try:
- context, nextstate, result = self.checkline(context, state)
+ context, next_state, result = self.check_line(context,
+ state)
except EOFError:
break
- state = self.getstate(nextstate)
+ state = self.get_state(next_state)
results.extend(result)
if self.debug:
print >>sys.stderr, ('\nStateMachine.run: eof transition')
@@ -222,96 +224,89 @@ class StateMachine:
raise
return results
- def getstate(self, nextstate=None):
+ def get_state(self, next_state=None):
"""
- Return current state object; set it first if `nextstate` given.
+ Return current state object; set it first if `next_state` given.
- Parameter `nextstate`: a string, the name of the next state.
+ Parameter `next_state`: a string, the name of the next state.
- Exception: `UnknownStateError` raised if `nextstate` unknown.
+ Exception: `UnknownStateError` raised if `next_state` unknown.
"""
- if nextstate:
- if self.debug and nextstate != self.currentstate:
+ if next_state:
+ if self.debug and next_state != self.current_state:
print >>sys.stderr, \
- ('\nStateMachine.getstate: Changing state from '
+ ('\nStateMachine.get_state: Changing state from '
'"%s" to "%s" (input line %s).'
- % (self.currentstate, nextstate, self.abslineno()))
- self.currentstate = nextstate
+ % (self.current_state, next_state,
+ self.abs_line_number()))
+ self.current_state = next_state
try:
- return self.states[self.currentstate]
+ return self.states[self.current_state]
except KeyError:
- raise UnknownStateError(self.currentstate)
+ raise UnknownStateError(self.current_state)
- def nextline(self, n=1):
+ def next_line(self, n=1):
"""Load `self.line` with the `n`'th next line and return it."""
- self.lineoffset += n
- self.line = self.inputlines[self.lineoffset]
+ self.line_offset += n
+ self.line = self.input_lines[self.line_offset]
return self.line
- def nextlineblank(self):
+ def is_next_line_blank(self):
"""Return 1 if the next line is blank or non-existant."""
try:
- return not self.inputlines[self.lineoffset + 1].strip()
+ return not self.input_lines[self.line_offset + 1].strip()
except IndexError:
return 1
- def ateof(self):
+ def at_eof(self):
"""Return 1 if the input is at or past end-of-file."""
- return self.lineoffset >= len(self.inputlines) - 1
+ return self.line_offset >= len(self.input_lines) - 1
- def atbof(self):
+ def at_bof(self):
"""Return 1 if the input is at or before beginning-of-file."""
- return self.lineoffset <= 0
+ return self.line_offset <= 0
- def previousline(self, n=1):
+ def previous_line(self, n=1):
"""Load `self.line` with the `n`'th previous line and return it."""
- self.lineoffset -= n
- self.line = self.inputlines[self.lineoffset]
+ self.line_offset -= n
+ self.line = self.input_lines[self.line_offset]
return self.line
- def gotoline(self, lineoffset):
- """Jump to absolute line offset `lineoffset`, load and return it."""
- self.lineoffset = lineoffset - self.inputoffset
- self.line = self.inputlines[self.lineoffset]
+ def goto_line(self, line_offset):
+ """Jump to absolute line offset `line_offset`, load and return it."""
+ self.line_offset = line_offset - self.input_offset
+ self.line = self.input_lines[self.line_offset]
return self.line
- def abslineoffset(self):
+ def abs_line_offset(self):
"""Return line offset of current line, from beginning of file."""
- return self.lineoffset + self.inputoffset
+ return self.line_offset + self.input_offset
- def abslineno(self):
+ def abs_line_number(self):
"""Return line number of current line (counting from 1)."""
- return self.lineoffset + self.inputoffset + 1
+ return self.line_offset + self.input_offset + 1
- def gettextblock(self):
- """Return a contiguous block of text."""
- block = []
- for line in self.inputlines[self.lineoffset:]:
- if not line.strip():
- break
- block.append(line)
- self.nextline(len(block) - 1) # advance to last line of block
- return block
-
- def getunindented(self):
+ def get_text_block(self, flush_left=0):
"""
- Return a contiguous, flush-left block of text.
+ Return a contiguous block of text.
- Raise `UnexpectedIndentationError` if an indented line is encountered
- before the text block ends (with a blank line).
+ If `flush_left` is true, raise `UnexpectedIndentationError` if an
+ indented line is encountered before the text block ends (with a blank
+ line).
"""
- block = [self.line]
- for line in self.inputlines[self.lineoffset + 1:]:
+ block = []
+ for line in self.input_lines[self.line_offset:]:
if not line.strip():
break
- if line[0] == ' ':
- self.nextline(len(block) - 1) # advance to last line of block
- raise UnexpectedIndentationError(block, self.abslineno() + 1)
+ if flush_left and (line[0] == ' '):
+ self.next_line(len(block) - 1) # advance to last line of block
+ raise UnexpectedIndentationError(block,
+ self.abs_line_number() + 1)
block.append(line)
- self.nextline(len(block) - 1) # advance to last line of block
+ self.next_line(len(block) - 1) # advance to last line of block
return block
- def checkline(self, context, state):
+ def check_line(self, context, state):
"""
Examine one line of input for a transition match.
@@ -327,13 +322,13 @@ class StateMachine:
- the result output of the transition, a list.
"""
if self.debug:
- print >>sys.stdout, ('\nStateMachine.checkline: '
+ print >>sys.stdout, ('\nStateMachine.check_line: '
'context "%s", state "%s"' %
(context, state.__class__.__name__))
- context, nextstate, result = self.matchtransition(context, state)
- return context, nextstate, result
+ context, next_state, result = self.match_transition(context, state)
+ return context, next_state, result
- def matchtransition(self, context, state):
+ def match_transition(self, context, state):
"""
Try to match the current line to a transition & execute its method.
@@ -351,25 +346,25 @@ class StateMachine:
"""
if self.debug:
print >>sys.stderr, (
- '\nStateMachine.matchtransition: state="%s", transitions=%r.'
- % (state.__class__.__name__, state.transitionorder))
- for name in state.transitionorder:
+ '\nStateMachine.match_transition: state="%s", transitions='
+ '%r.' % (state.__class__.__name__, state.transition_order))
+ for name in state.transition_order:
while 1:
- pattern, method, nextstate = state.transitions[name]
+ pattern, method, next_state = state.transitions[name]
if self.debug:
print >>sys.stderr, (
- '\nStateMachine.matchtransition: Trying transition '
- '"%s" in state "%s".'
+ '\nStateMachine.match_transition: Trying '
+ 'transition "%s" in state "%s".'
% (name, state.__class__.__name__))
match = self.match(pattern)
if match:
if self.debug:
print >>sys.stderr, (
- '\nStateMachine.matchtransition: Matched '
+ '\nStateMachine.match_transition: Matched '
'transition "%s" in state "%s".'
% (name, state.__class__.__name__))
try:
- return method(match, context, nextstate)
+ return method(match, context, next_state)
except TransitionCorrection, detail:
name = str(detail)
continue # try again with new transition name
@@ -385,29 +380,37 @@ class StateMachine:
"""
return pattern.match(self.line)
- def addstate(self, stateclass):
+ def add_state(self, state_class):
"""
- Initialize & add a `stateclass` (`State` subclass) object.
+ Initialize & add a `state_class` (`State` subclass) object.
- Exception: `DuplicateStateError` raised if `stateclass` already added.
+ Exception: `DuplicateStateError` raised if `state_class` was already
+ added.
"""
- statename = stateclass.__name__
+ statename = state_class.__name__
if self.states.has_key(statename):
raise DuplicateStateError(statename)
- self.states[statename] = stateclass(self, self.debug)
+ self.states[statename] = state_class(self, self.debug)
+
+ def add_states(self, state_classes):
+ """
+ Add `state_classes` (a list of `State` subclasses).
+ """
+ for state_class in state_classes:
+ self.add_state(state_class)
- def addstates(self, stateclasses):
+ def runtime_init(self):
"""
- Add `stateclasses` (a list of `State` subclasses).
+ Initialize `self.states`.
"""
- for stateclass in stateclasses:
- self.addstate(stateclass)
+ for state in self.states.values():
+ state.runtime_init()
def error(self):
"""Report error details."""
- type, value, module, line, function = _exceptiondata()
+ type, value, module, line, function = _exception_data()
print >>sys.stderr, '%s: %s' % (type, value)
- print >>sys.stderr, 'input line %s' % (self.abslineno())
+ print >>sys.stderr, 'input line %s' % (self.abs_line_number())
print >>sys.stderr, ('module %s, line %s, function %s'
% (module, line, function))
@@ -448,47 +451,48 @@ class State:
final processing result.
Typical applications need only subclass `State` (or a subclass), set the
- `patterns` and `initialtransitions` class attributes, and provide
+ `patterns` and `initial_transitions` class attributes, and provide
corresponding transition methods. The default object initialization will
take care of constructing the list of transitions.
"""
patterns = None
"""
- {Name: pattern} mapping, used by `maketransition()`. Each pattern may
+ {Name: pattern} mapping, used by `make_transition()`. Each pattern may
be a string or a compiled `re` pattern. Override in subclasses.
"""
- initialtransitions = None
+ initial_transitions = None
"""
A list of transitions to initialize when a `State` is instantiated.
Each entry is either a transition name string, or a (transition name, next
- state name) pair. See `maketransitions()`. Override in subclasses.
+ state name) pair. See `make_transitions()`. Override in subclasses.
"""
- nestedSM = None
+ nested_sm = None
"""
The `StateMachine` class for handling nested processing.
- If left as ``None``, `nestedSM` defaults to the class of the state's
+ If left as ``None``, `nested_sm` defaults to the class of the state's
controlling state machine. Override it in subclasses to avoid the default.
"""
- nestedSMkwargs = None
+ nested_sm_kwargs = None
"""
- Keyword arguments dictionary, passed to the `nestedSM` constructor.
+ Keyword arguments dictionary, passed to the `nested_sm` constructor.
Two keys must have entries in the dictionary:
- - Key 'stateclasses' must be set to a list of `State` classes.
- - Key 'initialstate' must be set to the name of the initial state class.
+ - Key 'state_classes' must be set to a list of `State` classes.
+ - Key 'initial_state' must be set to the name of the initial state class.
- If `nestedSMkwargs` is left as ``None``, 'stateclasses' defaults to the
- class of the current state, and 'initialstate' defaults to the name of the
- class of the current state. Override in subclasses to avoid the defaults.
+ If `nested_sm_kwargs` is left as ``None``, 'state_classes' defaults to the
+ class of the current state, and 'initial_state' defaults to the name of
+ the class of the current state. Override in subclasses to avoid the
+ defaults.
"""
- def __init__(self, statemachine, debug=0):
+ def __init__(self, state_machine, debug=0):
"""
Initialize a `State` object; make & add initial transitions.
@@ -498,7 +502,7 @@ class State:
- `debug`: a boolean; produce verbose output if true (nonzero).
"""
- self.transitionorder = []
+ self.transition_order = []
"""A list of transition names in search order."""
self.transitions = {}
@@ -510,27 +514,35 @@ class State:
or other classes.
"""
- if self.initialtransitions:
- names, transitions = self.maketransitions(self.initialtransitions)
- self.addtransitions(names, transitions)
+ if self.initial_transitions:
+ names, transitions = self.make_transitions(
+ self.initial_transitions)
+ self.add_transitions(names, transitions)
- self.statemachine = statemachine
+ self.state_machine = state_machine
"""A reference to the controlling `StateMachine` object."""
self.debug = debug
"""Debugging mode on/off."""
- if self.nestedSM is None:
- self.nestedSM = self.statemachine.__class__
- if self.nestedSMkwargs is None:
- self.nestedSMkwargs = {'stateclasses': [self.__class__],
- 'initialstate': self.__class__.__name__}
+ if self.nested_sm is None:
+ self.nested_sm = self.state_machine.__class__
+ if self.nested_sm_kwargs is None:
+ self.nested_sm_kwargs = {'state_classes': [self.__class__],
+ 'initial_state': self.__class__.__name__}
+
+ def runtime_init(self):
+ """
+ Initialize this `State` before running the state machine; called from
+ `self.state_machine.run()`.
+ """
+ pass
def unlink(self):
"""Remove circular references to objects no longer required."""
- self.statemachine = None
+ self.state_machine = None
- def addtransitions(self, names, transitions):
+ def add_transitions(self, names, transitions):
"""
Add a list of transitions to the start of the transition list.
@@ -546,10 +558,10 @@ class State:
raise DuplicateTransitionError(name)
if not transitions.has_key(name):
raise UnknownTransitionError(name)
- self.transitionorder[:0] = names
+ self.transition_order[:0] = names
self.transitions.update(transitions)
- def addtransition(self, name, transition):
+ def add_transition(self, name, transition):
"""
Add a transition to the start of the transition list.
@@ -559,10 +571,10 @@ class State:
"""
if self.transitions.has_key(name):
raise DuplicateTransitionError(name)
- self.transitionorder[:0] = [name]
+ self.transition_order[:0] = [name]
self.transitions[name] = transition
- def removetransition(self, name):
+ def remove_transition(self, name):
"""
Remove a transition by `name`.
@@ -570,11 +582,11 @@ class State:
"""
try:
del self.transitions[name]
- self.transitionorder.remove(name)
+ self.transition_order.remove(name)
except:
raise UnknownTransitionError(name)
- def maketransition(self, name, nextstate=None):
+ def make_transition(self, name, next_state=None):
"""
Make & return a transition tuple based on `name`.
@@ -585,14 +597,14 @@ class State:
- `name`: a string, the name of the transition pattern & method. This
`State` object must have a method called '`name`', and a dictionary
`self.patterns` containing a key '`name`'.
- - `nextstate`: a string, the name of the next `State` object for this
+ - `next_state`: a string, the name of the next `State` object for this
transition. A value of ``None`` (or absent) implies no state change
(i.e., continue with the same state).
Exceptions: `TransitionPatternNotFound`, `TransitionMethodNotFound`.
"""
- if nextstate is None:
- nextstate = self.__class__.__name__
+ if next_state is None:
+ next_state = self.__class__.__name__
try:
pattern = self.patterns[name]
if not hasattr(pattern, 'match'):
@@ -605,25 +617,25 @@ class State:
except AttributeError:
raise TransitionMethodNotFound(
'%s.%s' % (self.__class__.__name__, name))
- return (pattern, method, nextstate)
+ return (pattern, method, next_state)
- def maketransitions(self, namelist):
+ def make_transitions(self, name_list):
"""
Return a list of transition names and a transition mapping.
- Parameter `namelist`: a list, where each entry is either a
+ Parameter `name_list`: a list, where each entry is either a
transition name string, or a 1- or 2-tuple (transition name, optional
next state name).
"""
stringtype = type('')
names = []
transitions = {}
- for namestate in namelist:
+ for namestate in name_list:
if type(namestate) is stringtype:
- transitions[namestate] = self.maketransition(namestate)
+ transitions[namestate] = self.make_transition(namestate)
names.append(namestate)
else:
- transitions[namestate[0]] = self.maketransition(*namestate)
+ transitions[namestate[0]] = self.make_transition(*namestate)
names.append(namestate[0])
return names, transitions
@@ -647,14 +659,14 @@ class State:
"""
return []
- def nop(self, match, context, nextstate):
+ def nop(self, match, context, next_state):
"""
A "do nothing" transition method.
- Return unchanged `context` & `nextstate`, empty result. Useful for
+ Return unchanged `context` & `next_state`, empty result. Useful for
simple state changes (actionless transitions).
"""
- return context, nextstate, []
+ return context, next_state, []
class StateMachineWS(StateMachine):
@@ -668,32 +680,32 @@ class StateMachineWS(StateMachine):
methods. There are three methods provided for extracting indented text
blocks:
- - `getindented()`: use when the indent is unknown.
- - `getknownindented()`: use when the indent is known for all lines.
- - `getfirstknownindented()`: use when only the first line's indent is
+ - `get_indented()`: use when the indent is unknown.
+ - `get_known_indented()`: use when the indent is known for all lines.
+ - `get_first_known_indented()`: use when only the first line's indent is
known.
"""
spaces = re.compile(' *')
"""Indentation recognition pattern."""
- def checkline(self, context, state):
+ def check_line(self, context, state):
"""
Examine one line of input for whitespace first, then transitions.
- Extends `StateMachine.checkline()`.
+ Extends `StateMachine.check_line()`.
"""
if self.debug:
- print >>sys.stdout, ('\nStateMachineWS.checkline: '
+ print >>sys.stdout, ('\nStateMachineWS.check_line: '
'context "%s", state "%s"' %
(context, state.__class__.__name__))
- context, nextstate, result = self.checkwhitespace(context, state)
- if nextstate == '': # no whitespace match
- return StateMachine.checkline(self, context, state)
+ context, next_state, result = self.check_whitespace(context, state)
+ if next_state == '': # no whitespace match
+ return StateMachine.check_line(self, context, state)
else:
- return context, nextstate, result
+ return context, next_state, result
- def checkwhitespace(self, context, state):
+ def check_whitespace(self, context, state):
"""
Check for a blank line or increased indent. Call the state's
transition method if a match is found.
@@ -711,33 +723,35 @@ class StateMachineWS(StateMachine):
- the result output of the transition, a list (empty if no match).
"""
if self.debug:
- print >>sys.stdout, ('\nStateMachineWS.checkwhitespace: '
+ print >>sys.stdout, ('\nStateMachineWS.check_whitespace: '
'context "%s", state "%s"' %
(context, state.__class__.__name__))
match = self.spaces.match(self.line)
indent = match.end()
if indent == len(self.line):
if self.debug:
- print >>sys.stdout, ('\nStateMachineWS.checkwhitespace: '
+ print >>sys.stdout, ('\nStateMachineWS.check_whitespace: '
'implicit transition "blank" matched')
- return state.blank(match, context, self.currentstate)
+ return state.blank(match, context, self.current_state)
elif indent:
if self.debug:
- print >>sys.stdout, ('\nStateMachineWS.checkwhitespace: '
+ print >>sys.stdout, ('\nStateMachineWS.check_whitespace: '
'implicit transition "indent" matched')
- return state.indent(match, context, self.currentstate)
+ return state.indent(match, context, self.current_state)
else:
return context, '', [] # neither blank line nor indented
- def getindented(self, uptoblank=0, stripindent=1):
+ def get_indented(self, until_blank=0, strip_indent=1):
"""
- Return a indented lines of text and info.
+ Return a block of indented lines of text, and info.
Extract an indented block where the indent is unknown for all lines.
:Parameters:
- - `uptoblank`: Stop collecting at the first blank line if true (1).
- - `stripindent`: Strip common leading indent if true (1, default).
+ - `until_blank`: Stop collecting at the first blank line if true
+ (1).
+ - `strip_indent`: Strip common leading indent if true (1,
+ default).
:Return:
- the indented block (a list of lines of text),
@@ -745,17 +759,17 @@ class StateMachineWS(StateMachine):
- its first line offset from BOF, and
- whether or not it finished with a blank line.
"""
- offset = self.abslineoffset()
- indented, indent, blankfinish = extractindented(
- self.inputlines[self.lineoffset:], uptoblank, stripindent)
+ offset = self.abs_line_offset()
+ indented, indent, blank_finish = extract_indented(
+ self.input_lines[self.line_offset:], until_blank, strip_indent)
if indented:
- self.nextline(len(indented) - 1) # advance to last indented line
+ self.next_line(len(indented) - 1) # advance to last indented line
while indented and not indented[0].strip():
indented.pop(0)
offset += 1
- return indented, indent, offset, blankfinish
+ return indented, indent, offset, blank_finish
- def getknownindented(self, indent, uptoblank=0, stripindent=1):
+ def get_known_indented(self, indent, until_blank=0, strip_indent=1):
"""
Return an indented block and info.
@@ -766,8 +780,9 @@ class StateMachineWS(StateMachine):
:Parameters:
- `indent`: The number of indent columns/characters.
- - `uptoblank`: Stop collecting at the first blank line if true (1).
- - `stripindent`: Strip `indent` characters of indentation if true
+ - `until_blank`: Stop collecting at the first blank line if true
+ (1).
+ - `strip_indent`: Strip `indent` characters of indentation if true
(1, default).
:Return:
@@ -775,29 +790,29 @@ class StateMachineWS(StateMachine):
- its first line offset from BOF, and
- whether or not it finished with a blank line.
"""
- offset = self.abslineoffset()
+ offset = self.abs_line_offset()
indented = [self.line[indent:]]
- for line in self.inputlines[self.lineoffset + 1:]:
+ for line in self.input_lines[self.line_offset + 1:]:
if line[:indent].strip():
- blankfinish = not indented[-1].strip() and len(indented) > 1
+ blank_finish = not indented[-1].strip() and len(indented) > 1
break
- if uptoblank and line.strip():
- blankfinish = 1
+ if until_blank and line.strip():
+ blank_finish = 1
break
- if stripindent:
+ if strip_indent:
indented.append(line[indent:])
else:
indented.append(line)
else:
- blankfinish = 1
+ blank_finish = 1
if indented:
- self.nextline(len(indented) - 1) # advance to last indented line
+ self.next_line(len(indented) - 1) # advance to last indented line
while indented and not indented[0].strip():
indented.pop(0)
offset += 1
- return indented, offset, blankfinish
+ return indented, offset, blank_finish
- def getfirstknownindented(self, indent, uptoblank=0, stripindent=1):
+ def get_first_known_indented(self, indent, until_blank=0, strip_indent=1):
"""
Return an indented block and info.
@@ -806,8 +821,9 @@ class StateMachineWS(StateMachine):
:Parameters:
- `indent`: The first line's indent (# of columns/characters).
- - `uptoblank`: Stop collecting at the first blank line if true (1).
- - `stripindent`: Strip `indent` characters of indentation if true
+ - `until_blank`: Stop collecting at the first blank line if true
+ (1).
+ - `strip_indent`: Strip `indent` characters of indentation if true
(1, default).
:Return:
@@ -816,15 +832,16 @@ class StateMachineWS(StateMachine):
- its first line offset from BOF, and
- whether or not it finished with a blank line.
"""
- offset = self.abslineoffset()
+ offset = self.abs_line_offset()
indented = [self.line[indent:]]
- indented[1:], indent, blankfinish = extractindented(
- self.inputlines[self.lineoffset + 1:], uptoblank, stripindent)
- self.nextline(len(indented) - 1) # advance to last indented line
+ indented[1:], indent, blank_finish = extract_indented(
+ self.input_lines[self.line_offset + 1:], until_blank,
+ strip_indent)
+ self.next_line(len(indented) - 1) # advance to last indented line
while indented and not indented[0].strip():
indented.pop(0)
offset += 1
- return indented, indent, offset, blankfinish
+ return indented, indent, offset, blank_finish
class StateWS(State):
@@ -835,111 +852,113 @@ class StateWS(State):
Use this class with `StateMachineWS`. The transition method `blank()`
handles blank lines and `indent()` handles nested indented blocks.
Indented blocks trigger a new state machine to be created by `indent()`
- and run. The class of the state machine to be created is in `indentSM`,
+ and run. The class of the state machine to be created is in `indent_sm`,
and the constructor keyword arguments are in the dictionary
- `indentSMkwargs`.
+ `indent_sm_kwargs`.
- The methods `knownindent()` and `firstknownindent()` are provided for
+ The methods `known_indent()` and `firstknown_indent()` are provided for
indented blocks where the indent (all lines' and first line's only,
respectively) is known to the transition method, along with the attributes
- `knownindentSM` and `knownindentSMkwargs`. Neither transition method is
- triggered automatically.
+ `known_indent_sm` and `known_indent_sm_kwargs`. Neither transition method
+ is triggered automatically.
"""
- indentSM = None
+ indent_sm = None
"""
The `StateMachine` class handling indented text blocks.
- If left as ``None``, `indentSM` defaults to the value of `State.nestedSM`.
- Override it in subclasses to avoid the default.
+ If left as ``None``, `indent_sm` defaults to the value of
+ `State.nested_sm`. Override it in subclasses to avoid the default.
"""
- indentSMkwargs = None
+ indent_sm_kwargs = None
"""
- Keyword arguments dictionary, passed to the `indentSM` constructor.
+ Keyword arguments dictionary, passed to the `indent_sm` constructor.
- If left as ``None``, `indentSMkwargs` defaults to the value of
- `State.nestedSMkwargs`. Override it in subclasses to avoid the default.
+ If left as ``None``, `indent_sm_kwargs` defaults to the value of
+ `State.nested_sm_kwargs`. Override it in subclasses to avoid the default.
"""
- knownindentSM = None
+ known_indent_sm = None
"""
The `StateMachine` class handling known-indented text blocks.
- If left as ``None``, `knownindentSM` defaults to the value of `indentSM`.
- Override it in subclasses to avoid the default.
+ If left as ``None``, `known_indent_sm` defaults to the value of
+ `indent_sm`. Override it in subclasses to avoid the default.
"""
- knownindentSMkwargs = None
+ known_indent_sm_kwargs = None
"""
- Keyword arguments dictionary, passed to the `knownindentSM` constructor.
+ Keyword arguments dictionary, passed to the `known_indent_sm` constructor.
- If left as ``None``, `knownindentSMkwargs` defaults to the value of
- `indentSMkwargs`. Override it in subclasses to avoid the default.
+ If left as ``None``, `known_indent_sm_kwargs` defaults to the value of
+ `indent_sm_kwargs`. Override it in subclasses to avoid the default.
"""
- def __init__(self, statemachine, debug=0):
+ def __init__(self, state_machine, debug=0):
"""
Initialize a `StateSM` object; extends `State.__init__()`.
Check for indent state machine attributes, set defaults if not set.
"""
- State.__init__(self, statemachine, debug)
- if self.indentSM is None:
- self.indentSM = self.nestedSM
- if self.indentSMkwargs is None:
- self.indentSMkwargs = self.nestedSMkwargs
- if self.knownindentSM is None:
- self.knownindentSM = self.indentSM
- if self.knownindentSMkwargs is None:
- self.knownindentSMkwargs = self.indentSMkwargs
-
- def blank(self, match, context, nextstate):
+ State.__init__(self, state_machine, debug)
+ if self.indent_sm is None:
+ self.indent_sm = self.nested_sm
+ if self.indent_sm_kwargs is None:
+ self.indent_sm_kwargs = self.nested_sm_kwargs
+ if self.known_indent_sm is None:
+ self.known_indent_sm = self.indent_sm
+ if self.known_indent_sm_kwargs is None:
+ self.known_indent_sm_kwargs = self.indent_sm_kwargs
+
+ def blank(self, match, context, next_state):
"""Handle blank lines. Does nothing. Override in subclasses."""
- return self.nop(match, context, nextstate)
+ return self.nop(match, context, next_state)
- def indent(self, match, context, nextstate):
+ def indent(self, match, context, next_state):
"""
Handle an indented text block. Extend or override in subclasses.
Recursively run the registered state machine for indented blocks
- (`self.indentSM`).
+ (`self.indent_sm`).
"""
- indented, indent, lineoffset, blankfinish = \
- self.statemachine.getindented()
- sm = self.indentSM(debug=self.debug, **self.indentSMkwargs)
- results = sm.run(indented, inputoffset=lineoffset)
- return context, nextstate, results
+ indented, indent, line_offset, blank_finish = \
+ self.state_machine.get_indented()
+ sm = self.indent_sm(debug=self.debug, **self.indent_sm_kwargs)
+ results = sm.run(indented, input_offset=line_offset)
+ return context, next_state, results
- def knownindent(self, match, context, nextstate):
+ def known_indent(self, match, context, next_state):
"""
Handle a known-indent text block. Extend or override in subclasses.
Recursively run the registered state machine for known-indent indented
- blocks (`self.knownindentSM`). The indent is the length of the match,
+ blocks (`self.known_indent_sm`). The indent is the length of the match,
``match.end()``.
"""
- indented, lineoffset, blankfinish = \
- self.statemachine.getknownindented(match.end())
- sm = self.knownindentSM(debug=self.debug, **self.knownindentSMkwargs)
- results = sm.run(indented, inputoffset=lineoffset)
- return context, nextstate, results
-
- def firstknownindent(self, match, context, nextstate):
+ indented, line_offset, blank_finish = \
+ self.state_machine.get_known_indented(match.end())
+ sm = self.known_indent_sm(debug=self.debug,
+ **self.known_indent_sm_kwargs)
+ results = sm.run(indented, input_offset=line_offset)
+ return context, next_state, results
+
+ def first_known_indent(self, match, context, next_state):
"""
Handle an indented text block (first line's indent known).
Extend or override in subclasses.
Recursively run the registered state machine for known-indent indented
- blocks (`self.knownindentSM`). The indent is the length of the match,
- ``match.end()``.
+ blocks (`self.known_indent_sm`). The indent is the length of the
+ match, ``match.end()``.
"""
- indented, lineoffset, blankfinish = \
- self.statemachine.getfirstknownindented(match.end())
- sm = self.knownindentSM(debug=self.debug, **self.knownindentSMkwargs)
- results = sm.run(indented, inputoffset=lineoffset)
- return context, nextstate, results
+ indented, line_offset, blank_finish = \
+ self.state_machine.get_first_known_indented(match.end())
+ sm = self.known_indent_sm(debug=self.debug,
+ **self.known_indent_sm_kwargs)
+ results = sm.run(indented, input_offset=line_offset)
+ return context, next_state, results
class _SearchOverride:
@@ -993,36 +1012,36 @@ class TransitionCorrection(Exception):
_whitespace_conversion_table = string.maketrans('\v\f', ' ')
-def string2lines(astring, tabwidth=8, convertwhitespace=0):
+def string2lines(astring, tab_width=8, convert_whitespace=0):
"""
Return a list of one-line strings with tabs expanded and no newlines.
- Each tab is expanded with between 1 and `tabwidth` spaces, so that the
- next character's index becomes a multiple of `tabwidth` (8 by default).
+ Each tab is expanded with between 1 and `tab_width` spaces, so that the
+ next character's index becomes a multiple of `tab_width` (8 by default).
Parameters:
- `astring`: a multi-line string.
- - `tabwidth`: the number of columns between tab stops.
- - `convertwhitespace`: convert form feeds and vertical tabs to spaces?
+ - `tab_width`: the number of columns between tab stops.
+ - `convert_whitespace`: convert form feeds and vertical tabs to spaces?
"""
- if convertwhitespace:
+ if convert_whitespace:
astring = astring.translate(_whitespace_conversion_table)
- return [s.expandtabs(tabwidth) for s in astring.splitlines()]
+ return [s.expandtabs(tab_width) for s in astring.splitlines()]
-def extractindented(lines, uptoblank=0, stripindent=1):
+def extract_indented(lines, until_blank=0, strip_indent=1):
"""
Extract and return a list of indented lines of text.
Collect all lines with indentation, determine the minimum indentation,
remove the minimum indentation from all indented lines (unless
- `stripindent` is false), and return them. All lines up to but not
+ `strip_indent` is false), and return them. All lines up to but not
including the first unindented line will be returned.
:Parameters:
- `lines`: a list of one-line strings without newlines.
- - `uptoblank`: Stop collecting at the first blank line if true (1).
- - `stripindent`: Strip common leading indent if true (1, default).
+ - `until_blank`: Stop collecting at the first blank line if true (1).
+ - `strip_indent`: Strip common leading indent if true (1, default).
:Return:
- a list of indented lines with mininum indent removed;
@@ -1035,11 +1054,11 @@ def extractindented(lines, uptoblank=0, stripindent=1):
for line in lines:
if line and line[0] != ' ': # line not indented
# block finished properly iff the last indented line was blank
- blankfinish = len(source) and not source[-1].strip()
+ blank_finish = len(source) and not source[-1].strip()
break
stripped = line.lstrip()
- if uptoblank and not stripped: # blank line
- blankfinish = 1
+ if until_blank and not stripped: # blank line
+ blank_finish = 1
break
source.append(line)
if not stripped: # blank line
@@ -1050,15 +1069,15 @@ def extractindented(lines, uptoblank=0, stripindent=1):
else:
indent = min(indent, lineindent)
else:
- blankfinish = 1 # block ends at end of lines
+ blank_finish = 1 # block ends at end of lines
if indent:
- if stripindent:
+ if strip_indent:
source = [s[indent:] for s in source]
- return source, indent, blankfinish
+ return source, indent, blank_finish
else:
- return [], 0, blankfinish
+ return [], 0, blank_finish
-def _exceptiondata():
+def _exception_data():
"""
Return exception information:
--
cgit v1.2.1
From 9c5bc6ca7bedb2a9ebdd40ae9db57a38cdb183a5 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:31:17 +0000
Subject: Changed ``Messages`` transform to properly filter out system messages
below the warning threshold.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@83 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 63 +++++++++++++++++++++++-----------------
1 file changed, 36 insertions(+), 27 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index 1cebcc9db..145a89b01 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -19,7 +19,7 @@ Transforms needed by most or all documents:
__docformat__ = 'reStructuredText'
-import re
+import re, sys
from docutils import nodes, utils
from docutils.transforms import TransformError, Transform
@@ -32,24 +32,29 @@ class Messages(Transform):
"""
def transform(self):
- # @@@ filter out msgs below threshold?
- if len(self.doctree.messages) > 0:
+ unfiltered = self.document.messages.getchildren()
+ threshold = self.document.reporter['writer'].warning_level
+ messages = []
+ for msg in unfiltered:
+ if msg['level'] >= threshold:
+ messages.append(msg)
+ if len(messages) > 0:
section = nodes.section(CLASS='system-messages')
# @@@ get this from the language module?
section += nodes.title('', 'Docutils System Messages')
- section += self.doctree.messages.getchildren()
- self.doctree.messages[:] = []
- self.doctree += section
+ section += messages
+ self.document.messages[:] = []
+ self.document += section
class TestMessages(Transform):
"""
- Append all system messages to the end of the doctree.
+ Append all system messages to the end of the document.
"""
def transform(self):
- self.doctree += self.doctree.messages.getchildren()
+ self.document += self.document.messages.getchildren()
class FinalChecks(Transform):
@@ -61,8 +66,8 @@ class FinalChecks(Transform):
"""
def transform(self):
- visitor = FinalCheckVisitor(self.doctree)
- self.doctree.walk(visitor)
+ visitor = FinalCheckVisitor(self.document)
+ self.document.walk(visitor)
class FinalCheckVisitor(nodes.NodeVisitor):
@@ -75,21 +80,21 @@ class FinalCheckVisitor(nodes.NodeVisitor):
return
refname = node['refname']
try:
- id = self.doctree.nameids[refname]
+ id = self.document.nameids[refname]
except KeyError:
- msg = self.doctree.reporter.error(
+ msg = self.document.reporter.error(
'Unknown target name: "%s".' % (node['refname']))
- self.doctree.messages += msg
- msgid = self.doctree.set_id(msg)
+ self.document.messages += msg
+ msgid = self.document.set_id(msg)
prb = nodes.problematic(
node.rawsource, node.rawsource, refid=msgid)
- prbid = self.doctree.set_id(prb)
+ prbid = self.document.set_id(prb)
msg.add_backref(prbid)
node.parent.replace(node, prb)
return
del node['refname']
node['refid'] = id
- self.doctree.ids[id].referenced = 1
+ self.document.ids[id].referenced = 1
node.resolved = 1
visit_footnote_reference = visit_citation_reference = visit_reference
@@ -98,43 +103,47 @@ class FinalCheckVisitor(nodes.NodeVisitor):
class Pending(Transform):
"""
- Execute pending transforms.
+ Base class for the execution of pending transforms.
+
+ `nodes.pending` element objects each contain a "stage" attribute; the
+ stage of the pending element must match the `stage` of this transform.
"""
stage = None
"""The stage of processing applicable to this transform; match with
- `nodes.pending.stage`. Possible values include 'first_reader',
- 'last_reader', 'first_writer', and 'last_writer'. Override in
- subclasses."""
+ `nodes.pending.stage`. Possible values include 'first reader',
+ 'last reader', 'first writer', and 'last writer'. Overriden in
+ subclasses (below)."""
def transform(self):
- for pending in self.doctree.pending:
+ for pending in self.document.pending:
if pending.stage == self.stage:
- pending.transform(self.doctree, pending).transform()
+ pending.transform(self.document, self.component,
+ pending).transform()
class FirstReaderPending(Pending):
- stage = 'first_reader'
+ stage = 'first reader'
class LastReaderPending(Pending):
- stage = 'last_reader'
+ stage = 'last reader'
class FirstWriterPending(Pending):
- stage = 'first_writer'
+ stage = 'first writer'
class LastWriterPending(Pending):
- stage = 'last_writer'
+ stage = 'last writer'
test_transforms = (TestMessages,)
-"""Universal transforms to apply to the raw doctree when testing."""
+"""Universal transforms to apply to the raw document when testing."""
first_reader_transforms = (FirstReaderPending,)
"""Universal transforms to apply before any other Reader transforms."""
--
cgit v1.2.1
From 1391b104c8e096918cb1f12ed4befe4a3f9bdc11 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:34:56 +0000
Subject: renamed pseudoxml.py from pprint.py
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@84 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/pprint.py | 28 ----------------------------
docutils/writers/pseudoxml.py | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 35 insertions(+), 28 deletions(-)
delete mode 100644 docutils/writers/pprint.py
create mode 100644 docutils/writers/pseudoxml.py
(limited to 'docutils')
diff --git a/docutils/writers/pprint.py b/docutils/writers/pprint.py
deleted file mode 100644
index a34c2a920..000000000
--- a/docutils/writers/pprint.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#! /usr/bin/env python
-
-"""
-:Authors: David Goodger
-:Contact: goodger@users.sourceforge.net
-:Revision: $Revision$
-:Date: $Date$
-:Copyright: This module has been placed in the public domain.
-
-Simple internal document tree Writer, writes indented pseudo-XML.
-"""
-
-__docformat__ = 'reStructuredText'
-
-
-from docutils import writers
-
-
-class Writer(writers.Writer):
-
- output = None
- """Final translated form of `document`."""
-
- def translate(self):
- self.output = self.document.pformat()
-
- def record(self):
- self.recordfile(self.output, self.destination)
diff --git a/docutils/writers/pseudoxml.py b/docutils/writers/pseudoxml.py
new file mode 100644
index 000000000..a0cf5ea14
--- /dev/null
+++ b/docutils/writers/pseudoxml.py
@@ -0,0 +1,35 @@
+#! /usr/bin/env python
+
+"""
+:Authors: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Simple internal document tree Writer, writes indented pseudo-XML.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+from docutils import writers
+
+
+class Writer(writers.Writer):
+
+ supported = ('pprint', 'pformat', 'pseudoxml')
+ """Formats this writer supports."""
+
+ output = None
+ """Final translated form of `document`."""
+
+ def translate(self):
+ self.output = self.document.pformat()
+
+ def record(self):
+ self.recordfile(self.output, self.destination)
+
+ def supports(self, format):
+ """This writer supports all format-specific elements."""
+ return 1
--
cgit v1.2.1
From 8964493e1cc53888f581d21c6edcc29891c1b84a Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:35:35 +0000
Subject: - Made XHTML-compatible (switched to lowercase element & attribute
names; empty tag format). - Escape double-dashes in comment text.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@85 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index a911719ab..0390502d2 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -24,8 +24,8 @@ from docutils import writers, nodes, languages
class Writer(writers.Writer):
- names = ('html', 'html4css1', 'xhtml')
- """Names this writer answers to."""
+ supported = ('html', 'html4css1', 'xhtml')
+ """Formats this writer supports."""
output = None
"""Final translated form of `document`."""
@@ -41,13 +41,13 @@ class Writer(writers.Writer):
class HTMLTranslator(nodes.NodeVisitor):
- def __init__(self, doctree):
- nodes.NodeVisitor.__init__(self, doctree)
- self.language = languages.getlanguage(doctree.languagecode)
+ def __init__(self, document):
+ nodes.NodeVisitor.__init__(self, document)
+ self.language = languages.getlanguage(document.language_code)
self.head = ['\n',
- '\n\n' % doctree.languagecode,
+ '\n\n' % document.language_code,
'\n']
self.body = ['\n\n']
@@ -187,7 +187,7 @@ class HTMLTranslator(nodes.NodeVisitor):
if node.has_key('refid'):
href = '#' + node['refid']
elif node.has_key('refname'):
- href = '#' + self.doctree.nameids[node['refname']]
+ href = '#' + self.document.nameids[node['refname']]
self.body.append(self.starttag(node, 'a', '[', href=href,
CLASS='citation-reference'))
@@ -417,7 +417,7 @@ class HTMLTranslator(nodes.NodeVisitor):
if node.has_key('refid'):
href = '#' + node['refid']
elif node.has_key('refname'):
- href = '#' + self.doctree.nameids[node['refname']]
+ href = '#' + self.document.nameids[node['refname']]
self.body.append(self.starttag(node, 'a', '', href=href,
CLASS='footnote-reference'))
@@ -589,7 +589,7 @@ class HTMLTranslator(nodes.NodeVisitor):
elif node.has_key('refid'):
href = '#' + node['refid']
elif node.has_key('refname'):
- href = '#' + self.doctree.nameids[node['refname']]
+ href = '#' + self.document.nameids[node['refname']]
self.body.append(self.starttag(node, 'a', '', href=href,
CLASS='reference'))
@@ -644,7 +644,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('\n')
def visit_system_message(self, node):
- if node['level'] < self.doctree.reporter['writer'].warninglevel:
+ if node['level'] < self.document.reporter['writer'].warning_level:
raise nodes.SkipNode
self.body.append(self.starttag(node, 'div', CLASS='system-message'))
self.body.append('
')
--
cgit v1.2.1
From 23a164fa2084631177b50039af76e424b16db2d1 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:36:03 +0000
Subject: refactored; improved compound names
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@86 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/readers/standalone.py | 7 +-
docutils/transforms/__init__.py | 17 ++--
docutils/transforms/frontmatter.py | 69 ++++++-------
docutils/transforms/references.py | 193 +++++++++++++++++--------------------
docutils/utils.py | 66 +++++++------
docutils/writers/__init__.py | 26 ++---
6 files changed, 188 insertions(+), 190 deletions(-)
(limited to 'docutils')
diff --git a/docutils/readers/standalone.py b/docutils/readers/standalone.py
index 27c0ded6b..e6108f569 100644
--- a/docutils/readers/standalone.py
+++ b/docutils/readers/standalone.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python
"""
-:Authors: David Goodger
+:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:Revision: $Revision$
:Date: $Date$
@@ -21,6 +21,9 @@ from docutils.parsers.rst import Parser
class Reader(readers.Reader):
+ supported = ('standalone',)
+ """Contexts this reader supports."""
+
document = None
"""A single document tree."""
@@ -31,4 +34,4 @@ class Reader(readers.Reader):
references.Hyperlinks,)
def scan(self):
- self.input = self.scanfile(self.source)
+ self.input = self.scan_file(self.source)
diff --git a/docutils/transforms/__init__.py b/docutils/transforms/__init__.py
index 6c2ae279f..ddf92cb65 100644
--- a/docutils/transforms/__init__.py
+++ b/docutils/transforms/__init__.py
@@ -29,32 +29,37 @@ these standard transforms.
__docformat__ = 'reStructuredText'
-from docutils import languages
+from docutils import languages, ApplicationError, Component
-class TransformError(Exception): pass
+class TransformError(ApplicationError): pass
-class Transform:
+class Transform(Component):
"""
Docutils transform component abstract base class.
"""
- def __init__(self, doctree, startnode=None):
+ def __init__(self, document, component, startnode=None):
"""
Initial setup for in-place document transforms.
"""
- self.doctree = doctree
+ self.document = document
"""The document tree to transform."""
+ self.component = component
+ """The Docutils component running this transform. Transforms can
+ query their controlling components with calls to
+ `docutils.Component.supports()`."""
+
self.startnode = startnode
"""Node from which to begin the transform. For many transforms which
apply to the document as a whole, `startnode` is not set (i.e. its
value is `None`)."""
- self.language = languages.getlanguage(doctree.languagecode)
+ self.language = languages.getlanguage(document.language_code)
"""Language module local to this document."""
def transform(self):
diff --git a/docutils/transforms/frontmatter.py b/docutils/transforms/frontmatter.py
index 0a8068fad..d4bfce832 100644
--- a/docutils/transforms/frontmatter.py
+++ b/docutils/transforms/frontmatter.py
@@ -111,13 +111,13 @@ class DocTitle(Transform):
section, index = self.candidate_index()
if index is None:
return None
- doctree = self.doctree
+ document = self.document
# Transfer the section's attributes to the document element (at root):
- doctree.attributes.update(section.attributes)
- doctree[:] = (section[:1] # section title
- + doctree[:index] # everything that was in the document
- # before the section
- + section[1:]) # everything that was in the section
+ document.attributes.update(section.attributes)
+ document[:] = (section[:1] # section title
+ + document[:index] # everything that was in the
+ # document before the section
+ + section[1:]) # everything that was in the section
return 1
def promote_document_subtitle(self):
@@ -129,10 +129,10 @@ class DocTitle(Transform):
subtitle.attributes.update(subsection.attributes)
# Transfer the contents of the subsection's title to the subtitle:
subtitle[:] = subsection[0][:]
- doctree = self.doctree
- doctree[:] = (doctree[:1] # document title
+ document = self.document
+ document[:] = (document[:1] # document title
+ [subtitle]
- + doctree[1:index] # everything that was in the document
+ + document[1:index] # everything that was in the document
# before the section
+ subsection[1:]) # everything that was in the subsection
return 1
@@ -143,13 +143,13 @@ class DocTitle(Transform):
Return (None, None) if no valid candidate was found.
"""
- doctree = self.doctree
- index = doctree.findnonclass(nodes.PreBibliographic)
- if index is None or len(doctree) > (index + 1) or \
- not isinstance(doctree[index], nodes.section):
+ document = self.document
+ index = document.findnonclass(nodes.PreBibliographic)
+ if index is None or len(document) > (index + 1) or \
+ not isinstance(document[index], nodes.section):
return None, None
else:
- return doctree[index], index
+ return document[index], index
class DocInfo(Transform):
@@ -224,19 +224,19 @@ class DocInfo(Transform):
"""
def transform(self):
- doctree = self.doctree
- index = doctree.findnonclass(nodes.PreBibliographic)
+ document = self.document
+ index = document.findnonclass(nodes.PreBibliographic)
if index is None:
return
- candidate = doctree[index]
+ candidate = document[index]
if isinstance(candidate, nodes.field_list):
- biblioindex = doctree.findnonclass(nodes.Titular)
+ biblioindex = document.findnonclass(nodes.Titular)
nodelist, remainder = self.extract_bibliographic(candidate)
if remainder:
- doctree[index] = remainder
+ document[index] = remainder
else:
- del doctree[index]
- doctree[biblioindex:biblioindex] = nodelist
+ del document[index]
+ document[biblioindex:biblioindex] = nodelist
return
def extract_bibliographic(self, field_list):
@@ -247,7 +247,7 @@ class DocInfo(Transform):
for field in field_list:
try:
name = field[0][0].astext()
- normedname = utils.normname(name)
+ normedname = utils.normalize_name(name)
if not (len(field) == 2 and bibliofields.has_key(normedname)
and self.check_empty_biblio_field(field, name)):
raise TransformError
@@ -255,14 +255,15 @@ class DocInfo(Transform):
if issubclass(biblioclass, nodes.TextElement):
if not self.check_compound_biblio_field(field, name):
raise TransformError
- self.filter_rcs_keywords(field[1][0])
+ utils.clean_rcs_keywords(
+ field[1][0], self.rcs_keyword_substitutions)
docinfo.append(biblioclass('', '', *field[1][0]))
else: # multiple body elements possible
if issubclass(biblioclass, nodes.authors):
self.extract_authors(field, name, docinfo)
elif issubclass(biblioclass, nodes.topic):
if abstract:
- field[-1] += self.doctree.reporter.warning(
+ field[-1] += self.document.reporter.warning(
'There can only be one abstract.')
raise TransformError
title = nodes.title(
@@ -287,18 +288,18 @@ class DocInfo(Transform):
def check_empty_biblio_field(self, field, name):
if len(field[1]) < 1:
- field[-1] += self.doctree.reporter.warning(
+ field[-1] += self.document.reporter.warning(
'Cannot extract empty bibliographic field "%s".' % name)
return None
return 1
def check_compound_biblio_field(self, field, name):
if len(field[1]) > 1:
- field[-1] += self.doctree.reporter.warning(
+ field[-1] += self.document.reporter.warning(
'Cannot extract compound bibliographic field "%s".' % name)
return None
if not isinstance(field[1][0], nodes.paragraph):
- field[-1] += self.doctree.reporter.warning(
+ field[-1] += self.document.reporter.warning(
'Cannot extract bibliographic field "%s" containing anything '
'other than a single paragraph.'
% name)
@@ -308,19 +309,9 @@ class DocInfo(Transform):
rcs_keyword_substitutions = [
(re.compile(r'\$' r'Date: (\d\d\d\d)/(\d\d)/(\d\d) [\d:]+ \$$',
re.IGNORECASE), r'\1-\2-\3'),
- (re.compile(r'\$' r'RCSfile: (.+),v \$$',
- re.IGNORECASE), r'\1'),
+ (re.compile(r'\$' r'RCSfile: (.+),v \$$', re.IGNORECASE), r'\1'),
(re.compile(r'\$[a-zA-Z]+: (.+) \$$'), r'\1'),]
- def filter_rcs_keywords(self, paragraph):
- if len(paragraph) == 1 and isinstance(paragraph[0], nodes.Text):
- textnode = paragraph[0]
- for pattern, substitution in self.rcs_keyword_substitutions:
- match = pattern.match(textnode.data)
- if match:
- textnode.data = pattern.sub(substitution, textnode.data)
- return
-
def extract_authors(self, field, name, docinfo):
try:
if len(field[1]) == 1:
@@ -336,7 +327,7 @@ class DocInfo(Transform):
for author in authors if author]
docinfo.append(nodes.authors('', *authornodes))
except TransformError:
- field[-1] += self.doctree.reporter.warning(
+ field[-1] += self.document.reporter.warning(
'Bibliographic field "%s" incompatible with extraction: '
'it must contain either a single paragraph (with authors '
'separated by one of "%s"), multiple paragraphs (one per '
diff --git a/docutils/transforms/references.py b/docutils/transforms/references.py
index c2ff9189b..107bdfdee 100644
--- a/docutils/transforms/references.py
+++ b/docutils/transforms/references.py
@@ -25,22 +25,11 @@ class Hyperlinks(Transform):
"""Resolve the various types of hyperlink targets and references."""
def transform(self):
- stages = []
- #stages.append('Beginning of references.Hyperlinks.transform()\n' + self.doctree.pformat())
self.resolve_chained_targets()
- #stages.append('After references.Hyperlinks.resolve_chained_targets()\n' + self.doctree.pformat())
self.resolve_anonymous()
- #stages.append('After references.Hyperlinks.resolve_anonymous()\n' + self.doctree.pformat())
self.resolve_indirect()
- #stages.append('After references.Hyperlinks.resolve_indirect()\n' + self.doctree.pformat())
self.resolve_external_targets()
- #stages.append('After references.Hyperlinks.resolve_external_references()\n' + self.doctree.pformat())
self.resolve_internal_targets()
- #stages.append('After references.Hyperlinks.resolve_internal_references()\n' + self.doctree.pformat())
- #import difflib
- #compare = difflib.Differ().compare
- #for i in range(len(stages) - 1):
- # print ''.join(compare(stages[i].splitlines(1), stages[i+1].splitlines(1)))
def resolve_chained_targets(self):
"""
@@ -48,8 +37,8 @@ class Hyperlinks(Transform):
target up the chain of contiguous adjacent internal targets, using
`ChainedTargetResolver`.
"""
- visitor = ChainedTargetResolver(self.doctree)
- self.doctree.walk(visitor)
+ visitor = ChainedTargetResolver(self.document)
+ self.document.walk(visitor)
def resolve_anonymous(self):
"""
@@ -74,30 +63,30 @@ class Hyperlinks(Transform):
"""
- if len(self.doctree.anonymous_refs) \
- != len(self.doctree.anonymous_targets):
- msg = self.doctree.reporter.error(
+ if len(self.document.anonymous_refs) \
+ != len(self.document.anonymous_targets):
+ msg = self.document.reporter.error(
'Anonymous hyperlink mismatch: %s references but %s targets.'
- % (len(self.doctree.anonymous_refs),
- len(self.doctree.anonymous_targets)))
- self.doctree.messages += msg
- msgid = self.doctree.set_id(msg)
- for ref in self.doctree.anonymous_refs:
+ % (len(self.document.anonymous_refs),
+ len(self.document.anonymous_targets)))
+ self.document.messages += msg
+ msgid = self.document.set_id(msg)
+ for ref in self.document.anonymous_refs:
prb = nodes.problematic(
ref.rawsource, ref.rawsource, refid=msgid)
- prbid = self.doctree.set_id(prb)
+ prbid = self.document.set_id(prb)
msg.add_backref(prbid)
ref.parent.replace(ref, prb)
return
- for i in range(len(self.doctree.anonymous_refs)):
- ref = self.doctree.anonymous_refs[i]
- target = self.doctree.anonymous_targets[i]
+ for i in range(len(self.document.anonymous_refs)):
+ ref = self.document.anonymous_refs[i]
+ target = self.document.anonymous_targets[i]
if target.hasattr('refuri'):
ref['refuri'] = target['refuri']
ref.resolved = 1
else:
ref['refid'] = target['id']
- self.doctree.note_refid(ref)
+ self.document.note_refid(ref)
target.referenced = 1
def resolve_indirect(self):
@@ -150,9 +139,7 @@ class Hyperlinks(Transform):
"""
- #import mypdb as pdb
- #pdb.set_trace()
- for target in self.doctree.indirect_targets:
+ for target in self.document.indirect_targets:
if not target.resolved:
self.resolve_indirect_target(target)
self.resolve_indirect_references(target)
@@ -160,10 +147,10 @@ class Hyperlinks(Transform):
def resolve_indirect_target(self, target):
refname = target['refname']
reftarget = None
- if self.doctree.explicit_targets.has_key(refname):
- reftarget = self.doctree.explicit_targets[refname]
- elif self.doctree.implicit_targets.has_key(refname):
- reftarget = self.doctree.implicit_targets[refname]
+ if self.document.explicit_targets.has_key(refname):
+ reftarget = self.document.explicit_targets[refname]
+ elif self.document.implicit_targets.has_key(refname):
+ reftarget = self.document.implicit_targets[refname]
if not reftarget:
self.nonexistent_indirect_target(target)
return
@@ -173,14 +160,14 @@ class Hyperlinks(Transform):
if reftarget.hasattr('refuri'):
target['refuri'] = reftarget['refuri']
if target.hasattr('name'):
- self.doctree.note_external_target(target)
+ self.document.note_external_target(target)
elif reftarget.hasattr('refid'):
target['refid'] = reftarget['refid']
- self.doctree.note_refid(target)
+ self.document.note_refid(target)
else:
try:
target['refid'] = reftarget['id']
- self.doctree.note_refid(target)
+ self.document.note_refid(target)
except KeyError:
self.nonexistent_indirect_target(target)
return
@@ -192,19 +179,19 @@ class Hyperlinks(Transform):
naming = ''
if target.hasattr('name'):
naming = '"%s" ' % target['name']
- reflist = self.doctree.refnames[target['name']]
+ reflist = self.document.refnames[target['name']]
else:
- reflist = self.doctree.refnames[target['id']]
+ reflist = self.document.refnames[target['id']]
naming += '(id="%s")' % target['id']
- msg = self.doctree.reporter.warning(
+ msg = self.document.reporter.warning(
'Indirect hyperlink target %s refers to target "%s", '
'which does not exist.' % (naming, target['refname']))
- self.doctree.messages += msg
- msgid = self.doctree.set_id(msg)
+ self.document.messages += msg
+ msgid = self.document.set_id(msg)
for ref in reflist:
prb = nodes.problematic(
ref.rawsource, ref.rawsource, refid=msgid)
- prbid = self.doctree.set_id(prb)
+ prbid = self.document.set_id(prb)
msg.add_backref(prbid)
ref.parent.replace(ref, prb)
target.resolved = 1
@@ -213,39 +200,39 @@ class Hyperlinks(Transform):
if target.hasattr('refid'):
attname = 'refid'
call_if_named = 0
- call_method = self.doctree.note_refid
+ call_method = self.document.note_refid
elif target.hasattr('refuri'):
attname = 'refuri'
call_if_named = 1
- call_method = self.doctree.note_external_target
+ call_method = self.document.note_external_target
else:
return
attval = target[attname]
if target.hasattr('name'):
name = target['name']
try:
- reflist = self.doctree.refnames[name]
+ reflist = self.document.refnames[name]
except KeyError, instance:
if target.referenced:
return
- msg = self.doctree.reporter.info(
+ msg = self.document.reporter.info(
'Indirect hyperlink target "%s" is not referenced.'
% name)
- self.doctree.messages += msg
+ self.document.messages += msg
target.referenced = 1
return
delatt = 'refname'
else:
id = target['id']
try:
- reflist = self.doctree.refids[id]
+ reflist = self.document.refids[id]
except KeyError, instance:
if target.referenced:
return
- msg = self.doctree.reporter.info(
+ msg = self.document.reporter.info(
'Indirect hyperlink target id="%s" is not referenced.'
% id)
- self.doctree.messages += msg
+ self.document.messages += msg
target.referenced = 1
return
delatt = 'refid'
@@ -277,19 +264,19 @@ class Hyperlinks(Transform):
direct external
"""
- for target in self.doctree.external_targets:
+ for target in self.document.external_targets:
if target.hasattr('refuri') and target.hasattr('name'):
name = target['name']
refuri = target['refuri']
try:
- reflist = self.doctree.refnames[name]
+ reflist = self.document.refnames[name]
except KeyError, instance:
if target.referenced:
continue
- msg = self.doctree.reporter.info(
+ msg = self.document.reporter.info(
'External hyperlink target "%s" is not referenced.'
% name)
- self.doctree.messages += msg
+ self.document.messages += msg
target.referenced = 1
continue
for ref in reflist:
@@ -317,21 +304,21 @@ class Hyperlinks(Transform):
direct internal
"""
- for target in self.doctree.internal_targets:
+ for target in self.document.internal_targets:
if target.hasattr('refuri') or target.hasattr('refid') \
or not target.hasattr('name'):
continue
name = target['name']
refid = target['id']
try:
- reflist = self.doctree.refnames[name]
+ reflist = self.document.refnames[name]
except KeyError, instance:
if target.referenced:
continue
- msg = self.doctree.reporter.info(
+ msg = self.document.reporter.info(
'Internal hyperlink target "%s" is not referenced.'
% name)
- self.doctree.messages += msg
+ self.document.messages += msg
target.referenced = 1
continue
for ref in reflist:
@@ -352,7 +339,7 @@ class ChainedTargetResolver(nodes.NodeVisitor):
"point to" an external or indirect target. After the transform, all
chained targets will effectively point to the same place.
- Given the following ``doctree`` as input::
+ Given the following ``document`` as input::
@@ -365,7 +352,7 @@ class ChainedTargetResolver(nodes.NodeVisitor):
- ``ChainedTargetResolver(doctree).walk()`` will transform the above into::
+ ``ChainedTargetResolver(document).walk()`` will transform the above into::
@@ -385,10 +372,10 @@ class ChainedTargetResolver(nodes.NodeVisitor):
def visit_target(self, node):
if node.hasattr('refuri'):
attname = 'refuri'
- call_if_named = self.doctree.note_external_target
+ call_if_named = self.document.note_external_target
elif node.hasattr('refname'):
attname = 'refname'
- call_if_named = self.doctree.note_indirect_target
+ call_if_named = self.document.note_indirect_target
elif node.hasattr('refid'):
attname = 'refid'
call_if_named = None
@@ -414,7 +401,7 @@ class Footnotes(Transform):
Assign numbers to autonumbered footnotes, and resolve links to footnotes,
citations, and their references.
- Given the following ``doctree`` as input::
+ Given the following ``document`` as input::
@@ -491,8 +478,8 @@ class Footnotes(Transform):
def transform(self):
self.autofootnote_labels = []
- startnum = self.doctree.autofootnote_start
- self.doctree.autofootnote_start = self.number_footnotes(startnum)
+ startnum = self.document.autofootnote_start
+ self.document.autofootnote_start = self.number_footnotes(startnum)
self.number_footnote_references(startnum)
self.symbolize_footnotes()
self.resolve_footnotes_and_citations()
@@ -504,58 +491,58 @@ class Footnotes(Transform):
For labeled autonumbered footnotes, copy the number over to
corresponding footnote references.
"""
- for footnote in self.doctree.autofootnotes:
+ for footnote in self.document.autofootnotes:
while 1:
label = str(startnum)
startnum += 1
- if not self.doctree.explicit_targets.has_key(label):
+ if not self.document.explicit_targets.has_key(label):
break
footnote.insert(0, nodes.label('', label))
if footnote.hasattr('dupname'):
continue
if footnote.hasattr('name'):
name = footnote['name']
- for ref in self.doctree.footnote_refs.get(name, []):
+ for ref in self.document.footnote_refs.get(name, []):
ref += nodes.Text(label)
ref.delattr('refname')
ref['refid'] = footnote['id']
footnote.add_backref(ref['id'])
- self.doctree.note_refid(ref)
+ self.document.note_refid(ref)
ref.resolved = 1
else:
footnote['name'] = label
- self.doctree.note_explicit_target(footnote, footnote)
+ self.document.note_explicit_target(footnote, footnote)
self.autofootnote_labels.append(label)
return startnum
def number_footnote_references(self, startnum):
"""Assign numbers to autonumbered footnote references."""
i = 0
- for ref in self.doctree.autofootnote_refs:
+ for ref in self.document.autofootnote_refs:
if ref.resolved or ref.hasattr('refid'):
continue
try:
label = self.autofootnote_labels[i]
except IndexError:
- msg = self.doctree.reporter.error(
+ msg = self.document.reporter.error(
'Too many autonumbered footnote references: only %s '
'corresponding footnotes available.'
% len(self.autofootnote_labels))
- msgid = self.doctree.set_id(msg)
- self.doctree.messages += msg
- for ref in self.doctree.autofootnote_refs[i:]:
+ msgid = self.document.set_id(msg)
+ self.document.messages += msg
+ for ref in self.document.autofootnote_refs[i:]:
if ref.resolved or ref.hasattr('refname'):
continue
prb = nodes.problematic(
ref.rawsource, ref.rawsource, refid=msgid)
- prbid = self.doctree.set_id(prb)
+ prbid = self.document.set_id(prb)
msg.add_backref(prbid)
ref.parent.replace(ref, prb)
break
ref += nodes.Text(label)
- footnote = self.doctree.explicit_targets[label]
+ footnote = self.document.explicit_targets[label]
ref['refid'] = footnote['id']
- self.doctree.note_refid(ref)
+ self.document.note_refid(ref)
footnote.add_backref(ref['id'])
ref.resolved = 1
i += 1
@@ -563,36 +550,36 @@ class Footnotes(Transform):
def symbolize_footnotes(self):
"""Add symbols indexes to "[*]"-style footnotes and references."""
labels = []
- for footnote in self.doctree.symbol_footnotes:
- reps, index = divmod(self.doctree.symbol_footnote_start,
+ for footnote in self.document.symbol_footnotes:
+ reps, index = divmod(self.document.symbol_footnote_start,
len(self.symbols))
labeltext = self.symbols[index] * (reps + 1)
labels.append(labeltext)
footnote.insert(0, nodes.label('', labeltext))
- self.doctree.symbol_footnote_start += 1
- self.doctree.set_id(footnote)
+ self.document.symbol_footnote_start += 1
+ self.document.set_id(footnote)
i = 0
- for ref in self.doctree.symbol_footnote_refs:
+ for ref in self.document.symbol_footnote_refs:
try:
ref += nodes.Text(labels[i])
except IndexError:
- msg = self.doctree.reporter.error(
+ msg = self.document.reporter.error(
'Too many symbol footnote references: only %s '
'corresponding footnotes available.' % len(labels))
msgid = self.set_id(msg)
- self.doctree.messages += msg
- for ref in self.doctree.symbol_footnote_refs[i:]:
+ self.document.messages += msg
+ for ref in self.document.symbol_footnote_refs[i:]:
if ref.resolved or ref.hasattr('refid'):
continue
prb = nodes.problematic(
ref.rawsource, ref.rawsource, refid=msgid)
- prbid = self.doctree.set_id(prb)
+ prbid = self.document.set_id(prb)
msg.add_backref(prbid)
ref.parent.replace(ref, prb)
break
- footnote = self.doctree.symbol_footnotes[i]
+ footnote = self.document.symbol_footnotes[i]
ref['refid'] = footnote['id']
- self.doctree.note_refid(ref)
+ self.document.note_refid(ref)
footnote.add_backref(ref['id'])
i += 1
@@ -600,15 +587,15 @@ class Footnotes(Transform):
"""
Link manually-labeled footnotes and citations to/from their references.
"""
- for footnote in self.doctree.footnotes:
+ for footnote in self.document.footnotes:
label = footnote['name']
- if self.doctree.footnote_refs.has_key(label):
- reflist = self.doctree.footnote_refs[label]
+ if self.document.footnote_refs.has_key(label):
+ reflist = self.document.footnote_refs[label]
self.resolve_references(footnote, reflist)
- for citation in self.doctree.citations:
+ for citation in self.document.citations:
label = citation['name']
- if self.doctree.citation_refs.has_key(label):
- reflist = self.doctree.citation_refs[label]
+ if self.document.citation_refs.has_key(label):
+ reflist = self.document.citation_refs[label]
self.resolve_references(citation, reflist)
def resolve_references(self, note, reflist):
@@ -626,7 +613,7 @@ class Footnotes(Transform):
class Substitutions(Transform):
"""
- Given the following ``doctree`` as input::
+ Given the following ``document`` as input::
@@ -652,19 +639,19 @@ class Substitutions(Transform):
"""
def transform(self):
- defs = self.doctree.substitution_defs
- for refname, refs in self.doctree.substitution_refs.items():
+ defs = self.document.substitution_defs
+ for refname, refs in self.document.substitution_refs.items():
for ref in refs:
if defs.has_key(refname):
ref.parent.replace(ref, defs[refname].getchildren())
else:
- msg = self.doctree.reporter.error(
+ msg = self.document.reporter.error(
'Undefined substitution referenced: "%s".' % refname)
- msgid = self.doctree.set_id(msg)
- self.doctree.messages += msg
+ msgid = self.document.set_id(msg)
+ self.document.messages += msg
prb = nodes.problematic(
ref.rawsource, ref.rawsource, refid=msgid)
- prbid = self.doctree.set_id(prb)
+ prbid = self.document.set_id(prb)
msg.add_backref(prbid)
ref.parent.replace(ref, prb)
- self.doctree.substitution_refs = None # release replaced references
+ self.document.substitution_refs = None # release replaced references
diff --git a/docutils/utils.py b/docutils/utils.py
index a92c8fb97..0602b8d64 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -12,9 +12,10 @@ Miscellaneous utilities for the documentation utilities.
import sys, re
import nodes
+from docutils import ApplicationError, DataError
-class SystemMessage(Exception):
+class SystemMessage(ApplicationError):
def __init__(self, system_message):
Exception.__init__(self, system_message.astext())
@@ -59,15 +60,15 @@ class Reporter:
levels = 'DEBUG INFO WARNING ERROR SEVERE'.split()
"""List of names for system message levels, indexed by level."""
- def __init__(self, warninglevel, errorlevel, stream=None, debug=0):
+ def __init__(self, warning_level, error_level, stream=None, debug=0):
"""
Initialize the `ConditionSet` forthe `Reporter`'s default category.
:Parameters:
- - `warninglevel`: The level at or above which warning output will
+ - `warning_level`: The level at or above which warning output will
be sent to `stream`.
- - `errorlevel`: The level at or above which `SystemMessage`
+ - `error_level`: The level at or above which `SystemMessage`
exceptions will be raised.
- `debug`: Show debug (level=0) system messages?
- `stream`: Where warning output is sent (`None` implies
@@ -77,29 +78,29 @@ class Reporter:
if stream is None:
stream = sys.stderr
- self.categories = {'': ConditionSet(debug, warninglevel, errorlevel,
+ self.categories = {'': ConditionSet(debug, warning_level, error_level,
stream)}
"""Mapping of category names to conditions. Default category is ''."""
- def setconditions(self, category, warninglevel, errorlevel,
- stream=None, debug=0):
+ def set_conditions(self, category, warning_level, error_level,
+ stream=None, debug=0):
if stream is None:
stream = sys.stderr
- self.categories[category] = ConditionSet(debug, warninglevel,
- errorlevel, stream)
+ self.categories[category] = ConditionSet(debug, warning_level,
+ error_level, stream)
- def unsetconditions(self, category):
+ def unset_conditions(self, category):
if category and self.categories.has_key(category):
del self.categories[category]
- __delitem__ = unsetconditions
+ __delitem__ = unset_conditions
- def getconditions(self, category):
+ def get_conditions(self, category):
while not self.categories.has_key(category):
category = category[:category.rfind('.') + 1][:-1]
return self.categories[category]
- __getitem__ = getconditions
+ __getitem__ = get_conditions
def system_message(self, level, comment=None, category='',
*children, **attributes):
@@ -111,13 +112,13 @@ class Reporter:
msg = nodes.system_message(comment, level=level,
type=self.levels[level],
*children, **attributes)
- debug, warninglevel, errorlevel, stream = self[category].astuple()
- if level >= warninglevel or debug and level == 0:
+ debug, warning_level, error_level, stream = self[category].astuple()
+ if level >= warning_level or debug and level == 0:
if category:
print >>stream, 'Reporter "%s":' % category, msg.astext()
else:
print >>stream, 'Reporter:', msg.astext()
- if level >= errorlevel:
+ if level >= error_level:
raise SystemMessage(msg)
return msg
@@ -171,18 +172,18 @@ class ConditionSet:
category.
"""
- def __init__(self, debug, warninglevel, errorlevel, stream):
+ def __init__(self, debug, warning_level, error_level, stream):
self.debug = debug
- self.warninglevel = warninglevel
- self.errorlevel = errorlevel
+ self.warning_level = warning_level
+ self.error_level = error_level
self.stream = stream
def astuple(self):
- return (self.debug, self.warninglevel, self.errorlevel,
+ return (self.debug, self.warning_level, self.error_level,
self.stream)
-class ExtensionAttributeError(Exception): pass
+class ExtensionAttributeError(DataError): pass
class BadAttributeError(ExtensionAttributeError): pass
class BadAttributeDataError(ExtensionAttributeError): pass
class DuplicateAttributeError(ExtensionAttributeError): pass
@@ -272,7 +273,7 @@ def assemble_attribute_dict(attlist, attspec):
return attributes
-class NameValueError(Exception): pass
+class NameValueError(DataError): pass
def extract_name_value(line):
@@ -320,7 +321,7 @@ def extract_name_value(line):
return attlist
-def normname(name):
+def normalize_name(name):
"""Return a case- and whitespace-normalized name."""
return ' '.join(name.lower().split())
@@ -359,15 +360,24 @@ def id(string):
.. _HTML 4.01 spec: http://www.w3.org/TR/html401
.. _CSS1 spec: http://www.w3.org/TR/REC-CSS1
"""
- id = non_id_chars.sub('-', normname(string))
+ id = non_id_chars.sub('-', normalize_name(string))
id = non_id_at_ends.sub('', id)
return str(id)
non_id_chars = re.compile('[^a-z0-9]+')
non_id_at_ends = re.compile('^[-0-9]+|-+$')
-def newdocument(languagecode='en', warninglevel=2, errorlevel=4,
- stream=None, debug=0):
- reporter = Reporter(warninglevel, errorlevel, stream, debug)
- document = nodes.document(languagecode=languagecode, reporter=reporter)
+def new_document(language_code='en', warning_level=2, error_level=4,
+ stream=None, debug=0):
+ reporter = Reporter(warning_level, error_level, stream, debug)
+ document = nodes.document(language_code=language_code, reporter=reporter)
return document
+
+def clean_rcs_keywords(paragraph, keyword_substitutions):
+ if len(paragraph) == 1 and isinstance(paragraph[0], nodes.Text):
+ textnode = paragraph[0]
+ for pattern, substitution in keyword_substitutions:
+ match = pattern.match(textnode.data)
+ if match:
+ textnode.data = pattern.sub(substitution, textnode.data)
+ return
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
index 6d9d7c226..0f560e7ee 100644
--- a/docutils/writers/__init__.py
+++ b/docutils/writers/__init__.py
@@ -14,11 +14,11 @@ __docformat__ = 'reStructuredText'
import sys
-from docutils import languages
+from docutils import languages, Component
from docutils.transforms import universal
-class Writer:
+class Writer(Component):
"""
Abstract base class for docutils Writers.
@@ -49,7 +49,7 @@ class Writer:
def write(self, document, destination):
self.document = document
- self.language = languages.getlanguage(document.languagecode)
+ self.language = languages.getlanguage(document.language_code)
self.destination = destination
self.transform()
self.translate()
@@ -60,7 +60,7 @@ class Writer:
for xclass in (universal.first_writer_transforms
+ tuple(self.transforms)
+ universal.last_writer_transforms):
- xclass(self.document).transform()
+ xclass(self.document, self).transform()
def translate(self):
"""Override to do final document tree translation."""
@@ -93,12 +93,14 @@ class Writer:
_writer_aliases = {
- 'html': 'html4css1',}
-
-def get_writer_class(writername):
- """Return the Writer class from the `writername` module."""
- writername = writername.lower()
- if _writer_aliases.has_key(writername):
- writername = _writer_aliases[writername]
- module = __import__(writername, globals(), locals())
+ 'html': 'html4css1',
+ 'pprint': 'pseudoxml',
+ 'pformat': 'pseudoxml',}
+
+def get_writer_class(writer_name):
+ """Return the Writer class from the `writer_name` module."""
+ writer_name = writer_name.lower()
+ if _writer_aliases.has_key(writer_name):
+ writer_name = _writer_aliases[writer_name]
+ module = __import__(writer_name, globals(), locals())
return module.Writer
--
cgit v1.2.1
From f6d1d682215cee2501c938cf8389d720ef6118df Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 15:59:03 +0000
Subject: refactored; improved compound names
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@95 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/languages/__init__.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/languages/__init__.py b/docutils/parsers/rst/languages/__init__.py
index ee36d1148..07b44ea86 100644
--- a/docutils/parsers/rst/languages/__init__.py
+++ b/docutils/parsers/rst/languages/__init__.py
@@ -15,9 +15,9 @@ __docformat__ = 'reStructuredText'
_languages = {}
-def getlanguage(languagecode):
- if _languages.has_key(languagecode):
- return _languages[languagecode]
- module = __import__(languagecode, globals(), locals())
- _languages[languagecode] = module
+def getlanguage(language_code):
+ if _languages.has_key(language_code):
+ return _languages[language_code]
+ module = __import__(language_code, globals(), locals())
+ _languages[language_code] = module
return module
--
cgit v1.2.1
From e46540a319e09246ce45b26776e3b1408d04a7b4 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 5 May 2002 16:18:00 +0000
Subject: removed some debugging code
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@96 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/peps.py | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
index d3dca5b0e..ba311d488 100644
--- a/docutils/transforms/peps.py
+++ b/docutils/transforms/peps.py
@@ -17,7 +17,6 @@ __docformat__ = 'reStructuredText'
import sys, os, re, time
from docutils import nodes, utils, ApplicationError, DataError
from docutils.transforms import Transform, TransformError
-import mypdb as pdb
class Headers(Transform):
@@ -40,7 +39,6 @@ class Headers(Transform):
raise DataError('Document does not begin with an RFC-2822 '
'header; it is not a PEP.')
pep = title = None
- #pdb.set_trace()
for field in header:
if field[0].astext().lower() == 'pep': # should be the first field
pep = int(field[1].astext())
@@ -51,7 +49,6 @@ class Headers(Transform):
for field in header:
name = field[0].astext().lower()
body = field[1]
- print >>sys.stderr, 'name=%s, body=%s' % (name, body.astext()) ; sys.stderr.flush()
if len(body) > 1:
raise DataError('PEP header field body contains multiple '
'elements:\n%s' % field.pformat(level=1))
@@ -72,7 +69,8 @@ class Headers(Transform):
para = body[0]
if name == 'title':
title = body.astext()
- # @@@ Insert a "pending" element here, since we don't really want a separate document title?
+ # @@@ Insert a "pending" element here, since we don't really
+ # want a separate document title?
elif name in ('author', 'discussions-to'):
for node in para:
if isinstance(node, nodes.reference) \
@@ -89,11 +87,9 @@ class Headers(Transform):
newbody.append(space)
para[:] = newbody[:-1] # drop trailing space
elif name == 'last-modified':
- #pdb.set_trace()
utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
date = para.astext()
uri = self.pep_cvs_url % int(pep)
para[:] = [nodes.reference('', date, refuri=uri)]
elif name == 'version' and len(body):
utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
- print >>sys.stderr, 'name=%s, body=%s' % (name, body.astext()) ; sys.stderr.flush()
--
cgit v1.2.1
From c0405e481cc67c4aae4feb3de44696bc13760acd Mon Sep 17 00:00:00 2001
From: goodger
Date: Mon, 6 May 2002 03:28:16 +0000
Subject: - Renamed ``TreePruningException`` from ``VisitorException``. -
Added docstrings to ``TreePruningException``, subclasses, and
``Nodes.walk()``.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@99 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 82 +++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 67 insertions(+), 15 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 803fbc82e..00e7d532d 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -59,10 +59,16 @@ class Node:
Traverse a tree of `Node` objects, calling ``visit_...`` methods of
`visitor` when entering each node. If there is no
``visit_particular_node`` method for a node of type
- ``particular_node``, the ``unknown_visit`` method is called.
+ ``particular_node``, the ``unknown_visit`` method is called. (The
+ `walkabout()` method is similar, except it also calls ``depart_...``
+ methods before exiting each node.)
- Doesn't handle arbitrary modification in-place during the traversal.
- Replacing one element with one element is OK.
+ This tree traversal doesn't handle arbitrary in-place tree
+ modifications. Replacing one element with one element is OK.
+
+ Within ``visit_...`` methods (and ``depart_...`` methods for
+ `walkabout()`), `TreePruningException` subclasses may be raised
+ (`SkipChildren`, `SkipSiblings`, `SkipNode`, `SkipDeparture`).
Parameter `visitor`: A `NodeVisitor` object, containing a
``visit_...`` method for each `Node` subclass encountered.
@@ -85,9 +91,9 @@ class Node:
def walkabout(self, visitor):
"""
- Perform a tree traversal similarly to `Node.walk()`, except also call
- ``depart_...`` methods before exiting each node. If there is no
- ``depart_particular_node`` method for a node of type
+ Perform a tree traversal similarly to `Node.walk()` (which see),
+ except also call ``depart_...`` methods before exiting each node. If
+ there is no ``depart_particular_node`` method for a node of type
``particular_node``, the ``unknown_departure`` method is called.
Parameter `visitor`: A `NodeVisitor` object, containing ``visit_...``
@@ -1138,13 +1144,6 @@ class GenericNodeVisitor(NodeVisitor):
del name
-class VisitorException(Exception): pass
-class SkipChildren(VisitorException): pass
-class SkipSiblings(VisitorException): pass
-class SkipNode(VisitorException): pass
-class SkipDeparture(VisitorException): pass
-
-
class TreeCopyVisitor(GenericNodeVisitor):
"""
@@ -1159,11 +1158,64 @@ class TreeCopyVisitor(GenericNodeVisitor):
return self.parent_stack[0][0]
def default_visit(self, node):
- """"""
+ """Copy the current node, and make it the new acting parent."""
newnode = node.copy()
self.parent_stack[-1].append(newnode)
self.parent_stack.append(newnode)
def default_departure(self, node):
- """"""
+ """Restore the previous acting parent."""
self.parent_stack.pop()
+
+
+class TreePruningException(Exception):
+
+ """
+ Base class for `NodeVisitor`-related tree pruning exceptions.
+
+ Raise subclasses from within ``visit_...`` or ``depart_...`` methods
+ called from `Node.walk()` and `Node.walkabout()` tree traversals to prune
+ the tree traversed.
+ """
+
+ pass
+
+
+class SkipChildren(TreePruningException):
+
+ """
+ Do not visit any children of the current node. The current node's
+ siblings and ``depart_...`` method are not affected.
+ """
+
+ pass
+
+
+class SkipSiblings(TreePruningException):
+
+ """
+ Do not visit any more siblings (to the right) of the current node. The
+ current node's children and its ``depart_...`` method are not affected.
+ """
+
+ pass
+
+
+class SkipNode(TreePruningException):
+
+ """
+ Do not visit the current node's children, and do not call the current
+ node's ``depart_...`` method.
+ """
+
+ pass
+
+
+class SkipDeparture(TreePruningException):
+
+ """
+ Do not call the current node's ``depart_...`` method. The current node's
+ children and siblings are not affected.
+ """
+
+ pass
--
cgit v1.2.1
From bb7d59f401c5548c607574294c3ae4e23d4f6a22 Mon Sep 17 00:00:00 2001
From: richard
Date: Mon, 6 May 2002 04:53:08 +0000
Subject: Lose the extraneous blank line from the start of literal blocks.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@104 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 0390502d2..acbf5a66c 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -479,7 +479,8 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('')
def visit_literal_block(self, node):
- self.body.append(self.starttag(node, 'pre', CLASS='literal-block'))
+ self.body.append(self.starttag(node, 'pre', suffix='',
+ CLASS='literal-block'))
def depart_literal_block(self, node):
self.body.append('\n')
--
cgit v1.2.1
From 7cd21ab928fcae9a597ae04c69ae74b41b919ec4 Mon Sep 17 00:00:00 2001
From: richard
Date: Mon, 6 May 2002 07:45:06 +0000
Subject: ... same goes for doctest blocks
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@105 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index acbf5a66c..2e26a785c 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -289,7 +289,8 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('
\n')
def visit_doctest_block(self, node):
- self.body.append(self.starttag(node, 'pre', CLASS='doctest-block'))
+ self.body.append(self.starttag(node, 'pre', suffix='',
+ CLASS='doctest-block'))
def depart_doctest_block(self, node):
self.body.append('\n')
--
cgit v1.2.1
From d44e62eb34941a552ee243fef90b529064eda265 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 7 May 2002 04:15:17 +0000
Subject: - Improved boilerplate & modularity of output.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@106 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 38 ++++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 2e26a785c..eb62d6206 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -41,23 +41,37 @@ class Writer(writers.Writer):
class HTMLTranslator(nodes.NodeVisitor):
+ xml_declaration = '\n'
+ doctype = '\n'
+ html_head = '\n\n'
+ content_type = '\n',
+ stylesheet_link = '\n']
+
def __init__(self, document):
nodes.NodeVisitor.__init__(self, document)
- self.language = languages.getlanguage(document.language_code)
- self.head = ['\n',
- '\n\n' % document.language_code,
- '\n']
- self.body = ['\n\n']
- self.foot = ['\n\n']
+ self.language = languages.get_language(document.language_code)
+ self.head_prefix = [
+ self.xml_declaration, # @@@ % output_encoding
+ self.doctype,
+ self.html_head % document.language_code,
+ self.content_type, # @@@ % output encoding
+ self.stylesheet_link] # @@@ % stylesheet
+ self.head = []
+ self.body_prefix = ['\n\n']
+ self.body = []
+ self.body_suffix = ['\n\n']
self.sectionlevel = 0
self.context = []
self.topic_class = ''
def astext(self):
- return ''.join(self.head + self.body + self.foot)
+ return ''.join(self.head_prefix + self.head
+ + self.body_prefix + self.body + self.body_suffix)
def encode(self, text):
"""Encode special characters in `text` & return."""
@@ -290,7 +304,7 @@ class HTMLTranslator(nodes.NodeVisitor):
def visit_doctest_block(self, node):
self.body.append(self.starttag(node, 'pre', suffix='',
- CLASS='doctest-block'))
+ CLASS='doctest-block'))
def depart_doctest_block(self, node):
self.body.append('\n')
@@ -481,7 +495,7 @@ class HTMLTranslator(nodes.NodeVisitor):
def visit_literal_block(self, node):
self.body.append(self.starttag(node, 'pre', suffix='',
- CLASS='literal-block'))
+ CLASS='literal-block'))
def depart_literal_block(self, node):
self.body.append('\n')
--
cgit v1.2.1
From 5acb5943d2383d82e4e180a49905f6d7f7eb7337 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 7 May 2002 04:18:13 +0000
Subject: - Fixed bug reporting (line #) when no blank line.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@107 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index d2a133198..434888417 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -141,7 +141,7 @@ class RSTStateMachine(StateMachineWS):
StateMachine, and return the resulting
document.
"""
- self.language = languages.getlanguage(document.language_code)
+ self.language = languages.get_language(document.language_code)
self.match_titles = match_titles
if inliner is None:
inliner = Inliner()
@@ -947,9 +947,9 @@ class Body(RSTState):
input_offset=self.state_machine.abs_line_offset() + 1,
node=bulletlist, initial_state='BulletList',
blank_finish=blank_finish)
+ self.goto_line(newline_offset)
if not blank_finish:
self.parent += self.unindent_warning('Bullet list')
- self.goto_line(newline_offset)
return [], next_state, []
def list_item(self, indent):
@@ -1000,9 +1000,9 @@ class Body(RSTState):
node=enumlist, initial_state='EnumeratedList',
blank_finish=blank_finish,
extra_settings={'lastordinal': ordinal, 'format': format})
+ self.goto_line(newline_offset)
if not blank_finish:
self.parent += self.unindent_warning('Enumerated list')
- self.goto_line(newline_offset)
return [], next_state, []
def parse_enumerator(self, match, expected_sequence=None):
@@ -1067,9 +1067,9 @@ class Body(RSTState):
input_offset=self.state_machine.abs_line_offset() + 1,
node=fieldlist, initial_state='FieldList',
blank_finish=blank_finish)
+ self.goto_line(newline_offset)
if not blank_finish:
self.parent += self.unindent_warning('Field list')
- self.goto_line(newline_offset)
return [], next_state, []
def field(self, match):
@@ -1119,9 +1119,9 @@ class Body(RSTState):
input_offset=self.state_machine.abs_line_offset() + 1,
node=optionlist, initial_state='OptionList',
blank_finish=blank_finish)
+ self.goto_line(newline_offset)
if not blank_finish:
self.parent += self.unindent_warning('Option list')
- self.goto_line(newline_offset)
return [], next_state, []
def option_list_item(self, match):
@@ -1740,10 +1740,10 @@ class RFC2822Body(Body):
input_offset=self.state_machine.abs_line_offset() + 1,
node=fieldlist, initial_state='RFC2822List',
blank_finish=blank_finish)
+ self.goto_line(newline_offset)
if not blank_finish:
self.parent += self.unindent_warning(
'RFC2822-style field list')
- self.goto_line(newline_offset)
return [], next_state, []
def rfc2822_field(self, match):
@@ -1964,9 +1964,9 @@ class Text(RSTState):
input_offset=self.state_machine.abs_line_offset() + 1,
node=definitionlist, initial_state='DefinitionList',
blank_finish=blank_finish, blank_finish_state='Definition')
+ self.goto_line(newline_offset)
if not blank_finish:
self.parent += self.unindent_warning('Definition list')
- self.goto_line(newline_offset)
return [], 'Body', []
def underline(self, match, context, next_state):
--
cgit v1.2.1
From 56c5b187bf5a81759b2fcbb817824454382a1038 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 7 May 2002 04:19:58 +0000
Subject: - Improved ``TreeCopyVisitor`` class. - Improved names.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@108 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 00e7d532d..275469f6e 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -82,7 +82,7 @@ class Node:
return
except SkipDeparture: # not applicable; ignore
pass
- children = self.getchildren()
+ children = self.get_children()
try:
for i in range(len(children)):
children[i].walk(visitor)
@@ -110,7 +110,7 @@ class Node:
return
except SkipDeparture:
call_depart = 0
- children = self.getchildren()
+ children = self.get_children()
try:
for i in range(len(children)):
children[i].walkabout(visitor)
@@ -161,7 +161,7 @@ class Text(Node, MutableString):
result.append(indent + line + '\n')
return ''.join(result)
- def getchildren(self):
+ def get_children(self):
"""Text nodes have no children. Return []."""
return []
@@ -396,7 +396,7 @@ class Element(Node):
elif new is not None:
self[index:index+1] = new
- def findclass(self, childclass, start=0, end=sys.maxint):
+ def first_child_matching_class(self, childclass, start=0, end=sys.maxint):
"""
Return the index of the first child whose class exactly matches.
@@ -415,7 +415,8 @@ class Element(Node):
return index
return None
- def findnonclass(self, childclass, start=0, end=sys.maxint):
+ def first_child_not_matching_class(self, childclass, start=0,
+ end=sys.maxint):
"""
Return the index of the first child whose class does *not* match.
@@ -442,7 +443,7 @@ class Element(Node):
[child.pformat(indent, level+1)
for child in self.children])
- def getchildren(self):
+ def get_children(self):
"""Return this element's children."""
return self.children
@@ -1152,20 +1153,22 @@ class TreeCopyVisitor(GenericNodeVisitor):
def __init__(self, document):
GenericNodeVisitor.__init__(self, document)
- self.parent_stack = [[]]
+ self.parent_stack = []
+ self.parent = []
def get_tree_copy(self):
- return self.parent_stack[0][0]
+ return self.parent[0]
def default_visit(self, node):
"""Copy the current node, and make it the new acting parent."""
newnode = node.copy()
- self.parent_stack[-1].append(newnode)
- self.parent_stack.append(newnode)
+ self.parent.append(newnode)
+ self.parent_stack.append(self.parent)
+ self.parent = newnode
def default_departure(self, node):
"""Restore the previous acting parent."""
- self.parent_stack.pop()
+ self.parent = self.parent_stack.pop()
class TreePruningException(Exception):
--
cgit v1.2.1
From e5744d83bfa217b861297a76840492691f1896d2 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 7 May 2002 04:22:10 +0000
Subject: name improvements
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@109 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/languages/__init__.py | 2 +-
docutils/parsers/rst/directives/html.py | 2 +-
docutils/parsers/rst/languages/__init__.py | 2 +-
docutils/transforms/__init__.py | 2 +-
docutils/transforms/frontmatter.py | 9 ++++++---
docutils/transforms/parts.py | 4 ++--
docutils/transforms/references.py | 20 +++++++++++---------
docutils/transforms/universal.py | 4 ++--
docutils/writers/__init__.py | 4 ++--
9 files changed, 27 insertions(+), 22 deletions(-)
(limited to 'docutils')
diff --git a/docutils/languages/__init__.py b/docutils/languages/__init__.py
index 0de3674d7..bdddb5697 100644
--- a/docutils/languages/__init__.py
+++ b/docutils/languages/__init__.py
@@ -14,7 +14,7 @@ __docformat__ = 'reStructuredText'
_languages = {}
-def getlanguage(language_code):
+def get_language(language_code):
if _languages.has_key(language_code):
return _languages[language_code]
module = __import__(language_code, globals(), locals())
diff --git a/docutils/parsers/rst/directives/html.py b/docutils/parsers/rst/directives/html.py
index 262a124c8..d21ff0505 100644
--- a/docutils/parsers/rst/directives/html.py
+++ b/docutils/parsers/rst/directives/html.py
@@ -39,7 +39,7 @@ def meta(match, type_name, data, state, state_machine, attributes):
msg = state_machine.reporter.error('Empty meta directive at line %s.'
% state_machine.abs_line_number())
node += msg
- return node.getchildren(), blank_finish
+ return node.get_children(), blank_finish
def imagemap(match, type_name, data, state, state_machine, attributes):
return [], 0
diff --git a/docutils/parsers/rst/languages/__init__.py b/docutils/parsers/rst/languages/__init__.py
index 07b44ea86..4a5441e9e 100644
--- a/docutils/parsers/rst/languages/__init__.py
+++ b/docutils/parsers/rst/languages/__init__.py
@@ -15,7 +15,7 @@ __docformat__ = 'reStructuredText'
_languages = {}
-def getlanguage(language_code):
+def get_language(language_code):
if _languages.has_key(language_code):
return _languages[language_code]
module = __import__(language_code, globals(), locals())
diff --git a/docutils/transforms/__init__.py b/docutils/transforms/__init__.py
index ddf92cb65..55e656bff 100644
--- a/docutils/transforms/__init__.py
+++ b/docutils/transforms/__init__.py
@@ -59,7 +59,7 @@ class Transform(Component):
apply to the document as a whole, `startnode` is not set (i.e. its
value is `None`)."""
- self.language = languages.getlanguage(document.language_code)
+ self.language = languages.get_language(document.language_code)
"""Language module local to this document."""
def transform(self):
diff --git a/docutils/transforms/frontmatter.py b/docutils/transforms/frontmatter.py
index d4bfce832..c5aaa0d1e 100644
--- a/docutils/transforms/frontmatter.py
+++ b/docutils/transforms/frontmatter.py
@@ -144,7 +144,8 @@ class DocTitle(Transform):
Return (None, None) if no valid candidate was found.
"""
document = self.document
- index = document.findnonclass(nodes.PreBibliographic)
+ index = document.first_child_not_matching_class(
+ nodes.PreBibliographic)
if index is None or len(document) > (index + 1) or \
not isinstance(document[index], nodes.section):
return None, None
@@ -225,12 +226,14 @@ class DocInfo(Transform):
def transform(self):
document = self.document
- index = document.findnonclass(nodes.PreBibliographic)
+ index = document.first_child_not_matching_class(
+ nodes.PreBibliographic)
if index is None:
return
candidate = document[index]
if isinstance(candidate, nodes.field_list):
- biblioindex = document.findnonclass(nodes.Titular)
+ biblioindex = document.first_child_not_matching_class(
+ nodes.Titular)
nodelist, remainder = self.extract_bibliographic(candidate)
if remainder:
document[index] = remainder
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index 50667a1fa..ac9ad0466 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -95,7 +95,7 @@ class Contents(Transform):
class ContentsFilter(nodes.TreeCopyVisitor):
def get_entry_text(self):
- return self.get_tree_copy().getchildren()
+ return self.get_tree_copy().get_children()
def visit_citation_reference(self, node):
raise nodes.SkipNode
@@ -105,7 +105,7 @@ class ContentsFilter(nodes.TreeCopyVisitor):
def visit_image(self, node):
if node.hasattr('alt'):
- self.parent_stack[-1].append(nodes.Text(node['alt']))
+ self.parent.append(nodes.Text(node['alt']))
raise nodes.SkipNode
def ignore_node_but_process_children(self, node):
diff --git a/docutils/transforms/references.py b/docutils/transforms/references.py
index 107bdfdee..15ca5db89 100644
--- a/docutils/transforms/references.py
+++ b/docutils/transforms/references.py
@@ -66,9 +66,9 @@ class Hyperlinks(Transform):
if len(self.document.anonymous_refs) \
!= len(self.document.anonymous_targets):
msg = self.document.reporter.error(
- 'Anonymous hyperlink mismatch: %s references but %s targets.'
- % (len(self.document.anonymous_refs),
- len(self.document.anonymous_targets)))
+ 'Anonymous hyperlink mismatch: %s references but %s '
+ 'targets.' % (len(self.document.anonymous_refs),
+ len(self.document.anonymous_targets)))
self.document.messages += msg
msgid = self.document.set_id(msg)
for ref in self.document.anonymous_refs:
@@ -101,9 +101,9 @@ class Hyperlinks(Transform):
- The "refuri" attribute is migrated back to all indirect targets from
- the final direct target (i.e. a target not referring to another
- indirect target)::
+ The "refuri" attribute is migrated back to all indirect targets
+ from the final direct target (i.e. a target not referring to
+ another indirect target)::
@@ -585,7 +585,8 @@ class Footnotes(Transform):
def resolve_footnotes_and_citations(self):
"""
- Link manually-labeled footnotes and citations to/from their references.
+ Link manually-labeled footnotes and citations to/from their
+ references.
"""
for footnote in self.document.footnotes:
label = footnote['name']
@@ -643,10 +644,11 @@ class Substitutions(Transform):
for refname, refs in self.document.substitution_refs.items():
for ref in refs:
if defs.has_key(refname):
- ref.parent.replace(ref, defs[refname].getchildren())
+ ref.parent.replace(ref, defs[refname].get_children())
else:
msg = self.document.reporter.error(
- 'Undefined substitution referenced: "%s".' % refname)
+ 'Undefined substitution referenced: "%s".'
+ % refname)
msgid = self.document.set_id(msg)
self.document.messages += msg
prb = nodes.problematic(
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index 145a89b01..36c83f003 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -32,7 +32,7 @@ class Messages(Transform):
"""
def transform(self):
- unfiltered = self.document.messages.getchildren()
+ unfiltered = self.document.messages.get_children()
threshold = self.document.reporter['writer'].warning_level
messages = []
for msg in unfiltered:
@@ -54,7 +54,7 @@ class TestMessages(Transform):
"""
def transform(self):
- self.document += self.document.messages.getchildren()
+ self.document += self.document.messages.get_children()
class FinalChecks(Transform):
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
index 0f560e7ee..349ea3b24 100644
--- a/docutils/writers/__init__.py
+++ b/docutils/writers/__init__.py
@@ -49,7 +49,7 @@ class Writer(Component):
def write(self, document, destination):
self.document = document
- self.language = languages.getlanguage(document.language_code)
+ self.language = languages.get_language(document.language_code)
self.destination = destination
self.transform()
self.translate()
@@ -83,7 +83,7 @@ class Writer(Component):
(b) a path to a file, which is opened and then written; or
(c) `None`, which implies `sys.stdout`.
"""
- output = output.encode('raw-unicode-escape') # @@@ temporary
+ output = output.encode('utf-8') # @@@ temporary; must not hard-code
if hasattr(self.destination, 'write'):
destination.write(output)
elif self.destination:
--
cgit v1.2.1
From bd058e6fbfa94584b9026f705cd5cbe73dfa9827 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 7 May 2002 04:40:43 +0000
Subject: fixed
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@111 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index eb62d6206..c1e3246b5 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -17,7 +17,7 @@ contains a minimum of formatting information. A cascading style sheet
__docformat__ = 'reStructuredText'
-import time, string, re
+import sys, time, string, re
from types import ListType
from docutils import writers, nodes, languages
@@ -48,9 +48,9 @@ class HTMLTranslator(nodes.NodeVisitor):
'xhtml1-transitional.dtd">\n'
html_head = '\n\n'
content_type = '\n',
+ 'charset=UTF-8">\n'
stylesheet_link = '\n']
+ ' type="text/css" />\n'
def __init__(self, document):
nodes.NodeVisitor.__init__(self, document)
--
cgit v1.2.1
From aad2f637864a51bff65375083359cdf72652004c Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 9 May 2002 04:14:55 +0000
Subject: - Added "pdf" alias in anticipation of Engelbert Gruber's PDF
writer.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@114 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/__init__.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
index 349ea3b24..49eba12da 100644
--- a/docutils/writers/__init__.py
+++ b/docutils/writers/__init__.py
@@ -95,7 +95,8 @@ class Writer(Component):
_writer_aliases = {
'html': 'html4css1',
'pprint': 'pseudoxml',
- 'pformat': 'pseudoxml',}
+ 'pformat': 'pseudoxml',
+ 'pdf': 'rlpdf',}
def get_writer_class(writer_name):
"""Return the Writer class from the `writer_name` module."""
--
cgit v1.2.1
From 3510bd954117ba2d0179a2419887fd61cb3a2c7c Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 18 May 2002 02:53:47 +0000
Subject: - Added a "generator" meta tag to .
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@130 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index c1e3246b5..71a416ed4 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -47,8 +47,10 @@ class HTMLTranslator(nodes.NodeVisitor):
' SYSTEM "http://www.w3.org/TR/xhtml1/DTD/' \
'xhtml1-transitional.dtd">\n'
html_head = '\n\n'
- content_type = '\n'
+ generator = '\n'
stylesheet_link = '\n'
@@ -60,6 +62,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.doctype,
self.html_head % document.language_code,
self.content_type, # @@@ % output encoding
+ self.generator,
self.stylesheet_link] # @@@ % stylesheet
self.head = []
self.body_prefix = ['\n\n']
--
cgit v1.2.1
From 9e311d21148b1320c59bc46990f073939bec7826 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 18 May 2002 02:55:04 +0000
Subject: - Filled in some descriptions. - Added "shttp" scheme.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@131 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/urischemes.py | 57 ++++++++++++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 23 deletions(-)
(limited to 'docutils')
diff --git a/docutils/urischemes.py b/docutils/urischemes.py
index 367217ad4..6eb45820a 100644
--- a/docutils/urischemes.py
+++ b/docutils/urischemes.py
@@ -1,13 +1,14 @@
"""
`schemes` is a dictionary with lowercase URI addressing schemes as
keys and descriptions as values. It was compiled from the index at
-http://www.w3.org/Addressing/schemes.html, revised 2001-08-20. Many
-values are blank and should be filled in with useful descriptions.
+http://www.w3.org/Addressing/schemes.html (revised 2001-08-20).
"""
+# Many values are blank and should be filled in with useful descriptions.
+
schemes = {
'about': 'provides information on Navigator',
- 'acap': 'application configuration access protocol',
+ 'acap': 'Application Configuration Access Protocol',
'addbook': "To add vCard entries to Communicator's Address Book",
'afp': 'Apple Filing Protocol',
'afs': 'Andrew File System global file names',
@@ -16,33 +17,38 @@ schemes = {
'castanet': 'Castanet Tuner URLs for Netcaster',
'chttp': 'cached HTTP supported by RealPlayer',
'cid': 'content identifier',
- 'data': 'allows inclusion of small data items as "immediate" data; RFC-2397',
+ 'data': ('allows inclusion of small data items as "immediate" data; '
+ 'RFC 2397'),
'dav': 'Distributed Authoring and Versioning Protocol; RFC 2518',
'dns': 'Domain Name System resources',
'eid': ('External ID; non-URL data; general escape mechanism to allow '
'access to information for applications that are too '
'specialized to justify their own schemes'),
- 'fax': '',
+ 'fax': ('a connection to a terminal that can handle telefaxes '
+ '(facsimiles); RFC 2806'),
'file': 'Host-specific file names',
'finger': '',
'freenet': '',
'ftp': 'File Transfer Protocol',
'gopher': 'The Gopher Protocol',
- 'gsm-sms': '',
- 'h323': '',
- 'h324': '',
- 'hdl': '',
- 'hnews': '',
+ 'gsm-sms': ('Global System for Mobile Communications Short Message '
+ 'Service'),
+ 'h323': 'video (audiovisual) communication on local area networks',
+ 'h324': ('video and audio communications over low bitrate connections '
+ 'such as POTS modem connections'),
+ 'hdl': 'CNRI handle system',
+ 'hnews': 'an HTTP-tunneling variant of the NNTP news protocol',
'http': 'Hypertext Transfer Protocol',
- 'https': '',
- 'iioploc': '',
- 'ilu': '',
- 'imap': 'internet message access protocol',
- 'ior': '',
- 'ipp': '',
+ 'https': 'HTTP over SSL',
+ 'iioploc': 'Internet Inter-ORB Protocol Location?',
+ 'ilu': 'Inter-Language Unification',
+ 'imap': 'Internet Message Access Protocol',
+ 'ior': 'CORBA interoperable object reference',
+ 'ipp': 'Internet Printing Protocol',
'irc': 'Internet Relay Chat',
- 'jar': '',
- 'javascript': 'JavaScript code; evaluates the expression after the colon',
+ 'jar': 'Java archive',
+ 'javascript': ('JavaScript code; evaluates the expression after the '
+ 'colon'),
'jdbc': '',
'ldap': 'Lightweight Directory Access Protocol',
'lifn': '',
@@ -54,9 +60,10 @@ schemes = {
'md5': '',
'mid': 'message identifier',
'mocha': '',
- 'modem': '',
+ 'modem': ('a connection to a terminal that can handle incoming data '
+ 'calls; RFC 2806'),
'news': 'USENET news',
- 'nfs': 'network file system protocol',
+ 'nfs': 'Network File System protocol',
'nntp': 'USENET news using NNTP access',
'opaquelocktoken': '',
'phone': '',
@@ -71,12 +78,16 @@ schemes = {
'rx': 'Remote Execution',
'sdp': '',
'service': 'service location',
- 'sip': 'session initiation protocol',
+ 'shttp': 'secure hypertext transfer protocol',
+ 'sip': 'Session Initiation Protocol',
'smb': '',
'snews': 'For NNTP postings via SSL',
- 't120': '',
+ 't120': 'real time data conferencing (audiographics)',
'tcp': '',
- 'tel': 'telephone',
+ 'tel': ('a connection to a terminal that handles normal voice '
+ 'telephone calls, a voice mailbox or another voice messaging '
+ 'system or a service that can be operated using DTMF tones; '
+ 'RFC 2806.'),
'telephone': 'telephone',
'telnet': 'Reference to interactive sessions',
'tip': 'Transaction Internet Protocol',
--
cgit v1.2.1
From da1419a26009c34ea88c885bca2ef99f455c0708 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 18 May 2002 02:57:27 +0000
Subject: docstring fix
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@132 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 7 +++----
docutils/statemachine.py | 4 ++--
2 files changed, 5 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index a578fef5f..ffb86303c 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -10,7 +10,7 @@
Calling the `publish` convenience function (or instantiating a
`Publisher` object) with component names will result in default
behavior. For custom behavior (setting component options), create
-custom component objects first, and pass *them* to
+custom component objects first, and pass *them* to
`publish`/`Publisher`.
"""
@@ -33,8 +33,8 @@ class Publisher:
warning_stream=None, debug=0):
"""
Initial setup. If any of `reader`, `parser`, or `writer` are
- not specified, the corresponding 'set*' method should be
- called.
+ not specified, the corresponding ``set_...`` method should be
+ called with a component name.
"""
self.reader = reader
self.parser = parser
@@ -85,4 +85,3 @@ def publish(source=None, destination=None,
if writer is None:
pub.set_writer(writer_name)
pub.publish(source, destination)
-
diff --git a/docutils/statemachine.py b/docutils/statemachine.py
index 8c4cddb81..2a772c206 100644
--- a/docutils/statemachine.py
+++ b/docutils/statemachine.py
@@ -94,11 +94,11 @@ How To Use This Module
input_string = open('inputfile').read()
input_lines = statemachine.string2lines(input_string)
-6. Run the state machine on the input text and collect the results, a list::
+5. Run the state machine on the input text and collect the results, a list::
results = sm.run(input_lines)
-7. Remove any lingering circular references::
+6. Remove any lingering circular references::
sm.unlink()
"""
--
cgit v1.2.1
From 05e4910c4b36bdcc1534594160644f2bb2fec9c4 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 22 May 2002 04:19:32 +0000
Subject: docstrings
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@136 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 9 ++++++++-
docutils/transforms/components.py | 14 ++++++++------
2 files changed, 16 insertions(+), 7 deletions(-)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index e70a33167..db9d384cb 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -61,8 +61,15 @@ class Component:
Base class for Docutils components.
"""
- names = ()
+ supported = ()
"""Names for this component. Override in subclasses."""
def supports(self, format):
+ """
+ Is `format` supported by this component?
+
+ To be used by transforms to ask the component (Reader or Writer)
+ controlling the transform if that component supports a certain input
+ context or output format.
+ """
return format in self.supported
diff --git a/docutils/transforms/components.py b/docutils/transforms/components.py
index b0d1ae48f..71473bea9 100644
--- a/docutils/transforms/components.py
+++ b/docutils/transforms/components.py
@@ -27,18 +27,20 @@ class Filter(Transform):
attribute is 'last writer'). The value is the name of a specific format
or context of that component (e.g. ``details['writer'] = 'html'``). If
the Docutils component which called this transform supports that format or
- context, the "pending" element is replaced by the nodes in
- ``details['nodes']``; otherwise, the "pending" element is removed.
+ context, the "pending" element is replaced by the contents of
+ ``details['nodes']`` (a list of nodes); otherwise, the "pending" element
+ is removed.
For example, the reStructuredText "meta" directive creates a "pending"
- element containing a "meta" element. Only writers supporting the "html"
- format will include the "meta" element; it will be deleted from the output
- of all other writers.
+ element containing a "meta" element (in ``pending.details['nodes']``).
+ Only writers supporting the "html" format will include the "meta" element;
+ it will be deleted from the output of all other writers.
"""
def transform(self):
pending = self.startnode
- component_name = pending.details[pending.stage.split()[-1]]
+ component_type = pending.stage.split()[-1] # 'reader' or 'writer'
+ component_name = pending.details[component_type]
if self.component.supports(component_name):
pending.parent.replace(pending, pending.details['nodes'])
else:
--
cgit v1.2.1
From 8e5307cf701ccd24de772d2dd3cb1ae11b726318 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 22 May 2002 04:21:21 +0000
Subject: - Improved docstrings. - Added SparseNodeVisitor, refined
NodeVisitor.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@137 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 52 ++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 40 insertions(+), 12 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 275469f6e..ee05a638c 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -128,6 +128,12 @@ class Node:
class Text(Node, MutableString):
+ """
+ Instances are terminal nodes (leaves) containing text only; no child
+ nodes or attributes. Initialize by passing a string to the constructor.
+ Access the text itself with the `astext` method.
+ """
+
tagname = '#text'
def __repr__(self):
@@ -171,26 +177,30 @@ class Element(Node):
"""
`Element` is the superclass to all specific elements.
- Elements contain attributes and child nodes. Elements emulate dictionaries
- for attributes, indexing by attribute name (a string). To set the
- attribute 'att' to 'value', do::
+ Elements contain attributes and child nodes. Elements emulate
+ dictionaries for attributes, indexing by attribute name (a string). To
+ set the attribute 'att' to 'value', do::
element['att'] = 'value'
Elements also emulate lists for child nodes (element nodes and/or text
- nodes), indexing by integer. To get the first child node, use::
+ nodes), indexing by integer. To get the first child node, use::
element[0]
- Elements may be constructed using the ``+=`` operator. To add one new
+ Elements may be constructed using the ``+=`` operator. To add one new
child node to element, do::
element += node
+ This is equivalent to ``element.append(node)``.
+
To add a list of multiple child nodes at once, use the same ``+=``
operator::
element += [node1, node2]
+
+ This is equivalent to ``element.extend([node1, node2])``.
"""
tagname = None
@@ -523,9 +533,6 @@ class Part: pass
class Inline: pass
class Referential(Resolvable): pass
- #refnode = None
- #"""Resolved reference to a node."""
-
class Targetable(Resolvable):
@@ -662,7 +669,8 @@ class document(Root, Structural, Element):
if self.explicit_targets.has_key(name) \
or self.implicit_targets.has_key(name):
msg = self.reporter.info(
- 'Duplicate implicit target name: "%s".' % name, backrefs=[id])
+ 'Duplicate implicit target name: "%s".' % name,
+ backrefs=[id])
msgnode += msg
self.clear_target_names(name, self.implicit_targets)
del target['name']
@@ -695,7 +703,8 @@ class document(Root, Structural, Element):
target['dupname'] = name
elif self.implicit_targets.has_key(name):
msg = self.reporter.info(
- 'Duplicate implicit target name: "%s".' % name, backrefs=[id])
+ 'Duplicate implicit target name: "%s".' % name,
+ backrefs=[id])
msgnode += msg
self.clear_target_names(name, self.implicit_targets)
self.explicit_targets[name] = target
@@ -1072,11 +1081,20 @@ class NodeVisitor:
tree traversals.
Each node class has corresponding methods, doing nothing by default;
- override individual methods for specific and useful behaviour. The
+ override individual methods for specific and useful behaviour. The
"``visit_`` + node class name" method is called by `Node.walk()` upon
- entering a node. `Node.walkabout()` also calls the "``depart_`` + node
+ entering a node. `Node.walkabout()` also calls the "``depart_`` + node
class name" method before exiting a node.
+ This is a base class for visitors whose ``visit_...`` & ``depart_...``
+ methods should be implemented for *all* node types encountered (such as
+ for `docutils.writers.Writer` subclasses). Unimplemented methods will
+ raise exceptions.
+
+ For sparse traversals, where only certain node types are of interest,
+ subclass `SparseNodeVisitor` instead. When (mostly or entirely) uniform
+ processing is desired, subclass `GenericNodeVisitor`.
+
.. [GoF95] Gamma, Helm, Johnson, Vlissides. *Design Patterns: Elements of
Reusable Object-Oriented Software*. Addison-Wesley, Reading, MA, USA,
1995.
@@ -1103,6 +1121,16 @@ class NodeVisitor:
raise NotImplementedError('departing unknown node type: %s'
% node.__class__.__name__)
+
+class SparseNodeVisitor(NodeVisitor):
+
+ """
+ Base class for sparse traversals, where only certain node types are of
+ interest. When ``visit_...`` & ``depart_...`` methods should be
+ implemented for *all* node types (such as for `docutils.writers.Writer`
+ subclasses), subclass `NodeVisitor` instead.
+ """
+
# Save typing with dynamic definitions.
for name in node_class_names:
exec """def visit_%s(self, node): pass\n""" % name
--
cgit v1.2.1
From b4c6826884a1c00c4fb928dc3584cf241fdaff40 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 22 May 2002 04:23:41 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@138 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/references.py | 2 +-
docutils/transforms/universal.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/references.py b/docutils/transforms/references.py
index 15ca5db89..ccd43c749 100644
--- a/docutils/transforms/references.py
+++ b/docutils/transforms/references.py
@@ -330,7 +330,7 @@ class Hyperlinks(Transform):
target.referenced = 1
-class ChainedTargetResolver(nodes.NodeVisitor):
+class ChainedTargetResolver(nodes.SparseNodeVisitor):
"""
Copy reference attributes up the length of a hyperlink target chain.
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index 36c83f003..fb422270b 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -70,7 +70,7 @@ class FinalChecks(Transform):
self.document.walk(visitor)
-class FinalCheckVisitor(nodes.NodeVisitor):
+class FinalCheckVisitor(nodes.SparseNodeVisitor):
def unknown_visit(self, node):
pass
--
cgit v1.2.1
From b9a42c808f2d269e277d5c937e78ca1401563aff Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 23 May 2002 04:19:54 +0000
Subject: expanded docstrings; workings of a Writer
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@140 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/__init__.py | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
index 49eba12da..35e5254c6 100644
--- a/docutils/writers/__init__.py
+++ b/docutils/writers/__init__.py
@@ -14,6 +14,7 @@ __docformat__ = 'reStructuredText'
import sys
+import docutils
from docutils import languages, Component
from docutils.transforms import universal
@@ -24,6 +25,8 @@ class Writer(Component):
Abstract base class for docutils Writers.
Each writer module or package must export a subclass also called 'Writer'.
+ Each writer must support all standard node types listed in
+ `docutils.nodes.node_class_names`.
Call `write()` to process a document.
"""
@@ -63,7 +66,16 @@ class Writer(Component):
xclass(self.document, self).transform()
def translate(self):
- """Override to do final document tree translation."""
+ """
+ Override to do final document tree translation.
+
+ This is usually done with a `docutils.nodes.NodeVisitor` subclass, in
+ combination with a call to `docutils.nodes.Node.walk()` or
+ `docutils.nodes.Node.walkabout()`. The ``NodeVisitor`` subclass must
+ support all standard elements (listed in
+ `docutils.nodes.node_class_names`) and possibly non-standard elements
+ used by the current Reader as well.
+ """
raise NotImplementedError('subclass must override this method')
def record(self):
--
cgit v1.2.1
From 060ae1cc18c6362cbfc28c6ee525ff32616ad1fb Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 24 May 2002 03:08:09 +0000
Subject: - Changed names of Reporter's thresholds: warning_level ->
report_level; error_level -> halt_level.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@143 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 8 ++---
docutils/transforms/universal.py | 2 +-
docutils/utils.py | 71 ++++++++++++++++++++--------------------
docutils/writers/html4css1.py | 3 +-
4 files changed, 43 insertions(+), 41 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index ffb86303c..3cab9a5c1 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -29,7 +29,7 @@ class Publisher:
"""A `utils.Reporter` instance used for all document processing."""
def __init__(self, reader=None, parser=None, writer=None, reporter=None,
- language_code='en', warning_level=2, error_level=4,
+ language_code='en', report_level=2, halt_level=4,
warning_stream=None, debug=0):
"""
Initial setup. If any of `reader`, `parser`, or `writer` are
@@ -40,7 +40,7 @@ class Publisher:
self.parser = parser
self.writer = writer
if not reporter:
- reporter = utils.Reporter(warning_level, error_level,
+ reporter = utils.Reporter(report_level, halt_level,
warning_stream, debug)
self.reporter = reporter
self.language_code = language_code
@@ -76,10 +76,10 @@ def publish(source=None, destination=None,
parser=None, parser_name='restructuredtext',
writer=None, writer_name='pseudoxml',
reporter=None, language_code='en',
- warning_level=2, error_level=4, warning_stream=None, debug=0):
+ report_level=2, halt_level=4, warning_stream=None, debug=0):
"""A convenience function; set up & run a `Publisher`."""
pub = Publisher(reader, parser, writer, reporter, language_code,
- warning_level, error_level, warning_stream, debug)
+ report_level, halt_level, warning_stream, debug)
if reader is None:
pub.set_reader(reader_name, parser, parser_name)
if writer is None:
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index fb422270b..c17341bb9 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -33,7 +33,7 @@ class Messages(Transform):
def transform(self):
unfiltered = self.document.messages.get_children()
- threshold = self.document.reporter['writer'].warning_level
+ threshold = self.document.reporter['writer'].report_level
messages = []
for msg in unfiltered:
if msg['level'] >= threshold:
diff --git a/docutils/utils.py b/docutils/utils.py
index 0602b8d64..9f9130b5e 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -29,27 +29,28 @@ class Reporter:
Five levels of system messages are defined, along with corresponding
methods: `debug()`, `info()`, `warning()`, `error()`, and `severe()`.
- There is typically one Reporter object per process. A Reporter object is
- instantiated with thresholds for generating warnings and errors (raising
- exceptions), a switch to turn debug output on or off, and an I/O stream
- for warnings. These are stored in the default reporting category, ''
- (zero-length string).
-
- Multiple reporting categories [#]_ may be set, each with its own warning
- and error thresholds, debugging switch, and warning stream (collectively a
- `ConditionSet`). Categories are hierarchically-named strings that look
- like attribute references: 'spam', 'spam.eggs', 'neeeow.wum.ping'. The
- 'spam' category is the ancestor of 'spam.bacon.eggs'. Unset categories
- inherit stored conditions from their closest ancestor category that has
- been set.
+ There is typically one Reporter object per process. A Reporter object is
+ instantiated with thresholds for reporting (generating warnings) and
+ halting processing (raising exceptions), a switch to turn debug output on
+ or off, and an I/O stream for warnings. These are stored in the default
+ reporting category, '' (zero-length string).
+
+ Multiple reporting categories [#]_ may be set, each with its own reporting
+ and halting thresholds, debugging switch, and warning stream
+ (collectively a `ConditionSet`). Categories are hierarchical dotted-name
+ strings that look like attribute references: 'spam', 'spam.eggs',
+ 'neeeow.wum.ping'. The 'spam' category is the ancestor of
+ 'spam.bacon.eggs'. Unset categories inherit stored conditions from their
+ closest ancestor category that has been set.
When a system message is generated, the stored conditions from its
- category (or ancestor if unset) are retrieved. The system message level is
- compared to the thresholds stored in the category, and a warning or error
- is generated as appropriate. Debug messages are produced iff the stored
- debug switch is on. Message output is sent to the stored warning stream.
+ category (or ancestor if unset) are retrieved. The system message level
+ is compared to the thresholds stored in the category, and a warning or
+ error is generated as appropriate. Debug messages are produced iff the
+ stored debug switch is on. Message output is sent to the stored warning
+ stream.
- The default category is '' (empty string). By convention, Writers should
+ The default category is '' (empty string). By convention, Writers should
retrieve reporting conditions from the 'writer' category (which, unless
explicitly set, defaults to the conditions of the default category).
@@ -60,16 +61,16 @@ class Reporter:
levels = 'DEBUG INFO WARNING ERROR SEVERE'.split()
"""List of names for system message levels, indexed by level."""
- def __init__(self, warning_level, error_level, stream=None, debug=0):
+ def __init__(self, report_level, halt_level, stream=None, debug=0):
"""
Initialize the `ConditionSet` forthe `Reporter`'s default category.
:Parameters:
- - `warning_level`: The level at or above which warning output will
+ - `report_level`: The level at or above which warning output will
be sent to `stream`.
- - `error_level`: The level at or above which `SystemMessage`
- exceptions will be raised.
+ - `halt_level`: The level at or above which `SystemMessage`
+ exceptions will be raised, halting execution.
- `debug`: Show debug (level=0) system messages?
- `stream`: Where warning output is sent (`None` implies
`sys.stderr`).
@@ -78,16 +79,16 @@ class Reporter:
if stream is None:
stream = sys.stderr
- self.categories = {'': ConditionSet(debug, warning_level, error_level,
+ self.categories = {'': ConditionSet(debug, report_level, halt_level,
stream)}
"""Mapping of category names to conditions. Default category is ''."""
- def set_conditions(self, category, warning_level, error_level,
+ def set_conditions(self, category, report_level, halt_level,
stream=None, debug=0):
if stream is None:
stream = sys.stderr
- self.categories[category] = ConditionSet(debug, warning_level,
- error_level, stream)
+ self.categories[category] = ConditionSet(debug, report_level,
+ halt_level, stream)
def unset_conditions(self, category):
if category and self.categories.has_key(category):
@@ -112,13 +113,13 @@ class Reporter:
msg = nodes.system_message(comment, level=level,
type=self.levels[level],
*children, **attributes)
- debug, warning_level, error_level, stream = self[category].astuple()
- if level >= warning_level or debug and level == 0:
+ debug, report_level, halt_level, stream = self[category].astuple()
+ if level >= report_level or debug and level == 0:
if category:
print >>stream, 'Reporter "%s":' % category, msg.astext()
else:
print >>stream, 'Reporter:', msg.astext()
- if level >= error_level:
+ if level >= halt_level:
raise SystemMessage(msg)
return msg
@@ -172,14 +173,14 @@ class ConditionSet:
category.
"""
- def __init__(self, debug, warning_level, error_level, stream):
+ def __init__(self, debug, report_level, halt_level, stream):
self.debug = debug
- self.warning_level = warning_level
- self.error_level = error_level
+ self.report_level = report_level
+ self.halt_level = halt_level
self.stream = stream
def astuple(self):
- return (self.debug, self.warning_level, self.error_level,
+ return (self.debug, self.report_level, self.halt_level,
self.stream)
@@ -367,9 +368,9 @@ def id(string):
non_id_chars = re.compile('[^a-z0-9]+')
non_id_at_ends = re.compile('^[-0-9]+|-+$')
-def new_document(language_code='en', warning_level=2, error_level=4,
+def new_document(language_code='en', report_level=2, halt_level=4,
stream=None, debug=0):
- reporter = Reporter(warning_level, error_level, stream, debug)
+ reporter = Reporter(report_level, halt_level, stream, debug)
document = nodes.document(language_code=language_code, reporter=reporter)
return document
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 71a416ed4..2a32a88a1 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -78,6 +78,7 @@ class HTMLTranslator(nodes.NodeVisitor):
def encode(self, text):
"""Encode special characters in `text` & return."""
+ # @@@ A codec to do these and all other HTML entities would be nice.
text = text.replace("&", "&")
text = text.replace("<", "<")
text = text.replace('"', """)
@@ -663,7 +664,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('\n')
def visit_system_message(self, node):
- if node['level'] < self.document.reporter['writer'].warning_level:
+ if node['level'] < self.document.reporter['writer'].report_level:
raise nodes.SkipNode
self.body.append(self.starttag(node, 'div', CLASS='system-message'))
self.body.append('
')
--
cgit v1.2.1
From 6f467ee322d74ec5c68592a4c9b97a96488d79b8 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:09:19 +0000
Subject: - Added support for an option values object which carries default
settings and overrides (from command-line options and library use).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@148 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 8 +++++++-
docutils/readers/__init__.py | 19 ++++++-------------
2 files changed, 13 insertions(+), 14 deletions(-)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index db9d384cb..fe63168b7 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -19,7 +19,9 @@ Modules:
- core.py: Contains the ``Publisher`` class and ``publish()`` convenience
function.
-- nodes.py: DPS document tree (doctree) node class library.
+- frontend.py: Command-line and common processing for Docutils front-ends.
+
+- nodes.py: Docutils document tree (doctree) node class library.
- roman.py: Conversion to and from Roman numerals. Courtesy of Mark
Pilgrim (http://diveintopython.org/).
@@ -64,6 +66,10 @@ class Component:
supported = ()
"""Names for this component. Override in subclasses."""
+ cmdline_options = ()
+ """Command-line option specification. A list/tuple of tuples:
+ ``('help text', [list of option strings], {keyword arguments})``."""
+
def supports(self, format):
"""
Is `format` supported by this component?
diff --git a/docutils/readers/__init__.py b/docutils/readers/__init__.py
index 0ade6dbe3..47c5b2fab 100644
--- a/docutils/readers/__init__.py
+++ b/docutils/readers/__init__.py
@@ -14,7 +14,7 @@ __docformat__ = 'reStructuredText'
import sys
-from docutils import nodes, utils, parsers, Component
+from docutils import utils, parsers, Component
from docutils.transforms import universal
@@ -33,7 +33,7 @@ class Reader(Component):
"""Ordered tuple of transform classes (each with a ``transform()`` method).
Populated by subclasses. `Reader.transform()` instantiates & runs them."""
- def __init__(self, reporter, parser, parser_name, language_code):
+ def __init__(self, parser, parser_name):
"""
Initialize the Reader instance.
@@ -41,12 +41,6 @@ class Reader(Component):
Subclasses may use these attributes as they wish.
"""
- self.language_code = language_code
- """Default language for new documents."""
-
- self.reporter = reporter
- """A `utils.Reporter` instance shared by all doctrees."""
-
self.parser = parser
"""A `parsers.Parser` instance shared by all doctrees. May be left
unspecified if the document source determines the parser."""
@@ -66,10 +60,11 @@ class Reader(Component):
parser_class = parsers.get_parser_class(parser_name)
self.parser = parser_class()
- def read(self, source, parser):
+ def read(self, source, parser, options):
self.source = source
if not self.parser:
self.parser = parser
+ self.options = options
self.scan() # may modify self.parser, depending on input
self.parse()
self.transform()
@@ -107,11 +102,9 @@ class Reader(Component):
+ universal.last_reader_transforms):
xclass(self.document, self).transform()
- def new_document(self, language_code=None):
+ def new_document(self):
"""Create and return a new empty document tree (root node)."""
- document = nodes.document(
- language_code=(language_code or self.language_code),
- reporter=self.reporter)
+ document = utils.new_document(self.options)
document['source'] = self.source
return document
--
cgit v1.2.1
From 94bef8e11867100fe10a5daf83bde3db0019edd9 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:10:56 +0000
Subject: - Removed many keyword parameters to ``Publisher.__init__()`` and
``publish()``; bundled into an option values object. Added ``argv`` and
``usage`` parameters for command-line support. - Added
``Publisher.process_command_line()`` and ``.set_options()`` methods. -
Added support for an option values object which carries default settings
and overrides (from command-line options and library use). - Cleaned up
imports: no more relative package imports or comma-separated lists of
top-level modules.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@149 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 109 ++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 72 insertions(+), 37 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index 3cab9a5c1..7c28d800a 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -16,7 +16,10 @@ custom component objects first, and pass *them* to
__docformat__ = 'reStructuredText'
-import readers, parsers, writers, utils
+import sys
+from docutils import Component
+from docutils import readers, parsers, writers
+from docutils.frontend import OptionParser
class Publisher:
@@ -25,63 +28,95 @@ class Publisher:
A facade encapsulating the high-level logic of a Docutils system.
"""
- reporter = None
- """A `utils.Reporter` instance used for all document processing."""
-
- def __init__(self, reader=None, parser=None, writer=None, reporter=None,
- language_code='en', report_level=2, halt_level=4,
- warning_stream=None, debug=0):
+ def __init__(self, reader=None, parser=None, writer=None):
"""
- Initial setup. If any of `reader`, `parser`, or `writer` are
- not specified, the corresponding ``set_...`` method should be
- called with a component name.
+ Initial setup. If any of `reader`, `parser`, or `writer` are not
+ specified, the corresponding ``set_...`` method should be called with
+ a component name (`set_reader` sets the parser as well).
"""
+
self.reader = reader
+ """A `readers.Reader` instance."""
+
self.parser = parser
+ """A `parsers.Parser` instance."""
+
self.writer = writer
- if not reporter:
- reporter = utils.Reporter(report_level, halt_level,
- warning_stream, debug)
- self.reporter = reporter
- self.language_code = language_code
-
- def set_reader(self, reader_name, parser, parser_name,
- language_code=None):
+ """A `writers.Writer` instance."""
+
+ self.options = None
+ """An object containing Docutils settings as instance attributes.
+ Set by `self.process_command_line()` or `self.set_options()`."""
+
+ self.source = None
+ """The source of input data."""
+
+ self.destination = None
+ """The destination for docutils output."""
+
+ def set_reader(self, reader_name, parser, parser_name):
"""Set `self.reader` by name."""
reader_class = readers.get_reader_class(reader_name)
- self.reader = reader_class(self.reporter, parser, parser_name,
- language_code or self.language_code)
-
- def set_parser(self, parser_name):
- """Set `self.parser` by name."""
- parser_class = parsers.get_parser_class(parser_name)
- self.parser = parser_class()
+ self.reader = reader_class(parser, parser_name)
def set_writer(self, writer_name):
"""Set `self.writer` by name."""
writer_class = writers.get_writer_class(writer_name)
self.writer = writer_class()
- def publish(self, source, destination):
+ def set_options(self, **defaults):
+ """
+ Set default option values (keyword arguments).
+
+ Set components first (`self.set_reader` & `self.set_writer`).
+ Overrides the command line.
+ """
+ option_parser = OptionParser(
+ components=(self.reader, self.parser, self.writer),
+ defaults=defaults)
+ self.options = option_parser.get_default_values()
+
+ def process_command_line(self, argv=None, usage=None):
+ """
+ Pass an empty list to `argv` to avoid reading `sys.argv` (the
+ default).
+
+ Set components first (`self.set_reader` & `self.set_writer`).
+ """
+ option_parser = OptionParser(
+ components=(self.reader, self.parser, self.writer), usage=usage)
+ if argv is None:
+ argv = sys.argv[1:]
+ self.options, self.source, self.destination \
+ = option_parser.parse_args(argv)
+ """
+ # For testing purposes:
+ from pprint import pformat
+ print 'options:'
+ print pformat(options.__dict__)
+ print 'source=%r, destination=%r' % (source, destination)
+ sys.exit(0)
+ """
+
+ def publish(self, argv=None, usage=None):
"""
- Run `source` through `self.reader`, then through `self.writer` to
- `destination`.
+ Process command line options and arguments, run `self.reader`
+ and then `self.writer`.
"""
- document = self.reader.read(source, self.parser)
- self.writer.write(document, destination)
+ if self.options is None:
+ self.process_command_line(argv, usage)
+ document = self.reader.read(self.source, self.parser, self.options)
+ self.writer.write(document, self.destination)
-def publish(source=None, destination=None,
- reader=None, reader_name='standalone',
+def publish(reader=None, reader_name='standalone',
parser=None, parser_name='restructuredtext',
writer=None, writer_name='pseudoxml',
- reporter=None, language_code='en',
- report_level=2, halt_level=4, warning_stream=None, debug=0):
+ argv=None, usage=None):
"""A convenience function; set up & run a `Publisher`."""
- pub = Publisher(reader, parser, writer, reporter, language_code,
- report_level, halt_level, warning_stream, debug)
+ pub = Publisher(reader, parser, writer)
if reader is None:
pub.set_reader(reader_name, parser, parser_name)
if writer is None:
pub.set_writer(writer_name)
- pub.publish(source, destination)
+ pub.publish(argv, usage)
--
cgit v1.2.1
From 3f909add8d4943b2334a2943d8c7817fed3692cc Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:12:05 +0000
Subject: Support for front-end scripts. Option specifications may be augmented
by components. Requires Optik (http://optik.sf.net/) for option processing.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@150 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 122 insertions(+)
create mode 100644 docutils/frontend.py
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
new file mode 100644
index 000000000..727db95d0
--- /dev/null
+++ b/docutils/frontend.py
@@ -0,0 +1,122 @@
+#! /usr/bin/env python
+
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Command-line and common processing for Docutils front-ends.
+"""
+
+__docformat__ = 'reStructuredText'
+
+import optik
+
+
+class OptionParser(optik.OptionParser):
+
+ """
+ Parser for command-line and library use. The `cmdline_options` specification here and in other Docutils components are merged
+ """
+
+ standard_option_list = []
+ """We supply our own help option."""
+
+ cmdline_options = (
+ # Unimplemented or unused options are commented out.
+ #('Include a "Generated by Docutils" credit with a link, at the end '
+ # 'of the document.',
+ # ['--generator', '-g'], {'action': 'store_true', 'default': 0}),
+ #('Include the date at the end of the document (UTC).',
+ # ['--date', '-d'], {'action': 'store_const', 'const': '%Y-%m-%d',
+ # 'dest': 'datestamp', 'default': ''}),
+ #('Include the time & date at the end of the document (UTC).',
+ # ['--time', '-t'], {'action': 'store_const',
+ # 'const': '%Y-%m-%d %H:%M:%S UTC',
+ # 'dest': 'datestamp', 'default': ''}),
+ #('Include a "(View document source)" link.',
+ # ['--source-link', '-s'], {'action': 'store_true', 'default': 0}),
+ ('Set verbosity threshold; report system messages at or higher than '
+ ' (by name or number: "info" or "1", warning/2, error/3, '
+ 'severe/4; also, "none" or 5+). Default is 2 (warning).',
+ ['--report', '-r'], {'dest': 'report_level', 'default': 2,
+ 'metavar': ''}),
+ ('Report all system messages, info-level and higher. (Same as '
+ '"--report=info".)',
+ ['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
+ 'dest': 'report_level'}),
+ ('Set the threshold () at or above which system messages are '
+ 'converted to exceptions, halting execution immediately. Levels as '
+ 'in --report. Default is 4 (severe).',
+ ['--halt'], {'dest': 'halt_level', 'default': 4,
+ 'metavar': ''}),
+ ('Same as "--halt=info": halt processing at the slightest problem.',
+ ['--strict'], {'action': 'store_const', 'const': 'info',
+ 'dest': 'halt_level'}),
+ ('Report debug-level system messages.',
+ ['--debug'], {'action': 'store_true', 'default': 0}),
+ ('Send the output of system messages (warnings) to .',
+ ['--warnings'], {'dest': 'warning_stream', 'metavar': ''}),
+ # @@@ Take default encoding & language from locale?
+ #('Specify the encoding of input text. Default is "utf-8".',
+ # ['--encoding', '-e'], {'default': 'utf-8', 'metavar': ''}),
+ ('Specify the language of input text (ISO 639 2-letter identifier. '
+ 'Default is "en" (English).',
+ ['--language', '-l'], {'dest': 'language_code', 'default': 'en',
+ 'metavar': ''}),
+ ('Show this help message and exit.',
+ ['--help', '-h'], {'action': 'help'}),)
+ """Command-line option specifications, common to all Docutils front-ends.
+ A list/tuple of tuples: ``('help text', [list of option strings], {keyword
+ arguments})``. Option specs from Docutils components are also used (see
+ `build_option_parser()`)."""
+
+ thresholds = {'info': 1, 'warning': 2, 'error': 3, 'severe': 4, 'none': 5}
+ """Lookup table for --report and --halt threshold values."""
+
+ def __init__(self, components=(), defaults={}, *args, **kwargs):
+ """
+ `components` is a list of Docutils components each containing a
+ ``.cmdline_options`` attribute. `defaults` is a
+ """
+ optik.OptionParser.__init__(self, *args, **kwargs)
+ self.populate_from_components((self,) + tuple(components))
+ self.set_defaults(**defaults)
+
+ def populate_from_components(self, components):
+ for component in components:
+ if component is not None:
+ for (help_text, option_strings, kwargs) \
+ in component.cmdline_options:
+ self.add_option(help=help_text, *option_strings,
+ **kwargs)
+
+ def check_values(self, values, args):
+ values.report_level = self.check_threshold(values.report_level)
+ values.halt_level = self.check_threshold(values.halt_level)
+ source, destination = self.check_args(args)
+ return values, source, destination
+
+ def check_threshold(self, level):
+ try:
+ return int(level)
+ except ValueError:
+ try:
+ return self.thresholds[level.lower()]
+ except (KeyError, AttributeError):
+ self.error('Unknown threshold: %r.' % level)
+
+ def check_args(self, args):
+ source = destination = None
+ if args:
+ source = args.pop(0)
+ if args:
+ destination = args.pop(0)
+ if args:
+ self.error('Maximum 2 arguments allowed.')
+ return source, destination
+
+ def get_default_values(self):
+ return optik.option_parser.Values(self.defaults)
--
cgit v1.2.1
From 71a20e7a69cab41243bfb71ae0bab6fe91cbd2d3 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:13:34 +0000
Subject: - Moved ``utils.id()`` to ``nodes.make_id()`` to avoid circular
imports. - Added support for an option values object which carries default
settings and overrides (from command-line options and library use). - Cleaned
up imports: no more relative package imports or comma-separated lists of
top-level modules.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@151 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 64 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 55 insertions(+), 9 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index ee05a638c..6784416b2 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -19,12 +19,14 @@ element generic identifiers in the DTD_.
.. _DTD: http://docutils.sourceforge.net/spec/docutils.dtd
"""
-import sys, os
+__docformat__ = 'reStructuredText'
+
+import sys
+import os
+import re
import xml.dom.minidom
from types import IntType, SliceType, StringType, TupleType, ListType
from UserString import MutableString
-import utils
-import docutils
# ==============================
@@ -545,15 +547,15 @@ class Targetable(Resolvable):
class document(Root, Structural, Element):
- def __init__(self, reporter, language_code, *args, **kwargs):
+ def __init__(self, options, reporter, *args, **kwargs):
Element.__init__(self, *args, **kwargs)
+ self.options = options
+ """Command-line or internal option data record."""
+
self.reporter = reporter
"""System message generator."""
- self.language_code = language_code
- """ISO 639 2-letter language identifier."""
-
self.explicit_targets = {}
"""Mapping of target names to explicit target nodes."""
@@ -649,7 +651,7 @@ class document(Root, Structural, Element):
msgnode += msg
else:
if node.has_key('name'):
- id = utils.id(node['name'])
+ id = make_id(node['name'])
else:
id = ''
while not id or self.ids.has_key(id):
@@ -798,7 +800,7 @@ class document(Root, Structural, Element):
self.pending.append(pending)
def copy(self):
- return self.__class__(self.reporter, self.language_code,
+ return self.__class__(self.options, self.reporter,
**self.attributes)
@@ -832,6 +834,7 @@ class copyright(Bibliographic, TextElement): pass
class section(Structural, Element): pass
+
class topic(Structural, Element):
"""
@@ -1250,3 +1253,46 @@ class SkipDeparture(TreePruningException):
"""
pass
+
+
+def make_id(string):
+ """
+ Convert `string` into an identifier and return it.
+
+ Docutils identifiers will conform to the regular expression
+ ``[a-z][-a-z0-9]*``. For CSS compatibility, identifiers (the "class" and
+ "id" attributes) should have no underscores, colons, or periods. Hyphens
+ may be used.
+
+ - The `HTML 4.01 spec`_ defines identifiers based on SGML tokens:
+
+ ID and NAME tokens must begin with a letter ([A-Za-z]) and may be
+ followed by any number of letters, digits ([0-9]), hyphens ("-"),
+ underscores ("_"), colons (":"), and periods (".").
+
+ - However the `CSS1 spec`_ defines identifiers based on the "name" token,
+ a tighter interpretation ("flex" tokenizer notation; "latin1" and
+ "escape" 8-bit characters have been replaced with entities)::
+
+ unicode \\[0-9a-f]{1,4}
+ latin1 [¡-ÿ]
+ escape {unicode}|\\[ -~¡-ÿ]
+ nmchar [-a-z0-9]|{latin1}|{escape}
+ name {nmchar}+
+
+ The CSS1 "nmchar" rule does not include underscores ("_"), colons (":"),
+ or periods ("."), therefore "class" and "id" attributes should not contain
+ these characters. They should be replaced with hyphens ("-"). Combined
+ with HTML's requirements (the first character must be a letter; no
+ "unicode", "latin1", or "escape" characters), this results in the
+ ``[a-z][-a-z0-9]*`` pattern.
+
+ .. _HTML 4.01 spec: http://www.w3.org/TR/html401
+ .. _CSS1 spec: http://www.w3.org/TR/REC-CSS1
+ """
+ id = _non_id_chars.sub('-', ' '.join(string.lower().split()))
+ id = _non_id_at_ends.sub('', id)
+ return str(id)
+
+_non_id_chars = re.compile('[^a-z0-9]+')
+_non_id_at_ends = re.compile('^[-0-9]+|-+$')
--
cgit v1.2.1
From 677a4213e1d8a8c3ccfa01bfbcb67a5264adb129 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:14:23 +0000
Subject: - Moved ``utils.id()`` to ``nodes.make_id()``. - Added support for an
option values object which carries default settings and overrides (from
command-line options and library use). - Cleaned up imports: no more relative
package imports or comma-separated lists of top-level modules.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@152 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/utils.py | 68 +++++++++++++------------------------------------------
1 file changed, 16 insertions(+), 52 deletions(-)
(limited to 'docutils')
diff --git a/docutils/utils.py b/docutils/utils.py
index 9f9130b5e..d276b671f 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -10,9 +10,12 @@
Miscellaneous utilities for the documentation utilities.
"""
-import sys, re
-import nodes
+__docformat__ = 'reStructuredText'
+
+import sys
+from types import StringTypes
from docutils import ApplicationError, DataError
+from docutils import frontend, nodes
class SystemMessage(ApplicationError):
@@ -72,12 +75,14 @@ class Reporter:
- `halt_level`: The level at or above which `SystemMessage`
exceptions will be raised, halting execution.
- `debug`: Show debug (level=0) system messages?
- - `stream`: Where warning output is sent (`None` implies
- `sys.stderr`).
+ - `stream`: Where warning output is sent. Can be file-like (has a
+ ``.write`` method), a string (file name, opened for writing), or
+ `None` (implies `sys.stderr`; default).
"""
-
if stream is None:
stream = sys.stderr
+ elif type(stream) in StringTypes:
+ raise NotImplementedError('This should open a file for writing.')
self.categories = {'': ConditionSet(debug, report_level, halt_level,
stream)}
@@ -321,57 +326,16 @@ def extract_name_value(line):
attlist.append((attname.lower(), data))
return attlist
-
def normalize_name(name):
"""Return a case- and whitespace-normalized name."""
return ' '.join(name.lower().split())
-def id(string):
- """
- Convert `string` into an identifier and return it.
-
- Docutils identifiers will conform to the regular expression
- ``[a-z][-a-z0-9]*``. For CSS compatibility, identifiers (the "class" and
- "id" attributes) should have no underscores, colons, or periods. Hyphens
- may be used.
-
- - The `HTML 4.01 spec`_ defines identifiers based on SGML tokens:
-
- ID and NAME tokens must begin with a letter ([A-Za-z]) and may be
- followed by any number of letters, digits ([0-9]), hyphens ("-"),
- underscores ("_"), colons (":"), and periods (".").
-
- - However the `CSS1 spec`_ defines identifiers based on the "name" token,
- a tighter interpretation ("flex" tokenizer notation; "latin1" and
- "escape" 8-bit characters have been replaced with entities)::
-
- unicode \\[0-9a-f]{1,4}
- latin1 [¡-ÿ]
- escape {unicode}|\\[ -~¡-ÿ]
- nmchar [-a-z0-9]|{latin1}|{escape}
- name {nmchar}+
-
- The CSS1 "nmchar" rule does not include underscores ("_"), colons (":"),
- or periods ("."), therefore "class" and "id" attributes should not contain
- these characters. They should be replaced with hyphens ("-"). Combined
- with HTML's requirements (the first character must be a letter; no
- "unicode", "latin1", or "escape" characters), this results in the
- ``[a-z][-a-z0-9]*`` pattern.
-
- .. _HTML 4.01 spec: http://www.w3.org/TR/html401
- .. _CSS1 spec: http://www.w3.org/TR/REC-CSS1
- """
- id = non_id_chars.sub('-', normalize_name(string))
- id = non_id_at_ends.sub('', id)
- return str(id)
-
-non_id_chars = re.compile('[^a-z0-9]+')
-non_id_at_ends = re.compile('^[-0-9]+|-+$')
-
-def new_document(language_code='en', report_level=2, halt_level=4,
- stream=None, debug=0):
- reporter = Reporter(report_level, halt_level, stream, debug)
- document = nodes.document(language_code=language_code, reporter=reporter)
+def new_document(options=None):
+ if options is None:
+ options = frontend.OptionParser().get_default_values()
+ reporter = Reporter(options.report_level, options.halt_level,
+ options.warning_stream, options.debug)
+ document = nodes.document(options=options, reporter=reporter)
return document
def clean_rcs_keywords(paragraph, keyword_substitutions):
--
cgit v1.2.1
From 9c4cc2885cf24d4bf4c5edb3d968ecb3dae2ef0d Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:15:20 +0000
Subject: - Added ``-/:`` characters to inline markup's start string prefix,
``/`` to end string suffix. - Added support for an option values object which
carries default settings and overrides (from command-line options and
library use). - Cleaned up imports: no more relative package imports or
comma-separated lists of top-level modules.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@153 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 434888417..3ee0e0534 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -12,6 +12,7 @@ the reStructuredText parser. It defines the following:
- `RSTStateMachine`: reStructuredText parser's entry point.
- `NestedStateMachine`: recursive StateMachine.
- `RSTState`: reStructuredText State superclass.
+ - `Inliner`: For parsing inline markup.
- `Body`: Generic classifier of the first line of a block.
- `SpecializedBody`: Superclass for compound element members.
- `BulletList`: Second and subsequent bullet_list list_items
@@ -102,13 +103,15 @@ Parsing proceeds as follows:
__docformat__ = 'reStructuredText'
-import sys, re, string
-from docutils import nodes, statemachine, utils, roman, urischemes, \
- ApplicationError, DataError
+import sys
+import re
+import string
+from docutils import nodes, statemachine, utils, roman, urischemes
+from docutils import ApplicationError, DataError
from docutils.statemachine import StateMachineWS, StateWS
from docutils.utils import normalize_name
-import directives, languages
-from tableparser import TableParser, TableMarkupError
+from docutils.parsers.rst import directives, languages
+from docutils.parsers.rst.tableparser import TableParser, TableMarkupError
class MarkupError(DataError): pass
@@ -141,7 +144,7 @@ class RSTStateMachine(StateMachineWS):
StateMachine, and return the resulting
document.
"""
- self.language = languages.get_language(document.language_code)
+ self.language = languages.get_language(document.options.language_code)
self.match_titles = match_titles
if inliner is None:
inliner = Inliner()
@@ -431,9 +434,9 @@ class Inliner:
openers = '\'"([{<'
closers = '\'")]}>'
- start_string_prefix = (r'(?:(?<=^)|(?<=[ \n%s]))'
+ start_string_prefix = (r'(?:(?<=^)|(?<=[-/: \n%s]))'
% re.escape(openers))
- end_string_suffix = (r'(?:(?=$)|(?=[- \n.,:;!?%s]))'
+ end_string_suffix = (r'(?:(?=$)|(?=[-/:.,;!? \n%s]))'
% re.escape(closers))
non_whitespace_before = r'(?
Date: Thu, 30 May 2002 02:17:28 +0000
Subject: - Added support for the ``--stylesheet`` option. - Added support for
an option values object which carries default settings and overrides (from
command-line options and library use). - Cleaned up imports: no more relative
package imports or comma-separated lists of top-level modules.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@154 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 2a32a88a1..931718706 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -17,7 +17,10 @@ contains a minimum of formatting information. A cascading style sheet
__docformat__ = 'reStructuredText'
-import sys, time, string, re
+import sys
+import time
+import string
+import re
from types import ListType
from docutils import writers, nodes, languages
@@ -27,6 +30,10 @@ class Writer(writers.Writer):
supported = ('html', 'html4css1', 'xhtml')
"""Formats this writer supports."""
+ cmdline_options = (
+ ('Specify a stylesheet file. Default is "default.css".',
+ ['--stylesheet'], {'default': 'default.css', 'metavar': ''}),)
+
output = None
"""Final translated form of `document`."""
@@ -51,19 +58,18 @@ class HTMLTranslator(nodes.NodeVisitor):
'charset=UTF-8">\n'
generator = '\n'
- stylesheet_link = '\n'
+ stylesheet_link = '\n'
def __init__(self, document):
nodes.NodeVisitor.__init__(self, document)
- self.language = languages.get_language(document.language_code)
+ self.language = languages.get_language(document.options.language_code)
self.head_prefix = [
self.xml_declaration, # @@@ % output_encoding
self.doctype,
- self.html_head % document.language_code,
+ self.html_head % document.options.language_code,
self.content_type, # @@@ % output encoding
self.generator,
- self.stylesheet_link] # @@@ % stylesheet
+ self.stylesheet_link % document.options.stylesheet]
self.head = []
self.body_prefix = ['\n\n']
self.body = []
--
cgit v1.2.1
From 1be17ead1d6e210c5a8d76cd44a283879f932d69 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:29:07 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@158 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/__init__.py | 2 +-
docutils/writers/__init__.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/__init__.py b/docutils/transforms/__init__.py
index 55e656bff..b2b9337d5 100644
--- a/docutils/transforms/__init__.py
+++ b/docutils/transforms/__init__.py
@@ -59,7 +59,7 @@ class Transform(Component):
apply to the document as a whole, `startnode` is not set (i.e. its
value is `None`)."""
- self.language = languages.get_language(document.language_code)
+ self.language = languages.get_language(document.options.language_code)
"""Language module local to this document."""
def transform(self):
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
index 35e5254c6..3c20068d4 100644
--- a/docutils/writers/__init__.py
+++ b/docutils/writers/__init__.py
@@ -52,7 +52,7 @@ class Writer(Component):
def write(self, document, destination):
self.document = document
- self.language = languages.get_language(document.language_code)
+ self.language = languages.get_language(document.options.language_code)
self.destination = destination
self.transform()
self.translate()
--
cgit v1.2.1
From 1934c6cf5d19f763d01e03aa4babd681eea3b399 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:29:30 +0000
Subject: Cleaned up imports; updated.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@159 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/readers/pep.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/readers/pep.py b/docutils/readers/pep.py
index 113b2705e..b7fabebb9 100644
--- a/docutils/readers/pep.py
+++ b/docutils/readers/pep.py
@@ -13,7 +13,9 @@ Python Enhancement Proposal (PEP) Reader.
__docformat__ = 'reStructuredText'
-import sys, os, re
+import sys
+import os
+import re
from docutils import nodes
from docutils.readers import standalone
from docutils.transforms import peps, references
@@ -30,12 +32,11 @@ class Reader(standalone.Reader):
references.Footnotes,
references.Hyperlinks,)
- def __init__(self, reporter, parser, parser_name, language_code):
+ def __init__(self, parser, parser_name):
"""`parser` should be ``None``."""
if parser is None:
parser = rst.Parser(rfc2822=1, inliner=Inliner())
- standalone.Reader.__init__(
- self, reporter, parser, '', language_code)
+ standalone.Reader.__init__(self, parser, '')
class Inliner(rst.states.Inliner):
--
cgit v1.2.1
From 6e398dc95eb60a5b81047b899954503ce780f1db Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 02:30:40 +0000
Subject: Cleaned up imports
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@160 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/__init__.py | 2 +-
docutils/statemachine.py | 4 +++-
docutils/transforms/components.py | 8 ++++++--
docutils/transforms/parts.py | 3 ++-
docutils/transforms/peps.py | 8 ++++++--
docutils/transforms/universal.py | 3 ++-
6 files changed, 20 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/__init__.py b/docutils/parsers/rst/__init__.py
index 506a9e9fb..66b594841 100644
--- a/docutils/parsers/rst/__init__.py
+++ b/docutils/parsers/rst/__init__.py
@@ -48,7 +48,7 @@ __docformat__ = 'reStructuredText'
import docutils.parsers
import docutils.statemachine
-import states
+from docutils.parsers.rst import states
class Parser(docutils.parsers.Parser):
diff --git a/docutils/statemachine.py b/docutils/statemachine.py
index 2a772c206..e6502d3cd 100644
--- a/docutils/statemachine.py
+++ b/docutils/statemachine.py
@@ -105,7 +105,9 @@ How To Use This Module
__docformat__ = 'restructuredtext'
-import sys, re, string
+import sys
+import re
+import string
class StateMachine:
diff --git a/docutils/transforms/components.py b/docutils/transforms/components.py
index 71473bea9..dee54a215 100644
--- a/docutils/transforms/components.py
+++ b/docutils/transforms/components.py
@@ -11,8 +11,12 @@ Docutils component-related transforms.
__docformat__ = 'reStructuredText'
-import sys, os, re, time
-from docutils import nodes, utils, ApplicationError, DataError
+import sys
+import os
+import re
+import time
+from docutils import nodes, utils
+from docutils import ApplicationError, DataError
from docutils.transforms import Transform, TransformError
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index ac9ad0466..7a6d97219 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -14,7 +14,8 @@ Transforms related to document parts.
__docformat__ = 'reStructuredText'
-import re, sys
+import re
+import sys
from docutils import nodes, utils
from docutils.transforms import TransformError, Transform
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
index ba311d488..2c51fa861 100644
--- a/docutils/transforms/peps.py
+++ b/docutils/transforms/peps.py
@@ -14,8 +14,12 @@ Transforms for PEP processing.
__docformat__ = 'reStructuredText'
-import sys, os, re, time
-from docutils import nodes, utils, ApplicationError, DataError
+import sys
+import os
+import re
+import time
+from docutils import nodes, utils
+from docutils import ApplicationError, DataError
from docutils.transforms import Transform, TransformError
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index c17341bb9..175faf637 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -19,7 +19,8 @@ Transforms needed by most or all documents:
__docformat__ = 'reStructuredText'
-import re, sys
+import re
+import sys
from docutils import nodes, utils
from docutils.transforms import TransformError, Transform
--
cgit v1.2.1
From f58fb865a3aea6a7b87ca716fd16a0ba2cdd9ac6 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 30 May 2002 03:14:26 +0000
Subject: removed 2.2ism
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@162 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/utils.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/utils.py b/docutils/utils.py
index d276b671f..da9c49512 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -13,7 +13,7 @@ Miscellaneous utilities for the documentation utilities.
__docformat__ = 'reStructuredText'
import sys
-from types import StringTypes
+from types import StringType, UnicodeType
from docutils import ApplicationError, DataError
from docutils import frontend, nodes
@@ -81,7 +81,7 @@ class Reporter:
"""
if stream is None:
stream = sys.stderr
- elif type(stream) in StringTypes:
+ elif type(stream) in (StringType, UnicodeType):
raise NotImplementedError('This should open a file for writing.')
self.categories = {'': ConditionSet(debug, report_level, halt_level,
--
cgit v1.2.1
From 0e41749d3da1e831a98aefb848c6a168894db738 Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 31 May 2002 00:50:04 +0000
Subject: docstring
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@163 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index 7c28d800a..f64e00b8c 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -69,7 +69,8 @@ class Publisher:
Set default option values (keyword arguments).
Set components first (`self.set_reader` & `self.set_writer`).
- Overrides the command line.
+ Explicitly setting options disables command line option processing
+ from `self.publish()`.
"""
option_parser = OptionParser(
components=(self.reader, self.parser, self.writer),
--
cgit v1.2.1
From 8610e9c1dfa7383679ef821aac3e95185feadae4 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 1 Jun 2002 01:37:29 +0000
Subject: - Added ``decoration``, ``header``, and ``footer`` node classes,
and ``PreDecorative`` mixin.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@168 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 39 +++++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 16 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 6784416b2..45d5ef726 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -446,6 +446,7 @@ class Element(Node):
for c in childclass:
if isinstance(self.children[index], c):
match = 1
+ break
if not match:
return index
return None
@@ -506,13 +507,15 @@ class Root: pass
class Titular: pass
-class Bibliographic: pass
+class PreDecorative:
+ """Category of Node which may occur before Decorative Nodes."""
-
-class PreBibliographic:
+class PreBibliographic(PreDecorative):
"""Category of Node which may occur before Bibliographic Nodes."""
- pass
+class Bibliographic(PreDecorative): pass
+
+class Decorative: pass
class Structural: pass
@@ -524,11 +527,8 @@ class Sequential(Body): pass
class Admonition(Body): pass
-
class Special(Body):
"""Special internal body elements."""
- pass
-
class Part: pass
@@ -828,6 +828,15 @@ class date(Bibliographic, TextElement): pass
class copyright(Bibliographic, TextElement): pass
+# =====================
+# Decorative Elements
+# =====================
+
+class decoration(Decorative, Element): pass
+class header(Decorative, Element): pass
+class footer(Decorative, Element): pass
+
+
# =====================
# Structural Elements
# =====================
@@ -848,8 +857,6 @@ class topic(Structural, Element):
list, block quote, etc.
"""
- pass
-
class transition(Structural, Element): pass
@@ -1054,14 +1061,14 @@ node_class_names = """
Text
attention author authors
block_quote bullet_list
- caption caution citation citation_reference classifier colspec
- comment contact copyright
- danger date definition definition_list definition_list_item
+ caption caution citation citation_reference classifier colspec comment
+ contact copyright
+ danger date decoration definition definition_list definition_list_item
description docinfo doctest_block document
emphasis entry enumerated_list error
- field field_argument field_body field_list field_name figure
+ field field_argument field_body field_list field_name figure footer
footnote footnote_reference
- hint
+ header hint
image important interpreted
label legend list_item literal literal_block
note
@@ -1069,8 +1076,8 @@ node_class_names = """
option_string organization
paragraph pending problematic
raw reference revision row
- section status strong substitution_definition
- substitution_reference subtitle system_message
+ section status strong substitution_definition substitution_reference
+ subtitle system_message
table target tbody term tgroup thead tip title topic transition
version
warning""".split()
--
cgit v1.2.1
From 8f2f1d9958c71eecc024167722971ada5158f99d Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 1 Jun 2002 01:40:18 +0000
Subject: - Added ``Decorations`` transform (support for "--generator",
"--date", "--time", "--source-link" options).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@169 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 58 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index 175faf637..782d930c5 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -8,6 +8,7 @@
Transforms needed by most or all documents:
+- `Decorations`: Generate a document's header & footer.
- `Messages`: Placement of system messages stored in
`nodes.document.messages`.
- `TestMessages`: Like `Messages`, used on test runs.
@@ -21,10 +22,65 @@ __docformat__ = 'reStructuredText'
import re
import sys
+import time
from docutils import nodes, utils
from docutils.transforms import TransformError, Transform
+class Decorations(Transform):
+
+ """
+ Populate a document's decoration element (header, footer).
+ """
+
+ def transform(self):
+ header = self.generate_header()
+ footer = self.generate_footer()
+ if header or footer:
+ decoration = nodes.decoration()
+ decoration += header
+ decoration += footer
+ document = self.document
+ index = document.first_child_not_matching_class(
+ nodes.PreDecorative)
+ if index is None:
+ document += decoration
+ else:
+ document[index:index] = [decoration]
+
+ def generate_header(self):
+ return None
+
+ def generate_footer(self):
+ # @@@ Text is hard-coded for now.
+ # Should be made dynamic (language-dependent).
+ options = self.document.options
+ if options.generator or options.datestamp or options.source_link:
+ text = []
+ if options.generator:
+ text.extend([
+ nodes.Text('Generated by '),
+ nodes.reference('', 'Docutils', refuri=
+ 'http://docutils.sourceforge.net/'),
+ nodes.Text(' from '),
+ nodes.reference('', 'reStructuredText', refuri='http://'
+ 'docutils.sourceforge.net/rst.html'),
+ nodes.Text(' source. ')])
+ if options.source_link:
+ text.extend([
+ nodes.reference('', 'View document source',
+ refuri=self.document['source']),
+ nodes.Text('. ')])
+ if options.datestamp:
+ datestamp = time.strftime(options.datestamp, time.gmtime())
+ text.append(nodes.Text('Date: ' + datestamp + '. '))
+ footer = nodes.footer()
+ footer += nodes.paragraph('', '', *text)
+ return footer
+ else:
+ return None
+
+
class Messages(Transform):
"""
@@ -149,7 +205,7 @@ test_transforms = (TestMessages,)
first_reader_transforms = (FirstReaderPending,)
"""Universal transforms to apply before any other Reader transforms."""
-last_reader_transforms = (LastReaderPending,)
+last_reader_transforms = (LastReaderPending, Decorations)
"""Universal transforms to apply after all other Reader transforms."""
first_writer_transforms = (FirstWriterPending,)
--
cgit v1.2.1
From 83de8a45d6e3ca1567ee955f9d557c8f0c75e2c2 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 1 Jun 2002 01:41:33 +0000
Subject: Enabled a bunch of command-line options relating to the document
footer.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@170 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 36 +++++++++++++++++++++++-------------
1 file changed, 23 insertions(+), 13 deletions(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 727db95d0..6f158e862 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -26,18 +26,26 @@ class OptionParser(optik.OptionParser):
cmdline_options = (
# Unimplemented or unused options are commented out.
- #('Include a "Generated by Docutils" credit with a link, at the end '
- # 'of the document.',
- # ['--generator', '-g'], {'action': 'store_true', 'default': 0}),
- #('Include the date at the end of the document (UTC).',
- # ['--date', '-d'], {'action': 'store_const', 'const': '%Y-%m-%d',
- # 'dest': 'datestamp', 'default': ''}),
- #('Include the time & date at the end of the document (UTC).',
- # ['--time', '-t'], {'action': 'store_const',
- # 'const': '%Y-%m-%d %H:%M:%S UTC',
- # 'dest': 'datestamp', 'default': ''}),
- #('Include a "(View document source)" link.',
- # ['--source-link', '-s'], {'action': 'store_true', 'default': 0}),
+ ('Include a "Generated by Docutils" credit with a link, at the end '
+ 'of the document.',
+ ['--generator', '-g'], {'action': 'store_true'}),
+ ('Do not include a generator credit.',
+ ['--no-generator'], {'action': 'store_false', 'dest': 'generator'}),
+ ('Include the date at the end of the document (UTC).',
+ ['--date', '-d'], {'action': 'store_const', 'const': '%Y-%m-%d',
+ 'dest': 'datestamp'}),
+ ('Include the time & date at the end of the document (UTC).',
+ ['--time', '-t'], {'action': 'store_const',
+ 'const': '%Y-%m-%d %H:%M UTC',
+ 'dest': 'datestamp'}),
+ ('Do not include a datestamp of any kind.',
+ ['--no-datestamp'], {'action': 'store_const', 'const': None,
+ 'dest': 'datestamp'}),
+ ('Include a "View document source." link.',
+ ['--source-link', '-s'], {'action': 'store_true'}),
+ ('Do not include a "(View document source)" link.',
+ ['--no-source-link'], {'action': 'store_false',
+ 'dest': 'source_link'}),
('Set verbosity threshold; report system messages at or higher than '
' (by name or number: "info" or "1", warning/2, error/3, '
'severe/4; also, "none" or 5+). Default is 2 (warning).',
@@ -56,7 +64,9 @@ class OptionParser(optik.OptionParser):
['--strict'], {'action': 'store_const', 'const': 'info',
'dest': 'halt_level'}),
('Report debug-level system messages.',
- ['--debug'], {'action': 'store_true', 'default': 0}),
+ ['--debug'], {'action': 'store_true'}),
+ ('Do not report debug-level system messages.',
+ ['--no-debug'], {'action': 'store_false', 'dest': 'debug'}),
('Send the output of system messages (warnings) to .',
['--warnings'], {'dest': 'warning_stream', 'metavar': ''}),
# @@@ Take default encoding & language from locale?
--
cgit v1.2.1
From 4c89d002f8f9017caa9ff690e0a82d1ec7556f5d Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 1 Jun 2002 01:42:51 +0000
Subject: Removed temporary testing code.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@171 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 8 --------
1 file changed, 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index f64e00b8c..f46527a9f 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -90,14 +90,6 @@ class Publisher:
argv = sys.argv[1:]
self.options, self.source, self.destination \
= option_parser.parse_args(argv)
- """
- # For testing purposes:
- from pprint import pformat
- print 'options:'
- print pformat(options.__dict__)
- print 'source=%r, destination=%r' % (source, destination)
- sys.exit(0)
- """
def publish(self, argv=None, usage=None):
"""
--
cgit v1.2.1
From 52f3b32ff8b86bfee7f2415e0d1e6db5dc5a1acc Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 1 Jun 2002 01:43:35 +0000
Subject: docstring
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@172 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/utils.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/utils.py b/docutils/utils.py
index da9c49512..161526fa0 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -174,7 +174,8 @@ class Reporter:
class ConditionSet:
"""
- A set of thresholds, switches, and streams corresponding to one `Reporter`
+ A set of two thresholds (`report_level` & `halt_level`), a switch
+ (`debug`), and an I/O stream (`stream`), corresponding to one `Reporter`
category.
"""
--
cgit v1.2.1
From dfaa9f0a48d38d190eb44a83cef3a0cff6257805 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 1 Jun 2002 01:44:33 +0000
Subject: - Added support for ``decoration``, ``header``, and ``footer``
elements.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@173 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 931718706..60570a914 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -265,6 +265,12 @@ class HTMLTranslator(nodes.NodeVisitor):
def depart_date(self, node):
self.depart_docinfo_item()
+ def visit_decoration(self, node):
+ pass
+
+ def depart_decoration(self, node):
+ pass
+
def visit_definition(self, node):
self.body.append('\n')
self.body.append(self.starttag(node, 'dd'))
@@ -425,6 +431,16 @@ class HTMLTranslator(nodes.NodeVisitor):
def depart_figure(self, node):
self.body.append('\n')
+ def visit_footer(self, node):
+ self.context.append(len(self.body))
+
+ def depart_footer(self, node):
+ start = self.context.pop()
+ footer = ([self.starttag(node, 'div', CLASS='footer'), '\n']
+ + self.body[start:] + ['\n'])
+ self.body_suffix[:0] = footer
+ del self.body[start:]
+
def visit_footnote(self, node):
self.body.append(self.starttag(node, 'table', CLASS='footnote',
frame="void", rules="none"))
@@ -449,6 +465,16 @@ class HTMLTranslator(nodes.NodeVisitor):
def depart_footnote_reference(self, node):
self.body.append('')
+ def visit_header(self, node):
+ self.context.append(len(self.body))
+
+ def depart_header(self, node):
+ start = self.context.pop()
+ self.body_prefix.append(self.starttag(node, 'div', CLASS='header'))
+ self.body_prefix.extend(self.body[start:])
+ self.body_prefix.append('\n\n')
+ del self.body[start:]
+
def visit_hint(self, node):
self.visit_admonition(node, 'hint')
--
cgit v1.2.1
From 7ce7476c958ae579fbd64bbbb00ebcee127d88ac Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 13 Jun 2002 03:23:39 +0000
Subject: Added __version__
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@179 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 1 +
1 file changed, 1 insertion(+)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index fe63168b7..0ea2f1803 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -51,6 +51,7 @@ Subpackages:
"""
__docformat__ = 'reStructuredText'
+__version__ = '0.1+'
class ApplicationError(StandardError): pass
--
cgit v1.2.1
From 361fcaa4671d334ee92294de947ad99546469bd5 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 13 Jun 2002 03:25:41 +0000
Subject: Updated for new Optik option group functionality.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@180 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 13 ++---
docutils/frontend.py | 146 +++++++++++++++++++++++++++------------------------
2 files changed, 83 insertions(+), 76 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index f46527a9f..1fe6af418 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -77,7 +77,7 @@ class Publisher:
defaults=defaults)
self.options = option_parser.get_default_values()
- def process_command_line(self, argv=None, usage=None):
+ def process_command_line(self, argv=None, usage=None, description=None):
"""
Pass an empty list to `argv` to avoid reading `sys.argv` (the
default).
@@ -85,19 +85,20 @@ class Publisher:
Set components first (`self.set_reader` & `self.set_writer`).
"""
option_parser = OptionParser(
- components=(self.reader, self.parser, self.writer), usage=usage)
+ components=(self.reader, self.parser, self.writer),
+ usage=usage, description=description)
if argv is None:
argv = sys.argv[1:]
self.options, self.source, self.destination \
= option_parser.parse_args(argv)
- def publish(self, argv=None, usage=None):
+ def publish(self, argv=None, usage=None, description=None):
"""
Process command line options and arguments, run `self.reader`
and then `self.writer`.
"""
if self.options is None:
- self.process_command_line(argv, usage)
+ self.process_command_line(argv, usage, description)
document = self.reader.read(self.source, self.parser, self.options)
self.writer.write(document, self.destination)
@@ -105,11 +106,11 @@ class Publisher:
def publish(reader=None, reader_name='standalone',
parser=None, parser_name='restructuredtext',
writer=None, writer_name='pseudoxml',
- argv=None, usage=None):
+ argv=None, usage=None, description=None):
"""A convenience function; set up & run a `Publisher`."""
pub = Publisher(reader, parser, writer)
if reader is None:
pub.set_reader(reader_name, parser, parser_name)
if writer is None:
pub.set_writer(writer_name)
- pub.publish(argv, usage)
+ pub.publish(argv, usage, description)
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 6f158e862..01b0ed489 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -12,7 +12,8 @@ Command-line and common processing for Docutils front-ends.
__docformat__ = 'reStructuredText'
-import optik
+import docutils
+from docutils import optik
class OptionParser(optik.OptionParser):
@@ -21,87 +22,95 @@ class OptionParser(optik.OptionParser):
Parser for command-line and library use. The `cmdline_options` specification here and in other Docutils components are merged
"""
- standard_option_list = []
- """We supply our own help option."""
-
cmdline_options = (
- # Unimplemented or unused options are commented out.
- ('Include a "Generated by Docutils" credit with a link, at the end '
- 'of the document.',
- ['--generator', '-g'], {'action': 'store_true'}),
- ('Do not include a generator credit.',
- ['--no-generator'], {'action': 'store_false', 'dest': 'generator'}),
- ('Include the date at the end of the document (UTC).',
- ['--date', '-d'], {'action': 'store_const', 'const': '%Y-%m-%d',
- 'dest': 'datestamp'}),
- ('Include the time & date at the end of the document (UTC).',
- ['--time', '-t'], {'action': 'store_const',
- 'const': '%Y-%m-%d %H:%M UTC',
- 'dest': 'datestamp'}),
- ('Do not include a datestamp of any kind.',
- ['--no-datestamp'], {'action': 'store_const', 'const': None,
- 'dest': 'datestamp'}),
- ('Include a "View document source." link.',
- ['--source-link', '-s'], {'action': 'store_true'}),
- ('Do not include a "(View document source)" link.',
- ['--no-source-link'], {'action': 'store_false',
- 'dest': 'source_link'}),
- ('Set verbosity threshold; report system messages at or higher than '
- ' (by name or number: "info" or "1", warning/2, error/3, '
- 'severe/4; also, "none" or 5+). Default is 2 (warning).',
- ['--report', '-r'], {'dest': 'report_level', 'default': 2,
- 'metavar': ''}),
- ('Report all system messages, info-level and higher. (Same as '
- '"--report=info".)',
- ['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
- 'dest': 'report_level'}),
- ('Set the threshold () at or above which system messages are '
- 'converted to exceptions, halting execution immediately. Levels as '
- 'in --report. Default is 4 (severe).',
- ['--halt'], {'dest': 'halt_level', 'default': 4,
- 'metavar': ''}),
- ('Same as "--halt=info": halt processing at the slightest problem.',
- ['--strict'], {'action': 'store_const', 'const': 'info',
- 'dest': 'halt_level'}),
- ('Report debug-level system messages.',
- ['--debug'], {'action': 'store_true'}),
- ('Do not report debug-level system messages.',
- ['--no-debug'], {'action': 'store_false', 'dest': 'debug'}),
- ('Send the output of system messages (warnings) to .',
- ['--warnings'], {'dest': 'warning_stream', 'metavar': ''}),
- # @@@ Take default encoding & language from locale?
- #('Specify the encoding of input text. Default is "utf-8".',
- # ['--encoding', '-e'], {'default': 'utf-8', 'metavar': ''}),
- ('Specify the language of input text (ISO 639 2-letter identifier. '
- 'Default is "en" (English).',
- ['--language', '-l'], {'dest': 'language_code', 'default': 'en',
- 'metavar': ''}),
- ('Show this help message and exit.',
- ['--help', '-h'], {'action': 'help'}),)
+ 'General Options',
+ None,
+ (('Include a "Generated by Docutils" credit with a link, at the end '
+ 'of the document.',
+ ['--generator', '-g'], {'action': 'store_true'}),
+ ('Do not include a generator credit.',
+ ['--no-generator'], {'action': 'store_false', 'dest': 'generator'}),
+ ('Include the date at the end of the document (UTC).',
+ ['--date', '-d'], {'action': 'store_const', 'const': '%Y-%m-%d',
+ 'dest': 'datestamp'}),
+ ('Include the time & date at the end of the document (UTC).',
+ ['--time', '-t'], {'action': 'store_const',
+ 'const': '%Y-%m-%d %H:%M UTC',
+ 'dest': 'datestamp'}),
+ ('Do not include a datestamp of any kind.',
+ ['--no-datestamp'], {'action': 'store_const', 'const': None,
+ 'dest': 'datestamp'}),
+ ('Include a "View document source." link.',
+ ['--source-link', '-s'], {'action': 'store_true'}),
+ ('Do not include a "(View document source)" link.',
+ ['--no-source-link'], {'action': 'store_false',
+ 'dest': 'source_link'}),
+ ('Set verbosity threshold; report system messages at or higher than '
+ ' (by name or number: "info" or "1", warning/2, error/3, '
+ 'severe/4; also, "none" or 5+). Default is 2 (warning).',
+ ['--report', '-r'], {'dest': 'report_level', 'default': 2,
+ 'metavar': ''}),
+ ('Report all system messages, info-level and higher. (Same as '
+ '"--report=info".)',
+ ['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
+ 'dest': 'report_level'}),
+ ('Set the threshold () at or above which system messages are '
+ 'converted to exceptions, halting execution immediately. Levels '
+ 'as in --report. Default is 4 (severe).',
+ ['--halt'], {'dest': 'halt_level', 'default': 4,
+ 'metavar': ''}),
+ ('Same as "--halt=info": halt processing at the slightest problem.',
+ ['--strict'], {'action': 'store_const', 'const': 'info',
+ 'dest': 'halt_level'}),
+ ('Report debug-level system messages.',
+ ['--debug'], {'action': 'store_true'}),
+ ('Do not report debug-level system messages.',
+ ['--no-debug'], {'action': 'store_false', 'dest': 'debug'}),
+ ('Send the output of system messages (warnings) to .',
+ ['--warnings'], {'dest': 'warning_stream', 'metavar': ''}),
+ # @@@ Take default encoding & language from locale?
+ #('Specify the encoding of input text. Default is "utf-8".',
+ # ['--encoding', '-e'], {'default': 'utf-8', 'metavar': ''}),
+ ('Specify the language of input text (ISO 639 2-letter identifier. '
+ 'Default is "en" (English).',
+ ['--language', '-l'], {'dest': 'language_code', 'default': 'en',
+ 'metavar': ''}),
+ ("Show this program's version number and exit.",
+ ['--version'], {'action': 'version'}),
+ ('Show this help message and exit.',
+ ['--help', '-h'], {'action': 'help'}),))
"""Command-line option specifications, common to all Docutils front-ends.
- A list/tuple of tuples: ``('help text', [list of option strings], {keyword
- arguments})``. Option specs from Docutils components are also used (see
- `build_option_parser()`)."""
+ Option group title, description, and a list/tuple of tuples: ``('help
+ text', [list of option strings], {keyword arguments})``. Option specs
+ from Docutils components are also used (see
+ `populate_from_components()`)."""
thresholds = {'info': 1, 'warning': 2, 'error': 3, 'severe': 4, 'none': 5}
"""Lookup table for --report and --halt threshold values."""
+ version_template = '%%prog (Docutils %s)' % docutils.__version__
+
def __init__(self, components=(), defaults={}, *args, **kwargs):
"""
`components` is a list of Docutils components each containing a
``.cmdline_options`` attribute. `defaults` is a
"""
- optik.OptionParser.__init__(self, *args, **kwargs)
- self.populate_from_components((self,) + tuple(components))
+ optik.OptionParser.__init__(self, help=None, format=optik.Titled(),
+ *args, **kwargs)
+ if not self.version:
+ self.version = self.version_template
+ self.populate_from_components(tuple(components) + (self,))
self.set_defaults(**defaults)
def populate_from_components(self, components):
for component in components:
- if component is not None:
- for (help_text, option_strings, kwargs) \
- in component.cmdline_options:
- self.add_option(help=help_text, *option_strings,
- **kwargs)
+ if component is not None and component.cmdline_options:
+ title, description, option_spec = component.cmdline_options
+ group = optik.OptionGroup(self, title, description)
+ self.add_option_group(group)
+ for (help_text, option_strings, kwargs) in option_spec:
+ group.add_option(help=help_text, *option_strings,
+ **kwargs)
def check_values(self, values, args):
values.report_level = self.check_threshold(values.report_level)
@@ -127,6 +136,3 @@ class OptionParser(optik.OptionParser):
if args:
self.error('Maximum 2 arguments allowed.')
return source, destination
-
- def get_default_values(self):
- return optik.option_parser.Values(self.defaults)
--
cgit v1.2.1
From aff483bd932352ce97700fb7666c2cfc8190f5c5 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 13 Jun 2002 03:29:13 +0000
Subject: Combined from Optik package, with added option groups and other
modifications. The use of this module is probably only temporary.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@181 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/optik.py | 1282 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1282 insertions(+)
create mode 100644 docutils/optik.py
(limited to 'docutils')
diff --git a/docutils/optik.py b/docutils/optik.py
new file mode 100644
index 000000000..6feebabb4
--- /dev/null
+++ b/docutils/optik.py
@@ -0,0 +1,1282 @@
+# This is *not* the official distribution of Optik. See
+# http://optik.sourceforge.net/ for the official distro.
+#
+# This combined module was converted from the "optik" package for Docutils use
+# by David Goodger (2002-06-12). Optik is slated for inclusion in the Python
+# standard library as OptionParser.py. Once Optik itself becomes a single
+# module, Docutils will include the official module and kill off this
+# temporary fork.
+
+"""optik
+
+A powerful, extensible, and easy-to-use command-line parser for Python.
+
+By Greg Ward
+
+See http://optik.sourceforge.net/
+"""
+
+# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of the author nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+__revision__ = "$Id$"
+
+__version__ = "1.3+"
+
+
+import sys
+import os
+import types
+from types import TupleType, DictType
+from distutils.fancy_getopt import wrap_text
+
+
+SUPPRESS_HELP = "SUPPRESS"+"HELP"
+SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
+# Not supplying a default is different from a default of None,
+# so we need an explicit "not supplied" value.
+NO_DEFAULT = "NO"+"DEFAULT"
+
+
+class OptikError (Exception):
+ def __init__ (self, msg):
+ self.msg = msg
+
+ def __str__ (self):
+ return self.msg
+
+
+class OptionError (OptikError):
+ """
+ Raised if an Option instance is created with invalid or
+ inconsistent arguments.
+ """
+
+ def __init__ (self, msg, option):
+ self.msg = msg
+ self.option_id = str(option)
+
+ def __str__ (self):
+ if self.option_id:
+ return "option %s: %s" % (self.option_id, self.msg)
+ else:
+ return self.msg
+
+class OptionConflictError (OptionError):
+ """
+ Raised if conflicting options are added to an OptionParser.
+ """
+
+class OptionValueError (OptikError):
+ """
+ Raised if an invalid option value is encountered on the command
+ line.
+ """
+
+class BadOptionError (OptikError):
+ """
+ Raised if an invalid or ambiguous option is seen on the command-line.
+ """
+
+
+_builtin_cvt = { "int" : (int, "integer"),
+ "long" : (long, "long integer"),
+ "float" : (float, "floating-point"),
+ "complex" : (complex, "complex") }
+
+def check_builtin (option, opt, value):
+ (cvt, what) = _builtin_cvt[option.type]
+ try:
+ return cvt(value)
+ except ValueError:
+ raise OptionValueError(
+ #"%s: invalid %s argument %r" % (opt, what, value))
+ "option %s: invalid %s value: %r" % (opt, what, value))
+
+
+class Option:
+ """
+ Instance attributes:
+ _short_opts : [string]
+ _long_opts : [string]
+
+ action : string
+ type : string
+ dest : string
+ default : any
+ nargs : int
+ const : any
+ callback : function
+ callback_args : (any*)
+ callback_kwargs : { string : any }
+ help : string
+ metavar : string
+ """
+
+ # The list of instance attributes that may be set through
+ # keyword args to the constructor.
+ ATTRS = ['action',
+ 'type',
+ 'dest',
+ 'default',
+ 'nargs',
+ 'const',
+ 'callback',
+ 'callback_args',
+ 'callback_kwargs',
+ 'help',
+ 'metavar']
+
+ # The set of actions allowed by option parsers. Explicitly listed
+ # here so the constructor can validate its arguments.
+ ACTIONS = ("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "count",
+ "callback",
+ "help",
+ "version")
+
+ # The set of actions that involve storing a value somewhere;
+ # also listed just for constructor argument validation. (If
+ # the action is one of these, there must be a destination.)
+ STORE_ACTIONS = ("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "count")
+
+ # The set of actions for which it makes sense to supply a value
+ # type, ie. where we expect an argument to this option.
+ TYPED_ACTIONS = ("store",
+ "append",
+ "callback")
+
+ # The set of known types for option parsers. Again, listed here for
+ # constructor argument validation.
+ TYPES = ("string", "int", "long", "float", "complex")
+
+ # Dictionary of argument checking functions, which convert and
+ # validate option arguments according to the option type.
+ #
+ # Signature of checking functions is:
+ # check(option : Option, opt : string, value : string) -> any
+ # where
+ # option is the Option instance calling the checker
+ # opt is the actual option seen on the command-line
+ # (eg. "-a", "--file")
+ # value is the option argument seen on the command-line
+ #
+ # The return value should be in the appropriate Python type
+ # for option.type -- eg. an integer if option.type == "int".
+ #
+ # If no checker is defined for a type, arguments will be
+ # unchecked and remain strings.
+ TYPE_CHECKER = { "int" : check_builtin,
+ "long" : check_builtin,
+ "float" : check_builtin,
+ "complex" : check_builtin,
+ }
+
+
+ # CHECK_METHODS is a list of unbound method objects; they are called
+ # by the constructor, in order, after all attributes are
+ # initialized. The list is created and filled in later, after all
+ # the methods are actually defined. (I just put it here because I
+ # like to define and document all class attributes in the same
+ # place.) Subclasses that add another _check_*() method should
+ # define their own CHECK_METHODS list that adds their check method
+ # to those from this class.
+ CHECK_METHODS = None
+
+
+ # -- Constructor/initialization methods ----------------------------
+
+ def __init__ (self, *opts, **attrs):
+ # Set _short_opts, _long_opts attrs from 'opts' tuple
+ opts = self._check_opt_strings(opts)
+ self._set_opt_strings(opts)
+
+ # Set all other attrs (action, type, etc.) from 'attrs' dict
+ self._set_attrs(attrs)
+
+ # Check all the attributes we just set. There are lots of
+ # complicated interdependencies, but luckily they can be farmed
+ # out to the _check_*() methods listed in CHECK_METHODS -- which
+ # could be handy for subclasses! The one thing these all share
+ # is that they raise OptionError if they discover a problem.
+ for checker in self.CHECK_METHODS:
+ checker(self)
+
+ def _check_opt_strings (self, opts):
+ # Filter out None because early versions of Optik had exactly
+ # one short option and one long option, either of which
+ # could be None.
+ opts = filter(None, opts)
+ if not opts:
+ raise OptionError("at least one option string must be supplied",
+ self)
+ return opts
+
+ def _set_opt_strings (self, opts):
+ self._short_opts = []
+ self._long_opts = []
+ for opt in opts:
+ if len(opt) < 2:
+ raise OptionError(
+ "invalid option string %r: "
+ "must be at least two characters long" % opt, self)
+ elif len(opt) == 2:
+ if not (opt[0] == "-" and opt[1] != "-"):
+ raise OptionError(
+ "invalid short option string %r: "
+ "must be of the form -x, (x any non-dash char)" % opt,
+ self)
+ self._short_opts.append(opt)
+ else:
+ if not (opt[0:2] == "--" and opt[2] != "-"):
+ raise OptionError(
+ "invalid long option string %r: "
+ "must start with --, followed by non-dash" % opt,
+ self)
+ self._long_opts.append(opt)
+
+ def _set_attrs (self, attrs):
+ for attr in self.ATTRS:
+ if attrs.has_key(attr):
+ setattr(self, attr, attrs[attr])
+ del attrs[attr]
+ else:
+ if attr == 'default':
+ setattr(self, attr, NO_DEFAULT)
+ else:
+ setattr(self, attr, None)
+ if attrs:
+ raise OptionError(
+ "invalid keyword arguments: %s" % ", ".join(attrs.keys()),
+ self)
+
+
+ # -- Constructor validation methods --------------------------------
+
+ def _check_action (self):
+ if self.action is None:
+ self.action = "store"
+ elif self.action not in self.ACTIONS:
+ raise OptionError("invalid action: %r" % self.action, self)
+
+ def _check_type (self):
+ if self.type is None:
+ # XXX should factor out another class attr here: list of
+ # actions that *require* a type
+ if self.action in ("store", "append"):
+ # No type given? "string" is the most sensible default.
+ self.type = "string"
+ else:
+ if self.type not in self.TYPES:
+ raise OptionError("invalid option type: %r" % self.type, self)
+ if self.action not in self.TYPED_ACTIONS:
+ raise OptionError(
+ "must not supply a type for action %r" % self.action, self)
+
+ def _check_dest (self):
+ if self.action in self.STORE_ACTIONS and self.dest is None:
+ # No destination given, and we need one for this action.
+ # Glean a destination from the first long option string,
+ # or from the first short option string if no long options.
+ if self._long_opts:
+ # eg. "--foo-bar" -> "foo_bar"
+ self.dest = self._long_opts[0][2:].replace('-', '_')
+ else:
+ self.dest = self._short_opts[0][1]
+
+ def _check_const (self):
+ if self.action != "store_const" and self.const is not None:
+ raise OptionError(
+ "'const' must not be supplied for action %r" % self.action,
+ self)
+
+ def _check_nargs (self):
+ if self.action in self.TYPED_ACTIONS:
+ if self.nargs is None:
+ self.nargs = 1
+ elif self.nargs is not None:
+ raise OptionError(
+ "'nargs' must not be supplied for action %r" % self.action,
+ self)
+
+ def _check_callback (self):
+ if self.action == "callback":
+ if not callable(self.callback):
+ raise OptionError(
+ "callback not callable: %r" % self.callback, self)
+ if (self.callback_args is not None and
+ type(self.callback_args) is not TupleType):
+ raise OptionError(
+ "callback_args, if supplied, must be a tuple: not %r"
+ % self.callback_args, self)
+ if (self.callback_kwargs is not None and
+ type(self.callback_kwargs) is not DictType):
+ raise OptionError(
+ "callback_kwargs, if supplied, must be a dict: not %r"
+ % self.callback_kwargs, self)
+ else:
+ if self.callback is not None:
+ raise OptionError(
+ "callback supplied (%r) for non-callback option"
+ % self.callback, self)
+ if self.callback_args is not None:
+ raise OptionError(
+ "callback_args supplied for non-callback option", self)
+ if self.callback_kwargs is not None:
+ raise OptionError(
+ "callback_kwargs supplied for non-callback option", self)
+
+
+ CHECK_METHODS = [_check_action,
+ _check_type,
+ _check_dest,
+ _check_const,
+ _check_nargs,
+ _check_callback]
+
+
+ # -- Miscellaneous methods -----------------------------------------
+
+ def __str__ (self):
+ if self._short_opts or self._long_opts:
+ return "/".join(self._short_opts + self._long_opts)
+ else:
+ raise RuntimeError, "short_opts and long_opts both empty!"
+
+ def takes_value (self):
+ return self.type is not None
+
+
+ # -- Processing methods --------------------------------------------
+
+ def check_value (self, opt, value):
+ checker = self.TYPE_CHECKER.get(self.type)
+ if checker is None:
+ return value
+ else:
+ return checker(self, opt, value)
+
+ def process (self, opt, value, values, parser):
+
+ # First, convert the value(s) to the right type. Howl if any
+ # value(s) are bogus.
+ if value is not None:
+ if self.nargs == 1:
+ value = self.check_value(opt, value)
+ else:
+ value = tuple([self.check_value(opt, v) for v in value])
+
+ # And then take whatever action is expected of us.
+ # This is a separate method to make life easier for
+ # subclasses to add new actions.
+ return self.take_action(
+ self.action, self.dest, opt, value, values, parser)
+
+ def take_action (self, action, dest, opt, value, values, parser):
+ if action == "store":
+ setattr(values, dest, value)
+ elif action == "store_const":
+ setattr(values, dest, self.const)
+ elif action == "store_true":
+ setattr(values, dest, 1)
+ elif action == "store_false":
+ setattr(values, dest, 0)
+ elif action == "append":
+ values.ensure_value(dest, []).append(value)
+ elif action == "count":
+ setattr(values, dest, values.ensure_value(dest, 0) + 1)
+ elif action == "callback":
+ args = self.callback_args or ()
+ kwargs = self.callback_kwargs or {}
+ self.callback(self, opt, value, parser, *args, **kwargs)
+ elif action == "help":
+ parser.print_help()
+ sys.exit(0)
+ elif action == "version":
+ parser.print_version()
+ sys.exit(0)
+ else:
+ raise RuntimeError, "unknown action %r" % self.action
+
+ return 1
+
+# class Option
+
+
+# Some day, there might be many Option classes. As of Optik 1.3, the
+# preferred way to instantiate Options is indirectly, via make_option(),
+# which will become a factory function when there are many Option
+# classes.
+make_option = Option
+
+
+STD_HELP_OPTION = Option("-h", "--help",
+ action="help",
+ help="show this help message and exit")
+STD_VERSION_OPTION = Option("--version",
+ action="version",
+ help="show program's version number and exit")
+
+
+class OptionContainer:
+
+ """
+ Abstract base class.
+
+ Class attributes:
+ standard_option_list : [Option]
+ List of standard options that will be accepted by all instances
+ of this parser class (intended to be overridden by subclasses).
+
+ Instance attributes:
+ option_list : [Option]
+ The list of Option objects contained by this OptionContainer.
+ _short_opt : { string : Option }
+ Dictionary mapping short option strings, eg. "-f" or "-X",
+ to the Option instances that implement them. If an Option
+ has multiple short option strings, it will appears in this
+ dictionary multiple times. [1]
+ _long_opt : { string : Option }
+ Dictionary mapping long option strings, eg. "--file" or
+ "--exclude", to the Option instances that implement them.
+ Again, a given Option can occur multiple times in this
+ dictionary. [1]
+ defaults : { string : any }
+ Dictionary mapping option destination names to default
+ values for each destination. [1]
+
+ [1] These mappings are common to (shared by) all components of the
+ controlling OptionParser, where they are initially created.
+
+ """
+
+ standard_option_list = []
+
+ def __init__(self, parser, description=None, option_list=None):
+ # List of Options is local to this OptionContainer.
+ self.option_list = []
+ # The shared mappings are stored in the parser.
+ self._short_opt = parser._short_opt
+ self._long_opt = parser._long_opt
+ self.defaults = parser.defaults
+ #
+ self.format = parser.format
+ self.option_class = parser.option_class
+ self.conflict_handler = parser.conflict_handler
+ self.set_description(description)
+ self._populate_option_list(option_list)
+
+ def set_description(self, description):
+ self.description = description
+
+ def _populate_option_list(self, option_list, version=None, help=None):
+ if self.standard_option_list:
+ self.add_options(self.standard_option_list)
+ if option_list:
+ self.add_options(option_list)
+ if version:
+ self.add_option(STD_VERSION_OPTION)
+ if help:
+ self.add_option(STD_HELP_OPTION)
+
+
+ # -- Option-adding methods -----------------------------------------
+
+ def _check_conflict (self, option):
+ conflict_opts = []
+ for opt in option._short_opts:
+ if self._short_opt.has_key(opt):
+ conflict_opts.append((opt, self._short_opt[opt]))
+ for opt in option._long_opts:
+ if self._long_opt.has_key(opt):
+ conflict_opts.append((opt, self._long_opt[opt]))
+
+ if conflict_opts:
+ handler = self.conflict_handler
+ if handler == "ignore": # behaviour for Optik 1.0, 1.1
+ pass
+ elif handler == "error": # new in 1.2
+ raise OptionConflictError(
+ "conflicting option string(s): %s"
+ % ", ".join([co[0] for co in conflict_opts]),
+ option)
+ elif handler == "resolve": # new in 1.2
+ for (opt, c_option) in conflict_opts:
+ if opt.startswith("--"):
+ c_option._long_opts.remove(opt)
+ del self._long_opt[opt]
+ else:
+ c_option._short_opts.remove(opt)
+ del self._short_opt[opt]
+ if not (c_option._short_opts or c_option._long_opts):
+ c_option.container.option_list.remove(c_option)
+
+ def add_option (self, *args, **kwargs):
+ """add_option(Option)
+ add_option(opt_str, ..., kwarg=val, ...)
+ """
+ if type(args[0]) is types.StringType:
+ option = self.option_class(*args, **kwargs)
+ elif len(args) == 1 and not kwargs:
+ option = args[0]
+ if not isinstance(option, Option):
+ raise TypeError, "not an Option instance: %r" % option
+ else:
+ raise TypeError, "invalid arguments"
+
+ self._check_conflict(option)
+
+ self.option_list.append(option)
+ option.container = self
+ for opt in option._short_opts:
+ self._short_opt[opt] = option
+ for opt in option._long_opts:
+ self._long_opt[opt] = option
+
+ if option.dest is not None: # option has a dest, we need a default
+ if option.default is not NO_DEFAULT:
+ self.defaults[option.dest] = option.default
+ elif not self.defaults.has_key(option.dest):
+ self.defaults[option.dest] = None
+
+ def add_options (self, option_list):
+ for option in option_list:
+ self.add_option(option)
+
+ # -- Option query/removal methods ----------------------------------
+
+ def get_option (self, opt_str):
+ return (self._short_opt.get(opt_str) or
+ self._long_opt.get(opt_str))
+
+ def has_option (self, opt_str):
+ return (self._short_opt.has_key(opt_str) or
+ self._long_opt.has_key(opt_str))
+
+ def remove_option (self, opt_str):
+ option = self._short_opt.get(opt_str)
+ if option is None:
+ option = self._long_opt.get(opt_str)
+ if option is None:
+ raise ValueError("no such option %r" % opt_str)
+
+ for opt in option._short_opts:
+ del self._short_opt[opt]
+ for opt in option._long_opts:
+ del self._long_opt[opt]
+ option.container.option_list.remove(option)
+
+
+ # -- Feedback methods ----------------------------------------------
+
+ def get_options(self):
+ if not self.option_list:
+ return ""
+ # The help for each option consists of two parts:
+ # * the opt strings and metavars
+ # eg. ("-x", or "-fFILENAME, --file=FILENAME")
+ # * the user-supplied help string
+ # eg. ("turn on expert mode", "read data from FILENAME")
+ #
+ # If possible, we write both of these on the same line:
+ # -x turn on expert mode
+ #
+ # But if the opt string list is too long, we put the help
+ # string on a second line, indented to the same column it would
+ # start in if it fit on the first line.
+ # -fFILENAME, --file=FILENAME
+ # read data from FILENAME
+ result = [] # list of strings to "".join() later
+ for option in self.option_list:
+ if not option.help is SUPPRESS_HELP:
+ result.append(self.format.format_option(option))
+ return "".join(result)
+
+ def get_description(self):
+ if self.description:
+ return self.format.format_description(self.description)
+ else:
+ return ""
+
+ def get_help(self):
+ result = ""
+ if self.description:
+ result = self.get_description() + "\n"
+ return result + self.get_options()
+
+
+class OptionGroup(OptionContainer):
+
+ def __init__(self, parser, title, description=None):
+ OptionContainer.__init__(self, parser, description)
+ self.parser = parser
+ self.title = title
+ self.description = description
+
+ def set_title(self, title):
+ self.title = title
+
+ def get_help(self):
+ result = self.format.format_heading(self.title)
+ self.format.increase_nesting()
+ result += OptionContainer.get_help(self)
+ self.format.decrease_nesting()
+ return result
+
+
+class Values:
+
+ def __init__ (self, defaults=None):
+ if defaults:
+ for (attr, val) in defaults.items():
+ setattr(self, attr, val)
+
+
+ def _update_careful (self, dict):
+ """
+ Update the option values from an arbitrary dictionary, but only
+ use keys from dict that already have a corresponding attribute
+ in self. Any keys in dict without a corresponding attribute
+ are silently ignored.
+ """
+ for attr in dir(self):
+ if dict.has_key(attr):
+ dval = dict[attr]
+ if dval is not None:
+ setattr(self, attr, dval)
+
+ def _update_loose (self, dict):
+ """
+ Update the option values from an arbitrary dictionary,
+ using all keys from the dictionary regardless of whether
+ they have a corresponding attribute in self or not.
+ """
+ self.__dict__.update(dict)
+
+ def _update (self, dict, mode):
+ if mode == "careful":
+ self._update_careful(dict)
+ elif mode == "loose":
+ self._update_loose(dict)
+ else:
+ raise ValueError, "invalid update mode: %r" % mode
+
+ def read_module (self, modname, mode="careful"):
+ __import__(modname)
+ mod = sys.modules[modname]
+ self._update(vars(mod), mode)
+
+ def read_file (self, filename, mode="careful"):
+ vars = {}
+ execfile(filename, vars)
+ self._update(vars, mode)
+
+ def ensure_value (self, attr, value):
+ if not hasattr(self, attr) or getattr(self, attr) is None:
+ setattr(self, attr, value)
+ return getattr(self, attr)
+
+
+class OptionParser(OptionContainer):
+
+ """
+ Instance attributes:
+ usage : string
+ a usage string for your program. Before it is displayed
+ to the user, "%prog" will be expanded to the name of
+ your program (os.path.basename(sys.argv[0])).
+
+ allow_interspersed_args : boolean = true
+ If true, positional arguments may be interspersed with options.
+ Assuming -a and -b each take a single argument, the command-line
+ -ablah foo bar -bboo baz
+ will be interpreted the same as
+ -ablah -bboo -- foo bar baz
+ If this flag were false, that command line would be interpreted as
+ -ablah -- foo bar -bboo baz
+ -- ie. we stop processing options as soon as we see the first
+ non-option argument. (This is the tradition followed by
+ Python's getopt module, Perl's Getopt::Std, and other argument-
+ parsing libraries, but it is generally annoying to users.)
+
+ rargs : [string]
+ the argument list currently being parsed. Only set when
+ parse_args() is active, and continually trimmed down as
+ we consume arguments. Mainly there for the benefit of
+ callback options.
+ largs : [string]
+ the list of leftover arguments that we have skipped while
+ parsing options. If allow_interspersed_args is false, this
+ list is always empty.
+ values : Values
+ the set of option values currently being accumulated. Only
+ set when parse_args() is active. Also mainly for callbacks.
+
+ Because of the 'rargs', 'largs', and 'values' attributes,
+ OptionParser is not thread-safe. If, for some perverse reason, you
+ need to parse command-line arguments simultaneously in different
+ threads, use different OptionParser instances.
+
+ """
+
+ def __init__ (self,
+ usage=None,
+ description=None,
+ option_list=None,
+ option_class=Option,
+ version=None,
+ help=1,
+ conflict_handler="error",
+ format=None):
+ """Override OptionContainer.__init__."""
+ self.set_usage(usage)
+ self.set_description(description)
+ self.option_class = option_class
+ self.version = version
+ self.set_conflict_handler(conflict_handler)
+ self.allow_interspersed_args = 1
+ if not format:
+ format = Indented()
+ self.format = format
+
+ # Create the various lists and dicts that constitute the
+ # "option list". See class docstring for details about
+ # each attribute.
+ self._create_option_list()
+
+ # Populate the option list; initial sources are the
+ # standard_option_list class attribute, the 'option_list' argument,
+ # and the STD_VERSION_OPTION and STD_HELP_OPTION globals (if 'version'
+ # and/or 'help' supplied).
+ self._populate_option_list(option_list, version=version, help=help)
+
+ self._init_parsing_state()
+
+ # -- Private methods -----------------------------------------------
+ # (used by the constructor)
+
+ def _create_option_list (self):
+ self.option_list = []
+ self.option_groups = []
+ self._short_opt = {} # single letter -> Option instance
+ self._long_opt = {} # long option -> Option instance
+ self.defaults = {} # maps option dest -> default value
+
+ def _init_parsing_state (self):
+ # These are set in parse_args() for the convenience of callbacks.
+ self.rargs = None
+ self.largs = None
+ self.values = None
+
+
+ # -- Simple modifier methods ---------------------------------------
+
+ def set_usage (self, usage):
+ if usage is None:
+ self.usage = "%prog [options]"
+ elif usage is SUPPRESS_USAGE:
+ self.usage = None
+ else:
+ self.usage = usage
+
+ def enable_interspersed_args (self):
+ self.allow_interspersed_args = 1
+
+ def disable_interspersed_args (self):
+ self.allow_interspersed_args = 0
+
+ def set_conflict_handler (self, handler):
+ if handler not in ("ignore", "error", "resolve"):
+ raise ValueError, "invalid conflict_resolution value %r" % handler
+ self.conflict_handler = handler
+
+ def set_default (self, dest, value):
+ self.defaults[dest] = value
+
+ def set_defaults (self, **kwargs):
+ self.defaults.update(kwargs)
+
+ def get_default_values(self):
+ return Values(self.defaults)
+
+
+ # -- OptionGroup methods -------------------------------------------
+
+ def add_option_group(self, group):
+ self.option_groups.append(group)
+
+ def get_option_group(self, opt_str):
+ option = (self._short_opt.get(opt_str) or
+ self._long_opt.get(opt_str))
+ if option and option.container is not self:
+ return option.container
+ return None
+
+
+ # -- Option-parsing methods ----------------------------------------
+
+ def _get_args (self, args):
+ if args is None:
+ return sys.argv[1:]
+ else:
+ return args[:] # don't modify caller's list
+
+ def parse_args (self, args=None, values=None):
+ """
+ parse_args(args : [string] = sys.argv[1:],
+ values : Values = None)
+ -> (values : Values, args : [string])
+
+ Parse the command-line options found in 'args' (default:
+ sys.argv[1:]). Any errors result in a call to 'error()', which
+ by default prints the usage message to stderr and calls
+ sys.exit() with an error message. On success returns a pair
+ (values, args) where 'values' is an Values instance (with all
+ your option values) and 'args' is the list of arguments left
+ over after parsing options.
+ """
+ rargs = self._get_args(args)
+ if values is None:
+ values = self.get_default_values()
+
+ # Store the halves of the argument list as attributes for the
+ # convenience of callbacks:
+ # rargs
+ # the rest of the command-line (the "r" stands for
+ # "remaining" or "right-hand")
+ # largs
+ # the leftover arguments -- ie. what's left after removing
+ # options and their arguments (the "l" stands for "leftover"
+ # or "left-hand")
+ self.rargs = rargs
+ self.largs = largs = []
+ self.values = values
+
+ try:
+ stop = self._process_args(largs, rargs, values)
+ except (BadOptionError, OptionValueError), err:
+ self.error(err.msg)
+
+ args = largs + rargs
+ return self.check_values(values, args)
+
+ def check_values (self, values, args):
+ """
+ check_values(values : Values, args : [string])
+ -> (values : Values, args : [string])
+
+ Check that the supplied option values and leftover arguments are
+ valid. Returns the option values and leftover arguments
+ (possibly adjusted, possibly completely new -- whatever you
+ like). Default implementation just returns the passed-in
+ values; subclasses may override as desired.
+ """
+ return (values, args)
+
+ def _process_args (self, largs, rargs, values):
+ """_process_args(largs : [string],
+ rargs : [string],
+ values : Values)
+
+ Process command-line arguments and populate 'values', consuming
+ options and arguments from 'rargs'. If 'allow_interspersed_args' is
+ false, stop at the first non-option argument. If true, accumulate any
+ interspersed non-option arguments in 'largs'.
+ """
+ while rargs:
+ arg = rargs[0]
+ # We handle bare "--" explicitly, and bare "-" is handled by the
+ # standard arg handler since the short arg case ensures that the
+ # len of the opt string is greater than 1.
+ if arg == "--":
+ del rargs[0]
+ return
+ elif arg[0:2] == "--":
+ # process a single long option (possibly with value(s))
+ self._process_long_opt(rargs, values)
+ elif arg[:1] == "-" and len(arg) > 1:
+ # process a cluster of short options (possibly with
+ # value(s) for the last one only)
+ self._process_short_opts(rargs, values)
+ elif self.allow_interspersed_args:
+ largs.append(arg)
+ del rargs[0]
+ else:
+ return # stop now, leave this arg in rargs
+
+ # Say this is the original argument list:
+ # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
+ # ^
+ # (we are about to process arg(i)).
+ #
+ # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
+ # [arg0, ..., arg(i-1)] (any options and their arguments will have
+ # been removed from largs).
+ #
+ # _process_arg() will usually consume 1 or more arguments.
+ # If it consumes 1 (eg. arg is an option that takes no arguments),
+ # then after _process_arg() is done the situation is:
+ #
+ # largs = subset of [arg0, ..., arg(i)]
+ # rargs = [arg(i+1), ..., arg(N-1)]
+ #
+ # If allow_interspersed_args is false, largs will always be
+ # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
+ # not a very interesting subset!
+
+ def _match_long_opt (self, opt):
+ """_match_long_opt(opt : string) -> string
+
+ Determine which long option string 'opt' matches, ie. which one
+ it is an unambiguous abbrevation for. Raises BadOptionError if
+ 'opt' doesn't unambiguously match any long option string.
+ """
+ return _match_abbrev(opt, self._long_opt)
+
+ def _process_long_opt (self, rargs, values):
+ arg = rargs.pop(0)
+
+ # Value explicitly attached to arg? Pretend it's the next
+ # argument.
+ if "=" in arg:
+ (opt, next_arg) = arg.split("=", 1)
+ rargs.insert(0, next_arg)
+ had_explicit_value = 1
+ else:
+ opt = arg
+ had_explicit_value = 0
+
+ opt = self._match_long_opt(opt)
+ option = self._long_opt[opt]
+ if option.takes_value():
+ nargs = option.nargs
+ if len(rargs) < nargs:
+ if nargs == 1:
+ self.error("%s option requires a value" % opt)
+ else:
+ self.error("%s option requires %d values"
+ % (opt, nargs))
+ elif nargs == 1:
+ value = rargs.pop(0)
+ else:
+ value = tuple(rargs[0:nargs])
+ del rargs[0:nargs]
+
+ elif had_explicit_value:
+ self.error("%s option does not take a value" % opt)
+
+ else:
+ value = None
+
+ option.process(opt, value, values, self)
+
+ def _process_short_opts (self, rargs, values):
+ arg = rargs.pop(0)
+ stop = 0
+ i = 1
+ for ch in arg[1:]:
+ opt = "-" + ch
+ option = self._short_opt.get(opt)
+ i += 1 # we have consumed a character
+
+ if not option:
+ self.error("no such option: %s" % opt)
+ if option.takes_value():
+ # Any characters left in arg? Pretend they're the
+ # next arg, and stop consuming characters of arg.
+ if i < len(arg):
+ rargs.insert(0, arg[i:])
+ stop = 1
+
+ nargs = option.nargs
+ if len(rargs) < nargs:
+ if nargs == 1:
+ self.error("%s option requires a value" % opt)
+ else:
+ self.error("%s option requires %s values"
+ % (opt, nargs))
+ elif nargs == 1:
+ value = rargs.pop(0)
+ else:
+ value = tuple(rargs[0:nargs])
+ del rargs[0:nargs]
+
+ else: # option doesn't take a value
+ value = None
+
+ option.process(opt, value, values, self)
+
+ if stop:
+ break
+
+
+ # -- Feedback methods ----------------------------------------------
+
+ def error (self, msg):
+ """error(msg : string)
+
+ Print a usage message incorporating 'msg' to stderr and exit.
+ If you override this in a subclass, it should not return -- it
+ should either exit or raise an exception.
+ """
+ self.print_usage(sys.stderr)
+ sys.exit("%s: error: %s" % (get_prog_name(), msg))
+
+ def get_usage(self):
+ if self.usage:
+ return self.format.format_usage(
+ self.usage.replace("%prog", get_prog_name()))
+ else:
+ return ""
+
+ def print_usage (self, file=None):
+ """print_usage(file : file = stdout)
+
+ Print the usage message for the current program (self.usage) to
+ 'file' (default stdout). Any occurence of the string "%prog" in
+ self.usage is replaced with the name of the current program
+ (basename of sys.argv[0]). Does nothing if self.usage is empty
+ or not defined.
+ """
+ if self.usage:
+ print >>file, self.get_usage()
+
+ def get_version(self):
+ if self.version:
+ return self.version.replace("%prog", get_prog_name())
+ else:
+ return ""
+
+ def print_version (self, file=None):
+ """print_version(file : file = stdout)
+
+ Print the version message for this program (self.version) to
+ 'file' (default stdout). As with print_usage(), any occurence
+ of "%prog" in self.version is replaced by the current program's
+ name. Does nothing if self.version is empty or undefined.
+ """
+ if self.version:
+ print >>file, self.get_version()
+
+ def get_options(self):
+ result = []
+ result.append(self.format.format_heading("Options"))
+ self.format.increase_nesting()
+ if self.option_list:
+ result.append(OptionContainer.get_options(self))
+ result.append("\n")
+ for group in self.option_groups:
+ result.append(group.get_help())
+ result.append("\n")
+ self.format.decrease_nesting()
+ # Drop the last "\n", or the header if no options or option groups:
+ return "".join(result[:-1])
+
+ def get_help(self):
+ result = []
+ if self.usage:
+ result.append(self.get_usage() + "\n")
+ if self.description:
+ result.append(self.get_description() + "\n")
+ #if self.option_list or self.option_groups:
+ result.append(self.get_options())
+ return "".join(result)
+
+ def print_help (self, file=None):
+ """print_help(file : file = stdout)
+
+ Print an extended help message, listing all options and any
+ help text provided with them, to 'file' (default stdout).
+ """
+ if file is None:
+ file = sys.stdout
+ file.write(self.get_help())
+
+# class OptionParser
+
+
+class HelpFormat:
+
+ """
+ "--help" output format; abstract base class (Strategy).
+ """
+
+ def __init__(self, indent_increment, help_indent, width, short_first):
+ self.current_indent = 0
+ self.level = 0
+ self.indent_increment = indent_increment
+ self.help_indent = help_indent
+ self.width = width
+ self.help_width = self.width - self.help_indent
+ if short_first:
+ self.format_option_list = self.format_option_list_short_first
+ else:
+ self.format_option_list = self.format_option_list_long_first
+
+ def increase_nesting(self):
+ self.current_indent += self.indent_increment
+ self.level += 1
+
+ def decrease_nesting(self):
+ self.current_indent -= self.indent_increment
+ assert self.current_indent >= 0, "Indent decreased below 0."
+ self.level -= 1
+
+ def format_usage(self, usage):
+ raise NotImplementedError
+
+ def format_heading(self, heading):
+ raise NotImplementedError
+
+ def format_description(self, description):
+ desc_width = self.width - self.current_indent
+ desc_lines = wrap_text(description, desc_width)
+ result = ["%*s%s\n" % (self.current_indent, "", line)
+ for line in desc_lines]
+ return "".join(result)
+
+ def format_option(self, option):
+ result = []
+ opts = self.format_option_list(option)
+ opt_width = self.help_indent - self.current_indent - 2
+ if len(opts) > opt_width:
+ opts = "%*s%s\n" % (self.current_indent, "", opts)
+ indent_first = self.help_indent
+ else: # start help on same line as opts
+ opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts)
+ indent_first = 0
+ result.append(opts)
+ if option.help:
+ help_lines = wrap_text(option.help, self.help_width)
+ result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
+ result.extend(["%*s%s\n" % (self.help_indent, "", line)
+ for line in help_lines[1:]])
+ elif opts[-1] != "\n":
+ result.append("\n")
+ return "".join(result)
+
+ def format_option_list(self, option):
+ """Return a comma-separated list of option strigs & metavariables."""
+ raise NotImplementedError(
+ "Virtual method; use format_option_list_short_first or "
+ "format_option_list_long_first instead.")
+
+ def format_option_list_short_first(self, option):
+ opts = [] # list of "-a" or "--foo=FILE" strings
+ takes_value = option.takes_value()
+ if takes_value:
+ metavar = option.metavar or option.dest.upper()
+ for sopt in option._short_opts:
+ opts.append(sopt + metavar)
+ for lopt in option._long_opts:
+ opts.append(lopt + "=" + metavar)
+ else:
+ for opt in option._short_opts + option._long_opts:
+ opts.append(opt)
+ return ", ".join(opts)
+
+ def format_option_list_long_first(self, option):
+ opts = [] # list of "-a" or "--foo=FILE" strings
+ takes_value = option.takes_value()
+ if takes_value:
+ metavar = option.metavar or option.dest.upper()
+ for lopt in option._long_opts:
+ opts.append(lopt + "=" + metavar)
+ for sopt in option._short_opts:
+ opts.append(sopt + metavar)
+ else:
+ for opt in option._long_opts + option._short_opts:
+ opts.append(opt)
+ return ", ".join(opts)
+
+
+class Indented(HelpFormat):
+
+ def __init__(self, indent_increment=2, help_indent=24, width=78,
+ short_first=1):
+ HelpFormat.__init__(self, indent_increment, help_indent, width,
+ short_first)
+
+ def format_usage(self, usage):
+ return "Usage: %s\n" % usage
+
+ def format_heading(self, heading):
+ return "%*s%s:\n" % (self.current_indent, "", heading)
+
+
+class Titled(HelpFormat):
+
+ def __init__(self, indent_increment=0, help_indent=24, width=78,
+ short_first=None):
+ HelpFormat.__init__(self, indent_increment, help_indent, width,
+ short_first)
+
+ def format_usage(self, usage):
+ return "%s %s\n" % (self.format_heading("Usage"), usage)
+
+ def format_heading(self, heading):
+ return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading))
+
+
+def _match_abbrev (s, wordmap):
+ """_match_abbrev(s : string, wordmap : {string : Option}) -> string
+
+ Returns the string key in 'wordmap' for which 's' is an unambiguous
+ abbreviation. If 's' is found to be ambiguous or doesn't match any of
+ 'words', raises BadOptionError.
+ """
+ # Is there an exact match?
+ if wordmap.has_key(s):
+ return s
+ else:
+ # Isolate all words with s as a prefix.
+ possibilities = [word for word in wordmap.keys()
+ if word.startswith(s)]
+ # No exact match, so there had better be just one possibility.
+ if len(possibilities) == 1:
+ return possibilities[0]
+ elif not possibilities:
+ raise BadOptionError("no such option: %s" % s)
+ else:
+ # More than one possible completion: ambiguous prefix.
+ raise BadOptionError("ambiguous option: %s (%s?)"
+ % (s, ", ".join(possibilities)))
+
+def get_prog_name ():
+ return os.path.basename(sys.argv[0])
--
cgit v1.2.1
From 6453bd44f1c452379e81c537adfca225fb6ce65d Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 13 Jun 2002 03:30:45 +0000
Subject: Combined from the Optik package, with no modifications. This module
will probably eventually take over from optik.py.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@182 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/OptionParser.py | 1087 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1087 insertions(+)
create mode 100644 docutils/OptionParser.py
(limited to 'docutils')
diff --git a/docutils/OptionParser.py b/docutils/OptionParser.py
new file mode 100644
index 000000000..d0e4ab899
--- /dev/null
+++ b/docutils/OptionParser.py
@@ -0,0 +1,1087 @@
+"""optik
+
+A powerful, extensible, and easy-to-use command-line parser for Python.
+
+By Greg Ward
+
+See http://optik.sourceforge.net/
+"""
+
+# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
+# See the README.txt distributed with Optik for licensing terms.
+
+# This combined module created 2002-06-12 by David Goodger,
+# from the optik package.
+
+__revision__ = "$Id$"
+
+__version__ = "1.3"
+
+
+import sys
+import os
+import types
+from types import TupleType, DictType
+from distutils.fancy_getopt import wrap_text
+
+
+SUPPRESS_HELP = "SUPPRESS"+"HELP"
+SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
+# Not supplying a default is different from a default of None,
+# so we need an explicit "not supplied" value.
+NO_DEFAULT = "NO"+"DEFAULT"
+
+
+class OptikError (Exception):
+ def __init__ (self, msg):
+ self.msg = msg
+
+ def __str__ (self):
+ return self.msg
+
+
+class OptionError (OptikError):
+ """
+ Raised if an Option instance is created with invalid or
+ inconsistent arguments.
+ """
+
+ def __init__ (self, msg, option):
+ self.msg = msg
+ self.option_id = str(option)
+
+ def __str__ (self):
+ if self.option_id:
+ return "option %s: %s" % (self.option_id, self.msg)
+ else:
+ return self.msg
+
+class OptionConflictError (OptionError):
+ """
+ Raised if conflicting options are added to an OptionParser.
+ """
+
+class OptionValueError (OptikError):
+ """
+ Raised if an invalid option value is encountered on the command
+ line.
+ """
+
+class BadOptionError (OptikError):
+ """
+ Raised if an invalid or ambiguous option is seen on the command-line.
+ """
+
+
+_builtin_cvt = { "int" : (int, "integer"),
+ "long" : (long, "long integer"),
+ "float" : (float, "floating-point"),
+ "complex" : (complex, "complex") }
+
+def check_builtin (option, opt, value):
+ (cvt, what) = _builtin_cvt[option.type]
+ try:
+ return cvt(value)
+ except ValueError:
+ raise OptionValueError(
+ #"%s: invalid %s argument %r" % (opt, what, value))
+ "option %s: invalid %s value: %r" % (opt, what, value))
+
+
+class Option:
+ """
+ Instance attributes:
+ _short_opts : [string]
+ _long_opts : [string]
+
+ action : string
+ type : string
+ dest : string
+ default : any
+ nargs : int
+ const : any
+ callback : function
+ callback_args : (any*)
+ callback_kwargs : { string : any }
+ help : string
+ metavar : string
+ """
+
+ # The list of instance attributes that may be set through
+ # keyword args to the constructor.
+ ATTRS = ['action',
+ 'type',
+ 'dest',
+ 'default',
+ 'nargs',
+ 'const',
+ 'callback',
+ 'callback_args',
+ 'callback_kwargs',
+ 'help',
+ 'metavar']
+
+ # The set of actions allowed by option parsers. Explicitly listed
+ # here so the constructor can validate its arguments.
+ ACTIONS = ("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "count",
+ "callback",
+ "help",
+ "version")
+
+ # The set of actions that involve storing a value somewhere;
+ # also listed just for constructor argument validation. (If
+ # the action is one of these, there must be a destination.)
+ STORE_ACTIONS = ("store",
+ "store_const",
+ "store_true",
+ "store_false",
+ "append",
+ "count")
+
+ # The set of actions for which it makes sense to supply a value
+ # type, ie. where we expect an argument to this option.
+ TYPED_ACTIONS = ("store",
+ "append",
+ "callback")
+
+ # The set of known types for option parsers. Again, listed here for
+ # constructor argument validation.
+ TYPES = ("string", "int", "long", "float", "complex")
+
+ # Dictionary of argument checking functions, which convert and
+ # validate option arguments according to the option type.
+ #
+ # Signature of checking functions is:
+ # check(option : Option, opt : string, value : string) -> any
+ # where
+ # option is the Option instance calling the checker
+ # opt is the actual option seen on the command-line
+ # (eg. "-a", "--file")
+ # value is the option argument seen on the command-line
+ #
+ # The return value should be in the appropriate Python type
+ # for option.type -- eg. an integer if option.type == "int".
+ #
+ # If no checker is defined for a type, arguments will be
+ # unchecked and remain strings.
+ TYPE_CHECKER = { "int" : check_builtin,
+ "long" : check_builtin,
+ "float" : check_builtin,
+ "complex" : check_builtin,
+ }
+
+
+ # CHECK_METHODS is a list of unbound method objects; they are called
+ # by the constructor, in order, after all attributes are
+ # initialized. The list is created and filled in later, after all
+ # the methods are actually defined. (I just put it here because I
+ # like to define and document all class attributes in the same
+ # place.) Subclasses that add another _check_*() method should
+ # define their own CHECK_METHODS list that adds their check method
+ # to those from this class.
+ CHECK_METHODS = None
+
+
+ # -- Constructor/initialization methods ----------------------------
+
+ def __init__ (self, *opts, **attrs):
+ # Set _short_opts, _long_opts attrs from 'opts' tuple
+ opts = self._check_opt_strings(opts)
+ self._set_opt_strings(opts)
+
+ # Set all other attrs (action, type, etc.) from 'attrs' dict
+ self._set_attrs(attrs)
+
+ # Check all the attributes we just set. There are lots of
+ # complicated interdependencies, but luckily they can be farmed
+ # out to the _check_*() methods listed in CHECK_METHODS -- which
+ # could be handy for subclasses! The one thing these all share
+ # is that they raise OptionError if they discover a problem.
+ for checker in self.CHECK_METHODS:
+ checker(self)
+
+ def _check_opt_strings (self, opts):
+ # Filter out None because early versions of Optik had exactly
+ # one short option and one long option, either of which
+ # could be None.
+ opts = filter(None, opts)
+ if not opts:
+ raise OptionError("at least one option string must be supplied",
+ self)
+ return opts
+
+ def _set_opt_strings (self, opts):
+ self._short_opts = []
+ self._long_opts = []
+ for opt in opts:
+ if len(opt) < 2:
+ raise OptionError(
+ "invalid option string %r: "
+ "must be at least two characters long" % opt, self)
+ elif len(opt) == 2:
+ if not (opt[0] == "-" and opt[1] != "-"):
+ raise OptionError(
+ "invalid short option string %r: "
+ "must be of the form -x, (x any non-dash char)" % opt,
+ self)
+ self._short_opts.append(opt)
+ else:
+ if not (opt[0:2] == "--" and opt[2] != "-"):
+ raise OptionError(
+ "invalid long option string %r: "
+ "must start with --, followed by non-dash" % opt,
+ self)
+ self._long_opts.append(opt)
+
+ def _set_attrs (self, attrs):
+ for attr in self.ATTRS:
+ if attrs.has_key(attr):
+ setattr(self, attr, attrs[attr])
+ del attrs[attr]
+ else:
+ if attr == 'default':
+ setattr(self, attr, NO_DEFAULT)
+ else:
+ setattr(self, attr, None)
+ if attrs:
+ raise OptionError(
+ "invalid keyword arguments: %s" % ", ".join(attrs.keys()),
+ self)
+
+
+ # -- Constructor validation methods --------------------------------
+
+ def _check_action (self):
+ if self.action is None:
+ self.action = "store"
+ elif self.action not in self.ACTIONS:
+ raise OptionError("invalid action: %r" % self.action, self)
+
+ def _check_type (self):
+ if self.type is None:
+ # XXX should factor out another class attr here: list of
+ # actions that *require* a type
+ if self.action in ("store", "append"):
+ # No type given? "string" is the most sensible default.
+ self.type = "string"
+ else:
+ if self.type not in self.TYPES:
+ raise OptionError("invalid option type: %r" % self.type, self)
+ if self.action not in self.TYPED_ACTIONS:
+ raise OptionError(
+ "must not supply a type for action %r" % self.action, self)
+
+ def _check_dest (self):
+ if self.action in self.STORE_ACTIONS and self.dest is None:
+ # No destination given, and we need one for this action.
+ # Glean a destination from the first long option string,
+ # or from the first short option string if no long options.
+ if self._long_opts:
+ # eg. "--foo-bar" -> "foo_bar"
+ self.dest = self._long_opts[0][2:].replace('-', '_')
+ else:
+ self.dest = self._short_opts[0][1]
+
+ def _check_const (self):
+ if self.action != "store_const" and self.const is not None:
+ raise OptionError(
+ "'const' must not be supplied for action %r" % self.action,
+ self)
+
+ def _check_nargs (self):
+ if self.action in self.TYPED_ACTIONS:
+ if self.nargs is None:
+ self.nargs = 1
+ elif self.nargs is not None:
+ raise OptionError(
+ "'nargs' must not be supplied for action %r" % self.action,
+ self)
+
+ def _check_callback (self):
+ if self.action == "callback":
+ if not callable(self.callback):
+ raise OptionError(
+ "callback not callable: %r" % self.callback, self)
+ if (self.callback_args is not None and
+ type(self.callback_args) is not TupleType):
+ raise OptionError(
+ "callback_args, if supplied, must be a tuple: not %r"
+ % self.callback_args, self)
+ if (self.callback_kwargs is not None and
+ type(self.callback_kwargs) is not DictType):
+ raise OptionError(
+ "callback_kwargs, if supplied, must be a dict: not %r"
+ % self.callback_kwargs, self)
+ else:
+ if self.callback is not None:
+ raise OptionError(
+ "callback supplied (%r) for non-callback option"
+ % self.callback, self)
+ if self.callback_args is not None:
+ raise OptionError(
+ "callback_args supplied for non-callback option", self)
+ if self.callback_kwargs is not None:
+ raise OptionError(
+ "callback_kwargs supplied for non-callback option", self)
+
+
+ CHECK_METHODS = [_check_action,
+ _check_type,
+ _check_dest,
+ _check_const,
+ _check_nargs,
+ _check_callback]
+
+
+ # -- Miscellaneous methods -----------------------------------------
+
+ def __str__ (self):
+ if self._short_opts or self._long_opts:
+ return "/".join(self._short_opts + self._long_opts)
+ else:
+ raise RuntimeError, "short_opts and long_opts both empty!"
+
+ def takes_value (self):
+ return self.type is not None
+
+
+ # -- Processing methods --------------------------------------------
+
+ def check_value (self, opt, value):
+ checker = self.TYPE_CHECKER.get(self.type)
+ if checker is None:
+ return value
+ else:
+ return checker(self, opt, value)
+
+ def process (self, opt, value, values, parser):
+
+ # First, convert the value(s) to the right type. Howl if any
+ # value(s) are bogus.
+ if value is not None:
+ if self.nargs == 1:
+ value = self.check_value(opt, value)
+ else:
+ value = tuple([self.check_value(opt, v) for v in value])
+
+ # And then take whatever action is expected of us.
+ # This is a separate method to make life easier for
+ # subclasses to add new actions.
+ return self.take_action(
+ self.action, self.dest, opt, value, values, parser)
+
+ def take_action (self, action, dest, opt, value, values, parser):
+ if action == "store":
+ setattr(values, dest, value)
+ elif action == "store_const":
+ setattr(values, dest, self.const)
+ elif action == "store_true":
+ setattr(values, dest, 1)
+ elif action == "store_false":
+ setattr(values, dest, 0)
+ elif action == "append":
+ values.ensure_value(dest, []).append(value)
+ elif action == "count":
+ setattr(values, dest, values.ensure_value(dest, 0) + 1)
+ elif action == "callback":
+ args = self.callback_args or ()
+ kwargs = self.callback_kwargs or {}
+ self.callback(self, opt, value, parser, *args, **kwargs)
+ elif action == "help":
+ parser.print_help()
+ sys.exit(0)
+ elif action == "version":
+ parser.print_version()
+ sys.exit(0)
+ else:
+ raise RuntimeError, "unknown action %r" % self.action
+
+ return 1
+
+# class Option
+
+
+# Some day, there might be many Option classes. As of Optik 1.3, the
+# preferred way to instantiate Options is indirectly, via make_option(),
+# which will become a factory function when there are many Option
+# classes.
+make_option = Option
+
+
+STD_HELP_OPTION = Option("-h", "--help",
+ action="help",
+ help="show this help message and exit")
+STD_VERSION_OPTION = Option("--version",
+ action="version",
+ help="show program's version number and exit")
+
+
+class Values:
+
+ def __init__ (self, defaults=None):
+ if defaults:
+ for (attr, val) in defaults.items():
+ setattr(self, attr, val)
+
+
+ def _update_careful (self, dict):
+ """
+ Update the option values from an arbitrary dictionary, but only
+ use keys from dict that already have a corresponding attribute
+ in self. Any keys in dict without a corresponding attribute
+ are silently ignored.
+ """
+ for attr in dir(self):
+ if dict.has_key(attr):
+ dval = dict[attr]
+ if dval is not None:
+ setattr(self, attr, dval)
+
+ def _update_loose (self, dict):
+ """
+ Update the option values from an arbitrary dictionary,
+ using all keys from the dictionary regardless of whether
+ they have a corresponding attribute in self or not.
+ """
+ self.__dict__.update(dict)
+
+ def _update (self, dict, mode):
+ if mode == "careful":
+ self._update_careful(dict)
+ elif mode == "loose":
+ self._update_loose(dict)
+ else:
+ raise ValueError, "invalid update mode: %r" % mode
+
+ def read_module (self, modname, mode="careful"):
+ __import__(modname)
+ mod = sys.modules[modname]
+ self._update(vars(mod), mode)
+
+ def read_file (self, filename, mode="careful"):
+ vars = {}
+ execfile(filename, vars)
+ self._update(vars, mode)
+
+ def ensure_value (self, attr, value):
+ if not hasattr(self, attr) or getattr(self, attr) is None:
+ setattr(self, attr, value)
+ return getattr(self, attr)
+
+
+class OptionParser:
+ """
+ Class attributes:
+ standard_option_list : [Option]
+ list of standard options that will be accepted by all instances
+ of this parser class (intended to be overridden by subclasses).
+
+ Instance attributes:
+ usage : string
+ a usage string for your program. Before it is displayed
+ to the user, "%prog" will be expanded to the name of
+ your program (os.path.basename(sys.argv[0])).
+ option_list : [Option]
+ the list of all options accepted on the command-line of
+ this program
+ _short_opt : { string : Option }
+ dictionary mapping short option strings, eg. "-f" or "-X",
+ to the Option instances that implement them. If an Option
+ has multiple short option strings, it will appears in this
+ dictionary multiple times.
+ _long_opt : { string : Option }
+ dictionary mapping long option strings, eg. "--file" or
+ "--exclude", to the Option instances that implement them.
+ Again, a given Option can occur multiple times in this
+ dictionary.
+ _long_opts : [string]
+ list of long option strings recognized by this option
+ parser. Should be equal to _long_opt.keys().
+ defaults : { string : any }
+ dictionary mapping option destination names to default
+ values for each destination.
+
+ allow_interspersed_args : boolean = true
+ if true, positional arguments may be interspersed with options.
+ Assuming -a and -b each take a single argument, the command-line
+ -ablah foo bar -bboo baz
+ will be interpreted the same as
+ -ablah -bboo -- foo bar baz
+ If this flag were false, that command line would be interpreted as
+ -ablah -- foo bar -bboo baz
+ -- ie. we stop processing options as soon as we see the first
+ non-option argument. (This is the tradition followed by
+ Python's getopt module, Perl's Getopt::Std, and other argument-
+ parsing libraries, but it is generally annoying to users.)
+
+ rargs : [string]
+ the argument list currently being parsed. Only set when
+ parse_args() is active, and continually trimmed down as
+ we consume arguments. Mainly there for the benefit of
+ callback options.
+ largs : [string]
+ the list of leftover arguments that we have skipped while
+ parsing options. If allow_interspersed_args is false, this
+ list is always empty.
+ values : Values
+ the set of option values currently being accumulated. Only
+ set when parse_args() is active. Also mainly for callbacks.
+
+ Because of the 'rargs', 'largs', and 'values' attributes,
+ OptionParser is not thread-safe. If, for some perverse reason, you
+ need to parse command-line arguments simultaneously in different
+ threads, use different OptionParser instances.
+
+ """
+
+ standard_option_list = [STD_HELP_OPTION]
+
+
+ def __init__ (self,
+ usage=None,
+ option_list=None,
+ option_class=Option,
+ version=None,
+ conflict_handler="error"):
+ self.set_usage(usage)
+ self.option_class = option_class
+ self.version = version
+ self.set_conflict_handler(conflict_handler)
+ self.allow_interspersed_args = 1
+
+ # Create the various lists and dicts that constitute the
+ # "option list". See class docstring for details about
+ # each attribute.
+ self._create_option_list()
+
+ # Populate the option list; initial sources are the
+ # standard_option_list class attribute, the 'option_list'
+ # argument, and the STD_VERSION_OPTION global (if 'version'
+ # supplied).
+ self._populate_option_list(option_list)
+
+ self._init_parsing_state()
+
+ # -- Private methods -----------------------------------------------
+ # (used by the constructor)
+
+ def _create_option_list (self):
+ self.option_list = []
+ self._short_opt = {} # single letter -> Option instance
+ self._long_opt = {} # long option -> Option instance
+ self._long_opts = [] # list of long options
+ self.defaults = {} # maps option dest -> default value
+
+ def _populate_option_list (self, option_list):
+ if self.standard_option_list:
+ self.add_options(self.standard_option_list)
+ if self.version:
+ self.add_option(STD_VERSION_OPTION)
+ if option_list:
+ self.add_options(option_list)
+
+ def _init_parsing_state (self):
+ # These are set in parse_args() for the convenience of callbacks.
+ self.rargs = None
+ self.largs = None
+ self.values = None
+
+
+ # -- Simple modifier methods ---------------------------------------
+
+ def set_usage (self, usage):
+ if usage is None:
+ self.usage = "usage: %prog [options]"
+ elif usage is SUPPRESS_USAGE:
+ self.usage = None
+ else:
+ self.usage = usage
+
+ def enable_interspersed_args (self):
+ self.allow_interspersed_args = 1
+
+ def disable_interspersed_args (self):
+ self.allow_interspersed_args = 0
+
+ def set_conflict_handler (self, handler):
+ if handler not in ("ignore", "error", "resolve"):
+ raise ValueError, "invalid conflict_resolution value %r" % handler
+ self.conflict_handler = handler
+
+ def set_default (self, dest, value):
+ self.defaults[dest] = value
+
+ def set_defaults (self, **kwargs):
+ self.defaults.update(kwargs)
+
+ def get_default_values(self):
+ return Values(self.defaults)
+
+
+ # -- Option-adding methods -----------------------------------------
+
+ def _check_conflict (self, option):
+ conflict_opts = []
+ for opt in option._short_opts:
+ if self._short_opt.has_key(opt):
+ conflict_opts.append((opt, self._short_opt[opt]))
+ for opt in option._long_opts:
+ if self._long_opt.has_key(opt):
+ conflict_opts.append((opt, self._long_opt[opt]))
+
+ if conflict_opts:
+ handler = self.conflict_handler
+ if handler == "ignore": # behaviour for Optik 1.0, 1.1
+ pass
+ elif handler == "error": # new in 1.2
+ raise OptionConflictError(
+ "conflicting option string(s): %s"
+ % ", ".join([co[0] for co in conflict_opts]),
+ option)
+ elif handler == "resolve": # new in 1.2
+ for (opt, c_option) in conflict_opts:
+ if opt.startswith("--"):
+ c_option._long_opts.remove(opt)
+ del self._long_opt[opt]
+ else:
+ c_option._short_opts.remove(opt)
+ del self._short_opt[opt]
+ if not (c_option._short_opts or c_option._long_opts):
+ self.option_list.remove(c_option)
+
+
+ def add_option (self, *args, **kwargs):
+ """add_option(Option)
+ add_option(opt_str, ..., kwarg=val, ...)
+ """
+ if type(args[0]) is types.StringType:
+ option = self.option_class(*args, **kwargs)
+ elif len(args) == 1 and not kwargs:
+ option = args[0]
+ if not isinstance(option, Option):
+ raise TypeError, "not an Option instance: %r" % option
+ else:
+ raise TypeError, "invalid arguments"
+
+ self._check_conflict(option)
+
+ self.option_list.append(option)
+ for opt in option._short_opts:
+ self._short_opt[opt] = option
+ for opt in option._long_opts:
+ self._long_opt[opt] = option
+ self._long_opts.append(opt)
+
+ if option.dest is not None: # option has a dest, we need a default
+ if option.default is not NO_DEFAULT:
+ self.defaults[option.dest] = option.default
+ elif not self.defaults.has_key(option.dest):
+ self.defaults[option.dest] = None
+
+ def add_options (self, option_list):
+ for option in option_list:
+ self.add_option(option)
+
+
+ # -- Option query/removal methods ----------------------------------
+
+ def get_option (self, opt_str):
+ return (self._short_opt.get(opt_str) or
+ self._long_opt.get(opt_str))
+
+ def has_option (self, opt_str):
+ return (self._short_opt.has_key(opt_str) or
+ self._long_opt.has_key(opt_str))
+
+
+ def remove_option (self, opt_str):
+ option = self._short_opt.get(opt_str)
+ if option is None:
+ option = self._long_opt.get(opt_str)
+ if option is None:
+ raise ValueError("no such option %r" % opt_str)
+
+ for opt in option._short_opts:
+ del self._short_opt[opt]
+ for opt in option._long_opts:
+ del self._long_opt[opt]
+ self._long_opts.remove(opt)
+ self.option_list.remove(option)
+
+
+ # -- Option-parsing methods ----------------------------------------
+
+ def _get_args (self, args):
+ if args is None:
+ return sys.argv[1:]
+ else:
+ return args[:] # don't modify caller's list
+
+ def parse_args (self, args=None, values=None):
+ """
+ parse_args(args : [string] = sys.argv[1:],
+ values : Values = None)
+ -> (values : Values, args : [string])
+
+ Parse the command-line options found in 'args' (default:
+ sys.argv[1:]). Any errors result in a call to 'error()', which
+ by default prints the usage message to stderr and calls
+ sys.exit() with an error message. On success returns a pair
+ (values, args) where 'values' is an Values instance (with all
+ your option values) and 'args' is the list of arguments left
+ over after parsing options.
+ """
+ rargs = self._get_args(args)
+ if values is None:
+ values = self.get_default_values()
+
+ # Store the halves of the argument list as attributes for the
+ # convenience of callbacks:
+ # rargs
+ # the rest of the command-line (the "r" stands for
+ # "remaining" or "right-hand")
+ # largs
+ # the leftover arguments -- ie. what's left after removing
+ # options and their arguments (the "l" stands for "leftover"
+ # or "left-hand")
+
+ # Say this is the original argument list:
+ # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
+ # ^
+ # (we are about to process arg(i)).
+ #
+ # Then rargs is [arg(i), ..., arg(N-1)]
+ # and largs is a *subset* of [arg0, ..., arg(i-1)]
+ # (any options and their arguments will have been removed
+ # from largs).
+ #
+ # _process_arg() will always consume 1 or more arguments.
+ # If it consumes 1 (eg. arg is an option that takes no arguments),
+ # then after _process_arg() is done the situation is:
+ # largs = subset of [arg0, ..., arg(i)]
+ # rargs = [arg(i+1), ..., arg(N-1)]
+ #
+ # If allow_interspersed_args is false, largs will always be
+ # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
+ # not a very interesting subset!
+
+ self.rargs = rargs
+ self.largs = largs = []
+ self.values = values
+
+ stop = 0
+ while rargs and not stop:
+ try:
+ stop = self._process_arg(largs, rargs, values)
+ except (BadOptionError, OptionValueError), err:
+ self.error(err.msg)
+
+ args = largs + rargs
+ return self.check_values(values, args)
+
+ def check_values (self, values, args):
+ """
+ check_values(values : Values, args : [string])
+ -> (values : Values, args : [string])
+
+ Check that the supplied option values and leftover arguments are
+ valid. Returns the option values and leftover arguments
+ (possibly adjusted, possibly completely new -- whatever you
+ like). Default implementation just returns the passed-in
+ values; subclasses may override as desired.
+ """
+ return (values, args)
+
+ def _process_arg (self, largs, rargs, values):
+ """_process_args(largs : [string],
+ rargs : [string],
+ values : Values)
+ -> stop : boolean
+
+ Process a single command-line argument, consuming zero or more
+ arguments. The next argument to process is rargs[0], which will
+ almost certainly be consumed from rargs. (It might wind up in
+ largs, or it might affect a value in values, or -- if a callback
+ is involved -- almost anything might happen. It will not be
+ consumed if it is a non-option argument and
+ allow_interspersed_args is false.) More arguments from rargs
+ may also be consumed, depending on circumstances.
+
+ Returns true if option processing should stop after this
+ argument is processed.
+ """
+
+ # We handle bare "--" explicitly, and bare "-" is handled by the
+ # standard arg handler since the short arg case ensures that the len
+ # of the opt string is greater than 1.
+
+ arg = rargs[0]
+ if arg == "--":
+ del rargs[0]
+ return 1
+ elif arg[0:2] == "--":
+ # process a single long option (possibly with value(s))
+ self._process_long_opt(rargs, values)
+ elif arg[:1] == "-" and len(arg) > 1:
+ # process a cluster of short options (possibly with
+ # value(s) for the last one only)
+ self._process_short_opts(rargs, values)
+ else:
+ if self.allow_interspersed_args:
+ largs.append(arg)
+ del rargs[0]
+ else:
+ return 1 # stop now, leave this arg in rargs
+
+ return 0 # keep processing args
+
+ def _match_long_opt (self, opt):
+ """_match_long_opt(opt : string) -> string
+
+ Determine which long option string 'opt' matches, ie. which one
+ it is an unambiguous abbrevation for. Raises BadOptionError if
+ 'opt' doesn't unambiguously match any long option string.
+ """
+ return _match_abbrev(opt, self._long_opts)
+
+ def _process_long_opt (self, rargs, values):
+ arg = rargs.pop(0)
+
+ # Value explicitly attached to arg? Pretend it's the next
+ # argument.
+ if "=" in arg:
+ (opt, next_arg) = arg.split("=", 1)
+ rargs.insert(0, next_arg)
+ had_explicit_value = 1
+ else:
+ opt = arg
+ had_explicit_value = 0
+
+ opt = self._match_long_opt(opt)
+ option = self._long_opt[opt]
+ if option.takes_value():
+ nargs = option.nargs
+ if len(rargs) < nargs:
+ if nargs == 1:
+ self.error("%s option requires a value" % opt)
+ else:
+ self.error("%s option requires %d values"
+ % (opt, nargs))
+ elif nargs == 1:
+ value = rargs.pop(0)
+ else:
+ value = tuple(rargs[0:nargs])
+ del rargs[0:nargs]
+
+ elif had_explicit_value:
+ self.error("%s option does not take a value" % opt)
+
+ else:
+ value = None
+
+ option.process(opt, value, values, self)
+
+ def _process_short_opts (self, rargs, values):
+ arg = rargs.pop(0)
+ stop = 0
+ i = 1
+ for ch in arg[1:]:
+ opt = "-" + ch
+ option = self._short_opt.get(opt)
+ i += 1 # we have consumed a character
+
+ if not option:
+ self.error("no such option: %s" % opt)
+ if option.takes_value():
+ # Any characters left in arg? Pretend they're the
+ # next arg, and stop consuming characters of arg.
+ if i < len(arg):
+ rargs.insert(0, arg[i:])
+ stop = 1
+
+ nargs = option.nargs
+ if len(rargs) < nargs:
+ if nargs == 1:
+ self.error("%s option requires a value" % opt)
+ else:
+ self.error("%s option requires %s values"
+ % (opt, nargs))
+ elif nargs == 1:
+ value = rargs.pop(0)
+ else:
+ value = tuple(rargs[0:nargs])
+ del rargs[0:nargs]
+
+ else: # option doesn't take a value
+ value = None
+
+ option.process(opt, value, values, self)
+
+ if stop:
+ break
+
+
+ # -- Output/error methods ------------------------------------------
+
+ def error (self, msg):
+ """error(msg : string)
+
+ Print a usage message incorporating 'msg' to stderr and exit.
+ If you override this in a subclass, it should not return -- it
+ should either exit or raise an exception.
+ """
+ self.print_usage(sys.stderr)
+ sys.exit("%s: error: %s" % (get_prog_name(), msg))
+
+ def print_usage (self, file=None):
+ """print_usage(file : file = stdout)
+
+ Print the usage message for the current program (self.usage) to
+ 'file' (default stdout). Any occurence of the string "%prog" in
+ self.usage is replaced with the name of the current program
+ (basename of sys.argv[0]). Does nothing if self.usage is empty
+ or not defined.
+ """
+ if self.usage:
+ usage = self.usage.replace("%prog", get_prog_name())
+ print >>file, usage
+ print >>file
+
+ def print_version (self, file=None):
+ """print_version(file : file = stdout)
+
+ Print the version message for this program (self.version) to
+ 'file' (default stdout). As with print_usage(), any occurence
+ of "%prog" in self.version is replaced by the current program's
+ name. Does nothing if self.version is empty or undefined.
+ """
+ if self.version:
+ version = self.version.replace("%prog", get_prog_name())
+ print >>file, version
+
+ def print_help (self, file=None):
+ """print_help(file : file = stdout)
+
+ Print an extended help message, listing all options and any
+ help text provided with them, to 'file' (default stdout).
+ """
+ from distutils.fancy_getopt import wrap_text
+
+ if file is None:
+ file = sys.stdout
+
+ self.print_usage(file)
+
+ # The help for each option consists of two parts:
+ # * the opt strings and metavars
+ # eg. ("-x", or "-fFILENAME, --file=FILENAME")
+ # * the user-supplied help string
+ # eg. ("turn on expert mode", "read data from FILENAME")
+ #
+ # If possible, we write both of these on the same line:
+ # -x turn on expert mode
+ #
+ # But if the opt string list is too long, we put the help
+ # string on a second line, indented to the same column it would
+ # start in if it fit on the first line.
+ # -fFILENAME, --file=FILENAME
+ # read data from FILENAME
+
+ print >>file, "options:"
+ width = 78 # assume 80 cols for now
+
+ option_help = [] # list of (string, string) tuples
+ lengths = []
+
+ for option in self.option_list:
+ takes_value = option.takes_value()
+ if takes_value:
+ metavar = option.metavar or option.dest.upper()
+
+ opts = [] # list of "-a" or "--foo=FILE" strings
+ if option.help is SUPPRESS_HELP:
+ continue
+
+ if takes_value:
+ for sopt in option._short_opts:
+ opts.append(sopt + metavar)
+ for lopt in option._long_opts:
+ opts.append(lopt + "=" + metavar)
+ else:
+ for opt in option._short_opts + option._long_opts:
+ opts.append(opt)
+
+ opts = ", ".join(opts)
+ option_help.append((opts, option.help))
+ lengths.append(len(opts))
+
+ max_opts = min(max(lengths), 20)
+
+ for (opts, help) in option_help:
+ # how much to indent lines 2 .. N of help text
+ indent_rest = 2 + max_opts + 2
+ help_width = width - indent_rest
+
+ if len(opts) > max_opts:
+ opts = " " + opts + "\n"
+ indent_first = indent_rest
+
+ else: # start help on same line as opts
+ opts = " %-*s " % (max_opts, opts)
+ indent_first = 0
+
+ file.write(opts)
+
+ if help:
+ help_lines = wrap_text(help, help_width)
+ print >>file, "%*s%s" % (indent_first, "", help_lines[0])
+ for line in help_lines[1:]:
+ print >>file, "%*s%s" % (indent_rest, "", line)
+ elif opts[-1] != "\n":
+ file.write("\n")
+
+# class OptionParser
+
+
+def _match_abbrev (s, words):
+ """_match_abbrev(s : string, words : [string]) -> string
+
+ Returns the string in 'words' for which 's' is an unambiguous
+ abbreviation. If 's' is found to be ambiguous or doesn't match any
+ of 'words', raises BadOptionError.
+ """
+ match = None
+ for word in words:
+ # If s isn't even a prefix for this word, don't waste any
+ # more time on it: skip to the next word and try again.
+ if not word.startswith(s):
+ continue
+
+ # Exact match? Great, return now.
+ if s == word:
+ return word
+
+ # Now comes the tricky business of disambiguation. At this
+ # point, we know s is a proper prefix of word, eg. s='--foo' and
+ # word=='--foobar'. If we have already seen another word where
+ # this was the case, eg. '--foobaz', fail: s is ambiguous.
+ # Otherwise record this match and keep looping; we will return
+ # if we see an exact match, or when we fall out of the loop and
+ # it turns out that the current word is the match.
+ if match:
+ raise BadOptionError("ambiguous option: %s (%s, %s, ...?)"
+ % (s, match, word))
+ match = word
+
+ if match:
+ return match
+ else:
+ raise BadOptionError("no such option: %s" % s)
+
+def get_prog_name ():
+ return os.path.basename(sys.argv[0])
--
cgit v1.2.1
From 8950f53d00b5c27c494af1207b6e5ecf859bef78 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 13 Jun 2002 03:33:06 +0000
Subject: Updated for new Optik option group functionality.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@183 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 60570a914..bebc0a369 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -31,8 +31,11 @@ class Writer(writers.Writer):
"""Formats this writer supports."""
cmdline_options = (
- ('Specify a stylesheet file. Default is "default.css".',
- ['--stylesheet'], {'default': 'default.css', 'metavar': ''}),)
+ 'HTML-Specific Options',
+ None,
+ (('Specify a stylesheet file. Default is "default.css".',
+ ['--stylesheet'],
+ {'default': 'default.css', 'metavar': ''}),),)
output = None
"""Final translated form of `document`."""
--
cgit v1.2.1
From 13da103589ae4085005670489808aaff76d54145 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 13 Jun 2002 22:31:33 +0000
Subject: Docstrings, comments, minor edits, whitespace.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@186 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/optik.py | 69 ++++++++++++++++++++++++++++++++++---------------------
1 file changed, 43 insertions(+), 26 deletions(-)
(limited to 'docutils')
diff --git a/docutils/optik.py b/docutils/optik.py
index 6feebabb4..9faedd699 100644
--- a/docutils/optik.py
+++ b/docutils/optik.py
@@ -17,22 +17,22 @@ See http://optik.sourceforge.net/
"""
# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
-#
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
-#
+#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
-#
+#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
-#
+#
# * Neither the name of the author nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
-#
+#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
@@ -608,20 +608,6 @@ class OptionContainer:
def get_options(self):
if not self.option_list:
return ""
- # The help for each option consists of two parts:
- # * the opt strings and metavars
- # eg. ("-x", or "-fFILENAME, --file=FILENAME")
- # * the user-supplied help string
- # eg. ("turn on expert mode", "read data from FILENAME")
- #
- # If possible, we write both of these on the same line:
- # -x turn on expert mode
- #
- # But if the opt string list is too long, we put the help
- # string on a second line, indented to the same column it would
- # start in if it fit on the first line.
- # -fFILENAME, --file=FILENAME
- # read data from FILENAME
result = [] # list of strings to "".join() later
for option in self.option_list:
if not option.help is SUPPRESS_HELP:
@@ -1114,7 +1100,6 @@ class OptionParser(OptionContainer):
result.append(self.get_usage() + "\n")
if self.description:
result.append(self.get_description() + "\n")
- #if self.option_list or self.option_groups:
result.append(self.get_options())
return "".join(result)
@@ -1134,15 +1119,29 @@ class OptionParser(OptionContainer):
class HelpFormat:
"""
- "--help" output format; abstract base class (Strategy).
+ "--help" output format; abstract base class (Strategy design pattern).
+
+ Instance attributes:
+ indent_increment : int
+ number of columns to indent per nesting level
+ help_indent : int
+ the starting column for option help text
+ width : int
+ the overall width (in columns) for output
+ current_indent : int
+ in columns, calculated
+ level : int
+ increased for each additional nesting level
+ help_width : int
+ number of columns available for option help text
"""
def __init__(self, indent_increment, help_indent, width, short_first):
- self.current_indent = 0
- self.level = 0
self.indent_increment = indent_increment
self.help_indent = help_indent
self.width = width
+ self.current_indent = 0
+ self.level = 0
self.help_width = self.width - self.help_indent
if short_first:
self.format_option_list = self.format_option_list_short_first
@@ -1152,7 +1151,7 @@ class HelpFormat:
def increase_nesting(self):
self.current_indent += self.indent_increment
self.level += 1
-
+
def decrease_nesting(self):
self.current_indent -= self.indent_increment
assert self.current_indent >= 0, "Indent decreased below 0."
@@ -1172,6 +1171,20 @@ class HelpFormat:
return "".join(result)
def format_option(self, option):
+ # The help for each option consists of two parts:
+ # * the opt strings and metavars
+ # eg. ("-x", or "-fFILENAME, --file=FILENAME")
+ # * the user-supplied help string
+ # eg. ("turn on expert mode", "read data from FILENAME")
+ #
+ # If possible, we write both of these on the same line:
+ # -x turn on expert mode
+ #
+ # But if the opt string list is too long, we put the help
+ # string on a second line, indented to the same column it would
+ # start in if it fit on the first line.
+ # -fFILENAME, --file=FILENAME
+ # read data from FILENAME
result = []
opts = self.format_option_list(option)
opt_width = self.help_indent - self.current_indent - 2
@@ -1228,6 +1241,8 @@ class HelpFormat:
class Indented(HelpFormat):
+ """Formats help with indented section bodies."""
+
def __init__(self, indent_increment=2, help_indent=24, width=78,
short_first=1):
HelpFormat.__init__(self, indent_increment, help_indent, width,
@@ -1242,6 +1257,8 @@ class Indented(HelpFormat):
class Titled(HelpFormat):
+ """Formats help with underlined section headers."""
+
def __init__(self, indent_increment=0, help_indent=24, width=78,
short_first=None):
HelpFormat.__init__(self, indent_increment, help_indent, width,
@@ -1257,9 +1274,9 @@ class Titled(HelpFormat):
def _match_abbrev (s, wordmap):
"""_match_abbrev(s : string, wordmap : {string : Option}) -> string
- Returns the string key in 'wordmap' for which 's' is an unambiguous
+ Return the string key in 'wordmap' for which 's' is an unambiguous
abbreviation. If 's' is found to be ambiguous or doesn't match any of
- 'words', raises BadOptionError.
+ 'words', raise BadOptionError.
"""
# Is there an exact match?
if wordmap.has_key(s):
--
cgit v1.2.1
From c68e44ec4f2b29042e1ea2ae425ed982c00162c6 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 13 Jun 2002 22:32:07 +0000
Subject: minor
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@187 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 01b0ed489..275137a9c 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -23,7 +23,7 @@ class OptionParser(optik.OptionParser):
"""
cmdline_options = (
- 'General Options',
+ 'General Docutils Options',
None,
(('Include a "Generated by Docutils" credit with a link, at the end '
'of the document.',
@@ -93,7 +93,8 @@ class OptionParser(optik.OptionParser):
def __init__(self, components=(), defaults={}, *args, **kwargs):
"""
`components` is a list of Docutils components each containing a
- ``.cmdline_options`` attribute. `defaults` is a
+ ``.cmdline_options`` attribute. `defaults` is a mapping of option
+ default overrides.
"""
optik.OptionParser.__init__(self, help=None, format=optik.Titled(),
*args, **kwargs)
--
cgit v1.2.1
From ae57b4ceca35d1f06037284f4089684604a48e26 Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 14 Jun 2002 23:09:10 +0000
Subject: comment
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@191 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/optik.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/optik.py b/docutils/optik.py
index 9faedd699..16a927aec 100644
--- a/docutils/optik.py
+++ b/docutils/optik.py
@@ -935,7 +935,7 @@ class OptionParser(OptionContainer):
# [arg0, ..., arg(i-1)] (any options and their arguments will have
# been removed from largs).
#
- # _process_arg() will usually consume 1 or more arguments.
+ # The while loop will usually consume 1 or more arguments per pass.
# If it consumes 1 (eg. arg is an option that takes no arguments),
# then after _process_arg() is done the situation is:
#
--
cgit v1.2.1
From 7f675ec43766d8805ba70f87064e330912f90ec3 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 19 Jun 2002 02:54:38 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@197 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index bebc0a369..380179651 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -502,6 +502,8 @@ class HTMLTranslator(nodes.NodeVisitor):
self.depart_admonition()
def visit_interpreted(self, node):
+ # @@@ Incomplete, pending a proper implementation on the
+ # Parser/Reader end.
self.body.append('')
def depart_interpreted(self, node):
@@ -684,10 +686,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('')
def visit_substitution_definition(self, node):
- raise nodes.SkipChildren
-
- def depart_substitution_definition(self, node):
- pass
+ raise nodes.SkipNode
def visit_substitution_reference(self, node):
self.unimplemented_visit(node)
--
cgit v1.2.1
From ab7c4bbb0085e8cdc6fc716a3294294308de21a1 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 20 Jun 2002 03:52:42 +0000
Subject: not happening, not yet
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@198 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/OptionParser.py | 1087 ----------------------------------------------
1 file changed, 1087 deletions(-)
delete mode 100644 docutils/OptionParser.py
(limited to 'docutils')
diff --git a/docutils/OptionParser.py b/docutils/OptionParser.py
deleted file mode 100644
index d0e4ab899..000000000
--- a/docutils/OptionParser.py
+++ /dev/null
@@ -1,1087 +0,0 @@
-"""optik
-
-A powerful, extensible, and easy-to-use command-line parser for Python.
-
-By Greg Ward
-
-See http://optik.sourceforge.net/
-"""
-
-# Copyright (c) 2001 Gregory P. Ward. All rights reserved.
-# See the README.txt distributed with Optik for licensing terms.
-
-# This combined module created 2002-06-12 by David Goodger,
-# from the optik package.
-
-__revision__ = "$Id$"
-
-__version__ = "1.3"
-
-
-import sys
-import os
-import types
-from types import TupleType, DictType
-from distutils.fancy_getopt import wrap_text
-
-
-SUPPRESS_HELP = "SUPPRESS"+"HELP"
-SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
-# Not supplying a default is different from a default of None,
-# so we need an explicit "not supplied" value.
-NO_DEFAULT = "NO"+"DEFAULT"
-
-
-class OptikError (Exception):
- def __init__ (self, msg):
- self.msg = msg
-
- def __str__ (self):
- return self.msg
-
-
-class OptionError (OptikError):
- """
- Raised if an Option instance is created with invalid or
- inconsistent arguments.
- """
-
- def __init__ (self, msg, option):
- self.msg = msg
- self.option_id = str(option)
-
- def __str__ (self):
- if self.option_id:
- return "option %s: %s" % (self.option_id, self.msg)
- else:
- return self.msg
-
-class OptionConflictError (OptionError):
- """
- Raised if conflicting options are added to an OptionParser.
- """
-
-class OptionValueError (OptikError):
- """
- Raised if an invalid option value is encountered on the command
- line.
- """
-
-class BadOptionError (OptikError):
- """
- Raised if an invalid or ambiguous option is seen on the command-line.
- """
-
-
-_builtin_cvt = { "int" : (int, "integer"),
- "long" : (long, "long integer"),
- "float" : (float, "floating-point"),
- "complex" : (complex, "complex") }
-
-def check_builtin (option, opt, value):
- (cvt, what) = _builtin_cvt[option.type]
- try:
- return cvt(value)
- except ValueError:
- raise OptionValueError(
- #"%s: invalid %s argument %r" % (opt, what, value))
- "option %s: invalid %s value: %r" % (opt, what, value))
-
-
-class Option:
- """
- Instance attributes:
- _short_opts : [string]
- _long_opts : [string]
-
- action : string
- type : string
- dest : string
- default : any
- nargs : int
- const : any
- callback : function
- callback_args : (any*)
- callback_kwargs : { string : any }
- help : string
- metavar : string
- """
-
- # The list of instance attributes that may be set through
- # keyword args to the constructor.
- ATTRS = ['action',
- 'type',
- 'dest',
- 'default',
- 'nargs',
- 'const',
- 'callback',
- 'callback_args',
- 'callback_kwargs',
- 'help',
- 'metavar']
-
- # The set of actions allowed by option parsers. Explicitly listed
- # here so the constructor can validate its arguments.
- ACTIONS = ("store",
- "store_const",
- "store_true",
- "store_false",
- "append",
- "count",
- "callback",
- "help",
- "version")
-
- # The set of actions that involve storing a value somewhere;
- # also listed just for constructor argument validation. (If
- # the action is one of these, there must be a destination.)
- STORE_ACTIONS = ("store",
- "store_const",
- "store_true",
- "store_false",
- "append",
- "count")
-
- # The set of actions for which it makes sense to supply a value
- # type, ie. where we expect an argument to this option.
- TYPED_ACTIONS = ("store",
- "append",
- "callback")
-
- # The set of known types for option parsers. Again, listed here for
- # constructor argument validation.
- TYPES = ("string", "int", "long", "float", "complex")
-
- # Dictionary of argument checking functions, which convert and
- # validate option arguments according to the option type.
- #
- # Signature of checking functions is:
- # check(option : Option, opt : string, value : string) -> any
- # where
- # option is the Option instance calling the checker
- # opt is the actual option seen on the command-line
- # (eg. "-a", "--file")
- # value is the option argument seen on the command-line
- #
- # The return value should be in the appropriate Python type
- # for option.type -- eg. an integer if option.type == "int".
- #
- # If no checker is defined for a type, arguments will be
- # unchecked and remain strings.
- TYPE_CHECKER = { "int" : check_builtin,
- "long" : check_builtin,
- "float" : check_builtin,
- "complex" : check_builtin,
- }
-
-
- # CHECK_METHODS is a list of unbound method objects; they are called
- # by the constructor, in order, after all attributes are
- # initialized. The list is created and filled in later, after all
- # the methods are actually defined. (I just put it here because I
- # like to define and document all class attributes in the same
- # place.) Subclasses that add another _check_*() method should
- # define their own CHECK_METHODS list that adds their check method
- # to those from this class.
- CHECK_METHODS = None
-
-
- # -- Constructor/initialization methods ----------------------------
-
- def __init__ (self, *opts, **attrs):
- # Set _short_opts, _long_opts attrs from 'opts' tuple
- opts = self._check_opt_strings(opts)
- self._set_opt_strings(opts)
-
- # Set all other attrs (action, type, etc.) from 'attrs' dict
- self._set_attrs(attrs)
-
- # Check all the attributes we just set. There are lots of
- # complicated interdependencies, but luckily they can be farmed
- # out to the _check_*() methods listed in CHECK_METHODS -- which
- # could be handy for subclasses! The one thing these all share
- # is that they raise OptionError if they discover a problem.
- for checker in self.CHECK_METHODS:
- checker(self)
-
- def _check_opt_strings (self, opts):
- # Filter out None because early versions of Optik had exactly
- # one short option and one long option, either of which
- # could be None.
- opts = filter(None, opts)
- if not opts:
- raise OptionError("at least one option string must be supplied",
- self)
- return opts
-
- def _set_opt_strings (self, opts):
- self._short_opts = []
- self._long_opts = []
- for opt in opts:
- if len(opt) < 2:
- raise OptionError(
- "invalid option string %r: "
- "must be at least two characters long" % opt, self)
- elif len(opt) == 2:
- if not (opt[0] == "-" and opt[1] != "-"):
- raise OptionError(
- "invalid short option string %r: "
- "must be of the form -x, (x any non-dash char)" % opt,
- self)
- self._short_opts.append(opt)
- else:
- if not (opt[0:2] == "--" and opt[2] != "-"):
- raise OptionError(
- "invalid long option string %r: "
- "must start with --, followed by non-dash" % opt,
- self)
- self._long_opts.append(opt)
-
- def _set_attrs (self, attrs):
- for attr in self.ATTRS:
- if attrs.has_key(attr):
- setattr(self, attr, attrs[attr])
- del attrs[attr]
- else:
- if attr == 'default':
- setattr(self, attr, NO_DEFAULT)
- else:
- setattr(self, attr, None)
- if attrs:
- raise OptionError(
- "invalid keyword arguments: %s" % ", ".join(attrs.keys()),
- self)
-
-
- # -- Constructor validation methods --------------------------------
-
- def _check_action (self):
- if self.action is None:
- self.action = "store"
- elif self.action not in self.ACTIONS:
- raise OptionError("invalid action: %r" % self.action, self)
-
- def _check_type (self):
- if self.type is None:
- # XXX should factor out another class attr here: list of
- # actions that *require* a type
- if self.action in ("store", "append"):
- # No type given? "string" is the most sensible default.
- self.type = "string"
- else:
- if self.type not in self.TYPES:
- raise OptionError("invalid option type: %r" % self.type, self)
- if self.action not in self.TYPED_ACTIONS:
- raise OptionError(
- "must not supply a type for action %r" % self.action, self)
-
- def _check_dest (self):
- if self.action in self.STORE_ACTIONS and self.dest is None:
- # No destination given, and we need one for this action.
- # Glean a destination from the first long option string,
- # or from the first short option string if no long options.
- if self._long_opts:
- # eg. "--foo-bar" -> "foo_bar"
- self.dest = self._long_opts[0][2:].replace('-', '_')
- else:
- self.dest = self._short_opts[0][1]
-
- def _check_const (self):
- if self.action != "store_const" and self.const is not None:
- raise OptionError(
- "'const' must not be supplied for action %r" % self.action,
- self)
-
- def _check_nargs (self):
- if self.action in self.TYPED_ACTIONS:
- if self.nargs is None:
- self.nargs = 1
- elif self.nargs is not None:
- raise OptionError(
- "'nargs' must not be supplied for action %r" % self.action,
- self)
-
- def _check_callback (self):
- if self.action == "callback":
- if not callable(self.callback):
- raise OptionError(
- "callback not callable: %r" % self.callback, self)
- if (self.callback_args is not None and
- type(self.callback_args) is not TupleType):
- raise OptionError(
- "callback_args, if supplied, must be a tuple: not %r"
- % self.callback_args, self)
- if (self.callback_kwargs is not None and
- type(self.callback_kwargs) is not DictType):
- raise OptionError(
- "callback_kwargs, if supplied, must be a dict: not %r"
- % self.callback_kwargs, self)
- else:
- if self.callback is not None:
- raise OptionError(
- "callback supplied (%r) for non-callback option"
- % self.callback, self)
- if self.callback_args is not None:
- raise OptionError(
- "callback_args supplied for non-callback option", self)
- if self.callback_kwargs is not None:
- raise OptionError(
- "callback_kwargs supplied for non-callback option", self)
-
-
- CHECK_METHODS = [_check_action,
- _check_type,
- _check_dest,
- _check_const,
- _check_nargs,
- _check_callback]
-
-
- # -- Miscellaneous methods -----------------------------------------
-
- def __str__ (self):
- if self._short_opts or self._long_opts:
- return "/".join(self._short_opts + self._long_opts)
- else:
- raise RuntimeError, "short_opts and long_opts both empty!"
-
- def takes_value (self):
- return self.type is not None
-
-
- # -- Processing methods --------------------------------------------
-
- def check_value (self, opt, value):
- checker = self.TYPE_CHECKER.get(self.type)
- if checker is None:
- return value
- else:
- return checker(self, opt, value)
-
- def process (self, opt, value, values, parser):
-
- # First, convert the value(s) to the right type. Howl if any
- # value(s) are bogus.
- if value is not None:
- if self.nargs == 1:
- value = self.check_value(opt, value)
- else:
- value = tuple([self.check_value(opt, v) for v in value])
-
- # And then take whatever action is expected of us.
- # This is a separate method to make life easier for
- # subclasses to add new actions.
- return self.take_action(
- self.action, self.dest, opt, value, values, parser)
-
- def take_action (self, action, dest, opt, value, values, parser):
- if action == "store":
- setattr(values, dest, value)
- elif action == "store_const":
- setattr(values, dest, self.const)
- elif action == "store_true":
- setattr(values, dest, 1)
- elif action == "store_false":
- setattr(values, dest, 0)
- elif action == "append":
- values.ensure_value(dest, []).append(value)
- elif action == "count":
- setattr(values, dest, values.ensure_value(dest, 0) + 1)
- elif action == "callback":
- args = self.callback_args or ()
- kwargs = self.callback_kwargs or {}
- self.callback(self, opt, value, parser, *args, **kwargs)
- elif action == "help":
- parser.print_help()
- sys.exit(0)
- elif action == "version":
- parser.print_version()
- sys.exit(0)
- else:
- raise RuntimeError, "unknown action %r" % self.action
-
- return 1
-
-# class Option
-
-
-# Some day, there might be many Option classes. As of Optik 1.3, the
-# preferred way to instantiate Options is indirectly, via make_option(),
-# which will become a factory function when there are many Option
-# classes.
-make_option = Option
-
-
-STD_HELP_OPTION = Option("-h", "--help",
- action="help",
- help="show this help message and exit")
-STD_VERSION_OPTION = Option("--version",
- action="version",
- help="show program's version number and exit")
-
-
-class Values:
-
- def __init__ (self, defaults=None):
- if defaults:
- for (attr, val) in defaults.items():
- setattr(self, attr, val)
-
-
- def _update_careful (self, dict):
- """
- Update the option values from an arbitrary dictionary, but only
- use keys from dict that already have a corresponding attribute
- in self. Any keys in dict without a corresponding attribute
- are silently ignored.
- """
- for attr in dir(self):
- if dict.has_key(attr):
- dval = dict[attr]
- if dval is not None:
- setattr(self, attr, dval)
-
- def _update_loose (self, dict):
- """
- Update the option values from an arbitrary dictionary,
- using all keys from the dictionary regardless of whether
- they have a corresponding attribute in self or not.
- """
- self.__dict__.update(dict)
-
- def _update (self, dict, mode):
- if mode == "careful":
- self._update_careful(dict)
- elif mode == "loose":
- self._update_loose(dict)
- else:
- raise ValueError, "invalid update mode: %r" % mode
-
- def read_module (self, modname, mode="careful"):
- __import__(modname)
- mod = sys.modules[modname]
- self._update(vars(mod), mode)
-
- def read_file (self, filename, mode="careful"):
- vars = {}
- execfile(filename, vars)
- self._update(vars, mode)
-
- def ensure_value (self, attr, value):
- if not hasattr(self, attr) or getattr(self, attr) is None:
- setattr(self, attr, value)
- return getattr(self, attr)
-
-
-class OptionParser:
- """
- Class attributes:
- standard_option_list : [Option]
- list of standard options that will be accepted by all instances
- of this parser class (intended to be overridden by subclasses).
-
- Instance attributes:
- usage : string
- a usage string for your program. Before it is displayed
- to the user, "%prog" will be expanded to the name of
- your program (os.path.basename(sys.argv[0])).
- option_list : [Option]
- the list of all options accepted on the command-line of
- this program
- _short_opt : { string : Option }
- dictionary mapping short option strings, eg. "-f" or "-X",
- to the Option instances that implement them. If an Option
- has multiple short option strings, it will appears in this
- dictionary multiple times.
- _long_opt : { string : Option }
- dictionary mapping long option strings, eg. "--file" or
- "--exclude", to the Option instances that implement them.
- Again, a given Option can occur multiple times in this
- dictionary.
- _long_opts : [string]
- list of long option strings recognized by this option
- parser. Should be equal to _long_opt.keys().
- defaults : { string : any }
- dictionary mapping option destination names to default
- values for each destination.
-
- allow_interspersed_args : boolean = true
- if true, positional arguments may be interspersed with options.
- Assuming -a and -b each take a single argument, the command-line
- -ablah foo bar -bboo baz
- will be interpreted the same as
- -ablah -bboo -- foo bar baz
- If this flag were false, that command line would be interpreted as
- -ablah -- foo bar -bboo baz
- -- ie. we stop processing options as soon as we see the first
- non-option argument. (This is the tradition followed by
- Python's getopt module, Perl's Getopt::Std, and other argument-
- parsing libraries, but it is generally annoying to users.)
-
- rargs : [string]
- the argument list currently being parsed. Only set when
- parse_args() is active, and continually trimmed down as
- we consume arguments. Mainly there for the benefit of
- callback options.
- largs : [string]
- the list of leftover arguments that we have skipped while
- parsing options. If allow_interspersed_args is false, this
- list is always empty.
- values : Values
- the set of option values currently being accumulated. Only
- set when parse_args() is active. Also mainly for callbacks.
-
- Because of the 'rargs', 'largs', and 'values' attributes,
- OptionParser is not thread-safe. If, for some perverse reason, you
- need to parse command-line arguments simultaneously in different
- threads, use different OptionParser instances.
-
- """
-
- standard_option_list = [STD_HELP_OPTION]
-
-
- def __init__ (self,
- usage=None,
- option_list=None,
- option_class=Option,
- version=None,
- conflict_handler="error"):
- self.set_usage(usage)
- self.option_class = option_class
- self.version = version
- self.set_conflict_handler(conflict_handler)
- self.allow_interspersed_args = 1
-
- # Create the various lists and dicts that constitute the
- # "option list". See class docstring for details about
- # each attribute.
- self._create_option_list()
-
- # Populate the option list; initial sources are the
- # standard_option_list class attribute, the 'option_list'
- # argument, and the STD_VERSION_OPTION global (if 'version'
- # supplied).
- self._populate_option_list(option_list)
-
- self._init_parsing_state()
-
- # -- Private methods -----------------------------------------------
- # (used by the constructor)
-
- def _create_option_list (self):
- self.option_list = []
- self._short_opt = {} # single letter -> Option instance
- self._long_opt = {} # long option -> Option instance
- self._long_opts = [] # list of long options
- self.defaults = {} # maps option dest -> default value
-
- def _populate_option_list (self, option_list):
- if self.standard_option_list:
- self.add_options(self.standard_option_list)
- if self.version:
- self.add_option(STD_VERSION_OPTION)
- if option_list:
- self.add_options(option_list)
-
- def _init_parsing_state (self):
- # These are set in parse_args() for the convenience of callbacks.
- self.rargs = None
- self.largs = None
- self.values = None
-
-
- # -- Simple modifier methods ---------------------------------------
-
- def set_usage (self, usage):
- if usage is None:
- self.usage = "usage: %prog [options]"
- elif usage is SUPPRESS_USAGE:
- self.usage = None
- else:
- self.usage = usage
-
- def enable_interspersed_args (self):
- self.allow_interspersed_args = 1
-
- def disable_interspersed_args (self):
- self.allow_interspersed_args = 0
-
- def set_conflict_handler (self, handler):
- if handler not in ("ignore", "error", "resolve"):
- raise ValueError, "invalid conflict_resolution value %r" % handler
- self.conflict_handler = handler
-
- def set_default (self, dest, value):
- self.defaults[dest] = value
-
- def set_defaults (self, **kwargs):
- self.defaults.update(kwargs)
-
- def get_default_values(self):
- return Values(self.defaults)
-
-
- # -- Option-adding methods -----------------------------------------
-
- def _check_conflict (self, option):
- conflict_opts = []
- for opt in option._short_opts:
- if self._short_opt.has_key(opt):
- conflict_opts.append((opt, self._short_opt[opt]))
- for opt in option._long_opts:
- if self._long_opt.has_key(opt):
- conflict_opts.append((opt, self._long_opt[opt]))
-
- if conflict_opts:
- handler = self.conflict_handler
- if handler == "ignore": # behaviour for Optik 1.0, 1.1
- pass
- elif handler == "error": # new in 1.2
- raise OptionConflictError(
- "conflicting option string(s): %s"
- % ", ".join([co[0] for co in conflict_opts]),
- option)
- elif handler == "resolve": # new in 1.2
- for (opt, c_option) in conflict_opts:
- if opt.startswith("--"):
- c_option._long_opts.remove(opt)
- del self._long_opt[opt]
- else:
- c_option._short_opts.remove(opt)
- del self._short_opt[opt]
- if not (c_option._short_opts or c_option._long_opts):
- self.option_list.remove(c_option)
-
-
- def add_option (self, *args, **kwargs):
- """add_option(Option)
- add_option(opt_str, ..., kwarg=val, ...)
- """
- if type(args[0]) is types.StringType:
- option = self.option_class(*args, **kwargs)
- elif len(args) == 1 and not kwargs:
- option = args[0]
- if not isinstance(option, Option):
- raise TypeError, "not an Option instance: %r" % option
- else:
- raise TypeError, "invalid arguments"
-
- self._check_conflict(option)
-
- self.option_list.append(option)
- for opt in option._short_opts:
- self._short_opt[opt] = option
- for opt in option._long_opts:
- self._long_opt[opt] = option
- self._long_opts.append(opt)
-
- if option.dest is not None: # option has a dest, we need a default
- if option.default is not NO_DEFAULT:
- self.defaults[option.dest] = option.default
- elif not self.defaults.has_key(option.dest):
- self.defaults[option.dest] = None
-
- def add_options (self, option_list):
- for option in option_list:
- self.add_option(option)
-
-
- # -- Option query/removal methods ----------------------------------
-
- def get_option (self, opt_str):
- return (self._short_opt.get(opt_str) or
- self._long_opt.get(opt_str))
-
- def has_option (self, opt_str):
- return (self._short_opt.has_key(opt_str) or
- self._long_opt.has_key(opt_str))
-
-
- def remove_option (self, opt_str):
- option = self._short_opt.get(opt_str)
- if option is None:
- option = self._long_opt.get(opt_str)
- if option is None:
- raise ValueError("no such option %r" % opt_str)
-
- for opt in option._short_opts:
- del self._short_opt[opt]
- for opt in option._long_opts:
- del self._long_opt[opt]
- self._long_opts.remove(opt)
- self.option_list.remove(option)
-
-
- # -- Option-parsing methods ----------------------------------------
-
- def _get_args (self, args):
- if args is None:
- return sys.argv[1:]
- else:
- return args[:] # don't modify caller's list
-
- def parse_args (self, args=None, values=None):
- """
- parse_args(args : [string] = sys.argv[1:],
- values : Values = None)
- -> (values : Values, args : [string])
-
- Parse the command-line options found in 'args' (default:
- sys.argv[1:]). Any errors result in a call to 'error()', which
- by default prints the usage message to stderr and calls
- sys.exit() with an error message. On success returns a pair
- (values, args) where 'values' is an Values instance (with all
- your option values) and 'args' is the list of arguments left
- over after parsing options.
- """
- rargs = self._get_args(args)
- if values is None:
- values = self.get_default_values()
-
- # Store the halves of the argument list as attributes for the
- # convenience of callbacks:
- # rargs
- # the rest of the command-line (the "r" stands for
- # "remaining" or "right-hand")
- # largs
- # the leftover arguments -- ie. what's left after removing
- # options and their arguments (the "l" stands for "leftover"
- # or "left-hand")
-
- # Say this is the original argument list:
- # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
- # ^
- # (we are about to process arg(i)).
- #
- # Then rargs is [arg(i), ..., arg(N-1)]
- # and largs is a *subset* of [arg0, ..., arg(i-1)]
- # (any options and their arguments will have been removed
- # from largs).
- #
- # _process_arg() will always consume 1 or more arguments.
- # If it consumes 1 (eg. arg is an option that takes no arguments),
- # then after _process_arg() is done the situation is:
- # largs = subset of [arg0, ..., arg(i)]
- # rargs = [arg(i+1), ..., arg(N-1)]
- #
- # If allow_interspersed_args is false, largs will always be
- # *empty* -- still a subset of [arg0, ..., arg(i-1)], but
- # not a very interesting subset!
-
- self.rargs = rargs
- self.largs = largs = []
- self.values = values
-
- stop = 0
- while rargs and not stop:
- try:
- stop = self._process_arg(largs, rargs, values)
- except (BadOptionError, OptionValueError), err:
- self.error(err.msg)
-
- args = largs + rargs
- return self.check_values(values, args)
-
- def check_values (self, values, args):
- """
- check_values(values : Values, args : [string])
- -> (values : Values, args : [string])
-
- Check that the supplied option values and leftover arguments are
- valid. Returns the option values and leftover arguments
- (possibly adjusted, possibly completely new -- whatever you
- like). Default implementation just returns the passed-in
- values; subclasses may override as desired.
- """
- return (values, args)
-
- def _process_arg (self, largs, rargs, values):
- """_process_args(largs : [string],
- rargs : [string],
- values : Values)
- -> stop : boolean
-
- Process a single command-line argument, consuming zero or more
- arguments. The next argument to process is rargs[0], which will
- almost certainly be consumed from rargs. (It might wind up in
- largs, or it might affect a value in values, or -- if a callback
- is involved -- almost anything might happen. It will not be
- consumed if it is a non-option argument and
- allow_interspersed_args is false.) More arguments from rargs
- may also be consumed, depending on circumstances.
-
- Returns true if option processing should stop after this
- argument is processed.
- """
-
- # We handle bare "--" explicitly, and bare "-" is handled by the
- # standard arg handler since the short arg case ensures that the len
- # of the opt string is greater than 1.
-
- arg = rargs[0]
- if arg == "--":
- del rargs[0]
- return 1
- elif arg[0:2] == "--":
- # process a single long option (possibly with value(s))
- self._process_long_opt(rargs, values)
- elif arg[:1] == "-" and len(arg) > 1:
- # process a cluster of short options (possibly with
- # value(s) for the last one only)
- self._process_short_opts(rargs, values)
- else:
- if self.allow_interspersed_args:
- largs.append(arg)
- del rargs[0]
- else:
- return 1 # stop now, leave this arg in rargs
-
- return 0 # keep processing args
-
- def _match_long_opt (self, opt):
- """_match_long_opt(opt : string) -> string
-
- Determine which long option string 'opt' matches, ie. which one
- it is an unambiguous abbrevation for. Raises BadOptionError if
- 'opt' doesn't unambiguously match any long option string.
- """
- return _match_abbrev(opt, self._long_opts)
-
- def _process_long_opt (self, rargs, values):
- arg = rargs.pop(0)
-
- # Value explicitly attached to arg? Pretend it's the next
- # argument.
- if "=" in arg:
- (opt, next_arg) = arg.split("=", 1)
- rargs.insert(0, next_arg)
- had_explicit_value = 1
- else:
- opt = arg
- had_explicit_value = 0
-
- opt = self._match_long_opt(opt)
- option = self._long_opt[opt]
- if option.takes_value():
- nargs = option.nargs
- if len(rargs) < nargs:
- if nargs == 1:
- self.error("%s option requires a value" % opt)
- else:
- self.error("%s option requires %d values"
- % (opt, nargs))
- elif nargs == 1:
- value = rargs.pop(0)
- else:
- value = tuple(rargs[0:nargs])
- del rargs[0:nargs]
-
- elif had_explicit_value:
- self.error("%s option does not take a value" % opt)
-
- else:
- value = None
-
- option.process(opt, value, values, self)
-
- def _process_short_opts (self, rargs, values):
- arg = rargs.pop(0)
- stop = 0
- i = 1
- for ch in arg[1:]:
- opt = "-" + ch
- option = self._short_opt.get(opt)
- i += 1 # we have consumed a character
-
- if not option:
- self.error("no such option: %s" % opt)
- if option.takes_value():
- # Any characters left in arg? Pretend they're the
- # next arg, and stop consuming characters of arg.
- if i < len(arg):
- rargs.insert(0, arg[i:])
- stop = 1
-
- nargs = option.nargs
- if len(rargs) < nargs:
- if nargs == 1:
- self.error("%s option requires a value" % opt)
- else:
- self.error("%s option requires %s values"
- % (opt, nargs))
- elif nargs == 1:
- value = rargs.pop(0)
- else:
- value = tuple(rargs[0:nargs])
- del rargs[0:nargs]
-
- else: # option doesn't take a value
- value = None
-
- option.process(opt, value, values, self)
-
- if stop:
- break
-
-
- # -- Output/error methods ------------------------------------------
-
- def error (self, msg):
- """error(msg : string)
-
- Print a usage message incorporating 'msg' to stderr and exit.
- If you override this in a subclass, it should not return -- it
- should either exit or raise an exception.
- """
- self.print_usage(sys.stderr)
- sys.exit("%s: error: %s" % (get_prog_name(), msg))
-
- def print_usage (self, file=None):
- """print_usage(file : file = stdout)
-
- Print the usage message for the current program (self.usage) to
- 'file' (default stdout). Any occurence of the string "%prog" in
- self.usage is replaced with the name of the current program
- (basename of sys.argv[0]). Does nothing if self.usage is empty
- or not defined.
- """
- if self.usage:
- usage = self.usage.replace("%prog", get_prog_name())
- print >>file, usage
- print >>file
-
- def print_version (self, file=None):
- """print_version(file : file = stdout)
-
- Print the version message for this program (self.version) to
- 'file' (default stdout). As with print_usage(), any occurence
- of "%prog" in self.version is replaced by the current program's
- name. Does nothing if self.version is empty or undefined.
- """
- if self.version:
- version = self.version.replace("%prog", get_prog_name())
- print >>file, version
-
- def print_help (self, file=None):
- """print_help(file : file = stdout)
-
- Print an extended help message, listing all options and any
- help text provided with them, to 'file' (default stdout).
- """
- from distutils.fancy_getopt import wrap_text
-
- if file is None:
- file = sys.stdout
-
- self.print_usage(file)
-
- # The help for each option consists of two parts:
- # * the opt strings and metavars
- # eg. ("-x", or "-fFILENAME, --file=FILENAME")
- # * the user-supplied help string
- # eg. ("turn on expert mode", "read data from FILENAME")
- #
- # If possible, we write both of these on the same line:
- # -x turn on expert mode
- #
- # But if the opt string list is too long, we put the help
- # string on a second line, indented to the same column it would
- # start in if it fit on the first line.
- # -fFILENAME, --file=FILENAME
- # read data from FILENAME
-
- print >>file, "options:"
- width = 78 # assume 80 cols for now
-
- option_help = [] # list of (string, string) tuples
- lengths = []
-
- for option in self.option_list:
- takes_value = option.takes_value()
- if takes_value:
- metavar = option.metavar or option.dest.upper()
-
- opts = [] # list of "-a" or "--foo=FILE" strings
- if option.help is SUPPRESS_HELP:
- continue
-
- if takes_value:
- for sopt in option._short_opts:
- opts.append(sopt + metavar)
- for lopt in option._long_opts:
- opts.append(lopt + "=" + metavar)
- else:
- for opt in option._short_opts + option._long_opts:
- opts.append(opt)
-
- opts = ", ".join(opts)
- option_help.append((opts, option.help))
- lengths.append(len(opts))
-
- max_opts = min(max(lengths), 20)
-
- for (opts, help) in option_help:
- # how much to indent lines 2 .. N of help text
- indent_rest = 2 + max_opts + 2
- help_width = width - indent_rest
-
- if len(opts) > max_opts:
- opts = " " + opts + "\n"
- indent_first = indent_rest
-
- else: # start help on same line as opts
- opts = " %-*s " % (max_opts, opts)
- indent_first = 0
-
- file.write(opts)
-
- if help:
- help_lines = wrap_text(help, help_width)
- print >>file, "%*s%s" % (indent_first, "", help_lines[0])
- for line in help_lines[1:]:
- print >>file, "%*s%s" % (indent_rest, "", line)
- elif opts[-1] != "\n":
- file.write("\n")
-
-# class OptionParser
-
-
-def _match_abbrev (s, words):
- """_match_abbrev(s : string, words : [string]) -> string
-
- Returns the string in 'words' for which 's' is an unambiguous
- abbreviation. If 's' is found to be ambiguous or doesn't match any
- of 'words', raises BadOptionError.
- """
- match = None
- for word in words:
- # If s isn't even a prefix for this word, don't waste any
- # more time on it: skip to the next word and try again.
- if not word.startswith(s):
- continue
-
- # Exact match? Great, return now.
- if s == word:
- return word
-
- # Now comes the tricky business of disambiguation. At this
- # point, we know s is a proper prefix of word, eg. s='--foo' and
- # word=='--foobar'. If we have already seen another word where
- # this was the case, eg. '--foobaz', fail: s is ambiguous.
- # Otherwise record this match and keep looping; we will return
- # if we see an exact match, or when we fall out of the loop and
- # it turns out that the current word is the match.
- if match:
- raise BadOptionError("ambiguous option: %s (%s, %s, ...?)"
- % (s, match, word))
- match = word
-
- if match:
- return match
- else:
- raise BadOptionError("no such option: %s" % s)
-
-def get_prog_name ():
- return os.path.basename(sys.argv[0])
--
cgit v1.2.1
From f44268b3aa6ee4f03a83bd857cc7efd6b5d73dc7 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 20 Jun 2002 03:56:59 +0000
Subject: - Added new "choice" option type. - Re-enabled optimized help text
positioning. - Renamed some methods related to help output.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@199 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/optik.py | 136 ++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 95 insertions(+), 41 deletions(-)
(limited to 'docutils')
diff --git a/docutils/optik.py b/docutils/optik.py
index 16a927aec..fda0967a9 100644
--- a/docutils/optik.py
+++ b/docutils/optik.py
@@ -120,6 +120,14 @@ def check_builtin (option, opt, value):
#"%s: invalid %s argument %r" % (opt, what, value))
"option %s: invalid %s value: %r" % (opt, what, value))
+def check_choice(option, opt, value):
+ if value in option.choices:
+ return value
+ else:
+ raise OptionValueError(
+ "option %s: invalid choice: %r (choose one of %r)"
+ % (opt, value, option.choices))
+
class Option:
"""
@@ -127,12 +135,16 @@ class Option:
_short_opts : [string]
_long_opts : [string]
+ option_string : string
+ Set when help output is formatted.
+
action : string
type : string
dest : string
default : any
nargs : int
const : any
+ choices : [string]
callback : function
callback_args : (any*)
callback_kwargs : { string : any }
@@ -148,6 +160,7 @@ class Option:
'default',
'nargs',
'const',
+ 'choices',
'callback',
'callback_args',
'callback_kwargs',
@@ -184,7 +197,7 @@ class Option:
# The set of known types for option parsers. Again, listed here for
# constructor argument validation.
- TYPES = ("string", "int", "long", "float", "complex")
+ TYPES = ("string", "int", "long", "float", "complex", "choice")
# Dictionary of argument checking functions, which convert and
# validate option arguments according to the option type.
@@ -206,6 +219,7 @@ class Option:
"long" : check_builtin,
"float" : check_builtin,
"complex" : check_builtin,
+ "choice" : check_choice,
}
@@ -300,8 +314,12 @@ class Option:
# XXX should factor out another class attr here: list of
# actions that *require* a type
if self.action in ("store", "append"):
- # No type given? "string" is the most sensible default.
- self.type = "string"
+ if self.choices is not None:
+ # The "choices" attribute implies "choice" type.
+ self.type = "choice"
+ else:
+ # No type given? "string" is the most sensible default.
+ self.type = "string"
else:
if self.type not in self.TYPES:
raise OptionError("invalid option type: %r" % self.type, self)
@@ -309,6 +327,19 @@ class Option:
raise OptionError(
"must not supply a type for action %r" % self.action, self)
+ def _check_choice(self):
+ if self.type == "choice":
+ if self.choices is None:
+ raise OptionError(
+ "must supply a list of choices for type 'choice'", self)
+ elif type(self.choices) not in (TupleType, ListType):
+ raise OptionError(
+ "choices must be a list of strings ('%s' supplied)"
+ % str(type(self.choices)).split("'")[1], self)
+ elif self.choices is not None:
+ raise OptionError(
+ "must not supply choices for type %r" % self.type, self)
+
def _check_dest (self):
if self.action in self.STORE_ACTIONS and self.dest is None:
# No destination given, and we need one for this action.
@@ -365,6 +396,7 @@ class Option:
CHECK_METHODS = [_check_action,
_check_type,
+ _check_choice,
_check_dest,
_check_const,
_check_nargs,
@@ -605,7 +637,7 @@ class OptionContainer:
# -- Feedback methods ----------------------------------------------
- def get_options(self):
+ def get_option_help(self):
if not self.option_list:
return ""
result = [] # list of strings to "".join() later
@@ -614,7 +646,7 @@ class OptionContainer:
result.append(self.format.format_option(option))
return "".join(result)
- def get_description(self):
+ def get_description_help(self):
if self.description:
return self.format.format_description(self.description)
else:
@@ -623,8 +655,8 @@ class OptionContainer:
def get_help(self):
result = ""
if self.description:
- result = self.get_description() + "\n"
- return result + self.get_options()
+ result = self.get_description_help() + "\n"
+ return result + self.get_option_help()
class OptionGroup(OptionContainer):
@@ -1044,7 +1076,7 @@ class OptionParser(OptionContainer):
self.print_usage(sys.stderr)
sys.exit("%s: error: %s" % (get_prog_name(), msg))
- def get_usage(self):
+ def get_usage_help(self):
if self.usage:
return self.format.format_usage(
self.usage.replace("%prog", get_prog_name()))
@@ -1061,9 +1093,9 @@ class OptionParser(OptionContainer):
or not defined.
"""
if self.usage:
- print >>file, self.get_usage()
+ print >>file, self.get_usage_help()
- def get_version(self):
+ def get_version_help(self):
if self.version:
return self.version.replace("%prog", get_prog_name())
else:
@@ -1078,14 +1110,15 @@ class OptionParser(OptionContainer):
name. Does nothing if self.version is empty or undefined.
"""
if self.version:
- print >>file, self.get_version()
+ print >>file, self.get_version_help()
- def get_options(self):
+ def get_option_help(self):
+ self.format.store_option_strings(self)
result = []
result.append(self.format.format_heading("Options"))
self.format.increase_nesting()
if self.option_list:
- result.append(OptionContainer.get_options(self))
+ result.append(OptionContainer.get_option_help(self))
result.append("\n")
for group in self.option_groups:
result.append(group.get_help())
@@ -1097,10 +1130,10 @@ class OptionParser(OptionContainer):
def get_help(self):
result = []
if self.usage:
- result.append(self.get_usage() + "\n")
+ result.append(self.get_usage_help() + "\n")
if self.description:
- result.append(self.get_description() + "\n")
- result.append(self.get_options())
+ result.append(self.get_description_help() + "\n")
+ result.append(self.get_option_help())
return "".join(result)
def print_help (self, file=None):
@@ -1123,30 +1156,34 @@ class HelpFormat:
Instance attributes:
indent_increment : int
- number of columns to indent per nesting level
- help_indent : int
- the starting column for option help text
+ The number of columns to indent per nesting level.
+ max_help_position : int
+ The maximum starting column for option help text.
+ help_position : int
+ The calculated starting column for option help text;
+ initially the same as the maximum.
width : int
- the overall width (in columns) for output
+ The overall width (in columns) for output.
current_indent : int
- in columns, calculated
+ In columns, calculated.
level : int
- increased for each additional nesting level
+ Increased for each additional nesting level.
help_width : int
- number of columns available for option help text
+ Number of columns available for option help text, calculated.
"""
- def __init__(self, indent_increment, help_indent, width, short_first):
+ def __init__(self, indent_increment, max_help_position, width,
+ short_first):
self.indent_increment = indent_increment
- self.help_indent = help_indent
+ self.help_position = self.max_help_position = max_help_position
self.width = width
self.current_indent = 0
self.level = 0
- self.help_width = self.width - self.help_indent
+ self.help_width = width - max_help_position
if short_first:
- self.format_option_list = self.format_option_list_short_first
+ self.format_option_strings = self.format_option_strings_short_first
else:
- self.format_option_list = self.format_option_list_long_first
+ self.format_option_strings = self.format_option_strings_long_first
def increase_nesting(self):
self.current_indent += self.indent_increment
@@ -1186,11 +1223,11 @@ class HelpFormat:
# -fFILENAME, --file=FILENAME
# read data from FILENAME
result = []
- opts = self.format_option_list(option)
- opt_width = self.help_indent - self.current_indent - 2
+ opts = option.option_strings
+ opt_width = self.help_position - self.current_indent - 2
if len(opts) > opt_width:
opts = "%*s%s\n" % (self.current_indent, "", opts)
- indent_first = self.help_indent
+ indent_first = self.help_position
else: # start help on same line as opts
opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts)
indent_first = 0
@@ -1198,19 +1235,36 @@ class HelpFormat:
if option.help:
help_lines = wrap_text(option.help, self.help_width)
result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
- result.extend(["%*s%s\n" % (self.help_indent, "", line)
+ result.extend(["%*s%s\n" % (self.help_position, "", line)
for line in help_lines[1:]])
elif opts[-1] != "\n":
result.append("\n")
return "".join(result)
- def format_option_list(self, option):
+ def store_option_strings(self, parser):
+ self.increase_nesting()
+ max_len = 0
+ for opt in parser.option_list:
+ strings = self.format_option_strings(opt)
+ opt.option_strings = strings
+ max_len = max(max_len, len(strings) + self.current_indent)
+ self.increase_nesting()
+ for group in parser.option_groups:
+ for opt in group.option_list:
+ strings = self.format_option_strings(opt)
+ opt.option_strings = strings
+ max_len = max(max_len, len(strings) + self.current_indent)
+ self.decrease_nesting()
+ self.decrease_nesting()
+ self.help_position = min(max_len + 2, self.max_help_position)
+
+ def format_option_strings(self, option):
"""Return a comma-separated list of option strigs & metavariables."""
raise NotImplementedError(
- "Virtual method; use format_option_list_short_first or "
- "format_option_list_long_first instead.")
+ "Virtual method; use format_option_strings_short_first or "
+ "format_option_strings_long_first instead.")
- def format_option_list_short_first(self, option):
+ def format_option_strings_short_first(self, option):
opts = [] # list of "-a" or "--foo=FILE" strings
takes_value = option.takes_value()
if takes_value:
@@ -1224,7 +1278,7 @@ class HelpFormat:
opts.append(opt)
return ", ".join(opts)
- def format_option_list_long_first(self, option):
+ def format_option_strings_long_first(self, option):
opts = [] # list of "-a" or "--foo=FILE" strings
takes_value = option.takes_value()
if takes_value:
@@ -1243,9 +1297,9 @@ class Indented(HelpFormat):
"""Formats help with indented section bodies."""
- def __init__(self, indent_increment=2, help_indent=24, width=78,
+ def __init__(self, indent_increment=2, max_help_position=24, width=78,
short_first=1):
- HelpFormat.__init__(self, indent_increment, help_indent, width,
+ HelpFormat.__init__(self, indent_increment, max_help_position, width,
short_first)
def format_usage(self, usage):
@@ -1259,9 +1313,9 @@ class Titled(HelpFormat):
"""Formats help with underlined section headers."""
- def __init__(self, indent_increment=0, help_indent=24, width=78,
+ def __init__(self, indent_increment=0, max_help_position=24, width=78,
short_first=None):
- HelpFormat.__init__(self, indent_increment, help_indent, width,
+ HelpFormat.__init__(self, indent_increment, max_help_position, width,
short_first)
def format_usage(self, usage):
--
cgit v1.2.1
From e423e67e9ed18cdb153baa37a936482e85efb79a Mon Sep 17 00:00:00 2001
From: orutherfurd
Date: Mon, 24 Jun 2002 03:30:31 +0000
Subject: - added missing ListType import which is used for validating "choice"
options
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@200 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/optik.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/optik.py b/docutils/optik.py
index fda0967a9..d717f6864 100644
--- a/docutils/optik.py
+++ b/docutils/optik.py
@@ -54,7 +54,7 @@ __version__ = "1.3+"
import sys
import os
import types
-from types import TupleType, DictType
+from types import TupleType, DictType, ListType
from distutils.fancy_getopt import wrap_text
--
cgit v1.2.1
From 373cca31645a6460611519ee0ae27e02076d2495 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 27 Jun 2002 01:16:03 +0000
Subject: - Added ``option_spec`` parameter to ``publish()`` etc. - Added
"--dump-internal-document-attributes" support.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@204 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index 1fe6af418..4a75a9508 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -37,7 +37,7 @@ class Publisher:
self.reader = reader
"""A `readers.Reader` instance."""
-
+
self.parser = parser
"""A `parsers.Parser` instance."""
@@ -77,40 +77,45 @@ class Publisher:
defaults=defaults)
self.options = option_parser.get_default_values()
- def process_command_line(self, argv=None, usage=None, description=None):
+ def process_command_line(self, argv=None, usage=None, description=None,
+ option_spec=None):
"""
Pass an empty list to `argv` to avoid reading `sys.argv` (the
default).
-
+
Set components first (`self.set_reader` & `self.set_writer`).
"""
option_parser = OptionParser(
- components=(self.reader, self.parser, self.writer),
+ components=(option_spec, self.reader, self.parser, self.writer),
usage=usage, description=description)
if argv is None:
argv = sys.argv[1:]
self.options, self.source, self.destination \
= option_parser.parse_args(argv)
- def publish(self, argv=None, usage=None, description=None):
+ def publish(self, argv=None, usage=None, description=None,
+ option_spec=None):
"""
Process command line options and arguments, run `self.reader`
and then `self.writer`.
"""
if self.options is None:
- self.process_command_line(argv, usage, description)
+ self.process_command_line(argv, usage, description, option_spec)
document = self.reader.read(self.source, self.parser, self.options)
self.writer.write(document, self.destination)
+ if self.options.dump_internal_document_attributes:
+ from pprint import pformat
+ print >>sys.stderr, pformat(document.__dict__)
def publish(reader=None, reader_name='standalone',
parser=None, parser_name='restructuredtext',
writer=None, writer_name='pseudoxml',
- argv=None, usage=None, description=None):
+ argv=None, usage=None, description=None, option_spec=None):
"""A convenience function; set up & run a `Publisher`."""
pub = Publisher(reader, parser, writer)
if reader is None:
pub.set_reader(reader_name, parser, parser_name)
if writer is None:
pub.set_writer(writer_name)
- pub.publish(argv, usage, description)
+ pub.publish(argv, usage, description, option_spec)
--
cgit v1.2.1
From f7261b75de49dbcd0da320ac34cd549425e9dac2 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 27 Jun 2002 01:17:24 +0000
Subject: - Enabled "--encoding" option (but not implemented yet). - Added
"--dump-internal-document-attributes". - Support for non-grouped options.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@205 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 275137a9c..c833940b4 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -68,9 +68,8 @@ class OptionParser(optik.OptionParser):
['--no-debug'], {'action': 'store_false', 'dest': 'debug'}),
('Send the output of system messages (warnings) to .',
['--warnings'], {'dest': 'warning_stream', 'metavar': ''}),
- # @@@ Take default encoding & language from locale?
- #('Specify the encoding of input text. Default is "utf-8".',
- # ['--encoding', '-e'], {'default': 'utf-8', 'metavar': ''}),
+ ('Specify the encoding of input text. Default is locale-dependent.',
+ ['--encoding', '-e'], {'metavar': ''}),
('Specify the language of input text (ISO 639 2-letter identifier. '
'Default is "en" (English).',
['--language', '-l'], {'dest': 'language_code', 'default': 'en',
@@ -78,12 +77,17 @@ class OptionParser(optik.OptionParser):
("Show this program's version number and exit.",
['--version'], {'action': 'version'}),
('Show this help message and exit.',
- ['--help', '-h'], {'action': 'help'}),))
+ ['--help', '-h'], {'action': 'help'}),
+ # Hidden options, for development use only:
+ (optik.SUPPRESS_HELP, ['--dump-internal-document-attributes'],
+ {'action': 'store_true'}),))
+
"""Command-line option specifications, common to all Docutils front-ends.
Option group title, description, and a list/tuple of tuples: ``('help
- text', [list of option strings], {keyword arguments})``. Option specs
- from Docutils components are also used (see
- `populate_from_components()`)."""
+ text', [list of option strings], {keyword arguments})``. Group title
+ and/or description may be `None`; no group title implies no group, just a
+ list of single options. Option specs from Docutils components are also
+ used (see `populate_from_components()`)."""
thresholds = {'info': 1, 'warning': 2, 'error': 3, 'severe': 4, 'none': 5}
"""Lookup table for --report and --halt threshold values."""
@@ -107,8 +111,11 @@ class OptionParser(optik.OptionParser):
for component in components:
if component is not None and component.cmdline_options:
title, description, option_spec = component.cmdline_options
- group = optik.OptionGroup(self, title, description)
- self.add_option_group(group)
+ if title:
+ group = optik.OptionGroup(self, title, description)
+ self.add_option_group(group)
+ else:
+ group = self # single options
for (help_text, option_strings, kwargs) in option_spec:
group.add_option(help=help_text, *option_strings,
**kwargs)
--
cgit v1.2.1
From 5e35a98b286b3a7a3107818e01bdcc13dd2f2a79 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 27 Jun 2002 01:18:21 +0000
Subject: - Reworked the name/id bookkeeping; to ``document``, removed
``explicit_targets`` and ``implicit_targets`` attributes, added
``nametypes`` attribute and ``set_name_id_map`` method.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@206 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 127 +++++++++++++++++++++++++++---------------------------
1 file changed, 63 insertions(+), 64 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 45d5ef726..6f6367cdd 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -556,13 +556,6 @@ class document(Root, Structural, Element):
self.reporter = reporter
"""System message generator."""
- self.explicit_targets = {}
- """Mapping of target names to explicit target nodes."""
-
- self.implicit_targets = {}
- """Mapping of target names to implicit (internal) target
- nodes."""
-
self.external_targets = []
"""List of external target nodes."""
@@ -584,6 +577,10 @@ class document(Root, Structural, Element):
self.nameids = {}
"""Mapping of names to unique id's."""
+ self.nametypes = {}
+ """Mapping of names to hyperlink type (boolean: True => explicit,
+ False => implicit."""
+
self.ids = {}
"""Mapping of ids to nodes."""
@@ -622,7 +619,7 @@ class document(Root, Structural, Element):
"""List of citation nodes."""
self.pending = []
- """List of pending elements @@@."""
+ """List of pending elements."""
self.autofootnote_start = 1
"""Initial auto-numbered footnote number."""
@@ -642,12 +639,12 @@ class document(Root, Structural, Element):
return domroot
def set_id(self, node, msgnode=None):
- if msgnode == None:
- msgnode = self.messages
if node.has_key('id'):
id = node['id']
if self.ids.has_key(id) and self.ids[id] is not node:
msg = self.reporter.severe('Duplicate ID: "%s".' % id)
+ if msgnode == None:
+ msgnode = self.messages
msgnode += msg
else:
if node.has_key('name'):
@@ -659,66 +656,66 @@ class document(Root, Structural, Element):
self.id_start += 1
node['id'] = id
self.ids[id] = node
- if node.has_key('name'):
- self.nameids[node['name']] = id
return id
- def note_implicit_target(self, target, msgnode=None):
+ def set_name_id_map(self, node, id, msgnode=None, explicit=None):
+ if node.has_key('name'):
+ name = node['name']
+ if self.nameids.has_key(name):
+ self.set_duplicate_name_id(node, id, name, msgnode, explicit)
+ else:
+ self.nameids[name] = id
+ self.nametypes[name] = explicit
+
+ def set_duplicate_name_id(self, node, id, name, msgnode, explicit):
if msgnode == None:
msgnode = self.messages
- id = self.set_id(target, msgnode)
- name = target['name']
- if self.explicit_targets.has_key(name) \
- or self.implicit_targets.has_key(name):
+ old_id = self.nameids[name]
+ old_explicit = self.nametypes[name]
+ self.nametypes[name] = old_explicit or explicit
+ if explicit:
+ if old_explicit:
+ level = 2
+ if old_id is not None:
+ old_node = self.ids[old_id]
+ if node.has_key('refuri'):
+ refuri = node['refuri']
+ if old_node.has_key('name') \
+ and old_node.has_key('refuri') \
+ and old_node['refuri'] == refuri:
+ level = 1 # just inform if refuri's identical
+ if level > 1:
+ dupname(old_node)
+ self.nameids[name] = None
+ msg = self.reporter.system_message(
+ level, 'Duplicate explicit target name: "%s".' % name,
+ backrefs=[id])
+ msgnode += msg
+ dupname(node)
+ else:
+ self.nameids[name] = id
+ if old_id is not None:
+ old_node = self.ids[old_id]
+ dupname(old_node)
+ else:
+ if old_id is not None and not old_explicit:
+ self.nameids[name] = None
+ old_node = self.ids[old_id]
+ dupname(old_node)
+ dupname(node)
+ if not explicit or (not old_explicit and old_id is not None):
msg = self.reporter.info(
- 'Duplicate implicit target name: "%s".' % name,
- backrefs=[id])
+ 'Duplicate implicit target name: "%s".' % name,
+ backrefs=[id])
msgnode += msg
- self.clear_target_names(name, self.implicit_targets)
- del target['name']
- target['dupname'] = name
- self.implicit_targets[name] = None
- else:
- self.implicit_targets[name] = target
+
+ def note_implicit_target(self, target, msgnode=None):
+ id = self.set_id(target, msgnode)
+ self.set_name_id_map(target, id, msgnode, explicit=None)
def note_explicit_target(self, target, msgnode=None):
- if msgnode == None:
- msgnode = self.messages
id = self.set_id(target, msgnode)
- name = target['name']
- if self.explicit_targets.has_key(name):
- level = 2
- if target.has_key('refuri'): # external target, dups OK
- refuri = target['refuri']
- t = self.explicit_targets[name]
- if t.has_key('name') and t.has_key('refuri') \
- and t['refuri'] == refuri:
- level = 1 # just inform if refuri's identical
- msg = self.reporter.system_message(
- level, 'Duplicate explicit target name: "%s".' % name,
- backrefs=[id])
- msgnode += msg
- self.clear_target_names(name, self.explicit_targets,
- self.implicit_targets)
- if level > 1:
- del target['name']
- target['dupname'] = name
- elif self.implicit_targets.has_key(name):
- msg = self.reporter.info(
- 'Duplicate implicit target name: "%s".' % name,
- backrefs=[id])
- msgnode += msg
- self.clear_target_names(name, self.implicit_targets)
- self.explicit_targets[name] = target
-
- def clear_target_names(self, name, *targetdicts):
- for targetdict in targetdicts:
- if not targetdict.has_key(name):
- continue
- node = targetdict[name]
- if node.has_key('name'):
- node['dupname'] = node['name']
- del node['name']
+ self.set_name_id_map(target, id, msgnode, explicit=1)
def note_refname(self, node):
self.refnames.setdefault(node['refname'], []).append(node)
@@ -770,7 +767,6 @@ class document(Root, Structural, Element):
self.note_refname(ref)
def note_citation(self, citation):
- self.set_id(citation)
self.citations.append(citation)
def note_citation_ref(self, ref):
@@ -787,8 +783,7 @@ class document(Root, Structural, Element):
msgnode = self.messages
msgnode += msg
oldnode = self.substitution_defs[name]
- oldnode['dupname'] = oldnode['name']
- del oldnode['name']
+ dupname(oldnode)
# keep only the last definition
self.substitution_defs[name] = subdef
@@ -1303,3 +1298,7 @@ def make_id(string):
_non_id_chars = re.compile('[^a-z0-9]+')
_non_id_at_ends = re.compile('^[-0-9]+|-+$')
+
+def dupname(node):
+ node['dupname'] = node['name']
+ del node['name']
--
cgit v1.2.1
From b0f8ccca541e0f8adc95209845d205feb163f229 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 27 Jun 2002 01:19:28 +0000
Subject: - Some ``types`` cleanup. - Added ``Values.__repr__`` method.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@207 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/optik.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/optik.py b/docutils/optik.py
index d717f6864..a8652860c 100644
--- a/docutils/optik.py
+++ b/docutils/optik.py
@@ -53,8 +53,7 @@ __version__ = "1.3+"
import sys
import os
-import types
-from types import TupleType, DictType, ListType
+from types import TupleType, ListType, DictType, StringType
from distutils.fancy_getopt import wrap_text
@@ -583,7 +582,7 @@ class OptionContainer:
"""add_option(Option)
add_option(opt_str, ..., kwarg=val, ...)
"""
- if type(args[0]) is types.StringType:
+ if type(args[0]) is StringType:
option = self.option_class(*args, **kwargs)
elif len(args) == 1 and not kwargs:
option = args[0]
@@ -685,6 +684,8 @@ class Values:
for (attr, val) in defaults.items():
setattr(self, attr, val)
+ def __repr__(self):
+ return "%s(%r)" % (self.__class__, self.__dict__)
def _update_careful (self, dict):
"""
--
cgit v1.2.1
From 279a5cfc2c066bba8de6a9035c077f43710d849d Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 27 Jun 2002 01:20:25 +0000
Subject: Updated & cleaned up (a bit).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@208 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 3ee0e0534..543bc1108 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -1361,8 +1361,9 @@ class Body(RSTState):
footnote['name'] = name
self.document.note_footnote(footnote)
if name:
- self.document.note_explicit_target(footnote,
- footnote)
+ self.document.note_explicit_target(footnote, footnote)
+ else:
+ self.document.set_id(footnote)
if indented:
self.nested_parse(indented, input_offset=offset, node=footnote)
return [footnote], blank_finish
@@ -1444,8 +1445,7 @@ class Body(RSTState):
self.document.note_external_target(target)
else:
self.document.note_internal_target(target)
- self.document.note_explicit_target(
- target, self.parent)
+ self.document.note_explicit_target(target, self.parent)
else: # anonymous target
if refuri:
target['refuri'] = refuri
--
cgit v1.2.1
From b42175f802cb1f8bce74017430c5135e3fff5c55 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 27 Jun 2002 01:21:24 +0000
Subject: Fixed indirect target resolution in ``Hyperlinks`` transform;
updated.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@209 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/references.py | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/references.py b/docutils/transforms/references.py
index ccd43c749..20cdcd525 100644
--- a/docutils/transforms/references.py
+++ b/docutils/transforms/references.py
@@ -1,6 +1,6 @@
#! /usr/bin/env python
"""
-:Authors: David Goodger
+:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:Revision: $Revision$
:Date: $Date$
@@ -146,14 +146,11 @@ class Hyperlinks(Transform):
def resolve_indirect_target(self, target):
refname = target['refname']
- reftarget = None
- if self.document.explicit_targets.has_key(refname):
- reftarget = self.document.explicit_targets[refname]
- elif self.document.implicit_targets.has_key(refname):
- reftarget = self.document.implicit_targets[refname]
- if not reftarget:
+ reftarget_id = self.document.nameids.get(refname)
+ if not reftarget_id:
self.nonexistent_indirect_target(target)
return
+ reftarget = self.document.ids[reftarget_id]
if isinstance(reftarget, nodes.target) \
and not reftarget.resolved and reftarget.hasattr('refname'):
self.one_indirect_target(reftarget) # multiply indirect
@@ -179,9 +176,9 @@ class Hyperlinks(Transform):
naming = ''
if target.hasattr('name'):
naming = '"%s" ' % target['name']
- reflist = self.document.refnames[target['name']]
+ reflist = self.document.refnames.get(target['name'], [])
else:
- reflist = self.document.refnames[target['id']]
+ reflist = self.document.refids.get(target['id'], [])
naming += '(id="%s")' % target['id']
msg = self.document.reporter.warning(
'Indirect hyperlink target %s refers to target "%s", '
@@ -495,7 +492,7 @@ class Footnotes(Transform):
while 1:
label = str(startnum)
startnum += 1
- if not self.document.explicit_targets.has_key(label):
+ if not self.document.nameids.has_key(label):
break
footnote.insert(0, nodes.label('', label))
if footnote.hasattr('dupname'):
@@ -540,8 +537,9 @@ class Footnotes(Transform):
ref.parent.replace(ref, prb)
break
ref += nodes.Text(label)
- footnote = self.document.explicit_targets[label]
- ref['refid'] = footnote['id']
+ id = self.document.nameids[label]
+ footnote = self.document.ids[id]
+ ref['refid'] = id
self.document.note_refid(ref)
footnote.add_backref(ref['id'])
ref.resolved = 1
--
cgit v1.2.1
From 4c08c14508ae15f0d45164b54497ecf0105af264 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 27 Jun 2002 01:22:04 +0000
Subject: fiddling
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@210 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index 782d930c5..e9553cb13 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -136,9 +136,8 @@ class FinalCheckVisitor(nodes.SparseNodeVisitor):
if node.resolved or not node.hasattr('refname'):
return
refname = node['refname']
- try:
- id = self.document.nameids[refname]
- except KeyError:
+ id = self.document.nameids.get(refname)
+ if id is None:
msg = self.document.reporter.error(
'Unknown target name: "%s".' % (node['refname']))
self.document.messages += msg
@@ -148,11 +147,11 @@ class FinalCheckVisitor(nodes.SparseNodeVisitor):
prbid = self.document.set_id(prb)
msg.add_backref(prbid)
node.parent.replace(node, prb)
- return
- del node['refname']
- node['refid'] = id
- self.document.ids[id].referenced = 1
- node.resolved = 1
+ else:
+ del node['refname']
+ node['refid'] = id
+ self.document.ids[id].referenced = 1
+ node.resolved = 1
visit_footnote_reference = visit_citation_reference = visit_reference
--
cgit v1.2.1
From 9c38addab1cab5a5e7e5b763984ef67e06881440 Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 28 Jun 2002 04:13:41 +0000
Subject: Added to project; uniform API for a variety of input & output
mechanisms.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@217 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/io.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 140 insertions(+)
create mode 100644 docutils/io.py
(limited to 'docutils')
diff --git a/docutils/io.py b/docutils/io.py
new file mode 100644
index 000000000..66845e7f7
--- /dev/null
+++ b/docutils/io.py
@@ -0,0 +1,140 @@
+#! /usr/bin/env python
+
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+"""
+
+__docformat__ = 'reStructuredText'
+
+import sys
+import locale
+
+
+class IO:
+
+ """
+ Base class for abstract input/output wrappers.
+ """
+
+ source = None
+ destination = None
+
+ def __init__(self, options, source=None, destination=None):
+ """
+ :Parameters:
+ - `options`: a `docutils.optik.Values` object.
+ - `source`: identifies the source of input data.
+ - `destination`: identifies the destination for output data.
+ """
+ self.options = options
+
+ def __repr__(self):
+ return '%s: source=%r, destination=%r' % (self.__class__, self.source,
+ self.destination)
+
+ def read(self, reader):
+ raise NotImplementedError
+
+ def write(self, data):
+ raise NotImplementedError
+
+ def decode(self, data):
+ """
+ Decode a string, `data`, heuristically.
+ Raise UnicodeError if unsuccessful.
+ """
+ encodings = [self.options.input_encoding,
+ locale.getlocale()[1],
+ 'utf-8',
+ locale.getdefaultlocale()[1],]
+ # is locale.getdefaultlocale() platform-specific?
+ for enc in encodings:
+ if not enc:
+ continue
+ try:
+ decoded = unicode(data, enc)
+ return decoded
+ except UnicodeError:
+ pass
+ raise UnicodeError(
+ 'Unable to decode input data. Tried the following encodings: %s.'
+ % ', '.join([repr(enc) for enc in encodings if enc]))
+
+
+class FileIO(IO):
+
+ """
+ IO for single, simple files.
+ """
+
+ def __init__(self, options, source=None, destination=None):
+ """
+ :Parameters:
+ - `source`: one of (a) a file-like object, which is read directly;
+ (b) a path to a file, which is opened and then read; or (c)
+ `None`, which implies `sys.stdin`.
+ - `destination`: one of (a) a file-like object, which is written
+ directly; (b) a path to a file, which is opened and then
+ written; or (c) `None`, which implies `sys.stdout`.
+ """
+ IO.__init__(self, options)
+ if hasattr(source, 'read'):
+ self.source = source
+ elif source is None:
+ self.source = sys.stdin
+ else:
+ self.source = open(source)
+ if hasattr(destination, 'write'):
+ self.destination = destination
+ elif destination is None:
+ self.destination = sys.stdout
+ else:
+ self.destination = open(destination, 'w')
+
+ def read(self, reader):
+ """
+ Read and decode a single file and return the data.
+ """
+ data = self.source.read()
+ return self.decode(data)
+
+ def write(self, data):
+ """
+ Encode and write `data` to a single file.
+ """
+ output = data.encode(self.options.output_encoding)
+ self.destination.write(output)
+
+
+class StringIO(IO):
+
+ """
+ Direct string IO.
+ """
+
+ def __init__(self, options, source=None, destination=None):
+ """
+ :Parameters:
+ - `source`: a string containing input data.
+ - `destination`: not used.
+ """
+ IO.__init__(self, options)
+ self.source = source
+
+ def read(self, reader):
+ """
+ Decode and return the source string.
+ """
+ return self.decode(self.source)
+
+ def write(self, data):
+ """
+ Encode and return `data`.
+ """
+ self.destination = data.encode(self.options.output_encoding)
+ return self.destination
--
cgit v1.2.1
From 01e6d2ca28acbc89879acefd8e0baa3e6ca8c457 Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 28 Jun 2002 04:13:57 +0000
Subject: - Added support for the ``docutils.io.IO`` class & subclasses.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@218 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 53 ++++++++++++++++++++++++++++--------------
docutils/frontend.py | 9 ++++---
docutils/readers/__init__.py | 25 +++-----------------
docutils/readers/standalone.py | 3 ---
docutils/writers/__init__.py | 30 +++---------------------
docutils/writers/pseudoxml.py | 3 ---
6 files changed, 47 insertions(+), 76 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index 4a75a9508..c0f9f4375 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -18,7 +18,7 @@ __docformat__ = 'reStructuredText'
import sys
from docutils import Component
-from docutils import readers, parsers, writers
+from docutils import readers, parsers, writers, io
from docutils.frontend import OptionParser
@@ -28,7 +28,10 @@ class Publisher:
A facade encapsulating the high-level logic of a Docutils system.
"""
- def __init__(self, reader=None, parser=None, writer=None):
+ def __init__(self, reader=None, parser=None, writer=None,
+ source=None, source_class=io.FileIO,
+ destination=None, destination_class=io.FileIO,
+ options=None):
"""
Initial setup. If any of `reader`, `parser`, or `writer` are not
specified, the corresponding ``set_...`` method should be called with
@@ -44,27 +47,34 @@ class Publisher:
self.writer = writer
"""A `writers.Writer` instance."""
- self.options = None
- """An object containing Docutils settings as instance attributes.
- Set by `self.process_command_line()` or `self.set_options()`."""
+ self.source = source
+ """The source of input data, an `io.IO` instance."""
+
+ self.source_class = source_class
+ """The class for dynamically created source objects."""
- self.source = None
- """The source of input data."""
+ self.destination = destination
+ """The destination for docutils output, an `io.IO` instance."""
- self.destination = None
- """The destination for docutils output."""
+ self.destination_class = destination_class
+ """The class for dynamically created destination objects."""
+
+ self.options = options
+ """An object containing Docutils settings as instance attributes.
+ Set by `self.process_command_line()` or `self.set_options()`."""
def set_reader(self, reader_name, parser, parser_name):
"""Set `self.reader` by name."""
reader_class = readers.get_reader_class(reader_name)
self.reader = reader_class(parser, parser_name)
+ self.parser = self.reader.parser
def set_writer(self, writer_name):
"""Set `self.writer` by name."""
writer_class = writers.get_writer_class(writer_name)
self.writer = writer_class()
- def set_options(self, **defaults):
+ def set_options(self, option_spec=None, **defaults):
"""
Set default option values (keyword arguments).
@@ -73,12 +83,12 @@ class Publisher:
from `self.publish()`.
"""
option_parser = OptionParser(
- components=(self.reader, self.parser, self.writer),
+ components=(option_spec, self.reader, self.parser, self.writer),
defaults=defaults)
self.options = option_parser.get_default_values()
def process_command_line(self, argv=None, usage=None, description=None,
- option_spec=None):
+ option_spec=None):
"""
Pass an empty list to `argv` to avoid reading `sys.argv` (the
default).
@@ -90,29 +100,36 @@ class Publisher:
usage=usage, description=description)
if argv is None:
argv = sys.argv[1:]
- self.options, self.source, self.destination \
- = option_parser.parse_args(argv)
+ self.options, source, destination = option_parser.parse_args(argv)
+ self.source = self.source_class(self.options, source=source)
+ self.destination = self.destination_class(self.options,
+ destination=destination)
def publish(self, argv=None, usage=None, description=None,
option_spec=None):
"""
- Process command line options and arguments, run `self.reader`
- and then `self.writer`.
+ Process command line options and arguments (if `self.options` not
+ already set), run `self.reader` and then `self.writer`. Return
+ `self.writer`'s output.
"""
if self.options is None:
self.process_command_line(argv, usage, description, option_spec)
document = self.reader.read(self.source, self.parser, self.options)
- self.writer.write(document, self.destination)
+ output = self.writer.write(document, self.destination)
if self.options.dump_internal_document_attributes:
from pprint import pformat
print >>sys.stderr, pformat(document.__dict__)
+ return output
def publish(reader=None, reader_name='standalone',
parser=None, parser_name='restructuredtext',
writer=None, writer_name='pseudoxml',
argv=None, usage=None, description=None, option_spec=None):
- """A convenience function; set up & run a `Publisher`."""
+ """
+ A convenience function for file I/O front-ends; set up & run a
+ `Publisher`.
+ """
pub = Publisher(reader, parser, writer)
if reader is None:
pub.set_reader(reader_name, parser, parser_name)
diff --git a/docutils/frontend.py b/docutils/frontend.py
index c833940b4..cb0a11681 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -69,9 +69,12 @@ class OptionParser(optik.OptionParser):
('Send the output of system messages (warnings) to .',
['--warnings'], {'dest': 'warning_stream', 'metavar': ''}),
('Specify the encoding of input text. Default is locale-dependent.',
- ['--encoding', '-e'], {'metavar': ''}),
- ('Specify the language of input text (ISO 639 2-letter identifier. '
- 'Default is "en" (English).',
+ ['--input-encoding', '-i'], {'metavar': ''}),
+ ('Specify the encoding for output. Default is UTF-8.',
+ ['--output-encoding', '-o'],
+ {'metavar': '', 'default': 'utf-8'}),
+ ('Specify the language of input text (ISO 639 2-letter identifier).'
+ ' Default is "en" (English).',
['--language', '-l'], {'dest': 'language_code', 'default': 'en',
'metavar': ''}),
("Show this program's version number and exit.",
diff --git a/docutils/readers/__init__.py b/docutils/readers/__init__.py
index 47c5b2fab..053527faf 100644
--- a/docutils/readers/__init__.py
+++ b/docutils/readers/__init__.py
@@ -49,7 +49,7 @@ class Reader(Component):
self.set_parser(parser_name)
self.source = None
- """Path to the source of raw input."""
+ """`docutils.io` IO object, source of input data."""
self.input = None
"""Raw text input; either a single string or, for more complex cases,
@@ -65,31 +65,12 @@ class Reader(Component):
if not self.parser:
self.parser = parser
self.options = options
- self.scan() # may modify self.parser, depending on input
+ # May modify self.parser, depending on input:
+ self.input = self.source.read(self)
self.parse()
self.transform()
return self.document
- def scan(self):
- """Override to read `self.input` from `self.source`."""
- raise NotImplementedError('subclass must override this method')
-
- def scan_file(self, source):
- """
- Scan a single file and return the raw data.
-
- Parameter `source` may be:
-
- (a) a file-like object, which is read directly;
- (b) a path to a file, which is opened and then read; or
- (c) `None`, which implies `sys.stdin`.
- """
- if hasattr(source, 'read'):
- return source.read()
- if self.source:
- return open(source).read()
- return sys.stdin.read()
-
def parse(self):
"""Parse `self.input` into a document tree."""
self.document = self.new_document()
diff --git a/docutils/readers/standalone.py b/docutils/readers/standalone.py
index e6108f569..24a8074e7 100644
--- a/docutils/readers/standalone.py
+++ b/docutils/readers/standalone.py
@@ -32,6 +32,3 @@ class Reader(readers.Reader):
frontmatter.DocInfo,
references.Footnotes,
references.Hyperlinks,)
-
- def scan(self):
- self.input = self.scan_file(self.source)
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
index 3c20068d4..24d1cf384 100644
--- a/docutils/writers/__init__.py
+++ b/docutils/writers/__init__.py
@@ -38,7 +38,7 @@ class Writer(Component):
"""Language module for the document."""
destination = None
- """Where to write the document."""
+ """`docutils.io` IO object; where to write the document."""
transforms = ()
"""Ordered list of transform classes (each with a ``transform()`` method).
@@ -56,7 +56,8 @@ class Writer(Component):
self.destination = destination
self.transform()
self.translate()
- self.record()
+ output = self.destination.write(self.output)
+ return output
def transform(self):
"""Run all of the transforms defined for this Writer."""
@@ -78,31 +79,6 @@ class Writer(Component):
"""
raise NotImplementedError('subclass must override this method')
- def record(self):
- """Override to record `document` to `destination`."""
- raise NotImplementedError('subclass must override this method')
-
- def recordfile(self, output, destination):
- """
- Write `output` to a single file.
-
- Parameters:
-
- - `output`: Data to write.
- - `destination`: one of:
-
- (a) a file-like object, which is written directly;
- (b) a path to a file, which is opened and then written; or
- (c) `None`, which implies `sys.stdout`.
- """
- output = output.encode('utf-8') # @@@ temporary; must not hard-code
- if hasattr(self.destination, 'write'):
- destination.write(output)
- elif self.destination:
- open(self.destination, 'w').write(output)
- else:
- sys.stdout.write(output)
-
_writer_aliases = {
'html': 'html4css1',
diff --git a/docutils/writers/pseudoxml.py b/docutils/writers/pseudoxml.py
index a0cf5ea14..c1ba29347 100644
--- a/docutils/writers/pseudoxml.py
+++ b/docutils/writers/pseudoxml.py
@@ -27,9 +27,6 @@ class Writer(writers.Writer):
def translate(self):
self.output = self.document.pformat()
- def record(self):
- self.recordfile(self.output, self.destination)
-
def supports(self, format):
"""This writer supports all format-specific elements."""
return 1
--
cgit v1.2.1
From bd73da1949ce273e385463736c868a9d72b32d0d Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 28 Jun 2002 04:16:26 +0000
Subject: - Added support for input and output encodings and for internal
Unicode support. - Added support for the ``docutils.io.IO`` class &
subclasses.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@219 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 380179651..97cc8b6ea 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -45,20 +45,17 @@ class Writer(writers.Writer):
self.document.walkabout(visitor)
self.output = visitor.astext()
- def record(self):
- self.recordfile(self.output, self.destination)
-
class HTMLTranslator(nodes.NodeVisitor):
- xml_declaration = '\n'
+ xml_declaration = '\n'
doctype = '\n'
html_head = '\n\n'
content_type = '\n'
+ 'charset=%s">\n'
generator = '\n'
stylesheet_link = '\n'
@@ -67,10 +64,10 @@ class HTMLTranslator(nodes.NodeVisitor):
nodes.NodeVisitor.__init__(self, document)
self.language = languages.get_language(document.options.language_code)
self.head_prefix = [
- self.xml_declaration, # @@@ % output_encoding
+ self.xml_declaration % document.options.output_encoding,
self.doctype,
self.html_head % document.options.language_code,
- self.content_type, # @@@ % output encoding
+ self.content_type % document.options.output_encoding,
self.generator,
self.stylesheet_link % document.options.stylesheet]
self.head = []
@@ -97,7 +94,8 @@ class HTMLTranslator(nodes.NodeVisitor):
def attval(self, text,
transtable=string.maketrans('\n\r\t\v\f', ' ')):
"""Cleanse, encode, and return attribute value text."""
- return self.encode(text.translate(transtable))
+ return self.encode(
+ text.encode('utf-8').translate(transtable).decode('utf-8'))
def starttag(self, node, tagname, suffix='\n', infix='', **attributes):
"""
--
cgit v1.2.1
From 8772c081ae9e24fd5ee41211847ed9afc8cf1872 Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 28 Jun 2002 04:18:12 +0000
Subject: - Added support for input and output encodings and for internal
Unicode support.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@220 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 11 ++++++-----
docutils/statemachine.py | 4 +++-
docutils/utils.py | 4 ++--
3 files changed, 11 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 6f6367cdd..9324814a3 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -25,7 +25,8 @@ import sys
import os
import re
import xml.dom.minidom
-from types import IntType, SliceType, StringType, TupleType, ListType
+from types import IntType, SliceType, StringType, UnicodeType, \
+ TupleType, ListType
from UserString import MutableString
@@ -298,7 +299,7 @@ class Element(Node):
return len(self.children)
def __getitem__(self, key):
- if isinstance(key, StringType):
+ if isinstance(key, UnicodeType) or isinstance(key, StringType):
return self.attributes[key]
elif isinstance(key, IntType):
return self.children[key]
@@ -310,8 +311,8 @@ class Element(Node):
'an attribute name string')
def __setitem__(self, key, item):
- if isinstance(key, StringType):
- self.attributes[key] = item
+ if isinstance(key, UnicodeType) or isinstance(key, StringType):
+ self.attributes[str(key)] = item
elif isinstance(key, IntType):
item.parent = self
self.children[key] = item
@@ -325,7 +326,7 @@ class Element(Node):
'an attribute name string')
def __delitem__(self, key):
- if isinstance(key, StringType):
+ if isinstance(key, UnicodeType) or isinstance(key, StringType):
del self.attributes[key]
elif isinstance(key, IntType):
del self.children[key]
diff --git a/docutils/statemachine.py b/docutils/statemachine.py
index e6502d3cd..e985e1f89 100644
--- a/docutils/statemachine.py
+++ b/docutils/statemachine.py
@@ -1028,7 +1028,9 @@ def string2lines(astring, tab_width=8, convert_whitespace=0):
- `convert_whitespace`: convert form feeds and vertical tabs to spaces?
"""
if convert_whitespace:
- astring = astring.translate(_whitespace_conversion_table)
+ encoded = astring.encode('utf-8')
+ converted = encoded.translate(_whitespace_conversion_table)
+ astring = converted.decode('utf-8')
return [s.expandtabs(tab_width) for s in astring.splitlines()]
def extract_indented(lines, until_blank=0, strip_indent=1):
diff --git a/docutils/utils.py b/docutils/utils.py
index 161526fa0..c2418d91c 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -237,7 +237,7 @@ def extract_attributes(field_list):
if len(field) != 2:
raise BadAttributeError(
'extension attribute field may not contain field arguments')
- name = field[0].astext().lower()
+ name = str(field[0].astext().lower())
body = field[1]
if len(body) == 0:
data = None
@@ -275,7 +275,7 @@ def assemble_attribute_dict(attlist, attspec):
try:
attributes[name] = convertor(value)
except (ValueError, TypeError), detail:
- raise detail.__class__('(attribute "%s", value "%r") %s'
+ raise detail.__class__('(attribute "%s", value "%s") %s'
% (name, value, detail))
return attributes
--
cgit v1.2.1
From eca63d0c7af69af08c0acc8e54b1d8e9fc97b88d Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 28 Jun 2002 04:19:02 +0000
Subject: - Fixed bug with literal blocks. - Added support for input and output
encodings and for internal Unicode support.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@221 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 543bc1108..aff499625 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -353,7 +353,7 @@ class RSTState(StateWS):
if data[-2:] == '::':
if len(data) == 2:
return [], 1
- elif data[-3] == ' ':
+ elif data[-3] in ' \n':
text = data[:-3].rstrip()
else:
text = data[:-1]
@@ -445,8 +445,6 @@ class Inliner:
uric = r"""[-_.!~*'()[\];/:@&=+$,%a-zA-Z0-9]"""
urilast = r"""[_~/\]a-zA-Z0-9]"""
emailc = r"""[-_!~*'{|}/#?^`&=+$%a-zA-Z0-9]"""
- identity = string.maketrans('', '')
- null2backslash = string.maketrans('\x00', '\\')
patterns = Stuff(
initial=re.compile(
r"""
@@ -970,8 +968,8 @@ class Body(RSTState):
if ordinal is None:
msg = self.reporter.error(
('Enumerated list start value invalid at line %s: '
- '%r (sequence %r)' % (self.state_machine.abs_line_number(),
- text, sequence)))
+ '"%s" (sequence %r)'
+ % (self.state_machine.abs_line_number(), text, sequence)))
self.parent += msg
indented, line_offset, blank_finish = \
self.state_machine.get_known_indented(match.end())
@@ -984,8 +982,8 @@ class Body(RSTState):
if ordinal != 1:
msg = self.reporter.info(
('Enumerated list start value not ordinal-1 at line %s: '
- '%r (ordinal %s)' % (self.state_machine.abs_line_number(),
- text, ordinal)))
+ '"%s" (ordinal %s)'
+ % (self.state_machine.abs_line_number(), text, ordinal)))
self.parent += msg
enumlist = nodes.enumerated_list()
self.parent += enumlist
@@ -1167,8 +1165,8 @@ class Body(RSTState):
optlist.append(option)
else:
raise MarkupError('wrong numer of option tokens (=%s), '
- 'should be 1 or 2: %r' % (len(tokens),
- optionstring))
+ 'should be 1 or 2: "%s"' % (len(tokens),
+ optionstring))
return optlist
def doctest(self, match, context, next_state):
@@ -2221,6 +2219,6 @@ def escape2null(text):
def unescape(text, restore_backslashes=0):
"""Return a string with nulls removed or restored to backslashes."""
if restore_backslashes:
- return text.translate(Inliner.null2backslash)
+ return text.replace('\x00', '\\')
else:
- return text.translate(Inliner.identity, '\x00')
+ return ''.join(text.split('\x00'))
--
cgit v1.2.1
From ce2f906d0b60ee6836aacc32bf2922e338b8a314 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 29 Jun 2002 00:39:38 +0000
Subject: docstrings
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@225 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 5 +++++
docutils/io.py | 2 ++
2 files changed, 7 insertions(+)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index 0ea2f1803..52a9e500b 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -21,8 +21,13 @@ Modules:
- frontend.py: Command-line and common processing for Docutils front-ends.
+- io.py: Provides a uniform API for low-level input and output.
+
- nodes.py: Docutils document tree (doctree) node class library.
+- optik.py: Option parsing and command-line help; from Greg Ward's
+ http://optik.sf.net/ project, included for convenience.
+
- roman.py: Conversion to and from Roman numerals. Courtesy of Mark
Pilgrim (http://diveintopython.org/).
diff --git a/docutils/io.py b/docutils/io.py
index 66845e7f7..689bf4d80 100644
--- a/docutils/io.py
+++ b/docutils/io.py
@@ -7,6 +7,8 @@
:Date: $Date$
:Copyright: This module has been placed in the public domain.
+I/O classes provide a uniform API for low-level input and output. Subclasses
+will exist for a variety of input/output mechanisms.
"""
__docformat__ = 'reStructuredText'
--
cgit v1.2.1
From b1493cab0b638bf3706cb9968d04fe300d7c3f53 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 29 Jun 2002 00:42:25 +0000
Subject: - In ``string2lines()``, changed whitespace normalizing translation
table to regexp; restores Python 2.0 compatibility with Unicode.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@226 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/statemachine.py | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/statemachine.py b/docutils/statemachine.py
index e985e1f89..621be35b5 100644
--- a/docutils/statemachine.py
+++ b/docutils/statemachine.py
@@ -1012,9 +1012,8 @@ class TransitionCorrection(Exception):
"""
-_whitespace_conversion_table = string.maketrans('\v\f', ' ')
-
-def string2lines(astring, tab_width=8, convert_whitespace=0):
+def string2lines(astring, tab_width=8, convert_whitespace=0,
+ whitespace=re.compile('[\v\f]')):
"""
Return a list of one-line strings with tabs expanded and no newlines.
@@ -1028,9 +1027,7 @@ def string2lines(astring, tab_width=8, convert_whitespace=0):
- `convert_whitespace`: convert form feeds and vertical tabs to spaces?
"""
if convert_whitespace:
- encoded = astring.encode('utf-8')
- converted = encoded.translate(_whitespace_conversion_table)
- astring = converted.decode('utf-8')
+ astring = whitespace.sub(' ', astring)
return [s.expandtabs(tab_width) for s in astring.splitlines()]
def extract_indented(lines, until_blank=0, strip_indent=1):
--
cgit v1.2.1
From c8ba33f6335505e047a030d9dacf2d3f01521719 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 29 Jun 2002 00:44:28 +0000
Subject: - In ``HTMLTranslator.attval()``, changed whitespace normalizing
translation table to regexp; restores Python 2.0 compatibility with
Unicode.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@227 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 97cc8b6ea..4c8a6d9cc 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -92,10 +92,9 @@ class HTMLTranslator(nodes.NodeVisitor):
return text
def attval(self, text,
- transtable=string.maketrans('\n\r\t\v\f', ' ')):
- """Cleanse, encode, and return attribute value text."""
- return self.encode(
- text.encode('utf-8').translate(transtable).decode('utf-8'))
+ whitespace=re.compile('[\n\r\t\v\f]')):
+ """Cleanse, HTML encode, and return attribute value text."""
+ return self.encode(whitespace.sub(' ', text))
def starttag(self, node, tagname, suffix='\n', infix='', **attributes):
"""
--
cgit v1.2.1
From c06d0f016cf4f539db28a4ea6142855cc7bb92aa Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 29 Jun 2002 23:07:42 +0000
Subject: Applied patch from Simon Budig, simplifying regexps by with symbolic
names. Also, Inliner.groups and Body.explicit.groups have been removed.
The patch pointed out a bug in interpreted text parsing code, to be resolved.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@232 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 198 ++++++++++++++++++-----------------------
1 file changed, 89 insertions(+), 109 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index aff499625..ffce6171b 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -402,10 +402,6 @@ class Inliner:
self.parent = parent
pattern = self.patterns.initial
dispatch = self.dispatch
- start = self.groups.initial.start - 1
- backquote = self.groups.initial.backquote - 1
- refend = self.groups.initial.refend - 1
- fnend = self.groups.initial.fnend - 1
remaining = escape2null(text)
processed = []
unprocessed = []
@@ -413,11 +409,11 @@ class Inliner:
while remaining:
match = pattern.search(remaining)
if match:
- groups = match.groups()
- before, inlines, remaining, sysmessages = \
- dispatch[groups[start] or groups[backquote]
- or groups[refend]
- or groups[fnend]](self, match, lineno)
+ groupdict = match.groupdict()
+ method = dispatch[groupdict["start"] or groupdict["backquote"]
+ or groupdict["refend"] or groupdict["fnend"]]
+ before, inlines, remaining, sysmessages = method(self, match,
+ lineno)
unprocessed.append(before)
messages += sysmessages
if inlines:
@@ -434,14 +430,12 @@ class Inliner:
openers = '\'"([{<'
closers = '\'")]}>'
- start_string_prefix = (r'(?:(?<=^)|(?<=[-/: \n%s]))'
- % re.escape(openers))
- end_string_suffix = (r'(?:(?=$)|(?=[-/:.,;!? \n%s]))'
- % re.escape(closers))
+ start_string_prefix = (r'((?<=^)|(?<=[-/: \n%s]))' % re.escape(openers))
+ end_string_suffix = (r'((?=$)|(?=[-/:.,;!? \n%s]))' % re.escape(closers))
non_whitespace_before = r'(? # start-strings only:
\*\* # strong
|
\* # emphasis
@@ -464,27 +458,27 @@ class Inliner:
)
%s # no whitespace after
| # *OR*
- ( # whole constructs (group 3):
- (%s) # reference name (4)
- (__?) # end-string (5)
+ (?P # whole constructs:
+ (?P%s) # reference name
+ (?P__?) # end-string
|
\[ # footnote_reference or
# citation_reference start
- ( # label (group 6):
+ (?P # label:
[0-9]+ # manually numbered
| # *OR*
- \#(?:%s)? # auto-numbered (w/ label?)
+ \#(%s)? # auto-numbered (w/ label?)
| # *OR*
\* # auto-symbol
| # *OR*
- (%s) # citation reference (group 7)
+ (?P%s) # citation reference
)
- (\]_) # end-string (group 8)
+ (?P\]_) # end-string
)
%s # end-string suffix
| # *OR*
- ((?::%s:)?) # optional role (group 9)
- ( # start-string (group 10)
+ (?P(:%s:)?) # optional role
+ (?P # start-string
` # interpreted text
# or phrase reference
(?!`) # but not literal
@@ -505,9 +499,9 @@ class Inliner:
strong=re.compile(non_whitespace_escape_before
+ r'(\*\*)' + end_string_suffix),
interpreted_or_phrase_ref=re.compile(
- '%s(`(:%s:|__?)?)%s' % (non_whitespace_escape_before,
- simplename,
- end_string_suffix)),
+ '%s(`(?P:%s:|__?)?)%s' % (non_whitespace_escape_before,
+ simplename,
+ end_string_suffix)),
literal=re.compile(non_whitespace_before + '(``)'
+ end_string_suffix),
target=re.compile(non_whitespace_escape_before
@@ -518,33 +512,33 @@ class Inliner:
uri=re.compile(
r"""
%s # start-string prefix
- (
- ( # absolute URI (group 2)
- ( # scheme (http, ftp, mailto)
- [a-zA-Z][a-zA-Z0-9.+-]* # (group 3)
+ (?P
+ (?P # absolute URI
+ (?P # scheme (http, ftp, mailto)
+ [a-zA-Z][a-zA-Z0-9.+-]*
)
:
- (?:
- (?: # either:
- (?://?)? # hierarchical URI
+ (
+ ( # either:
+ (//?)? # hierarchical URI
%s* # URI characters
%s # final URI char
)
- (?: # optional query
+ ( # optional query
\?%s* # URI characters
%s # final URI char
)?
- (?: # optional fragment
+ ( # optional fragment
\#%s* # URI characters
%s # final URI char
)?
)
)
| # *OR*
- ( # email address (group 4)
- %s+(?:\.%s+)* # name
+ (?P # email address
+ %s+(\.%s+)* # name
@ # at
- %s+(?:\.%s*)* # host
+ %s+(\.%s*)* # host
%s # final URI char
)
)
@@ -553,11 +547,6 @@ class Inliner:
uric, urilast, emailc, emailc, emailc, emailc, urilast,
end_string_suffix,),
re.VERBOSE))
- groups = Stuff(initial=Stuff(start=2, whole=3, refname=4, refend=5,
- footnotelabel=6, citationlabel=7,
- fnend=8, role=9, backquote=10),
- interpreted_or_phrase_ref=Stuff(suffix=2),
- uri=Stuff(whole=1, absolute=2, scheme=3, email=4))
def quoted_start(self, match):
"""Return 1 if inline markup start-string is 'quoted', 0 if not."""
@@ -581,8 +570,8 @@ class Inliner:
def inline_obj(self, match, lineno, pattern, nodeclass,
restore_backslashes=0):
string = match.string
- matchstart = match.start(self.groups.initial.start)
- matchend = match.end(self.groups.initial.start)
+ matchstart = match.start('start')
+ matchend = match.end('start')
if self.quoted_start(match):
return (string[:matchend], [], string[matchend:], [], '')
endmatch = pattern.search(string[matchend:])
@@ -621,13 +610,11 @@ class Inliner:
def interpreted_or_phrase_ref(self, match, lineno):
pattern = self.patterns.interpreted_or_phrase_ref
- rolegroup = self.groups.initial.role
- backquote = self.groups.initial.backquote
string = match.string
- matchstart = match.start(backquote)
- matchend = match.end(backquote)
- rolestart = match.start(rolegroup)
- role = match.group(rolegroup)
+ matchstart = match.start('backquote')
+ matchend = match.end('backquote')
+ rolestart = match.start('role')
+ role = match.group('role')
position = ''
if role:
role = role[1:-1]
@@ -680,13 +667,12 @@ class Inliner:
def interpreted(self, before, after, endmatch, role, position, lineno,
escaped, rawsource, text):
- suffix = self.groups.interpreted_or_phrase_ref.suffix
- if endmatch.group(suffix):
+ if endmatch.group('suffix'):
if role:
msg = self.reporter.warning('Multiple roles in interpreted '
'text at line %s.' % lineno)
return (before + rawsource, [], after, [msg])
- role = endmatch.group(suffix)[1:-1]
+ role = endmatch.group('suffix')[1:-1]
position = 'suffix'
if role:
atts = {'role': role, 'position': position}
@@ -743,9 +729,9 @@ class Inliner:
Handles `nodes.footnote_reference` and `nodes.citation_reference`
elements.
"""
- label = match.group(self.groups.initial.footnotelabel)
+ label = match.group('footnotelabel')
refname = normalize_name(label)
- if match.group(self.groups.initial.citationlabel):
+ if match.group('citationlabel'):
refnode = nodes.citation_reference('[%s]_' % label,
refname=refname)
refnode += nodes.Text(label)
@@ -767,16 +753,15 @@ class Inliner:
refnode['refname'] = refname
self.document.note_footnote_ref(refnode)
string = match.string
- matchstart = match.start(self.groups.initial.whole)
- matchend = match.end(self.groups.initial.whole)
+ matchstart = match.start('whole')
+ matchend = match.end('whole')
return (string[:matchstart], [refnode], string[matchend:], [])
def reference(self, match, lineno, anonymous=None):
- referencename = match.group(self.groups.initial.refname)
+ referencename = match.group('refname')
refname = normalize_name(referencename)
- referencenode = nodes.reference(
- referencename + match.group(self.groups.initial.refend),
- referencename)
+ referencenode = nodes.reference(referencename + match.group('refend'),
+ referencename)
if anonymous:
referencenode['anonymous'] = 1
self.document.note_anonymous_ref(referencenode)
@@ -784,22 +769,21 @@ class Inliner:
referencenode['refname'] = refname
self.document.note_refname(referencenode)
string = match.string
- matchstart = match.start(self.groups.initial.whole)
- matchend = match.end(self.groups.initial.whole)
+ matchstart = match.start('whole')
+ matchend = match.end('whole')
return (string[:matchstart], [referencenode], string[matchend:], [])
def anonymous_reference(self, match, lineno):
return self.reference(match, lineno, anonymous=1)
def standalone_uri(self, match, lineno):
- scheme = self.groups.uri.scheme
- if not match.group(scheme) or urischemes.schemes.has_key(
- match.group(scheme).lower()):
- if match.group(self.groups.uri.email):
+ if not match.group('scheme') or urischemes.schemes.has_key(
+ match.group('scheme').lower()):
+ if match.group('email'):
addscheme = 'mailto:'
else:
addscheme = ''
- text = match.group(self.groups.uri.whole)
+ text = match.group('whole')
unescaped = unescape(text, 0)
return [nodes.reference(unescape(text, 1), unescaped,
refuri=addscheme + unescaped)]
@@ -1289,54 +1273,52 @@ class Body(RSTState):
explicit.patterns = Stuff(
target=re.compile(r"""
- (?:
- _ # anonymous target
- | # *OR*
- (`?) # optional open quote
- (?![ `]) # first char. not space or backquote
- ( # reference name
+ (
+ _ # anonymous target
+ | # *OR*
+ (?P`?) # optional open quote
+ (?![ `]) # first char. not space or
+ # backquote
+ (?P # reference name
.+?
)
- %s # not whitespace or escape
- \1 # close quote if open quote used
+ %s # not whitespace or escape
+ (?P=quote) # close quote if open quote used
)
- %s # not whitespace or escape
- : # end of reference name
- (?:[ ]+|$) # followed by whitespace
+ %s # not whitespace or escape
+ : # end of reference name
+ ([ ]+|$) # followed by whitespace
"""
% (Inliner.non_whitespace_escape_before,
Inliner.non_whitespace_escape_before),
re.VERBOSE),
reference=re.compile(r"""
- (?:
- (%s)_ # simple reference name
- | # *OR*
- ` # open backquote
- (?![ ]) # not space
- (.+?) # hyperlink phrase
- %s # not whitespace or escape
- `_ # close backquote, reference mark
+ (
+ (?P%s)_ # simple reference name
+ | # *OR*
+ ` # open backquote
+ (?![ ]) # not space
+ (?P.+?) # hyperlink phrase
+ %s # not whitespace or escape
+ `_ # close backquote,
+ # reference mark
)
- $ # end of string
+ $ # end of string
""" %
(Inliner.simplename,
Inliner.non_whitespace_escape_before,),
re.VERBOSE),
substitution=re.compile(r"""
- (?:
- (?![ ]) # first char. not space
- (.+?) # substitution text
- %s # not whitespace or escape
- \| # close delimiter
+ (
+ (?![ ]) # first char. not space
+ (?P.+?) # substitution text
+ %s # not whitespace or escape
+ \| # close delimiter
)
- (?:[ ]+|$) # followed by whitespace
+ ([ ]+|$) # followed by whitespace
""" %
Inliner.non_whitespace_escape_before,
re.VERBOSE),)
- explicit.groups = Stuff(
- target=Stuff(quote=1, name=2),
- reference=Stuff(simple=1, phrase=2),
- substitution=Stuff(name=1))
def footnote(self, match):
indented, indent, offset, blank_finish = \
@@ -1382,7 +1364,6 @@ class Body(RSTState):
def hyperlink_target(self, match):
pattern = self.explicit.patterns.target
- namegroup = self.explicit.groups.target.name
lineno = self.state_machine.abs_line_number()
block, indent, offset, blank_finish = \
self.state_machine.get_first_known_indented(
@@ -1408,7 +1389,7 @@ class Body(RSTState):
refname = self.is_reference(reference)
if refname:
target = nodes.target(blocktext, '', refname=refname)
- self.add_target(targetmatch.group(namegroup), '', target)
+ self.add_target(targetmatch.group('name'), '', target)
self.document.note_indirect_target(target)
return [target], blank_finish
nodelist = []
@@ -1423,7 +1404,7 @@ class Body(RSTState):
else:
unescaped = unescape(reference)
target = nodes.target(blocktext, '')
- self.add_target(targetmatch.group(namegroup), unescaped, target)
+ self.add_target(targetmatch.group('name'), unescaped, target)
nodelist.append(target)
return nodelist, blank_finish
@@ -1431,8 +1412,7 @@ class Body(RSTState):
match = self.explicit.patterns.reference.match(normalize_name(reference))
if not match:
return None
- return unescape(match.group(self.explicit.groups.reference.simple)
- or match.group(self.explicit.groups.reference.phrase))
+ return unescape(match.group('simple') or match.group('phrase'))
def add_target(self, targetname, refuri, target):
if targetname:
@@ -1475,7 +1455,7 @@ class Body(RSTState):
if not block[0]:
del block[0]
offset += 1
- subname = subdefmatch.group(self.explicit.groups.substitution.name)
+ subname = subdefmatch.group('name')
name = normalize_name(subname)
substitutionnode = nodes.substitution_definition(
blocktext, name=name, alt=subname)
@@ -1592,13 +1572,13 @@ class Body(RSTState):
\* # auto-symbol footnote
)
\]
- (?:[ ]+|$) # whitespace or end of line
+ ([ ]+|$) # whitespace or end of line
""" % Inliner.simplename, re.VERBOSE)),
(citation,
re.compile(r"""
\.\.[ ]+ # explicit markup start
\[(%s)\] # citation label
- (?:[ ]+|$) # whitespace or end of line
+ ([ ]+|$) # whitespace or end of line
""" % Inliner.simplename, re.VERBOSE)),
(hyperlink_target,
re.compile(r"""
@@ -1617,7 +1597,7 @@ class Body(RSTState):
\.\.[ ]+ # explicit markup start
(%s) # directive name
:: # directive delimiter
- (?:[ ]+|$) # whitespace or end of line
+ ([ ]+|$) # whitespace or end of line
""" % Inliner.simplename, re.VERBOSE))]
def explicit_markup(self, match, context, next_state):
--
cgit v1.2.1
From 15717892479e478467487d48f4e2e5f43eb66d10 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:19:02 +0000
Subject: Added ``source_path`` & ``destination_path`` for later reference.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@239 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/io.py | 73 ++++++++++++++++++++++++++++++++--------------------------
1 file changed, 40 insertions(+), 33 deletions(-)
(limited to 'docutils')
diff --git a/docutils/io.py b/docutils/io.py
index 689bf4d80..13f9b996c 100644
--- a/docutils/io.py
+++ b/docutils/io.py
@@ -23,17 +23,22 @@ class IO:
Base class for abstract input/output wrappers.
"""
- source = None
- destination = None
-
- def __init__(self, options, source=None, destination=None):
- """
- :Parameters:
- - `options`: a `docutils.optik.Values` object.
- - `source`: identifies the source of input data.
- - `destination`: identifies the destination for output data.
- """
+ def __init__(self, options, source=None, source_path=None,
+ destination=None, destination_path=None):
self.options = options
+ """A `docutils.optik.Values` object."""
+
+ self.source = source
+ """The source of input data."""
+
+ self.source_path = source_path
+ """A text reference to the source."""
+
+ self.destination = destination
+ """The destination for output data."""
+
+ self.destination_path = destination_path
+ """A text reference to the destination."""
def __repr__(self):
return '%s: source=%r, destination=%r' % (self.__class__, self.source,
@@ -61,7 +66,7 @@ class IO:
try:
decoded = unicode(data, enc)
return decoded
- except UnicodeError:
+ except (UnicodeError, LookupError):
pass
raise UnicodeError(
'Unable to decode input data. Tried the following encodings: %s.'
@@ -71,32 +76,34 @@ class IO:
class FileIO(IO):
"""
- IO for single, simple files.
+ IO for single, simple file-like objects.
"""
- def __init__(self, options, source=None, destination=None):
+ def __init__(self, options, source=None, source_path=None,
+ destination=None, destination_path=None):
"""
:Parameters:
- - `source`: one of (a) a file-like object, which is read directly;
- (b) a path to a file, which is opened and then read; or (c)
- `None`, which implies `sys.stdin`.
- - `destination`: one of (a) a file-like object, which is written
- directly; (b) a path to a file, which is opened and then
- written; or (c) `None`, which implies `sys.stdout`.
- """
- IO.__init__(self, options)
- if hasattr(source, 'read'):
- self.source = source
- elif source is None:
- self.source = sys.stdin
- else:
- self.source = open(source)
- if hasattr(destination, 'write'):
- self.destination = destination
- elif destination is None:
- self.destination = sys.stdout
- else:
- self.destination = open(destination, 'w')
+ - `source`: either a file-like object (which is read directly), or
+ `None` (which implies `sys.stdin` if no `source_path` given).
+ - `source_path`: a path to a file, which is opened and then read.
+ - `destination`: either a file-like object (which is written
+ directly) or `None` (which implies `sys.stdout` if no
+ `destination_path` given).
+ - `destination_path`: a path to a file, which is opened and then
+ written.
+ """
+ IO.__init__(self, options, source, source_path, destination,
+ destination_path)
+ if source is None:
+ if source_path:
+ self.source = open(source_path)
+ else:
+ self.source = sys.stdin
+ if destination is None:
+ if destination_path:
+ self.destination = open(destination_path, 'w')
+ else:
+ self.destination = sys.stdout
def read(self, reader):
"""
--
cgit v1.2.1
From 606baf1b20ec93778e127d90c11d60321ea2ae4e Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:21:21 +0000
Subject: - Converted regexps from ``'%s' % var`` to ``'%(var)s' %
locals()``. - Fixed a bug in ``Inliner.interpreted_or_phrase_ref()``.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@240 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 192 ++++++++++++++++++++---------------------
1 file changed, 93 insertions(+), 99 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index ffce6171b..f3be937d6 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -400,18 +400,18 @@ class Inliner:
self.reporter = memo.reporter
self.document = memo.document
self.parent = parent
- pattern = self.patterns.initial
+ pattern_search = self.patterns.initial.search
dispatch = self.dispatch
remaining = escape2null(text)
processed = []
unprocessed = []
messages = []
while remaining:
- match = pattern.search(remaining)
+ match = pattern_search(remaining)
if match:
- groupdict = match.groupdict()
- method = dispatch[groupdict["start"] or groupdict["backquote"]
- or groupdict["refend"] or groupdict["fnend"]]
+ groups = match.groupdict()
+ method = dispatch[groups['start'] or groups['backquote']
+ or groups['refend'] or groups['fnend']]
before, inlines, remaining, sysmessages = method(self, match,
lineno)
unprocessed.append(before)
@@ -437,12 +437,12 @@ class Inliner:
non_whitespace_after = r'(?![ \n])'
simplename = r'[a-zA-Z0-9]([-_.a-zA-Z0-9]*[a-zA-Z0-9])?'
uric = r"""[-_.!~*'()[\];/:@&=+$,%a-zA-Z0-9]"""
- urilast = r"""[_~/\]a-zA-Z0-9]"""
+ urilast = r"""[_~/\]a-zA-Z0-9]""" # no punctuation
emailc = r"""[-_!~*'{|}/#?^`&=+$%a-zA-Z0-9]"""
patterns = Stuff(
initial=re.compile(
r"""
- %s # start-string prefix
+ %(start_string_prefix)s
(
(?P # start-strings only:
\*\* # strong
@@ -456,52 +456,53 @@ class Inliner:
|
\| # substitution_reference start
)
- %s # no whitespace after
+ %(non_whitespace_after)s
| # *OR*
(?P # whole constructs:
- (?P%s) # reference name
- (?P__?) # end-string
+ (?P%(simplename)s) # reference name
+ (?P__?) # end-string
|
\[ # footnote_reference or
# citation_reference start
(?P # label:
[0-9]+ # manually numbered
| # *OR*
- \#(%s)? # auto-numbered (w/ label?)
+ \#(%(simplename)s)? # auto-numbered (w/ label?)
| # *OR*
\* # auto-symbol
| # *OR*
- (?P%s) # citation reference
+ (?P
+ %(simplename)s) # citation reference
)
(?P\]_) # end-string
)
- %s # end-string suffix
+ %(end_string_suffix)s
| # *OR*
- (?P(:%s:)?) # optional role
+ (?P(:%(simplename)s:)?) # optional role
(?P # start-string
` # interpreted text
# or phrase reference
(?!`) # but not literal
)
- %s # no whitespace after
+ %(non_whitespace_after)s # no whitespace after
)
- """ % (start_string_prefix,
- non_whitespace_after,
- simplename,
- simplename,
- simplename,
- end_string_suffix,
- simplename,
- non_whitespace_after,),
- re.VERBOSE),
+ """ % locals(), re.VERBOSE),
emphasis=re.compile(non_whitespace_escape_before
+ r'(\*)' + end_string_suffix),
strong=re.compile(non_whitespace_escape_before
+ r'(\*\*)' + end_string_suffix),
interpreted_or_phrase_ref=re.compile(
- '%s(`(?P:%s:|__?)?)%s' % (non_whitespace_escape_before,
- simplename,
- end_string_suffix)),
+ r"""
+ %(non_whitespace_escape_before)s
+ (
+ `
+ (?P
+ (?P:%(simplename)s:)?
+ (?P__?)?
+ )
+ )
+ %(end_string_suffix)s
+ """ % locals(), re.VERBOSE),
literal=re.compile(non_whitespace_before + '(``)'
+ end_string_suffix),
target=re.compile(non_whitespace_escape_before
@@ -511,7 +512,7 @@ class Inliner:
+ end_string_suffix),
uri=re.compile(
r"""
- %s # start-string prefix
+ %(start_string_prefix)s
(?P
(?P # absolute URI
(?P # scheme (http, ftp, mailto)
@@ -521,32 +522,29 @@ class Inliner:
(
( # either:
(//?)? # hierarchical URI
- %s* # URI characters
- %s # final URI char
+ %(uric)s* # URI characters
+ %(urilast)s # final URI char
)
( # optional query
- \?%s* # URI characters
- %s # final URI char
+ \?%(uric)s*
+ %(urilast)s
)?
( # optional fragment
- \#%s* # URI characters
- %s # final URI char
+ \#%(uric)s*
+ %(urilast)s
)?
)
)
| # *OR*
(?P # email address
- %s+(\.%s+)* # name
- @ # at
- %s+(\.%s*)* # host
- %s # final URI char
+ %(emailc)s+(\.%(emailc)s+)* # name
+ @ # at
+ %(emailc)s+(\.%(emailc)s*)* # host
+ %(urilast)s # final URI char
)
)
- %s # end-string suffix
- """ % (start_string_prefix, uric, urilast, uric, urilast,
- uric, urilast, emailc, emailc, emailc, emailc, urilast,
- end_string_suffix,),
- re.VERBOSE))
+ %(end_string_suffix)s
+ """ % locals(), re.VERBOSE))
def quoted_start(self, match):
"""Return 1 if inline markup start-string is 'quoted', 0 if not."""
@@ -567,22 +565,21 @@ class Inliner:
pass
return 0
- def inline_obj(self, match, lineno, pattern, nodeclass,
+ def inline_obj(self, match, lineno, end_pattern, nodeclass,
restore_backslashes=0):
string = match.string
matchstart = match.start('start')
matchend = match.end('start')
if self.quoted_start(match):
return (string[:matchend], [], string[matchend:], [], '')
- endmatch = pattern.search(string[matchend:])
+ endmatch = end_pattern.search(string[matchend:])
if endmatch and endmatch.start(1): # 1 or more chars
text = unescape(endmatch.string[:endmatch.start(1)],
restore_backslashes)
- rawsource = unescape(string[matchstart:matchend+endmatch.end(1)],
- 1)
+ textend = matchend + endmatch.end(1)
+ rawsource = unescape(string[matchstart:textend], 1)
return (string[:matchstart], [nodeclass(rawsource, text)],
- string[matchend:][endmatch.end(1):], [],
- endmatch.group(1))
+ string[textend:], [], endmatch.group(1))
msg = self.reporter.warning(
'Inline %s start-string without end-string '
'at line %s.' % (nodeclass.__name__, lineno))
@@ -609,7 +606,7 @@ class Inliner:
return before, inlines, remaining, sysmessages
def interpreted_or_phrase_ref(self, match, lineno):
- pattern = self.patterns.interpreted_or_phrase_ref
+ end_pattern = self.patterns.interpreted_or_phrase_ref
string = match.string
matchstart = match.start('backquote')
matchend = match.end('backquote')
@@ -621,40 +618,44 @@ class Inliner:
position = 'prefix'
elif self.quoted_start(match):
return (string[:matchend], [], string[matchend:], [])
- endmatch = pattern.search(string[matchend:])
+ endmatch = end_pattern.search(string[matchend:])
if endmatch and endmatch.start(1): # 1 or more chars
+ textend = matchend + endmatch.end()
+ if endmatch.group('role'):
+ if role:
+ msg = self.reporter.warning(
+ 'Multiple roles in interpreted text at line %s (both '
+ 'prefix and suffix present; only one allowed).'
+ % lineno)
+ text = unescape(string[rolestart:textend], 1)
+ prb = self.problematic(text, text, msg)
+ return string[:rolestart], [prb], string[textend:], [msg]
+ role = endmatch.group('suffix')[1:-1]
+ position = 'suffix'
escaped = endmatch.string[:endmatch.start(1)]
text = unescape(escaped, 0)
- rawsource = unescape(
- string[match.start():matchend+endmatch.end()], 1)
+ rawsource = unescape(string[matchstart:textend], 1)
if rawsource[-1:] == '_':
if role:
msg = self.reporter.warning(
- 'Mismatch: inline interpreted text start-string and'
- ' role with phrase-reference end-string at line %s.'
- % lineno)
- text = unescape(string[matchstart:matchend], 1)
- rawsource = unescape(string[matchstart:matchend], 1)
- prb = self.problematic(text, rawsource, msg)
- return (string[:matchstart], [prb], string[matchend:],
- [msg])
- return self.phrase_ref(
- string[:matchstart], string[matchend:][endmatch.end():],
- text, rawsource)
+ 'Mismatch: both interpreted text role %s and '
+ 'reference suffix at line %s.' % (position, lineno))
+ text = unescape(string[rolestart:textend], 1)
+ prb = self.problematic(text, text, msg)
+ return string[:rolestart], [prb], string[textend:], [msg]
+ return self.phrase_ref(string[:matchstart], string[textend:],
+ rawsource, text)
else:
- return self.interpreted(
- string[:rolestart], string[matchend:][endmatch.end():],
- endmatch, role, position, lineno,
- escaped, rawsource, text)
+ return self.interpreted(string[:rolestart], string[textend:],
+ rawsource, text, role, position)
msg = self.reporter.warning(
'Inline interpreted text or phrase reference start-string '
'without end-string at line %s.' % lineno)
text = unescape(string[matchstart:matchend], 1)
- rawsource = unescape(string[matchstart:matchend], 1)
- prb = self.problematic(text, rawsource, msg)
+ prb = self.problematic(text, text, msg)
return string[:matchstart], [prb], string[matchend:], [msg]
- def phrase_ref(self, before, after, text, rawsource):
+ def phrase_ref(self, before, after, rawsource, text):
refname = normalize_name(text)
reference = nodes.reference(rawsource, text)
if rawsource[-2:] == '__':
@@ -665,15 +666,7 @@ class Inliner:
self.document.note_refname(reference)
return before, [reference], after, []
- def interpreted(self, before, after, endmatch, role, position, lineno,
- escaped, rawsource, text):
- if endmatch.group('suffix'):
- if role:
- msg = self.reporter.warning('Multiple roles in interpreted '
- 'text at line %s.' % lineno)
- return (before + rawsource, [], after, [msg])
- role = endmatch.group('suffix')[1:-1]
- position = 'suffix'
+ def interpreted(self, before, after, rawsource, text, role, position):
if role:
atts = {'role': role, 'position': position}
else:
@@ -797,7 +790,8 @@ class Inliner:
"""
Check each of the patterns in `self.implicit` for a match, and
dispatch to the stored method for the pattern. Recursively check the
- text before and after the match.
+ text before and after the match. Return a list of `nodes.Text` and
+ inline element nodes.
"""
if not text:
return []
@@ -805,13 +799,20 @@ class Inliner:
match = pattern.search(text)
if match:
try:
- return (self.implicit_inline(text[:match.start()], lineno)
+ return (self.text(text[:match.start()])
+ dispatch(self, match, lineno) +
self.implicit_inline(text[match.end():], lineno))
except MarkupMismatch:
pass
return [nodes.Text(unescape(text))]
+ def text(self, text):
+ """Return a list containing one `nodes.Text` node or nothing."""
+ if not text:
+ return []
+ return [nodes.Text(unescape(text))]
+
+
dispatch = {'*': emphasis,
'**': strong,
'`': interpreted_or_phrase_ref,
@@ -1282,43 +1283,35 @@ class Body(RSTState):
(?P # reference name
.+?
)
- %s # not whitespace or escape
+ %(non_whitespace_escape_before)s
(?P=quote) # close quote if open quote used
)
- %s # not whitespace or escape
+ %(non_whitespace_escape_before)s
: # end of reference name
([ ]+|$) # followed by whitespace
- """
- % (Inliner.non_whitespace_escape_before,
- Inliner.non_whitespace_escape_before),
- re.VERBOSE),
+ """ % vars(Inliner), re.VERBOSE),
reference=re.compile(r"""
(
- (?P%s)_ # simple reference name
+ (?P%(simplename)s)_
| # *OR*
` # open backquote
(?![ ]) # not space
(?P.+?) # hyperlink phrase
- %s # not whitespace or escape
+ %(non_whitespace_escape_before)s
`_ # close backquote,
# reference mark
)
$ # end of string
- """ %
- (Inliner.simplename,
- Inliner.non_whitespace_escape_before,),
- re.VERBOSE),
+ """ % vars(Inliner), re.VERBOSE),
substitution=re.compile(r"""
(
(?![ ]) # first char. not space
(?P.+?) # substitution text
- %s # not whitespace or escape
+ %(non_whitespace_escape_before)s
\| # close delimiter
)
([ ]+|$) # followed by whitespace
- """ %
- Inliner.non_whitespace_escape_before,
- re.VERBOSE),)
+ """ % vars(Inliner), re.VERBOSE),)
def footnote(self, match):
indented, indent, offset, blank_finish = \
@@ -1409,7 +1402,8 @@ class Body(RSTState):
return nodelist, blank_finish
def is_reference(self, reference):
- match = self.explicit.patterns.reference.match(normalize_name(reference))
+ match = self.explicit.patterns.reference.match(
+ normalize_name(reference))
if not match:
return None
return unescape(match.group('simple') or match.group('phrase'))
--
cgit v1.2.1
From 426ed7ac0d7dc20b8dcd6df6c91b5f3627078227 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:22:14 +0000
Subject: Fixed source reference; bug pointed out by Simon Budig.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@241 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/readers/__init__.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/readers/__init__.py b/docutils/readers/__init__.py
index 053527faf..fbd0ee8fc 100644
--- a/docutils/readers/__init__.py
+++ b/docutils/readers/__init__.py
@@ -86,7 +86,8 @@ class Reader(Component):
def new_document(self):
"""Create and return a new empty document tree (root node)."""
document = utils.new_document(self.options)
- document['source'] = self.source
+ if self.source.source_path:
+ document['source'] = self.source.source_path
return document
--
cgit v1.2.1
From 9830aac6db5c209b7b022e61dbdcb76540b14acf Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:23:50 +0000
Subject: Rearranged footer.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@242 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index e9553cb13..e4ad65b48 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -57,6 +57,14 @@ class Decorations(Transform):
options = self.document.options
if options.generator or options.datestamp or options.source_link:
text = []
+ if options.source_link and self.document.hasattr('source'):
+ text.extend([
+ nodes.reference('', 'View document source',
+ refuri=self.document['source']),
+ nodes.Text('. ')])
+ if options.datestamp:
+ datestamp = time.strftime(options.datestamp, time.gmtime())
+ text.append(nodes.Text('Generated on: ' + datestamp + '. '))
if options.generator:
text.extend([
nodes.Text('Generated by '),
@@ -66,14 +74,6 @@ class Decorations(Transform):
nodes.reference('', 'reStructuredText', refuri='http://'
'docutils.sourceforge.net/rst.html'),
nodes.Text(' source. ')])
- if options.source_link:
- text.extend([
- nodes.reference('', 'View document source',
- refuri=self.document['source']),
- nodes.Text('. ')])
- if options.datestamp:
- datestamp = time.strftime(options.datestamp, time.gmtime())
- text.append(nodes.Text('Date: ' + datestamp + '. '))
footer = nodes.footer()
footer += nodes.paragraph('', '', *text)
return footer
--
cgit v1.2.1
From 08508d8729f833bab10c4b382a013c523e5837f9 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:25:05 +0000
Subject: Added "xml" alias.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@243 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/__init__.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/__init__.py b/docutils/writers/__init__.py
index 24d1cf384..4dabe2241 100644
--- a/docutils/writers/__init__.py
+++ b/docutils/writers/__init__.py
@@ -84,7 +84,8 @@ _writer_aliases = {
'html': 'html4css1',
'pprint': 'pseudoxml',
'pformat': 'pseudoxml',
- 'pdf': 'rlpdf',}
+ 'pdf': 'rlpdf',
+ 'xml': 'docutils_xml',}
def get_writer_class(writer_name):
"""Return the Writer class from the `writer_name` module."""
--
cgit v1.2.1
From 094e23351675a455639b6a313c43a344d69628e8 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:25:46 +0000
Subject: Added to project; trivial writer of the Docutils internal doctree in
XML.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@244 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/docutils_xml.py | 43 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 docutils/writers/docutils_xml.py
(limited to 'docutils')
diff --git a/docutils/writers/docutils_xml.py b/docutils/writers/docutils_xml.py
new file mode 100644
index 000000000..698908b27
--- /dev/null
+++ b/docutils/writers/docutils_xml.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python
+
+"""
+:Authors: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Simple internal document tree Writer, writes Docutils XML.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+from docutils import writers
+
+
+class Writer(writers.Writer):
+
+ supported = ('xml',)
+ """Formats this writer supports."""
+
+ cmdline_options = (
+ '"Docutils XML" Writer Options',
+ 'Warning: these options may adversely affect whitespace; use them '
+ 'only for reading convenience.',
+ (('Generate XML with newlines before and after tags.',
+ ['--newlines'], {'action': 'store_true'}),
+ ('Generate XML with indents and newlines.',
+ ['--indents'], {'action': 'store_true'}),),)
+
+ output = None
+ """Final translated form of `document`."""
+
+ def translate(self):
+ indent = newline = ''
+ if self.document.options.newlines:
+ newline = '\n'
+ if self.document.options.indents:
+ newline = '\n'
+ indent = ' '
+ self.output = self.document.asdom().toprettyxml(indent, newline)
--
cgit v1.2.1
From 46c86afe527c5cfa915ea67b42737494971dde83 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:26:57 +0000
Subject: Exposed modular output in Writer class.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@245 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 4c8a6d9cc..cda74eb0c 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -19,7 +19,6 @@ __docformat__ = 'reStructuredText'
import sys
import time
-import string
import re
from types import ListType
from docutils import writers, nodes, languages
@@ -44,6 +43,11 @@ class Writer(writers.Writer):
visitor = HTMLTranslator(self.document)
self.document.walkabout(visitor)
self.output = visitor.astext()
+ self.head_prefix = visitor.head_prefix
+ self.head = visitor.head
+ self.body_prefix = visitor.body_prefix
+ self.body = visitor.body
+ self.body_suffix = visitor.body_suffix
class HTMLTranslator(nodes.NodeVisitor):
--
cgit v1.2.1
From be8b2373908f3c5f02b983b0f65016a0911ad921 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 4 Jul 2002 01:36:18 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@248 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 6 +++---
docutils/statemachine.py | 1 -
2 files changed, 3 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index c0f9f4375..27a0e60b6 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -101,9 +101,9 @@ class Publisher:
if argv is None:
argv = sys.argv[1:]
self.options, source, destination = option_parser.parse_args(argv)
- self.source = self.source_class(self.options, source=source)
- self.destination = self.destination_class(self.options,
- destination=destination)
+ self.source = self.source_class(self.options, source_path=source)
+ self.destination = self.destination_class(
+ self.options, destination_path=destination)
def publish(self, argv=None, usage=None, description=None,
option_spec=None):
diff --git a/docutils/statemachine.py b/docutils/statemachine.py
index 621be35b5..b8496d3e0 100644
--- a/docutils/statemachine.py
+++ b/docutils/statemachine.py
@@ -107,7 +107,6 @@ __docformat__ = 'restructuredtext'
import sys
import re
-import string
class StateMachine:
--
cgit v1.2.1
From 5c1d1c93ddd584c9e2217a122f6650bc86de2543 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 6 Jul 2002 02:55:23 +0000
Subject: twiddled
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@253 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index cda74eb0c..956303fad 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -34,7 +34,7 @@ class Writer(writers.Writer):
None,
(('Specify a stylesheet file. Default is "default.css".',
['--stylesheet'],
- {'default': 'default.css', 'metavar': ''}),),)
+ {'default': 'default.css', 'metavar': ''}),))
output = None
"""Final translated form of `document`."""
@@ -78,7 +78,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body_prefix = ['\n\n']
self.body = []
self.body_suffix = ['\n\n']
- self.sectionlevel = 0
+ self.section_level = 0
self.context = []
self.topic_class = ''
@@ -667,11 +667,11 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('\n')
def visit_section(self, node):
- self.sectionlevel += 1
+ self.section_level += 1
self.body.append(self.starttag(node, 'div', CLASS='section'))
def depart_section(self, node):
- self.sectionlevel -= 1
+ self.section_level -= 1
self.body.append('\n')
def visit_status(self, node):
@@ -787,19 +787,20 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append(
self.starttag(node, 'p', '', CLASS='topic-title'))
self.context.append('
\n')
- elif self.sectionlevel == 0:
+ elif self.section_level == 0:
+ # document title
self.head.append('%s\n'
% self.encode(node.astext()))
self.body.append(self.starttag(node, 'h1', '', CLASS='title'))
self.context.append('\n')
else:
self.body.append(
- self.starttag(node, 'h%s' % self.sectionlevel, ''))
+ self.starttag(node, 'h%s' % self.section_level, ''))
context = ''
if node.hasattr('refid'):
self.body.append('' % node['refid'])
context = ''
- self.context.append('%s\n' % (context, self.sectionlevel))
+ self.context.append('%s\n' % (context, self.section_level))
def depart_title(self, node):
self.body.append(self.context.pop())
--
cgit v1.2.1
From 4a0d5fdbd47b04f30b3de5190ab3914f3cfb301c Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 6 Jul 2002 02:56:38 +0000
Subject: Added NodeFound exception, for use in Visitors.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@254 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 11 +++++++++++
1 file changed, 11 insertions(+)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 9324814a3..5a640daca 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -1258,6 +1258,17 @@ class SkipDeparture(TreePruningException):
pass
+class NodeFound(TreePruningException):
+
+ """
+ Raise to indicate that the target of a search has been found. This
+ exception must be caught by the client; it is not caught by the traversal
+ code.
+ """
+
+ pass
+
+
def make_id(string):
"""
Convert `string` into an identifier and return it.
--
cgit v1.2.1
From 0f210b84d6279337e7897f79d66ce7cf08729b94 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 6 Jul 2002 03:00:23 +0000
Subject: Modified ``IO.decode()`` encoding order and prepared for failure.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@255 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/io.py | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
(limited to 'docutils')
diff --git a/docutils/io.py b/docutils/io.py
index 13f9b996c..91bd436f7 100644
--- a/docutils/io.py
+++ b/docutils/io.py
@@ -55,11 +55,19 @@ class IO:
Decode a string, `data`, heuristically.
Raise UnicodeError if unsuccessful.
"""
- encodings = [self.options.input_encoding,
- locale.getlocale()[1],
- 'utf-8',
- locale.getdefaultlocale()[1],]
- # is locale.getdefaultlocale() platform-specific?
+ encodings = [self.options.input_encoding, 'utf-8']
+ try:
+ encodings.append(locale.nl_langinfo(locale.CODESET))
+ except:
+ pass
+ try:
+ encodings.append(locale.getlocale()[1])
+ except:
+ pass
+ try:
+ encodings.append(locale.getdefaultlocale()[1])
+ except:
+ pass
for enc in encodings:
if not enc:
continue
--
cgit v1.2.1
From 9a98f9a98ee1aec3a1e67a6e84bc5286814501f8 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 6 Jul 2002 03:01:17 +0000
Subject: Changed "--report" and "--halt" options to "choice" type.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@256 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index cb0a11681..0e1158024 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -22,6 +22,12 @@ class OptionParser(optik.OptionParser):
Parser for command-line and library use. The `cmdline_options` specification here and in other Docutils components are merged
"""
+ threshold_choices = 'info 1 warning 2 error 3 severe 4 none 5'.split()
+ """Possible inputs for for --report and --halt threshold values."""
+
+ thresholds = {'info': 1, 'warning': 2, 'error': 3, 'severe': 4, 'none': 5}
+ """Lookup table for --report and --halt threshold values."""
+
cmdline_options = (
'General Docutils Options',
None,
@@ -47,9 +53,9 @@ class OptionParser(optik.OptionParser):
'dest': 'source_link'}),
('Set verbosity threshold; report system messages at or higher than '
' (by name or number: "info" or "1", warning/2, error/3, '
- 'severe/4; also, "none" or 5+). Default is 2 (warning).',
- ['--report', '-r'], {'dest': 'report_level', 'default': 2,
- 'metavar': ''}),
+ 'severe/4; also, "none" or "5"). Default is 2 (warning).',
+ ['--report', '-r'], {'choices': threshold_choices, 'default': 2,
+ 'dest': 'report_level', 'metavar': ''}),
('Report all system messages, info-level and higher. (Same as '
'"--report=info".)',
['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
@@ -57,8 +63,8 @@ class OptionParser(optik.OptionParser):
('Set the threshold () at or above which system messages are '
'converted to exceptions, halting execution immediately. Levels '
'as in --report. Default is 4 (severe).',
- ['--halt'], {'dest': 'halt_level', 'default': 4,
- 'metavar': ''}),
+ ['--halt'], {'choices': threshold_choices, 'dest': 'halt_level',
+ 'default': 4, 'metavar': ''}),
('Same as "--halt=info": halt processing at the slightest problem.',
['--strict'], {'action': 'store_const', 'const': 'info',
'dest': 'halt_level'}),
@@ -92,9 +98,6 @@ class OptionParser(optik.OptionParser):
list of single options. Option specs from Docutils components are also
used (see `populate_from_components()`)."""
- thresholds = {'info': 1, 'warning': 2, 'error': 3, 'severe': 4, 'none': 5}
- """Lookup table for --report and --halt threshold values."""
-
version_template = '%%prog (Docutils %s)' % docutils.__version__
def __init__(self, components=(), defaults={}, *args, **kwargs):
--
cgit v1.2.1
From e521880b4a16e6500b171d673e1c6ef50d92e7e2 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 11 Jul 2002 01:49:35 +0000
Subject: - Allowed non-ASCII in "simple names" (directive names, field
names, references, etc.).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@262 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index f3be937d6..12174c5de 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -435,7 +435,7 @@ class Inliner:
non_whitespace_before = r'(?
Date: Thu, 11 Jul 2002 01:50:40 +0000
Subject: In ``DocInfo.extract_authors``, check for a single "author" in an
"authors" group, and convert it to a single "author" element.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@263 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/frontmatter.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/frontmatter.py b/docutils/transforms/frontmatter.py
index c5aaa0d1e..f61e828a1 100644
--- a/docutils/transforms/frontmatter.py
+++ b/docutils/transforms/frontmatter.py
@@ -328,7 +328,12 @@ class DocInfo(Transform):
authors = self.authors_from_paragraphs(field)
authornodes = [nodes.author('', '', *author)
for author in authors if author]
- docinfo.append(nodes.authors('', *authornodes))
+ if len(authornodes) > 1:
+ docinfo.append(nodes.authors('', *authornodes))
+ elif len(authornodes) == 1:
+ docinfo.append(authornodes[0])
+ else:
+ raise TransformError
except TransformError:
field[-1] += self.document.reporter.warning(
'Bibliographic field "%s" incompatible with extraction: '
@@ -348,7 +353,7 @@ class DocInfo(Transform):
if len(authornames) > 1:
break
authornames = [author.strip() for author in authornames]
- authors = [[nodes.Text(author)] for author in authornames]
+ authors = [[nodes.Text(author)] for author in authornames if author]
return authors
def authors_from_bullet_list(self, field):
--
cgit v1.2.1
From a71975394bb6d99904ae388d33e481e8e77709bf Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 11 Jul 2002 01:52:21 +0000
Subject: Added "name" attribute to TOC topic depending on its title.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@264 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/parts.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index 7a6d97219..8543de1ca 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -45,17 +45,20 @@ class Contents(Transform):
# section/document top-level? Drag it up until it is?
while not isinstance(startnode, nodes.Structural):
startnode = startnode.parent
- if not title:
- title = []
else:
startnode = self.document
if not title:
title = nodes.title('', self.language.labels['contents'])
contents = self.build_contents(startnode)
if len(contents):
- topic += title
+ if title:
+ topic['name'] = title.astext()
+ topic += title
+ else:
+ topic['name'] = self.language.labels['contents']
topic += contents
self.startnode.parent.replace(self.startnode, topic)
+ self.document.note_implicit_target(topic)
else:
self.startnode.parent.remove(self.startnode)
--
cgit v1.2.1
From 0cd6e450ebc86185487cadf3a91fbffcbfa0fd1e Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 13 Jul 2002 02:56:19 +0000
Subject: Added ``NullIO`` class. Added docstrings. Simplified.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@270 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/io.py | 44 +++++++++++++++++++++-----------------------
1 file changed, 21 insertions(+), 23 deletions(-)
(limited to 'docutils')
diff --git a/docutils/io.py b/docutils/io.py
index 91bd436f7..aa9d27c41 100644
--- a/docutils/io.py
+++ b/docutils/io.py
@@ -84,7 +84,7 @@ class IO:
class FileIO(IO):
"""
- IO for single, simple file-like objects.
+ I/O for single, simple file-like objects.
"""
def __init__(self, options, source=None, source_path=None,
@@ -114,16 +114,12 @@ class FileIO(IO):
self.destination = sys.stdout
def read(self, reader):
- """
- Read and decode a single file and return the data.
- """
+ """Read and decode a single file and return the data."""
data = self.source.read()
return self.decode(data)
def write(self, data):
- """
- Encode and write `data` to a single file.
- """
+ """Encode and write `data` to a single file."""
output = data.encode(self.options.output_encoding)
self.destination.write(output)
@@ -131,27 +127,29 @@ class FileIO(IO):
class StringIO(IO):
"""
- Direct string IO.
+ Direct string I/O.
"""
- def __init__(self, options, source=None, destination=None):
- """
- :Parameters:
- - `source`: a string containing input data.
- - `destination`: not used.
- """
- IO.__init__(self, options)
- self.source = source
-
def read(self, reader):
- """
- Decode and return the source string.
- """
+ """Decode and return the source string."""
return self.decode(self.source)
def write(self, data):
- """
- Encode and return `data`.
- """
+ """Encode and return `data`."""
self.destination = data.encode(self.options.output_encoding)
return self.destination
+
+
+class NullIO(IO):
+
+ """
+ Degenerate I/O: read & write nothing.
+ """
+
+ def read(self, reader):
+ """Return a null string."""
+ return u''
+
+ def write(self, data):
+ """Do nothing (send data to the bit bucket)."""
+ pass
--
cgit v1.2.1
From 5f80cbfd8f3d292c3de19c67b658127df3dd9e92 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 13 Jul 2002 02:57:11 +0000
Subject: Added ``document.has_name()`` method.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@271 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 3 +++
1 file changed, 3 insertions(+)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 5a640daca..84ce615a3 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -710,6 +710,9 @@ class document(Root, Structural, Element):
backrefs=[id])
msgnode += msg
+ def has_name(self, name):
+ return self.nameids.has_key(name)
+
def note_implicit_target(self, target, msgnode=None):
id = self.set_id(target, msgnode)
self.set_name_id_map(target, id, msgnode, explicit=None)
--
cgit v1.2.1
From a30c5f64519795f4e64b3475910bdad9d84f8270 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 13 Jul 2002 02:58:45 +0000
Subject: Fixed TOC "name" attribute.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@272 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/parts.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index 8543de1ca..d109d3552 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -52,12 +52,15 @@ class Contents(Transform):
contents = self.build_contents(startnode)
if len(contents):
if title:
- topic['name'] = title.astext()
+ name = title.astext()
topic += title
else:
- topic['name'] = self.language.labels['contents']
+ name = self.language.labels['contents']
topic += contents
self.startnode.parent.replace(self.startnode, topic)
+ name = utils.normalize_name(name)
+ if not self.document.has_name(name):
+ topic['name'] = name
self.document.note_implicit_target(topic)
else:
self.startnode.parent.remove(self.startnode)
--
cgit v1.2.1
From 36e8c4fdb6ac9dc864c9afea3486f259b55b1137 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 13 Jul 2002 02:59:13 +0000
Subject: docstring
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@273 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/peps.py | 1 +
1 file changed, 1 insertion(+)
(limited to 'docutils')
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
index 2c51fa861..70775c930 100644
--- a/docutils/transforms/peps.py
+++ b/docutils/transforms/peps.py
@@ -26,6 +26,7 @@ from docutils.transforms import Transform, TransformError
class Headers(Transform):
"""
+ Process fields in a PEP's initial RFC-2822 header.
"""
pep_cvs_url = ('http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/'
--
cgit v1.2.1
From 88804d77d0b560dbc7b80893770b052dfc765c37 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 13 Jul 2002 03:05:45 +0000
Subject: - Converted ``Inliner.patterns.initial`` to be dynamically built
from parts with ``build_regexp()`` function. - Changed
``Inliner.inline_target`` to ``.inline_internal_target``.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@275 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 103 +++++++++++++++++++++--------------------
1 file changed, 53 insertions(+), 50 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 12174c5de..6c26b779b 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -105,7 +105,7 @@ __docformat__ = 'reStructuredText'
import sys
import re
-import string
+from types import TupleType
from docutils import nodes, statemachine, utils, roman, urischemes
from docutils import ApplicationError, DataError
from docutils.statemachine import StateMachineWS, StateWS
@@ -377,6 +377,29 @@ class RSTState(StateWS):
% (node_name, self.state_machine.abs_line_number() + 1)))
+def build_regexp(definition, compile=1):
+ """
+ Build, compile and return a regular expression based on `definition`.
+
+ :Parameter: `definition`: a 4-tuple (group name, prefix, suffix, parts),
+ where "parts" is a list of regular expressions and/or regular
+ expression definitions to be joined into an or-group.
+ """
+ name, prefix, suffix, parts = definition
+ part_strings = []
+ for part in parts:
+ if type(part) is TupleType:
+ part_strings.append(build_regexp(part, None))
+ else:
+ part_strings.append(part)
+ or_group = '|'.join(part_strings)
+ regexp = '%(prefix)s(?P<%(name)s>%(or_group)s)%(suffix)s' % locals()
+ if compile:
+ return re.compile(regexp, re.UNICODE)
+ else:
+ return regexp
+
+
class Inliner:
"""
@@ -439,54 +462,34 @@ class Inliner:
uric = r"""[-_.!~*'()[\];/:@&=+$,%a-zA-Z0-9]"""
urilast = r"""[_~/\]a-zA-Z0-9]""" # no punctuation
emailc = r"""[-_!~*'{|}/#?^`&=+$%a-zA-Z0-9]"""
+ parts = ('initial_inline', start_string_prefix, '',
+ [('start', '', non_whitespace_after, # simple start-strings
+ [r'\*\*', # strong
+ r'\*(?!\*)', # emphasis but not strong
+ r'``', # literal
+ r'_`', # inline internal target
+ r'\|'] # substitution reference
+ ),
+ ('whole', '', end_string_suffix, # whole constructs
+ [# reference name & end-string
+ r'(?P%s)(?P__?)' % simplename,
+ ('footnotelabel', r'\[', r'(?P\]_)',
+ [r'[0-9]+', # manually numbered
+ r'\#(%s)?' % simplename, # auto-numbered (w/ label?)
+ r'\*', # auto-symbol
+ r'(?P%s)' % simplename] # citation reference
+ )
+ ]
+ ),
+ ('backquote', # interpreted text or phrase reference
+ '(?P(:%s:)?)' % simplename, # optional role
+ non_whitespace_after,
+ ['`(?!`)'] # but not literal
+ )
+ ]
+ )
patterns = Stuff(
- initial=re.compile(
- r"""
- %(start_string_prefix)s
- (
- (?P # start-strings only:
- \*\* # strong
- |
- \* # emphasis
- (?!\*) # but not strong
- |
- `` # literal
- |
- _` # inline hyperlink target
- |
- \| # substitution_reference start
- )
- %(non_whitespace_after)s
- | # *OR*
- (?P # whole constructs:
- (?P%(simplename)s) # reference name
- (?P__?) # end-string
- |
- \[ # footnote_reference or
- # citation_reference start
- (?P # label:
- [0-9]+ # manually numbered
- | # *OR*
- \#(%(simplename)s)? # auto-numbered (w/ label?)
- | # *OR*
- \* # auto-symbol
- | # *OR*
- (?P
- %(simplename)s) # citation reference
- )
- (?P\]_) # end-string
- )
- %(end_string_suffix)s
- | # *OR*
- (?P(:%(simplename)s:)?) # optional role
- (?P # start-string
- ` # interpreted text
- # or phrase reference
- (?!`) # but not literal
- )
- %(non_whitespace_after)s # no whitespace after
- )
- """ % locals(), re.VERBOSE | re.UNICODE),
+ initial=build_regexp(parts),
emphasis=re.compile(non_whitespace_escape_before
+ r'(\*)' + end_string_suffix),
strong=re.compile(non_whitespace_escape_before
@@ -679,7 +682,7 @@ class Inliner:
restore_backslashes=1)
return before, inlines, remaining, sysmessages
- def inline_target(self, match, lineno):
+ def inline_internal_target(self, match, lineno):
before, inlines, remaining, sysmessages, endstring = self.inline_obj(
match, lineno, self.patterns.target, nodes.target)
if inlines and isinstance(inlines[0], nodes.target):
@@ -817,7 +820,7 @@ class Inliner:
'**': strong,
'`': interpreted_or_phrase_ref,
'``': literal,
- '_`': inline_target,
+ '_`': inline_internal_target,
']_': footnote_reference,
'|': substitution_reference,
'_': reference,
--
cgit v1.2.1
From c21a148798856797bbf693ff1f5c8ba9c604cce1 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 14 Jul 2002 02:45:41 +0000
Subject: Undid a mistake.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@278 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 6c26b779b..9b4114b80 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -802,18 +802,14 @@ class Inliner:
match = pattern.search(text)
if match:
try:
- return (self.text(text[:match.start()])
+ # Must recurse on strings before *and* after the match;
+ # there may be multiple patterns.
+ return (self.implicit_inline(text[:match.start()], lineno)
+ dispatch(self, match, lineno) +
self.implicit_inline(text[match.end():], lineno))
except MarkupMismatch:
pass
return [nodes.Text(unescape(text))]
-
- def text(self, text):
- """Return a list containing one `nodes.Text` node or nothing."""
- if not text:
- return []
- return [nodes.Text(unescape(text))]
dispatch = {'*': emphasis,
--
cgit v1.2.1
From 6d6d20b280a38ca0d7b20b018d09c8bd3402758a Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 14 Jul 2002 02:47:41 +0000
Subject: Added a transform to insert a table of contents.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@279 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/readers/pep.py | 1 +
docutils/transforms/peps.py | 15 +++++++++++++++
2 files changed, 16 insertions(+)
(limited to 'docutils')
diff --git a/docutils/readers/pep.py b/docutils/readers/pep.py
index b7fabebb9..a4dc17cf1 100644
--- a/docutils/readers/pep.py
+++ b/docutils/readers/pep.py
@@ -29,6 +29,7 @@ class Reader(standalone.Reader):
transforms = (references.Substitutions,
peps.Headers,
+ peps.Contents,
references.Footnotes,
references.Hyperlinks,)
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
index 70775c930..d33e0989d 100644
--- a/docutils/transforms/peps.py
+++ b/docutils/transforms/peps.py
@@ -21,6 +21,7 @@ import time
from docutils import nodes, utils
from docutils import ApplicationError, DataError
from docutils.transforms import Transform, TransformError
+from docutils.transforms import parts
class Headers(Transform):
@@ -98,3 +99,17 @@ class Headers(Transform):
para[:] = [nodes.reference('', date, refuri=uri)]
elif name == 'version' and len(body):
utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
+
+
+class Contents(Transform):
+
+ """
+ Insert a table of contents into the document after the RFC 2822 header.
+ """
+
+
+ def transform(self):
+ pending = nodes.pending(parts.Contents, 'last reader',
+ {'title': None})
+ self.document.insert(1, pending)
+ self.document.note_pending(pending)
--
cgit v1.2.1
From baa38a937c93e341f6805c9220d42515d18a94b1 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 14 Jul 2002 02:51:19 +0000
Subject: - Added the translator class as instance variable to the Writer, to
make it easily subclassable. - Modified the ``field_body`` output.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@280 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 956303fad..9c5e14c62 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -39,8 +39,12 @@ class Writer(writers.Writer):
output = None
"""Final translated form of `document`."""
+ def __init__(self):
+ writers.Writer.__init__(self)
+ self.translator_class = HTMLTranslator
+
def translate(self):
- visitor = HTMLTranslator(self.document)
+ visitor = self.translator_class(self.document)
self.document.walkabout(visitor)
self.output = visitor.astext()
self.head_prefix = visitor.head_prefix
@@ -402,11 +406,12 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('')
def visit_field_body(self, node):
- self.body.append(':\n
\n')
+ #self.body.append('\n')
+ self.body.append('\n')
def visit_field_list(self, node):
self.body.append(self.starttag(node, 'table', frame='void',
--
cgit v1.2.1
From c81e34a5e7c0dd16fa6863908ff354c3b96f03b3 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 14 Jul 2002 02:58:29 +0000
Subject: Added to project; HTML Writer for PEPs (subclass of
``html4css1.Writer``).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@281 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/pep_html.py | 66 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 docutils/writers/pep_html.py
(limited to 'docutils')
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
new file mode 100644
index 000000000..37825d331
--- /dev/null
+++ b/docutils/writers/pep_html.py
@@ -0,0 +1,66 @@
+#! /usr/bin/env python
+
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+PEP HTML Writer.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+from docutils import nodes
+from docutils.writers import html4css1
+
+
+class Writer(html4css1.Writer):
+
+ cmdline_options = (
+ 'PEP/HTML-Specific Options',
+ None,
+ (('Specify a stylesheet file. Default is "rststyle.css".',
+ ['--stylesheet'],
+ {'default': 'rststyle.css', 'metavar': ''}),
+ ('Specify a template file. Default is "peptemplate.html".',
+ ['--template'],
+ {'default': 'peptemplate.html', 'metavar': ''}),
+ ('Python\'s home URL. Default is "http://www.python.org".',
+ ['--python-home'],
+ {'default': 'http://www.python.org', 'metavar': ''}),
+ ('Home URL for this PEP. Default is "." (current directory).',
+ ['--pep-home'],
+ {'default': '.', 'metavar': ''}),))
+
+ def __init__(self):
+ html4css1.Writer.__init__(self)
+ self.translator_class = HTMLTranslator
+
+ def translate(self):
+ html4css1.Writer.translate(self)
+ options = self.document.options
+ template = open(options.template).read()
+ pyhome = options.python_home
+ pephome = options.pep_home
+ index = self.document.first_child_matching_class(nodes.field_list)
+ header = self.document[index]
+ pep = header[0][1].astext()
+ try:
+ pepnum = '%04i' % int(pep)
+ except:
+ pepnum = pep
+ title = self.document[1][1].astext()
+ body = ''.join(self.body)
+ body_suffix = ''.join(self.body_suffix)
+ self.output = template % locals()
+
+
+class HTMLTranslator(html4css1.HTMLTranslator):
+
+ def depart_field_list(self, node):
+ html4css1.HTMLTranslator.depart_field_list(self, node)
+ if node.hasattr('class') and node['class'] == 'rfc2822':
+ self.body.append('\n')
--
cgit v1.2.1
From 0f70ab017321ae0f80a4aeaa2adcafb12dd26cb3 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 14 Jul 2002 03:10:30 +0000
Subject: Changed stylesheet & template file names.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@285 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/pep_html.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index 37825d331..e1452a5e0 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -22,12 +22,12 @@ class Writer(html4css1.Writer):
cmdline_options = (
'PEP/HTML-Specific Options',
None,
- (('Specify a stylesheet file. Default is "rststyle.css".',
+ (('Specify a stylesheet file. Default is "pep.css".',
['--stylesheet'],
- {'default': 'rststyle.css', 'metavar': ''}),
- ('Specify a template file. Default is "peptemplate.html".',
+ {'default': 'pep.css', 'metavar': ''}),
+ ('Specify a template file. Default is "pep-template.html".',
['--template'],
- {'default': 'peptemplate.html', 'metavar': ''}),
+ {'default': 'pep-template.html', 'metavar': ''}),
('Python\'s home URL. Default is "http://www.python.org".',
['--python-home'],
{'default': 'http://www.python.org', 'metavar': ''}),
--
cgit v1.2.1
From acb21b5d5622d284a3ed98236bf15ee70bb03069 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 14 Jul 2002 03:40:35 +0000
Subject: parameterized the stylesheet reference
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@291 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/pep_html.py | 1 +
1 file changed, 1 insertion(+)
(limited to 'docutils')
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index e1452a5e0..fe3c5b059 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -43,6 +43,7 @@ class Writer(html4css1.Writer):
html4css1.Writer.translate(self)
options = self.document.options
template = open(options.template).read()
+ stylesheet = options.stylesheet
pyhome = options.python_home
pephome = options.pep_home
index = self.document.first_child_matching_class(nodes.field_list)
--
cgit v1.2.1
From 79edab7ca03b79aae0397b2c449f0df1a5fe7920 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 14 Jul 2002 04:04:41 +0000
Subject: fixed the page title
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@294 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/pep_html.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index fe3c5b059..9cfaa0a89 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -53,7 +53,7 @@ class Writer(html4css1.Writer):
pepnum = '%04i' % int(pep)
except:
pepnum = pep
- title = self.document[1][1].astext()
+ title = header[1][1].astext()
body = ''.join(self.body)
body_suffix = ''.join(self.body_suffix)
self.output = template % locals()
--
cgit v1.2.1
From d23cdd89d86fd2bad2a067b67db87f229e52b25d Mon Sep 17 00:00:00 2001
From: richard
Date: Wed, 17 Jul 2002 00:49:09 +0000
Subject: Remove the 12 pixel cell spacing in option lists.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@297 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 9c5e14c62..db291ddee 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -593,7 +593,7 @@ class HTMLTranslator(nodes.NodeVisitor):
def visit_option_list(self, node):
self.body.append(
self.starttag(node, 'table', CLASS='option-list',
- frame="void", rules="none", cellspacing=12))
+ frame="void", rules="none"))
self.body.append('
\n'
'
\n'
'\n')
--
cgit v1.2.1
From d55f974593d719d4a2be200f6cf2ac73bb44334a Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 18 Jul 2002 00:50:18 +0000
Subject: ws
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@298 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 1 -
1 file changed, 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 0e1158024..d7dbf914f 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -90,7 +90,6 @@ class OptionParser(optik.OptionParser):
# Hidden options, for development use only:
(optik.SUPPRESS_HELP, ['--dump-internal-document-attributes'],
{'action': 'store_true'}),))
-
"""Command-line option specifications, common to all Docutils front-ends.
Option group title, description, and a list/tuple of tuples: ``('help
text', [list of option strings], {keyword arguments})``. Group title
--
cgit v1.2.1
From fda31a72bed007ad8a39d6ad109cb093028cbbec Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 18 Jul 2002 00:51:13 +0000
Subject: - Fixed DOM generation for list-attributes. - Added category
class ``Labeled`` (used by footnotes & citations).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@299 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 84ce615a3..77e4a2ce6 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -242,6 +242,8 @@ class Element(Node):
def _rooted_dom_node(self, domroot):
element = domroot.createElement(self.tagname)
for attribute, value in self.attributes.items():
+ if type(value) is ListType:
+ value = ' '.join(value)
element.setAttribute(attribute, str(value))
for child in self.children:
element.appendChild(child._rooted_dom_node(domroot))
@@ -541,6 +543,9 @@ class Targetable(Resolvable):
referenced = 0
+class Labeled:
+ """Contains a `label` as its first element."""
+
# ==============
# Root Element
@@ -636,7 +641,7 @@ class document(Root, Structural, Element):
def asdom(self, dom=xml.dom.minidom):
domroot = dom.Document()
- domroot.appendChild(Element._rooted_dom_node(self, domroot))
+ domroot.appendChild(self._rooted_dom_node(domroot))
return domroot
def set_id(self, node, msgnode=None):
@@ -921,8 +926,8 @@ class warning(Admonition, Element): pass
class comment(Special, PreBibliographic, TextElement): pass
class substitution_definition(Special, TextElement): pass
class target(Special, Inline, TextElement, Targetable): pass
-class footnote(General, Element, BackLinkable): pass
-class citation(General, Element, BackLinkable): pass
+class footnote(General, Element, Labeled, BackLinkable): pass
+class citation(General, Element, Labeled, BackLinkable): pass
class label(Part, TextElement): pass
class figure(General, Element): pass
class caption(Part, TextElement): pass
--
cgit v1.2.1
From 6b456ac082f235f368eaa37e4b4905222a76028d Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 18 Jul 2002 00:52:40 +0000
Subject: - Updated docstrings. - Changed "table" to "grid_table"; added
"simple_table" support.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@300 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 161 ++++++++++++++++++++++++++++++-----------
1 file changed, 119 insertions(+), 42 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 9b4114b80..04a9ea605 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -44,11 +44,11 @@ the reStructuredText parser. It defines the following:
Parser Overview
===============
-The reStructuredText parser is implemented as a state machine, examining its
-input one line at a time. To understand how the parser works, please first
-become familiar with the `docutils.statemachine` module. In the description
-below, references are made to classes defined in this module; please see the
-individual classes for details.
+The reStructuredText parser is implemented as a recursive state machine,
+examining its input one line at a time. To understand how the parser works,
+please first become familiar with the `docutils.statemachine` module. In the
+description below, references are made to classes defined in this module;
+please see the individual classes for details.
Parsing proceeds as follows:
@@ -60,26 +60,27 @@ Parsing proceeds as follows:
2. The method associated with the matched transition pattern is called.
A. Some transition methods are self-contained, appending elements to the
- document tree ('doctest' parses a doctest block). The parser's current
- line index is advanced to the end of the element, and parsing continues
- with step 1.
+ document tree (`Body.doctest` parses a doctest block). The parser's
+ current line index is advanced to the end of the element, and parsing
+ continues with step 1.
- B. Others trigger the creation of a nested state machine, whose job is to
- parse a compound construct ('indent' does a block quote, 'bullet' does a
- bullet list, 'overline' does a section [first checking for a valid
- section header]).
+ B. Other transition methods trigger the creation of a nested state machine,
+ whose job is to parse a compound construct ('indent' does a block quote,
+ 'bullet' does a bullet list, 'overline' does a section [first checking
+ for a valid section header], etc.).
- - In the case of lists and explicit markup, a new state machine is
- created and run to parse the first item.
+ - In the case of lists and explicit markup, a one-off state machine is
+ created and run to parse contents of the first item.
- A new state machine is created and its initial state is set to the
appropriate specialized state (`BulletList` in the case of the
- 'bullet' transition). This state machine is run to parse the compound
- element (or series of explicit markup elements), and returns as soon
- as a non-member element is encountered. For example, the `BulletList`
- state machine aborts as soon as it encounters an element which is not
- a list item of that bullet list. The optional omission of
- inter-element blank lines is handled by the nested state machine.
+ 'bullet' transition; see `SpecializedBody` for more detail). This
+ state machine is run to parse the compound element (or series of
+ explicit markup elements), and returns as soon as a non-member element
+ is encountered. For example, the `BulletList` state machine ends as
+ soon as it encounters an element which is not a list item of that
+ bullet list. The optional omission of inter-element blank lines is
+ enabled by this nested state machine.
- The current line index is advanced to the end of the elements parsed,
and parsing continues with step 1.
@@ -110,8 +111,7 @@ from docutils import nodes, statemachine, utils, roman, urischemes
from docutils import ApplicationError, DataError
from docutils.statemachine import StateMachineWS, StateWS
from docutils.utils import normalize_name
-from docutils.parsers.rst import directives, languages
-from docutils.parsers.rst.tableparser import TableParser, TableMarkupError
+from docutils.parsers.rst import directives, languages, tableparser
class MarkupError(DataError): pass
@@ -858,10 +858,14 @@ class Body(RSTState):
enum.sequenceregexps[sequence] = re.compile(
enum.sequencepats[sequence] + '$')
- table_top_pat = re.compile(r'\+-[-+]+-\+ *$')
- """Matches the top (& bottom) of a table)."""
+ grid_table_top_pat = re.compile(r'\+-[-+]+-\+ *$')
+ """Matches the top (& bottom) of a full table)."""
- tableparser = TableParser()
+ simple_table_top_pat = re.compile('=+( +=+)+ *$')
+ """Matches the top of a simple table."""
+
+ simple_table_border_pat = re.compile('=+[ =]*$')
+ """Matches the bottom & header bottom of a simple table."""
pats = {}
"""Fragments of patterns used by transitions."""
@@ -888,7 +892,8 @@ class Body(RSTState):
'field_marker': r':[^: ]([^:]*[^: ])?:( +|$)',
'option_marker': r'%(option)s(, %(option)s)*( +| ?$)' % pats,
'doctest': r'>>>( +|$)',
- 'table_top': table_top_pat,
+ 'grid_table_top': grid_table_top_pat,
+ 'simple_table_top': simple_table_top_pat,
'explicit_markup': r'\.\.( +|$)',
'anonymous': r'__( +|$)',
'line': r'(%(nonalphanum7bit)s)\1\1\1+ *$' % pats,
@@ -899,7 +904,8 @@ class Body(RSTState):
'field_marker',
'option_marker',
'doctest',
- 'table_top',
+ 'grid_table_top',
+ 'simple_table_top',
'explicit_markup',
'anonymous',
'line',
@@ -1159,9 +1165,22 @@ class Body(RSTState):
self.parent += nodes.doctest_block(data, data)
return [], next_state, []
- def table_top(self, match, context, next_state):
- """Top border of a table."""
- nodelist, blank_finish = self.table()
+ def grid_table_top(self, match, context, next_state):
+ """Top border of a full table."""
+ return self.table_top(match, context, next_state,
+ self.isolate_grid_table,
+ tableparser.GridTableParser)
+
+ def simple_table_top(self, match, context, next_state):
+ """Top border of a simple table."""
+ return self.table_top(match, context, next_state,
+ self.isolate_simple_table,
+ tableparser.SimpleTableParser)
+
+ def table_top(self, match, context, next_state,
+ isolate_function, parser_class):
+ """Top border of a generic table."""
+ nodelist, blank_finish = self.table(isolate_function, parser_class)
self.parent += nodelist
if not blank_finish:
msg = self.reporter.warning(
@@ -1170,23 +1189,24 @@ class Body(RSTState):
self.parent += msg
return [], next_state, []
- def table(self):
+ def table(self, isolate_function, parser_class):
"""Parse a table."""
- block, messages, blank_finish = self.isolate_table()
+ block, messages, blank_finish = isolate_function()
if block:
try:
- tabledata = self.tableparser.parse(block)
+ parser = parser_class()
+ tabledata = parser.parse(block)
tableline = (self.state_machine.abs_line_number() - len(block)
+ 1)
table = self.build_table(tabledata, tableline)
nodelist = [table] + messages
- except TableMarkupError, detail:
+ except tableparser.TableMarkupError, detail:
nodelist = self.malformed_table(block, str(detail)) + messages
else:
nodelist = messages
return nodelist, blank_finish
- def isolate_table(self):
+ def isolate_grid_table(self):
messages = []
blank_finish = 1
try:
@@ -1204,11 +1224,11 @@ class Body(RSTState):
self.state_machine.previous_line(len(block) - i)
del block[i:]
break
- if not self.table_top_pat.match(block[-1]): # find bottom
+ if not self.grid_table_top_pat.match(block[-1]): # find bottom
blank_finish = 0
# from second-last to third line of table:
for i in range(len(block) - 2, 1, -1):
- if self.table_top_pat.match(block[i]):
+ if self.grid_table_top_pat.match(block[i]):
self.state_machine.previous_line(len(block) - i + 1)
del block[i+1:]
break
@@ -1221,6 +1241,47 @@ class Body(RSTState):
return [], messages, blank_finish
return block, messages, blank_finish
+ def isolate_simple_table(self):
+ start = self.state_machine.line_offset
+ lines = self.state_machine.input_lines
+ limit = len(lines) - 1
+ toplen = len(lines[start].strip())
+ pattern_match = self.simple_table_border_pat.match
+ found = 0
+ found_at = None
+ i = start + 1
+ while i <= limit:
+ line = lines[i]
+ match = pattern_match(line)
+ if match:
+ if len(line.strip()) != toplen:
+ self.state_machine.next_line(i - start)
+ messages = self.malformed_table(
+ lines[start:i+1], 'Bottom/header table border does '
+ 'not match top border.')
+ return [], messages, i == limit or not lines[i+1].strip()
+ found += 1
+ found_at = i
+ if found == 2 or i == limit or not lines[i+1].strip():
+ end = i
+ break
+ i += 1
+ else: # reached end of input_lines
+ if found:
+ extra = ' or no blank line after table bottom'
+ self.state_machine.next_line(found_at - start)
+ block = lines[start:found_at+1]
+ else:
+ extra = ''
+ self.state_machine.next_line(i - start - 1)
+ block = lines[start:]
+ messages = self.malformed_table(
+ block, 'No bottom table border found%s.' % extra)
+ return [], messages, not extra
+ self.state_machine.next_line(end - start)
+ block = lines[start:end+1]
+ return block, [], end == limit or not lines[end+1].strip()
+
def malformed_table(self, block, detail=''):
data = '\n'.join(block)
message = 'Malformed table at line %s; formatting as a ' \
@@ -1738,10 +1799,25 @@ class RFC2822Body(Body):
class SpecializedBody(Body):
"""
- Superclass for second and subsequent compound element members.
-
- All transition methods are disabled. Override individual methods in
- subclasses to re-enable.
+ Superclass for second and subsequent compound element members. Compound
+ elements are lists and list-like constructs.
+
+ All transition methods are disabled (redefined as `invalid_input`).
+ Override individual methods in subclasses to re-enable.
+
+ For example, once an initial bullet list item, say, is recognized, the
+ `BulletList` subclass takes over, with a "bullet_list" node as its
+ container. Upon encountering the initial bullet list item, `Body.bullet`
+ calls its ``self.nested_list_parse`` (`RSTState.nested_list_parse`), which
+ starts up a nested parsing session with `BulletList` as the initial state.
+ Only the ``bullet`` transition method is enabled in `BulletList`; as long
+ as only bullet list items are encountered, they are parsed and inserted
+ into the container. The first construct which is *not* a bullet list item
+ triggers the `invalid_input` method, which ends the nested parse and
+ closes the container. `BulletList` needs to recognize input that is
+ invalid in the context of a bullet list, which means everything *other
+ than* bullet list items, so it inherits the transition list created in
+ `Body`.
"""
def invalid_input(self, match=None, context=None, next_state=None):
@@ -1755,7 +1831,8 @@ class SpecializedBody(Body):
field_marker = invalid_input
option_marker = invalid_input
doctest = invalid_input
- table_top = invalid_input
+ grid_table_top = invalid_input
+ simple_table_top = invalid_input
explicit_markup = invalid_input
anonymous = invalid_input
line = invalid_input
--
cgit v1.2.1
From 80dbe0f7f7d7ddc5d9850562e76912c93a7c2261 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 18 Jul 2002 00:53:21 +0000
Subject: - Changed ``TableParser`` to ``GridTableParser``. - Added
``SimpleTableParser``. - Refactored naming.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@301 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/tableparser.py | 345 ++++++++++++++++++++++++++++--------
1 file changed, 272 insertions(+), 73 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/tableparser.py b/docutils/parsers/rst/tableparser.py
index 3f7575040..51beb6b97 100644
--- a/docutils/parsers/rst/tableparser.py
+++ b/docutils/parsers/rst/tableparser.py
@@ -5,20 +5,25 @@
:Date: $Date$
:Copyright: This module has been placed in the public domain.
-This module defines the `TableParser` class, which parses a plaintext-graphic
-table and produces a well-formed data structure suitable for building a CALS
-table.
+This module defines table parser classes,which parse plaintext-graphic tables
+and produce a well-formed data structure suitable for building a CALS table.
+
+:Classes:
+ - `GridTableParser`: Parse fully-formed tables represented with a grid.
+ - `SimpleTableParser`: Parse simple tables, delimited by top & bottom
+ borders.
:Exception class: `TableMarkupError`
:Function:
- `update_dictoflists()`: Merge two dictionaries containing list values.
+ `update_dict_of_lists()`: Merge two dictionaries containing list values.
"""
__docformat__ = 'reStructuredText'
import re
+import sys
from docutils import DataError
@@ -28,9 +33,53 @@ class TableMarkupError(DataError): pass
class TableParser:
"""
- Parse a plaintext graphic table using `parse()`.
+ Abstract superclass for the common parts of the syntax-specific parsers.
+ """
- Here's an example of a plaintext graphic table::
+ head_body_separator_pat = None
+ """Matches the row separator between head rows and body rows."""
+
+ def parse(self, block):
+ """
+ Analyze the text `block` and return a table data structure.
+
+ Given a plaintext-graphic table in `block` (list of lines of text; no
+ whitespace padding), parse the table, construct and return the data
+ necessary to construct a CALS table or equivalent.
+
+ Raise `TableMarkupError` if there is any problem with the markup.
+ """
+ self.setup(block)
+ self.find_head_body_sep()
+ self.parse_table()
+ structure = self.structure_from_cells()
+ return structure
+
+ def find_head_body_sep(self):
+ """Look for a head/body row separator line; store the line index."""
+ for i in range(len(self.block)):
+ line = self.block[i]
+ if self.head_body_separator_pat.match(line):
+ if self.head_body_sep:
+ raise TableMarkupError(
+ 'Multiple head/body row separators in table (at line '
+ 'offset %s and %s); only one allowed.'
+ % (self.head_body_sep, i))
+ else:
+ self.head_body_sep = i
+ self.block[i] = line.replace('=', '-')
+ if self.head_body_sep == 0 or self.head_body_sep == (len(self.block)
+ - 1):
+ raise TableMarkupError('The head/body row separator may not be '
+ 'the first or last line of the table.')
+
+
+class GridTableParser(TableParser):
+
+ """
+ Parse a grid table using `parse()`.
+
+ Here's an example of a grid table::
+------------------------+------------+----------+----------+
| Header row, column 1 | Header 2 | Header 3 | Header 4 |
@@ -79,54 +128,19 @@ class TableParser:
and the cell contents, a list of lines of text.
"""
- headbodyseparatorpat = re.compile(r'\+=[=+]+=\+$')
- """Matches the row separator between head rows and body rows."""
-
- def parse(self, block):
- """
- Analyze the text `block` and return a table data structure.
-
- Given a plaintext-graphic table in `block` (list of lines of text; no
- whitespace padding), parse the table, construct and return the data
- necessary to construct a CALS table or equivalent.
-
- Raise `TableMarkupError` if there is any problem with the markup.
- """
- self.setup(block)
- self.findheadbodysep()
- self.parsegrid()
- structure = self.structurefromcells()
- return structure
+ head_body_separator_pat = re.compile(r'\+=[=+]+=\+ *$')
def setup(self, block):
self.block = block[:] # make a copy; it may be modified
self.bottom = len(block) - 1
self.right = len(block[0]) - 1
- self.headbodysep = None
+ self.head_body_sep = None
self.done = [-1] * len(block[0])
self.cells = []
self.rowseps = {0: [0]}
self.colseps = {0: [0]}
- def findheadbodysep(self):
- """Look for a head/body row separator line; store the line index."""
- for i in range(len(self.block)):
- line = self.block[i]
- if self.headbodyseparatorpat.match(line):
- if self.headbodysep:
- raise TableMarkupError, (
- 'Multiple head/body row separators in table (at line '
- 'offset %s and %s); only one allowed.'
- % (self.headbodysep, i))
- else:
- self.headbodysep = i
- self.block[i] = line.replace('=', '-')
- if self.headbodysep == 0 or self.headbodysep == len(self.block) - 1:
- raise TableMarkupError, (
- 'The head/body row separator may not be the first or last '
- 'line of the table.' % (self.headbodysep, i))
-
- def parsegrid(self):
+ def parse_table(self):
"""
Start with a queue of upper-left corners, containing the upper-left
corner of the table itself. Trace out one rectangular cell, remember
@@ -144,21 +158,21 @@ class TableParser:
if top == self.bottom or left == self.right \
or top <= self.done[left]:
continue
- result = self.scancell(top, left)
+ result = self.scan_cell(top, left)
if not result:
continue
bottom, right, rowseps, colseps = result
- update_dictoflists(self.rowseps, rowseps)
- update_dictoflists(self.colseps, colseps)
- self.markdone(top, left, bottom, right)
- cellblock = self.getcellblock(top, left, bottom, right)
+ update_dict_of_lists(self.rowseps, rowseps)
+ update_dict_of_lists(self.colseps, colseps)
+ self.mark_done(top, left, bottom, right)
+ cellblock = self.get_cell_block(top, left, bottom, right)
self.cells.append((top, left, bottom, right, cellblock))
corners.extend([(top, right), (bottom, left)])
corners.sort()
- if not self.checkparsecomplete():
- raise TableMarkupError, 'Malformed table; parse incomplete.'
+ if not self.check_parse_complete():
+ raise TableMarkupError('Malformed table; parse incomplete.')
- def markdone(self, top, left, bottom, right):
+ def mark_done(self, top, left, bottom, right):
"""For keeping track of how much of each text column has been seen."""
before = top - 1
after = bottom - 1
@@ -166,7 +180,7 @@ class TableParser:
assert self.done[col] == before
self.done[col] = after
- def checkparsecomplete(self):
+ def check_parse_complete(self):
"""Each text column should have been completely seen."""
last = self.bottom - 1
for col in range(self.right):
@@ -174,7 +188,7 @@ class TableParser:
return None
return 1
- def getcellblock(self, top, left, bottom, right):
+ def get_cell_block(self, top, left, bottom, right):
"""Given the corners, extract the text of a cell."""
cellblock = []
margin = right
@@ -182,18 +196,18 @@ class TableParser:
line = self.block[lineno][left + 1 : right].rstrip()
cellblock.append(line)
if line:
- margin = margin and min(margin, len(line) - len(line.lstrip()))
+ margin = min(margin, len(line) - len(line.lstrip()))
if 0 < margin < right:
cellblock = [line[margin:] for line in cellblock]
return cellblock
- def scancell(self, top, left):
+ def scan_cell(self, top, left):
"""Starting at the top-left corner, start tracing out a cell."""
assert self.block[top][left] == '+'
- result = self.scanright(top, left)
+ result = self.scan_right(top, left)
return result
- def scanright(self, top, left):
+ def scan_right(self, top, left):
"""
Look for the top-right corner of the cell, and make note of all column
boundaries ('+').
@@ -203,16 +217,16 @@ class TableParser:
for i in range(left + 1, self.right + 1):
if line[i] == '+':
colseps[i] = [top]
- result = self.scandown(top, left, i)
+ result = self.scan_down(top, left, i)
if result:
bottom, rowseps, newcolseps = result
- update_dictoflists(colseps, newcolseps)
+ update_dict_of_lists(colseps, newcolseps)
return bottom, i, rowseps, colseps
elif line[i] != '-':
return None
return None
- def scandown(self, top, left, right):
+ def scan_down(self, top, left, right):
"""
Look for the bottom-right corner of the cell, making note of all row
boundaries.
@@ -221,16 +235,16 @@ class TableParser:
for i in range(top + 1, self.bottom + 1):
if self.block[i][right] == '+':
rowseps[i] = [right]
- result = self.scanleft(top, left, i, right)
+ result = self.scan_left(top, left, i, right)
if result:
newrowseps, colseps = result
- update_dictoflists(rowseps, newrowseps)
+ update_dict_of_lists(rowseps, newrowseps)
return i, rowseps, colseps
elif self.block[i][right] != '|':
return None
return None
- def scanleft(self, top, left, bottom, right):
+ def scan_left(self, top, left, bottom, right):
"""
Noting column boundaries, look for the bottom-left corner of the cell.
It must line up with the starting point.
@@ -244,14 +258,16 @@ class TableParser:
return None
if line[left] != '+':
return None
- result = self.scanup(top, left, bottom, right)
+ result = self.scan_up(top, left, bottom, right)
if result is not None:
rowseps = result
return rowseps, colseps
return None
- def scanup(self, top, left, bottom, right):
- """Noting row boundaries, see if we can return to the starting point."""
+ def scan_up(self, top, left, bottom, right):
+ """
+ Noting row boundaries, see if we can return to the starting point.
+ """
rowseps = {}
for i in range(bottom - 1, top, -1):
if self.block[i][left] == '+':
@@ -260,9 +276,9 @@ class TableParser:
return None
return rowseps
- def structurefromcells(self):
+ def structure_from_cells(self):
"""
- From the data colledted by `scancell()`, convert to the final data
+ From the data colledted by `scan_cell()`, convert to the final data
structure.
"""
rowseps = self.rowseps.keys() # list of row boundaries
@@ -274,7 +290,7 @@ class TableParser:
colseps.sort()
colindex = {}
for i in range(len(colseps)):
- colindex[colseps[i]] = i # column boundary -> col number mapping
+ colindex[colseps[i]] = i # column boundary -> col number map
colspecs = [(colseps[i] - colseps[i - 1] - 1)
for i in range(1, len(colseps))] # list of column widths
# prepare an empty table with the correct number of rows & columns
@@ -294,8 +310,8 @@ class TableParser:
# write the cell into the table
rows[rownum][colnum] = (morerows, morecols, top + 1, block)
assert remaining == 0, 'Unused cells remaining.'
- if self.headbodysep: # separate head rows from body rows
- numheadrows = rowindex[self.headbodysep]
+ if self.head_body_sep: # separate head rows from body rows
+ numheadrows = rowindex[self.head_body_sep]
headrows = rows[:numheadrows]
bodyrows = rows[numheadrows:]
else:
@@ -304,7 +320,190 @@ class TableParser:
return (colspecs, headrows, bodyrows)
-def update_dictoflists(master, newdata):
+class SimpleTableParser(TableParser):
+
+ """
+ Parse a simple table using `parse()`.
+
+ Here's an example of a simple table::
+
+ ===== =====
+ col 1 col 2
+ ===== =====
+ 1 Second column of row 1.
+ 2 Second column of row 2.
+ Second line of paragraph.
+ 3 - Second column of row 3.
+
+ - Second item in bullet
+ list (row 3, column 2).
+ 4 is a span
+ ------------
+ 5
+ ===== =====
+
+ Top and bottom borders use '=', column span underlines use '-', column
+ separation is indicated with spaces.
+
+ Passing the above table to the `parse()` method will result in the
+ following data structure, whose interpretation is the same as for
+ `GridTableParser`::
+
+ ([5, 25],
+ [[(0, 0, 1, ['col 1']),
+ (0, 0, 1, ['col 2'])]],
+ [[(0, 0, 3, ['1']),
+ (0, 0, 3, ['Second column of row 1.'])],
+ [(0, 0, 4, ['2']),
+ (0, 0, 4, ['Second column of row 2.',
+ 'Second line of paragraph.'])],
+ [(0, 0, 6, ['3']),
+ (0, 0, 6, ['- Second column of row 3.',
+ '',
+ '- Second item in bullet',
+ ' list (row 3, column 2).'])],
+ [(0, 1, 10, ['4 is a span'])],
+ [(0, 0, 12, ['5']),
+ (0, 0, 12, [''])]])
+ """
+
+ head_body_separator_pat = re.compile('=[ =]*$')
+ span_pat = re.compile('-[ -]*$')
+
+ def setup(self, block):
+ self.block = block[:] # make a copy; it will be modified
+ # Convert top & bottom borders to column span underlines:
+ self.block[0] = self.block[0].replace('=', '-')
+ self.block[-1] = self.block[-1].replace('=', '-')
+ self.head_body_sep = None
+ self.columns = []
+ self.table = []
+ self.done = [-1] * len(block[0])
+ self.rowseps = {0: [0]}
+ self.colseps = {0: [0]}
+
+ def parse_table(self):
+ """
+ First determine the column boundaries from the top border, then
+ process rows. Each row may consist of multiple lines; accumulate
+ lines until a row is complete. Call `self.parse_row` to finish the
+ job.
+ """
+ # Top border must fully describe all table columns.
+ self.columns = self.parse_columns(self.block[0])
+ firststart, firstend = self.columns[0]
+ block = self.block[1:]
+ offset = 0
+ # Container for accumulating text lines until a row is complete:
+ rowlines = []
+ while block:
+ line = block.pop(0)
+ offset += 1
+ if self.span_pat.match(line):
+ # Column span underline or border; row is complete.
+ self.parse_row(rowlines, line)
+ rowlines = []
+ elif line[firststart:firstend].strip():
+ # First column not blank, therefore it's a new row.
+ if rowlines:
+ self.parse_row(rowlines)
+ rowlines = [(line, offset)]
+ else:
+ # Accumulate lines of incomplete row.
+ rowlines.append((line, offset))
+
+ def parse_columns(self, line):
+ """
+ Given a column span underline, return a list of (begin, end) pairs.
+ """
+ cols = []
+ end = 0
+ while 1:
+ begin = line.find('-', end)
+ end = line.find(' ', begin)
+ if begin < 0:
+ break
+ if end < 0:
+ end = len(line)
+ cols.append((begin, end))
+ return cols
+
+ def init_row(self, colspec, offset):
+ i = 0
+ cells = []
+ for start, end in colspec:
+ morecols = 0
+ try:
+ assert start == self.columns[i][0]
+ while end != self.columns[i][1]:
+ i += 1
+ morecols += 1
+ except (AssertionError, IndexError):
+ raise TableMarkupError('Column span alignment problem at '
+ 'line offset %s.' % offset)
+ cells.append((0, morecols, offset, []))
+ i += 1
+ return cells
+
+ def parse_row(self, lines, spanline=None):
+ """
+ Given the text `lines` of a row, parse it and append to `self.table`.
+
+ The row is parsed according to the current column spec (either
+ `spanline` if provided or `self.columns`). For each column, extract
+ text from each line, and check for text in column margins. Finally,
+ adjust for insigificant whitespace.
+ """
+ if spanline:
+ columns = self.parse_columns(spanline)
+ else:
+ columns = self.columns[:]
+ row = self.init_row(columns, lines[0][1])
+ # "Infinite" value for a dummy last column's beginning, used to
+ # check for text overflow:
+ columns.append((sys.maxint, None))
+ lastcol = len(columns) - 2
+ for i in range(len(columns) - 1):
+ start, end = columns[i]
+ nextstart = columns[i+1][0]
+ block = []
+ margin = sys.maxint
+ for line, offset in lines:
+ if i == lastcol and line[end:].strip():
+ text = line[start:].rstrip()
+ columns[lastcol] = (start, start + len(text))
+ self.adjust_last_column(start + len(text))
+ elif line[end:nextstart].strip():
+ raise TableMarkupError('Text in column margin at line '
+ 'offset %s.' % offset)
+ else:
+ text = line[start:end].rstrip()
+ block.append(text)
+ if text:
+ margin = min(margin, len(text) - len(text.lstrip()))
+ if 0 < margin < sys.maxint:
+ block = [line[margin:] for line in block]
+ row[i][3].extend(block)
+ self.table.append(row)
+
+ def adjust_last_column(self, new_end):
+ start, end = self.columns[-1]
+ if new_end > end:
+ self.columns[-1] = (start, new_end)
+
+ def structure_from_cells(self):
+ colspecs = [end - start for start, end in self.columns]
+ first_body_row = 0
+ if self.head_body_sep:
+ for i in range(len(self.table)):
+ if self.table[i][0][2] > self.head_body_sep:
+ first_body_row = i
+ break
+ return (colspecs, self.table[:first_body_row],
+ self.table[first_body_row:])
+
+
+def update_dict_of_lists(master, newdata):
"""
Extend the list values of `master` with those from `newdata`.
--
cgit v1.2.1
From 356d554c756d9b37284f6a1667995962f4ec2c67 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 18 Jul 2002 00:57:31 +0000
Subject: - Added ``Contents`` to insert TOC. - Added ``PEPZero`` for PEP 0
special processing. - Masked email address of "Author" field.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@302 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/peps.py | 61 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 54 insertions(+), 7 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
index d33e0989d..0df6fa246 100644
--- a/docutils/transforms/peps.py
+++ b/docutils/transforms/peps.py
@@ -10,6 +10,8 @@ Transforms for PEP processing.
- `Headers`: Used to transform a PEP's initial RFC-2822 header. It remains a
field list, but some entries get processed.
+- `Contents`: Auto-inserts a table of contents.
+- `PEPZero`: Special processing for PEP 0.
"""
__docformat__ = 'reStructuredText'
@@ -52,6 +54,11 @@ class Headers(Transform):
if pep is None:
raise DataError('Document does not contain an RFC-2822 "PEP" '
'header.')
+ if pep == 0:
+ # Special processing for PEP 0.
+ pending = nodes.pending(PEPZero, 'last reader', {})
+ self.document.insert(1, pending)
+ self.document.note_pending(pending)
for field in header:
name = field[0].astext().lower()
body = field[1]
@@ -73,15 +80,18 @@ class Headers(Transform):
else:
continue
para = body[0]
- if name == 'title':
- title = body.astext()
- # @@@ Insert a "pending" element here, since we don't really
- # want a separate document title?
- elif name in ('author', 'discussions-to'):
+ if name == 'author':
for node in para:
if isinstance(node, nodes.reference) \
- and node.has_key('refuri') \
- and node['refuri'][:7] == 'mailto:':
+ and node.has_key('refuri') \
+ and node['refuri'].startswith('mailto:'):
+ replacement = node.astext().replace('@', ' at ')
+ node.parent.replace(node, nodes.Text(replacement))
+ elif name == 'discussions-to':
+ for node in para:
+ if isinstance(node, nodes.reference) \
+ and node.has_key('refuri') \
+ and node['refuri'].startswith('mailto:'):
node['refuri'] += '?subject=PEP%%20%s' % pep
elif name in ('replaces', 'replaced-by'):
newbody = []
@@ -113,3 +123,40 @@ class Contents(Transform):
{'title': None})
self.document.insert(1, pending)
self.document.note_pending(pending)
+
+
+class PEPZero(Transform):
+
+ """
+ Special processing for PEP 0.
+ """
+
+ def transform(self):
+ visitor = EmailMasker(self.document)
+ self.document.walk(visitor)
+ self.startnode.parent.remove(self.startnode)
+
+
+class EmailMasker(nodes.SparseNodeVisitor):
+
+ """
+ For all email-address references such as "user@host", mask the address as
+ "user at host" (text) to thwart simple email address harvesters.
+ """
+
+ non_masked_addresses = ('peps@python.org',
+ 'python-list@python.org',
+ 'python-dev@python.org')
+
+ def unknown_visit(self, node):
+ pass
+
+ def visit_reference(self, node):
+ if node.hasattr('refuri') and node['refuri'].startswith('mailto:') \
+ and node['refuri'][8:] not in self.non_masked_addresses:
+ replacement = node.astext().replace('@', ' at ')
+ node.parent.replace(node, nodes.Text(replacement))
+
+ def visit_field_list(self, node):
+ if node.hasattr('class') and node['class'] == 'rfc2822':
+ raise nodes.SkipNode
--
cgit v1.2.1
From e57505e14b9a33b25b2daf344eae89150e2e37b0 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 18 Jul 2002 01:28:42 +0000
Subject: Changed default template name & Python's home. Made Python graphic
random.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@303 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/pep_html.py | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index 9cfaa0a89..bd11d3752 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -13,6 +13,8 @@ PEP HTML Writer.
__docformat__ = 'reStructuredText'
+import sys
+import random
from docutils import nodes
from docutils.writers import html4css1
@@ -25,12 +27,12 @@ class Writer(html4css1.Writer):
(('Specify a stylesheet file. Default is "pep.css".',
['--stylesheet'],
{'default': 'pep.css', 'metavar': ''}),
- ('Specify a template file. Default is "pep-template.html".',
+ ('Specify a template file. Default is "pep-html-template".',
['--template'],
- {'default': 'pep-template.html', 'metavar': ''}),
- ('Python\'s home URL. Default is "http://www.python.org".',
+ {'default': 'pep-html-template', 'metavar': ''}),
+ ('Python\'s home URL. Default is ".." (parent directory).',
['--python-home'],
- {'default': 'http://www.python.org', 'metavar': ''}),
+ {'default': '..', 'metavar': ''}),
('Home URL for this PEP. Default is "." (current directory).',
['--pep-home'],
{'default': '.', 'metavar': ''}),))
@@ -46,9 +48,14 @@ class Writer(html4css1.Writer):
stylesheet = options.stylesheet
pyhome = options.python_home
pephome = options.pep_home
+ if pyhome == '..':
+ pepindex = '.'
+ else:
+ pepindex = pyhome + '/peps/'
index = self.document.first_child_matching_class(nodes.field_list)
header = self.document[index]
pep = header[0][1].astext()
+ banner = random.randrange(64)
try:
pepnum = '%04i' % int(pep)
except:
--
cgit v1.2.1
From 6e0d115d7619215b4b5c03ead6f53f0c153246cc Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 18 Jul 2002 01:31:37 +0000
Subject: - Modified field list output. - Added backlinks to footnotes &
citations.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@304 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 42 ++++++++++++++++++++++++++++--------------
1 file changed, 28 insertions(+), 14 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index db291ddee..8c6e2f2d4 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -209,6 +209,7 @@ class HTMLTranslator(nodes.NodeVisitor):
'
')
- self.context.append(0)
+ self.body.append('')
+ self.context.append(0) # count number of options
def depart_option_group(self, node):
self.context.pop()
- self.body.append('
\n
')
+ self.body.append('\n')
self.body.append(self.context.pop())
def visit_option_list(self, node):
@@ -637,14 +672,18 @@ class HTMLTranslator(nodes.NodeVisitor):
self.depart_docinfo_item()
def visit_paragraph(self, node):
- if not self.topic_class == 'contents':
+ # Omit
tags if this is an only child and optimizable.
+ if (self.compact_simple or
+ self.compact_p and (len(node.parent) == 1 or
+ len(node.parent) == 2 and
+ isinstance(node.parent[0], nodes.label))):
+ self.context.append('')
+ else:
self.body.append(self.starttag(node, 'p', ''))
+ self.context.append('
\n')
def depart_paragraph(self, node):
- if self.topic_class == 'contents':
- self.body.append('\n')
- else:
- self.body.append('\n')
+ self.body.append(self.context.pop())
def visit_problematic(self, node):
if node.hasattr('refid'):
@@ -861,3 +900,34 @@ class HTMLTranslator(nodes.NodeVisitor):
def unimplemented_visit(self, node):
raise NotImplementedError('visiting unimplemented node type: %s'
% node.__class__.__name__)
+
+
+class SimpleListChecker(nodes.GenericNodeVisitor):
+
+ """
+ Raise `nodes.SkipNode` if non-simple list item is encountered.
+
+ Here "simple" means a list item containing anything other than a single
+ paragraph, a simple list, or a paragraph followed by a simple list.
+ """
+
+ def default_visit(self, node):
+ raise nodes.NodeFound
+
+ def visit_bullet_list(self, node):
+ pass
+
+ def visit_enumerated_list(self, node):
+ pass
+
+ def visit_list_item(self, node):
+ if len(node) <= 1 or (len(node) == 2 and
+ isinstance(node[0], nodes.paragraph) and
+ (isinstance(node[1], nodes.bullet_list) or
+ isinstance(node[1], nodes.enumerated_list))):
+ return
+ else:
+ raise nodes.NodeFound
+
+ def visit_paragraph(self, node):
+ raise nodes.SkipNode
--
cgit v1.2.1
From c838df7b5cd17daa4545f03e097791ae34679eb1 Mon Sep 17 00:00:00 2001
From: chodorowski
Date: Tue, 23 Jul 2002 03:04:00 +0000
Subject: Escaped all swedish characters and changed all strings to be unicode
strings (for consistency).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@352 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/languages/sv.py | 58 ++++++++++++++++++------------------
docutils/parsers/rst/languages/sv.py | 44 +++++++++++++--------------
2 files changed, 51 insertions(+), 51 deletions(-)
(limited to 'docutils')
diff --git a/docutils/languages/sv.py b/docutils/languages/sv.py
index e70479359..67d37df00 100644
--- a/docutils/languages/sv.py
+++ b/docutils/languages/sv.py
@@ -17,38 +17,38 @@ from docutils import nodes
labels = {
- 'author': 'Frfattare',
- 'authors': 'Frfattare',
- 'organization': 'Organisation',
- 'contact': 'Kontakt',
- 'version': 'Version',
- 'revision': 'Revision',
- 'status': 'Status',
- 'date': 'Datum',
- 'copyright': 'Copyright',
- 'abstract': 'Sammanfattning',
- 'attention': 'Observera!',
- 'caution': 'Varning!',
- 'danger': 'FARA!',
- 'error': 'Fel',
- 'hint': 'Vgledning',
- 'important': 'Viktigt',
- 'note': 'Notera',
- 'tip': 'Tips',
- 'warning': 'Varning',
- 'contents': 'Innehll'}
+ 'author': u'F\u00f6rfattare',
+ 'authors': u'F\u00f6rfattare',
+ 'organization': u'Organisation',
+ 'contact': u'Kontakt',
+ 'version': u'Version',
+ 'revision': u'Revision',
+ 'status': u'Status',
+ 'date': u'Datum',
+ 'copyright': u'Copyright',
+ 'abstract': u'Sammanfattning',
+ 'attention': u'Observera!',
+ 'caution': u'Varning!',
+ 'danger': u'FARA!',
+ 'error': u'Fel',
+ 'hint': u'V\u00e4gledning',
+ 'important': u'Viktigt',
+ 'note': u'Notera',
+ 'tip': u'Tips',
+ 'warning': u'Varning',
+ 'contents': u'Inneh\u00e5ll' }
"""Mapping of node class name to label text."""
bibliographic_fields = {
- 'frfattare': nodes.authors,
- 'organisation': nodes.organization,
- 'kontakt': nodes.contact,
- 'version': nodes.version,
- 'revision': nodes.revision,
- 'status': nodes.status,
- 'datum': nodes.date,
- 'copyright': nodes.copyright,
- 'sammanfattning': nodes.topic}
+ u'f\u00f6rfattare': nodes.authors,
+ u'organisation': nodes.organization,
+ u'kontakt': nodes.contact,
+ u'version': nodes.version,
+ u'revision': nodes.revision,
+ u'status': nodes.status,
+ u'datum': nodes.date,
+ u'copyright': nodes.copyright,
+ u'sammanfattning': nodes.topic }
"""Field name (lowcased) to node class name mapping for bibliographic fields
(field_list)."""
diff --git a/docutils/parsers/rst/languages/sv.py b/docutils/parsers/rst/languages/sv.py
index ad2454cb9..07e16a36c 100644
--- a/docutils/parsers/rst/languages/sv.py
+++ b/docutils/parsers/rst/languages/sv.py
@@ -14,26 +14,26 @@ __docformat__ = 'reStructuredText'
directives = {
- 'observera': 'attention',
- 'varning': 'caution',
- 'fara': 'danger',
- 'fel': 'error',
- 'vgledning': 'hint',
- 'viktigt': 'important',
- 'notera': 'note',
- 'tips': 'tip',
- 'varning': 'warning',
- 'frgor': 'questions',
- 'frgor-och-svar': 'questions', # NOTE: A bit long, but recommended by
- 'vanliga-frgor': 'questions', # NOTE: http://www.nada.kth.se/dataterm/
- 'meta': 'meta',
- #'bildkarta': 'imagemap', # FIXME: Translation might be to literal.
- 'bild': 'image',
- 'figur': 'figure',
- #'r': 'raw', # FIXME: Translation might be to literal.
- 'innehll': 'contents',
- #'fotnoter': 'footnotes',
- #'citeringar': 'citations',
- #'mne': 'topic',
- 'restructuredtext-test-directive': 'restructuredtext-test-directive'}
+ u'observera': 'attention',
+ u'varning': 'caution',
+ u'fara': 'danger',
+ u'fel': 'error',
+ u'v\u00e4gledning': 'hint',
+ u'viktigt': 'important',
+ u'notera': 'note',
+ u'tips': 'tip',
+ u'varning': 'warning',
+ u'fr\u00e5gor': 'questions',
+ u'fr\u00e5gor-och-svar': 'questions', # NOTE: A bit long, but recommended by
+ u'vanliga-fr\u00e5gor': 'questions', # NOTE: http://www.nada.kth.se/dataterm/
+ u'meta': 'meta',
+ # u'bildkarta': 'imagemap', # FIXME: Translation might be to literal.
+ u'bild': 'image',
+ u'figur': 'figure',
+ # u'r\u00e5': 'raw', # FIXME: Translation might be to literal.
+ u'innehll': 'contents',
+ # u'fotnoter': 'footnotes',
+ # u'citeringar': 'citations',
+ # u'\u00e4mne': 'topic',
+ u'restructuredtext-test-directive': 'restructuredtext-test-directive' }
"""Swedish name to registered (in directives/__init__.py) directive name mapping."""
--
cgit v1.2.1
From e2befb2363ac2b741e4ef450d7cd20ba2e2f38e4 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:35:21 +0000
Subject: Added options to control backlinks from footnotes/citations and
section headers (back to TOC).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@353 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index f0a4f8974..d6025e4a4 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -52,6 +52,25 @@ class OptionParser(optik.OptionParser):
('Do not include a "(View document source)" link.',
['--no-source-link'], {'action': 'store_false',
'dest': 'source_link'}),
+ ('Enable backlinks from section headers to table of contents '
+ 'entries. This is the default.',
+ ['--toc-entry-backlinks'],
+ {'dest': 'toc_backlinks', 'action': 'store_const', 'const': 'entry',
+ 'default': 'entry'}),
+ ('Enable backlinks from section headers to the top of the table of '
+ 'contents.',
+ ['--toc-top-backlinks'],
+ {'dest': 'toc_backlinks', 'action': 'store_const', 'const': 'top'}),
+ ('Disable backlinks to the table of contents.',
+ ['--no-toc-backlinks'],
+ {'dest': 'toc_backlinks', 'action': 'store_false'}),
+ ('Enable backlinks from footnotes and citations to their '
+ 'references. This is the default.',
+ ['--footnote-backlinks'],
+ {'action': 'store_true', 'default': 1}),
+ ('Disable backlinks from footnotes and citations.',
+ ['--no-footnote-backlinks'],
+ {'dest': 'footnote_backlinks', 'action': 'store_false'}),
('Set verbosity threshold; report system messages at or higher than '
' (by name or number: "info" or "1", warning/2, error/3, '
'severe/4; also, "none" or "5"). Default is 2 (warning).',
--
cgit v1.2.1
From 09d88c2d27d9781fd35f1cec44633cf4acd7d9ba Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:36:58 +0000
Subject: In case language_module is None.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@355 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/__init__.py b/docutils/parsers/rst/directives/__init__.py
index 484714588..74ff8830a 100644
--- a/docutils/parsers/rst/directives/__init__.py
+++ b/docutils/parsers/rst/directives/__init__.py
@@ -75,7 +75,7 @@ def directive(directive_name, language_module):
return _directives[normname]
try:
canonicalname = language_module.directives[normname]
- except KeyError:
+ except (KeyError, AttributeError):
try:
# Try English as a fallback:
canonicalname = _fallback_language_module.directives[normname]
--
cgit v1.2.1
From 9c1f254c9a15569eecdb31276a51628881f6a06f Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:37:44 +0000
Subject: Added "backlinks" attribute.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@356 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/parts.py | 15 +++++++++++++++
1 file changed, 15 insertions(+)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/parts.py b/docutils/parsers/rst/directives/parts.py
index 7b3d63697..d3bba86c5 100644
--- a/docutils/parsers/rst/directives/parts.py
+++ b/docutils/parsers/rst/directives/parts.py
@@ -19,8 +19,23 @@ from docutils.transforms import parts
def unchanged(arg):
return arg # unchanged!
+def backlinks(arg):
+ try:
+ value = arg.lower().strip()
+ except AttributeError:
+ raise TypeError('must supply an argument; choose from "top", '
+ '"entry", or "none"')
+ if value == 'none':
+ return None
+ elif value == 'top' or arg == 'entry':
+ return value
+ else:
+ raise ValueError(
+ '"%s" unknown; choose from "top", "entry", or "none"' % arg)
+
contents_attribute_spec = {'depth': int,
'local': unchanged,
+ 'backlinks': backlinks,
'qa': unchanged}
def contents(match, type_name, data, state, state_machine, attributes):
--
cgit v1.2.1
From 54a26a7452be9b2e0f5f0404d383e244fec5376a Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:39:23 +0000
Subject: Changed format of directve attribute error..
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@357 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index 04a9ea605..cfb934e9d 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -1598,7 +1598,7 @@ class Body(RSTState):
except KeyError, detail:
return 0, ('unknown attribute: "%s"' % detail), blank_finish
except (ValueError, TypeError), detail:
- return 0, ('invalid attribute value:\n%s' % detail), blank_finish
+ return 0, ('invalid attribute value: %s' % detail), blank_finish
except utils.ExtensionAttributeError, detail:
return 0, ('invalid attribute data: %s' % detail), blank_finish
return 1, attributes, blank_finish
--
cgit v1.2.1
From 0ef0fd6e65f2ac5221a125f6c2aa2e6d6340e8de Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:40:14 +0000
Subject: Support for optional TOC backlinks.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@358 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/parts.py | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index d109d3552..5c778fb12 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -49,19 +49,24 @@ class Contents(Transform):
startnode = self.document
if not title:
title = nodes.title('', self.language.labels['contents'])
+ if title:
+ name = title.astext()
+ topic += title
+ else:
+ name = self.language.labels['contents']
+ name = utils.normalize_name(name)
+ if not self.document.has_name(name):
+ topic['name'] = name
+ self.document.note_implicit_target(topic)
+ self.toc_id = topic['id']
+ if self.startnode.details.has_key('backlinks'):
+ self.backlinks = self.startnode.details['backlinks']
+ else:
+ self.backlinks = self.document.options.toc_backlinks
contents = self.build_contents(startnode)
if len(contents):
- if title:
- name = title.astext()
- topic += title
- else:
- name = self.language.labels['contents']
topic += contents
self.startnode.parent.replace(self.startnode, topic)
- name = utils.normalize_name(name)
- if not self.document.has_name(name):
- topic['name'] = name
- self.document.note_implicit_target(topic)
else:
self.startnode.parent.remove(self.startnode)
@@ -83,7 +88,10 @@ class Contents(Transform):
entry = nodes.paragraph('', '', reference)
item = nodes.list_item('', entry)
itemid = self.document.set_id(item)
- title['refid'] = itemid
+ if self.backlinks == 'entry':
+ title['refid'] = itemid
+ elif self.backlinks == 'top':
+ title['refid'] = self.toc_id
if level < depth:
subsects = self.build_contents(section, level)
item += subsects
--
cgit v1.2.1
From 513862cec4707b0b5f1f54460052a23e36ba7ecb Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:42:01 +0000
Subject: Changed format of directive attribute error.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@359 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/utils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/utils.py b/docutils/utils.py
index c2418d91c..8b1d7ddf9 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -275,7 +275,7 @@ def assemble_attribute_dict(attlist, attspec):
try:
attributes[name] = convertor(value)
except (ValueError, TypeError), detail:
- raise detail.__class__('(attribute "%s", value "%s") %s'
+ raise detail.__class__('(attribute: "%s"; value: %r)\n%s'
% (name, value, detail))
return attributes
--
cgit v1.2.1
From 3036132b61ec33f0d9e7f70daa6e3a25b6ae9c60 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:43:14 +0000
Subject: Added support for optional footnote/citation backlinks.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@360 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 9234463bb..0f205838d 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -328,6 +328,8 @@ class HTMLTranslator(nodes.NodeVisitor):
def visit_description(self, node):
self.body.append(self.starttag(node, 'td', ''))
+ if len(node) and isinstance(node[0], nodes.paragraph):
+ node[0].set_class('first')
def depart_description(self, node):
self.body.append('')
@@ -492,7 +494,8 @@ class HTMLTranslator(nodes.NodeVisitor):
self.footnote_backrefs(node)
def footnote_backrefs(self, node):
- if node.hasattr('backrefs'):
+ if self.document.options.footnote_backlinks \
+ and node.hasattr('backrefs'):
backrefs = node['backrefs']
if len(backrefs) == 1:
self.context.append(('', ''))
@@ -907,7 +910,7 @@ class SimpleListChecker(nodes.GenericNodeVisitor):
"""
Raise `nodes.SkipNode` if non-simple list item is encountered.
- Here "simple" means a list item containing anything other than a single
+ Here "simple" means a list item containing nothing other than a single
paragraph, a simple list, or a paragraph followed by a simple list.
"""
--
cgit v1.2.1
From 28df6f89902b7c24bd945c5857982d0ebfb7506b Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 24 Jul 2002 01:47:56 +0000
Subject: German language mappings; added to project. Thanks to Gunnar Schwant
for the translations.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@363 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/languages/de.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
create mode 100644 docutils/languages/de.py
(limited to 'docutils')
diff --git a/docutils/languages/de.py b/docutils/languages/de.py
new file mode 100644
index 000000000..8c512dc14
--- /dev/null
+++ b/docutils/languages/de.py
@@ -0,0 +1,57 @@
+#! /usr/bin/env python
+
+"""
+:Authors: David Goodger; Gunnar Schwant
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+German language mappings for language-dependent features of Docutils.
+"""
+
+__docformat__ = 'reStructuredText'
+
+from docutils import nodes
+
+
+labels = {
+ 'author': 'Autor',
+ 'authors': 'Autoren',
+ 'organization': 'Organisation',
+ 'contact': 'Kontakt',
+ 'version': 'Version',
+ 'revision': 'Revision',
+ 'status': 'Status',
+ 'date': 'Datum',
+ 'copyright': 'Copyright',
+ 'abstract': 'Zusammenfassung',
+ 'attention': 'Achtung!',
+ 'caution': 'Vorsicht!',
+ 'danger': '!GEFAHR!',
+ 'error': 'Fehler',
+ 'hint': 'Hinweis',
+ 'important': 'Wichtig',
+ 'note': 'Bemerkung',
+ 'tip': 'Tipp',
+ 'warning': 'Warnung',
+ 'contents': 'Inhalt'}
+"""Mapping of node class name to label text."""
+
+bibliographic_fields = {
+ 'autor': nodes.author,
+ 'autoren': nodes.authors,
+ 'organisation': nodes.organization,
+ 'kontakt': nodes.contact,
+ 'version': nodes.version,
+ 'revision': nodes.revision,
+ 'status': nodes.status,
+ 'datum': nodes.date,
+ 'copyright': nodes.copyright,
+ 'zusammenfassung': nodes.topic}
+"""Field name (lowcased) to node class name mapping for bibliographic fields
+(field_list)."""
+
+author_separators = [';', ',']
+"""List of separator strings for the 'Authors' bibliographic field. Tried in
+order."""
--
cgit v1.2.1
From 15f41ca47d032c33376f939059faf9eb82ac3f51 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 25 Jul 2002 01:46:28 +0000
Subject: Added default usage message and description.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@366 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index 5f2af0be3..eb6f35d20 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -136,18 +136,23 @@ class Publisher:
self.process_command_line(argv, usage, description, option_spec)
document = self.reader.read(self.source, self.parser, self.options)
output = self.writer.write(document, self.destination)
- if self.options.dump_internal_document_attributes:
+ if self.options.dump_internals:
from pprint import pformat
print >>sys.stderr, pformat(document.__dict__)
return output
+default_usage = '%prog [options] [ []]'
+default_description = ('Reads from (default is stdin) and writes to '
+ ' (default is stdout).')
+
def publish(reader=None, reader_name='standalone',
parser=None, parser_name='restructuredtext',
writer=None, writer_name='pseudoxml',
- argv=None, usage=None, description=None, option_spec=None):
+ argv=None, usage=default_usage, description=default_description,
+ option_spec=None):
"""
- A convenience function for file I/O front-ends; set up & run a
+ A convenience function for file I/O front ends; set up & run a
`Publisher`.
"""
pub = Publisher(reader, parser, writer)
--
cgit v1.2.1
From 8773019e39e7199f06b0bd263b778a74ffb86a61 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 25 Jul 2002 01:47:58 +0000
Subject: docstrings & option descriptions
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@367 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index d6025e4a4..759e11472 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -7,7 +7,7 @@
:Date: $Date$
:Copyright: This module has been placed in the public domain.
-Command-line and common processing for Docutils front-ends.
+Command-line and common processing for Docutils front-end tools.
"""
__docformat__ = 'reStructuredText'
@@ -32,7 +32,7 @@ class OptionParser(optik.OptionParser):
cmdline_options = (
'General Docutils Options',
None,
- (('Include a "Generated by Docutils" credit with a link, at the end '
+ (('Include a "Generated by Docutils" credit and link at the end '
'of the document.',
['--generator', '-g'], {'action': 'store_true'}),
('Do not include a generator credit.',
@@ -47,9 +47,9 @@ class OptionParser(optik.OptionParser):
('Do not include a datestamp of any kind.',
['--no-datestamp'], {'action': 'store_const', 'const': None,
'dest': 'datestamp'}),
- ('Include a "View document source." link.',
+ ('Include a "View document source" link.',
['--source-link', '-s'], {'action': 'store_true'}),
- ('Do not include a "(View document source)" link.',
+ ('Do not include a "View document source" link.',
['--no-source-link'], {'action': 'store_false',
'dest': 'source_link'}),
('Enable backlinks from section headers to table of contents '
@@ -109,15 +109,14 @@ class OptionParser(optik.OptionParser):
['--help', '-h'], {'action': 'help'}),
# Hidden options, for development use only:
(optik.SUPPRESS_HELP,
- ['--dump-internal-document-attributes'],
+ ['--dump-internals'],
{'action': 'store_true'}),))
- """Command-line option specifications, common to all Docutils front-ends.
- One or more sets of option group title, description, and a
- list/tuple of tuples: ``('help text', [list of option strings],
- {keyword arguments})``. Group title and/or description may be
- `None`; no group title implies no group, just a list of single
- options. Option specs from Docutils components are also used (see
- `populate_from_components()`)."""
+ """Command-line option specifications, common to all Docutils front ends.
+ One or more sets of option group title, description, and a list/tuple of
+ tuples: ``('help text', [list of option strings], {keyword arguments})``.
+ Group title and/or description may be `None`; no group title implies no
+ group, just a list of single options. Option specs from Docutils
+ components are also used (see `populate_from_components()`)."""
version_template = '%%prog (Docutils %s)' % docutils.__version__
--
cgit v1.2.1
From 659ceac33a3aa10d234d7eaf8e4f4adc2778df99 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 25 Jul 2002 01:49:17 +0000
Subject: one last 8-bit char; cleanup
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@368 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/languages/sv.py | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/languages/sv.py b/docutils/parsers/rst/languages/sv.py
index 07e16a36c..2d45a5222 100644
--- a/docutils/parsers/rst/languages/sv.py
+++ b/docutils/parsers/rst/languages/sv.py
@@ -24,16 +24,18 @@ directives = {
u'tips': 'tip',
u'varning': 'warning',
u'fr\u00e5gor': 'questions',
- u'fr\u00e5gor-och-svar': 'questions', # NOTE: A bit long, but recommended by
- u'vanliga-fr\u00e5gor': 'questions', # NOTE: http://www.nada.kth.se/dataterm/
+ # NOTE: A bit long, but recommended by http://www.nada.kth.se/dataterm/:
+ u'fr\u00e5gor-och-svar': 'questions',
+ u'vanliga-fr\u00e5gor': 'questions',
u'meta': 'meta',
- # u'bildkarta': 'imagemap', # FIXME: Translation might be to literal.
+ # u'bildkarta': 'imagemap', # FIXME: Translation might be too literal.
u'bild': 'image',
u'figur': 'figure',
- # u'r\u00e5': 'raw', # FIXME: Translation might be to literal.
- u'innehll': 'contents',
+ # u'r\u00e5': 'raw', # FIXME: Translation might be too literal.
+ u'inneh\u00e5ll': 'contents',
# u'fotnoter': 'footnotes',
# u'citeringar': 'citations',
# u'\u00e4mne': 'topic',
u'restructuredtext-test-directive': 'restructuredtext-test-directive' }
-"""Swedish name to registered (in directives/__init__.py) directive name mapping."""
+"""Swedish name to registered (in directives/__init__.py) directive name
+mapping."""
--
cgit v1.2.1
From 8d07f5fac59043b0af54a372a3ffbc4ed10f6cf3 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 25 Jul 2002 01:49:57 +0000
Subject: Simple tables bug fix.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@369 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/tableparser.py | 3 +++
1 file changed, 3 insertions(+)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/tableparser.py b/docutils/parsers/rst/tableparser.py
index 51beb6b97..d304445c8 100644
--- a/docutils/parsers/rst/tableparser.py
+++ b/docutils/parsers/rst/tableparser.py
@@ -426,6 +426,9 @@ class SimpleTableParser(TableParser):
if end < 0:
end = len(line)
cols.append((begin, end))
+ if self.columns:
+ # Allow for an unbounded rightmost column:
+ cols[-1] = (cols[-1][0], self.columns[-1][1])
return cols
def init_row(self, colspec, offset):
--
cgit v1.2.1
From a1713e3ba0b936004190f616c62f2189e0953b59 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 27 Jul 2002 03:42:23 +0000
Subject: Added "Dedication" bibliographic field mappings.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@376 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/languages/en.py | 2 ++
1 file changed, 2 insertions(+)
(limited to 'docutils')
diff --git a/docutils/languages/en.py b/docutils/languages/en.py
index 5b97dadb7..8488a902b 100644
--- a/docutils/languages/en.py
+++ b/docutils/languages/en.py
@@ -26,6 +26,7 @@ labels = {
'status': 'Status',
'date': 'Date',
'copyright': 'Copyright',
+ 'dedication': 'Dedication',
'abstract': 'Abstract',
'attention': 'Attention!',
'caution': 'Caution!',
@@ -49,6 +50,7 @@ bibliographic_fields = {
'status': nodes.status,
'date': nodes.date,
'copyright': nodes.copyright,
+ 'dedication': nodes.topic,
'abstract': nodes.topic}
"""Field name (lowcased) to node class name mapping for bibliographic fields
(field_list)."""
--
cgit v1.2.1
From 674653b218bfaa9ebe3f73f28b7dc1c744e1ab54 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 27 Jul 2002 03:45:39 +0000
Subject: Added support for "Dedication" and generic bibliographic fields.
(Not tested yet.)
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@377 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/frontmatter.py | 54 +++++++++++++++++---------------------
1 file changed, 24 insertions(+), 30 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/frontmatter.py b/docutils/transforms/frontmatter.py
index f61e828a1..1586bec5a 100644
--- a/docutils/transforms/frontmatter.py
+++ b/docutils/transforms/frontmatter.py
@@ -131,10 +131,11 @@ class DocTitle(Transform):
subtitle[:] = subsection[0][:]
document = self.document
document[:] = (document[:1] # document title
- + [subtitle]
- + document[1:index] # everything that was in the document
- # before the section
- + subsection[1:]) # everything that was in the subsection
+ + [subtitle]
+ # everything that was before the section:
+ + document[1:index]
+ # everything that was in the subsection:
+ + subsection[1:])
return 1
def candidate_index(self):
@@ -164,8 +165,9 @@ class DocInfo(Transform):
Given a field list as the first non-comment element after the
document title and subtitle (if present), registered bibliographic
field names are transformed to the corresponding DTD elements,
- becoming child elements of the "docinfo" element (except for the
- abstract, which becomes a "topic" element after "docinfo").
+ becoming child elements of the "docinfo" element (except for a
+ dedication and/or an abstract, which become "topic" elements after
+ "docinfo").
For example, given this document fragment after parsing::
@@ -234,19 +236,16 @@ class DocInfo(Transform):
if isinstance(candidate, nodes.field_list):
biblioindex = document.first_child_not_matching_class(
nodes.Titular)
- nodelist, remainder = self.extract_bibliographic(candidate)
- if remainder:
- document[index] = remainder
- else:
- del document[index]
+ nodelist = self.transform_bibliographic(candidate)
+ del document[index] # untransformed field list (candidate)
document[biblioindex:biblioindex] = nodelist
return
def extract_bibliographic(self, field_list):
docinfo = nodes.docinfo()
- remainder = []
bibliofields = self.language.bibliographic_fields
- abstract = None
+ labels = self.language.labels
+ topics = {'dedication': None, 'abstract': None}
for field in field_list:
try:
name = field[0][0].astext()
@@ -265,29 +264,25 @@ class DocInfo(Transform):
if issubclass(biblioclass, nodes.authors):
self.extract_authors(field, name, docinfo)
elif issubclass(biblioclass, nodes.topic):
- if abstract:
+ if topics[normedname]:
field[-1] += self.document.reporter.warning(
- 'There can only be one abstract.')
+ 'There can only be one "%s" field.' % name)
raise TransformError
- title = nodes.title(
- name, self.language.labels['abstract'])
- abstract = nodes.topic('', title, CLASS='abstract',
- *field[1].children)
+ title = nodes.title(name, labels[normedname])
+ topics[normedname] = biblioclass(
+ '', title, CLASS='normedname', *field[1].children)
else:
docinfo.append(biblioclass('', *field[1].children))
except TransformError:
- remainder.append(field)
+ docinfo.append(field)
continue
nodelist = []
if len(docinfo) != 0:
nodelist.append(docinfo)
- if abstract:
- nodelist.append(abstract)
- if remainder:
- field_list[:] = remainder
- else:
- field_list = None
- return nodelist, field_list
+ for name in ('dedication', 'abstract'):
+ if topics[name]:
+ nodelist.append(topics[name])
+ return nodelist
def check_empty_biblio_field(self, field, name):
if len(field[1]) < 1:
@@ -303,9 +298,8 @@ class DocInfo(Transform):
return None
if not isinstance(field[1][0], nodes.paragraph):
field[-1] += self.document.reporter.warning(
- 'Cannot extract bibliographic field "%s" containing anything '
- 'other than a single paragraph.'
- % name)
+ 'Cannot extract bibliographic field "%s" containing '
+ 'anything other than a single paragraph.' % name)
return None
return 1
--
cgit v1.2.1
From 6b056f9e44a429f6f1f6641e37dc383a02a97d42 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 27 Jul 2002 03:48:12 +0000
Subject: Added support for generic bibliographic fields.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@378 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 0f205838d..0903a7b59 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -88,6 +88,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.colspecs = []
self.compact_p = 1
self.compact_simple = None
+ self.in_docinfo = None
def astext(self):
return ''.join(self.head_prefix + self.head
@@ -340,15 +341,17 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('
", each with different effects. It would
+ be best to stick with strict body elements in list items, but they
+ affect vertical spacing in browsers (although they really
+ shouldn't).
+
+ Here is an outline of the optimization:
+
+ - Check for and omit
tags in "simple" lists: list items
+ contain either a single paragraph, a nested simple list, or a
+ paragraph followed by a nested simple list. This means that
+ this list can be compact:
+
+ - Item 1.
+ - Item 2.
+
+ But this list cannot be compact:
+
+ - Item 1.
+
+ This second paragraph forces space between list items.
+
+ - Item 2.
+
+ - In non-list contexts, omit
tags on a paragraph if that
+ paragraph is the only child of its parent (footnotes & citations
+ are allowed a label first).
+
+ - Regardless of the above, in definitions, table cells, field
+ bodies, option descriptions, and list items, mark the first
+ child with 'class="first"' if it is a paragraph. The stylesheet
+ sets the top margin to 0 for these paragraphs.
+ """
+
xml_declaration = '\n'
doctype = '
Date: Sat, 27 Jul 2002 14:53:16 +0000
Subject: Identify backrefs.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@389 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 52e739145..63773ed30 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -544,12 +544,14 @@ class HTMLTranslator(nodes.NodeVisitor):
backrefs = node['backrefs']
if len(backrefs) == 1:
self.context.append(('', ''))
- self.context.append(('' % backrefs[0],))
+ self.context.append((''
+ % backrefs[0],))
else:
i = 1
backlinks = []
for backref in backrefs:
- backlinks.append('%s' % (backref, i))
+ backlinks.append('%s'
+ % (backref, i))
i += 1
self.context.append(('', '(%s) ' % ', '.join(backlinks)))
self.context.append(('',))
@@ -912,7 +914,8 @@ class HTMLTranslator(nodes.NodeVisitor):
self.starttag(node, 'h%s' % self.section_level, ''))
context = ''
if node.hasattr('refid'):
- self.body.append('' % node['refid'])
+ self.body.append(''
+ % node['refid'])
context = ''
self.context.append('%s\n' % (context, self.section_level))
--
cgit v1.2.1
From 61d204ba2bacd28ca39307302970bda873e053d8 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 27 Jul 2002 15:07:53 +0000
Subject: Footer fiddling.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@391 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 63773ed30..2110c4424 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -525,7 +525,8 @@ class HTMLTranslator(nodes.NodeVisitor):
def depart_footer(self, node):
start = self.context.pop()
- footer = ([self.starttag(node, 'div', CLASS='footer'), '\n']
+ footer = (['\n',
+ self.starttag(node, 'div', CLASS='footer')]
+ self.body[start:] + ['\n'])
self.body_suffix[:0] = footer
del self.body[start:]
--
cgit v1.2.1
From 087383956c0c5aba2337ab961e66b3ef18e2445f Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 27 Jul 2002 15:49:37 +0000
Subject: docstring
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@393 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 759e11472..f9e2b7880 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -20,7 +20,13 @@ from docutils import optik
class OptionParser(optik.OptionParser):
"""
- Parser for command-line and library use. The `cmdline_options` specification here and in other Docutils components are merged
+ Parser for command-line and library use. The `cmdline_options`
+ specification here and in other Docutils components are merged to
+ build the set of command-line options for this process.
+
+ Common options (defined below) and component-specific options must
+ not conflict. Short options are reserved for common options, and
+ components are restrict to using long options.
"""
threshold_choices = 'info 1 warning 2 error 3 severe 4 none 5'.split()
--
cgit v1.2.1
From fe66cb1cd619d5abd815be4b235b116cd3c43807 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 15:35:28 +0000
Subject: Added ``relative_uri(source, target)``.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@396 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/utils.py | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
(limited to 'docutils')
diff --git a/docutils/utils.py b/docutils/utils.py
index 8b1d7ddf9..44a537667 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -13,6 +13,8 @@ Miscellaneous utilities for the documentation utilities.
__docformat__ = 'reStructuredText'
import sys
+import os
+import os.path
from types import StringType, UnicodeType
from docutils import ApplicationError, DataError
from docutils import frontend, nodes
@@ -347,3 +349,24 @@ def clean_rcs_keywords(paragraph, keyword_substitutions):
if match:
textnode.data = pattern.sub(substitution, textnode.data)
return
+
+def relative_uri(source, target):
+ """
+ Build and return a URI to `target`, relative to `source`.
+
+ If there is no common prefix, return the absolute path to `target`.
+ """
+ source_parts = os.path.abspath(source).split(os.sep)
+ target_parts = os.path.abspath(target).split(os.sep)
+ if source_parts[:2] != target_parts[:2]:
+ # Nothing in common between paths. Return absolute path.
+ return '/'.join(target_parts)
+ source_parts.reverse()
+ target_parts.reverse()
+ while source_parts[-1] == target_parts[-1]:
+ # Remove path components in common:
+ source_parts.pop()
+ target_parts.pop()
+ target_parts.reverse()
+ parts = ['..'] * (len(source_parts) - 1) + target_parts
+ return '/'.join(parts)
--
cgit v1.2.1
From 52307a7656fe38d3f35126a9bd90170e4fd10912 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 17:20:00 +0000
Subject: Source & destination paths now returned inside option values object.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@397 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index eb6f35d20..80344a793 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -120,10 +120,11 @@ class Publisher:
option_spec, **defaults)
if argv is None:
argv = sys.argv[1:]
- self.options, source, destination = option_parser.parse_args(argv)
- self.source = self.source_class(self.options, source_path=source)
+ self.options = option_parser.parse_args(argv)
+ self.source = self.source_class(self.options,
+ source_path=self.options.source)
self.destination = self.destination_class(
- self.options, destination_path=destination)
+ self.options, destination_path=self.options.destination)
def publish(self, argv=None, usage=None, description=None,
option_spec=None):
--
cgit v1.2.1
From 00721f31c013181f753ed200b3fa0414f143f780 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 17:38:04 +0000
Subject: - Added ``store_multiple()`` option callback. - Added "--source-url"
option. - Return source & destination path in option values object.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@398 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 27 ++++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index f9e2b7880..f2be2d46a 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -17,6 +17,19 @@ import docutils
from docutils import optik
+def store_multiple(option, opt, value, parser, *args, **kwargs):
+ """
+ Store multiple values in `parser.values`. (Option callback.)
+
+ Store `None` for each attribute named in `args`, and store the value for
+ each key (attribute name) in `kwargs`.
+ """
+ for attribute in args:
+ setattr(parser.values, attribute, None)
+ for key, value in kwargs.items():
+ setattr(parser.values, key, value)
+
+
class OptionParser(optik.OptionParser):
"""
@@ -53,11 +66,15 @@ class OptionParser(optik.OptionParser):
('Do not include a datestamp of any kind.',
['--no-datestamp'], {'action': 'store_const', 'const': None,
'dest': 'datestamp'}),
- ('Include a "View document source" link.',
+ ('Include a "View document source" link (relative to destination).',
['--source-link', '-s'], {'action': 'store_true'}),
+ ('Use the supplied for a "View document source" link; '
+ 'implies --source-link.',
+ ['--source-url'], {'metavar': ''}),
('Do not include a "View document source" link.',
- ['--no-source-link'], {'action': 'store_false',
- 'dest': 'source_link'}),
+ ['--no-source-link'],
+ {'action': 'callback', 'callback': store_multiple,
+ 'callback_args': ('source_link', 'source_url')}),
('Enable backlinks from section headers to table of contents '
'entries. This is the default.',
['--toc-entry-backlinks'],
@@ -158,8 +175,8 @@ class OptionParser(optik.OptionParser):
def check_values(self, values, args):
values.report_level = self.check_threshold(values.report_level)
values.halt_level = self.check_threshold(values.halt_level)
- source, destination = self.check_args(args)
- return values, source, destination
+ values.source, values.destination = self.check_args(args)
+ return values
def check_threshold(self, level):
try:
--
cgit v1.2.1
From efd006184800e755c1baef8b7fc5790bf301bb96 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 17:45:16 +0000
Subject: Changed "Decorations" transform to produce relative source links.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@400 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index e4ad65b48..9e58679bf 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -57,10 +57,15 @@ class Decorations(Transform):
options = self.document.options
if options.generator or options.datestamp or options.source_link:
text = []
- if options.source_link and self.document.hasattr('source'):
+ if options.source_link and options.source or options.source_uri:
+ if options.source_uri:
+ source = options.source_uri
+ else:
+ source = utils.relative_uri(options.destination,
+ options.source)
text.extend([
nodes.reference('', 'View document source',
- refuri=self.document['source']),
+ refuri=source),
nodes.Text('. ')])
if options.datestamp:
datestamp = time.strftime(options.datestamp, time.gmtime())
--
cgit v1.2.1
From ef63f320763f423632642e4b2aeb2b9570d4eedf Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 17:49:48 +0000
Subject: bugfix
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@402 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index 9e58679bf..004923887 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -55,9 +55,10 @@ class Decorations(Transform):
# @@@ Text is hard-coded for now.
# Should be made dynamic (language-dependent).
options = self.document.options
- if options.generator or options.datestamp or options.source_link:
+ if options.generator or options.datestamp or options.source_link \
+ or options.source_url:
text = []
- if options.source_link and options.source or options.source_uri:
+ if options.source_link and options.source or options.source_url:
if options.source_uri:
source = options.source_uri
else:
--
cgit v1.2.1
From e13eaad4a71d8536f52ca0445ee27b9b4e214eec Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 17:51:05 +0000
Subject: bugfix
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@403 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index 004923887..bc5a1bb74 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -59,8 +59,8 @@ class Decorations(Transform):
or options.source_url:
text = []
if options.source_link and options.source or options.source_url:
- if options.source_uri:
- source = options.source_uri
+ if options.source_url:
+ source = options.source_url
else:
source = utils.relative_uri(options.destination,
options.source)
--
cgit v1.2.1
From c7021872c6b1e32f2c2443b715b8809a094997ee Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 18:36:34 +0000
Subject: Relative URLs for stylesheet links.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@405 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 12 +++++++-----
docutils/writers/pep_html.py | 1 +
2 files changed, 8 insertions(+), 5 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 2110c4424..283edcac3 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -108,14 +108,16 @@ class HTMLTranslator(nodes.NodeVisitor):
def __init__(self, document):
nodes.NodeVisitor.__init__(self, document)
- self.language = languages.get_language(document.options.language_code)
+ options = document.options
+ self.language = languages.get_language(options.language_code)
self.head_prefix = [
- self.xml_declaration % document.options.output_encoding,
+ self.xml_declaration % options.output_encoding,
self.doctype,
- self.html_head % document.options.language_code,
- self.content_type % document.options.output_encoding,
+ self.html_head % options.language_code,
+ self.content_type % options.output_encoding,
self.generator,
- self.stylesheet_link % document.options.stylesheet]
+ self.stylesheet_link % utils.relative_uri(options.destination,
+ options.stylesheet)]
self.head = []
self.body_prefix = ['\n\n']
self.body = []
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index 2a0c273ea..9aff8d062 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -53,6 +53,7 @@ class Writer(html4css1.Writer):
stylesheet = options.pep_stylesheet
if stylesheet is None:
stylesheet = options.stylesheet
+ stylesheet = utils.relative_uri(options.destination, stylesheet)
pyhome = options.python_home
pephome = options.pep_home
if pyhome == '..':
--
cgit v1.2.1
From 6e912150d2857fd9067754fbfb9d319f1f7b59c0 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 18:40:19 +0000
Subject: omission
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@406 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 2 +-
docutils/writers/pep_html.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 283edcac3..d1a8fda04 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -21,7 +21,7 @@ import sys
import time
import re
from types import ListType
-from docutils import writers, nodes, languages
+from docutils import nodes, utils, writers, languages
class Writer(writers.Writer):
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index 9aff8d062..61689fd59 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -15,7 +15,7 @@ __docformat__ = 'reStructuredText'
import sys
#import random
-from docutils import nodes, optik
+from docutils import nodes, optik, utils
from docutils.writers import html4css1
--
cgit v1.2.1
From 0e1aadf8cc6ace83cb42ca97d89fa9d1649ad396 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 19:37:58 +0000
Subject: Added ``read_config_file()`` option callback & "--config" option.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@408 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 13 +++++++++++++
1 file changed, 13 insertions(+)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index f2be2d46a..100027497 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -29,6 +29,16 @@ def store_multiple(option, opt, value, parser, *args, **kwargs):
for key, value in kwargs.items():
setattr(parser.values, key, value)
+def read_config_file(option, opt, value, parser):
+ """
+ Read a configuration file during option processing. (Option callback.)
+ """
+ config = ConfigParser()
+ config.read(value)
+ if config.has_section('options'):
+ for entry in config.options('options'):
+ setattr(parser.values, entry, config.get('options', entry))
+
class OptionParser(optik.OptionParser):
@@ -126,6 +136,9 @@ class OptionParser(optik.OptionParser):
' Default is "en" (English).',
['--language', '-l'], {'dest': 'language_code', 'default': 'en',
'metavar': ''}),
+ ('Read this configuration .',
+ ['--config'], {'metavar': '', 'type': 'string',
+ 'action': 'callback', 'callback': read_config_file})
("Show this program's version number and exit.",
['--version'], {'action': 'version'}),
('Show this help message and exit.',
--
cgit v1.2.1
From fad349b8d9dac2aea4e20397ff4ff74143247622 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 28 Jul 2002 19:58:29 +0000
Subject: comma
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@411 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 100027497..d841a3774 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -138,7 +138,7 @@ class OptionParser(optik.OptionParser):
'metavar': ''}),
('Read this configuration .',
['--config'], {'metavar': '', 'type': 'string',
- 'action': 'callback', 'callback': read_config_file})
+ 'action': 'callback', 'callback': read_config_file}),
("Show this program's version number and exit.",
['--version'], {'action': 'version'}),
('Show this help message and exit.',
--
cgit v1.2.1
From 542dc656827c94acf719e1d942053787b5752b0a Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 31 Jul 2002 01:31:49 +0000
Subject: docstring
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@418 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index 52a9e500b..ba75a4427 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -73,8 +73,8 @@ class Component:
"""Names for this component. Override in subclasses."""
cmdline_options = ()
- """Command-line option specification. A list/tuple of tuples:
- ``('help text', [list of option strings], {keyword arguments})``."""
+ """Command-line option specification.
+ See `docutils.frontend.OptionParser`."""
def supports(self, format):
"""
--
cgit v1.2.1
From acd9230bd930f072e3857c81da4a8e138957b379 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 31 Jul 2002 01:33:11 +0000
Subject: Updated config file & command-line processing.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@419 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index 80344a793..9e836c6be 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -17,9 +17,8 @@ custom component objects first, and pass *them* to
__docformat__ = 'reStructuredText'
import sys
-import os.path
from docutils import Component
-from docutils import readers, parsers, writers, io
+from docutils import frontend, io, readers, parsers, writers
from docutils.frontend import OptionParser, ConfigParser
@@ -29,12 +28,6 @@ class Publisher:
A facade encapsulating the high-level logic of a Docutils system.
"""
- config_files = ('/etc/docutils.conf', # system-wide
- './docutils.conf', # project-specific
- os.path.expanduser('~/.docutils')) # user-specific
- """Docutils configuration files, using ConfigParser syntax (section
- 'options'). Later files override earlier ones."""
-
def __init__(self, reader=None, parser=None, writer=None,
source=None, source_class=io.FileIO,
destination=None, destination_class=io.FileIO,
@@ -84,10 +77,10 @@ class Publisher:
def setup_option_parser(self, usage=None, description=None,
option_spec=None, **defaults):
config = ConfigParser()
- config.read(self.config_files)
- if config.has_section('options'):
- for option in config.options('options'):
- defaults[option] = config.get('options', option)
+ config.read_standard_files()
+ config_options = config.get_section('options')
+ frontend.make_paths_absolute(config_options)
+ defaults.update(config_options)
option_parser = OptionParser(
components=(option_spec, self.reader, self.parser, self.writer),
usage=usage, description=description)
@@ -121,10 +114,12 @@ class Publisher:
if argv is None:
argv = sys.argv[1:]
self.options = option_parser.parse_args(argv)
+
+ def set_io(self):
self.source = self.source_class(self.options,
- source_path=self.options.source)
+ source_path=self.options._source)
self.destination = self.destination_class(
- self.options, destination_path=self.options.destination)
+ self.options, destination_path=self.options._destination)
def publish(self, argv=None, usage=None, description=None,
option_spec=None):
@@ -135,6 +130,7 @@ class Publisher:
"""
if self.options is None:
self.process_command_line(argv, usage, description, option_spec)
+ self.set_io()
document = self.reader.read(self.source, self.parser, self.options)
output = self.writer.write(document, self.destination)
if self.options.dump_internals:
--
cgit v1.2.1
From 3442dc02845bbf4569ddfa838bf1ea13449346fc Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 31 Jul 2002 01:38:04 +0000
Subject: Added "--quiet" option. Path-related settings now made absolute,
improving batch flexibility.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@420 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 92 insertions(+), 9 deletions(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index d841a3774..be31637de 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -8,13 +8,22 @@
:Copyright: This module has been placed in the public domain.
Command-line and common processing for Docutils front-end tools.
+
+Exports the following classes:
+
+- `OptionParser`: Standard Docutils command-line processing.
+- `Values`: Option values; objects are simple structs (``object.attribute``).
+- `ConfigParser`: Standard Docutils config file processing.
"""
__docformat__ = 'reStructuredText'
+import os
+import os.path
import ConfigParser as CP
import docutils
from docutils import optik
+from docutils.optik import Values
def store_multiple(option, opt, value, parser, *args, **kwargs):
@@ -33,11 +42,25 @@ def read_config_file(option, opt, value, parser):
"""
Read a configuration file during option processing. (Option callback.)
"""
- config = ConfigParser()
- config.read(value)
- if config.has_section('options'):
- for entry in config.options('options'):
- setattr(parser.values, entry, config.get('options', entry))
+ config_parser = ConfigParser()
+ config_parser.read(value)
+ settings = config_parser.get_section('options')
+ make_paths_absolute(settings, os.path.dirname(value))
+ parser.values.__dict__.update(settings)
+
+relative_path_options = ('warning_stream', 'stylesheet', 'pep_stylesheet',
+ 'pep_template')
+
+def make_paths_absolute(dictionary, base_path=None):
+ """
+ Interpret filesystem path settings relative to the `base_path` given.
+ """
+ if base_path is None:
+ base_path = os.getcwd()
+ for option in relative_path_options:
+ if dictionary.has_key(option) and dictionary[option]:
+ dictionary[option] = os.path.normpath(
+ os.path.join(base_path, dictionary[option]))
class OptionParser(optik.OptionParser):
@@ -113,6 +136,9 @@ class OptionParser(optik.OptionParser):
'"--report=info".)',
['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
'dest': 'report_level'}),
+ ('Don't report any system messages. (Same as "--report=none".)',
+ ['--quiet', '-q'], {'action': 'store_const', 'const': 'none',
+ 'dest': 'report_level'}),
('Set the threshold () at or above which system messages are '
'converted to exceptions, halting execution immediately. Levels '
'as in --report. Default is 4 (severe).',
@@ -136,7 +162,7 @@ class OptionParser(optik.OptionParser):
' Default is "en" (English).',
['--language', '-l'], {'dest': 'language_code', 'default': 'en',
'metavar': ''}),
- ('Read this configuration .',
+ ('Read configuration options from , if it exists.',
['--config'], {'metavar': '', 'type': 'string',
'action': 'callback', 'callback': read_config_file}),
("Show this program's version number and exit.",
@@ -186,9 +212,12 @@ class OptionParser(optik.OptionParser):
i += 3
def check_values(self, values, args):
- values.report_level = self.check_threshold(values.report_level)
- values.halt_level = self.check_threshold(values.halt_level)
- values.source, values.destination = self.check_args(args)
+ if hasattr(values, 'report_level'):
+ values.report_level = self.check_threshold(values.report_level)
+ if hasattr(values, 'halt_level'):
+ values.halt_level = self.check_threshold(values.halt_level)
+ values._source, values._destination = self.check_args(args)
+ make_paths_absolute(values.__dict__, os.getcwd())
return values
def check_threshold(self, level):
@@ -213,8 +242,62 @@ class OptionParser(optik.OptionParser):
class ConfigParser(CP.ConfigParser):
+ standard_config_files = (
+ '/etc/docutils.conf', # system-wide
+ './docutils.conf', # project-specific
+ os.path.expanduser('~/.docutils')) # user-specific
+ """Docutils configuration files, using ConfigParser syntax (section
+ 'options'). Later files override earlier ones."""
+
+ def read_standard_files(self):
+ self.read(self.standard_config_files)
+
def optionxform(self, optionstr):
"""
Transform '-' to '_' so the cmdline form of option names can be used.
"""
return optionstr.lower().replace('-', '_')
+
+ def get_section(self, section, raw=0, vars=None):
+ """
+ Return a given section as a dictionary (empty if the section
+ doesn't exist).
+
+ All % interpolations are expanded in the return values, based on the
+ defaults passed into the constructor, unless the optional argument
+ `raw` is true. Additional substitutions may be provided using the
+ `vars` argument, which must be a dictionary whose contents overrides
+ any pre-existing defaults.
+
+ The section DEFAULT is special.
+ """
+ try:
+ sectdict = self._ConfigParser__sections[section].copy()
+ except KeyError:
+ sectdict = {}
+ d = self._ConfigParser__defaults.copy()
+ d.update(sectdict)
+ # Update with the entry specific variables
+ if vars:
+ d.update(vars)
+ if raw:
+ return sectdict
+ # do the string interpolation
+ for option in sectdict.keys():
+ rawval = sectdict[option]
+ value = rawval # Make it a pretty variable name
+ depth = 0
+ while depth < 10: # Loop through this until it's done
+ depth += 1
+ if value.find("%(") >= 0:
+ try:
+ value = value % d
+ except KeyError, key:
+ raise CP.InterpolationError(key, option, section,
+ rawval)
+ else:
+ break
+ if value.find("%(") >= 0:
+ raise CP.InterpolationDepthError(option, section, rawval)
+ sectdict[option] = value
+ return sectdict
--
cgit v1.2.1
From c3dd163385425e7e2df847faef58c3bdb22d19a4 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 31 Jul 2002 01:39:19 +0000
Subject: bugfix
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@422 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/utils.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/utils.py b/docutils/utils.py
index 44a537667..c8a0be2ba 100644
--- a/docutils/utils.py
+++ b/docutils/utils.py
@@ -363,7 +363,8 @@ def relative_uri(source, target):
return '/'.join(target_parts)
source_parts.reverse()
target_parts.reverse()
- while source_parts[-1] == target_parts[-1]:
+ while (source_parts and target_parts
+ and source_parts[-1] == target_parts[-1]):
# Remove path components in common:
source_parts.pop()
target_parts.pop()
--
cgit v1.2.1
From 60e5c1371c60c00dc4c76d684f263021a703c3a7 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 31 Jul 2002 01:49:12 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@425 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/universal.py | 6 +++---
docutils/writers/html4css1.py | 2 +-
docutils/writers/pep_html.py | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/universal.py b/docutils/transforms/universal.py
index bc5a1bb74..dc4a97fb1 100644
--- a/docutils/transforms/universal.py
+++ b/docutils/transforms/universal.py
@@ -58,12 +58,12 @@ class Decorations(Transform):
if options.generator or options.datestamp or options.source_link \
or options.source_url:
text = []
- if options.source_link and options.source or options.source_url:
+ if options.source_link and options._source or options.source_url:
if options.source_url:
source = options.source_url
else:
- source = utils.relative_uri(options.destination,
- options.source)
+ source = utils.relative_uri(options._destination,
+ options._source)
text.extend([
nodes.reference('', 'View document source',
refuri=source),
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index d1a8fda04..78e5803a4 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -116,7 +116,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.html_head % options.language_code,
self.content_type % options.output_encoding,
self.generator,
- self.stylesheet_link % utils.relative_uri(options.destination,
+ self.stylesheet_link % utils.relative_uri(options._destination,
options.stylesheet)]
self.head = []
self.body_prefix = ['\n\n']
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index 61689fd59..af1a84dd5 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -53,7 +53,7 @@ class Writer(html4css1.Writer):
stylesheet = options.pep_stylesheet
if stylesheet is None:
stylesheet = options.stylesheet
- stylesheet = utils.relative_uri(options.destination, stylesheet)
+ stylesheet = utils.relative_uri(options._destination, stylesheet)
pyhome = options.python_home
pephome = options.pep_home
if pyhome == '..':
--
cgit v1.2.1
From e07795fb06abccd594d7553cc8d7c6daf7f199c4 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 31 Jul 2002 02:13:22 +0000
Subject: bugfix
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@428 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index be31637de..148a3b894 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -136,7 +136,7 @@ class OptionParser(optik.OptionParser):
'"--report=info".)',
['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
'dest': 'report_level'}),
- ('Don't report any system messages. (Same as "--report=none".)',
+ ('Do not report any system messages. (Same as "--report=none".)',
['--quiet', '-q'], {'action': 'store_const', 'const': 'none',
'dest': 'report_level'}),
('Set the threshold () at or above which system messages are '
--
cgit v1.2.1
From a0f7c8dbee178f8426ad60a251134cff94f2b99b Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 1 Aug 2002 00:07:43 +0000
Subject: docstring
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@431 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/io.py | 5 +++++
1 file changed, 5 insertions(+)
(limited to 'docutils')
diff --git a/docutils/io.py b/docutils/io.py
index 265e49851..00285c21d 100644
--- a/docutils/io.py
+++ b/docutils/io.py
@@ -55,6 +55,11 @@ class IO:
"""
Decode a string, `data`, heuristically.
Raise UnicodeError if unsuccessful.
+
+ The client application should call ``locale.setlocale`` at the
+ beginning of processing::
+
+ locale.setlocale(locale.LC_ALL, '')
"""
encodings = [self.options.input_encoding, 'utf-8']
try:
--
cgit v1.2.1
From 2a5a926315c1ef3dfe6c0a62329da715f0ba4a01 Mon Sep 17 00:00:00 2001
From: chodorowski
Date: Thu, 1 Aug 2002 10:01:18 +0000
Subject: Added translation for "dedication".
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@436 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/languages/sv.py | 2 ++
1 file changed, 2 insertions(+)
(limited to 'docutils')
diff --git a/docutils/languages/sv.py b/docutils/languages/sv.py
index 67d37df00..f2019c16e 100644
--- a/docutils/languages/sv.py
+++ b/docutils/languages/sv.py
@@ -26,6 +26,7 @@ labels = {
'status': u'Status',
'date': u'Datum',
'copyright': u'Copyright',
+ 'dedication': u'Dedikation',
'abstract': u'Sammanfattning',
'attention': u'Observera!',
'caution': u'Varning!',
@@ -48,6 +49,7 @@ bibliographic_fields = {
u'status': nodes.status,
u'datum': nodes.date,
u'copyright': nodes.copyright,
+ u'dedikation': nodes.topic,
u'sammanfattning': nodes.topic }
"""Field name (lowcased) to node class name mapping for bibliographic fields
(field_list)."""
--
cgit v1.2.1
From 415ea7d3b8d5217275984c80b475d4cf2da5b00d Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 2 Aug 2002 03:34:18 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@441 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index ba75a4427..d2b58ae0e 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -56,7 +56,7 @@ Subpackages:
"""
__docformat__ = 'reStructuredText'
-__version__ = '0.1+'
+__version__ = '0.2+'
class ApplicationError(StandardError): pass
--
cgit v1.2.1
From a411812a5ace3c65515654456a2cf329b4119e44 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 3 Aug 2002 15:43:50 +0000
Subject: - "name" attributes only on these tags: a, applet, form, frame,
iframe, img, map. - Add "name" attribute to in section titles for
Netscape 4 support (bug report: Pearu Peterson).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@442 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 78e5803a4..2412a1b5c 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -105,6 +105,8 @@ class HTMLTranslator(nodes.NodeVisitor):
generator = '\n'
stylesheet_link = '\n'
+ named_tags = {'a': 1, 'applet': 1, 'form': 1, 'frame': 1, 'iframe': 1,
+ 'img': 1, 'map': 1}
def __init__(self, document):
nodes.NodeVisitor.__init__(self, document)
@@ -153,6 +155,7 @@ class HTMLTranslator(nodes.NodeVisitor):
Construct and return a start tag given a node (id & class attributes
are extracted), tag name, and optional attributes.
"""
+ tagname = tagname.lower()
atts = {}
for (name, value) in attributes.items():
atts[name.lower()] = value
@@ -163,11 +166,11 @@ class HTMLTranslator(nodes.NodeVisitor):
for att in ('id',): # node attribute overrides
if node.has_key(att):
atts[att] = node[att]
- if atts.has_key('id'):
+ if atts.has_key('id') and self.named_tags.has_key(tagname):
atts['name'] = atts['id'] # for compatibility with old browsers
attlist = atts.items()
attlist.sort()
- parts = [tagname.lower()]
+ parts = [tagname]
for name, value in attlist:
if value is None: # boolean attribute
# According to the HTML spec, ```` is good,
@@ -915,12 +918,12 @@ class HTMLTranslator(nodes.NodeVisitor):
else:
self.body.append(
self.starttag(node, 'h%s' % self.section_level, ''))
- context = ''
+ atts = {'name': node.parent['id']}
if node.hasattr('refid'):
- self.body.append(''
- % node['refid'])
- context = ''
- self.context.append('%s\n' % (context, self.section_level))
+ atts['class'] = 'toc-backref'
+ atts['href'] = '#' + node['refid']
+ self.body.append(self.starttag({}, 'a', '', **atts)
+ self.context.append('\n' % (self.section_level))
def depart_title(self, node):
self.body.append(self.context.pop())
--
cgit v1.2.1
From ddcb0e28d9953527e67dd6c57ff1c2cfda4db40f Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 3 Aug 2002 15:46:05 +0000
Subject: *** empty log message ***
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@443 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 2412a1b5c..8dca22daf 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -922,7 +922,7 @@ class HTMLTranslator(nodes.NodeVisitor):
if node.hasattr('refid'):
atts['class'] = 'toc-backref'
atts['href'] = '#' + node['refid']
- self.body.append(self.starttag({}, 'a', '', **atts)
+ self.body.append(self.starttag({}, 'a', '', **atts))
self.context.append('\n' % (self.section_level))
def depart_title(self, node):
--
cgit v1.2.1
From 90b5fbc2436e55d24b306af0f63239513ca01700 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 3 Aug 2002 15:52:34 +0000
Subject: Sometimes a doesn't have an ID ("Docutils System
Messages").
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@444 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 8dca22daf..8c620d79d 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -918,7 +918,9 @@ class HTMLTranslator(nodes.NodeVisitor):
else:
self.body.append(
self.starttag(node, 'h%s' % self.section_level, ''))
- atts = {'name': node.parent['id']}
+ atts = {}
+ if node.parent.hasattr('id'):
+ atts['name'] = node.parent['id']
if node.hasattr('refid'):
atts['class'] = 'toc-backref'
atts['href'] = '#' + node['refid']
--
cgit v1.2.1
From b581b58ae8e7da7de63a48df9bd31f4b95e377a6 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 3 Aug 2002 17:57:22 +0000
Subject: - Moved the "id" attribute from TOC list items to the references
(``Contents.build_contents()``).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@445 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/parts.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index 5c778fb12..8b835f276 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -85,11 +85,11 @@ class Contents(Transform):
entrytext = self.copy_and_filter(title)
reference = nodes.reference('', '', refid=section['id'],
*entrytext)
+ ref_id = self.document.set_id(reference)
entry = nodes.paragraph('', '', reference)
item = nodes.list_item('', entry)
- itemid = self.document.set_id(item)
if self.backlinks == 'entry':
- title['refid'] = itemid
+ title['refid'] = ref_id
elif self.backlinks == 'top':
title['refid'] = self.toc_id
if level < depth:
--
cgit v1.2.1
From ae13869ee63c7ae64140e871af20b91000495388 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 3 Aug 2002 18:02:03 +0000
Subject: Fixed targets (names) on footnotes, citations, and topic titles (for
Netscape 4).
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@446 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 8c620d79d..ee804e5cc 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -549,9 +549,9 @@ class HTMLTranslator(nodes.NodeVisitor):
and node.hasattr('backrefs'):
backrefs = node['backrefs']
if len(backrefs) == 1:
- self.context.append(('', ''))
- self.context.append((''
- % backrefs[0],))
+ self.context.append('')
+ self.context.append('' % (backrefs[0], node['id']))
else:
i = 1
backlinks = []
@@ -559,11 +559,11 @@ class HTMLTranslator(nodes.NodeVisitor):
backlinks.append('%s'
% (backref, i))
i += 1
- self.context.append(('', '(%s) ' % ', '.join(backlinks)))
- self.context.append(('',))
+ self.context.append('(%s) ' % ', '.join(backlinks))
+ self.context.append('' % node['id'])
else:
- self.context.append(('', ''))
- self.context.append(('',))
+ self.context.append('')
+ self.context.append('' % node['id'])
def depart_footnote(self, node):
self.body.append('\n'
@@ -627,7 +627,7 @@ class HTMLTranslator(nodes.NodeVisitor):
CLASS='label'))
def depart_label(self, node):
- self.body.append(']%s
')
+ self.body.append(': ')
self.body.append(self.starttag(node, 'td', '', CLASS='field-body'))
if len(node) and isinstance(node[0], nodes.paragraph):
node[0].set_class('first')
@@ -510,7 +510,7 @@ class HTMLTranslator(nodes.NodeVisitor):
class_name = 'docinfo-name'
else:
class_name = 'field-name'
- self.body.append(self.starttag(node, 'td', '', CLASS=class_name))
+ self.body.append(self.starttag(node, 'th', '', CLASS=class_name))
def depart_field_name(self, node):
"""
--
cgit v1.2.1
From 6e9d13e192d14bb626255e5a06dbcfed07122564 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sun, 4 Aug 2002 21:08:35 +0000
Subject: docstring update
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@455 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/__init__.py | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/__init__.py b/docutils/parsers/rst/directives/__init__.py
index 74ff8830a..025405029 100644
--- a/docutils/parsers/rst/directives/__init__.py
+++ b/docutils/parsers/rst/directives/__init__.py
@@ -27,6 +27,12 @@ Where:
element the directive produces. Currently, only an "alt" attribute is passed
by substitution definitions (value: the substitution name), which may by
used by an embedded image directive.
+
+Directive functions return a tuple of two values:
+
+- 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), and
+- a boolean: true iff the directive block finished at a blank line.
"""
__docformat__ = 'reStructuredText'
--
cgit v1.2.1
From 88a5dd42dc5c2a6b77c637700f963e2624932529 Mon Sep 17 00:00:00 2001
From: goodger
Date: Mon, 5 Aug 2002 16:50:17 +0000
Subject: Added ``mask_email()`` function, updating to pep2html.py's
functionality.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@456 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/peps.py | 57 +++++++++++++++++++++++++++++----------------
1 file changed, 37 insertions(+), 20 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
index 618061649..ec8cc91fe 100644
--- a/docutils/transforms/peps.py
+++ b/docutils/transforms/peps.py
@@ -84,17 +84,12 @@ class Headers(Transform):
para = body[0]
if name == 'author':
for node in para:
- if isinstance(node, nodes.reference) \
- and node.has_key('refuri') \
- and node['refuri'].startswith('mailto:'):
- replacement = node.astext().replace('@', ' at ')
- node.parent.replace(node, nodes.Text(replacement))
+ if isinstance(node, nodes.reference):
+ node.parent.replace(node, mask_email(node))
elif name == 'discussions-to':
for node in para:
- if isinstance(node, nodes.reference) \
- and node.has_key('refuri') \
- and node['refuri'].startswith('mailto:'):
- node['refuri'] += '?subject=PEP%%20%s' % pep
+ if isinstance(node, nodes.reference):
+ node.parent.replace(node, mask_email(node, pep))
elif name in ('replaces', 'replaced-by'):
newbody = []
space = nodes.Text(' ')
@@ -144,28 +139,19 @@ class PEPZeroSpecial(nodes.SparseNodeVisitor):
"""
Perform the special processing needed by PEP 0:
- - For all email-address references such as "user@host", mask the address
- as "user at host" (text) to thwart simple email address harvesters
- (except for those listed in `non_masked_addresses` and addresses in the
- "Discussions-To" field).
+ - Mask email addresses.
- Link PEP numbers in the second column of 4-column tables to the PEPs
themselves.
"""
- non_masked_addresses = ('peps@python.org',
- 'python-list@python.org',
- 'python-dev@python.org')
pep_url = Headers.pep_url
def unknown_visit(self, node):
pass
def visit_reference(self, node):
- if node.hasattr('refuri') and node['refuri'].startswith('mailto:') \
- and node['refuri'][8:] not in self.non_masked_addresses:
- replacement = node.astext().replace('@', ' at ')
- node.parent.replace(node, nodes.Text(replacement))
+ node.parent.replace(node, mask_email(node))
def visit_field_list(self, node):
if node.hasattr('class') and node['class'] == 'rfc2822':
@@ -196,3 +182,34 @@ class PEPZeroSpecial(nodes.SparseNodeVisitor):
p[0] = nodes.reference(text, text, refuri=ref)
except ValueError:
pass
+
+
+non_masked_addresses = ('peps@python.org',
+ 'python-list@python.org',
+ 'python-dev@python.org')
+
+def mask_email(ref, pepno=None):
+ """
+ Mask the email address in `ref` and return a replacement node.
+
+ `ref` is returned unchanged if it contains no email address.
+
+ For email addresses such as "user@host", mask the address as "user at
+ host" (text) to thwart simple email address harvesters (except for those
+ listed in `non_masked_addresses`). If a PEP number (`pepno`) is given,
+ return a reference including a default email subject.
+ """
+ if ref.hasattr('refuri') and ref['refuri'].startswith('mailto:'):
+ if ref['refuri'][8:] in non_masked_addresses:
+ replacement = ref[0]
+ else:
+ replacement_text = ref.astext().replace('@', ' at ')
+ replacement = nodes.raw('', replacement_text, format='html')
+ if pepno is None:
+ return replacement
+ else:
+ ref['refuri'] += '?subject=PEP%%20%s' % pepno
+ ref[:] = [replacement]
+ return ref
+ else:
+ return ref
--
cgit v1.2.1
From 6d62cbfd975dd9cc39eca06f70e9a23daba93150 Mon Sep 17 00:00:00 2001
From: goodger
Date: Mon, 5 Aug 2002 16:51:03 +0000
Subject: Added "@" to "@" encoding to thwart address harvesters.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@457 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 1 +
1 file changed, 1 insertion(+)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index de25de2fc..63b51fb48 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -143,6 +143,7 @@ class HTMLTranslator(nodes.NodeVisitor):
text = text.replace("<", "<")
text = text.replace('"', """)
text = text.replace(">", ">")
+ text = text.replace("@", "@") # may thwart some address harvesters
return text
def attval(self, text,
--
cgit v1.2.1
From 1b900859f33ba50de9fcef9a07417edfe033922f Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 7 Aug 2002 01:05:41 +0000
Subject: - Added "Invisible" element category class. - Changed
``Node.walk()`` & ``.walkabout()`` to permit more tree modification
during a traversal.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@462 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 874659d99..c863c8ef5 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -66,8 +66,11 @@ class Node:
`walkabout()` method is similar, except it also calls ``depart_...``
methods before exiting each node.)
- This tree traversal doesn't handle arbitrary in-place tree
- modifications. Replacing one element with one element is OK.
+ This tree traversal supports limited in-place tree
+ modifications. Replacing one node with one or more nodes is
+ OK, as is removing an element. However, if the node removed
+ or replaced occurs after the current node, the old node will
+ still be traversed, and any new nodes will not.
Within ``visit_...`` methods (and ``depart_...`` methods for
`walkabout()`), `TreePruningException` subclasses may be raised
@@ -87,8 +90,8 @@ class Node:
pass
children = self.get_children()
try:
- for i in range(len(children)):
- children[i].walk(visitor)
+ for child in children[:]:
+ child.walk(visitor)
except SkipSiblings:
pass
@@ -115,8 +118,8 @@ class Node:
call_depart = 0
children = self.get_children()
try:
- for i in range(len(children)):
- children[i].walkabout(visitor)
+ for child in children[:]:
+ child.walkabout(visitor)
except SkipSiblings:
pass
except SkipChildren:
@@ -538,6 +541,9 @@ class Admonition(Body): pass
class Special(Body):
"""Special internal body elements."""
+class Invisible:
+ """Internal elements that don't appear in output."""
+
class Part: pass
class Inline: pass
@@ -928,9 +934,9 @@ class note(Admonition, Element): pass
class tip(Admonition, Element): pass
class hint(Admonition, Element): pass
class warning(Admonition, Element): pass
-class comment(Special, PreBibliographic, TextElement): pass
-class substitution_definition(Special, TextElement): pass
-class target(Special, Inline, TextElement, Targetable): pass
+class comment(Special, Invisible, PreBibliographic, TextElement): pass
+class substitution_definition(Special, Invisible, TextElement): pass
+class target(Special, Invisible, Inline, TextElement, Targetable): pass
class footnote(General, Element, Labeled, BackLinkable): pass
class citation(General, Element, Labeled, BackLinkable): pass
class label(Part, TextElement): pass
@@ -959,7 +965,7 @@ class system_message(Special, PreBibliographic, Element, BackLinkable):
Element.astext(self))
-class pending(Special, PreBibliographic, Element):
+class pending(Special, Invisible, PreBibliographic, Element):
"""
The "pending" element is used to encapsulate a pending operation: the
--
cgit v1.2.1
From 66dca2559e93fca4d221305e15099438b00ddc5a Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 7 Aug 2002 01:06:41 +0000
Subject: Added to project. Contains the "topic" directive.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@463 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/body.py | 47 +++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 docutils/parsers/rst/directives/body.py
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/body.py b/docutils/parsers/rst/directives/body.py
new file mode 100644
index 000000000..3cdc1d382
--- /dev/null
+++ b/docutils/parsers/rst/directives/body.py
@@ -0,0 +1,47 @@
+#! /usr/bin/env python
+
+"""
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This module has been placed in the public domain.
+
+Directives for additional body elements.
+"""
+
+__docformat__ = 'reStructuredText'
+
+from docutils import nodes
+
+
+def topic(match, type_name, data, state, state_machine, attributes):
+ lineno = state_machine.abs_line_number()
+ initial_offset = state_machine.line_offset
+ indented, indent, line_offset, blank_finish \
+ = state_machine.get_first_known_indented(match.end())
+ blocktext = '\n'.join(state_machine.input_lines[
+ initial_offset : line_offset + len(indented)])
+ if not state_machine.match_titles:
+ error = state_machine.reporter.error(
+ 'Topics may not be nested within body elements (line %s).'
+ % lineno, '', nodes.literal_block(blocktext, blocktext))
+ return [error], blank_finish
+ if not indented:
+ return [], blank_finish
+ title_text = indented.pop(0)
+ textnodes, messages = state.inline_text(title_text, lineno)
+ title = nodes.title(title_text, '', *textnodes)
+ if indented:
+ if indented[0].strip():
+ warning = state_machine.reporter.warning(
+ 'The second line of a topic block must be blank (line %s).'
+ % (lineno + 1 + line_offset - initial_offset), '')
+ messages.append(warning)
+ text = '\n'.join(indented)
+ else:
+ text = ''
+ topic_node = nodes.topic(text, title, *messages)
+ if text:
+ state.nested_parse(indented, line_offset, topic_node)
+ return [topic_node], blank_finish
--
cgit v1.2.1
From cb4fb1612a6ffa1ef09177bb72043d48139aba94 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 7 Aug 2002 01:07:18 +0000
Subject: bugfix
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@464 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/readers/pep.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/readers/pep.py b/docutils/readers/pep.py
index a4dc17cf1..c926723b8 100644
--- a/docutils/readers/pep.py
+++ b/docutils/readers/pep.py
@@ -69,7 +69,7 @@ class Inliner(rst.states.Inliner):
rfcnum = int(match.group('rfcnum'))
ref = self.rfc_url % rfcnum
else:
- raise MarkupMismatch
+ raise rst.states.MarkupMismatch
unescaped = rst.states.unescape(text, 0)
return [nodes.reference(rst.states.unescape(text, 1), unescaped,
refuri=ref)]
--
cgit v1.2.1
From 1ca64904a318386d094f5e14b78e4da1db2944ab Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 7 Aug 2002 01:08:29 +0000
Subject: Linked "Content-Type: text/x-rst" to PEP 12. Added support for
"Requires:" header.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@465 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/peps.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/peps.py b/docutils/transforms/peps.py
index ec8cc91fe..edc9ed382 100644
--- a/docutils/transforms/peps.py
+++ b/docutils/transforms/peps.py
@@ -90,10 +90,10 @@ class Headers(Transform):
for node in para:
if isinstance(node, nodes.reference):
node.parent.replace(node, mask_email(node, pep))
- elif name in ('replaces', 'replaced-by'):
+ elif name in ('replaces', 'replaced-by', 'requires'):
newbody = []
space = nodes.Text(' ')
- for refpep in body.astext().split():
+ for refpep in re.split(',?\s+', body.astext()):
pepno = int(refpep)
newbody.append(nodes.reference(
refpep, refpep, refuri=self.pep_url % pepno))
@@ -104,6 +104,10 @@ class Headers(Transform):
date = para.astext()
uri = self.pep_cvs_url % int(pep)
para[:] = [nodes.reference('', date, refuri=uri)]
+ elif name == 'content-type':
+ pep_type = para.astext()
+ uri = self.pep_url % 12
+ para[:] = [nodes.reference('', pep_type, refuri=uri)]
elif name == 'version' and len(body):
utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
--
cgit v1.2.1
From a7adc99cd85872704146a67073f508518f08cadd Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 7 Aug 2002 01:09:40 +0000
Subject: - Improved the vertical whitespace optimization; ignore "invisible"
nodes (targets, comments, etc.). - Improved inline literals with
```` around chunks of text and `` `` for runs of
spaces.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@466 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 49 +++++++++++++++++++++++++++++++------------
1 file changed, 36 insertions(+), 13 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index 63b51fb48..f1861a7f3 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -72,22 +72,22 @@ class HTMLTranslator(nodes.NodeVisitor):
contain either a single paragraph, a nested simple list, or a
paragraph followed by a nested simple list. This means that
this list can be compact:
-
+
- Item 1.
- Item 2.
-
+
But this list cannot be compact:
-
+
- Item 1.
-
+
This second paragraph forces space between list items.
-
+
- Item 2.
-
+
- In non-list contexts, omit
tags on a paragraph if that
paragraph is the only child of its parent (footnotes & citations
are allowed a label first).
-
+
- Regardless of the above, in definitions, table cells, field
bodies, option descriptions, and list items, mark the first
child with 'class="first"' if it is a paragraph. The stylesheet
@@ -107,6 +107,7 @@ class HTMLTranslator(nodes.NodeVisitor):
stylesheet_link = '\n'
named_tags = {'a': 1, 'applet': 1, 'form': 1, 'frame': 1, 'iframe': 1,
'img': 1, 'map': 1}
+ words_and_spaces = re.compile(r'\S+| +|\n')
def __init__(self, document):
nodes.NodeVisitor.__init__(self, document)
@@ -230,6 +231,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('\n')
def check_simple_list(self, node):
+ """Check for a simple list that can be rendered compactly."""
visitor = SimpleListChecker(self.document)
try:
node.walk(visitor)
@@ -646,9 +648,16 @@ class HTMLTranslator(nodes.NodeVisitor):
def visit_literal(self, node):
self.body.append(self.starttag(node, 'tt', '', CLASS='literal'))
-
- def depart_literal(self, node):
+ text = node.astext()
+ for token in self.words_and_spaces.findall(text):
+ if token in ('\n', ' '):
+ self.body.append(token)
+ elif token.strip():
+ self.body.append('%s' % token)
+ else:
+ self.body.append(' ' * (len(token) - 1) + ' ')
self.body.append('')
+ raise nodes.SkipNode
def visit_literal_block(self, node):
self.body.append(self.starttag(node, 'pre', suffix='',
@@ -991,13 +1000,27 @@ class SimpleListChecker(nodes.GenericNodeVisitor):
pass
def visit_list_item(self, node):
- if len(node) <= 1 or (len(node) == 2 and
- isinstance(node[0], nodes.paragraph) and
- (isinstance(node[1], nodes.bullet_list) or
- isinstance(node[1], nodes.enumerated_list))):
+ children = []
+ for child in node.get_children():
+ if not isinstance(child, nodes.Invisible):
+ children.append(child)
+ if (children and isinstance(children[0], nodes.paragraph)
+ and (isinstance(children[-1], nodes.bullet_list)
+ or isinstance(children[-1], nodes.enumerated_list))):
+ children.pop()
+ if len(children) <= 1:
return
else:
raise nodes.NodeFound
def visit_paragraph(self, node):
raise nodes.SkipNode
+
+ def invisible_visit(self, node):
+ """Invisible nodes should be ignored."""
+ pass
+
+ visit_comment = invisible_visit
+ visit_substitution_definition = invisible_visit
+ visit_target = invisible_visit
+ visit_pending = invisible_visit
--
cgit v1.2.1
From 1981123ec5a63f9d98ee3b8d8433e7d1cab3b021 Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 7 Aug 2002 01:25:26 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@474 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/__init__.py | 4 ++--
docutils/parsers/rst/languages/en.py | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/__init__.py b/docutils/parsers/rst/directives/__init__.py
index 025405029..ada409a79 100644
--- a/docutils/parsers/rst/directives/__init__.py
+++ b/docutils/parsers/rst/directives/__init__.py
@@ -50,13 +50,13 @@ _directive_registry = {
'tip': ('admonitions', 'tip'),
'hint': ('admonitions', 'hint'),
'warning': ('admonitions', 'warning'),
- 'questions': ('body', 'question_list'),
+ 'topic': ('body', 'topic'),
+ #'questions': ('body', 'question_list'),
'image': ('images', 'image'),
'figure': ('images', 'figure'),
'contents': ('parts', 'contents'),
#'footnotes': ('parts', 'footnotes'),
#'citations': ('parts', 'citations'),
- #'topic': ('parts', 'topic'),
'meta': ('html', 'meta'),
#'imagemap': ('html', 'imagemap'),
#'raw': ('misc', 'raw'),
diff --git a/docutils/parsers/rst/languages/en.py b/docutils/parsers/rst/languages/en.py
index 370c34d12..0ccba3952 100644
--- a/docutils/parsers/rst/languages/en.py
+++ b/docutils/parsers/rst/languages/en.py
@@ -24,9 +24,10 @@ directives = {
'note': 'note',
'tip': 'tip',
'warning': 'warning',
- 'questions': 'questions',
- 'qa': 'questions',
- 'faq': 'questions',
+ 'topic': 'topic',
+ #'questions': 'questions',
+ #'qa': 'questions',
+ #'faq': 'questions',
'meta': 'meta',
#'imagemap': 'imagemap',
'image': 'image',
@@ -35,7 +36,6 @@ directives = {
'contents': 'contents',
#'footnotes': 'footnotes',
#'citations': 'citations',
- #'topic': 'topic',
'restructuredtext-test-directive': 'restructuredtext-test-directive'}
"""English name to registered (in directives/__init__.py) directive name
mapping."""
--
cgit v1.2.1
From a83aaa90155115647d0bb2728003e61a7dc8248c Mon Sep 17 00:00:00 2001
From: goodger
Date: Wed, 7 Aug 2002 02:05:13 +0000
Subject: encode inline literals for HTML
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@475 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index f1861a7f3..c3de6df2c 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -653,7 +653,8 @@ class HTMLTranslator(nodes.NodeVisitor):
if token in ('\n', ' '):
self.body.append(token)
elif token.strip():
- self.body.append('%s' % token)
+ self.body.append('%s'
+ % self.encode(token))
else:
self.body.append(' ' * (len(token) - 1) + ' ')
self.body.append('')
--
cgit v1.2.1
From d23a7aba7c10024f062506f8c548b3f66f3e66c6 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 8 Aug 2002 00:24:11 +0000
Subject: - Check for & exit on identical source & destination paths. -
Fixed bug with absolute paths & ``--config``.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@479 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/frontend.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/frontend.py b/docutils/frontend.py
index 148a3b894..c03634634 100644
--- a/docutils/frontend.py
+++ b/docutils/frontend.py
@@ -60,7 +60,7 @@ def make_paths_absolute(dictionary, base_path=None):
for option in relative_path_options:
if dictionary.has_key(option) and dictionary[option]:
dictionary[option] = os.path.normpath(
- os.path.join(base_path, dictionary[option]))
+ os.path.abspath(os.path.join(base_path, dictionary[option])))
class OptionParser(optik.OptionParser):
@@ -237,6 +237,9 @@ class OptionParser(optik.OptionParser):
destination = args.pop(0)
if args:
self.error('Maximum 2 arguments allowed.')
+ if source and source == destination:
+ self.error('Do not specify the same file for both source and '
+ 'destination. It will clobber the source file.')
return source, destination
--
cgit v1.2.1
From 4b4b1b9a3615ba979d6c5b933e34a14d30dcf3c2 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 8 Aug 2002 00:25:37 +0000
Subject: Changed "title under/overline too short" system messages from INFO to
WARNING, and fixed its insertion location.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@480 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/states.py | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index cfb934e9d..e59102801 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -270,10 +270,10 @@ class RSTState(StateWS):
state_machine.unlink()
return state_machine.abs_line_offset(), blank_finish
- def section(self, title, source, style, lineno):
+ def section(self, title, source, style, lineno, messages):
"""Check for a valid subsection and create one if it checks out."""
if self.check_subsection(source, style, lineno):
- self.new_subsection(title, lineno)
+ self.new_subsection(title, lineno, messages)
def check_subsection(self, source, style, lineno):
"""
@@ -320,19 +320,20 @@ class RSTState(StateWS):
% lineno, '', literalblock)
return error
- def new_subsection(self, title, lineno):
+ def new_subsection(self, title, lineno, messages):
"""Append new subsection to document tree. On return, check level."""
memo = self.memo
mylevel = memo.section_level
memo.section_level += 1
sectionnode = nodes.section()
self.parent += sectionnode
- textnodes, messages = self.inline_text(title, lineno)
+ textnodes, title_messages = self.inline_text(title, lineno)
titlenode = nodes.title(title, '', *textnodes)
name = normalize_name(titlenode.astext())
sectionnode['name'] = name
sectionnode += titlenode
sectionnode += messages
+ sectionnode += title_messages
self.document.note_implicit_target(sectionnode, sectionnode)
offset = self.state_machine.line_offset + 1
absoffset = self.state_machine.abs_line_offset() + 1
@@ -2035,15 +2036,16 @@ class Text(RSTState):
title = context[0].rstrip()
underline = match.string.rstrip()
source = title + '\n' + underline
+ messages = []
if len(title) > len(underline):
blocktext = context[0] + '\n' + self.state_machine.line
- msg = self.reporter.info(
+ msg = self.reporter.warning(
'Title underline too short at line %s.' % lineno, '',
nodes.literal_block(blocktext, blocktext))
- self.parent += msg
+ messages.append(msg)
style = underline[0]
context[:] = []
- self.section(title, source, style, lineno - 1)
+ self.section(title, source, style, lineno - 1, messages)
return [], next_state, []
def text(self, match, context, next_state):
@@ -2226,14 +2228,15 @@ class Line(SpecializedText):
self.parent += msg
return [], 'Body', []
title = title.rstrip()
+ messages = []
if len(title) > len(overline):
- msg = self.reporter.info(
+ msg = self.reporter.warning(
'Title overline too short at line %s.'% lineno, '',
nodes.literal_block(source, source))
- self.parent += msg
+ messages.append(msg)
style = (overline[0], underline[0])
self.eofcheck = 0 # @@@ not sure this is correct
- self.section(title.lstrip(), source, style, lineno + 1)
+ self.section(title.lstrip(), source, style, lineno + 1, messages)
self.eofcheck = 1
return [], 'Body', []
--
cgit v1.2.1
From 0671afe0513fb59a81bcba14bf3d86fb057f5eb8 Mon Sep 17 00:00:00 2001
From: goodger
Date: Thu, 8 Aug 2002 00:26:37 +0000
Subject: - Parameterized output encoding in PEP template. - Reworked
substitutions from ``locals()`` into ``subs`` dict.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@481 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/pep_html.py | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index af1a84dd5..5c3bb0194 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -50,32 +50,38 @@ class Writer(html4css1.Writer):
html4css1.Writer.translate(self)
options = self.document.options
template = open(options.pep_template).read()
+ # Substitutions dict for template:
+ subs = {}
+ subs['encoding'] = options.output_encoding
stylesheet = options.pep_stylesheet
if stylesheet is None:
stylesheet = options.stylesheet
- stylesheet = utils.relative_uri(options._destination, stylesheet)
+ subs['stylesheet'] = utils.relative_uri(options._destination,
+ stylesheet)
pyhome = options.python_home
- pephome = options.pep_home
+ subs['pyhome'] = pyhome
+ subs['pephome'] = options.pep_home
if pyhome == '..':
- pepindex = '.'
+ subs['pepindex'] = '.'
else:
- pepindex = pyhome + '/peps/'
+ subs['pepindex'] = pyhome + '/peps/'
index = self.document.first_child_matching_class(nodes.field_list)
header = self.document[index]
- pep = header[0][1].astext()
+ pepnum = header[0][1].astext()
+ subs['pep'] = pepnum
if options.no_random:
- banner = 0
+ subs['banner'] = 0
else:
import random
- banner = random.randrange(64)
+ subs['banner'] = random.randrange(64)
try:
- pepnum = '%04i' % int(pep)
+ subs['pepnum'] = '%04i' % int(pepnum)
except:
- pepnum = pep
- title = header[1][1].astext()
- body = ''.join(self.body)
- body_suffix = ''.join(self.body_suffix)
- self.output = template % locals()
+ subs['pepnum'] = pepnum
+ subs['title'] = header[1][1].astext()
+ subs['body'] = ''.join(self.body)
+ subs['body_suffix'] = ''.join(self.body_suffix)
+ self.output = template % subs
class HTMLTranslator(html4css1.HTMLTranslator):
--
cgit v1.2.1
From f3c5decc4be60d2dd06c9dfbfef0f55788657c59 Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 9 Aug 2002 01:07:53 +0000
Subject: Bumped version to 0.2.1 to reflect changes to I/O classes.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@488 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/__init__.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
(limited to 'docutils')
diff --git a/docutils/__init__.py b/docutils/__init__.py
index d2b58ae0e..9e3df1414 100644
--- a/docutils/__init__.py
+++ b/docutils/__init__.py
@@ -56,7 +56,10 @@ Subpackages:
"""
__docformat__ = 'reStructuredText'
-__version__ = '0.2+'
+
+__version__ = '0.2.1'
+"""``major.minor.micro`` version number. The ``micro`` number is bumped any
+time there's a change in the API incompatible with one of the front ends."""
class ApplicationError(StandardError): pass
--
cgit v1.2.1
From 165ac29709e0fe634da2b3382b3224318a31e591 Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 9 Aug 2002 01:09:29 +0000
Subject: - Split ``IO`` classes into subclasses of ``Input`` and ``Output``.
- Added automatic closing to ``FileInput`` and ``FileOutput``. - Delayed
opening of ``FileOutput`` file until ``write()`` called.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@489 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/io.py | 139 ++++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 103 insertions(+), 36 deletions(-)
(limited to 'docutils')
diff --git a/docutils/io.py b/docutils/io.py
index 00285c21d..9b126c502 100644
--- a/docutils/io.py
+++ b/docutils/io.py
@@ -17,14 +17,13 @@ import sys
import locale
-class IO:
+class Input:
"""
- Base class for abstract input/output wrappers.
+ Abstract base class for input wrappers.
"""
- def __init__(self, options, source=None, source_path=None,
- destination=None, destination_path=None):
+ def __init__(self, options, source=None, source_path=None):
self.options = options
"""An option values object with "input_encoding" and "output_encoding"
attributes (typically a `docutils.optik.Values` object)."""
@@ -35,22 +34,13 @@ class IO:
self.source_path = source_path
"""A text reference to the source."""
- self.destination = destination
- """The destination for output data."""
-
- self.destination_path = destination_path
- """A text reference to the destination."""
-
def __repr__(self):
- return '%s: source=%r, destination=%r' % (self.__class__, self.source,
- self.destination)
+ return '%s: source=%r, source_path=%r' % (self.__class__, self.source,
+ self.source_path)
def read(self, reader):
raise NotImplementedError
- def write(self, data):
- raise NotImplementedError
-
def decode(self, data):
"""
Decode a string, `data`, heuristically.
@@ -88,75 +78,152 @@ class IO:
% ', '.join([repr(enc) for enc in encodings if enc]))
-class FileIO(IO):
+class Output:
"""
- I/O for single, simple file-like objects.
+ Abstract base class for output wrappers.
"""
- def __init__(self, options, source=None, source_path=None,
- destination=None, destination_path=None):
+ def __init__(self, options, destination=None, destination_path=None):
+ self.options = options
+ """An option values object with "input_encoding" and "output_encoding"
+ attributes (typically a `docutils.optik.Values` object)."""
+
+ self.destination = destination
+ """The destination for output data."""
+
+ self.destination_path = destination_path
+ """A text reference to the destination."""
+
+ def __repr__(self):
+ return ('%s: destination=%r, destination_path=%r'
+ % (self.__class__, self.destination, self.destination_path))
+
+ def write(self, data):
+ raise NotImplementedError
+
+
+class FileInput(Input):
+
+ """
+ Input for single, simple file-like objects.
+ """
+
+ def __init__(self, options, source=None, source_path=None, autoclose=1):
"""
:Parameters:
- `source`: either a file-like object (which is read directly), or
`None` (which implies `sys.stdin` if no `source_path` given).
- `source_path`: a path to a file, which is opened and then read.
- - `destination`: either a file-like object (which is written
- directly) or `None` (which implies `sys.stdout` if no
- `destination_path` given).
- - `destination_path`: a path to a file, which is opened and then
- written.
+ - `autoclose`: close automatically after read (boolean); always
+ false if `sys.stdin` is the source.
"""
- IO.__init__(self, options, source, source_path, destination,
- destination_path)
+ Input.__init__(self, options, source, source_path)
+ self.autoclose = autoclose
if source is None:
if source_path:
self.source = open(source_path)
else:
self.source = sys.stdin
- if destination is None:
- if destination_path:
- self.destination = open(destination_path, 'w')
- else:
- self.destination = sys.stdout
+ self.autoclose = None
def read(self, reader):
"""Read and decode a single file and return the data."""
data = self.source.read()
+ if self.autoclose:
+ self.close()
return self.decode(data)
+ def close(self):
+ self.source.close()
+
+
+class FileOutput(Output):
+
+ """
+ Output for single, simple file-like objects.
+ """
+
+ def __init__(self, options, destination=None, destination_path=None,
+ autoclose=1):
+ """
+ :Parameters:
+ - `destination`: either a file-like object (which is written
+ directly) or `None` (which implies `sys.stdout` if no
+ `destination_path` given).
+ - `destination_path`: a path to a file, which is opened and then
+ written.
+ - `autoclose`: close automatically after write (boolean); always
+ false if `sys.stdout` is the destination.
+ """
+ Output.__init__(self, options, destination, destination_path)
+ self.opened = 1
+ self.autoclose = autoclose
+ if destination is None:
+ if destination_path:
+ self.opened = None
+ else:
+ self.destination = sys.stdout
+ self.autoclose = None
+
+ def open(self):
+ self.destination = open(self.destination_path, 'w')
+ self.opened = 1
+
def write(self, data):
"""Encode and write `data` to a single file."""
output = data.encode(self.options.output_encoding)
+ if not self.opened:
+ self.open()
self.destination.write(output)
+ if self.autoclose:
+ self.close()
+
+ def close(self):
+ self.destination.close()
+ self.opened = None
-class StringIO(IO):
+class StringInput(Input):
"""
- Direct string I/O.
+ Direct string input.
"""
def read(self, reader):
"""Decode and return the source string."""
return self.decode(self.source)
+
+class StringOutput(Output):
+
+ """
+ Direct string output.
+ """
+
def write(self, data):
"""Encode and return `data`."""
self.destination = data.encode(self.options.output_encoding)
return self.destination
-class NullIO(IO):
+class NullInput(Input):
"""
- Degenerate I/O: read & write nothing.
+ Degenerate input: read nothing.
"""
def read(self, reader):
"""Return a null string."""
return u''
+
+class NullOutput(Output):
+
+ """
+ Degenerate output: write nothing.
+ """
+
def write(self, data):
- """Do nothing (send data to the bit bucket)."""
+ """Do nothing ([don't even] send data to the bit bucket)."""
pass
--
cgit v1.2.1
From a11abc12fc0b7d1d3b4c0b68dcd28201ade4d22e Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 9 Aug 2002 01:11:34 +0000
Subject: inline literals: comments & reordered cases
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@490 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index c3de6df2c..f8a58d736 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -650,12 +650,15 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append(self.starttag(node, 'tt', '', CLASS='literal'))
text = node.astext()
for token in self.words_and_spaces.findall(text):
- if token in ('\n', ' '):
- self.body.append(token)
- elif token.strip():
+ if token.strip():
+ # Protect text like "--an-option" from bad line wrapping:
self.body.append('%s'
% self.encode(token))
+ elif token in ('\n', ' '):
+ # Allow breaks at whitespace:
+ self.body.append(token)
else:
+ # Protect runs of multiple spaces; the last space can wrap:
self.body.append(' ' * (len(token) - 1) + ' ')
self.body.append('')
raise nodes.SkipNode
--
cgit v1.2.1
From d5f026e798598f57d02ab02ffa4b20efb818473f Mon Sep 17 00:00:00 2001
From: goodger
Date: Fri, 9 Aug 2002 01:19:11 +0000
Subject: updated
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@492 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/core.py | 8 ++++----
docutils/writers/pep_html.py | 1 -
2 files changed, 4 insertions(+), 5 deletions(-)
(limited to 'docutils')
diff --git a/docutils/core.py b/docutils/core.py
index 9e836c6be..6dcc93d8a 100644
--- a/docutils/core.py
+++ b/docutils/core.py
@@ -29,8 +29,8 @@ class Publisher:
"""
def __init__(self, reader=None, parser=None, writer=None,
- source=None, source_class=io.FileIO,
- destination=None, destination_class=io.FileIO,
+ source=None, source_class=io.FileInput,
+ destination=None, destination_class=io.FileOutput,
options=None):
"""
Initial setup. If any of `reader`, `parser`, or `writer` are not
@@ -48,13 +48,13 @@ class Publisher:
"""A `writers.Writer` instance."""
self.source = source
- """The source of input data, an `io.IO` instance."""
+ """The source of input data, an `io.Input` instance."""
self.source_class = source_class
"""The class for dynamically created source objects."""
self.destination = destination
- """The destination for docutils output, an `io.IO` instance."""
+ """The destination for docutils output, an `io.Output` instance."""
self.destination_class = destination_class
"""The class for dynamically created destination objects."""
diff --git a/docutils/writers/pep_html.py b/docutils/writers/pep_html.py
index 5c3bb0194..b591f9230 100644
--- a/docutils/writers/pep_html.py
+++ b/docutils/writers/pep_html.py
@@ -14,7 +14,6 @@ __docformat__ = 'reStructuredText'
import sys
-#import random
from docutils import nodes, optik, utils
from docutils.writers import html4css1
--
cgit v1.2.1
From 403cb20d5dc1c872855031ed1ea90dc2fa948281 Mon Sep 17 00:00:00 2001
From: goodger
Date: Sat, 10 Aug 2002 02:31:33 +0000
Subject: docstrings
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@493 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 42 ++++++++++++++++++++++++++++++++++++++----
docutils/parsers/rst/states.py | 2 +-
2 files changed, 39 insertions(+), 5 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index c863c8ef5..0924658a7 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -10,11 +10,15 @@
Docutils document tree element class library.
Classes in CamelCase are abstract base classes or auxiliary classes. The one
-exception is `Text`, for a text node; uppercase is used to differentiate from
-element classes.
+exception is `Text`, for a text (PCDATA) node; uppercase is used to
+differentiate from element classes. Classes in lower_case_with_underscores
+are element classes, matching the XML element generic identifiers in the DTD_.
-Classes in lower_case_with_underscores are element classes, matching the XML
-element generic identifiers in the DTD_.
+The position of each node (the level at which it can occur) is significant and
+is represented by abstract base classes (`Root`, `Structural`, `Body`,
+`Inline`, etc.). Certain transformations will be easier because we can use
+``isinstance(node, base_class)`` to determine the position of the node in the
+hierarchy.
.. _DTD: http://docutils.sourceforge.net/spec/docutils.dtd
"""
@@ -676,6 +680,36 @@ class document(Root, Structural, Element):
return id
def set_name_id_map(self, node, id, msgnode=None, explicit=None):
+ """
+ `self.nameids` maps names to IDs, while `self.nametypes` maps names to
+ booleans representing hyperlink type (True==explicit,
+ False==implicit). This method updates the mappings.
+
+ The following state transition table shows how `self.nameids` ("ids")
+ and `self.nametypes` ("types") change with new input (a call to this
+ method), and what actions are performed:
+
+ ==== ===== ======== ======== ======= ==== ===== =====
+ Old State Input Action New State Notes
+ ----------- -------- ----------------- ----------- -----
+ ids types new type sys.msg. dupname ids types
+ ==== ===== ======== ======== ======= ==== ===== =====
+ -- -- explicit -- -- new True
+ -- -- implicit -- -- new False
+ None False explicit -- -- new True
+ old False explicit implicit old new True
+ None True explicit explicit new None True
+ old True explicit explicit new,old None True [#]_
+ None False implicit implicit new None False
+ old False implicit implicit new,old None False
+ None True implicit implicit new None True
+ old True implicit implicit new old True
+ ==== ===== ======== ======== ======= ==== ===== =====
+
+ .. [#] Do not clear the name-to-id map or invalidate the old target if
+ both old and new targets are external and refer to identical URIs.
+ The new target is invalidated regardless.
+ """
if node.has_key('name'):
name = node['name']
if self.nameids.has_key(name):
diff --git a/docutils/parsers/rst/states.py b/docutils/parsers/rst/states.py
index e59102801..fec37d1c9 100644
--- a/docutils/parsers/rst/states.py
+++ b/docutils/parsers/rst/states.py
@@ -27,7 +27,7 @@ the reStructuredText parser. It defines the following:
- `SpecializedText`: Superclass for continuation lines of Text-variants.
- `Definition`: Second line of potential definition_list_item.
- `Line`: Second line of overlined section title or transition marker.
- - `Stuff`: An auxilliary collection class.
+ - `Stuff`: An auxiliary collection class.
:Exception classes:
- `MarkupError`
--
cgit v1.2.1
From 940de581fe90267e7d5b9b1acbfa878db8e7961c Mon Sep 17 00:00:00 2001
From: yole
Date: Sun, 11 Aug 2002 19:41:37 +0000
Subject: Second version of the .. sectnum:: directive implementation. Also,
the really working fix of the empty path problem in package_unittest.py.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@500 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/__init__.py | 1 +
docutils/parsers/rst/directives/parts.py | 35 ++++++++++++++-
docutils/transforms/parts.py | 66 +++++++++++++++++++++++++----
3 files changed, 93 insertions(+), 9 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/__init__.py b/docutils/parsers/rst/directives/__init__.py
index ada409a79..0a9721c9f 100644
--- a/docutils/parsers/rst/directives/__init__.py
+++ b/docutils/parsers/rst/directives/__init__.py
@@ -55,6 +55,7 @@ _directive_registry = {
'image': ('images', 'image'),
'figure': ('images', 'figure'),
'contents': ('parts', 'contents'),
+ 'sectnum': ('parts', 'sectnum'),
#'footnotes': ('parts', 'footnotes'),
#'citations': ('parts', 'citations'),
'meta': ('html', 'meta'),
diff --git a/docutils/parsers/rst/directives/parts.py b/docutils/parsers/rst/directives/parts.py
index d3bba86c5..aefea341d 100644
--- a/docutils/parsers/rst/directives/parts.py
+++ b/docutils/parsers/rst/directives/parts.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python
"""
-:Author: David Goodger
+:Author: David Goodger, Dmitry Jemerov
:Contact: goodger@users.sourceforge.net
:Revision: $Revision$
:Date: $Date$
@@ -75,3 +75,36 @@ def contents(match, type_name, data, state, state_machine, attributes):
return [error] + messages, blank_finish
state_machine.document.note_pending(pending)
return [pending] + messages, blank_finish
+
+sectnum_attribute_spec = {'depth': int}
+
+def sectnum(match, type_name, data, state, state_machine, attributes):
+ """
+ Parse the `.. sectnum::` directive.
+
+ The following attributes are supported:
+
+ - :depth:
+
+ The attributes can be specified in the lines following the directive,
+ or it is possible to specify one attribute in the same line as the
+ directive itself.
+ """
+ lineno = state_machine.abs_line_number()
+ line_offset = state_machine.line_offset
+ datablock, indent, offset, blank_finish = \
+ state_machine.get_first_known_indented(match.end(), until_blank=1)
+
+ pending = nodes.pending(parts.SectNum, 'last reader', {})
+ success, data, blank_finish = state.parse_extension_attributes(
+ sectnum_attribute_spec, datablock, blank_finish)
+ if success: # data is a dict of attributes
+ pending.details.update(data)
+ else: # data is an error string
+ error = state_machine.reporter.error(
+ 'Error in "%s" directive attributes at line %s:\n%s.'
+ % (match.group(1), lineno, data), '')
+ return [error], blank_finish
+
+ state_machine.document.note_pending(pending)
+ return [pending], blank_finish
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index 8b835f276..48b7588e3 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -1,6 +1,6 @@
#! /usr/bin/env python
"""
-:Authors: David Goodger, Ueli Schlaepfer
+:Authors: David Goodger, Ueli Schlaepfer, Dmitry Jemerov
:Contact: goodger@users.sourceforge.net
:Revision: $Revision$
:Date: $Date$
@@ -9,6 +9,7 @@
Transforms related to document parts.
- `Contents`: Used to build a table of contents.
+- `SectNum`: Used to automatically number the section titles.
"""
__docformat__ = 'reStructuredText'
@@ -19,6 +20,38 @@ import sys
from docutils import nodes, utils
from docutils.transforms import TransformError, Transform
+class SectNum(Transform):
+
+ """
+ This transform automatically assigns numbers to the titles of
+ document sections. It is possible to limit the maximum section
+ level for which the numbers are added. For those sections that
+ are auto-numbered, the "autonum" attribute is set, informing the
+ contents table generator that a different form of the TOC should
+ be used.
+ """
+
+ def transform(self):
+ self.maxdepth = self.startnode.details.get('depth', sys.maxint)
+ self.startnode.parent.remove(self.startnode)
+ self.update_section_numbers(self.document, "", 1)
+
+ def update_section_numbers(self, node, prefix, depth):
+ cur_index = 1
+ for child in node:
+ if isinstance(child, nodes.section):
+ number_str = "%s%d." % (prefix, cur_index)
+ title = child[0]
+ child['autonum_origtitle'] = copy_and_filter(self.document,
+ title)
+ child['autonum_prefix'] = prefix
+ if isinstance(title[0], nodes.Text):
+ title[0].data = number_str + " " + title[0].data
+ else:
+ title.insert(0, nodes.Text(number_str + " "))
+ if depth < self.maxdepth:
+ self.update_section_numbers(child, number_str, depth+1)
+ cur_index += 1
class Contents(Transform):
@@ -79,10 +112,20 @@ class Contents(Transform):
i -= 1
sections.reverse()
entries = []
+ autonum = 0
depth = self.startnode.details.get('depth', sys.maxint)
for section in sections:
title = section[0]
- entrytext = self.copy_and_filter(title)
+
+ # If the title has been modified by the sectnum transform,
+ # take the title before modification saved in the
+ # `autonum_origtitle` attribute.
+ entrytext = section.get('autonum_origtitle', '')
+ if entrytext:
+ autonum = 1
+ autonum_prefix = section.get('autonum_prefix')
+ else:
+ entrytext = copy_and_filter(self.document, title)
reference = nodes.reference('', '', refid=section['id'],
*entrytext)
ref_id = self.document.set_id(reference)
@@ -97,14 +140,21 @@ class Contents(Transform):
item += subsects
entries.append(item)
if entries:
- entries = nodes.bullet_list('', *entries)
+ if autonum:
+ entries = nodes.enumerated_list('',
+ enumtype='arabic',
+ prefix=autonum_prefix,
+ suffix='.',
+ *entries)
+ else:
+ entries = nodes.bullet_list('', *entries)
return entries
- def copy_and_filter(self, node):
- """Return a copy of a title, with references, images, etc. removed."""
- visitor = ContentsFilter(self.document)
- node.walkabout(visitor)
- return visitor.get_entry_text()
+def copy_and_filter(document, node):
+ """Return a copy of a title, with references, images, etc. removed."""
+ visitor = ContentsFilter(document)
+ node.walkabout(visitor)
+ return visitor.get_entry_text()
class ContentsFilter(nodes.TreeCopyVisitor):
--
cgit v1.2.1
From ed133b3ce34d61dabf89a02ad8b3f37745692f3f Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 13 Aug 2002 00:51:34 +0000
Subject: Added "generated" element. Improved "pending" docstrings.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@503 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/nodes.py | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
(limited to 'docutils')
diff --git a/docutils/nodes.py b/docutils/nodes.py
index 0924658a7..c03cc63d7 100644
--- a/docutils/nodes.py
+++ b/docutils/nodes.py
@@ -1003,10 +1003,10 @@ class pending(Special, Invisible, PreBibliographic, Element):
"""
The "pending" element is used to encapsulate a pending operation: the
- operation, the point at which to apply it, and any data it requires. Only
- the pending operation's location within the document is stored in the
- public document tree; the operation itself and its data are stored in
- internal instance attributes.
+ operation (transform), the point at which to apply it, and any data it
+ requires. Only the pending operation's location within the document is
+ stored in the public document tree; the operation itself and its data are
+ stored in internal instance attributes.
For example, say you want a table of contents in your reStructuredText
document. The easiest way to specify where to put it is from within the
@@ -1021,8 +1021,15 @@ class pending(Special, Invisible, PreBibliographic, Element):
+ internal attributes
- The "pending" node is also appended to `document.pending`, so that a later
- stage of processing can easily run all pending transforms.
+ Use `document.note_pending()` to append the "pending" node to
+ `document.pending`, so that a later stage of processing can easily run all
+ pending transforms. The processign stage must also be specified (one of
+ "first reader", "last reader", "first writer", or "last writer").
+
+ Pending transforms will be triggered by the transform subclasses of
+ ``docutils.transforms.universal.Pending``. These transforms are called by
+ ``docutils.readers.Reader.transform()`` and
+ ``docutils.readers.Writer.transform()``.
"""
def __init__(self, transform, stage, details,
@@ -1100,6 +1107,7 @@ class image(General, Inline, TextElement):
class problematic(Inline, TextElement): pass
+class generated(Inline, TextElement): pass
# ========================================
@@ -1117,6 +1125,7 @@ node_class_names = """
emphasis entry enumerated_list error
field field_argument field_body field_list field_name figure footer
footnote footnote_reference
+ generated
header hint
image important interpreted
label legend list_item literal literal_block
--
cgit v1.2.1
From 7a7a49ec21fec9c14621992cbfcee53337a424f4 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 13 Aug 2002 00:53:05 +0000
Subject: Changed the "Contents" transform's order. Docstrings.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@504 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/directives/parts.py | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/directives/parts.py b/docutils/parsers/rst/directives/parts.py
index aefea341d..eeff6fc29 100644
--- a/docutils/parsers/rst/directives/parts.py
+++ b/docutils/parsers/rst/directives/parts.py
@@ -39,6 +39,7 @@ contents_attribute_spec = {'depth': int,
'qa': unchanged}
def contents(match, type_name, data, state, state_machine, attributes):
+ """Table of contents."""
lineno = state_machine.abs_line_number()
line_offset = state_machine.line_offset
datablock, indent, offset, blank_finish = \
@@ -60,7 +61,7 @@ def contents(match, type_name, data, state, state_machine, attributes):
else:
messages = []
title = None
- pending = nodes.pending(parts.Contents, 'last reader', {'title': title},
+ pending = nodes.pending(parts.Contents, 'first writer', {'title': title},
blocktext)
if attlines:
success, data, blank_finish = state.parse_extension_attributes(
@@ -79,22 +80,11 @@ def contents(match, type_name, data, state, state_machine, attributes):
sectnum_attribute_spec = {'depth': int}
def sectnum(match, type_name, data, state, state_machine, attributes):
- """
- Parse the `.. sectnum::` directive.
-
- The following attributes are supported:
-
- - :depth:
-
- The attributes can be specified in the lines following the directive,
- or it is possible to specify one attribute in the same line as the
- directive itself.
- """
+ """Automatic section numbering."""
lineno = state_machine.abs_line_number()
line_offset = state_machine.line_offset
datablock, indent, offset, blank_finish = \
state_machine.get_first_known_indented(match.end(), until_blank=1)
-
pending = nodes.pending(parts.SectNum, 'last reader', {})
success, data, blank_finish = state.parse_extension_attributes(
sectnum_attribute_spec, datablock, blank_finish)
@@ -105,6 +95,5 @@ def sectnum(match, type_name, data, state, state_machine, attributes):
'Error in "%s" directive attributes at line %s:\n%s.'
% (match.group(1), lineno, data), '')
return [error], blank_finish
-
state_machine.document.note_pending(pending)
return [pending], blank_finish
--
cgit v1.2.1
From 3cfa7ce4f723086105232c55166fec4b7bc935bc Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 13 Aug 2002 00:53:40 +0000
Subject: Added "sectnum" directive.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@505 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/parsers/rst/languages/en.py | 2 ++
1 file changed, 2 insertions(+)
(limited to 'docutils')
diff --git a/docutils/parsers/rst/languages/en.py b/docutils/parsers/rst/languages/en.py
index 0ccba3952..3e95e1972 100644
--- a/docutils/parsers/rst/languages/en.py
+++ b/docutils/parsers/rst/languages/en.py
@@ -34,6 +34,8 @@ directives = {
'figure': 'figure',
#'raw': 'raw',
'contents': 'contents',
+ 'sectnum': 'sectnum',
+ 'section-numbering': 'sectnum',
#'footnotes': 'footnotes',
#'citations': 'citations',
'restructuredtext-test-directive': 'restructuredtext-test-directive'}
--
cgit v1.2.1
From 077121b3b8eada56010fc661595ab47f7c350638 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 13 Aug 2002 00:56:09 +0000
Subject: * Reworked the ``docutils.transforms.parts.SectNum`` transform's
``update_section_numbers()`` method:
- Simplified calling the method (default parameter values).
- Removed the "autonum_origtitle" and "autonum_prefix" attributes
from "section" elements: unnecessarily redundant. Instead, the
"title" elements get an "auto" attribute.
- The section number text is inserted into the title, wrapped in a
```` element. We don't actually use
this yet, but it could be used this to remove the generated text
if we need to.
* Reworked the ``docutils.transforms.parts.Contents`` transform's
``build_contents()`` method:
- It turns out that we don't need to build enumerated lists; we
continue to build bullet lists as before.
- If an "auto" attribute is detected in a title, we add a
``class="auto-toc"`` attribute to the bullet list.
- The generated text is left alone; there's no need to remove it.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@506 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/transforms/parts.py | 70 +++++++++++++++++++-------------------------
1 file changed, 30 insertions(+), 40 deletions(-)
(limited to 'docutils')
diff --git a/docutils/transforms/parts.py b/docutils/transforms/parts.py
index 48b7588e3..78a99b121 100644
--- a/docutils/transforms/parts.py
+++ b/docutils/transforms/parts.py
@@ -20,12 +20,13 @@ import sys
from docutils import nodes, utils
from docutils.transforms import TransformError, Transform
+
class SectNum(Transform):
"""
This transform automatically assigns numbers to the titles of
- document sections. It is possible to limit the maximum section
- level for which the numbers are added. For those sections that
+ document sections. It is possible to limit the maximum section
+ level for which the numbers are added. For those sections that
are auto-numbered, the "autonum" attribute is set, informing the
contents table generator that a different form of the TOC should
be used.
@@ -34,24 +35,24 @@ class SectNum(Transform):
def transform(self):
self.maxdepth = self.startnode.details.get('depth', sys.maxint)
self.startnode.parent.remove(self.startnode)
- self.update_section_numbers(self.document, "", 1)
+ self.update_section_numbers(self.document)
- def update_section_numbers(self, node, prefix, depth):
- cur_index = 1
+ def update_section_numbers(self, node, prefix=(), depth=0):
+ depth += 1
+ sectnum = 1
for child in node:
if isinstance(child, nodes.section):
- number_str = "%s%d." % (prefix, cur_index)
+ numbers = prefix + (str(sectnum),)
title = child[0]
- child['autonum_origtitle'] = copy_and_filter(self.document,
- title)
- child['autonum_prefix'] = prefix
- if isinstance(title[0], nodes.Text):
- title[0].data = number_str + " " + title[0].data
- else:
- title.insert(0, nodes.Text(number_str + " "))
+ # Use for spacing:
+ generated = nodes.generated(
+ '', '.'.join(numbers) + u'\u00a0' * 3, CLASS='sectnum')
+ title.insert(0, generated)
+ title['auto'] = 1
if depth < self.maxdepth:
- self.update_section_numbers(child, number_str, depth+1)
- cur_index += 1
+ self.update_section_numbers(child, numbers, depth)
+ sectnum += 1
+
class Contents(Transform):
@@ -116,16 +117,8 @@ class Contents(Transform):
depth = self.startnode.details.get('depth', sys.maxint)
for section in sections:
title = section[0]
-
- # If the title has been modified by the sectnum transform,
- # take the title before modification saved in the
- # `autonum_origtitle` attribute.
- entrytext = section.get('autonum_origtitle', '')
- if entrytext:
- autonum = 1
- autonum_prefix = section.get('autonum_prefix')
- else:
- entrytext = copy_and_filter(self.document, title)
+ auto = title.get('auto') # May be set by SectNum.
+ entrytext = self.copy_and_filter(title)
reference = nodes.reference('', '', refid=section['id'],
*entrytext)
ref_id = self.document.set_id(reference)
@@ -140,21 +133,18 @@ class Contents(Transform):
item += subsects
entries.append(item)
if entries:
- if autonum:
- entries = nodes.enumerated_list('',
- enumtype='arabic',
- prefix=autonum_prefix,
- suffix='.',
- *entries)
- else:
- entries = nodes.bullet_list('', *entries)
- return entries
-
-def copy_and_filter(document, node):
- """Return a copy of a title, with references, images, etc. removed."""
- visitor = ContentsFilter(document)
- node.walkabout(visitor)
- return visitor.get_entry_text()
+ contents = nodes.bullet_list('', *entries)
+ if auto:
+ contents.set_class('auto-toc')
+ return contents
+ else:
+ return []
+
+ def copy_and_filter(self, node):
+ """Return a copy of a title, with references, images, etc. removed."""
+ visitor = ContentsFilter(self.document)
+ node.walkabout(visitor)
+ return visitor.get_entry_text()
class ContentsFilter(nodes.TreeCopyVisitor):
--
cgit v1.2.1
From b0d73b9dfd712717d3f56e71b8e99f2ee081cbb7 Mon Sep 17 00:00:00 2001
From: goodger
Date: Tue, 13 Aug 2002 00:57:37 +0000
Subject: Improved modularity of output; added ``self.body_pre_docinfo`` and
``self.docinfo`` segments.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@507 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
---
docutils/writers/html4css1.py | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
(limited to 'docutils')
diff --git a/docutils/writers/html4css1.py b/docutils/writers/html4css1.py
index f8a58d736..cd7402fcd 100644
--- a/docutils/writers/html4css1.py
+++ b/docutils/writers/html4css1.py
@@ -50,6 +50,8 @@ class Writer(writers.Writer):
self.head_prefix = visitor.head_prefix
self.head = visitor.head
self.body_prefix = visitor.body_prefix
+ self.body_pre_docinfo = visitor.body_pre_docinfo
+ self.docinfo = visitor.docinfo
self.body = visitor.body
self.body_suffix = visitor.body_suffix
@@ -123,6 +125,8 @@ class HTMLTranslator(nodes.NodeVisitor):
options.stylesheet)]
self.head = []
self.body_prefix = ['\n\n']
+ self.body_pre_docinfo = []
+ self.docinfo = []
self.body = []
self.body_suffix = ['\n\n']
self.section_level = 0
@@ -134,8 +138,9 @@ class HTMLTranslator(nodes.NodeVisitor):
self.in_docinfo = None
def astext(self):
- return ''.join(self.head_prefix + self.head
- + self.body_prefix + self.body + self.body_suffix)
+ return ''.join(self.head_prefix + self.head + self.body_prefix
+ + self.body_pre_docinfo + self.docinfo + self.body
+ + self.body_suffix)
def encode(self, text):
"""Encode special characters in `text` & return."""
@@ -382,6 +387,7 @@ class HTMLTranslator(nodes.NodeVisitor):
self.body.append('