1e9073c33SBin Cui"Template support for Cheetah"
2e9073c33SBin Cui
3e9073c33SBin Cuiimport sys, os, imp
4e9073c33SBin Cui
5e9073c33SBin Cuifrom Cheetah import Compiler
6e9073c33SBin Cuiimport pkg_resources
7e9073c33SBin Cui
8e9073c33SBin Cuidef _recompile_template(package, basename, tfile, classname):
9e9073c33SBin Cui    tmpl = pkg_resources.resource_string(package, "%s.tmpl" % basename)
10e9073c33SBin Cui    c = Compiler.Compiler(source=tmpl, mainClassName='GenTemplate')
11e9073c33SBin Cui    code = str(c)
12e9073c33SBin Cui    mod = imp.new_module(classname)
13e9073c33SBin Cui    ns = dict()
14e9073c33SBin Cui    exec(code, ns)
15e9073c33SBin Cui    tempclass = ns.get("GenTemplate",
16e9073c33SBin Cui                       ns.get('DynamicallyCompiledCheetahTemplate'))
17e9073c33SBin Cui    assert tempclass
18e9073c33SBin Cui    tempclass.__name__ = basename
19e9073c33SBin Cui    setattr(mod, basename, tempclass)
20e9073c33SBin Cui    sys.modules[classname] = mod
21e9073c33SBin Cui    return mod
22e9073c33SBin Cui
23e9073c33SBin Cuiclass TurboCheetah:
24e9073c33SBin Cui    extension = "tmpl"
25e9073c33SBin Cui
26e9073c33SBin Cui    def __init__(self, extra_vars_func=None, options=None):
27e9073c33SBin Cui        if options is None:
28e9073c33SBin Cui            options = dict()
29e9073c33SBin Cui        self.get_extra_vars = extra_vars_func
30e9073c33SBin Cui        self.options = options
31e9073c33SBin Cui        self.compiledTemplates = {}
32e9073c33SBin Cui        self.search_path = []
33e9073c33SBin Cui
34e9073c33SBin Cui    def load_template(self, template=None,
35e9073c33SBin Cui                      template_string=None, template_file=None,
36e9073c33SBin Cui                      loadingSite=False):
37e9073c33SBin Cui        """Searches for a template along the Python path.
38e9073c33SBin Cui
39e9073c33SBin Cui        Template files must end in ".tmpl" and be in legitimate packages.
40e9073c33SBin Cui        """
41e9073c33SBin Cui        given = len([_f for _f in (template, template_string, template_file) if _f])
42e9073c33SBin Cui        if given > 1:
43e9073c33SBin Cui            raise TypeError(
44e9073c33SBin Cui                "You may give only one of template, template_string, and "
45e9073c33SBin Cui                "template_file")
46e9073c33SBin Cui        if not given:
47e9073c33SBin Cui            raise TypeError(
48e9073c33SBin Cui                "You must give one of template, template_string, or "
49e9073c33SBin Cui                "template_file")
50e9073c33SBin Cui        if template:
51e9073c33SBin Cui            return self.load_template_module(template)
52e9073c33SBin Cui        elif template_string:
53e9073c33SBin Cui            return self.load_template_string(template_string)
54e9073c33SBin Cui        elif template_file:
55e9073c33SBin Cui            return self.load_template_file(template_file)
56e9073c33SBin Cui
57e9073c33SBin Cui    def load_template_module(self, classname):
58e9073c33SBin Cui
59e9073c33SBin Cui        ct = self.compiledTemplates
60e9073c33SBin Cui
61e9073c33SBin Cui        divider = classname.rfind(".")
62e9073c33SBin Cui        if divider > -1:
63e9073c33SBin Cui            package = classname[0:divider]
64e9073c33SBin Cui            basename = classname[divider+1:]
65e9073c33SBin Cui        else:
66e9073c33SBin Cui            raise ValueError("All templates must be in a package")
67e9073c33SBin Cui
68e9073c33SBin Cui        if not self.options.get("cheetah.precompiled", False):
69e9073c33SBin Cui            tfile = pkg_resources.resource_filename(package,
70e9073c33SBin Cui                                                    "%s.%s" %
71e9073c33SBin Cui                                                    (basename,
72e9073c33SBin Cui                                                    self.extension))
73e9073c33SBin Cui            if classname in ct:
74e9073c33SBin Cui                mtime = os.stat(tfile).st_mtime
75e9073c33SBin Cui                if ct[classname] != mtime:
76e9073c33SBin Cui                    ct[classname] = mtime
77e9073c33SBin Cui                    del sys.modules[classname]
78e9073c33SBin Cui                    mod = _recompile_template(package, basename,
79e9073c33SBin Cui                                              tfile, classname)
80e9073c33SBin Cui                else:
81e9073c33SBin Cui                    mod = __import__(classname, dict(), dict(), [basename])
82e9073c33SBin Cui            else:
83e9073c33SBin Cui                ct[classname] = os.stat(tfile).st_mtime
84e9073c33SBin Cui                mod = _recompile_template(package, basename,
85e9073c33SBin Cui                                          tfile, classname)
86e9073c33SBin Cui        else:
87e9073c33SBin Cui            mod = __import__(classname, dict(), dict(), [basename])
88e9073c33SBin Cui        tempclass = getattr(mod, basename)
89e9073c33SBin Cui        return tempclass
90e9073c33SBin Cui
91e9073c33SBin Cui    def load_template_string(self, content):
92e9073c33SBin Cui        raise NotImplementedError
93e9073c33SBin Cui
94e9073c33SBin Cui    def load_template_file(self, filename):
95e9073c33SBin Cui        raise NotImplementedError
96e9073c33SBin Cui
97e9073c33SBin Cui    def render(self, info, format="html", fragment=False, template=None,
98e9073c33SBin Cui               template_string=None, template_file=None):
99e9073c33SBin Cui        tclass = self.load_template(
100e9073c33SBin Cui            template=template, template_string=template_string,
101e9073c33SBin Cui            template_file=template_file)
102e9073c33SBin Cui        if self.get_extra_vars:
103e9073c33SBin Cui            extra = self.get_extra_vars()
104e9073c33SBin Cui        else:
105e9073c33SBin Cui            extra = {}
106e9073c33SBin Cui        tempobj = tclass(searchList=[info, extra])
107e9073c33SBin Cui        if fragment:
108e9073c33SBin Cui            return tempobj.fragment()
109e9073c33SBin Cui        else:
110e9073c33SBin Cui            return tempobj.respond()