# HG changeset patch # User cmlenz # Date 1188241460 0 # Node ID bc5faca936992cb6bbb94e77451f21c7b4154d56 # Parent 6d1fa718794fc00a70182fce7e2261b8484ca596 Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,9 @@ which can speed up match templates in many cases, for example when a match template should only be applied once to a stream, or when it should not be applied recursively. + * Text templates now default to rendering as plain text; it is no longer + necessary to explicitly specify the "text" method to the `render()` or + `serialize()` method of the generated markup stream. Version 0.4.4 diff --git a/doc/templates.txt b/doc/templates.txt --- a/doc/templates.txt +++ b/doc/templates.txt @@ -129,7 +129,7 @@ >>> from genshi.template import TextTemplate >>> tmpl = TextTemplate('Hello, $name!') >>> stream = tmpl.generate(name='world') - >>> print stream.render('text') + >>> print stream Hello, world! .. note:: If you want to use text templates, you should consider using the diff --git a/genshi/core.py b/genshi/core.py --- a/genshi/core.py +++ b/genshi/core.py @@ -51,7 +51,7 @@ returns the complete generated text at once. Both accept various parameters that impact the way the stream is serialized. """ - __slots__ = ['events'] + __slots__ = ['events', 'serializer'] START = StreamEventKind('START') #: a start tag END = StreamEventKind('END') #: an end tag @@ -65,12 +65,17 @@ PI = StreamEventKind('PI') #: processing instruction COMMENT = StreamEventKind('COMMENT') #: comment - def __init__(self, events): + def __init__(self, events, serializer=None): """Initialize the stream with a sequence of markup events. :param events: a sequence or iterable providing the events + :param serializer: the default serialization method to use for this + stream + + :note: Changed in 0.5: added the `serializer` argument """ self.events = events #: The underlying iterable producing the events + self.serializer = serializer #: The default serializion method def __iter__(self): return iter(self.events) @@ -119,7 +124,7 @@ :return: the filtered stream :rtype: `Stream` """ - return Stream(_ensure(function(self))) + return Stream(_ensure(function(self)), serializer=self.serializer) def filter(self, *filters): """Apply filters to the stream. @@ -143,7 +148,7 @@ """ return reduce(operator.or_, (self,) + filters) - def render(self, method='xml', encoding='utf-8', **kwargs): + def render(self, method=None, encoding='utf-8', **kwargs): """Return a string representation of the stream. Any additional keyword arguments are passed to the serializer, and thus @@ -151,7 +156,8 @@ :param method: determines how the stream is serialized; can be either "xml", "xhtml", "html", "text", or a custom serializer - class + class; if `None`, the default serialization method of + the stream is used :param encoding: how the output string should be encoded; if set to `None`, this method returns a `unicode` object :return: a `str` or `unicode` object @@ -159,6 +165,8 @@ :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer """ from genshi.output import encode + if method is None: + method = self.serializer or 'xml' generator = self.serialize(method=method, **kwargs) return encode(generator, method=method, encoding=encoding) @@ -211,13 +219,16 @@ :param method: determines how the stream is serialized; can be either "xml", "xhtml", "html", "text", or a custom serializer - class + class; if `None`, the default serialization method of + the stream is used :return: an iterator over the serialization results (`Markup` or `unicode` objects, depending on the serialization method) :rtype: ``iterator`` :see: XMLSerializer, XHTMLSerializer, HTMLSerializer, TextSerializer """ from genshi.output import get_serializer + if method is None: + method = self.serializer or 'xml' return get_serializer(method, **kwargs)(_ensure(self)) def __str__(self): diff --git a/genshi/filters/transform.py b/genshi/filters/transform.py --- a/genshi/filters/transform.py +++ b/genshi/filters/transform.py @@ -160,7 +160,8 @@ transforms = self._mark(stream) for link in self.transforms: transforms = link(transforms) - return Stream(self._unmark(transforms)) + return Stream(self._unmark(transforms), + serializer=getattr(stream, 'serializer', None)) def apply(self, function): """Apply a transformation to the stream. diff --git a/genshi/path.py b/genshi/path.py --- a/genshi/path.py +++ b/genshi/path.py @@ -147,7 +147,8 @@ updateonly=True) elif result: yield result - return Stream(_generate()) + return Stream(_generate(), + serializer=getattr(stream, 'serializer', None)) def test(self, ignore_context=False): """Returns a function that can be used to track whether the path matches diff --git a/genshi/template/base.py b/genshi/template/base.py --- a/genshi/template/base.py +++ b/genshi/template/base.py @@ -289,6 +289,8 @@ directives should be applied. """ + serializer = None + def __init__(self, source, basedir=None, filename=None, loader=None, encoding=None, lookup='lenient', allow_exec=True): """Initialize a template from either a string, a file-like object, or @@ -423,7 +425,7 @@ stream = self.stream for filter_ in self.filters: stream = filter_(iter(stream), ctxt) - return Stream(stream) + return Stream(stream, self.serializer) def _eval(self, stream, ctxt): """Internal stream filter that evaluates any expressions in `START` and diff --git a/genshi/template/markup.py b/genshi/template/markup.py --- a/genshi/template/markup.py +++ b/genshi/template/markup.py @@ -64,6 +64,7 @@ ('content', ContentDirective), ('attrs', AttrsDirective), ('strip', StripDirective)] + serializer = 'xml' def __init__(self, source, basedir=None, filename=None, loader=None, encoding=None, lookup='lenient', allow_exec=True): diff --git a/genshi/template/tests/directives.py b/genshi/template/tests/directives.py --- a/genshi/template/tests/directives.py +++ b/genshi/template/tests/directives.py @@ -382,6 +382,7 @@ """) self.assertEqual(""" Hi, you! + """, str(tmpl.generate())) def test_function_with_star_args(self): diff --git a/genshi/template/tests/text.py b/genshi/template/tests/text.py --- a/genshi/template/tests/text.py +++ b/genshi/template/tests/text.py @@ -70,7 +70,7 @@ * 0 * 1 * 2 -""", tmpl.generate(items=range(3)).render('text')) +""", tmpl.generate(items=range(3)).render()) def test_empty_lines2(self): tmpl = OldTextTemplate("""Your items: @@ -87,7 +87,7 @@ * 2 -""", tmpl.generate(items=range(3)).render('text')) +""", tmpl.generate(items=range(3)).render()) def test_include(self): file1 = open(os.path.join(self.dirname, 'tmpl1.txt'), 'w') @@ -161,7 +161,7 @@ * 0 * 1 * 2 -""", tmpl.generate(items=range(3)).render('text')) +""", tmpl.generate(items=range(3)).render()) def test_empty_lines2(self): tmpl = NewTextTemplate("""Your items: @@ -178,12 +178,12 @@ * 2 -""", tmpl.generate(items=range(3)).render('text')) +""", tmpl.generate(items=range(3)).render()) def test_include(self): file1 = open(os.path.join(self.dirname, 'tmpl1.txt'), 'w') try: - file1.write("Included\n") + file1.write("Included") finally: file1.close() diff --git a/genshi/template/text.py b/genshi/template/text.py --- a/genshi/template/text.py +++ b/genshi/template/text.py @@ -58,7 +58,7 @@ ... * ${'Item %d' % item} ... {% end %} ... ''') - >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render('text') + >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render() Dear Joe, @@ -83,7 +83,7 @@ ... * $item ... {% end %}\ ... ''') - >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render('text') + >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render() Dear Joe, We have the following items for you: @@ -103,7 +103,7 @@ ... * $item ... {% end %}\ ... ''') - >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render('text') + >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render() Dear Joe, {# This is a comment #} @@ -122,6 +122,7 @@ ('if', IfDirective), ('choose', ChooseDirective), ('with', WithDirective)] + serializer = 'text' _DIRECTIVE_RE = r'((?>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render('text') + >>> print tmpl.generate(name='Joe', items=[1, 2, 3]).render() Dear Joe, We have the following items for you: @@ -245,6 +246,7 @@ ('if', IfDirective), ('choose', ChooseDirective), ('with', WithDirective)] + serializer = 'text' _DIRECTIVE_RE = re.compile(r'(?:^[ \t]*(?