Отладка Jinja2 в Google App Engine
Когда я запускаю Jinja2 в Google App Engine, я получаю бесполезную отладочную информацию. Я понимаю, что это из-за этого пункта в FAQ:
Если модуль ускорения не скомпилирован и вы используете установку Python без ctypes (Python 2.4 без ctypes, Jython или Googles AppEngine), Jinja2 не может предоставить правильную информацию для отладки, а трассировка может быть неполной. В настоящее время нет хорошего способа обхода решения для Jython или AppEngine, поскольку ctypes недоступно там, и невозможно использовать расширение ускорения.
В то время как для этого в настоящее время не существует "хорошего" способа обхода, есть ли какое-либо обходное решение, чтобы информация, напечатанная при возникновении исключений, могла быть более полезной?
Спасибо, что прочитали.
Брайан
Ответы
Ответ 1
Вы можете обойти это, добавив _ctypes и gestalt в белый список модулей сервера разработки с monkeypatching.
Чтобы сделать это, поместите следующий фрагмент вверху вашего main.py:
import os
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev'):
# Enable ctypes for Jinja debugging
from google.appengine.tools.dev_appserver import HardenedModulesHook
HardenedModulesHook._WHITE_LIST_C_MODULES += ['_ctypes', 'gestalt']
Вы также можете использовать этот трюк, чтобы включить другие C-модули, если у вас есть аналогичный модуль для локального модуля. Имейте в виду, что эти модули по-прежнему не будут работать после развертывания, поэтому пройдите осторожно.
В SDK 1.6.3 с использованием python2.7 вам необходимо изменить приведенный выше код на:
import os
if os.environ.get('SERVER_SOFTWARE', '').startswith('Dev'):
# Enable ctypes for Jinja debugging
import sys
from google.appengine.tools.dev_appserver import HardenedModulesHook
assert isinstance(sys.meta_path[0], HardenedModulesHook)
sys.meta_path[0]._white_list_c_modules += ['_ctypes', 'gestalt']
В SDK 1.8.6 для python 2.7 попробуйте следующее:
PRODUCTION_MODE = not os.environ.get(
'SERVER_SOFTWARE', 'Development').startswith('Development')
if not PRODUCTION_MODE:
from google.appengine.tools.devappserver2.python import sandbox
sandbox._WHITE_LIST_C_MODULES += ['_ctypes', 'gestalt']
Ответ 2
Я использую следующую команду monkeypatch, чтобы включить немного более полезную информацию, когда исключение возникает во время рендеринга шаблона Jinja2:
# Enabling this monkeypatch can help track down hard to find errors that crop
# up during template rendering (since Jinja 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
Это приведет к чуть более точным отслеживаниям исключений в ваших журналах ошибок. Я не думаю, что это обычно показывает вам точно, что пошло не так (но если я правильно помню это иногда делает), но это, по крайней мере, сократит исключение до правильного шаблона.
Почему это работает, я не знаю (или не могу вспомнить).
В качестве примера я просто добавил код, который вызовет исключение из одного из моих шаблонов. Под сервером разработки это то, что показывает мне "нормальный" обработчик исключений:
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
. Это самая неприятная часть отладки исключений шаблонов Jinja2 в App Engine: источник исключения почти всегда искажен. По моему опыту, источник обычно сообщается либо как родительский шаблон, либо как некоторый шаблонный макрос.
При установленном исключении регистрации 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
Здесь по-прежнему много посторонней информации, но эта трассировка по крайней мере указывает мне в правильном направлении. Он утверждает, что проблема находится в строке 54 accounts/edit_card.html
(правильный шаблон), но фактическое исключение происходит в строке 86.
Но с учетом правильного шаблона и правильного исключения, я могу довольно легко найти, что неприятный код - это
{% for x in sequence.sequence() %}
{{ x.y }}
{% endfor %}
где нет переменной sequence
в контексте шаблона.
Это не идеальное решение, но я нашел его полезным.
Ответ 3
Не уверен, что это будет полезно, но возможно, по крайней мере, добавить блок templatetag, например django 'debug', который, по крайней мере, поможет локализовать проблему.
Ответ 4
Возможно, просто используйте интерактивный отладчик PyCharm и выполните код:
http://www.jetbrains.com/pycharm/quickstart/#RunAndDebug
Ответ 5
Способ избежать перехвата обезьян (который зависит от изменяющихся внутренних компонентов SDK) заключается в использовании модуля imp
, который по крайней мере в настоящее время не отключен в локальной среде разработки. Затем просто загрузите _ctypes
, чтобы включить лучшую отладку Jinja2:
import imp
file, pathname, description = imp.find_module('_ctypes')
imp.load_module('_ctypes', file, pathname, description)
Ответ 6
Когда я сталкивался с подобной проблемой, я пытаюсь ее отладить в своей локальной оболочке iPython. Интересно, какой код генерирует такую ошибку. Должен быть способ написать для него тест.