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:
parent
ebfe476319
commit
9edc5a665e
22
qutebrowser/html/undef_error.html
Normal file
22
qutebrowser/html/undef_error.html
Normal 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>
|
@ -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
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user