次のモンキーパッチを使用して、Jinja2テンプレートのレンダリング中に例外が発生したときに少し役立つ情報を有効にします。
# Enabling this monkeypatch can help track down hard to find errors that crop
# up during template rendering (since Jinja's own error reporting is so
# unhelpful on AppEngine).
real_handle_exception = environment.handle_exception
def handle_exception(self, *args, **kwargs):
import logging, traceback
logging.error('Template exception:\n%s', traceback.format_exc())
real_handle_exception(self, *args, **kwargs)
environment.handle_exception = handle_exception
これにより、エラーログにわずかに正確な例外トレースバックが記録されます。通常、何がうまくいかなかったのかを正確に示すとは思いませんが(ただし、正しく覚えていれば、時々そうなることがあります)、少なくとも例外を正しいテンプレートに絞り込むことができます。
なぜこれが機能するのか、私にはわかりません(または思い出せません)。
例として、テンプレートの1つに例外をトリガーするコードを追加しました。開発サーバーでは、これが「通常の」例外ハンドラーに表示されるものです。
Traceback (most recent call last):
File "/Users/will/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 511, in __call__
handler.get(*groups)
File "/Users/will/workspace/keypremium/ki/shared/decorators.py", line 27, in inner
return func(self, *args, **kwargs)
File "/Users/will/workspace/keypremium/account/views.py", line 114, in get
self.render_jinja('accounts/edit_card.html', ctx)
File "/Users/will/workspace/keypremium/ki/webapp/handlers.py", line 186, in render_jinja
return self.response.out.write(jinja.render(template_path, new_context))
File "/Users/will/workspace/keypremium/ki/shared/jinja/__init__.py", line 21, in render
return template.render(context)
File "/Users/will/workspace/keypremium/ki/ext/jinja2/environment.py", line 705, in render
return self.environment.handle_exception(exc_info, True)
File "/Users/will/workspace/keypremium/ki/shared/jinja/environment.py", line 24, in handle_exception
real_handle_exception(self, *args, **kwargs)
File "/Users/will/workspace/keypremium/templates/accounts/edit_card.html", line 1, in top-level template code
{% extends 'accounts/base.html' %}
UndefinedError: 'sequence' is undefined
ただし、例外はaccounts/base.html
テンプレートにはなく、にありaccounts/edit_card.html
ます。これは、App EngineでのJinja2テンプレート例外のデバッグで最も苛立たしい部分です。例外のソースは、ほとんどの場合、誤って伝えられます。私の経験では、ソースは通常、親テンプレートまたはテンプレートマクロとして報告されます。
例外ロギングmonkeypatchがインストールされている場合、同じ例外がログに次のトレースバックを生成します。
Traceback (most recent call last):
File "/Users/will/workspace/keypremium/ki/ext/jinja2/environment.py", line 702, in render
return concat(self.root_render_func(self.new_context(vars)))
File "/Users/will/workspace/keypremium/templates/accounts/edit_card.html", line 11, in root
<div class="errors">
File "/Users/will/workspace/keypremium/templates/accounts/base.html", line 11, in root
</html>
File "/Users/will/workspace/keypremium/templates/accounts/edit_card.html", line 54, in block_content
<td>{{ form.cvv2|safe }}</td>
File "/Users/will/workspace/keypremium/ki/ext/jinja2/environment.py", line 352, in getattr
return getattr(obj, attribute)
File "/Users/will/workspace/keypremium/ki/ext/jinja2/runtime.py", line 445, in _fail_with_undefined_error
raise self._undefined_exception(hint)
UndefinedError: 'sequence' is undefined
ここにはまだ多くの無関係な情報がありますが、このトレースバックは少なくとも私を正しい方向に向けています。問題はaccounts/edit_card.html
(正しいテンプレート)の54行目にあると主張していますが、実際の例外は86行目で発生しています。
しかし、正しいテンプレートと正しい例外を考えると、厄介なコードがこれであることが非常に簡単にわかります
{% for x in sequence.sequence() %}
{{ x.y }}
{% endfor %}
sequence
テンプレートコンテキストに変数がない場合。
これは完璧な解決策ではありませんが、非常に役立つことがわかりました。