runtime.py 27 KB

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