From: Guenter M. <mi...@us...> - 2017-02-28 11:08:06
|
Dear David, On 2017-02-17, Guenter Milde wrote: > On 2017-02-14, David Goodger wrote: >> On Tue, Feb 14, 2017 at 7:19 AM, Guenter Milde <mi...@us...> wrote: ... >>>> Attached is context_check.py, which I propose adding to >>>> _html_base.py. > Actually, a context stack is not only used in _html_base, but also for > LaTeX, and Man writers. > If adding a context_check() method, why not do this (and the context > stack setup) in nodes.py? > We could even consider a stack-level check with every visit/depart call > there. Then, every unbalanced stack use could be localized without the > need to change client code. I tried this, but it resulted in numerous false positives of the kind (ERROR/3) Stack size inconsistent: 1 before visiting node "title", 0 after departure. (ERROR/3) Stack size inconsistent: 1 before visiting node "footer", 0 after departure. (ERROR/3) Stack size inconsistent: 1 before visiting node "decoration", 0 after departure. (ERROR/3) Stack size inconsistent: 1 before visiting node "title", 0 after departure. I am not sure where my error is: a) in the assumption that after a depart* call the stack should always be at the same level as before the corresponding visit* call, b) somewhere in the implementation. Günter Exec: svn 'diff' 'writers/_html_base.py' 'nodes.py' 2>&1 Dir: docutils/docutils Index: writers/_html_base.py =================================================================== --- writers/_html_base.py (Revision 8037) +++ writers/_html_base.py (Arbeitskopie) @@ -93,7 +93,7 @@ self.parts[part] = ''.join(getattr(self, part)) -class HTMLTranslator(nodes.NodeVisitor): +class HTMLTranslator(nodes.ContextNodeVisitor): """Generic Docutils to HTML translator. See the `html4css1` and `html5_polyglot` writers for full featured @@ -182,7 +182,7 @@ def __init__(self, document): - nodes.NodeVisitor.__init__(self, document) + nodes.ContextNodeVisitor.__init__(self, document) self.settings = settings = document.settings lcode = settings.language_code self.language = languages.get_language(lcode, document.reporter) @@ -213,7 +213,7 @@ self.math_output_options = self.math_output[1:] self.math_output = self.math_output[0].lower() - self.context = [] + # self.context = [] """Heterogeneous stack. Used by visit_* and depart_* functions in conjunction with the tree Index: nodes.py =================================================================== --- nodes.py (Revision 8037) +++ nodes.py (Arbeitskopie) @@ -1929,6 +1929,44 @@ """ +class ContextNodeVisitor(NodeVisitor): + + """ + Base class for traversals, where visit methods may store some information + in a heterogeneous "context" stack. + + See `_html_base.HTMLTranslator` for a usage example. + """ + + + def __init__(self, document): + NodeVisitor.__init__(self, document) + self.context = [] + """Heterogeneous stack. + + Used by visit_* and depart_* functions in conjunction with the tree + traversal. Make sure that the pops correspond to the pushes.""" + # Store the stack-size befor/after visit/depart calls. + # Used to check balanced use of the "context" stack. + self._stack_size_before = 0 + + + def dispatch_visit(self, node): + """Variant of dispatch_visit with context lenght check.""" + self._stack_size_before = len(self.context) + NodeVisitor.dispatch_visit(self, node) + + def dispatch_departure(self, node): + """Variant of dispatch_departure with context lenght check.""" + + result = NodeVisitor.dispatch_departure(self, node) + if self._stack_size_before != len(self.context): + self.document.reporter.error('Stack size inconsistent: ' + '%i before visiting node "%s", %i after departure.' + % (self._stack_size_before, node.__class__.__name__, + len(self.context))) + return result + class GenericNodeVisitor(NodeVisitor): """ |