mirror of
https://github.com/datafolklabs/cement.git
synced 2026-02-06 13:56:49 +00:00
Resolves Issue #381
This commit is contained in:
parent
252e9c8c99
commit
f5ee31f92b
@ -3,6 +3,7 @@
|
||||
import os
|
||||
import sys
|
||||
import pkgutil
|
||||
import re
|
||||
from ..core import exc, interface, handler
|
||||
from ..utils.misc import minimal_logger
|
||||
from ..utils import fs
|
||||
@ -121,17 +122,19 @@ class TemplateOutputHandler(CementOutputHandler):
|
||||
content = open(full_path, 'r').read()
|
||||
LOG.debug("loaded output template from file %s" %
|
||||
full_path)
|
||||
return content
|
||||
return (content, full_path)
|
||||
else:
|
||||
LOG.debug("output template file %s does not exist" %
|
||||
full_path)
|
||||
continue
|
||||
|
||||
return None
|
||||
return (None, None)
|
||||
|
||||
def _load_template_from_module(self, template_path):
|
||||
template_module = self.app._meta.template_module
|
||||
template_path = template_path.lstrip('/')
|
||||
full_module_path = "%s.%s" % (template_module,
|
||||
re.sub('/', '.', template_path))
|
||||
|
||||
LOG.debug("attemping to load output template '%s' from module %s" %
|
||||
(template_path, template_module))
|
||||
@ -143,20 +146,40 @@ class TemplateOutputHandler(CementOutputHandler):
|
||||
except ImportError as e:
|
||||
LOG.debug("unable to import template module '%s'."
|
||||
% template_module)
|
||||
return None
|
||||
return (None, None)
|
||||
|
||||
# get the template content
|
||||
try:
|
||||
content = pkgutil.get_data(template_module, template_path)
|
||||
LOG.debug("loaded output template '%s' from module %s" %
|
||||
(template_path, template_module))
|
||||
return content
|
||||
return (content, full_module_path)
|
||||
except IOError as e:
|
||||
LOG.debug("output template '%s' does not exist in module %s" %
|
||||
(template_path, template_module))
|
||||
return None
|
||||
return (None, None)
|
||||
|
||||
def load_template(self, template_path, with_location=False):
|
||||
def load_template(self, template_path):
|
||||
"""
|
||||
Loads a template file first from ``self.app._meta.template_dirs`` and
|
||||
secondly from ``self.app._meta.template_module``. The
|
||||
``template_dirs`` have presedence.
|
||||
:param template_path: The secondary path of the template **after**
|
||||
either ``template_module`` or ``template_dirs`` prefix (set via
|
||||
``CementApp.Meta``)
|
||||
:returns: The content of the template (str)
|
||||
:raises: FrameworkError if the template does not exist in either the
|
||||
``template_module`` or ``template_dirs``.
|
||||
"""
|
||||
res = self.load_template_with_location(template_path)
|
||||
content, template_type, path = res
|
||||
|
||||
# only return content for backward compatibility
|
||||
return content
|
||||
|
||||
# FIX ME: Should eventually replace ``load_template()`` (but that breaks
|
||||
# compatibility)
|
||||
def load_template_with_location(self, template_path):
|
||||
"""
|
||||
Loads a template file first from ``self.app._meta.template_dirs`` and
|
||||
secondly from ``self.app._meta.template_module``. The
|
||||
@ -165,11 +188,9 @@ class TemplateOutputHandler(CementOutputHandler):
|
||||
:param template_path: The secondary path of the template **after**
|
||||
either ``template_module`` or ``template_dirs`` prefix (set via
|
||||
``CementApp.Meta``)
|
||||
:param with_location: Request the location where the template was found
|
||||
('dirs' or 'module') to be returned along with the template content.
|
||||
This changes the return
|
||||
:returns: The content of the template (str)
|
||||
or a tuple (content, location) (str, str) if with_location=True
|
||||
:returns: A tuple that includes the content of the template (str),
|
||||
the type of template (str which is one of: ``directory``, or
|
||||
``module``), and the ``path`` (str) of the directory or module)
|
||||
:raises: FrameworkError if the template does not exist in either the
|
||||
``template_module`` or ``template_dirs``.
|
||||
"""
|
||||
@ -178,21 +199,18 @@ class TemplateOutputHandler(CementOutputHandler):
|
||||
template_path)
|
||||
|
||||
# first attempt to load from file
|
||||
content = self._load_template_from_file(template_path)
|
||||
content, path = self._load_template_from_file(template_path)
|
||||
if content is None:
|
||||
# second attempt to load from module
|
||||
content = self._load_template_from_module(template_path)
|
||||
location = 'module'
|
||||
content, path = self._load_template_from_module(template_path)
|
||||
template_type = 'module'
|
||||
else:
|
||||
location = 'dirs'
|
||||
template_type = 'directory'
|
||||
|
||||
# if content is None, that means we didn't find a template file in
|
||||
# either and that is an exception
|
||||
if content is not None:
|
||||
if with_location:
|
||||
return content, location
|
||||
else:
|
||||
return content
|
||||
else:
|
||||
if content is None:
|
||||
raise exc.FrameworkError("Could not locate template: %s" %
|
||||
template_path)
|
||||
|
||||
return (content, template_type, path)
|
||||
|
||||
@ -60,6 +60,7 @@ would then put a Jinja2 template file in
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
from ..core import output
|
||||
from ..utils.misc import minimal_logger
|
||||
from jinja2 import Environment, FileSystemLoader, PackageLoader
|
||||
@ -88,8 +89,9 @@ class Jinja2OutputHandler(output.TemplateOutputHandler):
|
||||
|
||||
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
|
||||
# higher in application code if necessary
|
||||
self.env = Environment(keep_trailing_newline=True)
|
||||
|
||||
def render(self, data_dict, template=None, **kw):
|
||||
@ -108,15 +110,23 @@ class Jinja2OutputHandler(output.TemplateOutputHandler):
|
||||
"""
|
||||
|
||||
LOG.debug("rendering output using '%s' as a template." % template)
|
||||
content, location = self.load_template(template, with_location=True)
|
||||
content, _type, path = self.load_template_with_location(template)
|
||||
|
||||
if location == 'dirs':
|
||||
if _type == 'directory':
|
||||
self.env.loader = FileSystemLoader(self.app._meta.template_dirs)
|
||||
elif location == 'module':
|
||||
elif _type == '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'))
|
||||
if sys.version_info[0] >= 3:
|
||||
if not isinstance(content, str):
|
||||
content = content.decode('utf-8')
|
||||
else:
|
||||
if not isinstance(content, unicode): # pragma: nocover # noqa
|
||||
content = content.decode('utf-8') # pragma: nocover
|
||||
|
||||
tmpl = self.env.from_string(content)
|
||||
|
||||
return tmpl.render(**data_dict)
|
||||
|
||||
|
||||
|
||||
@ -35,23 +35,33 @@ class Jinja2ExtTestCase(test.CementExtTestCase):
|
||||
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()
|
||||
self.app._meta.template_dirs = [self.tmp_dir]
|
||||
|
||||
# make sure it doesn't load from the tests directory module regardless
|
||||
self.app._meta.template_module = 'some.bogus.module.path'
|
||||
|
||||
tests_dir = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
from_file = os.path.join(tests_dir, 'templates',
|
||||
'test_template_parent.jinja2')
|
||||
to_file = os.path.join(self.tmp_dir, 'test_template_parent.jinja2')
|
||||
copyfile(from_file, to_file)
|
||||
|
||||
from_file = os.path.join(tests_dir, 'templates',
|
||||
'test_template_child.jinja2')
|
||||
to_file = os.path.join(self.tmp_dir, 'test_template_child.jinja2')
|
||||
copyfile(from_file, to_file)
|
||||
|
||||
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()
|
||||
self.app._meta.template_module = 'tests.templates'
|
||||
self.app._meta.template_dirs = []
|
||||
rando = random.random()
|
||||
res = self.app.render(dict(foo=rando), 'test_template_child.jinja2')
|
||||
jinja2_res = "foo equals %s\n" % rando
|
||||
|
||||
Loading…
Reference in New Issue
Block a user