123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- from pathlib import Path
-
- import jinja2
-
- from django.conf import settings
- from django.template import TemplateDoesNotExist, TemplateSyntaxError
- from django.utils.functional import cached_property
- from django.utils.module_loading import import_string
-
- from .base import BaseEngine
-
-
- class Jinja2(BaseEngine):
- app_dirname = "jinja2"
-
- def __init__(self, params):
- params = params.copy()
- options = params.pop("OPTIONS").copy()
- super().__init__(params)
-
- self.context_processors = options.pop("context_processors", [])
-
- environment = options.pop("environment", "jinja2.Environment")
- environment_cls = import_string(environment)
-
- if "loader" not in options:
- options["loader"] = jinja2.FileSystemLoader(self.template_dirs)
- options.setdefault("autoescape", True)
- options.setdefault("auto_reload", settings.DEBUG)
- options.setdefault(
- "undefined", jinja2.DebugUndefined if settings.DEBUG else jinja2.Undefined
- )
-
- self.env = environment_cls(**options)
-
- def from_string(self, template_code):
- return Template(self.env.from_string(template_code), self)
-
- def get_template(self, template_name):
- try:
- return Template(self.env.get_template(template_name), self)
- except jinja2.TemplateNotFound as exc:
- raise TemplateDoesNotExist(exc.name, backend=self) from exc
- except jinja2.TemplateSyntaxError as exc:
- new = TemplateSyntaxError(exc.args)
- new.template_debug = get_exception_info(exc)
- raise new from exc
-
- @cached_property
- def template_context_processors(self):
- return [import_string(path) for path in self.context_processors]
-
-
- class Template:
- def __init__(self, template, backend):
- self.template = template
- self.backend = backend
- self.origin = Origin(
- name=template.filename,
- template_name=template.name,
- )
-
- def render(self, context=None, request=None):
- from .utils import csrf_input_lazy, csrf_token_lazy
-
- if context is None:
- context = {}
- if request is not None:
- context["request"] = request
- context["csrf_input"] = csrf_input_lazy(request)
- context["csrf_token"] = csrf_token_lazy(request)
- for context_processor in self.backend.template_context_processors:
- context.update(context_processor(request))
- try:
- return self.template.render(context)
- except jinja2.TemplateSyntaxError as exc:
- new = TemplateSyntaxError(exc.args)
- new.template_debug = get_exception_info(exc)
- raise new from exc
-
-
- class Origin:
- """
- A container to hold debug information as described in the template API
- documentation.
- """
-
- def __init__(self, name, template_name):
- self.name = name
- self.template_name = template_name
-
-
- def get_exception_info(exception):
- """
- Format exception information for display on the debug page using the
- structure described in the template API documentation.
- """
- context_lines = 10
- lineno = exception.lineno
- source = exception.source
- if source is None:
- exception_file = Path(exception.filename)
- if exception_file.exists():
- source = exception_file.read_text()
- if source is not None:
- lines = list(enumerate(source.strip().split("\n"), start=1))
- during = lines[lineno - 1][1]
- total = len(lines)
- top = max(0, lineno - context_lines - 1)
- bottom = min(total, lineno + context_lines)
- else:
- during = ""
- lines = []
- total = top = bottom = 0
- return {
- "name": exception.filename,
- "message": exception.message,
- "source_lines": lines[top:bottom],
- "line": lineno,
- "before": "",
- "during": during,
- "after": "",
- "total": total,
- "top": top,
- "bottom": bottom,
- }
|