add new Template system, authorizing Django and ezt syntaxes (#19442)
This commit is contained in:
parent
234f1499fa
commit
f626c45cbb
|
@ -0,0 +1,44 @@
|
|||
import pytest
|
||||
|
||||
from qommon.template import Template, TemplateError
|
||||
|
||||
|
||||
def test_template():
|
||||
tmpl = Template('')
|
||||
assert tmpl.render() == ''
|
||||
assert tmpl.render({'foo': 'bar'}) == ''
|
||||
tmpl = Template('zoo')
|
||||
assert tmpl.render() == 'zoo'
|
||||
assert tmpl.render({'foo': 'bar'}) == 'zoo'
|
||||
|
||||
# django
|
||||
tmpl = Template('{{ foo }}')
|
||||
assert tmpl.render() == ''
|
||||
assert tmpl.render({'foo': 'bar'}) == 'bar'
|
||||
tmpl = Template('{% if foo %}{{ foo }}{% endif %}')
|
||||
assert tmpl.render() == ''
|
||||
assert tmpl.render({'foo': 'bar'}) == 'bar'
|
||||
|
||||
# ezt
|
||||
tmpl = Template('[foo]')
|
||||
assert tmpl.render() == '[foo]'
|
||||
assert tmpl.render({'foo': 'bar'}) == 'bar'
|
||||
tmpl = Template('[if-any foo][foo][end]')
|
||||
assert tmpl.render() == ''
|
||||
assert tmpl.render({'foo': 'bar'}) == 'bar'
|
||||
|
||||
# mix Django/ezt: Django wins
|
||||
tmpl = Template('{% if foo %}{{ foo }}[foo]{% endif %}')
|
||||
assert tmpl.render({'foo': 'bar'}) == 'bar[foo]'
|
||||
|
||||
# django syntax error
|
||||
with pytest.raises(TemplateError):
|
||||
tmpl = Template('{% if foo %}{{ foo }}{% end %}', raises=True)
|
||||
tmpl = Template('{% if foo %}{{ foo }}{% end %}')
|
||||
assert tmpl.render({'foo': 'bar'}) == '{% if foo %}{{ foo }}{% end %}'
|
||||
|
||||
# ezt syntax error
|
||||
with pytest.raises(TemplateError):
|
||||
tmpl = Template('[if-any foo][foo][endif]', raises=True)
|
||||
tmpl = Template('[if-any foo][foo][endif]')
|
||||
assert tmpl.render({'foo': 'bar'}) == '[if-any foo][foo][endif]'
|
|
@ -19,6 +19,9 @@ import os
|
|||
import glob
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from django.template import (Context as DjangoContext, Template as DjangoTemplate,
|
||||
TemplateSyntaxError as DjangoTemplateSyntaxError,
|
||||
VariableDoesNotExist as DjangoVariableDoesNotExist)
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from quixote import get_session, get_request, get_response, get_publisher
|
||||
|
@ -411,3 +414,95 @@ def decorate(body, response):
|
|||
|
||||
def render(template_name, context):
|
||||
return htmltext(render_to_string(template_name, context).encode('utf-8'))
|
||||
|
||||
|
||||
class TemplateError(Exception):
|
||||
def __init__(self, msg, params=()):
|
||||
self.msg = msg
|
||||
self.params = params
|
||||
|
||||
def __str__(self):
|
||||
return self.msg % self.params
|
||||
|
||||
|
||||
def ezt_raises(exception, on_parse=False):
|
||||
from qommon import _
|
||||
parts = []
|
||||
parts.append({
|
||||
ezt.ArgCountSyntaxError: _('wrong number of arguments'),
|
||||
ezt.UnknownReference: _('unknown reference'),
|
||||
ezt.NeedSequenceError: _('sequence required'),
|
||||
ezt.UnclosedBlocksError: _('unclosed block'),
|
||||
ezt.UnmatchedEndError: _('unmatched [end]'),
|
||||
ezt.UnmatchedElseError: _('unmatched [else]'),
|
||||
ezt.BaseUnavailableError: _('unavailable base location'),
|
||||
ezt.BadFormatConstantError: _('bad format constant'),
|
||||
ezt.UnknownFormatConstantError: _('unknown format constant'),
|
||||
}.get(exception.__class__, _('unknown error')))
|
||||
if exception.line is not None:
|
||||
parts.append(_('at line %(line)d and column %(column)d') % {
|
||||
'line': exception.line + 1, 'column': exception.column + 1})
|
||||
if on_parse:
|
||||
message = _('syntax error in ezt template: %s')
|
||||
else:
|
||||
message = _('failure to render ezt template: %s')
|
||||
raise TemplateError(message % ' '.join(parts))
|
||||
|
||||
|
||||
class Template(object):
|
||||
def __init__(self, value, raises=False):
|
||||
'''Guess kind of template (Django or ezt), and parse it'''
|
||||
self.value = value
|
||||
self.raises = raises
|
||||
|
||||
if '{{' in value or '{%' in value: # Django template
|
||||
self.render = self.django_render
|
||||
try:
|
||||
self.template = DjangoTemplate(value)
|
||||
except DjangoTemplateSyntaxError as e:
|
||||
if raises:
|
||||
from qommon import _
|
||||
raise TemplateError(_('syntax error in Django template: %s'), e)
|
||||
self.render = self.null_render
|
||||
|
||||
elif '[' in value: # ezt template
|
||||
self.render = self.ezt_render
|
||||
self.template = ezt.Template(compress_whitespace=False)
|
||||
try:
|
||||
self.template.parse(value)
|
||||
except ezt.EZTException as e:
|
||||
if raises:
|
||||
ezt_raises(e, on_parse=True)
|
||||
self.render = self.null_render
|
||||
|
||||
else:
|
||||
self.render = self.null_render
|
||||
|
||||
def null_render(self, context={}):
|
||||
return str(self.value)
|
||||
|
||||
def django_render(self, context={}):
|
||||
context = DjangoContext(context)
|
||||
try:
|
||||
return self.template.render(context)
|
||||
except (DjangoTemplateSyntaxError, DjangoVariableDoesNotExist) as e:
|
||||
if self.raises:
|
||||
from qommon import _
|
||||
raise TemplateError(_('failure to render Django template: %s'), e)
|
||||
else:
|
||||
return self.value
|
||||
|
||||
def ezt_render(self, context={}):
|
||||
fd = StringIO()
|
||||
try:
|
||||
self.template.generate(fd, context)
|
||||
except ezt.EZTException as e:
|
||||
if self.raises:
|
||||
ezt_raises(e)
|
||||
else:
|
||||
return self.value
|
||||
return fd.getvalue()
|
||||
|
||||
@classmethod
|
||||
def is_template_string(cls, string):
|
||||
return string and ('{{' in string or '{%' in string or '[' in string)
|
||||
|
|
Loading…
Reference in New Issue