template error traceback parity for jinja & genshi

This commit is contained in:
Mark McClain
2011-03-13 11:39:30 -04:00
parent 9da0e09d2b
commit 9eaa22cc05
4 changed files with 68 additions and 13 deletions

View File

@@ -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
#

View 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>

View File

@@ -7,6 +7,7 @@
<body>
<h1>Hello, {{name}}!</h1>
</body>
{# open a block without and name #}
{% block %}
</html>

View File

@@ -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