allow jinja2 template inheritance Fixes #381

This commit is contained in:
Nicolas Brisac 2016-07-07 12:30:48 +02:00
parent 739d2b82f3
commit e102ef064c
6 changed files with 52 additions and 4 deletions

View File

@ -62,7 +62,7 @@ would then put a Jinja2 template file in
from ..core import output
from ..utils.misc import minimal_logger
from jinja2 import Template
from jinja2 import Environment, FileSystemLoader, PackageLoader
LOG = minimal_logger(__name__)
@ -86,6 +86,12 @@ class Jinja2OutputHandler(output.TemplateOutputHandler):
interface = output.IOutput
label = 'jinja2'
def __init__(self, *args, **kw):
super(Jinja2OutputHandler, self).__init__(*args, **kw)
# expose Jinja2 Environment instance so that we can manipulate it
# higher in application code
self.env = Environment(keep_trailing_newline=True)
def render(self, data_dict, template=None, **kw):
"""
Take a data dictionary and render it using the given template file.
@ -102,9 +108,15 @@ class Jinja2OutputHandler(output.TemplateOutputHandler):
"""
LOG.debug("rendering output using '%s' as a template." % template)
content = self.load_template(template)
content, location = self.load_template(template, with_location=True)
tmpl = Template(content.decode('utf-8'), keep_trailing_newline=True)
if location == 'dirs':
self.env.loader = FileSystemLoader(self.app._meta.template_dirs)
elif location == 'module':
parts = self.app._meta.template_module.rsplit('.', 1)
self.env.loader = PackageLoader(parts[0], package_path=parts[1])
tmpl = self.env.from_string(content.decode('utf-8'))
return tmpl.render(**data_dict)

View File

@ -20,6 +20,7 @@ The following output handlers are included and maintained with Cement:
* :class:`cement.ext.ext_json.JsonOutputHandler`
* :class:`cement.ext.ext_yaml.YamlOutputHandler`
* :class:`cement.ext.ext_genshi.GenshiOutputHandler`
* :class:`cement.ext.ext_jinja2.Jinja2OutputHandler`
* :class:`cement.ext.ext_mustache.MustacheOutputHandler`
* :class:`cement.ext.ext_tabulate.TabulateOutputHandler`
@ -165,4 +166,3 @@ just Json output (supressing all other output) using our return dictionary:
$ python myapp.py -o json
{"foo": "bar"}

View File

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
"""Tests for cement.ext.ext_jinja2."""
import os
import sys
import random
from shutil import copyfile, rmtree
from cement.core import exc, foundation, handler, backend, controller
from cement.utils import test
@ -25,6 +27,36 @@ class Jinja2ExtTestCase(test.CementExtTestCase):
jinja2_res = "foo equals %s\n" % rando
self.eq(res, jinja2_res)
def test_jinja2_utf8(self):
self.app.setup()
rando = random.random()
res = self.app.render(dict(foo=rando), 'test_template_utf8.jinja2')
jinja2_res = u"foo est égal à %s\n" % rando
self.eq(res, jinja2_res)
def test_jinja2_filesystemloader(self):
self.app._meta.template_dirs = ['/tmp/cement_tests']
if os.path.isdir('/tmp/cement_tests'):
rmtree('/tmp/cement_tests')
os.makedirs('/tmp/cement_tests')
tests_dir = os.path.dirname(os.path.dirname(__file__))
copyfile(
'%s/templates/test_template_parent.jinja2' % tests_dir,
'/tmp/cement_tests/test_template_parent.jinja2')
self.app.setup()
rando = random.random()
res = self.app.render(dict(foo=rando), 'test_template_child.jinja2')
jinja2_res = "foo equals %s\n" % rando
self.eq(res, jinja2_res)
def test_jinja2_packageloader(self):
self.app._meta.template_module = 'tests.templates'
self.app.setup()
rando = random.random()
res = self.app.render(dict(foo=rando), 'test_template_child.jinja2')
jinja2_res = "foo equals %s\n" % rando
self.eq(res, jinja2_res)
@test.raises(exc.FrameworkError)
def test_jinja2_bad_template(self):
self.app.setup()

View File

@ -0,0 +1,2 @@
{% extends 'test_template_parent.jinja2' %}
{% block test %}foo equals{% endblock %}

View File

@ -0,0 +1 @@
{% block test %}{% endblock %} {{ foo }}

View File

@ -0,0 +1 @@
foo est égal à {{foo}}