runtime.py 28 KB

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