[Zope-Checkins] CVS: Zope/lib/python/docutils -
__init__.py:1.2.10.10 core.py:1.2.10.8 examples.py:1.1.4.4
frontend.py:1.2.10.9 io.py:1.2.10.8 nodes.py:1.2.10.8
statemachine.py:1.2.10.8 utils.py:1.2.10.8
Andreas Jung
andreas at andreas-jung.com
Sun Oct 9 10:44:14 EDT 2005
Update of /cvs-repository/Zope/lib/python/docutils
In directory cvs.zope.org:/tmp/cvs-serv26422
Modified Files:
Tag: Zope-2_7-branch
__init__.py core.py examples.py frontend.py io.py nodes.py
statemachine.py utils.py
Log Message:
upgrade to docutils 0.3.9
=== Zope/lib/python/docutils/__init__.py 1.2.10.9 => 1.2.10.10 ===
--- Zope/lib/python/docutils/__init__.py:1.2.10.9 Fri Jan 7 08:26:01 2005
+++ Zope/lib/python/docutils/__init__.py Sun Oct 9 10:43:43 2005
@@ -51,7 +51,7 @@
__docformat__ = 'reStructuredText'
-__version__ = '0.3.7'
+__version__ = '0.3.9'
"""``major.minor.micro`` version number. The micro number is bumped for API
changes, for new functionality, and for interim project releases. The minor
number is bumped whenever there is a significant project release. The major
=== Zope/lib/python/docutils/core.py 1.2.10.7 => 1.2.10.8 ===
--- Zope/lib/python/docutils/core.py:1.2.10.7 Fri Jan 7 08:26:01 2005
+++ Zope/lib/python/docutils/core.py Sun Oct 9 10:43:43 2005
@@ -197,6 +197,7 @@
self.writer.assemble_parts()
except Exception, error:
if self.settings.traceback: # propagate exceptions?
+ self.debugging_dumps(document)
raise
self.report_Exception(error)
exit = 1
@@ -210,6 +211,8 @@
return output
def debugging_dumps(self, document):
+ if not document:
+ return
if self.settings.dump_settings:
print >>sys.stderr, '\n::: Runtime settings:'
print >>sys.stderr, pprint.pformat(self.settings.__dict__)
=== Zope/lib/python/docutils/examples.py 1.1.4.3 => 1.1.4.4 ===
--- Zope/lib/python/docutils/examples.py:1.1.4.3 Fri Jan 7 08:26:02 2005
+++ Zope/lib/python/docutils/examples.py Sun Oct 9 10:43:43 2005
@@ -7,12 +7,13 @@
"""
This module contains practical examples of Docutils client code.
-Importing this module is not recommended; its contents are subject to change
-in future Docutils releases. Instead, it is recommended that you copy and
-paste the parts you need into your own code, modifying as necessary.
+Importing this module from client code is not recommended; its contents are
+subject to change in future Docutils releases. Instead, it is recommended
+that you copy and paste the parts you need into your own code, modifying as
+necessary.
"""
-from docutils import core
+from docutils import core, io
def html_parts(input_string, source_path=None, destination_path=None,
@@ -72,3 +73,23 @@
if output_encoding != 'unicode':
fragment = fragment.encode(output_encoding)
return fragment
+
+def internals(input_string, source_path=None, destination_path=None,
+ input_encoding='unicode'):
+ """
+ Return the document tree and publisher, for exploring Docutils internals.
+
+ Parameters: see `html_parts()`.
+ """
+ overrides = {'input_encoding': input_encoding}
+ output, pub = core.publish_programmatically(
+ source_class=io.StringInput, source=input_string,
+ source_path=source_path,
+ destination_class=io.NullOutput, destination=None,
+ destination_path=destination_path,
+ reader=None, reader_name='standalone',
+ parser=None, parser_name='restructuredtext',
+ writer=None, writer_name='null',
+ settings=None, settings_spec=None, settings_overrides=overrides,
+ config_section=None, enable_exit_status=None)
+ return pub.writer.document, pub
=== Zope/lib/python/docutils/frontend.py 1.2.10.8 => 1.2.10.9 ===
--- Zope/lib/python/docutils/frontend.py:1.2.10.8 Fri Jan 7 08:26:02 2005
+++ Zope/lib/python/docutils/frontend.py Sun Oct 9 10:43:43 2005
@@ -124,6 +124,13 @@
None, sys.exc_info()[2])
return value
+def validate_nonnegative_int(setting, value, option_parser,
+ config_parser=None, config_section=None):
+ value = int(value)
+ if value < 0:
+ raise ValueError('negative value; must be positive or zero')
+ return value
+
def validate_threshold(setting, value, option_parser,
config_parser=None, config_section=None):
try:
@@ -333,10 +340,10 @@
'validator': validate_threshold}),
('Report all system messages, info-level and higher. (Same as '
'"--report=info".)',
- ['--verbose', '-v'], {'action': 'store_const', 'const': 'info',
+ ['--verbose', '-v'], {'action': 'store_const', 'const': 1,
'dest': 'report_level'}),
('Do not report any system messages. (Same as "--report=none".)',
- ['--quiet', '-q'], {'action': 'store_const', 'const': 'none',
+ ['--quiet', '-q'], {'action': 'store_const', 'const': 5,
'dest': 'report_level'}),
('Set the threshold (<level>) at or above which system messages are '
'converted to exceptions, halting execution immediately by '
@@ -429,6 +436,9 @@
['--version', '-V'], {'action': 'version'}),
('Show this help message and exit.',
['--help', '-h'], {'action': 'help'}),
+ # Typically not useful for non-programmatical use.
+ (SUPPRESS_HELP, ['--id-prefix'], {'default': ''}),
+ (SUPPRESS_HELP, ['--auto-id-prefix'], {'default': 'id'}),
# Hidden options, for development use only:
(SUPPRESS_HELP, ['--dump-settings'], {'action': 'store_true'}),
(SUPPRESS_HELP, ['--dump-internals'], {'action': 'store_true'}),
=== Zope/lib/python/docutils/io.py 1.2.10.7 => 1.2.10.8 ===
--- Zope/lib/python/docutils/io.py:1.2.10.7 Fri Jan 7 08:26:02 2005
+++ Zope/lib/python/docutils/io.py Sun Oct 9 10:43:43 2005
@@ -70,32 +70,42 @@
if (self.encoding and self.encoding.lower() == 'unicode'
or isinstance(data, UnicodeType)):
return data
- encodings = [self.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
- encodings.append('latin-1')
+ encodings = [self.encoding]
+ if not self.encoding:
+ # Apply heuristics only if no encoding is explicitly given.
+ encodings.append('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
+ encodings.append('latin-1')
+ error = None
+ error_details = ''
for enc in encodings:
if not enc:
continue
try:
decoded = unicode(data, enc, self.error_handler)
self.successful_encoding = enc
- return decoded
- except (UnicodeError, LookupError):
+ # Return decoded, removing BOMs.
+ return decoded.replace(u'\ufeff', u'')
+ except (UnicodeError, LookupError), error:
pass
+ if error is not None:
+ error_details = '\n(%s: %s)' % (error.__class__.__name__, error)
raise UnicodeError(
- 'Unable to decode input data. Tried the following encodings: %s.'
- % ', '.join([repr(enc) for enc in encodings if enc]))
+ 'Unable to decode input data. Tried the following encodings: '
+ '%s.%s'
+ % (', '.join([repr(enc) for enc in encodings if enc]),
+ error_details))
class Output(TransformSpec):
=== Zope/lib/python/docutils/nodes.py 1.2.10.7 => 1.2.10.8 ===
--- Zope/lib/python/docutils/nodes.py:1.2.10.7 Fri Jan 7 08:26:02 2005
+++ Zope/lib/python/docutils/nodes.py Sun Oct 9 10:43:43 2005
@@ -26,6 +26,8 @@
import sys
import os
import re
+import copy
+import warnings
import xml.dom.minidom
from types import IntType, SliceType, StringType, UnicodeType, \
TupleType, ListType
@@ -103,7 +105,7 @@
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
+ Within ``visit`` methods (and ``depart`` methods for
`walkabout()`), `TreePruningException` subclasses may be raised
(`SkipChildren`, `SkipSiblings`, `SkipNode`, `SkipDeparture`).
@@ -111,15 +113,15 @@
``visit`` implementation for each `Node` subclass encountered.
"""
visitor.document.reporter.debug(
- 'calling dispatch_visit for %s' % self.__class__.__name__,
- category='nodes.Node.walk')
+ 'docutils.nodes.Node.walk calling dispatch_visit for %s'
+ % self.__class__.__name__)
try:
visitor.dispatch_visit(self)
except (SkipChildren, SkipNode):
return
except SkipDeparture: # not applicable; ignore
pass
- children = self.get_children()
+ children = self.children
try:
for child in children[:]:
child.walk(visitor)
@@ -138,8 +140,8 @@
"""
call_depart = 1
visitor.document.reporter.debug(
- 'calling dispatch_visit for %s' % self.__class__.__name__,
- category='nodes.Node.walkabout')
+ 'docutils.nodes.Node.walkabout calling dispatch_visit for %s'
+ % self.__class__.__name__)
try:
try:
visitor.dispatch_visit(self)
@@ -147,7 +149,7 @@
return
except SkipDeparture:
call_depart = 0
- children = self.get_children()
+ children = self.children
try:
for child in children[:]:
child.walkabout(visitor)
@@ -157,10 +159,83 @@
pass
if call_depart:
visitor.document.reporter.debug(
- 'calling dispatch_departure for %s' % self.__class__.__name__,
- category='nodes.Node.walkabout')
+ 'docutils.nodes.Node.walkabout calling dispatch_departure '
+ 'for %s' % self.__class__.__name__)
visitor.dispatch_departure(self)
+ def traverse(self, condition=None,
+ include_self=1, descend=1, siblings=0, ascend=0):
+ """
+ Return an iterable containing
+
+ * self (if include_self is true)
+ * all descendants in tree traversal order (if descend is true)
+ * all siblings (if siblings is true) and their descendants (if
+ also descend is true)
+ * the siblings of the parent (if ascend is true) and their
+ descendants (if also descend is true), and so on
+
+ If ascend is true, assume siblings to be true as well.
+
+ For example, given the following tree::
+
+ <paragraph>
+ <emphasis> <--- emphasis.traverse() and
+ <strong> <--- strong.traverse() are called.
+ Foo
+ Bar
+ <reference name="Baz" refid="baz">
+ Baz
+
+ Then list(emphasis.traverse()) equals ::
+
+ [<emphasis>, <strong>, <#text: Foo>, <#text: Bar>]
+
+ and list(strong.traverse(ascend=1)) equals ::
+
+ [<strong>, <#text: Foo>, <#text: Bar>, <reference>, <#text: Baz>]
+ """
+ r = []
+ if ascend:
+ siblings=1
+ if include_self and (condition is None or condition(self)):
+ r.append(self)
+ if descend and len(self.children):
+ for child in self:
+ r.extend(child.traverse(
+ include_self=1, descend=1, siblings=0, ascend=0,
+ condition=condition))
+ if siblings or ascend:
+ node = self
+ while node.parent:
+ index = node.parent.index(node)
+ for sibling in node.parent[index+1:]:
+ r.extend(sibling.traverse(include_self=1, descend=descend,
+ siblings=0, ascend=0,
+ condition=condition))
+ if not ascend:
+ break
+ else:
+ node = node.parent
+ return r
+
+
+ def next_node(self, condition=None,
+ include_self=0, descend=1, siblings=0, ascend=0):
+ """
+ Return the first node in the iterable returned by traverse(),
+ or None if the iterable is empty.
+
+ Parameter list is the same as of traverse. Note that
+ include_self defaults to 0, though.
+ """
+ iterable = self.traverse(condition=condition,
+ include_self=include_self, descend=descend,
+ siblings=siblings, ascend=ascend)
+ try:
+ return iterable[0]
+ except IndexError:
+ return None
class Text(Node, UserString):
@@ -172,6 +247,9 @@
tagname = '#text'
+ children = ()
+ """Text nodes have no children, and cannot have children."""
+
def __init__(self, data, rawsource=''):
UserString.__init__(self, data)
@@ -209,10 +287,6 @@
result.append(indent + line + '\n')
return ''.join(result)
- def get_children(self):
- """Text nodes have no children. Return []."""
- return []
-
class Element(Node):
@@ -225,6 +299,12 @@
element['att'] = 'value'
+ There are two special attributes: 'ids' and 'names'. Both are
+ lists of unique identifiers, and names serve as human interfaces
+ to IDs. Names are case- and whitespace-normalized (see the
+ fully_normalize_name() function), and IDs conform to the regular
+ expression ``[a-z](-?[a-z0-9]+)*`` (see the make_id() function).
+
Elements also emulate lists for child nodes (element nodes and/or text
nodes), indexing by integer. To get the first child node, use::
@@ -245,6 +325,10 @@
This is equivalent to ``element.extend([node1, node2])``.
"""
+ attr_defaults = {'ids': [], 'classes': [], 'names': [],
+ 'dupnames': [], 'backrefs': []}
+ """Default attributes."""
+
tagname = None
"""The element generic identifier. If None, it is set as an instance
attribute to the name of the class."""
@@ -261,7 +345,7 @@
self.extend(children) # maintain parent info
- self.attributes = {}
+ self.attributes = copy.deepcopy(self.attr_defaults)
"""Dictionary of attribute {name: value}."""
for att, value in attributes.items():
@@ -272,7 +356,7 @@
def _dom_node(self, domroot):
element = domroot.createElement(self.tagname)
- for attribute, value in self.attributes.items():
+ for attribute, value in self.attlist():
if isinstance(value, ListType):
value = ' '.join(['%s' % v for v in value])
element.setAttribute(attribute, '%s' % value)
@@ -287,16 +371,16 @@
if len(data) > 60:
data = data[:56] + ' ...'
break
- if self.hasattr('name'):
+ if self['names']:
return '<%s "%s": %s>' % (self.__class__.__name__,
- self.attributes['name'], data)
+ '; '.join(self['names']), data)
else:
return '<%s: %s>' % (self.__class__.__name__, data)
def shortrepr(self):
- if self.hasattr('name'):
+ if self['names']:
return '<%s "%s"...>' % (self.__class__.__name__,
- self.attributes['name'])
+ '; '.join(self['names']))
else:
return '<%s...>' % self.tagname
@@ -382,20 +466,24 @@
def __iadd__(self, other):
"""Append a node or a list of nodes to `self.children`."""
if isinstance(other, Node):
- self.setup_child(other)
- self.children.append(other)
+ self.append(other)
elif other is not None:
- for node in other:
- self.setup_child(node)
- self.children.extend(other)
+ self.extend(other)
return self
def astext(self):
return self.child_text_separator.join(
[child.astext() for child in self.children])
+ def non_default_attributes(self):
+ atts = {}
+ for key, value in self.attributes.items():
+ if self.is_not_default(key):
+ atts[key] = value
+ return atts
+
def attlist(self):
- attlist = self.attributes.items()
+ attlist = self.non_default_attributes().items()
attlist.sort()
return attlist
@@ -420,8 +508,7 @@
def extend(self, item):
for node in item:
- self.setup_child(node)
- self.children.extend(item)
+ self.append(node)
def insert(self, index, item):
if isinstance(item, Node):
@@ -439,6 +526,15 @@
def index(self, item):
return self.children.index(item)
+ def is_not_default(self, key):
+ try:
+ return self[key] != self.attr_defaults[key]
+ except KeyError:
+ return 1
+
+ def clear(self):
+ self.children = []
+
def replace(self, old, new):
"""Replace one child `Node` with another child or children."""
index = self.index(old)
@@ -482,12 +578,10 @@
if not isinstance(childclass, TupleType):
childclass = (childclass,)
for index in range(start, min(len(self), end)):
- match = 0
for c in childclass:
if isinstance(self.children[index], c):
- match = 1
break
- if not match:
+ else:
return index
return None
@@ -496,17 +590,33 @@
[child.pformat(indent, level+1)
for child in self.children])
- def get_children(self):
- """Return this element's children."""
- return self.children
-
def copy(self):
return self.__class__(**self.attributes)
def set_class(self, name):
- """Add a new name to the "class" attribute."""
- self.attributes['class'] = (self.attributes.get('class', '') + ' '
- + name.lower()).strip()
+ """Add a new class to the "classes" attribute."""
+ warnings.warn('docutils.nodes.Element.set_class deprecated; '
+ "append to Element['classes'] list attribute directly",
+ DeprecationWarning, stacklevel=2)
+ assert ' ' not in name
+ self['classes'].append(name.lower())
+
+ def note_referenced_by(self, name=None, id=None):
+ """Note that this Element has been referenced by its name
+ `name` or id `id`."""
+ self.referenced = 1
+ # Element.expect_referenced_by_* dictionaries map names or ids
+ # to nodes whose ``referenced`` attribute is set to true as
+ # soon as this node is referenced by the given name or id.
+ # Needed for target propagation.
+ by_name = getattr(self, 'expect_referenced_by_name', {}).get(name)
+ by_id = getattr(self, 'expect_referenced_by_id', {}).get(id)
+ if by_name:
+ assert name is not None
+ by_name.referenced = 1
+ if by_id:
+ assert id is not None
+ by_id.referenced = 1
class TextElement(Element):
@@ -514,7 +624,7 @@
"""
An element which directly contains text.
- Its children are all `Text` or `TextElement` subclass nodes. You can
+ Its children are all `Text` or `Inline` subclass nodes. You can
check whether an element's context is inline simply by checking whether
its immediate parent is a `TextElement` instance (including subclasses).
This is handy for nodes like `image` that can appear both inline and as
@@ -557,7 +667,7 @@
class BackLinkable:
def add_backref(self, refid):
- self.setdefault('backrefs', []).append(refid)
+ self['backrefs'].append(refid)
# ====================
@@ -568,15 +678,12 @@
class Titular: pass
-class PreDecorative:
- """Category of Node which may occur before Decorative Nodes."""
-
-class PreBibliographic(PreDecorative):
+class PreBibliographic:
"""Category of Node which may occur before Bibliographic Nodes."""
-class Bibliographic(PreDecorative): pass
+class Bibliographic: pass
-class Decorative: pass
+class Decorative(PreBibliographic): pass
class Structural: pass
@@ -584,7 +691,8 @@
class General(Body): pass
-class Sequential(Body): pass
+class Sequential(Body):
+ """List-like elements."""
class Admonition(Body): pass
@@ -604,9 +712,6 @@
referenced = 0
- indirect_reference_name = None
- """Holds the whitespace_normalized_name (contains mixed case) of a target"""
-
class Labeled:
"""Contains a `label` as its first element."""
@@ -717,6 +822,9 @@
self.transformer = docutils.transforms.Transformer(self)
"""Storage for transforms to be applied to this document."""
+ self.decoration = None
+ """Document's `decoration` node."""
+
self.document = self
def asdom(self, dom=xml.dom.minidom):
@@ -726,21 +834,23 @@
return domroot
def set_id(self, node, msgnode=None):
- if node.has_key('id'):
- id = node['id']
+ for id in node['ids']:
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 += msg
- else:
- if node.has_key('name'):
- id = make_id(node['name'])
+ if not node['ids']:
+ for name in node['names']:
+ id = self.settings.id_prefix + make_id(name)
+ if id and not self.ids.has_key(id):
+ break
else:
id = ''
- while not id or self.ids.has_key(id):
- id = 'id%s' % self.id_start
- self.id_start += 1
- node['id'] = id
+ while not id or self.ids.has_key(id):
+ id = (self.settings.id_prefix +
+ self.settings.auto_id_prefix + str(self.id_start))
+ self.id_start += 1
+ node['ids'].append(id)
self.ids[id] = node
return id
@@ -775,8 +885,7 @@
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']
+ for name in node['names']:
if self.nameids.has_key(name):
self.set_duplicate_name_id(node, id, name, msgnode, explicit)
else:
@@ -794,30 +903,30 @@
old_node = self.ids[old_id]
if node.has_key('refuri'):
refuri = node['refuri']
- if old_node.has_key('name') \
+ if old_node['names'] \
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)
+ dupname(old_node, name)
self.nameids[name] = None
msg = self.reporter.system_message(
level, 'Duplicate explicit target name: "%s".' % name,
backrefs=[id], base_node=node)
if msgnode != None:
msgnode += msg
- dupname(node)
+ dupname(node, name)
else:
self.nameids[name] = id
if old_id is not None:
old_node = self.ids[old_id]
- dupname(old_node)
+ dupname(old_node, name)
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)
+ dupname(old_node, name)
+ dupname(node, name)
if not explicit or (not old_explicit and old_id is not None):
msg = self.reporter.info(
'Duplicate implicit target name: "%s".' % name,
@@ -851,7 +960,7 @@
def note_indirect_target(self, target):
self.indirect_targets.append(target)
- if target.has_key('name'):
+ if target['names']:
self.note_refname(target)
def note_anonymous_target(self, target):
@@ -895,7 +1004,8 @@
self.note_refname(ref)
def note_substitution_def(self, subdef, def_name, msgnode=None):
- name = subdef['name'] = whitespace_normalize_name(def_name)
+ name = whitespace_normalize_name(def_name)
+ subdef['names'].append(name)
if self.substitution_defs.has_key(name):
msg = self.reporter.error(
'Duplicate substitution definition name: "%s".' % name,
@@ -903,7 +1013,7 @@
if msgnode != None:
msgnode += msg
oldnode = self.substitution_defs[name]
- dupname(oldnode)
+ dupname(oldnode, name)
# keep only the last definition:
self.substitution_defs[name] = subdef
# case-insensitive mapping:
@@ -933,6 +1043,16 @@
return self.__class__(self.settings, self.reporter,
**self.attributes)
+ def get_decoration(self):
+ if not self.decoration:
+ self.decoration = decoration()
+ index = self.first_child_not_matching_class(Titular)
+ if index is None:
+ self.append(self.decoration)
+ else:
+ self.insert(index, self.decoration)
+ return self.decoration
+
# ================
# Title Elements
@@ -964,7 +1084,19 @@
# Decorative Elements
# =====================
-class decoration(Decorative, Element): pass
+class decoration(Decorative, Element):
+
+ def get_header(self):
+ if not len(self.children) or not isinstance(self.children[0], header):
+ self.insert(0, header())
+ return self.children[0]
+
+ def get_footer(self):
+ if not len(self.children) or not isinstance(self.children[-1], footer):
+ self.append(footer())
+ return self.children[-1]
+
+
class header(Decorative, Element): pass
class footer(Decorative, Element): pass
@@ -1061,7 +1193,7 @@
class line_block(General, Element): pass
-class line(General, TextElement):
+class line(Part, TextElement):
indent = None
@@ -1081,8 +1213,8 @@
class comment(Special, Invisible, FixedTextElement): 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 footnote(General, BackLinkable, Element, Labeled, Targetable): pass
+class citation(General, BackLinkable, Element, Labeled, Targetable): pass
class label(Part, TextElement): pass
class figure(General, Element): pass
class caption(Part, TextElement): pass
@@ -1096,7 +1228,7 @@
class entry(Part, Element): pass
-class system_message(Special, PreBibliographic, Element, BackLinkable):
+class system_message(Special, BackLinkable, PreBibliographic, Element):
def __init__(self, message=None, *children, **attributes):
if message:
@@ -1210,7 +1342,7 @@
class subscript(Inline, TextElement): pass
-class image(General, Inline, TextElement):
+class image(General, Inline, Element):
def astext(self):
return self.get('alt', '')
@@ -1306,8 +1438,8 @@
node_name = node.__class__.__name__
method = getattr(self, 'visit_' + node_name, self.unknown_visit)
self.document.reporter.debug(
- 'calling %s for %s' % (method.__name__, node_name),
- category='nodes.NodeVisitor.dispatch_visit')
+ 'docutils.nodes.NodeVisitor.dispatch_visit calling %s for %s'
+ % (method.__name__, node_name))
return method(node)
def dispatch_departure(self, node):
@@ -1319,8 +1451,8 @@
node_name = node.__class__.__name__
method = getattr(self, 'depart_' + node_name, self.unknown_departure)
self.document.reporter.debug(
- 'calling %s for %s' % (method.__name__, node_name),
- category='nodes.NodeVisitor.dispatch_departure')
+ 'docutils.nodes.NodeVisitor.dispatch_departure calling %s for %s'
+ % (method.__name__, node_name))
return method(node)
def unknown_visit(self, node):
@@ -1357,6 +1489,7 @@
subclasses), subclass `NodeVisitor` instead.
"""
+
class GenericNodeVisitor(NodeVisitor):
"""
@@ -1398,10 +1531,11 @@
setattr(GenericNodeVisitor, "visit_" + _name, _call_default_visit)
setattr(GenericNodeVisitor, "depart_" + _name, _call_default_departure)
setattr(SparseNodeVisitor, 'visit_' + _name, _nop)
- setattr(SparseNodeVisitor, 'depart' + _name, _nop)
+ setattr(SparseNodeVisitor, 'depart_' + _name, _nop)
_add_node_class_names(node_class_names)
+
class TreeCopyVisitor(GenericNodeVisitor):
"""
@@ -1534,9 +1668,12 @@
_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']
+def dupname(node, name):
+ node['dupnames'].append(name)
+ node['names'].remove(name)
+ # Assume that this method is referenced, even though it isn't; we
+ # don't want to throw unnecessary system_messages.
+ node.referenced = 1
def fully_normalize_name(name):
"""Return a case- and whitespace-normalized name."""
=== Zope/lib/python/docutils/statemachine.py 1.2.10.7 => 1.2.10.8 ===
=== Zope/lib/python/docutils/utils.py 1.2.10.7 => 1.2.10.8 ===
--- Zope/lib/python/docutils/utils.py:1.2.10.7 Fri Jan 7 08:26:02 2005
+++ Zope/lib/python/docutils/utils.py Sun Oct 9 10:43:43 2005
@@ -13,6 +13,7 @@
import sys
import os
import os.path
+import warnings
from types import StringType, UnicodeType
from docutils import ApplicationError, DataError
from docutils import frontend, nodes
@@ -39,27 +40,14 @@
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).
+ or off, and an I/O stream for warnings. These are stored as instance
+ attributes.
- 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 if not set to ''.
-
- 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).
+ When a system message is generated, its level is compared to the stored
+ thresholds, and a warning or error is generated as appropriate. Debug
+ messages are produced iff the stored debug switch is on, independently of
+ other thresholds. Message output is sent to the stored warning stream if
+ not set to ''.
The Reporter class also employs a modified form of the "Observer" pattern
[GoF95]_ to track system messages generated. The `attach_observer` method
@@ -67,9 +55,6 @@
accepts system messages. The observer can be removed with
`detach_observer`, and another added in its place.
- .. [#] The concept of "categories" was inspired by the log4j project:
- http://jakarta.apache.org/log4j/.
-
.. [GoF95] Gamma, Helm, Johnson, Vlissides. *Design Patterns: Elements of
Reusable Object-Oriented Software*. Addison-Wesley, Reading, MA, USA,
1995.
@@ -81,10 +66,7 @@
def __init__(self, source, report_level, halt_level, stream=None,
debug=0, encoding='ascii', error_handler='replace'):
"""
- Initialize the `ConditionSet` forthe `Reporter`'s default category.
-
:Parameters:
-
- `source`: The path to or description of the source data.
- `report_level`: The level at or above which warning output will
be sent to `stream`.
@@ -101,6 +83,23 @@
self.source = source
"""The path to or description of the source data."""
+ self.encoding = encoding
+ """The character encoding for the stderr output."""
+
+ self.error_handler = error_handler
+ """The character encoding error handler."""
+
+ self.debug_flag = debug
+ """Show debug (level=0) system messages?"""
+
+ self.report_level = report_level
+ """The level at or above which warning output will be sent
+ to `self.stream`."""
+
+ self.halt_level = halt_level
+ """The level at or above which `SystemMessage` exceptions
+ will be raised, halting execution."""
+
if stream is None:
stream = sys.stderr
elif type(stream) in (StringType, UnicodeType):
@@ -111,15 +110,8 @@
elif type(stream) == UnicodeType:
stream = open(stream.encode(), 'w')
- self.encoding = encoding
- """The character encoding for the stderr output."""
-
- self.error_handler = error_handler
- """The character encoding error handler."""
-
- self.categories = {'': ConditionSet(debug, report_level, halt_level,
- stream)}
- """Mapping of category names to conditions. Default category is ''."""
+ self.stream = stream
+ """Where warning output is sent."""
self.observers = []
"""List of bound methods or functions to call with each system_message
@@ -130,23 +122,15 @@
def set_conditions(self, category, report_level, halt_level,
stream=None, debug=0):
+ warnings.warn('docutils.utils.Reporter.set_conditions deprecated; '
+ 'set attributes via configuration settings or directly',
+ DeprecationWarning, stacklevel=2)
+ self.report_level = report_level
+ self.halt_level = halt_level
if stream is None:
stream = sys.stderr
- self.categories[category] = ConditionSet(debug, report_level,
- halt_level, stream)
-
- def unset_conditions(self, category):
- if category and self.categories.has_key(category):
- del self.categories[category]
-
- __delitem__ = unset_conditions
-
- def get_conditions(self, category):
- while not self.categories.has_key(category):
- category = category[:category.rfind('.') + 1][:-1]
- return self.categories[category]
-
- __getitem__ = get_conditions
+ self.stream = stream
+ self.debug = debug
def attach_observer(self, observer):
"""
@@ -169,9 +153,6 @@
Raise an exception or generate a warning if appropriate.
"""
attributes = kwargs.copy()
- category = kwargs.get('category', '')
- if kwargs.has_key('category'):
- del attributes['category']
if kwargs.has_key('base_node'):
source, line = get_source_line(kwargs['base_node'])
del attributes['base_node']
@@ -183,16 +164,13 @@
msg = nodes.system_message(message, level=level,
type=self.levels[level],
*children, **attributes)
- debug, report_level, halt_level, stream = self[category].astuple()
- if (level >= report_level or debug and level == 0) and stream:
+ if self.stream and (level >= self.report_level
+ or self.debug_flag and level == 0):
msgtext = msg.astext().encode(self.encoding, self.error_handler)
- if category:
- print >>stream, msgtext, '[%s]' % category
- else:
- print >>stream, msgtext
- if level >= halt_level:
+ print >>self.stream, msgtext
+ if level >= self.halt_level:
raise SystemMessage(msg, level)
- if level > 0 or debug:
+ if level > 0 or self.debug_flag:
self.notify_observers(msg)
self.max_level = max(level, self.max_level)
return msg
@@ -203,7 +181,8 @@
effect on the processing. Level-0 system messages are handled
separately from the others.
"""
- return self.system_message(0, *args, **kwargs)
+ if self.debug_flag:
+ return self.system_message(0, *args, **kwargs)
def info(self, *args, **kwargs):
"""
@@ -235,25 +214,6 @@
return self.system_message(4, *args, **kwargs)
-class ConditionSet:
-
- """
- A set of two thresholds (`report_level` & `halt_level`), a switch
- (`debug`), and an I/O stream (`stream`), corresponding to one `Reporter`
- category.
- """
-
- def __init__(self, debug, report_level, halt_level, stream):
- self.debug = debug
- self.report_level = report_level
- self.halt_level = halt_level
- self.stream = stream
-
- def astuple(self):
- return (self.debug, self.report_level, self.halt_level,
- self.stream)
-
-
class ExtensionOptionError(DataError): pass
class BadOptionError(ExtensionOptionError): pass
class BadOptionDataError(ExtensionOptionError): pass
@@ -346,7 +306,7 @@
options[name] = convertor(value)
except (ValueError, TypeError), detail:
raise detail.__class__('(option: "%s"; value: %r)\n%s'
- % (name, value, detail))
+ % (name, value, ' '.join(detail.args)))
return options
More information about the Zope-Checkins
mailing list