1# mako/runtime.py
2# Copyright 2006-2020 the Mako authors and contributors <see AUTHORS file>
3#
4# This module is part of Mako and is released under
5# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7"""provides runtime services for templates, including Context,
8Namespace, and various helper functions."""
9
10import builtins
11import functools
12import sys
13
14from mako import compat
15from mako import exceptions
16from mako import util
17
18
19class Context:
20
21    """Provides runtime namespace, output buffer, and various
22    callstacks for templates.
23
24    See :ref:`runtime_toplevel` for detail on the usage of
25    :class:`.Context`.
26
27    """
28
29    def __init__(self, buffer, **data):
30        self._buffer_stack = [buffer]
31
32        self._data = data
33
34        self._kwargs = data.copy()
35        self._with_template = None
36        self._outputting_as_unicode = None
37        self.namespaces = {}
38
39        # "capture" function which proxies to the
40        # generic "capture" function
41        self._data["capture"] = functools.partial(capture, self)
42
43        # "caller" stack used by def calls with content
44        self.caller_stack = self._data["caller"] = CallerStack()
45
46    def _set_with_template(self, t):
47        self._with_template = t
48        illegal_names = t.reserved_names.intersection(self._data)
49        if illegal_names:
50            raise exceptions.NameConflictError(
51                "Reserved words passed to render(): %s"
52                % ", ".join(illegal_names)
53            )
54
55    @property
56    def lookup(self):
57        """Return the :class:`.TemplateLookup` associated
58        with this :class:`.Context`.
59
60        """
61        return self._with_template.lookup
62
63    @property
64    def kwargs(self):
65        """Return the dictionary of top level keyword arguments associated
66        with this :class:`.Context`.
67
68        This dictionary only includes the top-level arguments passed to
69        :meth:`.Template.render`.  It does not include names produced within
70        the template execution such as local variable names or special names
71        such as ``self``, ``next``, etc.
72
73        The purpose of this dictionary is primarily for the case that
74        a :class:`.Template` accepts arguments via its ``<%page>`` tag,
75        which are normally expected to be passed via :meth:`.Template.render`,
76        except the template is being called in an inheritance context,
77        using the ``body()`` method.   :attr:`.Context.kwargs` can then be
78        used to propagate these arguments to the inheriting template::
79
80            ${next.body(**context.kwargs)}
81
82        """
83        return self._kwargs.copy()
84
85    def push_caller(self, caller):
86        """Push a ``caller`` callable onto the callstack for
87        this :class:`.Context`."""
88
89        self.caller_stack.append(caller)
90
91    def pop_caller(self):
92        """Pop a ``caller`` callable onto the callstack for this
93        :class:`.Context`."""
94
95        del self.caller_stack[-1]
96
97    def keys(self):
98        """Return a list of all names established in this :class:`.Context`."""
99
100        return list(self._data.keys())
101
102    def __getitem__(self, key):
103        if key in self._data:
104            return self._data[key]
105        else:
106            return builtins.__dict__[key]
107
108    def _push_writer(self):
109        """push a capturing buffer onto this Context and return
110        the new writer function."""
111
112        buf = util.FastEncodingBuffer()
113        self._buffer_stack.append(buf)
114        return buf.write
115
116    def _pop_buffer_and_writer(self):
117        """pop the most recent capturing buffer from this Context
118        and return the current writer after the pop.
119
120        """
121
122        buf = self._buffer_stack.pop()
123        return buf, self._buffer_stack[-1].write
124
125    def _push_buffer(self):
126        """push a capturing buffer onto this Context."""
127
128        self._push_writer()
129
130    def _pop_buffer(self):
131        """pop the most recent capturing buffer from this Context."""
132
133        return self._buffer_stack.pop()
134
135    def get(self, key, default=None):
136        """Return a value from this :class:`.Context`."""
137
138        return self._data.get(key, builtins.__dict__.get(key, default))
139
140    def write(self, string):
141        """Write a string to this :class:`.Context` object's
142        underlying output buffer."""
143
144        self._buffer_stack[-1].write(string)
145
146    def writer(self):
147        """Return the current writer function."""
148
149        return self._buffer_stack[-1].write
150
151    def _copy(self):
152        c = Context.__new__(Context)
153        c._buffer_stack = self._buffer_stack
154        c._data = self._data.copy()
155        c._kwargs = self._kwargs
156        c._with_template = self._with_template
157        c._outputting_as_unicode = self._outputting_as_unicode
158        c.namespaces = self.namespaces
159        c.caller_stack = self.caller_stack
160        return c
161
162    def _locals(self, d):
163        """Create a new :class:`.Context` with a copy of this
164        :class:`.Context`'s current state,
165        updated with the given dictionary.
166
167        The :attr:`.Context.kwargs` collection remains
168        unaffected.
169
170
171        """
172
173        if not d:
174            return self
175        c = self._copy()
176        c._data.update(d)
177        return c
178
179    def _clean_inheritance_tokens(self):
180        """create a new copy of this :class:`.Context`. with
181        tokens related to inheritance state removed."""
182
183        c = self._copy()
184        x = c._data
185        x.pop("self", None)
186        x.pop("parent", None)
187        x.pop("next", None)
188        return c
189
190
191class CallerStack(list):
192    def __init__(self):
193        self.nextcaller = None
194
195    def __nonzero__(self):
196        return self.__bool__()
197
198    def __bool__(self):
199        return len(self) and self._get_caller() and True or False
200
201    def _get_caller(self):
202        # this method can be removed once
203        # codegen MAGIC_NUMBER moves past 7
204        return self[-1]
205
206    def __getattr__(self, key):
207        return getattr(self._get_caller(), key)
208
209    def _push_frame(self):
210        frame = self.nextcaller or None
211        self.append(frame)
212        self.nextcaller = None
213        return frame
214
215    def _pop_frame(self):
216        self.nextcaller = self.pop()
217
218
219class Undefined:
220
221    """Represents an undefined value in a template.
222
223    All template modules have a constant value
224    ``UNDEFINED`` present which is an instance of this
225    object.
226
227    """
228
229    def __str__(self):
230        raise NameError("Undefined")
231
232    def __nonzero__(self):
233        return self.__bool__()
234
235    def __bool__(self):
236        return False
237
238
239UNDEFINED = Undefined()
240STOP_RENDERING = ""
241
242
243class LoopStack:
244
245    """a stack for LoopContexts that implements the context manager protocol
246    to automatically pop off the top of the stack on context exit
247    """
248
249    def __init__(self):
250        self.stack = []
251
252    def _enter(self, iterable):
253        self._push(iterable)
254        return self._top
255
256    def _exit(self):
257        self._pop()
258        return self._top
259
260    @property
261    def _top(self):
262        if self.stack:
263            return self.stack[-1]
264        else:
265            return self
266
267    def _pop(self):
268        return self.stack.pop()
269
270    def _push(self, iterable):
271        new = LoopContext(iterable)
272        if self.stack:
273            new.parent = self.stack[-1]
274        return self.stack.append(new)
275
276    def __getattr__(self, key):
277        raise exceptions.RuntimeException("No loop context is established")
278
279    def __iter__(self):
280        return iter(self._top)
281
282
283class LoopContext:
284
285    """A magic loop variable.
286    Automatically accessible in any ``% for`` block.
287
288    See the section :ref:`loop_context` for usage
289    notes.
290
291    :attr:`parent` -> :class:`.LoopContext` or ``None``
292        The parent loop, if one exists.
293    :attr:`index` -> `int`
294        The 0-based iteration count.
295    :attr:`reverse_index` -> `int`
296        The number of iterations remaining.
297    :attr:`first` -> `bool`
298        ``True`` on the first iteration, ``False`` otherwise.
299    :attr:`last` -> `bool`
300        ``True`` on the last iteration, ``False`` otherwise.
301    :attr:`even` -> `bool`
302        ``True`` when ``index`` is even.
303    :attr:`odd` -> `bool`
304        ``True`` when ``index`` is odd.
305    """
306
307    def __init__(self, iterable):
308        self._iterable = iterable
309        self.index = 0
310        self.parent = None
311
312    def __iter__(self):
313        for i in self._iterable:
314            yield i
315            self.index += 1
316
317    @util.memoized_instancemethod
318    def __len__(self):
319        return len(self._iterable)
320
321    @property
322    def reverse_index(self):
323        return len(self) - self.index - 1
324
325    @property
326    def first(self):
327        return self.index == 0
328
329    @property
330    def last(self):
331        return self.index == len(self) - 1
332
333    @property
334    def even(self):
335        return not self.odd
336
337    @property
338    def odd(self):
339        return bool(self.index % 2)
340
341    def cycle(self, *values):
342        """Cycle through values as the loop progresses."""
343        if not values:
344            raise ValueError("You must provide values to cycle through")
345        return values[self.index % len(values)]
346
347
348class _NSAttr:
349    def __init__(self, parent):
350        self.__parent = parent
351
352    def __getattr__(self, key):
353        ns = self.__parent
354        while ns:
355            if hasattr(ns.module, key):
356                return getattr(ns.module, key)
357            else:
358                ns = ns.inherits
359        raise AttributeError(key)
360
361
362class Namespace:
363
364    """Provides access to collections of rendering methods, which
365    can be local, from other templates, or from imported modules.
366
367    To access a particular rendering method referenced by a
368    :class:`.Namespace`, use plain attribute access:
369
370    .. sourcecode:: mako
371
372      ${some_namespace.foo(x, y, z)}
373
374    :class:`.Namespace` also contains several built-in attributes
375    described here.
376
377    """
378
379    def __init__(
380        self,
381        name,
382        context,
383        callables=None,
384        inherits=None,
385        populate_self=True,
386        calling_uri=None,
387    ):
388        self.name = name
389        self.context = context
390        self.inherits = inherits
391        if callables is not None:
392            self.callables = {c.__name__: c for c in callables}
393
394    callables = ()
395
396    module = None
397    """The Python module referenced by this :class:`.Namespace`.
398
399    If the namespace references a :class:`.Template`, then
400    this module is the equivalent of ``template.module``,
401    i.e. the generated module for the template.
402
403    """
404
405    template = None
406    """The :class:`.Template` object referenced by this
407        :class:`.Namespace`, if any.
408
409    """
410
411    context = None
412    """The :class:`.Context` object for this :class:`.Namespace`.
413
414    Namespaces are often created with copies of contexts that
415    contain slightly different data, particularly in inheritance
416    scenarios. Using the :class:`.Context` off of a :class:`.Namespace` one
417    can traverse an entire chain of templates that inherit from
418    one-another.
419
420    """
421
422    filename = None
423    """The path of the filesystem file used for this
424    :class:`.Namespace`'s module or template.
425
426    If this is a pure module-based
427    :class:`.Namespace`, this evaluates to ``module.__file__``. If a
428    template-based namespace, it evaluates to the original
429    template file location.
430
431    """
432
433    uri = None
434    """The URI for this :class:`.Namespace`'s template.
435
436    I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
437
438    This is the equivalent of :attr:`.Template.uri`.
439
440    """
441
442    _templateuri = None
443
444    @util.memoized_property
445    def attr(self):
446        """Access module level attributes by name.
447
448        This accessor allows templates to supply "scalar"
449        attributes which are particularly handy in inheritance
450        relationships.
451
452        .. seealso::
453
454            :ref:`inheritance_attr`
455
456            :ref:`namespace_attr_for_includes`
457
458        """
459        return _NSAttr(self)
460
461    def get_namespace(self, uri):
462        """Return a :class:`.Namespace` corresponding to the given ``uri``.
463
464        If the given ``uri`` is a relative URI (i.e. it does not
465        contain a leading slash ``/``), the ``uri`` is adjusted to
466        be relative to the ``uri`` of the namespace itself. This
467        method is therefore mostly useful off of the built-in
468        ``local`` namespace, described in :ref:`namespace_local`.
469
470        In
471        most cases, a template wouldn't need this function, and
472        should instead use the ``<%namespace>`` tag to load
473        namespaces. However, since all ``<%namespace>`` tags are
474        evaluated before the body of a template ever runs,
475        this method can be used to locate namespaces using
476        expressions that were generated within the body code of
477        the template, or to conditionally use a particular
478        namespace.
479
480        """
481        key = (self, uri)
482        if key in self.context.namespaces:
483            return self.context.namespaces[key]
484        ns = TemplateNamespace(
485            uri,
486            self.context._copy(),
487            templateuri=uri,
488            calling_uri=self._templateuri,
489        )
490        self.context.namespaces[key] = ns
491        return ns
492
493    def get_template(self, uri):
494        """Return a :class:`.Template` from the given ``uri``.
495
496        The ``uri`` resolution is relative to the ``uri`` of this
497        :class:`.Namespace` object's :class:`.Template`.
498
499        """
500        return _lookup_template(self.context, uri, self._templateuri)
501
502    def get_cached(self, key, **kwargs):
503        """Return a value from the :class:`.Cache` referenced by this
504        :class:`.Namespace` object's :class:`.Template`.
505
506        The advantage to this method versus direct access to the
507        :class:`.Cache` is that the configuration parameters
508        declared in ``<%page>`` take effect here, thereby calling
509        up the same configured backend as that configured
510        by ``<%page>``.
511
512        """
513
514        return self.cache.get(key, **kwargs)
515
516    @property
517    def cache(self):
518        """Return the :class:`.Cache` object referenced
519        by this :class:`.Namespace` object's
520        :class:`.Template`.
521
522        """
523        return self.template.cache
524
525    def include_file(self, uri, **kwargs):
526        """Include a file at the given ``uri``."""
527
528        _include_file(self.context, uri, self._templateuri, **kwargs)
529
530    def _populate(self, d, l):
531        for ident in l:
532            if ident == "*":
533                for k, v in self._get_star():
534                    d[k] = v
535            else:
536                d[ident] = getattr(self, ident)
537
538    def _get_star(self):
539        if self.callables:
540            for key in self.callables:
541                yield (key, self.callables[key])
542
543    def __getattr__(self, key):
544        if key in self.callables:
545            val = self.callables[key]
546        elif self.inherits:
547            val = getattr(self.inherits, key)
548        else:
549            raise AttributeError(
550                "Namespace '%s' has no member '%s'" % (self.name, key)
551            )
552        setattr(self, key, val)
553        return val
554
555
556class TemplateNamespace(Namespace):
557
558    """A :class:`.Namespace` specific to a :class:`.Template` instance."""
559
560    def __init__(
561        self,
562        name,
563        context,
564        template=None,
565        templateuri=None,
566        callables=None,
567        inherits=None,
568        populate_self=True,
569        calling_uri=None,
570    ):
571        self.name = name
572        self.context = context
573        self.inherits = inherits
574        if callables is not None:
575            self.callables = {c.__name__: c for c in callables}
576
577        if templateuri is not None:
578            self.template = _lookup_template(context, templateuri, calling_uri)
579            self._templateuri = self.template.module._template_uri
580        elif template is not None:
581            self.template = template
582            self._templateuri = template.module._template_uri
583        else:
584            raise TypeError("'template' argument is required.")
585
586        if populate_self:
587            lclcallable, lclcontext = _populate_self_namespace(
588                context, self.template, self_ns=self
589            )
590
591    @property
592    def module(self):
593        """The Python module referenced by this :class:`.Namespace`.
594
595        If the namespace references a :class:`.Template`, then
596        this module is the equivalent of ``template.module``,
597        i.e. the generated module for the template.
598
599        """
600        return self.template.module
601
602    @property
603    def filename(self):
604        """The path of the filesystem file used for this
605        :class:`.Namespace`'s module or template.
606        """
607        return self.template.filename
608
609    @property
610    def uri(self):
611        """The URI for this :class:`.Namespace`'s template.
612
613        I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
614
615        This is the equivalent of :attr:`.Template.uri`.
616
617        """
618        return self.template.uri
619
620    def _get_star(self):
621        if self.callables:
622            for key in self.callables:
623                yield (key, self.callables[key])
624
625        def get(key):
626            callable_ = self.template._get_def_callable(key)
627            return functools.partial(callable_, self.context)
628
629        for k in self.template.module._exports:
630            yield (k, get(k))
631
632    def __getattr__(self, key):
633        if key in self.callables:
634            val = self.callables[key]
635        elif self.template.has_def(key):
636            callable_ = self.template._get_def_callable(key)
637            val = functools.partial(callable_, self.context)
638        elif self.inherits:
639            val = getattr(self.inherits, key)
640
641        else:
642            raise AttributeError(
643                "Namespace '%s' has no member '%s'" % (self.name, key)
644            )
645        setattr(self, key, val)
646        return val
647
648
649class ModuleNamespace(Namespace):
650
651    """A :class:`.Namespace` specific to a Python module instance."""
652
653    def __init__(
654        self,
655        name,
656        context,
657        module,
658        callables=None,
659        inherits=None,
660        populate_self=True,
661        calling_uri=None,
662    ):
663        self.name = name
664        self.context = context
665        self.inherits = inherits
666        if callables is not None:
667            self.callables = {c.__name__: c for c in callables}
668
669        mod = __import__(module)
670        for token in module.split(".")[1:]:
671            mod = getattr(mod, token)
672        self.module = mod
673
674    @property
675    def filename(self):
676        """The path of the filesystem file used for this
677        :class:`.Namespace`'s module or template.
678        """
679        return self.module.__file__
680
681    def _get_star(self):
682        if self.callables:
683            for key in self.callables:
684                yield (key, self.callables[key])
685        for key in dir(self.module):
686            if key[0] != "_":
687                callable_ = getattr(self.module, key)
688                if callable(callable_):
689                    yield key, functools.partial(callable_, self.context)
690
691    def __getattr__(self, key):
692        if key in self.callables:
693            val = self.callables[key]
694        elif hasattr(self.module, key):
695            callable_ = getattr(self.module, key)
696            val = functools.partial(callable_, self.context)
697        elif self.inherits:
698            val = getattr(self.inherits, key)
699        else:
700            raise AttributeError(
701                "Namespace '%s' has no member '%s'" % (self.name, key)
702            )
703        setattr(self, key, val)
704        return val
705
706
707def supports_caller(func):
708    """Apply a caller_stack compatibility decorator to a plain
709    Python function.
710
711    See the example in :ref:`namespaces_python_modules`.
712
713    """
714
715    def wrap_stackframe(context, *args, **kwargs):
716        context.caller_stack._push_frame()
717        try:
718            return func(context, *args, **kwargs)
719        finally:
720            context.caller_stack._pop_frame()
721
722    return wrap_stackframe
723
724
725def capture(context, callable_, *args, **kwargs):
726    """Execute the given template def, capturing the output into
727    a buffer.
728
729    See the example in :ref:`namespaces_python_modules`.
730
731    """
732
733    if not callable(callable_):
734        raise exceptions.RuntimeException(
735            "capture() function expects a callable as "
736            "its argument (i.e. capture(func, *args, **kwargs))"
737        )
738    context._push_buffer()
739    try:
740        callable_(*args, **kwargs)
741    finally:
742        buf = context._pop_buffer()
743    return buf.getvalue()
744
745
746def _decorate_toplevel(fn):
747    def decorate_render(render_fn):
748        def go(context, *args, **kw):
749            def y(*args, **kw):
750                return render_fn(context, *args, **kw)
751
752            try:
753                y.__name__ = render_fn.__name__[7:]
754            except TypeError:
755                # < Python 2.4
756                pass
757            return fn(y)(context, *args, **kw)
758
759        return go
760
761    return decorate_render
762
763
764def _decorate_inline(context, fn):
765    def decorate_render(render_fn):
766        dec = fn(render_fn)
767
768        def go(*args, **kw):
769            return dec(context, *args, **kw)
770
771        return go
772
773    return decorate_render
774
775
776def _include_file(context, uri, calling_uri, **kwargs):
777    """locate the template from the given uri and include it in
778    the current output."""
779
780    template = _lookup_template(context, uri, calling_uri)
781    (callable_, ctx) = _populate_self_namespace(
782        context._clean_inheritance_tokens(), template
783    )
784    kwargs = _kwargs_for_include(callable_, context._data, **kwargs)
785    if template.include_error_handler:
786        try:
787            callable_(ctx, **kwargs)
788        except Exception:
789            result = template.include_error_handler(ctx, compat.exception_as())
790            if not result:
791                raise
792    else:
793        callable_(ctx, **kwargs)
794
795
796def _inherit_from(context, uri, calling_uri):
797    """called by the _inherit method in template modules to set
798    up the inheritance chain at the start of a template's
799    execution."""
800
801    if uri is None:
802        return None
803    template = _lookup_template(context, uri, calling_uri)
804    self_ns = context["self"]
805    ih = self_ns
806    while ih.inherits is not None:
807        ih = ih.inherits
808    lclcontext = context._locals({"next": ih})
809    ih.inherits = TemplateNamespace(
810        "self:%s" % template.uri,
811        lclcontext,
812        template=template,
813        populate_self=False,
814    )
815    context._data["parent"] = lclcontext._data["local"] = ih.inherits
816    callable_ = getattr(template.module, "_mako_inherit", None)
817    if callable_ is not None:
818        ret = callable_(template, lclcontext)
819        if ret:
820            return ret
821
822    gen_ns = getattr(template.module, "_mako_generate_namespaces", None)
823    if gen_ns is not None:
824        gen_ns(context)
825    return (template.callable_, lclcontext)
826
827
828def _lookup_template(context, uri, relativeto):
829    lookup = context._with_template.lookup
830    if lookup is None:
831        raise exceptions.TemplateLookupException(
832            "Template '%s' has no TemplateLookup associated"
833            % context._with_template.uri
834        )
835    uri = lookup.adjust_uri(uri, relativeto)
836    try:
837        return lookup.get_template(uri)
838    except exceptions.TopLevelLookupException as e:
839        raise exceptions.TemplateLookupException(
840            str(compat.exception_as())
841        ) from e
842
843
844def _populate_self_namespace(context, template, self_ns=None):
845    if self_ns is None:
846        self_ns = TemplateNamespace(
847            "self:%s" % template.uri,
848            context,
849            template=template,
850            populate_self=False,
851        )
852    context._data["self"] = context._data["local"] = self_ns
853    if hasattr(template.module, "_mako_inherit"):
854        ret = template.module._mako_inherit(template, context)
855        if ret:
856            return ret
857    return (template.callable_, context)
858
859
860def _render(template, callable_, args, data, as_unicode=False):
861    """create a Context and return the string
862    output of the given template and template callable."""
863
864    if as_unicode:
865        buf = util.FastEncodingBuffer()
866    else:
867        buf = util.FastEncodingBuffer(
868            encoding=template.output_encoding, errors=template.encoding_errors
869        )
870    context = Context(buf, **data)
871    context._outputting_as_unicode = as_unicode
872    context._set_with_template(template)
873
874    _render_context(
875        template,
876        callable_,
877        context,
878        *args,
879        **_kwargs_for_callable(callable_, data),
880    )
881    return context._pop_buffer().getvalue()
882
883
884def _kwargs_for_callable(callable_, data):
885    argspec = compat.inspect_getargspec(callable_)
886    # for normal pages, **pageargs is usually present
887    if argspec[2]:
888        return data
889
890    # for rendering defs from the top level, figure out the args
891    namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
892    kwargs = {}
893    for arg in namedargs:
894        if arg != "context" and arg in data and arg not in kwargs:
895            kwargs[arg] = data[arg]
896    return kwargs
897
898
899def _kwargs_for_include(callable_, data, **kwargs):
900    argspec = compat.inspect_getargspec(callable_)
901    namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
902    for arg in namedargs:
903        if arg != "context" and arg in data and arg not in kwargs:
904            kwargs[arg] = data[arg]
905    return kwargs
906
907
908def _render_context(tmpl, callable_, context, *args, **kwargs):
909    import mako.template as template
910
911    # create polymorphic 'self' namespace for this
912    # template with possibly updated context
913    if not isinstance(tmpl, template.DefTemplate):
914        # if main render method, call from the base of the inheritance stack
915        (inherit, lclcontext) = _populate_self_namespace(context, tmpl)
916        _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
917    else:
918        # otherwise, call the actual rendering method specified
919        (inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent)
920        _exec_template(callable_, context, args=args, kwargs=kwargs)
921
922
923def _exec_template(callable_, context, args=None, kwargs=None):
924    """execute a rendering callable given the callable, a
925    Context, and optional explicit arguments
926
927    the contextual Template will be located if it exists, and
928    the error handling options specified on that Template will
929    be interpreted here.
930    """
931    template = context._with_template
932    if template is not None and (
933        template.format_exceptions or template.error_handler
934    ):
935        try:
936            callable_(context, *args, **kwargs)
937        except Exception:
938            _render_error(template, context, compat.exception_as())
939        except:
940            e = sys.exc_info()[0]
941            _render_error(template, context, e)
942    else:
943        callable_(context, *args, **kwargs)
944
945
946def _render_error(template, context, error):
947    if template.error_handler:
948        result = template.error_handler(context, error)
949        if not result:
950            tp, value, tb = sys.exc_info()
951            if value and tb:
952                raise value.with_traceback(tb)
953            else:
954                raise error
955    else:
956        error_template = exceptions.html_error_template()
957        if context._outputting_as_unicode:
958            context._buffer_stack[:] = [util.FastEncodingBuffer()]
959        else:
960            context._buffer_stack[:] = [
961                util.FastEncodingBuffer(
962                    error_template.output_encoding,
963                    error_template.encoding_errors,
964                )
965            ]
966
967        context._set_with_template(error_template)
968        error_template.render_context(context, error=error)
969