# HG changeset patch # User cmlenz # Date 1161011753 0 # Node ID 6e6950ac0e56d40a762b2cf20c0670c528cc2070 # Parent 748f2294bbee305511a11232fff7612d55687563 Various performance-oriented tweaks. diff --git a/genshi/filters.py b/genshi/filters.py --- 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: diff --git a/genshi/output.py b/genshi/output.py --- 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: diff --git a/genshi/path.py b/genshi/path.py --- 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('') >>> 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: diff --git a/genshi/template.py b/genshi/template.py --- 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):