diff --git a/pecan/templating.py b/pecan/templating.py
index 385e106..d76ddcc 100644
--- a/pecan/templating.py
+++ b/pecan/templating.py
@@ -91,6 +91,37 @@ try:
except ImportError: # pragma no cover
pass
+#
+# Jinja2 rendering engine
+#
+try:
+ from jinja2 import Environment, FileSystemLoader
+ from jinja2 import exceptions as jinja_exceptions
+
+ class JinjaRenderer(object):
+ def __init__(self, path, extra_vars):
+ self.env = Environment(loader=FileSystemLoader(path))
+ self.extra_vars = extra_vars
+
+ def render(self, template_path, namespace):
+ template = self.env.get_template(template_path)
+ return template.render(self.extra_vars.make_ns(namespace))
+ _builtin_renderers['jinja'] = JinjaRenderer
+
+ def format_jinja_error(exc_value):
+ import cgi
+ if isinstance(exc_value, (jinja_exceptions.TemplateSyntaxError)):
+ retval = '
Jinja2 template syntax error in \'%s\' on line %d
' % (exc_value.name, exc_value.lineno)
+ lines = [cgi.escape(x) for x in open(exc_value.filename)]
+ lineno = exc_value.lineno - 1 # files are 1 not 0 index
+ lines[lineno] = '%s' % lines[lineno]
+
+ retval +='%s
' % '
'.join(lines)
+ return retval
+ error_formatters.append(format_jinja_error)
+except ImportError: # pragma no cover
+ pass
+
#
# Extra Vars Rendering
#
diff --git a/tests/templates/jinja.html b/tests/templates/jinja.html
new file mode 100644
index 0000000..e96835a
--- /dev/null
+++ b/tests/templates/jinja.html
@@ -0,0 +1,11 @@
+
+
+
+ Hello, {{name}}!
+
+
+
+ Hello, {{name}}!
+
+
+
diff --git a/tests/templates/jinja_bad.html b/tests/templates/jinja_bad.html
new file mode 100644
index 0000000..db01676
--- /dev/null
+++ b/tests/templates/jinja_bad.html
@@ -0,0 +1,12 @@
+
+
+
+ Hello, {{name}}!
+
+
+
+ Hello, {{name}}!
+
+{% block %}
+
+
diff --git a/tests/test_base.py b/tests/test_base.py
index ff80beb..b1b8039 100644
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -706,6 +706,33 @@ class TestEngines(object):
r = app.get('/index.html?name=World')
assert r.status_int == 200
assert "Hello, World!
" in r.body
+
+ def test_jinja(self):
+ if 'jinja' not in builtin_renderers:
+ return
+ class RootController(object):
+ @expose('jinja:jinja.html')
+ def index(self, name='Jonathan'):
+ return dict(name=name)
+
+ @expose('jinja:jinja_bad.html')
+ def badtemplate(self):
+ return dict()
+
+ app = TestApp(Pecan(RootController(), template_path=self.template_path))
+ r = app.get('/')
+ assert r.status_int == 200
+ assert "Hello, Jonathan!
" in r.body
+
+ error_msg = None
+ try:
+ r = app.get('/badtemplate.html')
+ except Exception, e:
+ for error_f in error_formatters:
+ error_msg = error_f(e)
+ if error_msg:
+ break
+ assert error_msg is not None
def test_mako(self):
if 'mako' not in builtin_renderers:
@@ -724,7 +751,6 @@ class TestEngines(object):
assert r.status_int == 200
assert "Hello, Jonathan!
" in r.body
- app = TestApp(Pecan(RootController(), template_path=self.template_path))
r = app.get('/index.html?name=World')
assert r.status_int == 200
assert "Hello, World!
" in r.body