Handle jinja's UndefinedError in jinja.render

We can get UndefinedError when a new function got added to the jinja
env (and gets called from a template) and the user did update the
on-disk templates but not restart qutebrowser yet.

In this case, let's show a special error page to the user and tell them
to do :report in the unlikely case it's actually a bug.

Fixes #1362.
See #1360.
This commit is contained in:
Florian Bruhin 2016-03-25 23:57:29 +01:00
parent ebfe476319
commit 9edc5a665e
3 changed files with 51 additions and 4 deletions

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<!--
vim: ft=html fileencoding=utf-8 sts=4 sw=4 et:
-->
<html>
<head>
<meta charset="utf-8">
<title>Error while rendering HTML</title>
</head>
<body>
<h1>Error while rendering internal qutebrowser page</h1>
<p>There was an error while rendering {pagename}.</p>
<p>This most likely happened because you updated qutebrowser but didn't restart yet.</p>
<p>If you believe this isn't the case and this is a bug, please do :report.<p>
<h2>Traceback</h2>
<pre>{traceback}</pre>
</body>
</html>

View File

@ -21,10 +21,12 @@
import os
import os.path
import traceback
import jinja2
import jinja2.exceptions
from qutebrowser.utils import utils
from qutebrowser.utils import utils, log
from PyQt5.QtCore import QUrl
@ -74,8 +76,13 @@ def resource_url(path):
def render(template, **kwargs):
"""Render the given template and pass the given arguments to it."""
return _env.get_template(template).render(**kwargs)
try:
return _env.get_template(template).render(**kwargs)
except jinja2.exceptions.UndefinedError:
log.misc.exception("UndefinedError while rendering " + template)
err_template = utils.read_file(os.path.join('html', 'undef_error.html'))
tb = traceback.format_exc()
return err_template.format(pagename=template, traceback=tb)
_env = jinja2.Environment(loader=Loader('html'), autoescape=_guess_autoescape)
_env.globals['resource_url'] = resource_url

View File

@ -23,21 +23,27 @@ import os
import os.path
import pytest
import logging
import jinja2
from PyQt5.QtCore import QUrl
from qutebrowser.utils import jinja
from qutebrowser.utils import utils, jinja
@pytest.fixture(autouse=True)
def patch_read_file(monkeypatch):
"""pytest fixture to patch utils.read_file."""
real_read_file = utils.read_file
def _read_file(path):
"""A read_file which returns a simple template if the path is right."""
if path == os.path.join('html', 'test.html'):
return """Hello {{var}}"""
elif path == os.path.join('html', 'test2.html'):
return """{{ resource_url('utils/testfile') }}"""
elif path == os.path.join('html', 'undef.html'):
return """{{ does_not_exist() }}"""
elif path == os.path.join('html', 'undef_error.html'):
return real_read_file(path)
else:
raise IOError("Invalid path {}!".format(path))
@ -87,6 +93,18 @@ def test_utf8():
assert data == "Hello \u2603"
def test_undefined_function(caplog):
"""Make sure we don't crash if an undefined function is called."""
with caplog.at_level(logging.ERROR):
data = jinja.render('undef.html')
assert 'There was an error while rendering undef.html' in data
assert "'does_not_exist' is undefined" in data
assert data.startswith('<!DOCTYPE html>')
assert len(caplog.records) == 1
assert caplog.records[0].msg == "UndefinedError while rendering undef.html"
@pytest.mark.parametrize('name, expected', [
(None, False),
('foo', False),