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