from jinja.loaders import LoaderWrapper
from jinja.datastructure import Undefined, Markup, Context, FakeTranslator
from jinja.utils import escape, collect_translations, get_attribute
-from jinja.exceptions import FilterNotFound, TestNotFound, SecurityException
+from jinja.exceptions import FilterNotFound, TestNotFound, \
+ SecurityException, TemplateSyntaxError
from jinja.defaults import DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
"""Load a template from a string."""
from jinja.parser import Parser
from jinja.translators.python import PythonTranslator
- rv = PythonTranslator.process(self, Parser(self, source).parse())
- # attach the source for debugging
- rv._source = source
- return rv
+ try:
+ rv = PythonTranslator.process(self, Parser(self, source).parse())
+ except TemplateSyntaxError, e:
+ # if errors occour raise a better traceback
+ from jinja.utils import raise_syntax_error
+ __traceback_hide__ = True
+ raise_syntax_error(e, self, source)
+ else:
+ # everything went well. attach the source and return it
+ # attach the source for debugging
+ rv._source = source
+ return rv
def get_template(self, filename):
"""Load a template from a filename. Only works
if m is not None:
d = m.groupdict()
this = (d['filename'] or None, int(d['lineno']))
- # if there is no filename in this debug symbol
# if it's the same as the line before we ignore it
- if this[0] and this != last:
+ if this != last:
debug_mapping.append((idx - offset,) + this)
last = this
# for each debug symbol the line number and so the offset
return wrapped
-def fake_template_exception(exception, filename, lineno, template,
+def fake_template_exception(exception, filename, lineno, source,
context_or_env):
"""
Raise an exception "in a template". Return a traceback
namespace = {}
offset = '\n' * (lineno - 1)
- code = compile(offset + 'raise __exception_to_raise__', filename, 'exec')
+ code = compile(offset + 'raise __exception_to_raise__',
+ filename or '<template>', 'exec')
globals = {
'__name__': filename,
'__file__': filename,
- '__loader__': TracebackLoader(env, template, filename),
+ '__loader__': TracebackLoader(env, source, filename),
'__exception_to_raise__': exception
}
try:
return traceback
return fake_template_exception(exc_value, tmpl_filename, tmpl_line,
- template, context)[2]
+ template._source, context)[2]
-def raise_syntax_error(exception, env):
+def raise_syntax_error(exception, env, source=None):
"""
This method raises an exception that includes more debugging
informations so that debugging works better. Unlike
the traceback.
"""
exc_info = fake_template_exception(exception, exception.filename,
- exception.lineno, None, env)
+ exception.lineno, source, env)
raise exc_info[0], exc_info[1], exc_info[2]
Fake importer that just returns the source of a template.
"""
- def __init__(self, environment, template, filename):
+ def __init__(self, environment, source, filename):
self.loader = environment.loader
- self.template = template
+ self.source = source
self.filename = filename
def get_source(self, impname):
- if self.loader is not None:
+ if self.source is not None:
+ return self.source
+ elif self.loader is not None:
try:
return self.loader.get_source(self.filename)
except TemplateNotFound:
pass
- if self.template is not None:
- return self.template._source or ''
return ''
<li><a href="runtime_error">runtime error</a></li>
<li><a href="nested_syntax_error">nested syntax error</a></li>
<li><a href="nested_runtime_error">nested runtime error</a></li>
+ <li><a href="syntax_from_string">a syntax error from string</a></li>
+ <li><a href="runtime_from_string">runtime error from a string</a></li>
</ul>
</body>
</html>
{% raw %}just some foo'''
}))
+FAILING_STRING_TEMPLATE = '{{ 1 / 0 }}'
+BROKEN_STRING_TEMPLATE = '{% if foo %}...{% endfor %}'
+
def test(environ, start_response):
+ path = environ.get('PATH_INFO' or '/')
try:
- tmpl = e.get_template(environ.get('PATH_INFO') or '/')
+ tmpl = e.get_template(path)
except TemplateNotFound:
- start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
- return ['NOT FOUND']
+ if path == '/syntax_from_string':
+ tmpl = e.from_string(BROKEN_STRING_TEMPLATE)
+ elif path == '/runtime_from_string':
+ tmpl = e.from_string(FAILING_STRING_TEMPLATE)
+ else:
+ start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
+ return ['NOT FOUND']
start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
return [tmpl.render().encode('utf-8')]