99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
|
"""
|
||
|
Cheetah API
|
||
|
(from web.py)
|
||
|
"""
|
||
|
|
||
|
__all__ = ["render"]
|
||
|
|
||
|
import re, urlparse, pprint, traceback, sys
|
||
|
from Cheetah.Compiler import Compiler
|
||
|
from Cheetah.Filters import Filter
|
||
|
from utils import re_compile, memoize, dictadd
|
||
|
from net import htmlquote, websafe
|
||
|
from webapi import ctx, header, output, input, cookies, loadhooks
|
||
|
|
||
|
def upvars(level=2):
|
||
|
"""Guido van Rossum sez: don't use this function."""
|
||
|
return dictadd(
|
||
|
sys._getframe(level).f_globals,
|
||
|
sys._getframe(level).f_locals)
|
||
|
|
||
|
r_include = re_compile(r'(?!\\)#include \"(.*?)\"($|#)', re.M)
|
||
|
def __compiletemplate(template, base=None, isString=False):
|
||
|
if isString:
|
||
|
text = template
|
||
|
else:
|
||
|
text = open('templates/'+template).read()
|
||
|
# implement #include at compile-time
|
||
|
def do_include(match):
|
||
|
text = open('templates/'+match.groups()[0]).read()
|
||
|
return text
|
||
|
while r_include.findall(text):
|
||
|
text = r_include.sub(do_include, text)
|
||
|
|
||
|
execspace = _compiletemplate.bases.copy()
|
||
|
tmpl_compiler = Compiler(source=text, mainClassName='GenTemplate')
|
||
|
tmpl_compiler.addImportedVarNames(execspace.keys())
|
||
|
exec str(tmpl_compiler) in execspace
|
||
|
if base:
|
||
|
_compiletemplate.bases[base] = execspace['GenTemplate']
|
||
|
|
||
|
return execspace['GenTemplate']
|
||
|
|
||
|
_compiletemplate = memoize(__compiletemplate)
|
||
|
_compiletemplate.bases = {}
|
||
|
|
||
|
def render(template, terms=None, asTemplate=False, base=None,
|
||
|
isString=False):
|
||
|
"""
|
||
|
Renders a template, caching where it can.
|
||
|
|
||
|
`template` is the name of a file containing the a template in
|
||
|
the `templates/` folder, unless `isString`, in which case it's the
|
||
|
template itself.
|
||
|
|
||
|
`terms` is a dictionary used to fill the template. If it's None, then
|
||
|
the caller's local variables are used instead, plus context, if it's not
|
||
|
already set, is set to `context`.
|
||
|
|
||
|
If asTemplate is False, it `output`s the template directly. Otherwise,
|
||
|
it returns the template object.
|
||
|
|
||
|
If the template is a potential base template (that is, something other templates)
|
||
|
can extend, then base should be a string with the name of the template. The
|
||
|
template will be cached and made available for future calls to `render`.
|
||
|
|
||
|
Requires [Cheetah](http://cheetahtemplate.org/).
|
||
|
"""
|
||
|
# terms=['var1', 'var2'] means grab those variables
|
||
|
if isinstance(terms, list):
|
||
|
new = {}
|
||
|
old = upvars()
|
||
|
for k in terms:
|
||
|
new[k] = old[k]
|
||
|
terms = new
|
||
|
# default: grab all locals
|
||
|
elif terms is None:
|
||
|
terms = {'context': ctx, 'ctx':ctx}
|
||
|
terms.update(sys._getframe(1).f_locals)
|
||
|
# terms=d means use d as the searchList
|
||
|
if not isinstance(terms, tuple):
|
||
|
terms = (terms,)
|
||
|
|
||
|
if 'headers' in ctx and not isString and template.endswith('.html'):
|
||
|
header('Content-Type','text/html; charset=utf-8', unique=True)
|
||
|
|
||
|
if loadhooks.has_key('reloader'):
|
||
|
compiled_tmpl = __compiletemplate(template, base=base, isString=isString)
|
||
|
else:
|
||
|
compiled_tmpl = _compiletemplate(template, base=base, isString=isString)
|
||
|
compiled_tmpl = compiled_tmpl(searchList=terms, filter=WebSafe)
|
||
|
if asTemplate:
|
||
|
return compiled_tmpl
|
||
|
else:
|
||
|
return output(str(compiled_tmpl))
|
||
|
|
||
|
class WebSafe(Filter):
|
||
|
def filter(self, val, **keywords):
|
||
|
return websafe(val)
|