From: <bl...@us...> - 2006-06-28 16:28:06
|
Author: blais Date: 2006-06-28 18:27:55 +0200 (Wed, 28 Jun 2006) New Revision: 4641 Added: trunk/docutils/test/test_traversals.py Modified: trunk/docutils/docutils/nodes.py Log: Added StopTraversal exception in nodes, to interrupt the traversal cleanly. I needed this for my Nabu presentation layer, in order to be able to render just the first portion of my blog entries. Modified: trunk/docutils/docutils/nodes.py =================================================================== --- trunk/docutils/docutils/nodes.py 2006-06-27 13:18:32 UTC (rev 4640) +++ trunk/docutils/docutils/nodes.py 2006-06-28 16:27:55 UTC (rev 4641) @@ -113,22 +113,31 @@ Parameter `visitor`: A `NodeVisitor` object, containing a ``visit`` implementation for each `Node` subclass encountered. + + Return true if we should stop the traversal. """ + stop = 0 visitor.document.reporter.debug( '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.children - try: - for child in children[:]: - child.walk(visitor) - except SkipSiblings: - pass + try: + visitor.dispatch_visit(self) + except (SkipChildren, SkipNode): + return stop + except SkipDeparture: # not applicable; ignore + pass + children = self.children + try: + for child in children[:]: + if child.walk(visitor): + stop = 1 + break + except SkipSiblings: + pass + except StopTraversal: + stop = 1 + return stop def walkabout(self, visitor): """ @@ -139,8 +148,11 @@ Parameter `visitor`: A `NodeVisitor` object, containing a ``visit`` and ``depart`` implementation for each `Node` subclass encountered. + + Return true if we should stop the traversal. """ call_depart = 1 + stop = 0 visitor.document.reporter.debug( 'docutils.nodes.Node.walkabout calling dispatch_visit for %s' % self.__class__.__name__) @@ -148,22 +160,27 @@ try: visitor.dispatch_visit(self) except SkipNode: - return + return stop except SkipDeparture: call_depart = 0 children = self.children try: for child in children[:]: - child.walkabout(visitor) + if child.walkabout(visitor): + stop = 1 + break except SkipSiblings: pass except SkipChildren: pass + except StopTraversal: + stop = 1 if call_depart: visitor.document.reporter.debug( 'docutils.nodes.Node.walkabout calling dispatch_departure ' 'for %s' % self.__class__.__name__) visitor.dispatch_departure(self) + return stop def traverse(self, condition=None, include_self=1, descend=1, siblings=0, ascend=0): @@ -1692,6 +1709,19 @@ pass +class StopTraversal(TreePruningException): + + """ + Stop the traversal alltogether. The current node's ``depart_...`` method + is not affected. The parent nodes ``depart_...`` methods are also called + as usual. No other nodes are visited. This is an alternative to + NodeFound that does not cause exception handling to trickle up to the + caller. + """ + + pass + + def make_id(string): """ Convert `string` into an identifier and return it. Added: trunk/docutils/test/test_traversals.py =================================================================== --- trunk/docutils/test/test_traversals.py 2006-06-27 13:18:32 UTC (rev 4640) +++ trunk/docutils/test/test_traversals.py 2006-06-28 16:27:55 UTC (rev 4641) @@ -0,0 +1,75 @@ +#! /usr/bin/env python + +# $Id$ +# Author: Martin Blais <bl...@fu...> +# Copyright: This module has been placed in the public domain. + +""" +Test module for traversals. +""" + +import unittest +import DocutilsTestSupport # must be imported before docutils +from docutils import nodes, core, io, utils, writers +from docutils.writers.null import Writer as NullWriter +import docutils + + + +stop_traversal_input = ''' +================== + Train Travel +================== + +Happily, happily going by train. + +.. attention:: Attention, attention. This is a public annoucement. + You must get off the train now. + +KaZoom! Train crashes. + +- Told ya!!! Get off the train next time. + +''' + +class AttentiveVisitor(nodes.SparseNodeVisitor): + + def visit_attention(self, node): + raise nodes.StopTraversal + + def visit_bullet_list(self, node): + raise RuntimeError("It's too late for attention, " + "more discipline is needed!.") + +class AttentiveWriter(writers.Writer): + + def translate(self): + self.visitor = visitor = AttentiveVisitor(self.document) + + # Test both kinds of traversals. + self.document.walkabout(visitor) + self.document.walk(visitor) + +class StopTraversalTests(unittest.TestCase, docutils.SettingsSpec): + """ + Test interrupting the visitor during traversal. In this test we stop it + when we reach an attention node. + """ + def test_stop_traversal(self): + # Load some document tree in memory. + doctree = docutils.core.publish_doctree( + source=stop_traversal_input, + reader_name='standalone', + parser_name='restructuredtext', + settings_spec=self) + self.assert_(isinstance(doctree, nodes.document)) + + parts = docutils.core.publish_parts( + reader_name='doctree', source_class=docutils.io.DocTreeInput, + source=doctree, source_path='test', + writer=AttentiveWriter()) + + +if __name__ == '__main__': + unittest.main() + Property changes on: trunk/docutils/test/test_traversals.py ___________________________________________________________________ Name: svn:executable + * Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native |