changeset 305:60111a041e7c trunk

Various performance-oriented tweaks.
author cmlenz
date Mon, 16 Oct 2006 15:15:53 +0000
parents b2fdaff8c385
children 095a754f95a8
files genshi/filters.py genshi/output.py genshi/path.py genshi/template.py
diffstat 4 files changed, 59 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/genshi/filters.py
+++ b/genshi/filters.py
@@ -305,10 +305,10 @@
         """
         from genshi.template import TemplateError, TemplateNotFound
 
+        namespace = self.NAMESPACE
         ns_prefixes = []
         in_fallback = False
-        include_href, fallback_stream = None, None
-        namespace = self.NAMESPACE
+        include_href = fallback_stream = None
 
         for kind, data, pos in stream:
 
--- a/genshi/output.py
+++ b/genshi/output.py
@@ -315,7 +315,7 @@
         super(HTMLSerializer, self).__init__(doctype, False)
         if strip_whitespace:
             self.filters.append(WhitespaceFilter(self._PRESERVE_SPACE,
-                                                 self._NOESCAPE_ELEMS, True))
+                                                 self._NOESCAPE_ELEMS))
 
     def __call__(self, stream):
         namespace = self.NAMESPACE
@@ -453,7 +453,7 @@
     """A filter that removes extraneous ignorable white space from the
     stream."""
 
-    def __init__(self, preserve=None, noescape=None, escape_cdata=False):
+    def __init__(self, preserve=None, noescape=None):
         """Initialize the filter.
         
         @param preserve: a set or sequence of tag names for which white-space
@@ -470,7 +470,6 @@
         if noescape is None:
             noescape = []
         self.noescape = frozenset(noescape)
-        self.escape_cdata = escape_cdata
 
     def __call__(self, stream, ctxt=None, space=XML_NAMESPACE['space'],
                  trim_trailing_space=re.compile('[ \t]+(?=\n)').sub,
@@ -480,7 +479,6 @@
         preserve = False
         noescape_elems = self.noescape
         noescape = False
-        escape_cdata = self.escape_cdata
 
         textbuf = []
         push_text = textbuf.append
@@ -512,10 +510,10 @@
                 elif kind is END:
                     preserve = noescape = False
 
-                elif kind is START_CDATA and not escape_cdata:
+                elif kind is START_CDATA:
                     noescape = True
 
-                elif kind is END_CDATA and not escape_cdata:
+                elif kind is END_CDATA:
                     noescape = False
 
                 if kind:
--- a/genshi/path.py
+++ b/genshi/path.py
@@ -117,19 +117,19 @@
         stream = iter(stream)
         def _generate():
             test = self.test()
-            for kind, data, pos in stream:
-                result = test(kind, data, pos, namespaces, variables)
+            for event in stream:
+                result = test(event, namespaces, variables)
                 if result is True:
-                    yield kind, data, pos
+                    yield event
                     depth = 1
                     while depth > 0:
-                        subkind, subdata, subpos = stream.next()
-                        if subkind is START:
+                        subevent = stream.next()
+                        if subevent[0] is START:
                             depth += 1
-                        elif subkind is END:
+                        elif subevent[0] is END:
                             depth -= 1
-                        yield subkind, subdata, subpos
-                        test(subkind, subdata, subpos, namespaces, variables)
+                        yield subevent
+                        test(subevent, namespaces, variables)
                 elif result:
                     yield result
         return Stream(_generate())
@@ -138,10 +138,10 @@
         """Returns a function that can be used to track whether the path matches
         a specific stream event.
         
-        The function returned expects the positional arguments `kind`, `data`,
-        `pos` (basically an unpacked stream event), as well as `namespaces`
-        and `variables`. The latter two are a mapping of namespace prefixes to
-        URIs, and a mapping of variable names to values, respectively.
+        The function returned expects the positional arguments `event`,
+        `namespaces` and `variables`. The first is a stream event, while the
+        latter two are a mapping of namespace prefixes to URIs, and a mapping
+        of variable names to values, respectively.
         
         If the path matches the event, the function returns the match (for
         example, a `START` or `TEXT` event.) Otherwise, it returns `None`.
@@ -149,14 +149,15 @@
         >>> from genshi.input import XML
         >>> xml = XML('<root><elem><child id="1"/></elem><child id="2"/></root>')
         >>> test = Path('child').test()
-        >>> for kind, data, pos in xml:
-        ...     if test(kind, data, pos, {}, {}):
-        ...         print kind, data
-        START (u'child', [(u'id', u'2')])
+        >>> for event in xml:
+        ...     if test(event, {}, {}):
+        ...         print event
+        ('START', (u'child', [(u'id', u'2')]), (None, 1, 34))
         """
         paths = [(p, len(p), [0], [], [0] * len(p)) for p in self.paths]
 
-        def _test(kind, data, pos, namespaces, variables):
+        def _test(event, namespaces, variables):
+            kind, data, pos = event
             retval = None
             for steps, size, cursors, cutoff, counter in paths:
 
--- a/genshi/template.py
+++ b/genshi/template.py
@@ -302,15 +302,12 @@
 
     def __call__(self, stream, ctxt, directives):
         def _generate():
-            kind, data, pos = stream.next()
-            if kind is START:
-                yield kind, data, pos # emit start tag
-            yield EXPR, self.expr, pos
-            previous = stream.next()
-            for event in stream:
-                previous = event
-            if previous is not None:
-                yield previous
+            yield stream.next()
+            yield EXPR, self.expr, (None, -1, -1)
+            event = stream.next()
+            for next in stream:
+                event = next
+            yield event
 
         return _apply_directives(_generate(), ctxt, directives)
 
@@ -552,8 +549,7 @@
     __slots__ = []
 
     def __call__(self, stream, ctxt, directives):
-        kind, data, pos = stream.next()
-        yield EXPR, self.expr, pos
+        yield EXPR, self.expr, (None, -1, -1)
 
 
 class StripDirective(Directive):
@@ -929,44 +925,36 @@
 
             elif kind is EXPR:
                 result = data.evaluate(ctxt)
-                if result is None:
-                    continue
-
-                # First check for a string, otherwise the iterable test below
-                # succeeds, and the string will be chopped up into individual
-                # characters
-                if isinstance(result, basestring):
-                    yield TEXT, result, pos
-                else:
-                    # Test if the expression evaluated to an iterable, in which
-                    # case we yield the individual items
-                    try:
-                        substream = _ensure(iter(result))
-                    except TypeError:
-                        # Neither a string nor an iterable, so just pass it
-                        # through
-                        yield TEXT, unicode(result), pos
-                    else:
+                if result is not None:
+                    # First check for a string, otherwise the iterable test below
+                    # succeeds, and the string will be chopped up into individual
+                    # characters
+                    if isinstance(result, basestring):
+                        yield TEXT, result, pos
+                    elif hasattr(result, '__iter__'):
+                        substream = _ensure(result)
                         for filter_ in filters:
                             substream = filter_(substream, ctxt)
                         for event in substream:
                             yield event
+                    else:
+                        yield TEXT, unicode(result), pos
 
             else:
                 yield kind, data, pos
 
     def _flatten(self, stream, ctxt):
         """Internal stream filter that expands `SUB` events in the stream."""
-        for kind, data, pos in stream:
-            if kind is SUB:
+        for event in stream:
+            if event[0] is SUB:
                 # This event is a list of directives and a list of nested
                 # events to which those directives should be applied
-                directives, substream = data
+                directives, substream = event[1]
                 substream = _apply_directives(substream, ctxt, directives)
                 for event in self._flatten(substream, ctxt):
                     yield event
             else:
-                yield kind, data, pos
+                yield event
 
 
 EXPR = Template.EXPR
@@ -1113,47 +1101,46 @@
         def _strip(stream):
             depth = 1
             while 1:
-                kind, data, pos = stream.next()
-                if kind is START:
+                event = stream.next()
+                if event[0] is START:
                     depth += 1
-                elif kind is END:
+                elif event[0] is END:
                     depth -= 1
                 if depth > 0:
-                    yield kind, data, pos
+                    yield event
                 else:
-                    tail[:] = [(kind, data, pos)]
+                    tail[:] = [event]
                     break
 
-        for kind, data, pos in stream:
+        for event in stream:
 
             # We (currently) only care about start and end events for matching
             # We might care about namespace events in the future, though
-            if not match_templates or kind not in (START, END):
-                yield kind, data, pos
+            if not match_templates or (event[0] is not START and
+                                       event[0] is not END):
+                yield event
                 continue
 
             for idx, (test, path, template, namespaces, directives) in \
                     enumerate(match_templates):
 
-                if test(kind, data, pos, namespaces, ctxt) is True:
+                if test(event, namespaces, ctxt) is True:
 
                     # Let the remaining match templates know about the event so
                     # they get a chance to update their internal state
                     for test in [mt[0] for mt in match_templates[idx + 1:]]:
-                        test(kind, data, pos, namespaces, ctxt)
+                        test(event, namespaces, ctxt)
 
                     # Consume and store all events until an end event
                     # corresponding to this start event is encountered
-                    content = chain([(kind, data, pos)],
-                                    self._match(_strip(stream), ctxt),
+                    content = chain([event], self._match(_strip(stream), ctxt),
                                     tail)
                     for filter_ in self.filters[3:]:
                         content = filter_(content, ctxt)
                     content = list(content)
 
-                    kind, data, pos = tail[0]
                     for test in [mt[0] for mt in match_templates]:
-                        test(kind, data, pos, namespaces, ctxt)
+                        test(tail[0], namespaces, ctxt)
 
                     # Make the select() function available in the body of the
                     # match template
@@ -1174,7 +1161,7 @@
                     break
 
             else: # no matches
-                yield kind, data, pos
+                yield event
 
 
 class TextTemplate(Template):
Copyright (C) 2012-2017 Edgewall Software