Подтвердить что ты не робот

Отладка Jinja2 в Google App Engine

Когда я запускаю Jinja2 в Google App Engine, я получаю бесполезную отладочную информацию. Я понимаю, что это из-за этого пункта в FAQ:

Мои трассировки выглядят странно. Что происходит?

Если модуль ускорения не скомпилирован и вы используете установку Python без ctypes (Python 2.4 без ctypes, Jython или Googles AppEngine), Jinja2 не может предоставить правильную информацию для отладки, а трассировка может быть неполной. В настоящее время нет хорошего способа обхода решения для Jython или AppEngine, поскольку ctypes недоступно там, и невозможно использовать расширение ускорения.

В то время как для этого в настоящее время не существует "хорошего" способа обхода, есть ли какое-либо обходное решение, чтобы информация, напечатанная при возникновении исключений, могла быть более полезной?

Спасибо, что прочитали.

Брайан

4b9b3361

Ответ 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', который, по крайней мере, поможет локализовать проблему.

Ответ 5

Способ избежать перехвата обезьян (который зависит от изменяющихся внутренних компонентов SDK) заключается в использовании модуля imp, который по крайней мере в настоящее время не отключен в локальной среде разработки. Затем просто загрузите _ctypes, чтобы включить лучшую отладку Jinja2:

import imp
file, pathname, description =  imp.find_module('_ctypes')
imp.load_module('_ctypes', file, pathname, description)

Ответ 6

Когда я сталкивался с подобной проблемой, я пытаюсь ее отладить в своей локальной оболочке iPython. Интересно, какой код генерирует такую ​​ошибку. Должен быть способ написать для него тест.