Commit 1bfcc950 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Set context.template instead of context.engine while rendering.

This opens more possibilities, like accessing context.template.origin.

It also follows the chain of objects instead of following a shortcut.
parent efb1f99f
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -204,19 +204,19 @@ class Template(object):

    def render(self, context):
        "Display stage -- can be called many times"
        # Set engine attribute here to avoid changing the signature of either
        # Context.__init__ or Node.render. The engine is set only on the first
        # call to render. Further calls e.g. for includes don't override it.
        toplevel_render = context.engine is None
        # Set context.template to the original template -- as opposed to
        # extended or included templates -- during rendering. This may be
        # used for accessing context.template.engine.
        toplevel_render = context.template is None
        if toplevel_render:
            context.engine = self.engine
            context.template = self
        context.render_context.push()
        try:
            return self._render(context)
        finally:
            context.render_context.pop()
            if toplevel_render:
                context.engine = None
                context.template = None


class Token(object):
@@ -655,7 +655,7 @@ class FilterExpression(object):
                if ignore_failures:
                    obj = None
                else:
                    string_if_invalid = context.engine.string_if_invalid
                    string_if_invalid = context.template.engine.string_if_invalid
                    if string_if_invalid:
                        if '%s' in string_if_invalid:
                            return string_if_invalid % self.var
@@ -847,7 +847,7 @@ class Variable(object):
                    if getattr(current, 'do_not_call_in_templates', False):
                        pass
                    elif getattr(current, 'alters_data', False):
                        current = context.engine.string_if_invalid
                        current = context.template.engine.string_if_invalid
                    else:
                        try:  # method call (assuming no args required)
                            current = current()
@@ -855,12 +855,12 @@ class Variable(object):
                            try:
                                getcallargs(current)
                            except TypeError:  # arguments *were* required
                                current = context.engine.string_if_invalid  # invalid method call
                                current = context.template.engine.string_if_invalid  # invalid method call
                            else:
                                raise
        except Exception as e:
            if getattr(e, 'silent_variable_failure', False):
                current = context.engine.string_if_invalid
                current = context.template.engine.string_if_invalid
            else:
                raise

@@ -1257,9 +1257,9 @@ class Library(object):
                        elif isinstance(getattr(file_name, 'template', None), Template):
                            t = file_name.template
                        elif not isinstance(file_name, six.string_types) and is_iterable(file_name):
                            t = context.engine.select_template(file_name)
                            t = context.template.engine.select_template(file_name)
                        else:
                            t = context.engine.get_template(file_name)
                            t = context.template.engine.get_template(file_name)
                        self.nodelist = t.nodelist
                    new_context = context.new(_dict)
                    # Copy across the CSRF token, if present, because
+19 −13
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ class Context(BaseContext):
    "A stack container for variable context"
    def __init__(self, dict_=None, autoescape=True,
            current_app=_current_app_undefined,
            use_l10n=None, use_tz=None, engine=None):
            use_l10n=None, use_tz=None):
        if current_app is not _current_app_undefined:
            warnings.warn(
                "The current_app argument of Context is deprecated. Use "
@@ -133,8 +133,10 @@ class Context(BaseContext):
        self._current_app = current_app
        self.use_l10n = use_l10n
        self.use_tz = use_tz
        self.engine = engine
        self.render_context = RenderContext()
        # Set to the original template during rendering -- as opposed to
        # extended or included templates
        self.template = None
        super(Context, self).__init__(dict_)

    @property
@@ -192,11 +194,11 @@ class RequestContext(Context):
    """
    def __init__(self, request, dict_=None, processors=None,
            current_app=_current_app_undefined,
            use_l10n=None, use_tz=None, engine=None):
            use_l10n=None, use_tz=None):
        # current_app isn't passed here to avoid triggering the deprecation
        # warning in Context.__init__.
        super(RequestContext, self).__init__(
            dict_, use_l10n=use_l10n, use_tz=use_tz, engine=engine)
            dict_, use_l10n=use_l10n, use_tz=use_tz)
        if current_app is not _current_app_undefined:
            warnings.warn(
                "The current_app argument of RequestContext is deprecated. "
@@ -207,23 +209,27 @@ class RequestContext(Context):
        self._processors = () if processors is None else tuple(processors)
        self._processors_index = len(self.dicts)
        self.update({})         # placeholder for context processors output
        self.engine = engine    # re-run the setter in case engine is not None

    @property
    def engine(self):
        return self._engine

    @engine.setter
    def engine(self, engine):
        self._engine = engine
    def template(self):
        return self._template

    @template.setter
    def template(self, template):
        # Execute context processors when Template.render(self, context) sets
        # context.template = self. Until then, since the context isn't tied to
        # an engine, it has no way to know which context processors to apply.
        self._template = template
        if hasattr(self, '_processors_index'):
            if engine is None:
            if template is None:
                # Unset context processors.
                self.dicts[self._processors_index] = {}
            else:
                # Set context processors for this engine.
                processors = (template.engine.template_context_processors +
                              self._processors)
                updates = {}
                for processor in engine.template_context_processors + self._processors:
                for processor in processors:
                    updates.update(processor(self.request))
                self.dicts[self._processors_index] = updates

+3 −3
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ class ForNode(Node):
                    context[self.loopvars[0]] = item
                # In debug mode provide the source of the node which raised
                # the exception
                if context.engine.debug:
                if context.template.engine.debug:
                    for node in self.nodelist_loop:
                        try:
                            nodelist.append(node.render(context))
@@ -392,7 +392,7 @@ class SsiNode(Node):
    def render(self, context):
        filepath = self.filepath.resolve(context)

        if not include_is_allowed(filepath, context.engine.allowed_include_roots):
        if not include_is_allowed(filepath, context.template.engine.allowed_include_roots):
            if settings.DEBUG:
                return "[Didn't have permission to include file]"
            else:
@@ -404,7 +404,7 @@ class SsiNode(Node):
            output = ''
        if self.parsed:
            try:
                t = Template(output, name=filepath, engine=context.engine)
                t = Template(output, name=filepath, engine=context.template.engine)
                return t.render(context)
            except TemplateSyntaxError as e:
                if settings.DEBUG:
+3 −3
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ class ExtendsNode(Node):
        if isinstance(getattr(parent, 'template', None), Template):
            # parent is a django.template.backends.django.Template
            return parent.template
        return context.engine.get_template(parent)
        return context.template.engine.get_template(parent)

    def render(self, context):
        compiled_parent = self.get_parent(context)
@@ -148,7 +148,7 @@ class IncludeNode(Node):
            # Does this quack like a Template?
            if not callable(getattr(template, 'render', None)):
                # If not, we'll try get_template
                template = context.engine.get_template(template)
                template = context.template.engine.get_template(template)
            values = {
                name: var.resolve(context)
                for name, var in six.iteritems(self.extra_context)
@@ -158,7 +158,7 @@ class IncludeNode(Node):
            with context.push(**values):
                return template.render(context)
        except Exception:
            if context.engine.debug:
            if context.template.engine.debug:
                raise
            return ''

+1 −1
Original line number Diff line number Diff line
@@ -149,7 +149,7 @@ class BlockTranslateNode(Node):
                result = translation.pgettext(message_context, singular)
            else:
                result = translation.ugettext(singular)
        default_value = context.engine.string_if_invalid
        default_value = context.template.engine.string_if_invalid

        def render_value(key):
            if key in context:
Loading