runtime.py 26 KB

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