1c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley# mako/template.py
2c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley# Copyright (C) 2006-2015 the Mako authors and contributors <see AUTHORS file>
3c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley#
4c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley# This module is part of Mako and is released under
5c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley# the MIT License: http://www.opensource.org/licenses/mit-license.php
6c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
7c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley"""Provides the Template class, a facade for parsing, generating and executing
8c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleytemplate strings, as well as template runtime operations."""
9c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
10c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyfrom mako.lexer import Lexer
11c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyfrom mako import runtime, util, exceptions, codegen, cache, compat
12c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport os
13c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport re
14c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport shutil
15c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport stat
16c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport sys
17c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport tempfile
18c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport types
19c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyimport weakref
20c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
21c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
22c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyclass Template(object):
23c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    """Represents a compiled template.
24c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
25c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :class:`.Template` includes a reference to the original
26c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    template source (via the :attr:`.source` attribute)
27c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    as well as the source code of the
28c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    generated Python module (i.e. the :attr:`.code` attribute),
29c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    as well as a reference to an actual Python module.
30c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
31c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :class:`.Template` is constructed using either a literal string
32c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    representing the template text, or a filename representing a filesystem
33c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    path to a source file.
34c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
35c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param text: textual template source.  This argument is mutually
36c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     exclusive versus the ``filename`` parameter.
37c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
38c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param filename: filename of the source template.  This argument is
39c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     mutually exclusive versus the ``text`` parameter.
40c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
41c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param buffer_filters: string list of filters to be applied
42c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     to the output of ``%def``\ s which are buffered, cached, or otherwise
43c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     filtered, after all filters
44c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     defined with the ``%def`` itself have been applied. Allows the
45c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     creation of default expression filters that let the output
46c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     of return-valued ``%def``\ s "opt out" of that filtering via
47c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     passing special attributes or objects.
48c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
49c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param bytestring_passthrough: When ``True``, and ``output_encoding`` is
50c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     set to ``None``, and :meth:`.Template.render` is used to render,
51c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     the `StringIO` or `cStringIO` buffer will be used instead of the
52c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     default "fast" buffer.   This allows raw bytestrings in the
53c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     output stream, such as in expressions, to pass straight
54c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     through to the buffer.  This flag is forced
55c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     to ``True`` if ``disable_unicode`` is also configured.
56c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
57c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     .. versionadded:: 0.4
58c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        Added to provide the same behavior as that of the previous series.
59c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
60c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param cache_args: Dictionary of cache configuration arguments that
61c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     will be passed to the :class:`.CacheImpl`.   See :ref:`caching_toplevel`.
62c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
63c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param cache_dir:
64c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
65c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     .. deprecated:: 0.6
66c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        Use the ``'dir'`` argument in the ``cache_args`` dictionary.
67c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        See :ref:`caching_toplevel`.
68c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
69c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param cache_enabled: Boolean flag which enables caching of this
70c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     template.  See :ref:`caching_toplevel`.
71c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
72c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param cache_impl: String name of a :class:`.CacheImpl` caching
73c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     implementation to use.   Defaults to ``'beaker'``.
74c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
75c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param cache_type:
76c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
77c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     .. deprecated:: 0.6
78c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        Use the ``'type'`` argument in the ``cache_args`` dictionary.
79c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        See :ref:`caching_toplevel`.
80c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
81c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param cache_url:
82c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
83c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     .. deprecated:: 0.6
84c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        Use the ``'url'`` argument in the ``cache_args`` dictionary.
85c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        See :ref:`caching_toplevel`.
86c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
87c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param default_filters: List of string filter names that will
88c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     be applied to all expressions.  See :ref:`filtering_default_filters`.
89c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
90c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param disable_unicode: Disables all awareness of Python Unicode
91c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     objects.  See :ref:`unicode_disabled`.
92c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
93c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param enable_loop: When ``True``, enable the ``loop`` context variable.
94c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     This can be set to ``False`` to support templates that may
95c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     be making usage of the name "``loop``".   Individual templates can
96c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     re-enable the "loop" context by placing the directive
97c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     ``enable_loop="True"`` inside the ``<%page>`` tag -- see
98c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     :ref:`migrating_loop`.
99c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
100c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param encoding_errors: Error parameter passed to ``encode()`` when
101c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     string encoding is performed. See :ref:`usage_unicode`.
102c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
103c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param error_handler: Python callable which is called whenever
104c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     compile or runtime exceptions occur. The callable is passed
105c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     the current context as well as the exception. If the
106c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     callable returns ``True``, the exception is considered to
107c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     be handled, else it is re-raised after the function
108c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     completes. Is used to provide custom error-rendering
109c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     functions.
110c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
111c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param format_exceptions: if ``True``, exceptions which occur during
112c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     the render phase of this template will be caught and
113c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     formatted into an HTML error page, which then becomes the
114c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     rendered result of the :meth:`.render` call. Otherwise,
115c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     runtime exceptions are propagated outwards.
116c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
117c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param imports: String list of Python statements, typically individual
118c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     "import" lines, which will be placed into the module level
119c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     preamble of all generated Python modules. See the example
120c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     in :ref:`filtering_default_filters`.
121c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
122c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param future_imports: String list of names to import from `__future__`.
123c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     These will be concatenated into a comma-separated string and inserted
124c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     into the beginning of the template, e.g. ``futures_imports=['FOO',
125c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     'BAR']`` results in ``from __future__ import FOO, BAR``.  If you're
126c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     interested in using features like the new division operator, you must
127c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     use future_imports to convey that to the renderer, as otherwise the
128c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     import will not appear as the first executed statement in the generated
129c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     code and will therefore not have the desired effect.
130c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
131c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param input_encoding: Encoding of the template's source code.  Can
132c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     be used in lieu of the coding comment. See
133c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     :ref:`usage_unicode` as well as :ref:`unicode_toplevel` for
134c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     details on source encoding.
135c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
136c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param lookup: a :class:`.TemplateLookup` instance that will be used
137c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     for all file lookups via the ``<%namespace>``,
138c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     ``<%include>``, and ``<%inherit>`` tags. See
139c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     :ref:`usage_templatelookup`.
140c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
141c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param module_directory: Filesystem location where generated
142c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     Python module files will be placed.
143c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
144c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param module_filename: Overrides the filename of the generated
145c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     Python module file. For advanced usage only.
146c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
147c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param module_writer: A callable which overrides how the Python
148c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     module is written entirely.  The callable is passed the
149c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     encoded source content of the module and the destination
150c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     path to be written to.   The default behavior of module writing
151c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     uses a tempfile in conjunction with a file move in order
152c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     to make the operation atomic.   So a user-defined module
153c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     writing function that mimics the default behavior would be:
154c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
155c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     .. sourcecode:: python
156c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
157c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley         import tempfile
158c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley         import os
159c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley         import shutil
160c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
161c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley         def module_writer(source, outputpath):
162c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley             (dest, name) = \\
163c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                 tempfile.mkstemp(
164c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                     dir=os.path.dirname(outputpath)
165c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                 )
166c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
167c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley             os.write(dest, source)
168c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley             os.close(dest)
169c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley             shutil.move(name, outputpath)
170c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
171c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley         from mako.template import Template
172c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley         mytemplate = Template(
173c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                         filename="index.html",
174c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                         module_directory="/path/to/modules",
175c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                         module_writer=module_writer
176c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                     )
177c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
178c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     The function is provided for unusual configurations where
179c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     certain platform-specific permissions or other special
180c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     steps are needed.
181c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
182c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param output_encoding: The encoding to use when :meth:`.render`
183c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     is called.
184c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     See :ref:`usage_unicode` as well as :ref:`unicode_toplevel`.
185c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
186c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param preprocessor: Python callable which will be passed
187c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     the full template source before it is parsed. The return
188c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     result of the callable will be used as the template source
189c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     code.
190c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
191c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param lexer_cls: A :class:`.Lexer` class used to parse
192c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     the template.   The :class:`.Lexer` class is used by
193c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     default.
194c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
195c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     .. versionadded:: 0.7.4
196c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
197c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param strict_undefined: Replaces the automatic usage of
198c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     ``UNDEFINED`` for any undeclared variables not located in
199c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     the :class:`.Context` with an immediate raise of
200c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     ``NameError``. The advantage is immediate reporting of
201c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     missing variables which include the name.
202c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
203c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     .. versionadded:: 0.3.6
204c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
205c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    :param uri: string URI or other identifier for this template.
206c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     If not provided, the ``uri`` is generated from the filesystem
207c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     path, or from the in-memory identity of a non-file-based
208c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     template. The primary usage of the ``uri`` is to provide a key
209c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     within :class:`.TemplateLookup`, as well as to generate the
210c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     file path of the generated Python module file, if
211c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     ``module_directory`` is specified.
212c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
213c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    """
214c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
215c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    lexer_cls = Lexer
216c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
217c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def __init__(self,
218c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    text=None,
219c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    filename=None,
220c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    uri=None,
221c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    format_exceptions=False,
222c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    error_handler=None,
223c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    lookup=None,
224c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    output_encoding=None,
225c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    encoding_errors='strict',
226c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    module_directory=None,
227c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    cache_args=None,
228c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    cache_impl='beaker',
229c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    cache_enabled=True,
230c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    cache_type=None,
231c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    cache_dir=None,
232c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    cache_url=None,
233c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    module_filename=None,
234c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    input_encoding=None,
235c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    disable_unicode=False,
236c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    module_writer=None,
237c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    bytestring_passthrough=False,
238c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    default_filters=None,
239c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    buffer_filters=(),
240c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    strict_undefined=False,
241c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    imports=None,
242c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    future_imports=None,
243c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    enable_loop=True,
244c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    preprocessor=None,
245c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    lexer_cls=None):
246c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if uri:
247c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.module_id = re.sub(r'\W', "_", uri)
248c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.uri = uri
249c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        elif filename:
250c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.module_id = re.sub(r'\W', "_", filename)
251c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            drive, path = os.path.splitdrive(filename)
252c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            path = os.path.normpath(path).replace(os.path.sep, "/")
253c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.uri = path
254c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
255c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.module_id = "memory:" + hex(id(self))
256c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.uri = self.module_id
257c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
258c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        u_norm = self.uri
259c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if u_norm.startswith("/"):
260c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            u_norm = u_norm[1:]
261c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        u_norm = os.path.normpath(u_norm)
262c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if u_norm.startswith(".."):
263c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            raise exceptions.TemplateLookupException(
264c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    "Template uri \"%s\" is invalid - "
265c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    "it cannot be relative outside "
266c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    "of the root path." % self.uri)
267c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
268c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.input_encoding = input_encoding
269c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.output_encoding = output_encoding
270c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.encoding_errors = encoding_errors
271c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.disable_unicode = disable_unicode
272c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.bytestring_passthrough = bytestring_passthrough or disable_unicode
273c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.enable_loop = enable_loop
274c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.strict_undefined = strict_undefined
275c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module_writer = module_writer
276c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
277c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if compat.py3k and disable_unicode:
278c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            raise exceptions.UnsupportedError(
279c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "Mako for Python 3 does not "
280c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "support disabling Unicode")
281c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        elif output_encoding and disable_unicode:
282c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            raise exceptions.UnsupportedError(
283c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "output_encoding must be set to "
284c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "None when disable_unicode is used.")
285c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if default_filters is None:
286c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            if compat.py3k or self.disable_unicode:
287c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                self.default_filters = ['str']
288c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            else:
289c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                self.default_filters = ['unicode']
290c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
291c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.default_filters = default_filters
292c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.buffer_filters = buffer_filters
293c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
294c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.imports = imports
295c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.future_imports = future_imports
296c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.preprocessor = preprocessor
297c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
298c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if lexer_cls is not None:
299c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.lexer_cls = lexer_cls
300c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
301c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        # if plain text, compile code in memory only
302c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if text is not None:
303c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            (code, module) = _compile_text(self, text, filename)
304c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self._code = code
305c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self._source = text
306c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            ModuleInfo(module, None, self, filename, code, text)
307c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        elif filename is not None:
308c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            # if template filename and a module directory, load
309c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            # a filesystem-based module file, generating if needed
310c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            if module_filename is not None:
311c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                path = module_filename
312c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            elif module_directory is not None:
313c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                path = os.path.abspath(
314c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        os.path.join(
315c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            os.path.normpath(module_directory),
316c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            u_norm + ".py"
317c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            )
318c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        )
319c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            else:
320c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                path = None
321c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            module = self._compile_from_file(path, filename)
322c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
323c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            raise exceptions.RuntimeException(
324c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                "Template requires text or filename")
325c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
326c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module = module
327c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.filename = filename
328c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.callable_ = self.module.render_body
329c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.format_exceptions = format_exceptions
330c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.error_handler = error_handler
331c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.lookup = lookup
332c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
333c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module_directory = module_directory
334c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
335c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self._setup_cache_args(
336c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            cache_impl, cache_enabled, cache_args,
337c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            cache_type, cache_dir, cache_url
338c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        )
339c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
340c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
341c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @util.memoized_property
342c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def reserved_names(self):
343c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if self.enable_loop:
344c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            return codegen.RESERVED_NAMES
345c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
346c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            return codegen.RESERVED_NAMES.difference(['loop'])
347c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
348c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def _setup_cache_args(self,
349c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                cache_impl, cache_enabled, cache_args,
350c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                cache_type, cache_dir, cache_url):
351c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.cache_impl = cache_impl
352c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.cache_enabled = cache_enabled
353c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if cache_args:
354c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.cache_args = cache_args
355c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
356c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.cache_args = {}
357c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
358c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        # transfer deprecated cache_* args
359c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if cache_type:
360c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.cache_args['type'] = cache_type
361c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if cache_dir:
362c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.cache_args['dir'] = cache_dir
363c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if cache_url:
364c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self.cache_args['url'] = cache_url
365c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
366c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def _compile_from_file(self, path, filename):
367c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if path is not None:
368c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            util.verify_directory(os.path.dirname(path))
369c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            filemtime = os.stat(filename)[stat.ST_MTIME]
370c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            if not os.path.exists(path) or \
371c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        os.stat(path)[stat.ST_MTIME] < filemtime:
372c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                data = util.read_file(filename)
373c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                _compile_module_file(
374c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            self,
375c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            data,
376c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            filename,
377c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            path,
378c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            self.module_writer)
379c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            module = compat.load_module(self.module_id, path)
380c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            del sys.modules[self.module_id]
381c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            if module._magic_number != codegen.MAGIC_NUMBER:
382c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                data = util.read_file(filename)
383c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                _compile_module_file(
384c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            self,
385c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            data,
386c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            filename,
387c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            path,
388c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            self.module_writer)
389c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                module = compat.load_module(self.module_id, path)
390c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                del sys.modules[self.module_id]
391c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            ModuleInfo(module, path, self, filename, None, None)
392c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
393c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            # template filename and no module directory, compile code
394c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            # in memory
395c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            data = util.read_file(filename)
396c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            code, module = _compile_text(
397c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                self,
398c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                data,
399c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                filename)
400c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self._source = None
401c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self._code = code
402c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            ModuleInfo(module, None, self, filename, code, None)
403c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return module
404c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
405c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
406c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def source(self):
407c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """Return the template source code for this :class:`.Template`."""
408c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
409c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return _get_module_info_from_callable(self.callable_).source
410c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
411c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
412c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def code(self):
413c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """Return the module source code for this :class:`.Template`."""
414c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
415c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return _get_module_info_from_callable(self.callable_).code
416c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
417c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @util.memoized_property
418c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def cache(self):
419c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return cache.Cache(self)
420c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
421c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
422c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def cache_dir(self):
423c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return self.cache_args['dir']
424c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
425c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def cache_url(self):
426c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return self.cache_args['url']
427c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
428c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def cache_type(self):
429c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return self.cache_args['type']
430c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
431c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def render(self, *args, **data):
432c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """Render the output of this template as a string.
433c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
434c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        If the template specifies an output encoding, the string
435c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        will be encoded accordingly, else the output is raw (raw
436c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        output uses `cStringIO` and can't handle multibyte
437c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        characters). A :class:`.Context` object is created corresponding
438c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        to the given data. Arguments that are explicitly declared
439c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        by this template's internal rendering method are also
440c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        pulled from the given ``*args``, ``**data`` members.
441c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
442c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """
443c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return runtime._render(self, self.callable_, args, data)
444c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
445c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def render_unicode(self, *args, **data):
446c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """Render the output of this template as a unicode object."""
447c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
448c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return runtime._render(self,
449c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                self.callable_,
450c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                args,
451c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                data,
452c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                as_unicode=True)
453c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
454c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def render_context(self, context, *args, **kwargs):
455c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """Render this :class:`.Template` with the given context.
456c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
457c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        The data is written to the context's buffer.
458c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
459c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """
460c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if getattr(context, '_with_template', None) is None:
461c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            context._set_with_template(self)
462c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        runtime._render_context(self,
463c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                self.callable_,
464c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                context,
465c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                *args,
466c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                **kwargs)
467c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
468c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def has_def(self, name):
469c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return hasattr(self.module, "render_%s" % name)
470c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
471c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def get_def(self, name):
472c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        """Return a def of this template as a :class:`.DefTemplate`."""
473c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
474c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return DefTemplate(self, getattr(self.module, "render_%s" % name))
475c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
476c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def _get_def_callable(self, name):
477c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return getattr(self.module, "render_%s" % name)
478c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
479c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
480c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def last_modified(self):
481c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return self.module._modified_time
482c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
483c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyclass ModuleTemplate(Template):
484c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    """A Template which is constructed given an existing Python module.
485c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
486c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        e.g.::
487c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
488c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        t = Template("this is a template")
489c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        f = file("mymodule.py", "w")
490c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        f.write(t.code)
491c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        f.close()
492c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
493c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        import mymodule
494c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
495c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        t = ModuleTemplate(mymodule)
496c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        print t.render()
497c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
498c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    """
499c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
500c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def __init__(self, module,
501c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        module_filename=None,
502c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        template=None,
503c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        template_filename=None,
504c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        module_source=None,
505c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        template_source=None,
506c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        output_encoding=None,
507c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        encoding_errors='strict',
508c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        disable_unicode=False,
509c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        bytestring_passthrough=False,
510c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        format_exceptions=False,
511c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        error_handler=None,
512c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        lookup=None,
513c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        cache_args=None,
514c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        cache_impl='beaker',
515c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        cache_enabled=True,
516c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        cache_type=None,
517c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        cache_dir=None,
518c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        cache_url=None,
519c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    ):
520c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module_id = re.sub(r'\W', "_", module._template_uri)
521c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.uri = module._template_uri
522c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.input_encoding = module._source_encoding
523c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.output_encoding = output_encoding
524c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.encoding_errors = encoding_errors
525c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.disable_unicode = disable_unicode
526c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.bytestring_passthrough = bytestring_passthrough or disable_unicode
527c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.enable_loop = module._enable_loop
528c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
529c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if compat.py3k and disable_unicode:
530c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            raise exceptions.UnsupportedError(
531c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "Mako for Python 3 does not "
532c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "support disabling Unicode")
533c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        elif output_encoding and disable_unicode:
534c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            raise exceptions.UnsupportedError(
535c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "output_encoding must be set to "
536c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    "None when disable_unicode is used.")
537c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
538c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module = module
539c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.filename = template_filename
540c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        ModuleInfo(module,
541c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        module_filename,
542c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        self,
543c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        template_filename,
544c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        module_source,
545c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        template_source)
546c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
547c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.callable_ = self.module.render_body
548c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.format_exceptions = format_exceptions
549c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.error_handler = error_handler
550c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.lookup = lookup
551c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self._setup_cache_args(
552c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            cache_impl, cache_enabled, cache_args,
553c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            cache_type, cache_dir, cache_url
554c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        )
555c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
556c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyclass DefTemplate(Template):
557c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    """A :class:`.Template` which represents a callable def in a parent
558c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    template."""
559c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
560c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def __init__(self, parent, callable_):
561c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.parent = parent
562c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.callable_ = callable_
563c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.output_encoding = parent.output_encoding
564c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module = parent.module
565c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.encoding_errors = parent.encoding_errors
566c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.format_exceptions = parent.format_exceptions
567c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.error_handler = parent.error_handler
568c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.enable_loop = parent.enable_loop
569c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.lookup = parent.lookup
570c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.bytestring_passthrough = parent.bytestring_passthrough
571c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
572c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def get_def(self, name):
573c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return self.parent.get_def(name)
574c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
575c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleyclass ModuleInfo(object):
576c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    """Stores information about a module currently loaded into
577c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    memory, provides reverse lookups of template source, module
578c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    source code based on a module's identifier.
579c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
580c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley     """
581c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    _modules = weakref.WeakValueDictionary()
582c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
583c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def __init__(self,
584c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    module,
585c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    module_filename,
586c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    template,
587c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    template_filename,
588c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    module_source,
589c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    template_source):
590c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module = module
591c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module_filename = module_filename
592c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.template_filename = template_filename
593c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.module_source = module_source
594c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self.template_source = template_source
595c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        self._modules[module.__name__] = template._mmarker = self
596c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if module_filename:
597c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            self._modules[module_filename] = self
598c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
599c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @classmethod
600c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def get_module_source_metadata(cls, module_source, full_line_map=False):
601c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        source_map = re.search(
602c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        r"__M_BEGIN_METADATA(.+?)__M_END_METADATA",
603c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        module_source, re.S).group(1)
604c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        source_map = compat.json.loads(source_map)
605c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        source_map['line_map'] = dict((int(k), int(v))
606c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                    for k, v in source_map['line_map'].items())
607c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if full_line_map:
608c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            f_line_map = source_map['full_line_map'] = []
609c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            line_map = source_map['line_map']
610c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
611c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            curr_templ_line = 1
612c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            for mod_line in range(1, max(line_map)):
613c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                if mod_line in line_map:
614c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    curr_templ_line = line_map[mod_line]
615c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                f_line_map.append(curr_templ_line)
616c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return source_map
617c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
618c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
619c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def code(self):
620c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if self.module_source is not None:
621c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            return self.module_source
622c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
623c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            return util.read_python_file(self.module_filename)
624c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
625c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    @property
626c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    def source(self):
627c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        if self.template_source is not None:
628c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            if self.module._source_encoding and \
629c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                    not isinstance(self.template_source, compat.text_type):
630c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                return self.template_source.decode(
631c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                                self.module._source_encoding)
632c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            else:
633c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                return self.template_source
634c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        else:
635c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            data = util.read_file(self.template_filename)
636c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            if self.module._source_encoding:
637c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                return data.decode(self.module._source_encoding)
638c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley            else:
639c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                return data
640c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
641c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleydef _compile(template, text, filename, generate_magic_comment):
642c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    lexer = template.lexer_cls(text,
643c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                           filename,
644c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                           disable_unicode=template.disable_unicode,
645c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                           input_encoding=template.input_encoding,
646c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                           preprocessor=template.preprocessor)
647c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    node = lexer.parse()
648c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    source = codegen.compile(node,
649c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            template.uri,
650c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            filename,
651c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            default_filters=template.default_filters,
652c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            buffer_filters=template.buffer_filters,
653c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            imports=template.imports,
654c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            future_imports=template.future_imports,
655c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            source_encoding=lexer.encoding,
656c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            generate_magic_comment=generate_magic_comment,
657c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            disable_unicode=template.disable_unicode,
658c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            strict_undefined=template.strict_undefined,
659c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            enable_loop=template.enable_loop,
660c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                            reserved_names=template.reserved_names)
661c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    return source, lexer
662c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
663c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleydef _compile_text(template, text, filename):
664c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    identifier = template.module_id
665c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    source, lexer = _compile(template, text, filename,
666c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        generate_magic_comment=template.disable_unicode)
667c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
668c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    cid = identifier
669c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    if not compat.py3k and isinstance(cid, compat.text_type):
670c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        cid = cid.encode()
671c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    module = types.ModuleType(cid)
672c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    code = compile(source, cid, 'exec')
673c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
674c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    # this exec() works for 2.4->3.3.
675c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    exec(code, module.__dict__, module.__dict__)
676c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    return (source, module)
677c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
678c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleydef _compile_module_file(template, text, filename, outputpath, module_writer):
679c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    source, lexer = _compile(template, text, filename,
680c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley                        generate_magic_comment=True)
681c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
682c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    if isinstance(source, compat.text_type):
683c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        source = source.encode(lexer.encoding or 'ascii')
684c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
685c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    if module_writer:
686c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        module_writer(source, outputpath)
687c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    else:
688c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        # make tempfiles in the same location as the ultimate
689c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        # location.   this ensures they're on the same filesystem,
690c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        # avoiding synchronization issues.
691c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        (dest, name) = tempfile.mkstemp(dir=os.path.dirname(outputpath))
692c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
693c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        os.write(dest, source)
694c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        os.close(dest)
695c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        shutil.move(name, outputpath)
696c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
697c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleydef _get_module_info_from_callable(callable_):
698c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    if compat.py3k:
699c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return _get_module_info(callable_.__globals__['__name__'])
700c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    else:
701c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley        return _get_module_info(callable_.func_globals['__name__'])
702c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
703c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowleydef _get_module_info(filename):
704c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley    return ModuleInfo._modules[filename]
705c6e67f5a9373e916a8d2333585cb5787aa5f7bb7Tim Rowley
706