Edgewall Software

source: tags/0.3.4/genshi/plugin.py

Last change on this file was 337, checked in by cmlenz, 17 years ago

Ported [330],[333], and [334] to 0.3.x stable branch.

  • Property svn:eol-style set to native
File size: 4.2 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2006 Edgewall Software
4# Copyright (C) 2006 Matthew Good
5# All rights reserved.
6#
7# This software is licensed as described in the file COPYING, which
8# you should have received as part of this distribution. The terms
9# are also available at http://genshi.edgewall.org/wiki/License.
10#
11# This software consists of voluntary contributions made by many
12# individuals. For the exact contribution history, see the revision
13# history and logs, available at http://genshi.edgewall.org/log/.
14
15"""Basic support for the template engine plugin API used by TurboGears and
16CherryPy/Buffet.
17"""
18
19from pkg_resources import resource_filename
20
21from genshi.core import Attrs, Stream, QName
22from genshi.eval import Undefined
23from genshi.input import HTML, XML
24from genshi.template import Context, MarkupTemplate, Template, TemplateLoader, \
25                            TextTemplate
26
27def ET(element):
28    """Converts the given ElementTree element to a markup stream."""
29    tag_name = element.tag
30    if tag_name.startswith('{'):
31        tag_name = tag_name[1:]
32    tag_name = QName(tag_name)
33    attrib = Attrs(element.items())
34
35    yield (Stream.START, (tag_name, attrib), (None, -1, -1))
36    if element.text:
37        yield Stream.TEXT, element.text, (None, -1, -1)
38    for child in element.getchildren():
39        for item in ET(child):
40            yield item
41    yield Stream.END, tag_name, (None, -1, -1)
42    if element.tail:
43        yield Stream.TEXT, element.tail, (None, -1, -1)
44
45
46class AbstractTemplateEnginePlugin(object):
47    """Implementation of the plugin API."""
48
49    template_class = None
50    extension = None
51
52    def __init__(self, extra_vars_func=None, options=None):
53        if options is None:
54            options = {}
55        # TODO get loader_args from the options dict
56
57        self.loader = TemplateLoader(auto_reload=True)
58        self.options = options
59        self.get_extra_vars = extra_vars_func
60
61    def load_template(self, templatename, template_string=None):
62        """Find a template specified in python 'dot' notation, or load one from
63        a string.
64        """
65        if template_string is not None:
66            return self.template_class(template_string)
67
68        divider = templatename.rfind('.')
69        if divider >= 0:
70            package = templatename[:divider]
71            basename = templatename[divider + 1:] + self.extension
72            templatename = resource_filename(package, basename)
73
74        return self.loader.load(templatename, cls=self.template_class)
75
76    def render(self, info, format='html', fragment=False, template=None):
77        """Render the template to a string using the provided info."""
78        return self.transform(info, template).render(method=format)
79
80    def transform(self, info, template):
81        """Render the output to an event stream."""
82        if not isinstance(template, Template):
83            template = self.load_template(template)
84        ctxt = Context(**info)
85
86        # Some functions for Kid compatibility
87        def defined(name):
88            return ctxt.get(name, Undefined) is not Undefined
89        ctxt['defined'] = defined
90        def value_of(name, default=None):
91            return ctxt.get(name, default)
92        ctxt['value_of'] = value_of
93
94        return template.generate(ctxt)
95
96
97class MarkupTemplateEnginePlugin(AbstractTemplateEnginePlugin):
98    """Implementation of the plugin API for markup templates."""
99
100    template_class = MarkupTemplate
101    extension = '.html'
102
103    def transform(self, info, template):
104        """Render the output to an event stream."""
105        data = {'ET': ET, 'HTML': HTML, 'XML': XML}
106        if self.get_extra_vars:
107            data.update(self.get_extra_vars())
108        data.update(info)
109        return super(MarkupTemplateEnginePlugin, self).transform(data, template)
110
111
112class TextTemplateEnginePlugin(AbstractTemplateEnginePlugin):
113    """Implementation of the plugin API for text templates."""
114
115    template_class = TextTemplate
116    extension = '.txt'
117
118    def transform(self, info, template):
119        """Render the output to an event stream."""
120        data = {}
121        if self.get_extra_vars:
122            data.update(self.get_extra_vars())
123        data.update(info)
124        return super(TextTemplateEnginePlugin, self).transform(data, template)
Note: See TracBrowser for help on using the repository browser.