Mercurial > genshi > mirror
diff genshi/core.py @ 958:6fc92535c888 experimental-performance-improvement-exploration
Be more careful about what is passed into streams as events and remove many uses of _ensure as a result. An ATTRS event is added for handling Attributes returned by gensh.path.select().
author | hodgestar |
---|---|
date | Tue, 13 Mar 2012 03:03:02 +0000 |
parents | 417787b9b9a7 |
children |
line wrap: on
line diff
--- a/genshi/core.py +++ b/genshi/core.py @@ -107,7 +107,7 @@ Filters can be any function that accepts and produces a stream (where a stream is anything that iterates over events): - + >>> def uppercase(stream): ... for kind, data, pos in stream: ... if kind is TEXT: @@ -130,7 +130,13 @@ :return: the filtered stream :rtype: `Stream` """ - return Stream(_ensure(function(self)), serializer=self.serializer) + # TODO: this is horribly slow because is has to guess whether + # the function passed in is something that produces stream + # events or something that produces a sequence of strings. + # Sequences of strings are converted back to a sequence of + # stream events (and then back to text when rendered). + events = _possible_text_iterator_to_stream(function(self)) + return Stream(events, serializer=self.serializer) def filter(self, *filters): """Apply filters to the stream. @@ -242,7 +248,7 @@ from genshi.output import get_serializer if method is None: method = self.serializer or 'xml' - return get_serializer(method, **kwargs)(_ensure(self)) + return get_serializer(method, **kwargs)(self) def __str__(self): return self.render() @@ -267,26 +273,30 @@ COMMENT = Stream.COMMENT -def _ensure(stream): - """Ensure that every item on the stream is actually a markup event.""" - stream = iter(stream) - event = stream.next() +def _text_event(text): + return (TEXT, unicode(text), (None, -1, -1)) + + +def _text_to_stream(text): + yield _text_event(text) + + +def _possible_text_iterator_to_stream(textiter_or_stream): + it = iter(textiter_or_stream) + event = it.next() # Check whether the iterable is a real markup event stream by examining the # first item it yields; if it's not we'll need to do some conversion - if type(event) is not tuple or len(event) != 3: - for event in chain([event], stream): - if hasattr(event, 'totuple'): - event = event.totuple() - else: - event = TEXT, unicode(event), (None, -1, -1) - yield event + if type(event) is not tuple: + yield TEXT, unicode(event), (None, -1, -1) + for event in it: + yield TEXT, unicode(event), (None, -1, -1) return # This looks like a markup event stream, so we'll just pass it through # unchanged yield event - for event in stream: + for event in it: yield event @@ -344,6 +354,8 @@ """ __slots__ = [] + ATTRS = StreamEventKind('ATTRS') + def __contains__(self, name): """Return whether the list includes an attribute with the specified name. @@ -427,19 +439,33 @@ return value return default - def totuple(self): + def toevent(self): """Return the attributes as a markup event. - The returned event is a `TEXT` event, the data is the value of all - attributes joined together. + The returned event is an `ATTRS` event, the data is the Attr object. + + >>> a = Attrs([('href', '#'), ('title', 'Foo')]) + >>> a.toevent() + ('ATTRS', Attrs([('href', '#'), ('title', 'Foo')]), (None, -1, -1)) - >>> Attrs([('href', '#'), ('title', 'Foo')]).totuple() - ('TEXT', '#Foo', (None, -1, -1)) - - :return: a `TEXT` event + :return: an `ATTR` event :rtype: `tuple` """ - return TEXT, ''.join([x[1] for x in self]), (None, -1, -1) + return self.ATTRS, self, (None, -1, -1) + + def concatenate_values(self): + """Return the values of the attributes concatenated into a string. + + >>> a = Attrs([('href', '#'), ('title', 'Foo')]) + >>> a.concatenate_values() + '#Foo' + + :return: the concatenated attribute values + :rtype: `str` + """ + return ''.join([x[1] for x in self]) + +ATTRS = Attrs.ATTRS class Markup(unicode):