[Zope-Checkins] CVS: Zope/lib/python/docutils/transforms -
__init__.py:1.2.10.7 components.py:1.2.10.7
frontmatter.py:1.2.10.7 misc.py:1.2.10.7 parts.py:1.2.10.7
peps.py:1.2.10.8 references.py:1.2.10.7 universal.py:1.2.10.7
Andreas Jung
andreas at andreas-jung.com
Sun Oct 9 10:44:17 EDT 2005
Update of /cvs-repository/Zope/lib/python/docutils/transforms
In directory cvs.zope.org:/tmp/cvs-serv26422/transforms
Modified Files:
Tag: Zope-2_7-branch
__init__.py components.py frontmatter.py misc.py parts.py
peps.py references.py universal.py
Log Message:
upgrade to docutils 0.3.9
=== Zope/lib/python/docutils/transforms/__init__.py 1.2.10.6 => 1.2.10.7 ===
--- Zope/lib/python/docutils/transforms/__init__.py:1.2.10.6 Fri Jan 7 08:26:05 2005
+++ Zope/lib/python/docutils/transforms/__init__.py Sun Oct 9 10:43:46 2005
@@ -59,7 +59,7 @@
self.language = languages.get_language(
document.settings.language_code)
"""Language module local to this document."""
-
+
def apply(self):
"""Override to apply the transform to the document tree."""
@@ -163,7 +163,6 @@
decorated_list = [(f.priority, f) for f in unknown_reference_resolvers]
decorated_list.sort()
self.unknown_reference_resolvers.extend([f[1] for f in decorated_list])
-
def apply_transforms(self):
"""Apply all of the stored transforms, in priority order."""
=== Zope/lib/python/docutils/transforms/components.py 1.2.10.6 => 1.2.10.7 ===
=== Zope/lib/python/docutils/transforms/frontmatter.py 1.2.10.6 => 1.2.10.7 ===
--- Zope/lib/python/docutils/transforms/frontmatter.py:1.2.10.6 Fri Jan 7 08:26:06 2005
+++ Zope/lib/python/docutils/transforms/frontmatter.py Sun Oct 9 10:43:46 2005
@@ -5,13 +5,15 @@
# Copyright: This module has been placed in the public domain.
"""
-Transforms related to the front matter of a document (information
-found before the main text):
+Transforms related to the front matter of a document or a section
+(information found before the main text):
- `DocTitle`: Used to transform a lone top level section's title to
the document title, and promote a remaining lone top-level section's
title to the document subtitle.
+- `SectionTitle`: Used to transform a lone subsection into a subtitle.
+
- `DocInfo`: Used to transform a bibliographic field list into docinfo
elements.
"""
@@ -23,7 +25,100 @@
from docutils.transforms import TransformError, Transform
-class DocTitle(Transform):
+class TitlePromoter(Transform):
+
+ """
+ Abstract base class for DocTitle and SectionSubTitle transforms.
+ """
+
+ def promote_title(self, node):
+ """
+ Transform the following tree::
+
+ <node>
+ <section>
+ <title>
+ ...
+
+ into ::
+
+ <node>
+ <title>
+ ...
+
+ `node` is normally a document.
+ """
+ # `node` must not have a title yet.
+ assert not (len(node) and isinstance(node[0], nodes.title))
+ section, index = self.candidate_index(node)
+ if index is None:
+ return None
+ # Transfer the section's attributes to the node:
+ node.attributes.update(section.attributes)
+ # setup_child is called automatically for all nodes.
+ node[:] = (section[:1] # section title
+ + node[:index] # everything that was in the
+ # node before the section
+ + section[1:]) # everything that was in the section
+ assert isinstance(node[0], nodes.title)
+ return 1
+
+ def promote_subtitle(self, node):
+ """
+ Transform the following node tree::
+
+ <node>
+ <title>
+ <section>
+ <title>
+ ...
+
+ into ::
+
+ <node>
+ <title>
+ <subtitle>
+ ...
+ """
+ subsection, index = self.candidate_index(node)
+ if index is None:
+ return None
+ subtitle = nodes.subtitle()
+ # Transfer the subsection's attributes to the new subtitle:
+ # This causes trouble with list attributes! To do: Write a
+ # test case which catches direct access to the `attributes`
+ # dictionary and/or write a test case which shows problems in
+ # this particular case.
+ subtitle.attributes.update(subsection.attributes)
+ # We're losing the subtitle's attributes here! To do: Write a
+ # test case which shows this behavior.
+ # Transfer the contents of the subsection's title to the
+ # subtitle:
+ subtitle[:] = subsection[0][:]
+ node[:] = (node[:1] # title
+ + [subtitle]
+ # everything that was before the section:
+ + node[1:index]
+ # everything that was in the subsection:
+ + subsection[1:])
+ return 1
+
+ def candidate_index(self, node):
+ """
+ Find and return the promotion candidate and its index.
+
+ Return (None, None) if no valid candidate was found.
+ """
+ index = node.first_child_not_matching_class(
+ nodes.PreBibliographic)
+ if index is None or len(node) > (index + 1) or \
+ not isinstance(node[index], nodes.section):
+ return None, None
+ else:
+ return node[index], index
+
+
+class DocTitle(TitlePromoter):
"""
In reStructuredText_, there is no way to specify a document title
@@ -50,7 +145,7 @@
Once parsed, it looks like this::
<document>
- <section name="top-level title">
+ <section names="top-level title">
<title>
Top-Level Title
<paragraph>
@@ -58,7 +153,7 @@
After running the DocTitle transform, we have::
- <document name="top-level title">
+ <document names="top-level title">
<title>
Top-Level Title
<paragraph>
@@ -85,10 +180,10 @@
After parsing and running the Section Promotion transform, the
result is::
- <document name="top-level title">
+ <document names="top-level title">
<title>
Top-Level Title
- <subtitle name="second-level title">
+ <subtitle names="second-level title">
Second-Level Title
<paragraph>
A paragraph.
@@ -107,54 +202,47 @@
def apply(self):
if not getattr(self.document.settings, 'doctitle_xform', 1):
return
- if self.promote_document_title():
- self.promote_document_subtitle()
+ if self.promote_title(self.document):
+ self.promote_subtitle(self.document)
- def promote_document_title(self):
- section, index = self.candidate_index()
- if index is None:
- return None
- document = self.document
- # Transfer the section's attributes to the document element (at root):
- 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):
- subsection, index = self.candidate_index()
- if index is None:
- return None
- subtitle = nodes.subtitle()
- # Transfer the subsection's attributes to the new subtitle:
- subtitle.attributes.update(subsection.attributes)
- # Transfer the contents of the subsection's title to the subtitle:
- subtitle[:] = subsection[0][:]
- document = self.document
- document[:] = (document[:1] # document title
- + [subtitle]
- # everything that was before the section:
- + document[1:index]
- # everything that was in the subsection:
- + subsection[1:])
- return 1
+class SectionSubTitle(TitlePromoter):
- def candidate_index(self):
- """
- Find and return the promotion candidate and its index.
+ """
+ This works like document subtitles, but for sections. For example, ::
- Return (None, None) if no valid candidate was found.
- """
- document = self.document
- 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
- else:
- return document[index], index
+ <section>
+ <title>
+ Title
+ <section>
+ <title>
+ Subtitle
+ ...
+
+ is transformed into ::
+
+ <section>
+ <title>
+ Title
+ <subtitle>
+ Subtitle
+ ...
+
+ For details refer to the docstring of DocTitle.
+ """
+
+ default_priority = 350
+
+ def apply(self):
+ if not getattr(self.document.settings, 'sectsubtitle_xform', 1):
+ return
+ for section in self.document.traverse(lambda n:
+ isinstance(n, nodes.section)):
+ # On our way through the node tree, we are deleting
+ # sections, but we call self.promote_subtitle for those
+ # sections nonetheless. To do: Write a test case which
+ # shows the problem and discuss on Docutils-develop.
+ self.promote_subtitle(section)
class DocInfo(Transform):
@@ -258,11 +346,10 @@
candidate = document[index]
if isinstance(candidate, nodes.field_list):
biblioindex = document.first_child_not_matching_class(
- nodes.Titular)
+ (nodes.Titular, nodes.Decorative))
nodelist = self.extract_bibliographic(candidate)
del document[index] # untransformed field list (candidate)
document[biblioindex:biblioindex] = nodelist
- return
def extract_bibliographic(self, field_list):
docinfo = nodes.docinfo()
@@ -294,7 +381,7 @@
raise TransformError
title = nodes.title(name, labels[canonical])
topics[canonical] = biblioclass(
- '', title, CLASS=canonical, *field[1].children)
+ '', title, classes=[canonical], *field[1].children)
else:
docinfo.append(biblioclass('', *field[1].children))
except TransformError:
=== Zope/lib/python/docutils/transforms/misc.py 1.2.10.6 => 1.2.10.7 ===
--- Zope/lib/python/docutils/transforms/misc.py:1.2.10.6 Fri Jan 7 08:26:06 2005
+++ Zope/lib/python/docutils/transforms/misc.py Sun Oct 9 10:43:46 2005
@@ -45,7 +45,6 @@
def apply(self):
pending = self.startnode
- class_value = pending.details['class']
parent = pending.parent
child = pending
while parent:
@@ -55,7 +54,7 @@
if (isinstance(element, nodes.Invisible) or
isinstance(element, nodes.system_message)):
continue
- element.set_class(class_value)
+ element['classes'] += pending.details['class']
pending.parent.remove(pending)
return
else:
=== Zope/lib/python/docutils/transforms/parts.py 1.2.10.6 => 1.2.10.7 ===
--- Zope/lib/python/docutils/transforms/parts.py:1.2.10.6 Fri Jan 7 08:26:06 2005
+++ Zope/lib/python/docutils/transforms/parts.py Sun Oct 9 10:43:46 2005
@@ -54,7 +54,7 @@
generated = nodes.generated(
'', (self.prefix + '.'.join(numbers) + self.suffix
+ u'\u00a0' * 3),
- CLASS='sectnum')
+ classes=['sectnum'])
title.insert(0, generated)
title['auto'] = 1
if depth < self.maxdepth:
@@ -84,14 +84,13 @@
details = self.startnode.details
if details.has_key('local'):
startnode = self.startnode.parent.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):
+ while not (isinstance(startnode, nodes.section)
+ or isinstance(startnode, nodes.document)):
+ # find the ToC root: a direct ancestor of startnode
startnode = startnode.parent
else:
startnode = self.document
-
- self.toc_id = self.startnode.parent['id']
+ self.toc_id = self.startnode.parent['ids'][0]
if details.has_key('backlinks'):
self.backlinks = details['backlinks']
else:
@@ -117,15 +116,17 @@
title = section[0]
auto = title.get('auto') # May be set by SectNum.
entrytext = self.copy_and_filter(title)
- reference = nodes.reference('', '', refid=section['id'],
+ reference = nodes.reference('', '', refid=section['ids'][0],
*entrytext)
ref_id = self.document.set_id(reference)
entry = nodes.paragraph('', '', reference)
item = nodes.list_item('', entry)
- if self.backlinks == 'entry':
- title['refid'] = ref_id
- elif self.backlinks == 'top':
- title['refid'] = self.toc_id
+ if (self.backlinks in ('entry', 'top') and title.next_node(
+ lambda n: isinstance(n, nodes.reference)) is None):
+ if self.backlinks == 'entry':
+ title['refid'] = ref_id
+ elif self.backlinks == 'top':
+ title['refid'] = self.toc_id
if level < depth:
subsects = self.build_contents(section, level)
item += subsects
@@ -133,7 +134,7 @@
if entries:
contents = nodes.bullet_list('', *entries)
if auto:
- contents.set_class('auto-toc')
+ contents['classes'].append('auto-toc')
return contents
else:
return []
@@ -148,7 +149,7 @@
class ContentsFilter(nodes.TreeCopyVisitor):
def get_entry_text(self):
- return self.get_tree_copy().get_children()
+ return self.get_tree_copy().children
def visit_citation_reference(self, node):
raise nodes.SkipNode
=== Zope/lib/python/docutils/transforms/peps.py 1.2.10.7 => 1.2.10.8 ===
--- Zope/lib/python/docutils/transforms/peps.py:1.2.10.7 Fri Jan 7 08:26:06 2005
+++ Zope/lib/python/docutils/transforms/peps.py Sun Oct 9 10:43:46 2005
@@ -46,7 +46,7 @@
raise DataError('Document tree is empty.')
header = self.document[0]
if not isinstance(header, nodes.field_list) or \
- header.get('class') != 'rfc2822':
+ 'rfc2822' not in header['classes']:
raise DataError('Document does not begin with an RFC-2822 '
'header; it is not a PEP.')
pep = None
@@ -149,10 +149,10 @@
language = languages.get_language(self.document.settings.language_code)
name = language.labels['contents']
title = nodes.title('', name)
- topic = nodes.topic('', title, CLASS='contents')
+ topic = nodes.topic('', title, classes=['contents'])
name = nodes.fully_normalize_name(name)
if not self.document.has_name(name):
- topic['name'] = name
+ topic['names'].append(name)
self.document.note_implicit_target(topic)
pending = nodes.pending(parts.Contents)
topic += pending
@@ -244,7 +244,7 @@
node.parent.replace(node, mask_email(node))
def visit_field_list(self, node):
- if node.hasattr('class') and node['class'] == 'rfc2822':
+ if 'rfc2822' in node['classes']:
raise nodes.SkipNode
def visit_tgroup(self, node):
@@ -254,7 +254,7 @@
def visit_colspec(self, node):
self.entry += 1
if self.pep_table and self.entry == 2:
- node['class'] = 'num'
+ node['classes'].append('num')
def visit_row(self, node):
self.entry = 0
@@ -262,7 +262,7 @@
def visit_entry(self, node):
self.entry += 1
if self.pep_table and self.entry == 2 and len(node) == 1:
- node['class'] = 'num'
+ node['classes'].append('num')
p = node[0]
if isinstance(p, nodes.paragraph) and len(p) == 1:
text = p.astext()
=== Zope/lib/python/docutils/transforms/references.py 1.2.10.6 => 1.2.10.7 ===
--- Zope/lib/python/docutils/transforms/references.py:1.2.10.6 Fri Jan 7 08:26:06 2005
+++ Zope/lib/python/docutils/transforms/references.py Sun Oct 9 10:43:46 2005
@@ -16,87 +16,75 @@
from docutils.transforms import TransformError, Transform
-indices = xrange(sys.maxint)
-
-
-class ChainedTargets(Transform):
+class PropagateTargets(Transform):
"""
- Attributes "refuri" and "refname" are migrated from the final direct
- target up the chain of contiguous adjacent internal targets, using
- `ChainedTargetResolver`.
- """
-
- default_priority = 420
-
- def apply(self):
- visitor = ChainedTargetResolver(self.document)
- self.document.walk(visitor)
-
+ Propagate empty internal targets to the next element.
-class ChainedTargetResolver(nodes.SparseNodeVisitor):
+ Given the following nodes::
- """
- Copy reference attributes up the length of a hyperlink target chain.
-
- "Chained targets" are multiple adjacent internal hyperlink targets which
- "point to" an external or indirect target. After the transform, all
- chained targets will effectively point to the same place.
-
- Given the following ``document`` as input::
-
- <document>
- <target id="a" name="a">
- <target id="b" name="b">
- <target id="c" name="c" refuri="http://chained.external.targets">
- <target id="d" name="d">
- <paragraph>
- I'm known as "d".
- <target id="e" name="e">
- <target id="id1">
- <target id="f" name="f" refname="d">
+ <target ids="internal1" names="internal1">
+ <target anonymous="1" ids="id1">
+ <target ids="internal2" names="internal2">
+ <paragraph>
+ This is a test.
- ``ChainedTargetResolver(document).walk()`` will transform the above into::
+ PropagateTargets propagates the ids and names of the internal
+ targets preceding the paragraph to the paragraph itself::
- <document>
- <target id="a" name="a" refuri="http://chained.external.targets">
- <target id="b" name="b" refuri="http://chained.external.targets">
- <target id="c" name="c" refuri="http://chained.external.targets">
- <target id="d" name="d">
- <paragraph>
- I'm known as "d".
- <target id="e" name="e" refname="d">
- <target id="id1" refname="d">
- <target id="f" name="f" refname="d">
+ <target refid="internal1">
+ <target anonymous="1" refid="id1">
+ <target refid="internal2">
+ <paragraph ids="internal2 id1 internal1" names="internal2 internal1">
+ This is a test.
"""
- def unknown_visit(self, node):
- pass
+ default_priority = 260
- def visit_target(self, node):
- if node.hasattr('refuri'):
- attname = 'refuri'
- call_if_named = self.document.note_external_target
- elif node.hasattr('refname'):
- attname = 'refname'
- call_if_named = self.document.note_indirect_target
- elif node.hasattr('refid'):
- attname = 'refid'
- call_if_named = None
- else:
- return
- attval = node[attname]
- index = node.parent.index(node)
- for i in range(index - 1, -1, -1):
- sibling = node.parent[i]
- if not isinstance(sibling, nodes.target) \
- or sibling.hasattr('refuri') \
- or sibling.hasattr('refname') \
- or sibling.hasattr('refid'):
- break
- sibling[attname] = attval
- if sibling.hasattr('name') and call_if_named:
- call_if_named(sibling)
+ def apply(self):
+ for target in self.document.internal_targets:
+ if not (len(target) == 0 and
+ not (target.attributes.has_key('refid') or
+ target.attributes.has_key('refuri') or
+ target.attributes.has_key('refname'))):
+ continue
+ next_node = target.next_node(ascend=1)
+ # Do not move names and ids into Invisibles (we'd lose the
+ # attributes) or different Targetables (e.g. footnotes).
+ if (next_node is not None and
+ ((not isinstance(next_node, nodes.Invisible) and
+ not isinstance(next_node, nodes.Targetable)) or
+ isinstance(next_node, nodes.target))):
+ next_node['ids'].extend(target['ids'])
+ next_node['names'].extend(target['names'])
+ # Set defaults for next_node.expect_referenced_by_name/id.
+ if not hasattr(next_node, 'expect_referenced_by_name'):
+ next_node.expect_referenced_by_name = {}
+ if not hasattr(next_node, 'expect_referenced_by_id'):
+ next_node.expect_referenced_by_id = {}
+ for id in target['ids']:
+ # Update IDs to node mapping.
+ self.document.ids[id] = next_node
+ # If next_node is referenced by id ``id``, this
+ # target shall be marked as referenced.
+ next_node.expect_referenced_by_id[id] = target
+ for name in target['names']:
+ next_node.expect_referenced_by_name[name] = target
+ # If there are any expect_referenced_by_... attributes
+ # in target set, copy them to next_node.
+ next_node.expect_referenced_by_name.update(
+ getattr(target, 'expect_referenced_by_name', {}))
+ next_node.expect_referenced_by_id.update(
+ getattr(target, 'expect_referenced_by_id', {}))
+ # Set refid to point to the first former ID of target
+ # which is now an ID of next_node.
+ target['refid'] = target['ids'][0]
+ # Clear ids and names; they have been moved to
+ # next_node.
+ target['ids'] = []
+ target['names'] = []
+ self.document.note_refid(target)
+ self.document.note_internal_target(next_node)
class AnonymousHyperlinks(Transform):
@@ -109,8 +97,8 @@
internal
<reference anonymous="1">
external
- <target anonymous="1" id="id1">
- <target anonymous="1" id="id2" refuri="http://external">
+ <target anonymous="1" ids="id1">
+ <target anonymous="1" ids="id2" refuri="http://external">
Corresponding references are linked via "refid" or resolved via "refuri"::
@@ -119,8 +107,8 @@
text
<reference anonymous="1" refuri="http://external">
external
- <target anonymous="1" id="id1">
- <target anonymous="1" id="id2" refuri="http://external">
+ <target anonymous="1" ids="id1">
+ <target anonymous="1" ids="id2" refuri="http://external">
"""
default_priority = 440
@@ -140,16 +128,28 @@
prbid = self.document.set_id(prb)
msg.add_backref(prbid)
ref.parent.replace(ref, prb)
+ for target in self.document.anonymous_targets:
+ # Assume that all anonymous targets have been
+ # referenced to avoid generating lots of
+ # system_messages.
+ target.referenced = 1
return
for ref, target in zip(self.document.anonymous_refs,
self.document.anonymous_targets):
- if target.hasattr('refuri'):
- ref['refuri'] = target['refuri']
- ref.resolved = 1
- else:
- ref['refid'] = target['id']
- self.document.note_refid(ref)
target.referenced = 1
+ while 1:
+ if target.hasattr('refuri'):
+ ref['refuri'] = target['refuri']
+ ref.resolved = 1
+ break
+ else:
+ if not target['ids']:
+ # Propagated target.
+ target = self.document.ids[target['refid']]
+ continue
+ ref['refid'] = target['ids'][0]
+ self.document.note_refid(ref)
+ break
class IndirectHyperlinks(Transform):
@@ -213,20 +213,24 @@
self.resolve_indirect_references(target)
def resolve_indirect_target(self, target):
- refname = target['refname']
- reftarget_id = self.document.nameids.get(refname)
- if not reftarget_id:
- # Check the unknown_reference_resolvers
- for resolver_function in (self.document.transformer
- .unknown_reference_resolvers):
- if resolver_function(target):
- break
- else:
- self.nonexistent_indirect_target(target)
- return
+ refname = target.get('refname')
+ if refname is None:
+ reftarget_id = target['refid']
+ else:
+ reftarget_id = self.document.nameids.get(refname)
+ if not reftarget_id:
+ # Check the unknown_reference_resolvers
+ for resolver_function in \
+ self.document.transformer.unknown_reference_resolvers:
+ if resolver_function(target):
+ break
+ else:
+ self.nonexistent_indirect_target(target)
+ return
reftarget = self.document.ids[reftarget_id]
+ reftarget.note_referenced_by(id=reftarget_id)
if isinstance(reftarget, nodes.target) \
- and not reftarget.resolved and reftarget.hasattr('refname'):
+ and not reftarget.resolved and reftarget.hasattr('refname'):
if hasattr(target, 'multiply_indirect'):
#and target.multiply_indirect):
#del target.multiply_indirect
@@ -237,21 +241,23 @@
del target.multiply_indirect
if reftarget.hasattr('refuri'):
target['refuri'] = reftarget['refuri']
- if target.hasattr('name'):
+ if target['names']:
self.document.note_external_target(target)
+ if target.has_key('refid'):
+ del target['refid']
elif reftarget.hasattr('refid'):
target['refid'] = reftarget['refid']
self.document.note_refid(target)
else:
- try:
- target['refid'] = reftarget['id']
+ if reftarget['ids']:
+ target['refid'] = reftarget_id
self.document.note_refid(target)
- except KeyError:
+ else:
self.nonexistent_indirect_target(target)
return
- del target['refname']
+ if refname is not None:
+ del target['refname']
target.resolved = 1
- reftarget.referenced = 1
def nonexistent_indirect_target(self, target):
if self.document.nameids.has_key(target['refname']):
@@ -265,18 +271,19 @@
def indirect_target_error(self, target, explanation):
naming = ''
- if target.hasattr('name'):
- naming = '"%s" ' % target['name']
- reflist = self.document.refnames.get(target['name'], [])
- else:
- reflist = self.document.refids.get(target['id'], [])
- naming += '(id="%s")' % target['id']
+ reflist = []
+ if target['names']:
+ naming = '"%s" ' % target['names'][0]
+ for name in target['names']:
+ reflist.extend(self.document.refnames.get(name, []))
+ for id in target['ids']:
+ reflist.extend(self.document.refids.get(id, []))
+ naming += '(id="%s")' % target['ids'][0]
msg = self.document.reporter.error(
'Indirect hyperlink target %s refers to target "%s", %s.'
- % (naming, target['refname'], explanation),
- base_node=target)
+ % (naming, target['refname'], explanation), base_node=target)
msgid = self.document.set_id(msg)
- for ref in reflist:
+ for ref in uniq(reflist):
prb = nodes.problematic(
ref.rawsource, ref.rawsource, refid=msgid)
prbid = self.document.set_id(prb)
@@ -296,43 +303,34 @@
else:
return
attval = target[attname]
- if target.hasattr('name'):
- name = target['name']
- try:
- reflist = self.document.refnames[name]
- except KeyError, instance:
- if target.referenced:
- return
- msg = self.document.reporter.info(
- 'Indirect hyperlink target "%s" is not referenced.'
- % name, base_node=target)
- target.referenced = 1
- return
- delatt = 'refname'
- else:
- id = target['id']
- try:
- reflist = self.document.refids[id]
- except KeyError, instance:
- if target.referenced:
- return
- msg = self.document.reporter.info(
- 'Indirect hyperlink target id="%s" is not referenced.'
- % id, base_node=target)
- target.referenced = 1
- return
- delatt = 'refid'
- for ref in reflist:
- if ref.resolved:
- continue
- del ref[delatt]
- ref[attname] = attval
- if not call_if_named or ref.hasattr('name'):
- call_method(ref)
- ref.resolved = 1
- if isinstance(ref, nodes.target):
- self.resolve_indirect_references(ref)
- target.referenced = 1
+ for name in target['names']:
+ reflist = self.document.refnames.get(name, [])
+ if reflist:
+ target.note_referenced_by(name=name)
+ for ref in reflist:
+ if ref.resolved:
+ continue
+ del ref['refname']
+ ref[attname] = attval
+ if not call_if_named or ref['names']:
+ call_method(ref)
+ ref.resolved = 1
+ if isinstance(ref, nodes.target):
+ self.resolve_indirect_references(ref)
+ for id in target['ids']:
+ reflist = self.document.refids.get(id, [])
+ if reflist:
+ target.note_referenced_by(id=id)
+ for ref in reflist:
+ if ref.resolved:
+ continue
+ del ref['refid']
+ ref[attname] = attval
+ if not call_if_named or ref['names']:
+ call_method(ref)
+ ref.resolved = 1
+ if isinstance(ref, nodes.target):
+ self.resolve_indirect_references(ref)
class ExternalTargets(Transform):
@@ -357,74 +355,59 @@
def apply(self):
for target in self.document.external_targets:
- if target.hasattr('refuri') and target.hasattr('name'):
- name = target['name']
+ if target.hasattr('refuri'):
refuri = target['refuri']
- try:
- reflist = self.document.refnames[name]
- except KeyError, instance:
- # @@@ First clause correct???
- if not isinstance(target, nodes.target) or target.referenced:
- continue
- msg = self.document.reporter.info(
- 'External hyperlink target "%s" is not referenced.'
- % name, base_node=target)
- target.referenced = 1
- continue
- for ref in reflist:
- if ref.resolved:
- continue
- del ref['refname']
- ref['refuri'] = refuri
- ref.resolved = 1
- target.referenced = 1
+ for name in target['names']:
+ reflist = self.document.refnames.get(name, [])
+ if reflist:
+ target.note_referenced_by(name=name)
+ for ref in reflist:
+ if ref.resolved:
+ continue
+ del ref['refname']
+ ref['refuri'] = refuri
+ ref.resolved = 1
class InternalTargets(Transform):
- """
- Given::
+ default_priority = 660
- <paragraph>
- <reference refname="direct internal">
- direct internal
- <target id="id1" name="direct internal">
+ def apply(self):
+ for target in self.document.internal_targets:
+ self.resolve_reference_ids(target)
- The "refname" attribute is replaced by "refid" linking to the target's
- "id"::
+ def resolve_reference_ids(self, target):
+ """
+ Given::
- <paragraph>
- <reference refid="id1">
- direct internal
- <target id="id1" name="direct internal">
- """
+ <paragraph>
+ <reference refname="direct internal">
+ direct internal
+ <target id="id1" name="direct internal">
- default_priority = 660
+ The "refname" attribute is replaced by "refid" linking to the target's
+ "id"::
- def apply(self):
- 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.document.refnames[name]
- except KeyError, instance:
- if target.referenced:
- continue
- msg = self.document.reporter.info(
- 'Internal hyperlink target "%s" is not referenced.'
- % name, base_node=target)
- target.referenced = 1
- continue
+ <paragraph>
+ <reference refid="id1">
+ direct internal
+ <target id="id1" name="direct internal">
+ """
+ if target.hasattr('refuri') or target.hasattr('refid') \
+ or not target['names']:
+ return
+ for name in target['names']:
+ refid = self.document.nameids[name]
+ reflist = self.document.refnames.get(name, [])
+ if reflist:
+ target.note_referenced_by(name=name)
for ref in reflist:
if ref.resolved:
continue
del ref['refname']
ref['refid'] = refid
ref.resolved = 1
- target.referenced = 1
class Footnotes(Transform):
@@ -532,19 +515,17 @@
if not self.document.nameids.has_key(label):
break
footnote.insert(0, nodes.label('', label))
- if footnote.hasattr('dupname'):
- continue
- if footnote.hasattr('name'):
- name = footnote['name']
+ for name in footnote['names']:
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'])
+ assert len(footnote['ids']) == len(ref['ids']) == 1
+ ref['refid'] = footnote['ids'][0]
+ footnote.add_backref(ref['ids'][0])
self.document.note_refid(ref)
ref.resolved = 1
- else:
- footnote['name'] = label
+ if not footnote['names'] and not footnote['dupnames']:
+ footnote['names'].append(label)
self.document.note_explicit_target(footnote, footnote)
self.autofootnote_labels.append(label)
return startnum
@@ -577,7 +558,8 @@
footnote = self.document.ids[id]
ref['refid'] = id
self.document.note_refid(ref)
- footnote.add_backref(ref['id'])
+ assert len(ref['ids']) == 1
+ footnote.add_backref(ref['ids'][0])
ref.resolved = 1
i += 1
@@ -612,9 +594,10 @@
ref.parent.replace(ref, prb)
break
footnote = self.document.symbol_footnotes[i]
- ref['refid'] = footnote['id']
+ assert len(footnote['ids']) == 1
+ ref['refid'] = footnote['ids'][0]
self.document.note_refid(ref)
- footnote.add_backref(ref['id'])
+ footnote.add_backref(ref['ids'][0])
i += 1
def resolve_footnotes_and_citations(self):
@@ -623,24 +606,26 @@
references.
"""
for footnote in self.document.footnotes:
- label = footnote['name']
- if self.document.footnote_refs.has_key(label):
- reflist = self.document.footnote_refs[label]
- self.resolve_references(footnote, reflist)
+ for label in footnote['names']:
+ if self.document.footnote_refs.has_key(label):
+ reflist = self.document.footnote_refs[label]
+ self.resolve_references(footnote, reflist)
for citation in self.document.citations:
- label = citation['name']
- if self.document.citation_refs.has_key(label):
- reflist = self.document.citation_refs[label]
- self.resolve_references(citation, reflist)
+ for label in citation['names']:
+ 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):
- id = note['id']
+ assert len(note['ids']) == 1
+ id = note['ids'][0]
for ref in reflist:
if ref.resolved:
continue
ref.delattr('refname')
ref['refid'] = id
- note.add_backref(ref['id'])
+ assert len(ref['ids']) == 1
+ note.add_backref(ref['ids'][0])
ref.resolved = 1
note.resolved = 1
@@ -680,7 +665,9 @@
def apply(self):
defs = self.document.substitution_defs
normed = self.document.substitution_names
- for refname, refs in self.document.substitution_refs.items():
+ subreflist = self.document.substitution_refs.items()
+ subreflist.sort()
+ for refname, refs in subreflist:
for ref in refs:
key = None
if defs.has_key(refname):
@@ -715,7 +702,7 @@
and isinstance(parent[index + 1], nodes.Text)):
parent.replace(parent[index + 1],
parent[index + 1].lstrip())
- parent.replace(ref, subdef.get_children())
+ parent.replace(ref, subdef.children)
self.document.substitution_refs = None # release replaced references
@@ -734,11 +721,12 @@
notes = {}
nodelist = []
for target in self.document.external_targets:
- name = target.get('name')
- if not name:
- print >>sys.stderr, 'no name on target: %r' % target
- continue
- refs = self.document.refnames.get(name, [])
+ names = target['names']
+ # Only named targets.
+ assert names
+ refs = []
+ for name in names:
+ refs.extend(self.document.refnames.get(name, []))
if not refs:
continue
footnote = self.make_target_footnote(target, refs, notes)
@@ -760,14 +748,16 @@
refuri = target['refuri']
if notes.has_key(refuri): # duplicate?
footnote = notes[refuri]
- footnote_name = footnote['name']
+ assert len(footnote['names']) == 1
+ footnote_name = footnote['names'][0]
else: # original
footnote = nodes.footnote()
footnote_id = self.document.set_id(footnote)
- # Use a colon; they can't be produced inside names by the parser:
- footnote_name = 'target_note: ' + footnote_id
+ # Use uppercase letters and a colon; they can't be
+ # produced inside names by the parser.
+ footnote_name = 'TARGET_NOTE: ' + footnote_id
footnote['auto'] = 1
- footnote['name'] = footnote_name
+ footnote['names'] = [footnote_name]
footnote_paragraph = nodes.paragraph()
footnote_paragraph += nodes.reference('', refuri, refuri=refuri)
footnote += footnote_paragraph
@@ -786,3 +776,11 @@
reflist.insert(0, nodes.Text(' '))
ref.parent.insert(index, reflist)
return footnote
+
+
+def uniq(L):
+ r = []
+ for item in L:
+ if not item in r:
+ r.append(item)
+ return r
=== Zope/lib/python/docutils/transforms/universal.py 1.2.10.6 => 1.2.10.7 ===
--- Zope/lib/python/docutils/transforms/universal.py:1.2.10.6 Fri Jan 7 08:26:06 2005
+++ Zope/lib/python/docutils/transforms/universal.py Sun Oct 9 10:43:46 2005
@@ -32,19 +32,16 @@
default_priority = 820
def apply(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]
+ header_nodes = self.generate_header()
+ if header_nodes:
+ decoration = self.document.get_decoration()
+ header = decoration.get_header()
+ header.extend(header_nodes)
+ footer_nodes = self.generate_footer()
+ if footer_nodes:
+ decoration = self.document.get_decoration()
+ footer = decoration.get_footer()
+ footer.extend(footer_nodes)
def generate_header(self):
return None
@@ -79,9 +76,7 @@
nodes.reference('', 'reStructuredText', refuri='http://'
'docutils.sourceforge.net/rst.html'),
nodes.Text(' source.\n')])
- footer = nodes.footer()
- footer += nodes.paragraph('', '', *text)
- return footer
+ return [nodes.paragraph('', '', *text)]
else:
return None
@@ -97,13 +92,13 @@
def apply(self):
unfiltered = self.document.transform_messages
- threshold = self.document.reporter['writer'].report_level
+ threshold = self.document.reporter.report_level
messages = []
for msg in unfiltered:
if msg['level'] >= threshold and not msg.parent:
messages.append(msg)
if messages:
- section = nodes.section(CLASS='system-messages')
+ section = nodes.section(classes=['system-messages'])
# @@@ get this from the language module?
section += nodes.title('', 'Docutils System Messages')
section += messages
@@ -130,7 +125,7 @@
pass
def visit_system_message(self, node):
- if node['level'] < self.document.reporter['writer'].report_level:
+ if node['level'] < self.document.reporter.report_level:
node.parent.remove(node)
@@ -167,6 +162,21 @@
if self.document.settings.expose_internals:
visitor = InternalAttributeExposer(self.document)
self.document.walk(visitor)
+ # *After* resolving all references, check for unreferenced
+ # targets:
+ for target in self.document.traverse():
+ if isinstance(target, nodes.target) and not target.referenced:
+ if target['names']:
+ naming = target['names'][0]
+ elif target['ids']:
+ naming = target['ids'][0]
+ else:
+ # Hack: Propagated targets always have their refid
+ # attribute set.
+ naming = target['refid']
+ self.document.reporter.info(
+ 'Hyperlink target "%s" is not referenced.'
+ % naming, base_node=target)
class FinalCheckVisitor(nodes.SparseNodeVisitor):
@@ -206,7 +216,7 @@
else:
del node['refname']
node['refid'] = id
- self.document.ids[id].referenced = 1
+ self.document.ids[id].note_referenced_by(id=id)
node.resolved = 1
visit_footnote_reference = visit_citation_reference = visit_reference
More information about the Zope-Checkins
mailing list