Fixed #24119, #24120 -- Formalized debug integration for template backends.

This commit is contained in:
Preston Timmons 2015-04-24 14:33:03 -05:00
parent d1df1fd2bb
commit adff499e47
14 changed files with 354 additions and 63 deletions

View file

@ -249,6 +249,9 @@ Templates
* The debug page template postmortem now include output from each engine that
is installed.
* :ref:`Debug page integration <template-debug-integration>` for custom
template engines was added.
Requests and Responses
^^^^^^^^^^^^^^^^^^^^^^

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -152,11 +152,32 @@ The ``django.template.loader`` module defines two functions to load templates.
If loading a template fails, the following two exceptions, defined in
``django.template``, may be raised:
.. exception:: TemplateDoesNotExist
.. exception:: TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)
This exception is raised when a template cannot be found.
This exception is raised when a template cannot be found. It accepts the
following optional arguments for populating the :ref:`template postmortem
<template-postmortem>` on the debug page:
.. exception:: TemplateSyntaxError
``backend``
The template backend instance from which the exception originated.
``tried``
A list of sources that were tried when finding the template. This is
formatted as a list of tuples containing ``(origin, status)``, where
``origin`` is an :ref:`origin-like <template-origin-api>` object and
``status`` is a string with the reason the template wasn't found.
``chain``
A list of intermediate :exc:`~django.template.TemplateDoesNotExist`
exceptions raised when trying to load a template. This is used by
functions, such as :func:`~django.template.loader.get_template`, that
try to load a given template from multiple engines.
.. versionadded:: 1.9
The ``backend``, ``tried``, and ``chain`` arguments were added.
.. exception:: TemplateSyntaxError(msg)
This exception is raised when a template was found but contains errors.
@ -478,7 +499,6 @@ fictional ``foobar`` template library::
self.engine = foobar.Engine(**options)
def from_string(self, template_code):
try:
return Template(self.engine.from_string(template_code))
@ -489,7 +509,7 @@ fictional ``foobar`` template library::
try:
return Template(self.engine.get_template(template_name))
except foobar.TemplateNotFound as exc:
raise TemplateDoesNotExist(exc.args)
raise TemplateDoesNotExist(exc.args, backend=self)
except foobar.TemplateCompilationFailed as exc:
raise TemplateSyntaxError(exc.args)
@ -510,6 +530,117 @@ fictional ``foobar`` template library::
See `DEP 182`_ for more information.
.. _template-debug-integration:
Debug integration for custom engines
------------------------------------
.. versionadded:: 1.9
Debug page integration for non-Django template engines was added.
The Django debug page has hooks to provide detailed information when a template
error arises. Custom template engines can use these hooks to enhance the
traceback information that appears to users. The following hooks are available:
.. _template-postmortem:
Template postmortem
~~~~~~~~~~~~~~~~~~~
The postmortem appears when :exc:`~django.template.TemplateDoesNotExist` is
raised. It lists the template engines and loaders that were used when trying
to find a given template. For example, if two Django engines are configured,
the postmortem will appear like:
.. image:: _images/postmortem.png
Custom engines can populate the postmortem by passing the ``backend`` and
``tried`` arguments when raising :exc:`~django.template.TemplateDoesNotExist`.
Backends that use the postmortem :ref:`should specify an origin
<template-origin-api>` on the template object.
Contextual line information
~~~~~~~~~~~~~~~~~~~~~~~~~~~
If an error happens during template parsing or rendering, Django can display
the line the error happened on. For example:
.. image:: _images/template-lines.png
Custom engines can populate this information by setting a ``template_debug``
attribute on exceptions raised during parsing and rendering. This attribute
is a :class:`dict` with the following values:
* ``'name'``: The name of the template in which the exception occurred.
* ``'message'``: The exception message.
* ``'source_lines'``: The lines before, after, and including the line the
exception occurred on. This is for context, so it shouldn't contain more than
20 lines or so.
* ``'line'``: The line number on which the exception occurred.
* ``'before'``: The content on the error line before the token that raised the
error.
* ``'during'``: The token that raised the error.
* ``'after'``: The content on the error line after the token that raised the
error.
* ``'total'``: The number of lines in ``source_lines``.
* ``'top'``: The line number where ``source_lines`` starts.
* ``'bottom'``: The line number where ``source_lines`` ends.
Given the above template error, ``template_debug`` would look like::
{
'name': '/path/to/template.html',
'message': "Invalid block tag: 'syntax'",
'source_lines': [
(1, 'some\n'),
(2, 'lines\n'),
(3, 'before\n'),
(4, 'Hello {% syntax error %} {{ world }}\n'),
(5, 'some\n'),
(6, 'lines\n'),
(7, 'after\n'),
(8, ''),
],
'line': 4,
'before': 'Hello ',
'during': '{% syntax error %}',
'after': ' {{ world }}\n',
'total': 9,
'bottom': 9,
'top': 1,
}
.. _template-origin-api:
Origin API and 3rd-party integration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Django templates have an :class:`~django.template.base.Origin` object available
through the ``template.origin`` attribute. This enables debug information to be
displayed in the :ref:`template postmortem <template-postmortem>`, as well as
in 3rd-party libraries, like the `Django Debug Toolbar`_.
Custom engines can provide their own ``template.origin`` information by
creating an object that specifies the following attributes:
* ``'name'``: The full path to the template.
* ``'template_name'``: The relative path to the template as passed into the
the template loading methods.
* ``'loader_name'``: An optional string identifying the function or class used
to load the template, e.g. ``django.template.loaders.filesystem.Loader``.
.. currentmodule:: django.template
.. _template-language-intro:
@ -687,3 +818,4 @@ Implementing a custom context processor is as simple as defining a function.
.. _Jinja2: http://jinja.pocoo.org/
.. _DEP 182: https://github.com/django/deps/blob/master/accepted/0182-multiple-template-engines.rst
.. _Django Debug Toolbar: https://github.com/django-debug-toolbar/django-debug-toolbar