template error traceback parity for jinja & genshi
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import cgi
|
||||
|
||||
__all__ = ['RendererFactory']
|
||||
|
||||
_builtin_renderers = {}
|
||||
@@ -23,7 +25,8 @@ _builtin_renderers['json'] = JsonRenderer
|
||||
#
|
||||
|
||||
try:
|
||||
from genshi.template import TemplateLoader
|
||||
from genshi.template import (TemplateLoader,
|
||||
TemplateError as gTemplateError)
|
||||
|
||||
class GenshiRenderer(object):
|
||||
def __init__(self, path, extra_vars):
|
||||
@@ -36,7 +39,13 @@ try:
|
||||
return stream.render('html')
|
||||
|
||||
_builtin_renderers['genshi'] = GenshiRenderer
|
||||
# TODO: add error formatter for genshi
|
||||
|
||||
def format_genshi_error(exc_value):
|
||||
if isinstance(exc_value, (gTemplateError)):
|
||||
retval = '<h4>Genshi error %s</h4>' % cgi.escape(exc_value.message)
|
||||
retval += format_line_context(exc_value.filename, exc_value.lineno)
|
||||
return retval
|
||||
error_formatters.append(format_genshi_error)
|
||||
except ImportError: #pragma no cover
|
||||
pass
|
||||
|
||||
@@ -96,7 +105,7 @@ except ImportError: # pragma no cover
|
||||
#
|
||||
try:
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
from jinja2 import exceptions as jinja_exceptions
|
||||
from jinja2.exceptions import TemplateSyntaxError as jTemplateSyntaxError
|
||||
|
||||
class JinjaRenderer(object):
|
||||
def __init__(self, path, extra_vars):
|
||||
@@ -109,19 +118,34 @@ try:
|
||||
_builtin_renderers['jinja'] = JinjaRenderer
|
||||
|
||||
def format_jinja_error(exc_value):
|
||||
import cgi
|
||||
if isinstance(exc_value, (jinja_exceptions.TemplateSyntaxError)):
|
||||
retval = '<h4>Jinja2 template syntax error in \'%s\' on line %d</h4>' % (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] = '<strong>%s</strong>' % lines[lineno]
|
||||
|
||||
retval +='<div style="background-color:#ccc;padding:2em;">%s</div>' % '<br>'.join(lines)
|
||||
if isinstance(exc_value, (jTemplateSyntaxError)):
|
||||
retval = '<h4>Jinja2 template syntax error in \'%s\' on line %d</h4><div>%s</div>' % (exc_value.name, exc_value.lineno, exc_value.message)
|
||||
retval += format_line_context(exc_value.filename, exc_value.lineno)
|
||||
return retval
|
||||
error_formatters.append(format_jinja_error)
|
||||
except ImportError: # pragma no cover
|
||||
pass
|
||||
|
||||
#
|
||||
# format helper function
|
||||
#
|
||||
def format_line_context(filename, lineno, context=10):
|
||||
lines = open(filename).readlines()
|
||||
|
||||
lineno = lineno - 1 # files are indexed by 1 not 0
|
||||
if lineno > 0:
|
||||
start_lineno = max(lineno-context, 0)
|
||||
end_lineno = lineno+context
|
||||
|
||||
lines = [cgi.escape(l) for l in lines[start_lineno:end_lineno]]
|
||||
i = lineno-start_lineno
|
||||
lines[i] = '<strong>%s</strong>' % lines[i]
|
||||
|
||||
else:
|
||||
lines = [cgi.escape(l) for l in lines[:context]]
|
||||
|
||||
return '<pre style="background-color:#ccc;padding:2em;">%s</pre>' % ''.join(lines)
|
||||
|
||||
#
|
||||
# Extra Vars Rendering
|
||||
#
|
||||
|
||||
18
tests/templates/genshi_bad.html
Normal file
18
tests/templates/genshi_bad.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:py="http://genshi.edgewall.org/"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
|
||||
<title>Hello, ${name}!</title>
|
||||
<!-- comment out close tag to cause error
|
||||
</head>
|
||||
-->
|
||||
|
||||
<body>
|
||||
<h1>Hello, ${name}!</h1>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -7,6 +7,7 @@
|
||||
<body>
|
||||
<h1>Hello, {{name}}!</h1>
|
||||
</body>
|
||||
{# open a block without and name #}
|
||||
{% block %}
|
||||
|
||||
</html>
|
||||
|
||||
@@ -677,16 +677,29 @@ class TestEngines(object):
|
||||
@expose('genshi:genshi.html')
|
||||
def index(self, name='Jonathan'):
|
||||
return dict(name=name)
|
||||
|
||||
@expose('genshi:genshi_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 "<h1>Hello, Jonathan!</h1>" 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 "<h1>Hello, World!</h1>" 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_kajiki(self):
|
||||
if 'kajiki' not in builtin_renderers:
|
||||
@@ -702,7 +715,6 @@ class TestEngines(object):
|
||||
assert r.status_int == 200
|
||||
assert "<h1>Hello, Jonathan!</h1>" 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 "<h1>Hello, World!</h1>" in r.body
|
||||
|
||||
Reference in New Issue
Block a user