runtime.py 26 KB

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