summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2011-01-19 10:33:00 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2011-01-19 10:33:00 -0500
commit6779081b32cfb237062da8bc623a27d47301ce4c (patch)
treefc3372c916cfc9efc61cccffde74528772532b37
parent76e622b46ef71eddfbcd1232ee08b4e55c88c363 (diff)
downloadmako-6779081b32cfb237062da8bc623a27d47301ce4c.tar.gz
- now that trailing whitespace comes up in red, need to get rid of it
-rw-r--r--CHANGES72
-rw-r--r--README4
-rw-r--r--README.py3k4
-rw-r--r--doc/build/builder/builders.py14
-rw-r--r--doc/build/builder/util.py4
-rw-r--r--doc/build/caching.rst22
-rw-r--r--doc/build/defs.rst40
-rw-r--r--doc/build/filtering.rst46
-rw-r--r--doc/build/index.rst4
-rw-r--r--doc/build/inheritance.rst46
-rw-r--r--doc/build/namespaces.rst40
-rw-r--r--doc/build/runtime.rst6
-rw-r--r--doc/build/static/docs.css4
-rw-r--r--doc/build/syntax.rst38
-rw-r--r--doc/build/templates/genindex.mako2
-rw-r--r--doc/build/templates/layout.mako8
-rw-r--r--doc/build/unicode.rst22
-rw-r--r--doc/build/usage.rst68
-rw-r--r--examples/bench/basic.py2
-rw-r--r--examples/bench/cheetah/template.tmpl4
-rw-r--r--examples/bench/kid/template.kid2
-rw-r--r--examples/bench/mako/template.html4
-rw-r--r--examples/bench/mako_inheritance/base.html2
-rw-r--r--examples/bench/mako_inheritance/template.html2
-rw-r--r--examples/wsgi/htdocs/index.html2
-rw-r--r--examples/wsgi/run_wsgi.py4
-rw-r--r--mako/ast.py22
-rw-r--r--mako/cache.py54
-rw-r--r--mako/codegen.py202
-rw-r--r--mako/exceptions.py44
-rw-r--r--mako/ext/autohandler.py4
-rw-r--r--mako/ext/preprocessors.py4
-rw-r--r--mako/ext/turbogears.py2
-rw-r--r--mako/filters.py14
-rw-r--r--mako/lexer.py66
-rw-r--r--mako/lookup.py90
-rw-r--r--mako/parsetree.py106
-rw-r--r--mako/pygen.py86
-rw-r--r--mako/pyparser.py4
-rw-r--r--mako/runtime.py176
-rw-r--r--mako/template.py128
-rw-r--r--mako/util.py40
-rw-r--r--setup.py2
-rw-r--r--test/__init__.py20
-rw-r--r--test/foo/test_ns.py2
-rw-r--r--test/sample_module_namespace.py2
-rw-r--r--test/templates/gettext.mako4
-rw-r--r--test/templates/internationalization.html4
-rw-r--r--test/test_ast.py46
-rw-r--r--test/test_babelplugin.py4
-rw-r--r--test/test_cache.py44
-rw-r--r--test/test_call.py54
-rw-r--r--test/test_decorators.py10
-rw-r--r--test/test_def.py80
-rw-r--r--test/test_exceptions.py26
-rw-r--r--test/test_filters.py46
-rw-r--r--test/test_inheritance.py26
-rw-r--r--test/test_lexer.py34
-rw-r--r--test/test_lookup.py14
-rw-r--r--test/test_lru.py34
-rw-r--r--test/test_namespace.py114
-rw-r--r--test/test_pygen.py6
-rw-r--r--test/test_template.py132
-rw-r--r--test/test_tgplugin.py2
64 files changed, 1107 insertions, 1107 deletions
diff --git a/CHANGES b/CHANGES
index 0eb73e4..c993ad6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -19,12 +19,12 @@
- Patch to lexer to not generate an empty
'' write in the case of backslash-ended
lines. [ticket:155]
-
+
- Fixed missing **extra collection in
setup.py which prevented setup.py
from running 2to3 on install.
[ticket:148]
-
+
- New flag on Template, TemplateLookup -
strict_undefined=True, will cause
variables not found in the context to
@@ -44,7 +44,7 @@
a little bit of tinkering in the AST code,
which hadn't really been touched for
a couple of years, just FYI.
-
+
0.3.5
- The <%namespace> tag allows expressions
for the `file` argument, i.e. with ${}.
@@ -55,7 +55,7 @@
- ${} expressions embedded in tags,
such as <%foo:bar x="${...}">, now
allow multiline Python expressions.
-
+
- Fixed previously non-covered regular
expression, such that using a ${} expression
inside of a tag element that doesn't allow
@@ -67,7 +67,7 @@
[ticket:151] No idea whatsoever if the
install_requires in setup.py also breaks GAE,
couldn't get an answer on this.
-
+
0.3.4
- Now using MarkupSafe for HTML escaping,
i.e. in place of cgi.escape(). Faster
@@ -75,19 +75,19 @@
single quotes for additional security.
Supports the __html__ attribute for
the given expression as well.
-
+
When using "disable_unicode" mode,
a pure Python HTML escaper function
is used which also quotes single quotes.
-
+
Note that Pylons by default doesn't
use Mako's filter - check your
environment.py file.
-
+
- Fixed call to "unicode.strip" in
exceptions.text_error_template which
is not Py3k compatible. [ticket:137]
-
+
0.3.3
- Added conditional to RichTraceback
such that if no traceback is passed
@@ -95,7 +95,7 @@
the formatter just returns blank
for the "traceback" portion.
[ticket:135]
-
+
- Fixed sometimes incorrect usage of
exc.__class__.__name__
in html/text error templates when using
@@ -116,15 +116,15 @@
files share the same filesystem, thus
avoiding cross-filesystem synchronization
issues. Thanks to Charles Cazabon.
-
+
0.3.2
- Calling a def from the top, via
template.get_def(...).render() now checks the
argument signature the same way as it did in
0.2.5, so that TypeError is not raised.
reopen of [ticket:116]
-
-
+
+
0.3.1
- Fixed incorrect dir name in setup.py
[ticket:129]
@@ -135,7 +135,7 @@
- Python 3 support is added ! See README.py3k
for installation and testing notes.
[ticket:119]
-
+
- Unit tests now run with nose. [ticket:127]
- Source code escaping has been simplified.
@@ -151,7 +151,7 @@
text_error_template().render() now accept "error"
and "traceback" as optional arguments, and
these are now actually used. [ticket:122]
-
+
- The exception output generated when
format_exceptions=True will now be as a Python
unicode if it occurred during render_unicode(),
@@ -186,7 +186,7 @@
a given path that is a directory, not a filename,
instead of passing through to the template to
generate IOError. [ticket:73]
-
+
0.2.6
- Fix mako function decorators to preserve the
@@ -214,11 +214,11 @@
scenarios. Note that the mode is always
subject to the restrictions of the existing
umask. [ticket:101]
-
+
- Fixed namespace.__getattr__() to raise
AttributeError on attribute not found
instead of RuntimeError. [ticket:104]
-
+
- Added last_modified accessor to Template,
returns the time.time() when the module
was created. [ticket:97]
@@ -233,7 +233,7 @@
- added "mako.__version__" attribute to
the base module. [ticket:110]
-
+
0.2.4
- Fixed compatibility with Jython 2.5b1.
@@ -248,7 +248,7 @@
nested. Many examples of the new syntax are in the
"Calling a def with embedded content" section
of the docs.
-
+
- added support for Jython 2.5.
- cache module now uses Beaker's CacheManager
@@ -265,7 +265,7 @@
operations to "pass through" and execute every time;
this flag should be integrated in Pylons with its own
cache_enabled configuration setting.
-
+
- the Cache object now supports invalidate_def(name),
invalidate_body(), invalidate_closure(name),
invalidate(key), which will remove the given key
@@ -286,7 +286,7 @@
- fixed bug whereby an <%included> template with
<%page> args named the same as a __builtin__ would not
honor the default value specified in <%page> [ticket:93]
-
+
- fixed the html_error_template not handling tracebacks from
normal .py files with a magic encoding comment [ticket:88]
@@ -295,7 +295,7 @@
and text_error_template() accept an optional
render()-time argument "traceback" which is passed to the
RichTraceback object.
-
+
- added ModuleTemplate class, which allows the construction
of a Template given a Python module generated by a previous
Template. This allows Python modules alone to be used
@@ -347,18 +347,18 @@ help with memcached.
template variable. This affords a 12-30% speedup in
template render time. (idea courtesy same anonymous
guest) [ticket:76]
-
+
- New Features, API changes:
- added "attr" accessor to namespaces. Returns
attributes configured as module level attributes, i.e.
within <%! %> sections. [ticket:62] i.e.:
-
+
# somefile.html
<%!
foo = 27
%>
-
+
# some other template
<%namespace name="myns" file="somefile.html"/>
${myns.attr.foo}
@@ -366,7 +366,7 @@ help with memcached.
The slight backwards incompatibility here is, you
can't have namespace defs named "attr" since the
"attr" descriptor will occlude it.
-
+
- cache_key argument can now render arguments passed
directly to the %page or %def, i.e. <%def
name="foo(x)" cached="True" cache_key="${x}"/>
@@ -379,15 +379,15 @@ help with memcached.
- added a runner script "mako-render" which renders
standard input as a template to stdout [ticket:81]
[ticket:56]
-
+
- Bugfixes:
- can now use most names from __builtins__ as variable
names without explicit declaration (i.e. 'id',
'exception', 'range', etc.) [ticket:83] [ticket:84]
-
+
- can also use builtin names as local variable names
(i.e. dict, locals) (came from fix for [ticket:84])
-
+
- fixed bug in python generation when variable names are
used with identifiers like "else", "finally", etc.
inside them [ticket:68]
@@ -402,10 +402,10 @@ help with memcached.
- fixed issue with inline format_exceptions that was
producing blank exception pages when an inheriting
template is present [ticket:71]
-
+
- format_exceptions will apply the encoding options of
html_error_template() to the buffered output
-
+
- rewrote the "whitespace adjuster" function to work
with more elaborate combinations of quotes and
comments [ticket:75]
@@ -421,7 +421,7 @@ help with memcached.
- fixed another namespace bug where the namespace functions
did not have access to the correct context containing
their 'self' and 'parent'
-
+
0.1.9
- filters.Decode filter can also accept a non-basestring
object and will call str() + unicode() on it [ticket:47]
@@ -481,7 +481,7 @@ python 2.3 installations
lines (#32)
- fixed codegen bug when defining <%def> within <%call> within <%call>
- leading utf-8 BOM in template files is honored according to pep-0263
-
+
0.1.5
- AST expression generation - added in just about everything
expression-wise from the AST module [ticket:26]
@@ -497,7 +497,7 @@ of buffered/cached/filtered %defs, after all filters defined with the %def
itself have been applied. allows the creation of default expression filters
that let the output of return-valued %defs "opt out" of that filtering
via passing special attributes or objects.
-
+
0.1.4
- got defs-within-defs to be cacheable
- fixes to code parsing/whitespace adjusting where plain python comments
@@ -537,7 +537,7 @@ either one "#" sign or two for now; two is preferred going forward, i.e.
- added mako.ext.preprocessors package, contains one preprocessor so far:
'convert_comments', which will convert single # comments to the new ##
format
-
+
0.1.2
- fix to parsing of code/expression blocks to insure that non-ascii
characters, combined with a template that indicates a non-standard
diff --git a/README b/README
index 224c744..1930412 100644
--- a/README
+++ b/README
@@ -7,14 +7,14 @@ To install:
python setup.py install
SVN checkouts also inlcude setup.cfg file allowing setuptools to create
-an svn-tagged build.
+an svn-tagged build.
Documentation is available in HTML format in the ./doc/ directory.
Unit tests run via nose, and are available via setup.py:
python setup.py test
-
+
Or direct nose usage:
nosetests -v
diff --git a/README.py3k b/README.py3k
index c5329eb..73e0190 100644
--- a/README.py3k
+++ b/README.py3k
@@ -18,7 +18,7 @@ install Distribute:
Installing Mako in Python 3
---------------------------------
-Once Distribute is installed, Mako can be installed directly.
+Once Distribute is installed, Mako can be installed directly.
The 2to3 process will kick in which takes several minutes:
python3 setup.py install
@@ -35,7 +35,7 @@ If using 3.1's 2to3 tool, the --no-diffs flag might help
with unicode issues:
2to3-3.1 -w --no-diffs mako test
-
+
The above will rewrite all files in-place in Python 3 format.
Running Tests
diff --git a/doc/build/builder/builders.py b/doc/build/builder/builders.py
index afe2a21..89eb350 100644
--- a/doc/build/builder/builders.py
+++ b/doc/build/builder/builders.py
@@ -15,14 +15,14 @@ from mako.ext.pygmentplugin import MakoLexer
class MakoBridge(TemplateBridge):
def init(self, builder, *args, **kw):
self.layout = builder.config.html_context.get('mako_layout', 'html')
-
+
self.lookup = TemplateLookup(directories=builder.config.templates_path,
format_exceptions=True,
imports=[
"from builder import util"
]
)
-
+
def render(self, template, context):
template = template.replace(".html", ".mako")
context['prevtopic'] = context.pop('prev', None)
@@ -31,8 +31,8 @@ class MakoBridge(TemplateBridge):
# sphinx 1.0b2 doesn't seem to be providing _ for some reason...
context.setdefault('_', lambda x:x)
return self.lookup.get_template(template).render_unicode(**context)
-
-
+
+
def render_string(self, template, context):
context['prevtopic'] = context.pop('prev', None)
context['nexttopic'] = context.pop('next', None)
@@ -45,7 +45,7 @@ class MakoBridge(TemplateBridge):
"from builder import util"
]
).render_unicode(**context)
-
+
class StripDocTestFilter(Filter):
def filter(self, lexer, stream):
for ttype, value in stream:
@@ -65,5 +65,5 @@ def setup(app):
# Mako is already in Pygments, adding the local
# lexer here so that the latest syntax is available
app.add_lexer('mako', MakoLexer())
-
- \ No newline at end of file
+
+ \ No newline at end of file
diff --git a/doc/build/builder/util.py b/doc/build/builder/util.py
index dc2e272..75a5c72 100644
--- a/doc/build/builder/util.py
+++ b/doc/build/builder/util.py
@@ -6,7 +6,7 @@ def striptags(text):
def go(m):
# .html with no anchor if present, otherwise "#" for top of page
return m.group(1) or '#'
-
+
def strip_toplevel_anchors(text):
return re.compile(r'(\.html)?#[-\w]+-toplevel').sub(go, text)
-
+
diff --git a/doc/build/caching.rst b/doc/build/caching.rst
index 0620d32..6cf7197 100644
--- a/doc/build/caching.rst
+++ b/doc/build/caching.rst
@@ -10,9 +10,9 @@ argument to the ``<%page>`` or ``<%def>`` directives:
.. sourcecode:: mako
<%page cached="True"/>
-
+
template text
-
+
The above template, after being executed the first time, will
store its content within a cache that by default is scoped
within memory. Subsequent calls to the template's :meth:`~.Template.render`
@@ -64,7 +64,7 @@ The options available are:
``module_directory`` is used (i.e. the directory where compiled
template modules are stored). If neither option is available
an exception is thrown.
-
+
In the case of the ``memcached`` type, this attribute is required
and it's used to store the lock files.
* ``cache_key`` - the "key" used to uniquely identify this content
@@ -75,15 +75,15 @@ The options available are:
the value of the key on the fly. For example, heres a page
that caches any page which inherits from it, based on the
filename of the calling template:
-
+
.. sourcecode:: mako
<%page cached="True" cache_key="${self.filename}"/>
${next.body()}
-
+
## rest of template
-
+
Accessing the Cache
===================
@@ -99,7 +99,7 @@ values:
<%
local.cache.put("somekey", type="memory", "somevalue")
%>
-
+
Above, the cache associated with the ``local`` namespace is
accessed and a key is placed within a memory cache.
@@ -109,16 +109,16 @@ sections programmatically:
.. sourcecode:: python
template = lookup.get_template('/sometemplate.html')
-
+
# invalidate the "body" of the template
template.cache.invalidate_body()
-
+
# invalidate an individual def
template.cache.invalidate_def('somedef')
-
+
# invalidate an arbitrary key
template.cache.invalidate('somekey')
-
+
API Reference
==============
diff --git a/doc/build/defs.rst b/doc/build/defs.rst
index 1e3abb6..42380ee 100644
--- a/doc/build/defs.rst
+++ b/doc/build/defs.rst
@@ -32,12 +32,12 @@ variables ``username`` and ``accountdata`` inside the context:
.. sourcecode:: mako
Hello there ${username}, how are ya. Lets see what your account says:
-
+
${account()}
<%def name="account()">
Account for ${username}:<br/>
-
+
% for row in accountdata:
Value: ${row}<br/>
% endfor
@@ -53,7 +53,7 @@ arguments to them as well:
.. sourcecode:: mako
${account(accountname='john')}
-
+
<%def name="account(accountname, type='regular')">
account name: ${accountname}, type ${type}
</%def>
@@ -120,20 +120,20 @@ object. This is a :class:`.Template` subclass which the parent
.. sourcecode:: python
from mako.template import Template
-
+
template = Template("""
<%def name="hi(name)">
hi ${name}!
</%def>
-
+
<%def name="bye(name)">
bye ${name}!
</%def>
""")
-
+
print template.get_def("hi").render(name="ed")
print template.get_def("bye").render(name="ed")
-
+
Defs within Defs
================
@@ -148,7 +148,7 @@ within the parent's **enclosing scope**:
<%def name="subdef()">
a sub def
</%def>
-
+
im the def, and the subcomponent is ${subdef()}
</%def>
@@ -182,9 +182,9 @@ the following code will raise an error:
%>
<%def name="somedef()">
## error !
- somedef, x is ${x}
+ somedef, x is ${x}
<%
- x = 27
+ x = 27
%>
</%def>
@@ -237,11 +237,11 @@ custom tag:
</td></tr>
</table>
</%def>
-
+
<%self:buildtable>
I am the table body.
</%self:buildtable>
-
+
This produces the output (whitespace formatted):
.. sourcecode:: html
@@ -279,13 +279,13 @@ conditionals, etc:
${caller.body()}
% endfor
</%def>
-
+
<%self:lister count="${3}">
hi
</%self:lister>
-
+
Produces:
-
+
.. sourcecode:: html
hi
@@ -296,7 +296,7 @@ Notice above we pass ``3`` as a Python expression, so that it
remains as an integer.
A custom "conditional" tag:
-
+
.. sourcecode:: mako
<%def name="conditional(expression)">
@@ -340,7 +340,7 @@ element of data from its argument:
<%self:layoutdata somedata="${[[1,2,3],[4,5,6],[7,8,9]]}" args="col">\
Body data: ${col}\
</%self:layoutdata>
-
+
Produces:
.. sourcecode:: html
@@ -362,7 +362,7 @@ Produces:
<td>Body data: 9</td>
</tr>
</table>
-
+
You don't have to stick to calling just the ``body()`` function.
The caller can define any number of callables, allowing the
``<%call>`` tag to produce whole layouts:
@@ -395,10 +395,10 @@ The caller can define any number of callables, allowing the
<li>sidebar 2</li>
</ul>
</%def>
-
+
this is the body
</%self:layout>
-
+
The above layout would produce:
.. sourcecode:: html
diff --git a/doc/build/filtering.rst b/doc/build/filtering.rst
index 0921176..9cf65ec 100644
--- a/doc/build/filtering.rst
+++ b/doc/build/filtering.rst
@@ -51,16 +51,16 @@ Python function that accepts a single string argument, and
returns the filtered result. The expressions after the ``|``
operator draw upon the local namespace of the template in which
they appear, meaning you can define escaping functions locally:
-
+
.. sourcecode:: mako
<%!
def myescape(text):
return "<TAG>" + text + "</TAG>"
%>
-
+
Heres some tagged text: ${"text" | myescape}
-
+
Or from any Python module:
.. sourcecode:: mako
@@ -68,18 +68,18 @@ Or from any Python module:
<%!
import myfilters
%>
-
+
Heres some tagged text: ${"text" | myfilters.tagfilter}
-
+
A page can apply a default set of filters to all expression tags
using the ``expression_filter`` argument to the ``%page`` tag:
.. sourcecode:: mako
<%page expression_filter="h"/>
-
+
Escaped text: ${"<html>some html</html>"}
-
+
Result:
.. sourcecode:: html
@@ -117,7 +117,7 @@ list:
.. sourcecode:: python
t = TemplateLookup(directories=['/tmp'], default_filters=[])
-
+
Any string name can be added to ``default_filters`` where it
will be added to all expressions as a filter. The filters are
applied from left to right, meaning the leftmost filter is
@@ -126,7 +126,7 @@ applied first.
.. sourcecode:: python
t = Template(templatetext, default_filters=['unicode', 'myfilter'])
-
+
To ease the usage of ``default_filters`` with custom filters,
you can also add imports (or other code) to all templates using
the ``imports`` argument:
@@ -136,7 +136,7 @@ the ``imports`` argument:
t = TemplateLookup(directories=['/tmp'],
default_filters=['unicode', 'myfilter'],
imports=['from mypackage import myfilter'])
-
+
The above will generate templates something like this:
.. sourcecode:: python
@@ -163,8 +163,8 @@ Will render ``myexpression`` with no filtering of any kind, and
.. sourcecode:: mako
${'myexpression' | n, trim}
-
-will render ``myexpression`` using the ``trim`` filter only.
+
+will render ``myexpression`` using the ``trim`` filter only.
Filtering Defs
=================
@@ -177,7 +177,7 @@ given list of filter functions to the output of the ``%def``:
<%def name="foo()" filter="h, trim">
<b>this is bold</b>
</%def>
-
+
When the filter attribute is applied to a def as above, the def
is automatically **buffered** as well. This is described next.
@@ -204,14 +204,14 @@ something like this:
.. sourcecode:: mako
${" results " + somedef() + " more results "}
-
+
If the ``somedef()`` function produced the content "``somedef's
results``", the above template would produce this output:
.. sourcecode:: html
somedef's results results more results
-
+
This is because ``somedef()`` fully executes before the
expression returns the results of its concatenation; the
concatenation in turn receives just the empty string as its
@@ -225,7 +225,7 @@ buffering to the ``%def`` itself:
<%def name="somedef()" buffered="True">
somedef's results
</%def>
-
+
The above definition will generate code similar to this:
.. sourcecode:: python
@@ -237,7 +237,7 @@ The above definition will generate code similar to this:
finally:
buf = context.pop_buffer()
return buf.getvalue()
-
+
So that the content of ``somedef()`` is sent to a second buffer,
which is then popped off the stack and its value returned. The
speed hit inherent in buffering the output of a def is also
@@ -259,7 +259,7 @@ except it is specified by the caller.
.. sourcecode:: mako
${" results " + capture(somedef) + " more results "}
-
+
Note that the first argument to the ``capture`` function is
**the function itself**, not the result of calling it. This is
because the ``capture`` function takes over the job of actually
@@ -270,13 +270,13 @@ to ``capture`` instead:
.. sourcecode:: mako
${capture(somedef, 17, 'hi', use_paging=True)}
-
+
The above call is equivalent to the unbuffered call:
.. sourcecode:: mako
${somedef(17, 'hi', use_paging=True)}
-
+
Decorating
===========
@@ -304,13 +304,13 @@ simplicities' sake:
return ''
return decorate
%>
-
+
<%def name="foo()" decorator="bar">
this is foo
</%def>
-
+
${foo()}
-
+
The above template will return, with more whitespace than this,
``"BAR this is foo BAR"``. The function is the render callable
itself (or possibly a wrapper around it), and by default will
diff --git a/doc/build/index.rst b/doc/build/index.rst
index 827225b..3a29f26 100644
--- a/doc/build/index.rst
+++ b/doc/build/index.rst
@@ -3,7 +3,7 @@ Table of Contents
.. toctree::
:maxdepth: 2
-
+
usage
syntax
defs
@@ -13,7 +13,7 @@ Table of Contents
filtering
unicode
caching
-
+
Indices and tables
------------------
diff --git a/doc/build/inheritance.rst b/doc/build/inheritance.rst
index c876864..e8fe2c2 100644
--- a/doc/build/inheritance.rst
+++ b/doc/build/inheritance.rst
@@ -21,13 +21,13 @@ template, ``index.html``:
## index.html
<%inherit file="base.html"/>
-
+
<%def name="header()">
this is some header content
</%def>
-
+
this is the body content.
-
+
And ``base.html``, the inherited template:
.. sourcecode:: mako
@@ -38,9 +38,9 @@ And ``base.html``, the inherited template:
<div class="header">
${self.header()}
</div>
-
+
${self.body()}
-
+
<div class="footer">
${self.footer()}
</div>
@@ -52,7 +52,7 @@ And ``base.html``, the inherited template:
</%def>
Here is a breakdown of the execution:
-
+
* When ``index.html`` is rendered, control immediately passes to
``base.html``.
* ``base.html`` then renders the top part of an HTML document,
@@ -85,9 +85,9 @@ Here is a breakdown of the execution:
<div class="header">
this is some header content
</div>
-
+
this is the body content.
-
+
<div class="footer">
this is the footer
</div>
@@ -129,9 +129,9 @@ Lets change the line in ``base.html`` which calls upon
<div class="header">
${self.header()}
</div>
-
+
${next.body()}
-
+
<div class="footer">
${self.footer()}
</div>
@@ -155,12 +155,12 @@ which inherits from ``base.html``:
<div class="mainlayout">
${next.body()}
</div>
-
+
<%def name="toolbar()">
<li>selection 1</li>
<li>selection 2</li>
<li>selection 3</li>
- </%def>
+ </%def>
And finally change ``index.html`` to inherit from
``layout.html`` instead:
@@ -169,9 +169,9 @@ And finally change ``index.html`` to inherit from
## index.html
<%inherit file="layout.html"/>
-
+
## .. rest of template
-
+
In this setup, each call to ``next.body()`` will render the body
of the next template in the inheritance chain (which can be
written as ``base.html -> layout.html -> index.html``). Control
@@ -194,11 +194,11 @@ The output we get would be:
<li>selection 2</li>
<li>selection 3</li>
</ul>
-
+
<div class="mainlayout">
this is the body content.
</div>
-
+
<div class="footer">
this is the footer
</div>
@@ -243,7 +243,7 @@ by the ``toolbar`` function in ``layout.html``:
<li>selection 4</li>
<li>selection 5</li>
</%def>
-
+
this is the body content.
Above, we implemented a ``toolbar()`` function, which is meant
@@ -269,11 +269,11 @@ thing is now:
<li>selection 4</li>
<li>selection 5</li>
</ul>
-
+
<div class="mainlayout">
this is the body content.
</div>
-
+
<div class="footer">
this is the footer
</div>
@@ -295,11 +295,11 @@ inheritance chain as declared in ``<%! %>`` sections. Such as:
<%!
class_ = "grey"
%>
-
+
<div class="${self.attr.class_}">
${self.body()}
</div>
-
+
If a an inheriting template overrides ``class_`` to be
``white``, as in:
@@ -309,9 +309,9 @@ If a an inheriting template overrides ``class_`` to be
class_ = "white"
%>
<%inherit file="parent.html"/>
-
+
This is the body
-
+
You'll get output like:
.. sourcecode:: html
diff --git a/doc/build/namespaces.rst b/doc/build/namespaces.rst
index 0da3488..3fed8f4 100644
--- a/doc/build/namespaces.rst
+++ b/doc/build/namespaces.rst
@@ -15,11 +15,11 @@ If the file ``components.html`` defines these two components:
<%def name="comp1()">
this is comp1
</%def>
-
+
<%def name="comp2(x)">
this is comp2, x is ${x}
</%def>
-
+
You can make another file, for example ``index.html``, that
pulls those two components into a namespace called ``comp``:
@@ -27,7 +27,7 @@ pulls those two components into a namespace called ``comp``:
## index.html
<%namespace name="comp" file="components.html"/>
-
+
Heres comp1: ${comp.comp1()}
Heres comp2: ${comp.comp2(x=5)}
@@ -44,10 +44,10 @@ need to call it via the ".". When ``import`` is used, the
.. sourcecode:: mako
<%namespace file="components.html" import="comp1, comp2"/>
-
+
Heres comp1: ${comp1()}
Heres comp2: ${comp2(x=5)}
-
+
``import`` also supports the "*" operator:
.. sourcecode:: mako
@@ -70,7 +70,7 @@ context variables, the ``context`` must be named explicitly:
.. sourcecode:: mako
<%namespace name="dyn" file="${context['namespace_name']}"/>
-
+
Ways to Call Namespaces
========================
@@ -84,7 +84,7 @@ expressions like any other function:
.. sourcecode:: mako
${mynamespace.somefunction('some arg1', 'some arg2', arg3='some arg3', arg4='some arg4')}
-
+
Synonymous with the "expression" format is the "custom tag"
format, when a "closed" tag is used. This format, introduced in
Mako 0.2.3, allows the usage of a "custom" Mako tag, with the
@@ -93,7 +93,7 @@ function arguments passed in using named attributes:
.. sourcecode:: mako
<%mynamespace:somefunction arg1="some arg1" arg2="some arg2" arg3="some arg3" arg4="some arg4"/>
-
+
When using tags, the values of the arguments are taken as
literal strings by default. To embed Python expressions as
arguments, use the embedded expression format:
@@ -140,13 +140,13 @@ modules. These callables need to take at least one argument,
return ''
A template can use this module via:
-
+
.. sourcecode:: mako
<%namespace name="hw" module="some.module"/>
${hw.my_tag()}
-
+
Note that the ``context`` argument is not needed in the call;
the :class:`.Namespace` tag creates a locally-scoped callable which
takes care of it. The ``return ''`` is so that the def does not
@@ -163,14 +163,14 @@ def is called, supporting embedded content:
.. sourcecode:: python
from mako.runtime import supports_caller
-
+
@supports_caller
def my_tag(context):
context.write("<div>")
context['caller'].body()
context.write("</div>")
return ''
-
+
Capturing of output is available as well, using the
outside-of-templates version of the :func:`.capture` function,
which accepts the "context" as its first argument:
@@ -191,7 +191,7 @@ The ``<%namespace>`` tag supports the definition of ``<%defs>``
directly inside the tag. These defs become part of the namespace
like any other function, and will override the definitions
pulled in from a remote template or module:
-
+
.. sourcecode:: mako
## define a namespace
@@ -200,7 +200,7 @@ pulled in from a remote template or module:
comp1
</%def>
</%namespace>
-
+
## then call it
${stuff.comp1()}
@@ -228,7 +228,7 @@ own argument signature explicitly. You do this via using the
.. sourcecode:: mako
<%page args="x, y, someval=8, scope='foo', **kwargs"/>
-
+
A template which defines the above signature requires that the
variables ``x`` and ``y`` are defined, defines default values
for ``someval`` and ``scope``, and sets up ``**kwargs`` to
@@ -244,7 +244,7 @@ So above, the body might be called as:
.. sourcecode:: mako
${self.body(5, y=10, someval=15, delta=7)}
-
+
The :class:`.Context` object also supplies a :attr:`~.Context.kwargs` accessor, for
cases when youd like to pass along whatever is in the context to
a ``body()`` callable:
@@ -306,17 +306,17 @@ attached to the ``self`` namespace. Since ``self`` is globally
available throughout an inheritance chain (described in the next
section), all the templates in an inheritance chain can get at
the namespace imported in a super-template via ``self``.
-
+
.. sourcecode:: mako
## base.html
<%namespace name="foo" file="foo.html" inheritable="True"/>
-
+
${next.body()}
## somefile.html
<%inherit file="base.html"/>
-
+
${self.foo.bar()}
This allows a super-template to load a whole bunch of namespaces
@@ -334,7 +334,7 @@ API Reference
.. autoclass:: mako.runtime.Namespace
:show-inheritance:
:members:
-
+
.. autofunction:: mako.runtime.supports_caller
.. autofunction:: mako.runtime.capture
diff --git a/doc/build/runtime.rst b/doc/build/runtime.rst
index 8db081a..cc30c9f 100644
--- a/doc/build/runtime.rst
+++ b/doc/build/runtime.rst
@@ -100,7 +100,7 @@ automatically correspond to what was passed into the current
% else:
someval is: ${someval}
% endif
-
+
Another facet of the :class:`.Context` is that its dictionary of
variables is **immutable**. Whatever is set when
:meth:`~.Template.render` is called is what stays. Of course, since
@@ -141,7 +141,7 @@ are all stored in unique :class:`.Context` instances).
attributes['foo'] = 'bar'
%>
'foo' attribute is: ${attributes['foo']}
-
+
* **Why can't "attributes" be a built-in feature of the
Context?** - This is an area where Mako is trying to make as
few decisions about your application as it possibly can.
@@ -233,6 +233,6 @@ API Reference
.. autoclass:: mako.runtime.Undefined
:show-inheritance:
-
+
diff --git a/doc/build/static/docs.css b/doc/build/static/docs.css
index f886e02..2af5ba9 100644
--- a/doc/build/static/docs.css
+++ b/doc/build/static/docs.css
@@ -95,7 +95,7 @@ h1 {
margin:26px 4px 0px 5px;
font-size:1.6em;
font-weight:normal;
- line-height:1.6em;
+ line-height:1.6em;
}
.topnav h3 {
@@ -178,7 +178,7 @@ div.admonition .admonition-title {
.totoc {
-
+
}
.doc_copyright {
diff --git a/doc/build/syntax.rst b/doc/build/syntax.rst
index 1e5ecfb..7251e9b 100644
--- a/doc/build/syntax.rst
+++ b/doc/build/syntax.rst
@@ -31,14 +31,14 @@ from, its usually from the ``Context`` supplied to the
template's rendering function. If ``x`` was not supplied to the
template and was not otherwise assigned locally, it evaluates to
a special value ``UNDEFINED``. More on that later.
-
+
The contents within the ``${}`` tag are evaluated by Python
directly, so full expressions are OK:
.. sourcecode:: mako
pythagorean theorem: ${pow(x,2) + pow(y,2)}
-
+
The results of the expression are evaluated into a string result
in all cases before being rendered to the output stream, such as
the above example where the expression produces a numeric
@@ -81,7 +81,7 @@ using another ``%`` marker with the tag "``end<name>``", where
% if x==5:
this is some output
% endif
-
+
The ``%`` can appear anywhere on the line as long as no text
precedes it; indentation is not signficant. The full range of
Python "colon" expressions are allowed here, including
@@ -107,7 +107,7 @@ line, by escaping it as in ``%%``:
.. sourcecode:: mako
%% some text
-
+
%% some more text
Comments
@@ -141,11 +141,11 @@ the next line:
here is a line that goes onto \
another line.
-
+
The above text evaluates to::
here is a line that goes onto another line.
-
+
Python Blocks
=============
@@ -162,7 +162,7 @@ Any arbitrary block of python can be dropped in using the ``<%
% for elem in y:
element: ${elem}
% endfor
-
+
Within ``<% %>``, you're writing a regular block of Python code.
While the code can appear with an arbitrary level of preceding
whitespace, it has to be consistently formatted with itself.
@@ -187,11 +187,11 @@ pure-Python functions you might want to declare:
<%!
import mylib
import re
-
+
def filter(text):
return re.sub(r'^@', '', text)
%>
-
+
Any number of ``<%! %>`` blocks can be declared anywhere in a
template; they will be rendered in the resulting module
in a single contiguous block above all render callables,
@@ -209,11 +209,11 @@ character, or an explicit closing tag:
.. sourcecode:: mako
<%include file="foo.txt"/>
-
+
<%def name="foo" buffered="True">
this is a def
</%def>
-
+
All tags have a set of attributes which are defined for each
tag. Some of these attributes are required. Also, many
attributes support **evaluation**, meaning you can embed an
@@ -222,7 +222,7 @@ expression (using ``${}``) inside the attribute text:
.. sourcecode:: mako
<%include file="/foo/bar/${myfile}.txt"/>
-
+
Whether or not an attribute accepts runtime evaluation depends
on the type of tag and how that tag is compiled into the
template. The best way to find out if you can stick an
@@ -241,9 +241,9 @@ which the template expects when invoked.
.. sourcecode:: mako
<%page args="x, y, z='default'"/>
-
+
Or a page tag that defines caching characteristics:
-
+
.. sourcecode:: mako
<%page cached="True" cache_type="memory"/>
@@ -254,7 +254,7 @@ release, for now make sure you have only one ``<%page>`` tag
defined in your template, else you may not get the results you
want. The details of what ``<%page>`` is used for are described
further in :ref:`namespaces_body` as well as :ref:`caching_toplevel`.
-
+
<%include>
-----------
@@ -265,9 +265,9 @@ the rendered result of that file:
.. sourcecode:: mako
<%include file="header.html"/>
-
+
hello world
-
+
<%include file="footer.html"/>
Include also accepts arguments which are available as ``<%page>`` arguments in the receiving template:
@@ -288,9 +288,9 @@ template. The basic idea is simple:
<%def name="myfunc(x)">
this is myfunc, x is ${x}
</%def>
-
+
${myfunc(7)}
-
+
The %def tag is a lot more powerful than a plain Python def, as
the Mako compiler provides many extra services with %def that
you wouldn't normally have, such as the ability to export defs
diff --git a/doc/build/templates/genindex.mako b/doc/build/templates/genindex.mako
index bdb699a..1543314 100644
--- a/doc/build/templates/genindex.mako
+++ b/doc/build/templates/genindex.mako
@@ -30,7 +30,7 @@
% else:
${entryname|h}
% endif
-
+
% if subitems:
<dd><dl>
% for subentryname, subentrylinks in subitems:
diff --git a/doc/build/templates/layout.mako b/doc/build/templates/layout.mako
index d842fdd..0355cd1 100644
--- a/doc/build/templates/layout.mako
+++ b/doc/build/templates/layout.mako
@@ -58,12 +58,12 @@
<div class="topnav">
<div id="pagecontrol">
<a href="${pathto('genindex')}">Index</a>
-
+
% if sourcename:
<div class="sourcelink">(<a href="${pathto('_sources/' + sourcename, True)|h}">${_('view source')})</div>
% endif
</div>
-
+
<div class="navbanner">
<a class="totoc" href="${pathto(master_doc)}">Table of Contents</a>
% if parents:
@@ -74,7 +74,7 @@
% if current_page_name != master_doc:
» ${self.show_title()}
% endif
-
+
${prevnext()}
<h2>
${self.show_title()}
@@ -85,7 +85,7 @@
% endif
<div class="clearboth"></div>
</div>
-
+
<div class="document">
<div class="body">
${next.body()}
diff --git a/doc/build/unicode.rst b/doc/build/unicode.rst
index cc80733..13f5aa1 100644
--- a/doc/build/unicode.rst
+++ b/doc/build/unicode.rst
@@ -105,7 +105,7 @@ use this encoding in order to convert the template source into a
For the picky, the regular expression used is derived from that
of the abovementioned pep:
-
+
.. sourcecode:: python
#.*coding[:=]\s*([-\w.]+).*\n
@@ -122,7 +122,7 @@ the ``input_encoding`` parameter:
.. sourcecode:: python
t = TemplateLookup(directories=['./'], input_encoding='utf-8')
-
+
The above will assume all located templates specify ``utf-8``
encoding, unless the template itself contains its own magic
encoding comment, which takes precedence.
@@ -137,7 +137,7 @@ this:
.. sourcecode:: mako
${"hello world"}
-
+
looks something like this:
.. sourcecode:: python
@@ -149,7 +149,7 @@ In Python 3, its just:
.. sourcecode:: python
context.write(str("hello world"))
-
+
That is, **the output of all expressions is run through the
``unicode`` builtin**. This is the default setting, and can be
modified to expect various encodings. The ``unicode`` step serves
@@ -179,7 +179,7 @@ explcitly decode to unicode first, such as:
.. sourcecode:: mako
${call_my_object().decode('utf-8')}
-
+
Note that filehandles acquired by ``open()`` in Python 3 default
to returning "text", that is the decoding is done for you. See
Python 3's documentation for the ``open()`` builtin for details on
@@ -218,9 +218,9 @@ supported codec:
from mako.template import Template
from mako.lookup import TemplateLookup
-
+
mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
-
+
mytemplate = mylookup.get_template("foo.txt")
print mytemplate.render()
@@ -234,14 +234,14 @@ returns a native string.
.. sourcecode:: python
print mytemplate.render_unicode()
-
+
The above method disgards the output encoding keyword argument;
you can encode yourself by saying:
.. sourcecode:: python
print mytemplate.render_unicode().encode('utf-8', 'replace')
-
+
Buffer Selection
-----------------
@@ -280,7 +280,7 @@ Python. For these users, assuming they're sticking with Python
# -*- encoding:utf-8 -*-
from mako.template import Template
-
+
t = Template("drôle de petite voix m’a réveillé.", disable_unicode=True, input_encoding='utf-8')
print t.code
@@ -332,6 +332,6 @@ strings.
vast majority of users who stick to the Unicode program.
* Python 3 is unicode by default, and the flag is not available
when running on Python 3.
-
+
diff --git a/doc/build/usage.rst b/doc/build/usage.rst
index df852b1..0aadacf 100644
--- a/doc/build/usage.rst
+++ b/doc/build/usage.rst
@@ -16,10 +16,10 @@ The most basic way to create a template and render it is through
the :class:`.Template` class::
from mako.template import Template
-
+
mytemplate = Template("hello world!")
print mytemplate.render()
-
+
Above, the text argument to :class:`.Template` is **compiled** into a
Python module representation. This module contains a function
called ``render_body()``, which produces the output of the
@@ -35,10 +35,10 @@ sending them as additional keyword arguments to the :meth:`~.Template.render`
method::
from mako.template import Template
-
+
mytemplate = Template("hello, ${name}!")
print mytemplate.render(name="jack")
-
+
The :meth:`~.Template.render` method calls upon Mako to create a
:class:`.Context` object, which stores all the variable names accessible
to the template and also stores a buffer used to capture output.
@@ -48,7 +48,7 @@ render with it, using the :meth:`~.Template.render_context` method::
from mako.template import Template
from mako.runtime import Context
from StringIO import StringIO
-
+
mytemplate = Template("hello, ${name}!")
buf = StringIO()
ctx = Context(buf, name="jack")
@@ -62,10 +62,10 @@ A :class:`.Template` can also load its template source code from a file,
using the ``filename`` keyword argument::
from mako.template import Template
-
+
mytemplate = Template(filename='/docs/mytmpl.txt')
print mytemplate.render()
-
+
For improved performance, a :class:`.Template` which is loaded from a
file can also cache the source code to its generated module on
the filesystem as a regular Python module file (i.e. a .py
@@ -100,7 +100,7 @@ the :class:`.Template` objects it creates::
from mako.template import Template
from mako.lookup import TemplateLookup
-
+
mylookup = TemplateLookup(directories=['/docs'])
mytemplate = Template("""<%include file="header.txt"/> hello world!""", lookup=mylookup)
@@ -119,9 +119,9 @@ desired template::
from mako.template import Template
from mako.lookup import TemplateLookup
-
+
mylookup = TemplateLookup(directories=['/docs'], module_directory='/tmp/mako_modules')
-
+
def serve_template(templatename, **kwargs):
mytemplate = mylookup.get_template(templatename)
print mytemplate.render(**kwargs)
@@ -154,7 +154,7 @@ size using the ``collection_size`` argument::
mylookup = TemplateLookup(directories=['/docs'],
module_directory='/tmp/mako_modules', collection_size=500)
-
+
The above lookup will continue to load templates into memory
until it reaches a count of around 500. At that point, it will
clean out a certain percentage of templates using a least
@@ -184,9 +184,9 @@ output in any Python supported codec::
from mako.template import Template
from mako.lookup import TemplateLookup
-
+
mylookup = TemplateLookup(directories=['/docs'], output_encoding='utf-8', encoding_errors='replace')
-
+
mytemplate = mylookup.get_template("foo.txt")
print mytemplate.render()
@@ -199,12 +199,12 @@ return the template output as a Python ``unicode`` object, or in
Python 3 a ``string``::
print mytemplate.render_unicode()
-
+
The above method disregards the output encoding keyword
argument; you can encode yourself by saying::
print mytemplate.render_unicode().encode('utf-8', 'replace')
-
+
Note that Mako's ability to return data in any encoding and/or
``unicode`` implies that the underlying output stream of the
template is a Python unicode object. This behavior is described
@@ -237,13 +237,13 @@ To format exception traces, the :func:`.text_error_template` and
Usage of these handlers usually looks like::
from mako import exceptions
-
+
try:
template = lookup.get_template(uri)
print template.render()
except:
print exceptions.text_error_template().render()
-
+
Or for the HTML render function::
from mako import exceptions
@@ -271,7 +271,7 @@ will result in the output being substituted with the output of
template = Template(filename="/foo/bar", format_exceptions=True)
print template.render()
-
+
Note that the compile stage of the above template occurs when
you construct the :class:`.Template` itself, and no output stream is
defined. Therefore exceptions which occur within the
@@ -289,7 +289,7 @@ directly to provide custom error views. Here's an example usage
which describes its general API::
from mako.exceptions import RichTraceback
-
+
try:
template = lookup.get_template(uri)
print template.render()
@@ -299,7 +299,7 @@ which describes its general API::
print "File %s, line %s, in %s" % (filename, lineno, function)
print line, "\n"
print "%s: %s" % (str(traceback.error.__class__.__name__), traceback.error)
-
+
Common Framework Integrations
=============================
@@ -438,47 +438,47 @@ API Reference
:show-inheritance:
.. py:attribute:: error
-
+
the exception instance.
.. py:attribute:: message
-
+
the exception error message as unicode
-
+
.. py:attribute:: source
-
- source code of the file where the error occured.
+
+ source code of the file where the error occured.
if the error occured within a compiled template,
this is the template source.
-
+
.. py:attribute:: lineno
-
+
line number where the error occured. if the error
occured within a compiled template, the line number
is adjusted to that of the template source
-
+
.. py:attribute:: records
-
+
a list of 8-tuples containing the original
python traceback elements, plus the
filename, line number, source line, and full template source
for the traceline mapped back to its originating source
template, if any for that traceline (else the fields are None).
-
+
.. py:attribute:: reverse_records
-
+
the list of records in reverse
traceback - a list of 4-tuples, in the same format as a regular
python traceback, with template-corresponding
traceback records replacing the originals
-
+
.. py:attribute:: reverse_traceback
-
+
the traceback list in reverse
.. autofunction:: mako.exceptions.html_error_template
.. autofunction:: mako.exceptions.text_error_template
-
+
diff --git a/examples/bench/basic.py b/examples/bench/basic.py
index 84c4b11..c335b7f 100644
--- a/examples/bench/basic.py
+++ b/examples/bench/basic.py
@@ -133,7 +133,7 @@ def run(engines, number=2000, verbose=False):
t = timeit.Timer(setup='from __main__ import %s; render = %s(r"%s", %s)'
% (engine, engine, dirname, verbose),
stmt='render()')
-
+
time = t.timeit(number=number) / number
if verbose:
print '--------------------------------------------------------'
diff --git a/examples/bench/cheetah/template.tmpl b/examples/bench/cheetah/template.tmpl
index c7cf1e4..f1c2243 100644
--- a/examples/bench/cheetah/template.tmpl
+++ b/examples/bench/cheetah/template.tmpl
@@ -10,13 +10,13 @@
#def greeting(name)
<p>hello ${name}!</p>
#end def
-
+
#include "cheetah/header.tmpl"
$greeting($user)
$greeting('me')
$greeting('world')
-
+
<h2>Loop</h2>
#if $list_items
<ul>
diff --git a/examples/bench/kid/template.kid b/examples/bench/kid/template.kid
index 5da52e4..7f79d7a 100644
--- a/examples/bench/kid/template.kid
+++ b/examples/bench/kid/template.kid
@@ -12,7 +12,7 @@
<div>${greeting(user)}</div>
<div>${greeting('me')}</div>
<div>${greeting('world')}</div>
-
+
<h2>Loop</h2>
<ul py:if="items">
<li py:for="idx, item in enumerate(items)" py:content="item"
diff --git a/examples/bench/mako/template.html b/examples/bench/mako/template.html
index 96ccf79..d5ded9a 100644
--- a/examples/bench/mako/template.html
+++ b/examples/bench/mako/template.html
@@ -10,13 +10,13 @@
<%def name="greeting(name)">
<p>hello ${name}!</p>
</%def>
-
+
<%include file="header.html"/>
${greeting(user)}
${greeting('me')}
${greeting('world')}
-
+
<h2>Loop</h2>
% if list_items:
<ul>
diff --git a/examples/bench/mako_inheritance/base.html b/examples/bench/mako_inheritance/base.html
index 87f0f24..84b2930 100644
--- a/examples/bench/mako_inheritance/base.html
+++ b/examples/bench/mako_inheritance/base.html
@@ -10,7 +10,7 @@
<%def name="greeting(name)">
<p>hello ${name}!</p>
</%def>
-
+
<div id="header">
<h1>${title}</h1>
</div>
diff --git a/examples/bench/mako_inheritance/template.html b/examples/bench/mako_inheritance/template.html
index 45a6822..7c53bf1 100644
--- a/examples/bench/mako_inheritance/template.html
+++ b/examples/bench/mako_inheritance/template.html
@@ -3,7 +3,7 @@
${parent.greeting(user)}
${parent.greeting('me')}
${parent.greeting('world')}
-
+
<h2>Loop</h2>
% if list_items:
<ul>
diff --git a/examples/wsgi/htdocs/index.html b/examples/wsgi/htdocs/index.html
index 0f0ce9d..ef2df4d 100644
--- a/examples/wsgi/htdocs/index.html
+++ b/examples/wsgi/htdocs/index.html
@@ -4,5 +4,5 @@
<%inherit file="root.html"/>
This is index.html
-
+
c is ${c is not UNDEFINED and c or "undefined"}
diff --git a/examples/wsgi/run_wsgi.py b/examples/wsgi/run_wsgi.py
index 82268ad..6e86406 100644
--- a/examples/wsgi/run_wsgi.py
+++ b/examples/wsgi/run_wsgi.py
@@ -45,7 +45,7 @@ def serve(environ, start_response):
filename = os.path.join(root, u)
start_response("200 OK", [('Content-type',guess_type(uri))])
return [file(filename).read()]
-
+
def getfield(f):
"""convert values from cgi.Field objects to plain values."""
if isinstance(f, list):
@@ -68,7 +68,7 @@ def guess_type(path):
return extensions_map[ext]
else:
return extensions_map['']
-
+
if __name__ == '__main__':
import wsgiref.simple_server
server = wsgiref.simple_server.make_server('', port, serve)
diff --git a/mako/ast.py b/mako/ast.py
index 242b6ee..3969c6f 100644
--- a/mako/ast.py
+++ b/mako/ast.py
@@ -14,13 +14,13 @@ class PythonCode(object):
"""represents information about a string containing Python code"""
def __init__(self, code, **exception_kwargs):
self.code = code
-
+
# represents all identifiers which are assigned to at some point in the code
self.declared_identifiers = set()
-
+
# represents all identifiers which are referenced before their assignment, if any
self.undeclared_identifiers = set()
-
+
# note that an identifier can be in both the undeclared and declared lists.
# using AST to parse instead of using code.co_varnames,
@@ -56,10 +56,10 @@ class ArgumentList(object):
f = pyparser.FindTuple(self, PythonCode, **exception_kwargs)
f.visit(expr)
-
+
class PythonFragment(PythonCode):
"""extends PythonCode to provide identifier lookups in partial control statements
-
+
e.g.
for x in 5:
elif y==9:
@@ -88,14 +88,14 @@ class PythonFragment(PythonCode):
"Unsupported control keyword: '%s'" %
keyword, **exception_kwargs)
super(PythonFragment, self).__init__(code, **exception_kwargs)
-
-
+
+
class FunctionDecl(object):
"""function declaration"""
def __init__(self, code, allow_kwargs=True, **exception_kwargs):
self.code = code
expr = pyparser.parse(code, "exec", **exception_kwargs)
-
+
f = pyparser.ParseFunc(self, **exception_kwargs)
f.visit(expr)
if not hasattr(self, 'funcname'):
@@ -106,10 +106,10 @@ class FunctionDecl(object):
raise exceptions.CompileException(
"'**%s' keyword argument not allowed here" %
self.argnames[-1], **exception_kwargs)
-
+
def get_argument_expressions(self, include_defaults=True):
"""return the argument declarations of this FunctionDecl as a printable list."""
-
+
namedecls = []
defaults = [d for d in self.defaults]
kwargs = self.kwargs
@@ -138,6 +138,6 @@ class FunctionDecl(object):
class FunctionArgs(FunctionDecl):
"""the argument portion of a function declaration"""
-
+
def __init__(self, code, **kwargs):
super(FunctionArgs, self).__init__("def ANON(%s):pass" % code, **kwargs)
diff --git a/mako/cache.py b/mako/cache.py
index ffee5ea..c82bd05 100644
--- a/mako/cache.py
+++ b/mako/cache.py
@@ -9,94 +9,94 @@ class BeakerMissing(object):
class Cache(object):
"""Represents a data content cache made available to the module
space of a :class:`.Template` object.
-
+
:class:`.Cache` is a wrapper on top of a Beaker CacheManager object.
This object in turn references any number of "containers", each of
which defines its own backend (i.e. file, memory, memcached, etc.)
independently of the rest.
-
+
"""
-
+
def __init__(self, id, starttime):
self.id = id
self.starttime = starttime
self.def_regions = {}
-
+
def put(self, key, value, **kwargs):
"""Place a value in the cache.
-
+
:param key: the value's key.
:param value: the value
:param \**kwargs: cache configuration arguments. The
backend is configured using these arguments upon first request.
Subsequent requests that use the same series of configuration
values will use that same backend.
-
+
"""
-
+
defname = kwargs.pop('defname', None)
expiretime = kwargs.pop('expiretime', None)
createfunc = kwargs.pop('createfunc', None)
-
+
self._get_cache(defname, **kwargs).put_value(key, starttime=self.starttime, expiretime=expiretime)
-
+
def get(self, key, **kwargs):
"""Retrieve a value from the cache.
-
+
:param key: the value's key.
:param \**kwargs: cache configuration arguments. The
backend is configured using these arguments upon first request.
Subsequent requests that use the same series of configuration
values will use that same backend.
-
+
"""
-
+
defname = kwargs.pop('defname', None)
expiretime = kwargs.pop('expiretime', None)
createfunc = kwargs.pop('createfunc', None)
-
+
return self._get_cache(defname, **kwargs).get_value(key, starttime=self.starttime, expiretime=expiretime, createfunc=createfunc)
-
+
def invalidate(self, key, **kwargs):
"""Invalidate a value in the cache.
-
+
:param key: the value's key.
:param \**kwargs: cache configuration arguments. The
backend is configured using these arguments upon first request.
Subsequent requests that use the same series of configuration
values will use that same backend.
-
+
"""
defname = kwargs.pop('defname', None)
expiretime = kwargs.pop('expiretime', None)
createfunc = kwargs.pop('createfunc', None)
-
+
self._get_cache(defname, **kwargs).remove_value(key, starttime=self.starttime, expiretime=expiretime)
-
+
def invalidate_body(self):
"""Invalidate the cached content of the "body" method for this template.
-
+
"""
self.invalidate('render_body', defname='render_body')
-
+
def invalidate_def(self, name):
"""Invalidate the cached content of a particular <%def> within this template."""
-
+
self.invalidate('render_%s' % name, defname='render_%s' % name)
-
+
def invalidate_closure(self, name):
"""Invalidate a nested <%def> within this template.
-
+
Caching of nested defs is a blunt tool as there is no
management of scope - nested defs that use cache tags
need to have names unique of all other nested defs in the
template, else their content will be overwritten by
each other.
-
+
"""
-
+
self.invalidate(name, defname=name)
-
+
def _get_cache(self, defname, type=None, **kw):
global cache
if not cache:
@@ -115,4 +115,4 @@ class Cache(object):
else:
self.def_regions[defname] = (type, kw)
return cache.get_cache(self.id, type=type, **kw)
- \ No newline at end of file
+ \ No newline at end of file
diff --git a/mako/codegen.py b/mako/codegen.py
index 1a64944..9c577d5 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -23,7 +23,7 @@ def compile(node,
generate_magic_comment=True,
disable_unicode=False,
strict_undefined=False):
-
+
"""Generate module source code given a parsetree node,
uri, and optional source filename"""
@@ -33,8 +33,8 @@ def compile(node,
# result into a unicode object, in "disable_unicode" mode
if not util.py3k and isinstance(source_encoding, unicode):
source_encoding = source_encoding.encode(source_encoding)
-
-
+
+
buf = util.FastEncodingBuffer()
printer = PythonPrinter(buf)
@@ -71,11 +71,11 @@ class _CompileContext(object):
self.generate_magic_comment = generate_magic_comment
self.disable_unicode = disable_unicode
self.strict_undefined = strict_undefined
-
+
class _GenerateRenderMethod(object):
"""A template visitor object which generates the
full module source for a template.
-
+
"""
def __init__(self, printer, compiler, node):
self.printer = printer
@@ -83,7 +83,7 @@ class _GenerateRenderMethod(object):
self.compiler = compiler
self.node = node
self.identifier_stack = [None]
-
+
self.in_def = isinstance(node, parsetree.DefTag)
if self.in_def:
@@ -111,24 +111,24 @@ class _GenerateRenderMethod(object):
args = ['context']
else:
args = [a for a in ['context'] + args]
-
+
self.write_render_callable(
pagetag or node,
name, args,
buffered, filtered, cached)
-
+
if defs is not None:
for node in defs:
_GenerateRenderMethod(printer, compiler, node)
-
+
@property
def identifiers(self):
return self.identifier_stack[-1]
-
+
def write_toplevel(self):
"""Traverse a template structure for module-level directives and
generate the start of module-level code.
-
+
"""
inherit = []
namespaces = {}
@@ -136,7 +136,7 @@ class _GenerateRenderMethod(object):
encoding =[None]
self.compiler.pagetag = None
-
+
class FindTopLevel(object):
def visitInheritTag(s, node):
inherit.append(node)
@@ -147,7 +147,7 @@ class _GenerateRenderMethod(object):
def visitCode(s, node):
if node.ismodule:
module_code.append(node)
-
+
f = FindTopLevel()
for n in self.node.nodes:
n.accept_visitor(f)
@@ -160,13 +160,13 @@ class _GenerateRenderMethod(object):
module_identifiers = _Identifiers()
module_identifiers.declared = module_ident
-
+
# module-level names, python code
if self.compiler.generate_magic_comment and \
self.compiler.source_encoding:
self.printer.writeline("# -*- encoding:%s -*-" %
self.compiler.source_encoding)
-
+
self.printer.writeline("from mako import runtime, filters, cache")
self.printer.writeline("UNDEFINED = runtime.UNDEFINED")
self.printer.writeline("__M_dict_builtin = dict")
@@ -192,7 +192,7 @@ class _GenerateRenderMethod(object):
filename='template defined imports')
else:
impcode = None
-
+
main_identifiers = module_identifiers.branch(self.node)
module_identifiers.topleveldefs = \
module_identifiers.topleveldefs.\
@@ -200,7 +200,7 @@ class _GenerateRenderMethod(object):
module_identifiers.declared.add("UNDEFINED")
if impcode:
module_identifiers.declared.update(impcode.declared_identifiers)
-
+
self.compiler.identifiers = module_identifiers
self.printer.writeline("_exports = %r" %
[n.name for n in
@@ -221,14 +221,14 @@ class _GenerateRenderMethod(object):
def write_render_callable(self, node, name, args, buffered, filtered, cached):
"""write a top-level render callable.
-
+
this could be the main render() method or that of a top-level def."""
-
+
if self.in_def:
decorator = node.decorator
if decorator:
self.printer.writeline("@runtime._decorate_toplevel(%s)" % decorator)
-
+
self.printer.writelines(
"def %s(%s):" % (name, ','.join(args)),
"context.caller_stack._push_frame()",
@@ -236,7 +236,7 @@ class _GenerateRenderMethod(object):
)
if buffered or filtered or cached:
self.printer.writeline("context._push_buffer()")
-
+
self.identifier_stack.append(self.compiler.identifiers.branch(self.node))
if not self.in_def and '**pageargs' in args:
self.identifier_stack[-1].argument_declared.add('pageargs')
@@ -264,7 +264,7 @@ class _GenerateRenderMethod(object):
node, name,
args, buffered,
self.identifiers, toplevel=True)
-
+
def write_module_code(self, module_code):
"""write module-level template code, i.e. that which
is enclosed in <%! %> tags in the template."""
@@ -274,7 +274,7 @@ class _GenerateRenderMethod(object):
def write_inherit(self, node):
"""write the module-level inheritance-determination callable."""
-
+
self.printer.writelines(
"def _mako_inherit(template, context):",
"_mako_generate_namespaces(context)",
@@ -296,7 +296,7 @@ class _GenerateRenderMethod(object):
)
self.printer.writeline("def _mako_generate_namespaces(context):")
-
+
for node in namespaces.values():
if node.attributes.has_key('import'):
self.compiler.has_ns_imports = True
@@ -330,16 +330,16 @@ class _GenerateRenderMethod(object):
)
if eval(node.attributes.get('inheritable', "False")):
self.printer.writeline("context['self'].%s = ns" % (node.name))
-
+
self.printer.writeline("context.namespaces[(__name__, %s)] = ns" % repr(node.name))
self.printer.write("\n")
if not len(namespaces):
self.printer.writeline("pass")
self.printer.writeline(None)
-
+
def write_variable_declares(self, identifiers, toplevel=False, limit=None):
"""write variable declarations at the top of a function.
-
+
the variable declarations are in the form of callable
definitions for defs and/or name lookup within the
function's context argument. the names declared are based
@@ -348,22 +348,22 @@ class _GenerateRenderMethod(object):
operation. names that are assigned within the body are
assumed to be locally-scoped variables and are not
separately declared.
-
+
for def callable definitions, if the def is a top-level
callable then a 'stub' callable is generated which wraps
the current Context into a closure. if the def is not
top-level, it is fully rendered as a local closure.
-
+
"""
-
+
# collection of all defs available to us in this scope
comp_idents = dict([(c.name, c) for c in identifiers.defs])
to_write = set()
-
+
# write "context.get()" for all variables we are going to
# need that arent in the namespace yet
to_write = to_write.union(identifiers.undeclared)
-
+
# write closure functions for closures that we define
# right here
to_write = to_write.union([c.name for c in identifiers.closuredefs.values()])
@@ -372,18 +372,18 @@ class _GenerateRenderMethod(object):
# signature of the callable
to_write = to_write.difference(identifiers.argument_declared)
- # remove identifiers that we are going to assign to.
+ # remove identifiers that we are going to assign to.
# in this way we mimic Python's behavior,
# i.e. assignment to a variable within a block
# means that variable is now a "locally declared" var,
- # which cannot be referenced beforehand.
+ # which cannot be referenced beforehand.
to_write = to_write.difference(identifiers.locally_declared)
-
+
# if a limiting set was sent, constraint to those items in that list
# (this is used for the caching decorator)
if limit is not None:
to_write = to_write.intersection(limit)
-
+
if toplevel and getattr(self.compiler, 'has_ns_imports', False):
self.printer.writeline("_import_ns = {}")
self.compiler.has_imports = True
@@ -395,7 +395,7 @@ class _GenerateRenderMethod(object):
ident,
re.split(r'\s*,\s*', ns.attributes['import'])
))
-
+
for ident in to_write:
if ident in comp_idents:
comp = comp_idents[ident]
@@ -440,9 +440,9 @@ class _GenerateRenderMethod(object):
self.printer.writeline(
"%s = context.get(%r, UNDEFINED)" % (ident, ident)
)
-
+
self.printer.writeline("__M_writer = context.writer()")
-
+
def write_source_comment(self, node):
"""write a source comment containing the line number of the corresponding template line."""
if self.last_source_line != node.lineno:
@@ -454,7 +454,7 @@ class _GenerateRenderMethod(object):
funcname = node.function_decl.funcname
namedecls = node.function_decl.get_argument_expressions()
nameargs = node.function_decl.get_argument_expressions(include_defaults=False)
-
+
if not self.in_def and (
len(self.identifiers.locally_assigned) > 0 or
len(self.identifiers.argument_declared) > 0):
@@ -464,12 +464,12 @@ class _GenerateRenderMethod(object):
self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls)))
self.printer.writeline("return render_%s(%s)" % (funcname, ",".join(nameargs)))
self.printer.writeline(None)
-
+
def write_inline_def(self, node, identifiers, nested):
"""write a locally-available def callable inside an enclosing def."""
-
+
namedecls = node.function_decl.get_argument_expressions()
-
+
decorator = node.decorator
if decorator:
self.printer.writeline("@runtime._decorate_inline(context, %s)" % decorator)
@@ -489,26 +489,26 @@ class _GenerateRenderMethod(object):
identifiers = identifiers.branch(node, nested=nested)
self.write_variable_declares(identifiers)
-
+
self.identifier_stack.append(identifiers)
for n in node.nodes:
n.accept_visitor(self)
self.identifier_stack.pop()
-
+
self.write_def_finish(node, buffered, filtered, cached)
self.printer.writeline(None)
if cached:
self.write_cache_decorator(node, node.name,
namedecls, False, identifiers,
inline=True, toplevel=False)
-
+
def write_def_finish(self, node, buffered, filtered, cached, callstack=True):
"""write the end section of a rendering function, either outermost or inline.
-
+
this takes into account if the rendering function was filtered, buffered, etc.
and closes the corresponding try: block if any, and writes code to retrieve
captured content, apply filters, send proper return value."""
-
+
if not buffered and not cached and not filtered:
self.printer.writeline("return ''")
if callstack:
@@ -517,7 +517,7 @@ class _GenerateRenderMethod(object):
"context.caller_stack._pop_frame()",
None
)
-
+
if buffered or filtered or cached:
if buffered or cached:
# in a caching scenario, don't try to get a writer
@@ -533,10 +533,10 @@ class _GenerateRenderMethod(object):
"finally:",
"__M_buf, __M_writer = context._pop_buffer_and_writer()"
)
-
+
if callstack:
self.printer.writeline("context.caller_stack._pop_frame()")
-
+
s = "__M_buf.getvalue()"
if filtered:
s = self.create_filter_callable(node.filter_args.args, s, False)
@@ -556,7 +556,7 @@ class _GenerateRenderMethod(object):
inline=False, toplevel=False):
"""write a post-function decorator to replace a rendering
callable with a cached version of itself."""
-
+
self.printer.writeline("__M_%s = %s" % (name, name))
cachekey = node_or_pagetag.parsed_attributes.get('cache_key', repr(name))
cacheargs = {}
@@ -577,9 +577,9 @@ class _GenerateRenderMethod(object):
cacheargs[arg[1]] == int(eval(val))
else:
cacheargs[arg[1]] = val
-
+
self.printer.writeline("def %s(%s):" % (name, ','.join(args)))
-
+
# form "arg1, arg2, arg3=arg3, arg4=arg4", etc.
pass_args = [
'=' in a and "%s=%s" % ((a.split('=')[0],)*2) or a
@@ -615,7 +615,7 @@ class _GenerateRenderMethod(object):
"""write a filter-applying expression based on the filters
present in the given filter names, adjusting for the global
'default' filter aliases as needed."""
-
+
def locate_encode(name):
if re.match(r'decode\..+', name):
return "filters." + name
@@ -623,7 +623,7 @@ class _GenerateRenderMethod(object):
return filters.NON_UNICODE_ESCAPES.get(name, name)
else:
return filters.DEFAULT_ESCAPES.get(name, name)
-
+
if 'n' not in args:
if is_expression:
if self.compiler.pagetag:
@@ -645,7 +645,7 @@ class _GenerateRenderMethod(object):
assert e is not None
target = "%s(%s)" % (e, target)
return target
-
+
def visitExpression(self, node):
self.write_source_comment(node)
if len(node.escapes) or \
@@ -654,12 +654,12 @@ class _GenerateRenderMethod(object):
len(self.compiler.pagetag.filter_args.args)
) or \
len(self.compiler.default_filters):
-
+
s = self.create_filter_callable(node.escapes_code.args, "%s" % node.text, True)
self.printer.writeline("__M_writer(%s)" % s)
else:
self.printer.writeline("__M_writer(%s)" % node.text)
-
+
def visitControlLine(self, node):
if node.isend:
if not node.get_children():
@@ -668,11 +668,11 @@ class _GenerateRenderMethod(object):
else:
self.write_source_comment(node)
self.printer.writeline(node.text)
-
+
def visitText(self, node):
self.write_source_comment(node)
self.printer.writeline("__M_writer(%s)" % repr(node.content))
-
+
def visitTextTag(self, node):
filtered = len(node.filter_args.args) > 0
if filtered:
@@ -693,7 +693,7 @@ class _GenerateRenderMethod(object):
False),
None
)
-
+
def visitCode(self, node):
if not node.ismodule:
self.write_source_comment(node)
@@ -722,10 +722,10 @@ class _GenerateRenderMethod(object):
self.printer.writeline(
"runtime._include_file(context, %s, _template_uri)" %
(node.parsed_attributes['file']))
-
+
def visitNamespaceTag(self, node):
pass
-
+
def visitDefTag(self, node):
pass
@@ -734,7 +734,7 @@ class _GenerateRenderMethod(object):
# as ensure the given namespace will be imported,
# pre-import the namespace, etc.
self.visitCallTag(node)
-
+
def visitCallTag(self, node):
self.printer.writeline("def ccall(caller):")
export = ['body']
@@ -745,7 +745,7 @@ class _GenerateRenderMethod(object):
# <%def>s within <%call> we want the current caller
# off the call stack (if any)
body_identifiers.add_declared('caller')
-
+
self.identifier_stack.append(body_identifiers)
class DefVisitor(object):
def visitDefTag(s, node):
@@ -760,10 +760,10 @@ class _GenerateRenderMethod(object):
for n in node.nodes:
n.accept_visitor(vis)
self.identifier_stack.pop()
-
- bodyargs = node.body_decl.get_argument_expressions()
+
+ bodyargs = node.body_decl.get_argument_expressions()
self.printer.writeline("def body(%s):" % ','.join(bodyargs))
-
+
# TODO: figure out best way to specify
# buffering/nonbuffering (at call time would be better)
buffered = False
@@ -774,11 +774,11 @@ class _GenerateRenderMethod(object):
)
self.write_variable_declares(body_identifiers)
self.identifier_stack.append(body_identifiers)
-
+
for n in node.nodes:
n.accept_visitor(self)
self.identifier_stack.pop()
-
+
self.write_def_finish(node, buffered, False, False, callstack=False)
self.printer.writelines(
None,
@@ -803,9 +803,9 @@ class _GenerateRenderMethod(object):
class _Identifiers(object):
"""tracks the status of identifier names as template code is rendered."""
-
+
def __init__(self, node=None, parent=None, nested=False):
-
+
if parent is not None:
# if we are the branch created in write_namespaces(),
# we don't share any context from the main body().
@@ -819,56 +819,56 @@ class _Identifiers(object):
union([c.name for c in parent.closuredefs.values()]).\
union(parent.locally_declared).\
union(parent.argument_declared)
-
+
# if these identifiers correspond to a "nested"
# scope, it means whatever the parent identifiers
# had as undeclared will have been declared by that parent,
# and therefore we have them in our scope.
if nested:
self.declared = self.declared.union(parent.undeclared)
-
+
# top level defs that are available
self.topleveldefs = util.SetLikeDict(**parent.topleveldefs)
else:
self.declared = set()
self.topleveldefs = util.SetLikeDict()
-
+
# things within this level that are referenced before they
# are declared (e.g. assigned to)
self.undeclared = set()
-
+
# things that are declared locally. some of these things
# could be in the "undeclared" list as well if they are
# referenced before declared
self.locally_declared = set()
-
- # assignments made in explicit python blocks.
+
+ # assignments made in explicit python blocks.
# these will be propagated to
# the context of local def calls.
self.locally_assigned = set()
-
+
# things that are declared in the argument
# signature of the def callable
self.argument_declared = set()
-
+
# closure defs that are defined in this level
self.closuredefs = util.SetLikeDict()
-
+
self.node = node
-
+
if node is not None:
node.accept_visitor(self)
-
+
def branch(self, node, **kwargs):
"""create a new Identifiers for a new Node, with
this Identifiers as the parent."""
-
+
return _Identifiers(node, self, **kwargs)
-
+
@property
def defs(self):
return set(self.topleveldefs.union(self.closuredefs).values())
-
+
def __repr__(self):
return "Identifiers(declared=%r, locally_declared=%r, "\
"undeclared=%r, topleveldefs=%r, closuredefs=%r, argumentdeclared=%r)" %\
@@ -879,33 +879,33 @@ class _Identifiers(object):
[c.name for c in self.topleveldefs.values()],
[c.name for c in self.closuredefs.values()],
self.argument_declared)
-
+
def check_declared(self, node):
"""update the state of this Identifiers with the undeclared
and declared identifiers of the given node."""
-
+
for ident in node.undeclared_identifiers():
if ident != 'context' and ident not in self.declared.union(self.locally_declared):
self.undeclared.add(ident)
for ident in node.declared_identifiers():
self.locally_declared.add(ident)
-
+
def add_declared(self, ident):
self.declared.add(ident)
if ident in self.undeclared:
self.undeclared.remove(ident)
-
+
def visitExpression(self, node):
self.check_declared(node)
-
+
def visitControlLine(self, node):
self.check_declared(node)
-
+
def visitCode(self, node):
if not node.ismodule:
self.check_declared(node)
self.locally_assigned = self.locally_assigned.union(node.declared_identifiers())
-
+
def visitNamespaceTag(self, node):
# only traverse into the sub-elements of a
# <%namespace> tag if we are the branch created in
@@ -913,7 +913,7 @@ class _Identifiers(object):
if self.node is node:
for n in node.nodes:
n.accept_visitor(self)
-
+
def visitDefTag(self, node):
if node.is_root():
self.topleveldefs[node.name] = node
@@ -923,25 +923,25 @@ class _Identifiers(object):
for ident in node.undeclared_identifiers():
if ident != 'context' and ident not in self.declared.union(self.locally_declared):
self.undeclared.add(ident)
-
+
# visit defs only one level deep
if node is self.node:
for ident in node.declared_identifiers():
self.argument_declared.add(ident)
for n in node.nodes:
n.accept_visitor(self)
-
+
def visitIncludeTag(self, node):
self.check_declared(node)
-
+
def visitPageTag(self, node):
for ident in node.declared_identifiers():
self.argument_declared.add(ident)
self.check_declared(node)
-
+
def visitCallNamespaceTag(self, node):
self.visitCallTag(node)
-
+
def visitCallTag(self, node):
if node is self.node:
for ident in node.undeclared_identifiers():
@@ -955,4 +955,4 @@ class _Identifiers(object):
for ident in node.undeclared_identifiers():
if ident != 'context' and ident not in self.declared.union(self.locally_declared):
self.undeclared.add(ident)
-
+
diff --git a/mako/exceptions.py b/mako/exceptions.py
index 5976d65..d7fb12b 100644
--- a/mako/exceptions.py
+++ b/mako/exceptions.py
@@ -20,8 +20,8 @@ def _format_filepos(lineno, pos, filename):
return " at line: %d char: %d" % (lineno, pos)
else:
return " in file '%s' at line: %d char: %d" % (filename, lineno, pos)
-
-
+
+
class CompileException(MakoException):
def __init__(self, message, source, lineno, pos, filename):
MakoException.__init__(self, message + _format_filepos(lineno, pos, filename))
@@ -29,7 +29,7 @@ class CompileException(MakoException):
self.pos = pos
self.filename = filename
self.source = source
-
+
class SyntaxException(MakoException):
def __init__(self, message, source, lineno, pos, filename):
MakoException.__init__(self, message + _format_filepos(lineno, pos, filename))
@@ -40,47 +40,47 @@ class SyntaxException(MakoException):
class UnsupportedError(MakoException):
"""raised when a retired feature is used."""
-
+
class TemplateLookupException(MakoException):
pass
class TopLevelLookupException(TemplateLookupException):
pass
-
+
class RichTraceback(object):
"""Pulls the current exception from the sys traceback and extracts
Mako-specific template information.
-
+
See the usage examples in :ref:`handling_exceptions`.
-
+
"""
def __init__(self, error=None, traceback=None):
self.source, self.lineno = "", 0
if error is None or traceback is None:
t, value, tback = sys.exc_info()
-
+
if error is None:
error = value or t
-
+
if traceback is None:
traceback = tback
-
+
self.error = error
self.records = self._init(traceback)
-
+
if isinstance(self.error, (CompileException, SyntaxException)):
import mako.template
self.source = self.error.source
self.lineno = self.error.lineno
self._has_source = True
-
+
self._init_message()
-
+
@property
def errorname(self):
return util.exception_name(self.error)
-
+
def _init_message(self):
"""Find a unicode representation of self.error"""
try:
@@ -101,25 +101,25 @@ class RichTraceback(object):
yield (rec[4], rec[5], rec[2], rec[6])
else:
yield tuple(rec[0:4])
-
+
@property
def traceback(self):
"""return a list of 4-tuple traceback records (i.e. normal python
format) with template-corresponding lines remapped to the originating
template.
-
+
"""
return list(self._get_reformatted_records(self.records))
-
+
@property
def reverse_records(self):
return reversed(self.records)
-
+
@property
def reverse_traceback(self):
"""return the same data as traceback, except in reverse order.
"""
-
+
return list(self._get_reformatted_records(self.reverse_records))
def _init(self, trcback):
@@ -204,13 +204,13 @@ class RichTraceback(object):
self.lineno = new_trcback[-1][1]
return new_trcback
-
+
def text_error_template(lookup=None):
"""Provides a template that renders a stack trace in a similar format to
the Python interpreter, substituting source template filenames, line
numbers and code for that of the originating source template, as
applicable.
-
+
"""
import mako.template
return mako.template.Template(r"""
@@ -239,7 +239,7 @@ def html_error_template():
template has two options. With the full option disabled, only a section of
an HTML document is returned. with the css option disabled, the default
stylesheet won't be included.
-
+
"""
import mako.template
return mako.template.Template(r"""
diff --git a/mako/ext/autohandler.py b/mako/ext/autohandler.py
index 2ca88e1..5e1474a 100644
--- a/mako/ext/autohandler.py
+++ b/mako/ext/autohandler.py
@@ -42,7 +42,7 @@ def autohandler(template, context, name='autohandler'):
if len(tokens) == 1:
break
tokens[-2:] = [name]
-
+
if not lookup.filesystem_checks:
return lookup._uri_cache.setdefault(
(autohandler, _template_uri, name), None)
@@ -56,4 +56,4 @@ def _file_exists(lookup, path):
return True
else:
return False
-
+
diff --git a/mako/ext/preprocessors.py b/mako/ext/preprocessors.py
index 3361cc7..2f7c47d 100644
--- a/mako/ext/preprocessors.py
+++ b/mako/ext/preprocessors.py
@@ -5,9 +5,9 @@ import re
def convert_comments(text):
"""preprocess old style comments.
-
+
example:
-
+
from mako.ext.preprocessors import convert_comments
t = Template(..., preprocessor=preprocess_comments)"""
return re.sub(r'(?<=\n)\s*#[^#]', "##", text)
diff --git a/mako/ext/turbogears.py b/mako/ext/turbogears.py
index f82f907..22b707a 100644
--- a/mako/ext/turbogears.py
+++ b/mako/ext/turbogears.py
@@ -19,7 +19,7 @@ class TGPlugin(object):
elif k in ['directories', 'filesystem_checks', 'module_directory']:
lookup_options[k] = v
self.lookup = TemplateLookup(**lookup_options)
-
+
self.tmpl_options = {}
# transfer lookup args to template args, based on those available
# in getargspec
diff --git a/mako/filters.py b/mako/filters.py
index 23b77e1..3c1af69 100644
--- a/mako/filters.py
+++ b/mako/filters.py
@@ -14,7 +14,7 @@ xml_escapes = {
'>' : '&gt;',
'<' : '&lt;',
'"' : '&#34;', # also &quot; in html-only
- "'" : '&#39;' # also &apos; in html-only
+ "'" : '&#39;' # also &apos; in html-only
}
# XXX: &quot; is valid in HTML and XML
@@ -32,7 +32,7 @@ try:
except ImportError:
html_escape = legacy_html_escape
-
+
def xml_escape(string):
return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string)
@@ -62,14 +62,14 @@ class Decode(object):
return unicode(x, encoding=key)
return decode
decode = Decode()
-
-
+
+
_ASCII_re = re.compile(r'\A[\x00-\x7f]*\Z')
def is_ascii_str(text):
return isinstance(text, str) and _ASCII_re.match(text)
-################################################################
+################################################################
class XMLEntityEscaper(object):
def __init__(self, codepoint2name, name2codepoint):
@@ -116,7 +116,7 @@ class XMLEntityEscaper(object):
| ( (?!\d) [:\w] [-.:\w]+ )
) ;''',
re.X | re.UNICODE)
-
+
def __unescape(self, m):
dval, hval, name = m.groups()
if dval:
@@ -129,7 +129,7 @@ class XMLEntityEscaper(object):
if codepoint < 128:
return chr(codepoint)
return unichr(codepoint)
-
+
def unescape(self, text):
"""Unescape character references.
diff --git a/mako/lexer.py b/mako/lexer.py
index 241853c..bd1fb70 100644
--- a/mako/lexer.py
+++ b/mako/lexer.py
@@ -27,29 +27,29 @@ class Lexer(object):
self.control_line = []
self.disable_unicode = disable_unicode
self.encoding = input_encoding
-
+
if util.py3k and disable_unicode:
raise exceptions.UnsupportedError(
"Mako for Python 3 does not "
"support disabling Unicode")
-
+
if preprocessor is None:
self.preprocessor = []
elif not hasattr(preprocessor, '__iter__'):
self.preprocessor = [preprocessor]
else:
self.preprocessor = preprocessor
-
+
@property
def exception_kwargs(self):
return {'source':self.text,
'lineno':self.matched_lineno,
'pos':self.matched_charpos,
'filename':self.filename}
-
+
def match(self, regexp, flags=None):
"""compile the given regexp, cache the reg, and call match_reg()."""
-
+
try:
reg = _regexp_cache[(regexp, flags)]
except KeyError:
@@ -58,14 +58,14 @@ class Lexer(object):
else:
reg = re.compile(regexp)
_regexp_cache[(regexp, flags)] = reg
-
+
return self.match_reg(reg)
-
+
def match_reg(self, reg):
"""match the given regular expression object to the current text position.
-
+
if a match occurs, update the current text and line position.
-
+
"""
mp = self.match_position
@@ -88,7 +88,7 @@ class Lexer(object):
# self.matched_lineno, "LINE END:", self.lineno
#print "MATCH:", regexp, "\n", self.text[mp : mp + 15], (match and "TRUE" or "FALSE")
return match
-
+
def parse_until_text(self, *text):
startpos = self.match_position
while True:
@@ -116,7 +116,7 @@ class Lexer(object):
"Expected: %s" %
','.join(text),
**self.exception_kwargs)
-
+
def append_node(self, nodecls, *args, **kwargs):
kwargs.setdefault('source', self.text)
kwargs.setdefault('lineno', self.matched_lineno)
@@ -193,17 +193,17 @@ class Lexer(object):
for preproc in self.preprocessor:
self.text = preproc(self.text)
-
+
# push the match marker past the
# encoding comment.
self.match_reg(self._coding_re)
-
+
self.textlength = len(self.text)
-
+
while (True):
if self.match_position > self.textlength:
break
-
+
if self.match_end():
break
if self.match_expression():
@@ -220,11 +220,11 @@ class Lexer(object):
continue
if self.match_text():
continue
-
+
if self.match_position > self.textlength:
break
raise exceptions.CompileException("assertion failed")
-
+
if len(self.tag):
raise exceptions.SyntaxException("Unclosed tag: <%%%s>" %
self.tag[-1].keyword,
@@ -240,19 +240,19 @@ class Lexer(object):
def match_tag_start(self):
match = self.match(r'''
\<% # opening tag
-
+
([\w\.\:]+) # keyword
-
+
((?:\s+\w+|\s*=\s*|".*?"|'.*?')*) # attrname, = sign, string expression
-
+
\s* # more whitespace
-
+
(/)?> # closing
-
+
''',
-
+
re.I | re.S | re.X)
-
+
if match:
keyword, attr, isend = match.group(1), match.group(2), match.group(3)
self.keyword = keyword
@@ -279,7 +279,7 @@ class Lexer(object):
return True
else:
return False
-
+
def match_tag_end(self):
match = self.match(r'\</%[\t ]*(.+?)[\t ]*>')
if match:
@@ -297,7 +297,7 @@ class Lexer(object):
return True
else:
return False
-
+
def match_end(self):
match = self.match(r'\Z', re.S)
if match:
@@ -308,7 +308,7 @@ class Lexer(object):
return True
else:
return False
-
+
def match_text(self):
match = self.match(r"""
(.*?) # anything, followed by:
@@ -328,7 +328,7 @@ class Lexer(object):
|
\Z # end of string
)""", re.X | re.S)
-
+
if match:
text = match.group(1)
if text:
@@ -336,7 +336,7 @@ class Lexer(object):
return True
else:
return False
-
+
def match_python_block(self):
match = self.match(r"<%(!)?")
if match:
@@ -344,7 +344,7 @@ class Lexer(object):
text, end = self.parse_until_text(r'%>')
# the trailing newline helps
# compiler.parse() not complain about indentation
- text = adjust_whitespace(text) + "\n"
+ text = adjust_whitespace(text) + "\n"
self.append_node(
parsetree.Code,
text,
@@ -352,7 +352,7 @@ class Lexer(object):
return True
else:
return False
-
+
def match_expression(self):
match = self.match(r"\${")
if match:
@@ -385,7 +385,7 @@ class Lexer(object):
**self.exception_kwargs)
isend, keyword = m2.group(1, 2)
isend = (isend is not None)
-
+
if isend:
if not len(self.control_line):
raise exceptions.SyntaxException(
@@ -412,4 +412,4 @@ class Lexer(object):
return True
else:
return False
-
+
diff --git a/mako/lookup.py b/mako/lookup.py
index c1fd391..18bbf8c 100644
--- a/mako/lookup.py
+++ b/mako/lookup.py
@@ -13,21 +13,21 @@ try:
import threading
except:
import dummy_threading as threading
-
+
class TemplateCollection(object):
"""Represent a collection of :class:`.Template` objects,
identifiable via uri.
-
+
A :class:`.TemplateCollection` is linked to the usage of
all template tags that address other templates, such
as ``<%include>``, ``<%namespace>``, and ``<%inherit>``.
The ``file`` attribute of each of those tags refers
to a string URI that is passed to that :class:`.Template`
object's :class:`.TemplateCollection` for resolution.
-
+
:class:`.TemplateCollection` is an abstract class,
with the usual default implementation being :class:`.TemplateLookup`.
-
+
"""
def has_template(self, uri):
@@ -36,7 +36,7 @@ class TemplateCollection(object):
given URL.
:param uri: String uri of the template to be resolved.
-
+
"""
try:
self.get_template(uri)
@@ -47,28 +47,28 @@ class TemplateCollection(object):
def get_template(self, uri, relativeto=None):
"""Return a :class:`.Template` object corresponding to the given
URL.
-
+
The default implementation raises
:class:`.NotImplementedError`. Implementations should
raise :class:`.TemplateLookupException` if the given uri
cannot be resolved.
-
+
:param uri: String uri of the template to be resolved.
:param relativeto: if present, the given URI is assumed to
be relative to this uri.
-
+
"""
raise NotImplementedError()
def filename_to_uri(self, uri, filename):
"""Convert the given filename to a uri relative to
this TemplateCollection."""
-
+
return uri
-
+
def adjust_uri(self, uri, filename):
"""Adjust the given uri based on the calling filename.
-
+
When this method is called from the runtime, the
'filename' parameter is taken directly to the 'filename'
attribute of the calling template. Therefore a custom
@@ -76,38 +76,38 @@ class TemplateCollection(object):
identifier desired in the "filename" parameter of the
Template objects it constructs and have them come back
here.
-
+
"""
return uri
-
+
class TemplateLookup(TemplateCollection):
"""Represent a collection of templates that locates template source files
from the local filesystem.
-
+
The primary argument is the ``directories`` argument, the list of
directories to search::
-
+
lookup = TemplateLookup(["/path/to/templates"])
some_template = lookup.get_template("/index.html")
-
+
The :class:`.TemplateLookup` can also be given :class:`.Template` objects
programatically using :meth:`.put_string` or :meth:`.put_template`::
-
+
lookup = TemplateLookup()
lookup.put_string("base.html", '''
<html><body>${self.next()}</body></html>
''')
lookup.put_string("hello.html", '''
<%include file='base.html'/>
-
+
Hello, world !
''')
-
-
+
+
:param directories: A list of directory names which will be
searched for a particular template URI. The URI is appended
to each directory and the filesystem checked.
-
+
:param collection_size: Approximate size of the collection used
to store templates. If left at its default of -1, the size
is unbounded, and a plain Python dictionary is used to
@@ -115,7 +115,7 @@ class TemplateLookup(TemplateCollection):
Otherwise, a least-recently-used cache object is used which
will maintain the size of the collection approximately to
the number given.
-
+
:param filesystem_checks: When at its default value of ``True``,
each call to :meth:`TemplateLookup.get_template()` will
compare the filesystem last modified time to the time in
@@ -124,7 +124,7 @@ class TemplateLookup(TemplateCollection):
new :class:`.Template` whenever the original source has
been updated. Set this to ``False`` for a very minor
performance increase.
-
+
:param modulename_callable: A callable which, when present,
is passed the path of the source file as well as the
requested URI, and then returns the full path of the
@@ -132,15 +132,15 @@ class TemplateLookup(TemplateCollection):
alternate schemes for Pyhton module location. If left at
its default of ``None``, the built in system of generation
based on ``module_directory`` plus ``uri`` is used.
-
+
All other keyword parameters available for
:class:`.Template` are mirrored here. When new
:class:`.Template` objects are created, the keywords
established with this :class:`.TemplateLookup` are passed on
to each new :class:`.Template`.
-
+
"""
-
+
def __init__(self,
directories=None,
module_directory=None,
@@ -161,7 +161,7 @@ class TemplateLookup(TemplateCollection):
imports=None,
input_encoding=None,
preprocessor=None):
-
+
self.directories = [posixpath.normpath(d) for d in
util.to_list(directories, ())
]
@@ -183,7 +183,7 @@ class TemplateLookup(TemplateCollection):
'cache_url':cache_url,
'cache_enabled':cache_enabled,
'default_filters':default_filters,
- 'buffer_filters':buffer_filters,
+ 'buffer_filters':buffer_filters,
'strict_undefined':strict_undefined,
'imports':imports,
'preprocessor':preprocessor}
@@ -195,15 +195,15 @@ class TemplateLookup(TemplateCollection):
self._collection = util.LRUCache(collection_size)
self._uri_cache = util.LRUCache(collection_size)
self._mutex = threading.Lock()
-
+
def get_template(self, uri):
"""Return a :class:`.Template` object corresponding to the given
URL.
-
+
Note the "relativeto" argument is not supported here at the moment.
-
+
"""
-
+
try:
if self.filesystem_checks:
return self._check(uri, self._collection[uri])
@@ -221,7 +221,7 @@ class TemplateLookup(TemplateCollection):
def adjust_uri(self, uri, relativeto):
"""adjust the given uri based on the given relative uri."""
-
+
if uri[0] != '/':
if relativeto is not None:
return posixpath.join(posixpath.dirname(relativeto), uri)
@@ -229,8 +229,8 @@ class TemplateLookup(TemplateCollection):
return '/' + uri
else:
return uri
-
-
+
+
def filename_to_uri(self, filename):
"""Convert the given filename to a uri relative to
this TemplateCollection."""
@@ -241,20 +241,20 @@ class TemplateLookup(TemplateCollection):
value = self._relativeize(filename)
self._uri_cache[filename] = value
return value
-
+
def _relativeize(self, filename):
"""Return the portion of a filename that is 'relative'
to the directories in this lookup.
-
+
"""
-
+
filename = posixpath.normpath(filename)
for dir in self.directories:
if filename[0:len(dir)] == dir:
return filename[len(dir):]
else:
return None
-
+
def _load(self, filename, uri):
self._mutex.acquire()
try:
@@ -284,7 +284,7 @@ class TemplateLookup(TemplateCollection):
raise
finally:
self._mutex.release()
-
+
def _check(self, uri, template):
if template.filename is None:
return template
@@ -298,24 +298,24 @@ class TemplateLookup(TemplateCollection):
return self._load(template.filename, uri)
else:
return template
-
+
def put_string(self, uri, text):
"""Place a new :class:`.Template` object into this
:class:`.TemplateLookup`, based on the given string of
text.
-
+
"""
self._collection[uri] = Template(
text,
lookup=self,
uri=uri,
**self.template_args)
-
+
def put_template(self, uri, template):
"""Place a new :class:`.Template` object into this
:class:`.TemplateLookup`, based on the given
:class:`.Template` object.
-
+
"""
self._collection[uri] = template
-
+
diff --git a/mako/parsetree.py b/mako/parsetree.py
index 68816f8..3fbd2fc 100644
--- a/mako/parsetree.py
+++ b/mako/parsetree.py
@@ -16,15 +16,15 @@ class Node(object):
self.lineno = lineno
self.pos = pos
self.filename = filename
-
+
@property
def exception_kwargs(self):
return {'source':self.source, 'lineno':self.lineno,
'pos':self.pos, 'filename':self.filename}
-
+
def get_children(self):
return []
-
+
def accept_visitor(self, visitor):
def traverse(node):
for n in node.get_children():
@@ -34,29 +34,29 @@ class Node(object):
class TemplateNode(Node):
"""a 'container' node that stores the overall collection of nodes."""
-
+
def __init__(self, filename):
super(TemplateNode, self).__init__('', 0, 0, filename)
self.nodes = []
self.page_attributes = {}
-
+
def get_children(self):
return self.nodes
-
+
def __repr__(self):
return "TemplateNode(%s, %r)" % (
util.sorted_dict_repr(self.page_attributes),
self.nodes)
-
+
class ControlLine(Node):
"""defines a control line, a line-oriented python line or end tag.
-
+
e.g.::
% if foo:
(markup)
% endif
-
+
"""
def __init__(self, keyword, isend, text, **kwargs):
@@ -78,17 +78,17 @@ class ControlLine(Node):
def undeclared_identifiers(self):
return self._undeclared_identifiers
-
+
def is_ternary(self, keyword):
"""return true if the given keyword is a ternary keyword
for this ControlLine"""
-
+
return keyword in {
'if':set(['else', 'elif']),
'try':set(['except', 'finally']),
'for':set(['else'])
}.get(self.keyword, [])
-
+
def __repr__(self):
return "ControlLine(%r, %r, %r, %r)" % (
self.keyword,
@@ -99,29 +99,29 @@ class ControlLine(Node):
class Text(Node):
"""defines plain text in the template."""
-
+
def __init__(self, content, **kwargs):
super(Text, self).__init__(**kwargs)
self.content = content
-
+
def __repr__(self):
return "Text(%r, %r)" % (self.content, (self.lineno, self.pos))
-
+
class Code(Node):
"""defines a Python code block, either inline or module level.
-
+
e.g.::
inline:
<%
x = 12
%>
-
+
module level:
<%!
import logger
%>
-
+
"""
def __init__(self, text, ismodule, **kwargs):
@@ -142,28 +142,28 @@ class Code(Node):
self.ismodule,
(self.lineno, self.pos)
)
-
+
class Comment(Node):
"""defines a comment line.
-
+
# this is a comment
-
+
"""
-
+
def __init__(self, text, **kwargs):
super(Comment, self).__init__(**kwargs)
self.text = text
def __repr__(self):
return "Comment(%r, %r)" % (self.text, (self.lineno, self.pos))
-
+
class Expression(Node):
"""defines an inline expression.
-
+
${x+y}
-
+
"""
-
+
def __init__(self, text, escapes, **kwargs):
super(Expression, self).__init__(**kwargs)
self.text = text
@@ -188,18 +188,18 @@ class Expression(Node):
self.escapes_code.args,
(self.lineno, self.pos)
)
-
+
class _TagMeta(type):
"""metaclass to allow Tag to produce a subclass according to
its keyword"""
-
+
_classmap = {}
-
+
def __init__(cls, clsname, bases, dict):
if cls.__keyword__ is not None:
cls._classmap[cls.__keyword__] = cls
super(_TagMeta, cls).__init__(clsname, bases, dict)
-
+
def __call__(cls, keyword, attributes, **kwargs):
if ":" in keyword:
ns, defname = keyword.split(':')
@@ -217,41 +217,41 @@ class _TagMeta(type):
filename=kwargs['filename']
)
return type.__call__(cls, keyword, attributes, **kwargs)
-
+
class Tag(Node):
"""abstract base class for tags.
-
+
<%sometag/>
-
+
<%someothertag>
stuff
</%someothertag>
-
+
"""
-
+
__metaclass__ = _TagMeta
__keyword__ = None
-
+
def __init__(self, keyword, attributes, expressions,
nonexpressions, required, **kwargs):
"""construct a new Tag instance.
-
+
this constructor not called directly, and is only called
by subclasses.
-
+
:param keyword: the tag keyword
-
+
:param attributes: raw dictionary of attribute key/value pairs
-
+
:param expressions: a set of identifiers that are legal attributes,
which can also contain embedded expressions
-
+
:param nonexpressions: a set of identifiers that are legal
attributes, which cannot contain embedded expressions
-
+
:param \**kwargs:
other arguments passed to the Node superclass (lineno, pos)
-
+
"""
super(Tag, self).__init__(**kwargs)
self.keyword = keyword
@@ -265,13 +265,13 @@ class Tag(Node):
**self.exception_kwargs)
self.parent = None
self.nodes = []
-
+
def is_root(self):
return self.parent is None
-
+
def get_children(self):
return self.nodes
-
+
def _parse_attributes(self, expressions, nonexpressions):
undeclared_identifiers = set()
self.parsed_attributes = {}
@@ -323,7 +323,7 @@ class Tag(Node):
(self.lineno, self.pos),
self.nodes
)
-
+
class IncludeTag(Tag):
__keyword__ = 'include'
@@ -346,7 +346,7 @@ class IncludeTag(Tag):
difference(self.page_args.declared_identifiers)
return identifiers.union(super(IncludeTag, self).
undeclared_identifiers())
-
+
class NamespaceTag(Tag):
__keyword__ = 'namespace'
@@ -357,7 +357,7 @@ class NamespaceTag(Tag):
('name','inheritable',
'import','module'),
(), **kwargs)
-
+
self.name = attributes.get('name', '__anon_%s' % hex(abs(id(self))))
if not 'name' in attributes and not 'import' in attributes:
raise exceptions.CompileException(
@@ -379,7 +379,7 @@ class TextTag(Tag):
self.filter_args = ast.ArgumentList(
attributes.get('filter', ''),
**self.exception_kwargs)
-
+
class DefTag(Tag):
__keyword__ = 'def'
@@ -446,7 +446,7 @@ class CallNamespaceTag(Tag):
(),
(),
**kwargs)
-
+
self.expression = "%s.%s(%s)" % (
namespace,
defname,
@@ -495,5 +495,5 @@ class PageTag(Tag):
def declared_identifiers(self):
return self.body_decl.argnames
-
-
+
+
diff --git a/mako/pygen.py b/mako/pygen.py
index 9415305..fd19a99 100644
--- a/mako/pygen.py
+++ b/mako/pygen.py
@@ -14,48 +14,48 @@ class PythonPrinter(object):
def __init__(self, stream):
# indentation counter
self.indent = 0
-
+
# a stack storing information about why we incremented
# the indentation counter, to help us determine if we
# should decrement it
self.indent_detail = []
-
+
# the string of whitespace multiplied by the indent
# counter to produce a line
self.indentstring = " "
-
+
# the stream we are writing to
self.stream = stream
-
+
# a list of lines that represents a buffered "block" of code,
# which can be later printed relative to an indent level
self.line_buffer = []
-
+
self.in_indent_lines = False
-
+
self._reset_multi_line_flags()
def write(self, text):
self.stream.write(text)
-
+
def write_indented_block(self, block):
"""print a line or lines of python which already contain indentation.
-
+
The indentation of the total block of lines will be adjusted to that of
the current indent level."""
self.in_indent_lines = False
for l in re.split(r'\r?\n', block):
self.line_buffer.append(l)
-
+
def writelines(self, *lines):
"""print a series of lines of python."""
for line in lines:
self.writeline(line)
-
+
def writeline(self, line):
"""print a line of python, indenting it according to the current
indent level.
-
+
this also adjusts the indentation counter according to the
content of the line.
@@ -66,7 +66,7 @@ class PythonPrinter(object):
self.in_indent_lines = True
decreased_indent = False
-
+
if (line is None or
re.match(r"^\s*#",line) or
re.match(r"^\s*$", line)
@@ -76,29 +76,29 @@ class PythonPrinter(object):
hastext = True
is_comment = line and len(line) and line[0] == '#'
-
+
# see if this line should decrease the indentation level
if (not decreased_indent and
not is_comment and
(not hastext or self._is_unindentor(line))
):
-
+
if self.indent > 0:
self.indent -=1
# if the indent_detail stack is empty, the user
# probably put extra closures - the resulting
- # module wont compile.
- if len(self.indent_detail) == 0:
+ # module wont compile.
+ if len(self.indent_detail) == 0:
raise exceptions.SyntaxException(
"Too many whitespace closures")
self.indent_detail.pop()
-
+
if line is None:
return
-
+
# write the line
self.stream.write(self._indent_line(line) + "\n")
-
+
# see if this line should increase the indentation level.
# note that a line can both decrase (before printing) and
# then increase (after printing) the indentation level.
@@ -127,39 +127,39 @@ class PythonPrinter(object):
def close(self):
"""close this printer, flushing any remaining lines."""
self._flush_adjusted_lines()
-
+
def _is_unindentor(self, line):
"""return true if the given line is an 'unindentor',
relative to the last 'indent' event received.
-
+
"""
-
+
# no indentation detail has been pushed on; return False
if len(self.indent_detail) == 0:
return False
indentor = self.indent_detail[-1]
-
+
# the last indent keyword we grabbed is not a
# compound statement keyword; return False
if indentor is None:
return False
-
+
# if the current line doesnt have one of the "unindentor" keywords,
# return False
match = re.match(r"^\s*(else|elif|except|finally).*\:", line)
if not match:
return False
-
+
# whitespace matches up, we have a compound indentor,
# and this line has an unindentor, this
# is probably good enough
return True
-
+
# should we decide that its not good enough, heres
# more stuff to check.
#keyword = match.group(1)
-
+
# match the original indent keyword
#for crit in [
# (r'if|elif', r'else|elif'),
@@ -168,12 +168,12 @@ class PythonPrinter(object):
#]:
# if re.match(crit[0], indentor) and re.match(crit[1], keyword):
# return True
-
+
#return False
-
+
def _indent_line(self, line, stripspace=''):
"""indent the given line according to the current indent level.
-
+
stripspace is a string of space that will be truncated from the
start of the line before indenting."""
@@ -185,7 +185,7 @@ class PythonPrinter(object):
or triple-quoted section."""
self.backslashed, self.triplequoted = False, False
-
+
def _in_multi_line(self, line):
"""return true if the given line is part of a multi-line block,
via backslash or triple-quote."""
@@ -195,24 +195,24 @@ class PythonPrinter(object):
# guard against the possibility of modifying the space inside of
# a literal multiline string with unfortunately placed
# whitespace
-
+
current_state = (self.backslashed or self.triplequoted)
-
+
if re.search(r"\\$", line):
self.backslashed = True
else:
self.backslashed = False
-
+
triples = len(re.findall(r"\"\"\"|\'\'\'", line))
if triples == 1 or triples % 2 != 0:
self.triplequoted = not self.triplequoted
-
+
return current_state
def _flush_adjusted_lines(self):
stripspace = None
self._reset_multi_line_flags()
-
+
for entry in self.line_buffer:
if self._in_multi_line(entry):
self.stream.write(entry + "\n")
@@ -221,32 +221,32 @@ class PythonPrinter(object):
if stripspace is None and re.search(r"^[ \t]*[^# \t]", entry):
stripspace = re.match(r"^([ \t]*)", entry).group(1)
self.stream.write(self._indent_line(entry, stripspace) + "\n")
-
+
self.line_buffer = []
self._reset_multi_line_flags()
def adjust_whitespace(text):
"""remove the left-whitespace margin of a block of Python code."""
-
+
state = [False, False]
(backslashed, triplequoted) = (0, 1)
def in_multi_line(line):
start_state = (state[backslashed] or state[triplequoted])
-
+
if re.search(r"\\$", line):
state[backslashed] = True
else:
state[backslashed] = False
-
+
def match(reg, t):
m = re.match(reg, t)
if m:
return m, t[len(m.group(0)):]
else:
return None, t
-
+
while line:
if state[triplequoted]:
m, line = match(r"%s" % state[triplequoted], line)
@@ -258,14 +258,14 @@ def adjust_whitespace(text):
m, line = match(r'#', line)
if m:
return start_state
-
+
m, line = match(r"\"\"\"|\'\'\'", line)
if m:
state[triplequoted] = m.group(0)
continue
m, line = match(r".*?(?=\"\"\"|\'\'\'|#|$)", line)
-
+
return start_state
def _indent_line(line, stripspace = ''):
diff --git a/mako/pyparser.py b/mako/pyparser.py
index ab9c2b6..4192ddd 100644
--- a/mako/pyparser.py
+++ b/mako/pyparser.py
@@ -25,7 +25,7 @@ else:
# words that cannot be assigned to (notably
# smaller than the total keys in __builtins__)
reserved = set(['True', 'False', 'None'])
-
+
# the "id" attribute on a function node
arg_id = operator.attrgetter('id')
@@ -42,7 +42,7 @@ except ImportError:
def parse(code, mode='exec', **exception_kwargs):
"""Parse an expression into AST"""
-
+
try:
if _ast:
diff --git a/mako/runtime.py b/mako/runtime.py
index 7713f0d..1011aa4 100644
--- a/mako/runtime.py
+++ b/mako/runtime.py
@@ -13,18 +13,18 @@ import __builtin__, inspect, sys
class Context(object):
"""Provides runtime namespace, output buffer, and various
callstacks for templates.
-
+
See :ref:`runtime_toplevel` for detail on the usage of
:class:`.Context`.
-
+
"""
-
+
def __init__(self, buffer, **data):
self._buffer_stack = [buffer]
-
+
# original data, minus the builtins
self._orig = data
-
+
# the context data which includes builtins
self._data = __builtin__.__dict__.copy()
self._data.update(data)
@@ -32,55 +32,55 @@ class Context(object):
self._with_template = None
self._outputting_as_unicode = None
self.namespaces = {}
-
+
# "capture" function which proxies to the
# generic "capture" function
self._data['capture'] = util.partial(capture, self)
-
+
# "caller" stack used by def calls with content
self.caller_stack = self._data['caller'] = CallerStack()
-
+
@property
def lookup(self):
"""Return the :class:`.TemplateLookup` associated
with this :class:`.Context`.
-
+
"""
return self._with_template.lookup
-
+
@property
def kwargs(self):
"""Return the dictionary of keyword argments associated with this
:class:`.Context`.
-
+
"""
return self._kwargs.copy()
-
+
def push_caller(self, caller):
"""Pushes a 'caller' callable onto the callstack for
this :class:`.Context`."""
-
-
+
+
self.caller_stack.append(caller)
-
+
def pop_caller(self):
"""Pops a 'caller' callable onto the callstack for this
:class:`.Context`."""
del self.caller_stack[-1]
-
+
def keys(self):
"""Return a list of all names established in this :class:`.Context`."""
return self._data.keys()
-
+
def __getitem__(self, key):
return self._data[key]
def _push_writer(self):
"""push a capturing buffer onto this Context and return
the new writer function."""
-
+
buf = util.FastEncodingBuffer()
self._buffer_stack.append(buf)
return buf.write
@@ -88,33 +88,33 @@ class Context(object):
def _pop_buffer_and_writer(self):
"""pop the most recent capturing buffer from this Context
and return the current writer after the pop.
-
+
"""
buf = self._buffer_stack.pop()
return buf, self._buffer_stack[-1].write
-
+
def _push_buffer(self):
"""push a capturing buffer onto this Context."""
-
+
self._push_writer()
-
+
def _pop_buffer(self):
"""pop the most recent capturing buffer from this Context."""
-
+
return self._buffer_stack.pop()
-
+
def get(self, key, default=None):
"""Return a value from this :class:`.Context`."""
-
+
return self._data.get(key, default)
-
+
def write(self, string):
"""Write a string to this :class:`.Context` object's
underlying output buffer."""
-
+
self._buffer_stack[-1].write(string)
-
+
def writer(self):
"""Return the current writer function"""
@@ -131,17 +131,17 @@ class Context(object):
c.namespaces = self.namespaces
c.caller_stack = self.caller_stack
return c
-
+
def locals_(self, d):
"""create a new :class:`.Context` with a copy of this
:class:`Context`'s current state, updated with the given dictionary."""
-
+
if len(d) == 0:
return self
c = self._copy()
c._data.update(d)
return c
-
+
def _clean_inheritance_tokens(self):
"""create a new copy of this :class:`.Context`. with
tokens related to inheritance state removed."""
@@ -167,15 +167,15 @@ class CallerStack(list):
self.nextcaller = None
def _pop_frame(self):
self.nextcaller = self.pop()
-
-
+
+
class Undefined(object):
"""Represents an undefined value in a template.
-
+
All template modules have a constant value
``UNDEFINED`` present which is an instance of this
object.
-
+
"""
def __str__(self):
raise NameError("Undefined")
@@ -194,22 +194,22 @@ class _NSAttr(object):
return getattr(ns.module, key)
else:
ns = ns.inherits
- raise AttributeError(key)
-
+ raise AttributeError(key)
+
class Namespace(object):
"""Provides access to collections of rendering methods, which
can be local, from other templates, or from imported modules.
-
+
To access a particular rendering method referenced by a
:class:`.Namespace`, use plain attribute access::
-
+
${some_namespace.foo(x, y, z)}
-
+
:class:`.Namespace` also contains several built-in attributes
described here.
-
+
"""
-
+
def __init__(self, name, context, module=None,
template=None, templateuri=None,
callables=None, inherits=None,
@@ -238,7 +238,7 @@ class Namespace(object):
if populate_self and self.template is not None:
lclcallable, lclcontext = \
_populate_self_namespace(context, self.template, self_ns=self)
-
+
template = None
"""The :class:`.Template` object referenced by this
:class:`.Namespace`, if any.
@@ -247,7 +247,7 @@ class Namespace(object):
context = None
"""The :class:`.Context` object for this namespace.
-
+
Namespaces are often created with copies of contexts that
contain slightly different data, particularly in inheritance
scenarios. Using the :class:`.Context` off of a :class:`.Namespace` one
@@ -255,41 +255,41 @@ class Namespace(object):
one-another.
"""
-
-
+
+
@property
def module(self):
"""The Python module referenced by this Namespace.
-
+
If the namespace references a :class:`.Template`, then
this module is the equivalent of ``template.module``,
i.e. the generated module for the template.
"""
return self._module or self.template.module
-
+
@property
def filename(self):
"""The path of the filesystem file used for this
Namespace's module or template.
-
+
If this is a pure module-based
Namespace, this evaluates to ``module.__file__``. If a
template-based namespace, it evaluates to the original
template file location.
-
+
"""
if self._module:
return self._module.__file__
else:
return self.template.filename
-
+
@property
def uri(self):
"""The uri for this Namespace's template.
-
+
I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
-
+
This is the equivalent of :attr:`Template.uri`.
"""
@@ -298,7 +298,7 @@ class Namespace(object):
@property
def attr(self):
"""Access module level attributes by name.
-
+
This accessor allows templates to supply "scalar"
attributes which are particularly handy in inheritance
relationships. See the example in
@@ -311,7 +311,7 @@ class Namespace(object):
def get_namespace(self, uri):
"""Return a :class:`.Namespace` corresponding to the given uri.
-
+
If the given uri is a relative uri (i.e. it does not
contain ia leading slash ``/``), the uri is adjusted to
be relative to the uri of the namespace itself. This
@@ -327,7 +327,7 @@ class Namespace(object):
expressions that were generated within the body code of
the template, or to conditionally use a particular
namespace.
-
+
"""
key = (self, uri)
if self.context.namespaces.has_key(key):
@@ -338,28 +338,28 @@ class Namespace(object):
calling_uri=self._templateuri)
self.context.namespaces[key] = ns
return ns
-
+
def get_template(self, uri):
"""Return a :class:`.Template` from the given uri.
-
+
The uri resolution is relative to the uri of this :class:`.Namespace`
object's :class:`.Template`.
-
+
"""
return _lookup_template(self.context, uri, self._templateuri)
-
+
def get_cached(self, key, **kwargs):
"""Return a value from the :class:`.Cache` referenced by this
:class:`.Namespace` object's :class:`.Template`.
-
+
The advantage to this method versus direct access to the
:class:`.Cache` is that the configuration parameters
declared in ``<%page>`` take effect here, thereby calling
up the same configured backend as that configured
by ``<%page>``.
-
+
"""
-
+
if self.template:
if not self.template.cache_enabled:
createfunc = kwargs.get('createfunc', None)
@@ -367,7 +367,7 @@ class Namespace(object):
return createfunc()
else:
return None
-
+
if self.template.cache_dir:
kwargs.setdefault('data_dir', self.template.cache_dir)
if self.template.cache_type:
@@ -375,20 +375,20 @@ class Namespace(object):
if self.template.cache_url:
kwargs.setdefault('url', self.template.cache_url)
return self.cache.get(key, **kwargs)
-
+
@property
def cache(self):
"""Return the :class:`.Cache` object referenced by this :class:`.Namespace` object's
:class:`.Template`.
-
+
"""
return self.template.cache
-
+
def include_file(self, uri, **kwargs):
"""Include a file at the given uri"""
-
+
_include_file(self.context, uri, self._templateuri, **kwargs)
-
+
def _populate(self, d, l):
for ident in l:
if ident == '*':
@@ -396,7 +396,7 @@ class Namespace(object):
d[k] = v
else:
d[ident] = getattr(self, ident)
-
+
def _get_star(self):
if self.callables:
for key in self.callables:
@@ -414,7 +414,7 @@ class Namespace(object):
for k in dir(self._module):
if k[0] != '_':
yield (k, get(k))
-
+
def __getattr__(self, key):
if self.callables and key in self.callables:
return self.callables[key]
@@ -436,11 +436,11 @@ class Namespace(object):
def supports_caller(func):
"""Apply a caller_stack compatibility decorator to a plain
Python function.
-
+
See the example in :ref:`namespaces_python_modules`.
-
+
"""
-
+
def wrap_stackframe(context, *args, **kwargs):
context.caller_stack._push_frame()
try:
@@ -448,15 +448,15 @@ def supports_caller(func):
finally:
context.caller_stack._pop_frame()
return wrap_stackframe
-
+
def capture(context, callable_, *args, **kwargs):
"""Execute the given template def, capturing the output into
a buffer.
-
+
See the example in :ref:`namespaces_python_modules`.
-
+
"""
-
+
if not callable(callable_):
raise exceptions.RuntimeException(
"capture() function expects a callable as "
@@ -482,7 +482,7 @@ def _decorate_toplevel(fn):
return fn(y)(context, *args, **kw)
return go
return decorate_render
-
+
def _decorate_inline(context, fn):
def decorate_render(render_fn):
dec = fn(render_fn)
@@ -490,17 +490,17 @@ def _decorate_inline(context, fn):
return dec(context, *args, **kw)
return go
return decorate_render
-
+
def _include_file(context, uri, calling_uri, **kwargs):
"""locate the template from the given uri and include it in
the current output."""
-
+
template = _lookup_template(context, uri, calling_uri)
(callable_, ctx) = _populate_self_namespace(
context._clean_inheritance_tokens(),
template)
callable_(ctx, **_kwargs_for_include(callable_, context._orig, **kwargs))
-
+
def _inherit_from(context, uri, calling_uri):
"""called by the _inherit method in template modules to set
up the inheritance chain at the start of a template's
@@ -570,7 +570,7 @@ def _render(template, callable_, args, data, as_unicode=False):
context = Context(buf, **data)
context._outputting_as_unicode = as_unicode
context._with_template = template
-
+
_render_context(template, callable_, context, *args,
**_kwargs_for_callable(callable_, data))
return context._pop_buffer().getvalue()
@@ -580,7 +580,7 @@ def _kwargs_for_callable(callable_, data):
# for normal pages, **pageargs is usually present
if argspec[2]:
return data
-
+
# for rendering defs from the top level, figure out the args
namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
kwargs = {}
@@ -596,7 +596,7 @@ def _kwargs_for_include(callable_, data, **kwargs):
if arg != 'context' and arg in data and arg not in kwargs:
kwargs[arg] = data[arg]
return kwargs
-
+
def _render_context(tmpl, callable_, context, *args, **kwargs):
import mako.template as template
# create polymorphic 'self' namespace for this
@@ -609,7 +609,7 @@ def _render_context(tmpl, callable_, context, *args, **kwargs):
# otherwise, call the actual rendering method specified
(inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent)
_exec_template(callable_, context, args=args, kwargs=kwargs)
-
+
def _exec_template(callable_, context, args=None, kwargs=None):
"""execute a rendering callable given the callable, a
Context, and optional explicit arguments
@@ -626,7 +626,7 @@ def _exec_template(callable_, context, args=None, kwargs=None):
callable_(context, *args, **kwargs)
except Exception, e:
_render_error(template, context, e)
- except:
+ except:
e = sys.exc_info()[0]
_render_error(template, context, e)
else:
@@ -645,6 +645,6 @@ def _render_error(template, context, error):
context._buffer_stack[:] = [util.FastEncodingBuffer(
error_template.output_encoding,
error_template.encoding_errors)]
-
+
context._with_template = error_template
error_template.render_context(context, error=error)
diff --git a/mako/template.py b/mako/template.py
index bc1f40b..e152c3b 100644
--- a/mako/template.py
+++ b/mako/template.py
@@ -12,10 +12,10 @@ from mako.lexer import Lexer
from mako import runtime, util, exceptions, codegen
import imp, os, re, shutil, stat, sys, tempfile, time, types, weakref
-
+
class Template(object):
"""Represents a compiled template.
-
+
:class:`.Template` includes a reference to the original
template source (via the ``.source`` attribute)
as well as the source code of the
@@ -25,7 +25,7 @@ class Template(object):
:class:`.Template` is constructed using either a literal string
representing the template text, or a filename representing a filesystem
path to a source file.
-
+
:param text: textual template source. This argument is mutually
exclusive versus the "filename" parameter.
@@ -39,16 +39,16 @@ class Template(object):
creation of default expression filters that let the output
of return-valued %defs "opt out" of that filtering via
passing special attributes or objects.
-
+
:param cache_dir: Filesystem directory where cache files will be
placed. See :ref:`caching_toplevel`.
-
+
:param cache_enabled: Boolean flag which enables caching of this
template. See :ref:`caching_toplevel`.
-
+
:param cache_type: Type of Beaker caching to be applied to the
template. See :ref:`caching_toplevel`.
-
+
:param cache_url: URL of a memcached server with which to use
for caching. See :ref:`caching_toplevel`.
@@ -60,7 +60,7 @@ class Template(object):
:param encoding_errors: Error parameter passed to ``encode()`` when
string encoding is performed. See :ref:`usage_unicode`.
-
+
:param error_handler: Python callable which is called whenever
compile or runtime exceptions occur. The callable is passed
the current context as well as the exception. If the
@@ -68,13 +68,13 @@ class Template(object):
be handled, else it is re-raised after the function
completes. Is used to provide custom error-rendering
functions.
-
+
:param format_exceptions: if ``True``, exceptions which occur during
the render phase of this template will be caught and
formatted into an HTML error page, which then becomes the
rendered result of the :meth:`render` call. Otherwise,
runtime exceptions are propagated outwards.
-
+
:param imports: String list of Python statements, typically individual
"import" lines, which will be placed into the module level
preamble of all generated Python modules. See the example
@@ -84,43 +84,43 @@ class Template(object):
be used in lieu of the coding comment. See
:ref:`usage_unicode` as well as :ref:`unicode_toplevel` for
details on source encoding.
-
+
:param lookup: a :class:`.TemplateLookup` instance that will be used
for all file lookups via the ``<%namespace>``,
``<%include>``, and ``<%inherit>`` tags. See
:ref:`usage_templatelookup`.
-
+
:param module_directory: Filesystem location where generated
Python module files will be placed.
:param module_filename: Overrides the filename of the generated
Python module file. For advanced usage only.
-
+
:param output_encoding: The encoding to use when :meth:`.render`
is called. See :ref:`usage_unicode` as well as
:ref:`unicode_toplevel`.
-
+
:param preprocessor: Python callable which will be passed
the full template source before it is parsed. The return
result of the callable will be used as the template source
code.
-
+
:param strict_undefined: Replaces the automatic usage of
``UNDEFINED`` for any undeclared variables not located in
the :class:`.Context` with an immediate raise of
``NameError``. The advantage is immediate reporting of
missing variables which include the name. New in 0.3.6.
-
- :param uri: string uri or other identifier for this template.
+
+ :param uri: string uri or other identifier for this template.
If not provided, the uri is generated from the filesystem
path, or from the in-memory identity of a non-file-based
template. The primary usage of the uri is to provide a key
within :class:`.TemplateLookup`, as well as to generate the
file path of the generated Python module file, if
``module_directory`` is specified.
-
+
"""
-
+
def __init__(self,
text=None,
filename=None,
@@ -154,7 +154,7 @@ class Template(object):
else:
self.module_id = "memory:" + hex(id(self))
self.uri = self.module_id
-
+
self.input_encoding = input_encoding
self.output_encoding = output_encoding
self.encoding_errors = encoding_errors
@@ -165,7 +165,7 @@ class Template(object):
raise exceptions.UnsupportedError(
"Mako for Python 3 does not "
"support disabling Unicode")
-
+
if default_filters is None:
if util.py3k or self.disable_unicode:
self.default_filters = ['str']
@@ -174,10 +174,10 @@ class Template(object):
else:
self.default_filters = default_filters
self.buffer_filters = buffer_filters
-
+
self.imports = imports
self.preprocessor = preprocessor
-
+
# if plain text, compile code in memory only
if text is not None:
(code, module) = _compile_text(self, text, filename)
@@ -201,7 +201,7 @@ class Template(object):
)
else:
path = None
-
+
module = self._compile_from_file(path, filename)
else:
raise exceptions.RuntimeException(
@@ -217,7 +217,7 @@ class Template(object):
self.cache_dir = cache_dir
self.cache_url = cache_url
self.cache_enabled = cache_enabled
-
+
def _compile_from_file(self, path, filename):
if path is not None:
util.verify_directory(os.path.dirname(path))
@@ -251,26 +251,26 @@ class Template(object):
self._code = code
ModuleInfo(module, None, self, filename, code, None)
return module
-
+
@property
def source(self):
"""return the template source code for this Template."""
-
+
return _get_module_info_from_callable(self.callable_).source
@property
def code(self):
"""return the module source code for this Template"""
-
+
return _get_module_info_from_callable(self.callable_).code
-
+
@property
def cache(self):
return self.module._template_cache
-
+
def render(self, *args, **data):
"""Render the output of this template as a string.
-
+
if the template specifies an output encoding, the string
will be encoded accordingly, else the output is raw (raw
output uses cStringIO and can't handle multibyte
@@ -278,24 +278,24 @@ class Template(object):
to the given data. Arguments that are explictly declared
by this template's internal rendering method are also
pulled from the given \*args, \**data members.
-
+
"""
return runtime._render(self, self.callable_, args, data)
-
+
def render_unicode(self, *args, **data):
"""render the output of this template as a unicode object."""
-
+
return runtime._render(self,
self.callable_,
args,
data,
as_unicode=True)
-
+
def render_context(self, context, *args, **kwargs):
- """Render this Template with the given context.
-
+ """Render this Template with the given context.
+
the data is written to the context's buffer.
-
+
"""
if getattr(context, '_with_template', None) is None:
context._with_template = self
@@ -304,39 +304,39 @@ class Template(object):
context,
*args,
**kwargs)
-
+
def has_def(self, name):
return hasattr(self.module, "render_%s" % name)
-
+
def get_def(self, name):
"""Return a def of this template as a :class:`.DefTemplate`."""
-
+
return DefTemplate(self, getattr(self.module, "render_%s" % name))
def _get_def_callable(self, name):
return getattr(self.module, "render_%s" % name)
-
+
@property
def last_modified(self):
- return self.module._modified_time
-
+ return self.module._modified_time
+
class ModuleTemplate(Template):
"""A Template which is constructed given an existing Python module.
-
+
e.g.::
-
+
t = Template("this is a template")
f = file("mymodule.py", "w")
f.write(t.code)
f.close()
-
+
import mymodule
-
+
t = ModuleTemplate(mymodule)
print t.render()
-
+
"""
-
+
def __init__(self, module,
module_filename=None,
template=None,
@@ -368,7 +368,7 @@ class ModuleTemplate(Template):
template_filename,
module_source,
template_source)
-
+
self.callable_ = self.module.render_body
self.format_exceptions = format_exceptions
self.error_handler = error_handler
@@ -377,11 +377,11 @@ class ModuleTemplate(Template):
self.cache_dir = cache_dir
self.cache_url = cache_url
self.cache_enabled = cache_enabled
-
+
class DefTemplate(Template):
"""a Template which represents a callable def in a parent
template."""
-
+
def __init__(self, parent, callable_):
self.parent = parent
self.callable_ = callable_
@@ -399,7 +399,7 @@ class ModuleInfo(object):
"""Stores information about a module currently loaded into
memory, provides reverse lookups of template source, module
source code based on a module's identifier.
-
+
"""
_modules = weakref.WeakValueDictionary()
@@ -418,14 +418,14 @@ class ModuleInfo(object):
self._modules[module.__name__] = template._mmarker = self
if module_filename:
self._modules[module_filename] = self
-
+
@property
def code(self):
if self.module_source is not None:
return self.module_source
else:
return open(self.module_filename).read()
-
+
@property
def source(self):
if self.template_source is not None:
@@ -441,7 +441,7 @@ class ModuleInfo(object):
decode(self.module._source_encoding)
else:
return open(self.template_filename).read()
-
+
def _compile_text(template, text, filename):
identifier = template.module_id
lexer = Lexer(text,
@@ -450,7 +450,7 @@ def _compile_text(template, text, filename):
input_encoding=template.input_encoding,
preprocessor=template.preprocessor)
node = lexer.parse()
-
+
source = codegen.compile(node,
template.uri,
filename,
@@ -477,7 +477,7 @@ def _compile_module_file(template, text, filename, outputpath):
disable_unicode=template.disable_unicode,
input_encoding=template.input_encoding,
preprocessor=template.preprocessor)
-
+
node = lexer.parse()
source = codegen.compile(node,
template.uri,
@@ -489,22 +489,22 @@ def _compile_module_file(template, text, filename, outputpath):
generate_magic_comment=True,
disable_unicode=template.disable_unicode,
strict_undefined=template.strict_undefined)
-
+
# make tempfiles in the same location as the ultimate
# location. this ensures they're on the same filesystem,
# avoiding synchronization issues.
(dest, name) = tempfile.mkstemp(dir=os.path.dirname(outputpath))
-
+
if isinstance(source, unicode):
source = source.encode(lexer.encoding or 'ascii')
-
+
os.write(dest, source)
os.close(dest)
shutil.move(name, outputpath)
def _get_module_info_from_callable(callable_):
return _get_module_info(callable_.func_globals['__name__'])
-
+
def _get_module_info(filename):
return ModuleInfo._modules[filename]
-
+
diff --git a/mako/util.py b/mako/util.py
index 4c741b7..8d0385a 100644
--- a/mako/util.py
+++ b/mako/util.py
@@ -33,7 +33,7 @@ if win32 or jython:
time_func = time.clock
else:
time_func = time.time
-
+
def function_named(fn, name):
"""Return a function with a given __name__.
@@ -63,12 +63,12 @@ if py24:
else:
def exception_name(exc):
return exc.__class__.__name__
-
+
def verify_directory(dir):
"""create and/or verify a filesystem directory."""
-
+
tries = 0
-
+
while not os.path.exists(dir):
try:
tries += 1
@@ -86,14 +86,14 @@ def to_list(x, default=None):
return x
-
+
class SetLikeDict(dict):
"""a dictionary that has some setlike methods on it"""
def union(self, other):
"""produce a 'union' of this dict and another (at the key level).
-
+
values in the second dict take precedence over that of the first"""
x = SetLikeDict(**self)
x.update(other)
@@ -102,7 +102,7 @@ class SetLikeDict(dict):
class FastEncodingBuffer(object):
"""a very rudimentary buffer that is faster than StringIO,
but doesnt crash on unicode data like cStringIO."""
-
+
def __init__(self, encoding=None, errors='strict', unicode=False):
self.data = []
self.encoding = encoding
@@ -113,10 +113,10 @@ class FastEncodingBuffer(object):
self.unicode = unicode
self.errors = errors
self.write = self.data.append
-
+
def truncate(self):
self.data =[]
-
+
def getvalue(self):
if self.encoding:
return self.delim.join(self.data).encode(self.encoding, self.errors)
@@ -126,12 +126,12 @@ class FastEncodingBuffer(object):
class LRUCache(dict):
"""A dictionary-like object that stores a limited number of items, discarding
lesser used items periodically.
-
+
this is a rewrite of LRUCache from Myghty to use a periodic timestamp-based
paradigm so that synchronization is not really needed. the size management
is inexact.
"""
-
+
class _Item(object):
def __init__(self, key, value):
self.key = key
@@ -139,26 +139,26 @@ class LRUCache(dict):
self.timestamp = time_func()
def __repr__(self):
return repr(self.value)
-
+
def __init__(self, capacity, threshold=.5):
self.capacity = capacity
self.threshold = threshold
-
+
def __getitem__(self, key):
item = dict.__getitem__(self, key)
item.timestamp = time_func()
return item.value
-
+
def values(self):
return [i.value for i in dict.values(self)]
-
+
def setdefault(self, key, value):
if key in self:
return self[key]
else:
self[key] = value
return value
-
+
def __setitem__(self, key, value):
item = dict.get(self, key)
if item is None:
@@ -167,7 +167,7 @@ class LRUCache(dict):
else:
item.value = value
self._manage_size()
-
+
def _manage_size(self):
while len(self) > self.capacity + self.capacity * self.threshold:
bytime = sorted(dict.values(self),
@@ -232,14 +232,14 @@ def parse_encoding(fp):
def sorted_dict_repr(d):
"""repr() a dictionary with the keys in order.
-
+
Used by the lexer unit test to compare parse trees based on strings.
-
+
"""
keys = d.keys()
keys.sort()
return "{" + ", ".join(["%r: %r" % (k, d[k]) for k in keys]) + "}"
-
+
def restore__ast(_ast):
"""Attempt to restore the required classes to the _ast module if it
appears to be missing them
diff --git a/setup.py b/setup.py
index c35fe53..de3a5c6 100644
--- a/setup.py
+++ b/setup.py
@@ -53,7 +53,7 @@ ties to Python calling and scoping semantics.
entry_points="""
[python.templating.engines]
mako = mako.ext.turbogears:TGPlugin
-
+
[pygments.lexers]
mako = mako.ext.pygmentplugin:MakoLexer
html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
diff --git a/test/__init__.py b/test/__init__.py
index f9e3118..d2a1f25 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -10,34 +10,34 @@ template_base = os.path.join(os.path.dirname(__file__), 'templates')
module_base = os.path.join(template_base, 'modules')
class TemplateTest(unittest.TestCase):
-
+
def _file_template(self, filename, **kw):
filepath = self._file_path(filename)
return Template(uri=filename, filename=filepath,
module_directory=module_base, **kw)
-
+
def _file_path(self, filename):
name, ext = os.path.splitext(filename)
-
+
if py3k:
py3k_path = os.path.join(template_base, name + "_py3k" + ext)
if os.path.exists(py3k_path):
return py3k_path
-
+
return os.path.join(template_base, filename)
-
+
def _do_file_test(self, filename, expected, filters=None,
unicode_=True, template_args=None, **kw):
t1 = self._file_template(filename, **kw)
self._do_test(t1, expected, filters=filters,
unicode_=unicode_, template_args=template_args)
-
+
def _do_memory_test(self, source, expected, filters=None,
unicode_=True, template_args=None, **kw):
t1 = Template(text=source, **kw)
self._do_test(t1, expected, filters=filters,
unicode_=unicode_, template_args=template_args)
-
+
def _do_test(self, template, expected, filters=None, template_args=None, unicode_=True):
if template_args is None:
template_args = {}
@@ -45,11 +45,11 @@ class TemplateTest(unittest.TestCase):
output = template.render_unicode(**template_args)
else:
output = template.render(**template_args)
-
+
if filters:
output = filters(output)
eq_(output, expected)
-
+
def eq_(a, b, msg=None):
"""Assert a == b, with repr messaging on failure."""
assert a == b, msg or "%r != %r" % (a, b)
@@ -64,7 +64,7 @@ def assert_raises(except_cls, callable_, *args, **kw):
success = False
except except_cls, e:
success = True
-
+
# assert outside the block so it works for AssertionError too !
assert success, "Callable did not raise an exception"
diff --git a/test/foo/test_ns.py b/test/foo/test_ns.py
index 084fe97..7a2425d 100644
--- a/test/foo/test_ns.py
+++ b/test/foo/test_ns.py
@@ -1,7 +1,7 @@
def foo1(context):
context.write("this is foo1.")
return ''
-
+
def foo2(context, x):
context.write("this is foo2, x is " + x)
return '' \ No newline at end of file
diff --git a/test/sample_module_namespace.py b/test/sample_module_namespace.py
index 084fe97..7a2425d 100644
--- a/test/sample_module_namespace.py
+++ b/test/sample_module_namespace.py
@@ -1,7 +1,7 @@
def foo1(context):
context.write("this is foo1.")
return ''
-
+
def foo2(context, x):
context.write("this is foo2, x is " + x)
return '' \ No newline at end of file
diff --git a/test/templates/gettext.mako b/test/templates/gettext.mako
index 8b7dfbb..df47d10 100644
--- a/test/templates/gettext.mako
+++ b/test/templates/gettext.mako
@@ -40,7 +40,7 @@ top = gettext('Begin')
## TRANSLATOR: Good bye
${_('Goodbye')}
</div>
-
+
<%def name="makerow(row=_('Babel'), count=1)">
<!-- ${ungettext('hella', 'hellas', count)} -->
% for i in range(count):
@@ -67,7 +67,7 @@ top = gettext('Begin')
<div id="end">
<a href="#top">
## TRANSLATOR: you won't see this either
-
+
${_('Top')}
</a>
</div>
diff --git a/test/templates/internationalization.html b/test/templates/internationalization.html
index 12ae25b..da5b61c 100644
--- a/test/templates/internationalization.html
+++ b/test/templates/internationalization.html
@@ -1,7 +1,7 @@
<div class="rst-docs">
-
+
<h1 class="pudge-member-page-heading">Internationalization, Localization and Unicode</h1>
-
+
<table rules="none" frame="void" class="docinfo">
<col class="docinfo-name"></col>
<col class="docinfo-content"></col>
diff --git a/test/test_ast.py b/test/test_ast.py
index b9fe948..adea08a 100644
--- a/test/test_ast.py
+++ b/test/test_ast.py
@@ -25,7 +25,7 @@ for lar in (1,2,3):
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.declared_identifiers == set(['a','b','c', 'g', 'h', 'i', 'u', 'k', 'j', 'gh', 'lar', 'x'])
assert parsed.undeclared_identifiers == set(['x', 'q', 'foo', 'gah', 'blah'])
-
+
parsed = ast.PythonCode("x + 5 * (y-z)", **exception_kwargs)
assert parsed.undeclared_identifiers == set(['x', 'y', 'z'])
assert parsed.declared_identifiers == set()
@@ -55,7 +55,7 @@ for y in range(1, y):
"""
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.undeclared_identifiers == set(['x', 'y', 'z', 'q', 'range'])
-
+
def test_locate_identifiers_4(self):
if util.py3k:
code = """
@@ -63,18 +63,18 @@ x = 5
(y, )
def mydef(mydefarg):
print("mda is", mydefarg)
-"""
+"""
else:
code = """
x = 5
(y, )
def mydef(mydefarg):
print "mda is", mydefarg
-"""
+"""
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.undeclared_identifiers == set(['y'])
assert parsed.declared_identifiers == set(['mydef', 'x'])
-
+
def test_locate_identifiers_5(self):
if util.py3k:
code = """
@@ -84,7 +84,7 @@ except:
print(y)
"""
else:
-
+
code = """
try:
print x
@@ -93,7 +93,7 @@ except:
"""
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.undeclared_identifiers == set(['x', 'y'])
-
+
def test_locate_identifiers_6(self):
code = """
def foo():
@@ -101,7 +101,7 @@ def foo():
"""
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.undeclared_identifiers == set(['bar'])
-
+
if util.py3k:
code = """
def lala(x, y):
@@ -117,7 +117,7 @@ print x
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.undeclared_identifiers == set(['z', 'x'])
assert parsed.declared_identifiers == set(['lala'])
-
+
if util.py3k:
code = """
def lala(x, y):
@@ -137,7 +137,7 @@ print z
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.undeclared_identifiers == set(['z'])
assert parsed.declared_identifiers == set(['lala'])
-
+
def test_locate_identifiers_7(self):
code = """
import foo.bar
@@ -156,7 +156,7 @@ class Hi(object):
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.declared_identifiers == set(['Hi'])
assert parsed.undeclared_identifiers == set()
-
+
def test_locate_identifiers_9(self):
code = """
",".join([t for t in ("a", "b", "c")])
@@ -164,14 +164,14 @@ class Hi(object):
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.declared_identifiers == set(['t'])
assert parsed.undeclared_identifiers == set(['t'])
-
+
code = """
[(val, name) for val, name in x]
"""
parsed = ast.PythonCode(code, **exception_kwargs)
assert parsed.declared_identifiers == set(['val', 'name'])
assert parsed.undeclared_identifiers == set(['val', 'name', 'x'])
-
+
def test_locate_identifiers_10(self):
code = """
lambda q: q + 5
@@ -179,7 +179,7 @@ lambda q: q + 5
parsed = ast.PythonCode(code, **exception_kwargs)
eq_(parsed.declared_identifiers, set())
eq_(parsed.undeclared_identifiers, set())
-
+
def test_locate_identifiers_11(self):
code = """
def x(q):
@@ -195,12 +195,12 @@ from foo import *
import x as bar
"""
self.assertRaises(exceptions.CompileException, ast.PythonCode, code, **exception_kwargs)
-
+
def test_python_fragment(self):
parsed = ast.PythonFragment("for x in foo:", **exception_kwargs)
assert parsed.declared_identifiers == set(['x'])
assert parsed.undeclared_identifiers == set(['foo'])
-
+
parsed = ast.PythonFragment("try:", **exception_kwargs)
if util.py3k:
@@ -209,7 +209,7 @@ import x as bar
parsed = ast.PythonFragment("except MyException, e:", **exception_kwargs)
eq_(parsed.declared_identifiers, set(['e']))
eq_(parsed.undeclared_identifiers, set(['MyException']))
-
+
def test_argument_list(self):
parsed = ast.ArgumentList("3, 5, 'hi', x+5, context.get('lala')", **exception_kwargs)
assert parsed.undeclared_identifiers == set(['x', 'context'])
@@ -231,7 +231,7 @@ import x as bar
parsed = ast.FunctionDecl(code, **exception_kwargs)
assert parsed.funcname=='foo'
assert parsed.argnames==['a', 'b', 'c', 'args', 'kwargs']
-
+
def test_expr_generate(self):
"""test the round trip of expressions to AST back to python source"""
x = 1
@@ -242,12 +242,12 @@ import x as bar
def lala(arg):
return "blah" + arg
local_dict = dict(x=x, y=y, foo=F(), lala=lala)
-
+
code = "str((x+7*y) / foo.bar(5,6)) + lala('ho')"
astnode = pyparser.parse(code)
newcode = pyparser.ExpressionGenerator(astnode).value()
assert (eval(code, local_dict) == eval(newcode, local_dict))
-
+
a = ["one", "two", "three"]
hoho = {'somevalue':"asdf"}
g = [1,2,3,4,5]
@@ -256,7 +256,7 @@ import x as bar
astnode = pyparser.parse(code)
newcode = pyparser.ExpressionGenerator(astnode).value()
assert(eval(code, local_dict) == eval(newcode, local_dict))
-
+
local_dict={'f':lambda :9, 'x':7}
code = "x+f()"
astnode = pyparser.parse(code)
@@ -269,5 +269,5 @@ import x as bar
newcode = pyparser.ExpressionGenerator(astnode).value()
assert(eval(code, local_dict)) == eval(newcode, local_dict), "%s != %s" % (code, newcode)
-
-
+
+
diff --git a/test/test_babelplugin.py b/test/test_babelplugin.py
index 2fea024..f6bbf01 100644
--- a/test/test_babelplugin.py
+++ b/test/test_babelplugin.py
@@ -6,13 +6,13 @@ try:
from mako.ext.babelplugin import extract
except:
babel = None
-
+
import os
class ExtractMakoTestCase(TemplateTest):
@skip_if(lambda: not babel, 'babel not installed: skipping babelplugin test')
-
+
def test_extract(self):
mako_tmpl = open(os.path.join(template_base, 'gettext.mako'))
messages = list(extract(mako_tmpl, {'_': None, 'gettext': None,
diff --git a/test/test_cache.py b/test/test_cache.py
index 11469f5..b2198b5 100644
--- a/test/test_cache.py
+++ b/test/test_cache.py
@@ -10,7 +10,7 @@ try:
except:
from nose import SkipTest
raise SkipTest("Beaker is required for these tests.")
-
+
class MockCache(object):
def __init__(self, realcache):
self.realcache = realcache
@@ -20,7 +20,7 @@ class MockCache(object):
self.kwargs.pop('createfunc', None)
self.kwargs.pop('defname', None)
return self.realcache.get(key, **kwargs)
-
+
class CacheTest(TemplateTest):
def test_def(self):
t = Template("""
@@ -33,7 +33,7 @@ class CacheTest(TemplateTest):
callcount[0] += 1
%>
</%def>
-
+
${foo()}
${foo()}
${foo()}
@@ -63,7 +63,7 @@ class CacheTest(TemplateTest):
m = self._install_mock_cache(t)
assert t.render().strip() =="callcount: [2]"
-
+
def test_nested_def(self):
t = Template("""
<%!
@@ -92,7 +92,7 @@ class CacheTest(TemplateTest):
'callcount: [1]',
]
assert m.kwargs == {}
-
+
def test_page(self):
t = Template("""
<%!
@@ -149,7 +149,7 @@ class CacheTest(TemplateTest):
assert result_lines(t.render()) == ['hi']
assert m.key == "foo_hi"
-
+
def test_dynamic_key_with_imports(self):
lookup = TemplateLookup()
lookup.put_string("foo.html", """
@@ -174,7 +174,7 @@ class CacheTest(TemplateTest):
"callcount: [1]"
]
assert m.kwargs == {}
-
+
def test_fileargs_implicit(self):
l = lookup.TemplateLookup(module_directory=module_base)
l.put_string("test","""
@@ -193,7 +193,7 @@ class CacheTest(TemplateTest):
${foo()}
callcount: ${callcount}
""")
-
+
m = self._install_mock_cache(l.get_template('test'))
assert result_lines(l.get_template('test').render()) == [
'this is foo',
@@ -202,7 +202,7 @@ class CacheTest(TemplateTest):
'callcount: [1]',
]
assert m.kwargs == {'type':'dbm', 'data_dir':module_base}
-
+
def test_fileargs_deftag(self):
t = Template("""
<%%!
@@ -267,7 +267,7 @@ class CacheTest(TemplateTest):
m = self._install_mock_cache(t)
t.render()
assert m.kwargs == {'data_dir':module_base, 'type':'file', 'expiretime':30}
-
+
t2 = Template("""
<%%page cached="True" cache_timeout="30" cache_dir="%s" cache_type="file" cache_key='somekey'/>
hi
@@ -294,7 +294,7 @@ class CacheTest(TemplateTest):
${foo()}
callcount: ${callcount}
""")
-
+
t = l.get_template('test')
m = self._install_mock_cache(t)
assert result_lines(l.get_template('test').render()) == [
@@ -304,7 +304,7 @@ class CacheTest(TemplateTest):
'callcount: [1]',
]
assert m.kwargs == {'data_dir':module_base, 'type':'file'}
-
+
def test_buffered(self):
t = Template("""
<%!
@@ -318,11 +318,11 @@ class CacheTest(TemplateTest):
</%def>
""", buffer_filters=["a"])
assert result_lines(t.render()) == ["this is a this is a test", "this is a this is a test"]
-
+
def test_load_from_expired(self):
"""test that the cache callable can be called safely after the
originating template has completed rendering.
-
+
"""
t = Template("""
${foo()}
@@ -330,13 +330,13 @@ class CacheTest(TemplateTest):
foo
</%def>
""")
-
+
import time
x1 = t.render()
time.sleep(3)
x2 = t.render()
assert x1.strip() == x2.strip() == "foo"
-
+
def test_cache_uses_current_context(self):
t = Template("""
${foo()}
@@ -344,7 +344,7 @@ class CacheTest(TemplateTest):
foo: ${x}
</%def>
""")
-
+
import time
x1 = t.render(x=1)
time.sleep(3)
@@ -367,7 +367,7 @@ class CacheTest(TemplateTest):
%>
""")
assert result_lines(t.render()) == ['foo: 1', 'foo: 1', 'foo: 3', 'foo: 3']
-
+
def test_invalidate(self):
t = Template("""
<%%def name="foo()" cached="True">
@@ -385,10 +385,10 @@ class CacheTest(TemplateTest):
assert result_lines(t.render(x=3)) == ["foo: 3", "bar: 1"]
t.cache.invalidate_def('bar')
assert result_lines(t.render(x=4)) == ["foo: 3", "bar: 4"]
-
+
t = Template("""
<%%page cached="True" cache_type="dbm" cache_dir="%s"/>
-
+
page: ${x}
""" % module_base)
assert result_lines(t.render(x=1)) == ["page: 1"]
@@ -396,8 +396,8 @@ class CacheTest(TemplateTest):
t.cache.invalidate_body()
assert result_lines(t.render(x=3)) == ["page: 3"]
assert result_lines(t.render(x=4)) == ["page: 3"]
-
-
+
+
def _install_mock_cache(self, template):
m = MockCache(template.module._template_cache)
template.module._template_cache = m
diff --git a/test/test_call.py b/test/test_call.py
index fecb2de..6aadf62 100644
--- a/test/test_call.py
+++ b/test/test_call.py
@@ -9,7 +9,7 @@ class CallTest(TemplateTest):
<%def name="foo()">
hi im foo ${caller.body(y=5)}
</%def>
-
+
<%call expr="foo()" args="y, **kwargs">
this is the body, y is ${y}
</%call>
@@ -23,16 +23,16 @@ class CallTest(TemplateTest):
<%def name="bar()">
this is bar
</%def>
-
+
<%def name="comp1()">
this comp1 should not be called
</%def>
-
+
<%def name="foo()">
foo calling comp1: ${caller.comp1(x=5)}
foo calling body: ${caller.body()}
</%def>
-
+
<%call expr="foo()">
<%def name="comp1(x)">
this is comp1, ${x}
@@ -46,10 +46,10 @@ class CallTest(TemplateTest):
def test_new_syntax(self):
"""test foo:bar syntax, including multiline args and expression eval."""
-
+
# note the trailing whitespace in the bottom ${} expr, need to strip
# that off < python 2.7
-
+
t = Template("""
<%def name="foo(x, y, q, z)">
${x}
@@ -57,26 +57,26 @@ class CallTest(TemplateTest):
${q}
${",".join("%s->%s" % (a, b) for a, b in z)}
</%def>
-
+
<%self:foo x="this is x" y="${'some ' + 'y'}" q="
this
is
q"
-
+
z="${[
(1, 2),
(3, 4),
(5, 6)
]
-
+
}"/>
""")
-
+
eq_(
result_lines(t.render()),
['this is x', 'some y', 'this', 'is', 'q', '1->2,3->4,5->6']
)
-
+
def test_ccall_caller(self):
t = Template("""
<%def name="outer_func()">
@@ -104,7 +104,7 @@ class CallTest(TemplateTest):
"INNER END",
"OUTER END",
]
-
+
def test_stack_pop(self):
t = Template("""
<%def name="links()" buffered="True">
@@ -130,7 +130,7 @@ class CallTest(TemplateTest):
"</h1>",
"Some links"
]
-
+
def test_conditional_call(self):
"""test that 'caller' is non-None only if the immediate <%def> was called via <%call>"""
@@ -169,7 +169,7 @@ class CallTest(TemplateTest):
"BBB",
"CCC"
]
-
+
def test_chained_call(self):
"""test %calls that are chained through their targets"""
t = Template("""
@@ -184,11 +184,11 @@ class CallTest(TemplateTest):
whats in the body's caller's body ?
${context.caller_stack[-2].body()}
</%def>
-
+
<%call expr="a()">
heres the main templ call
</%call>
-
+
""")
assert result_lines(t.render()) == [
'this is a.',
@@ -225,7 +225,7 @@ class CallTest(TemplateTest):
"bar:",
"this is bar body: 10"
]
-
+
def test_nested_call_2(self):
t = Template("""
x is ${x}
@@ -240,13 +240,13 @@ class CallTest(TemplateTest):
<%call expr="foo()">
<%def name="foosub(x)">
this is foo body: ${x}
-
+
<%call expr="bar()">
<%def name="barsub()">
this is bar body: ${x}
</%def>
</%call>
-
+
</%def>
</%call>
@@ -278,7 +278,7 @@ class CallTest(TemplateTest):
''')
assert flatten_result(template.render()) == "foo"
-
+
def test_chained_call_in_nested(self):
t = Template("""
<%def name="embedded()">
@@ -309,7 +309,7 @@ class CallTest(TemplateTest):
"whats in the body's caller's body ?",
'heres the main templ call'
]
-
+
def test_call_in_nested(self):
t = Template("""
<%def name="a()">
@@ -339,7 +339,7 @@ class CallTest(TemplateTest):
context.write("a is done")
return ''
%>
-
+
<%def name="b()">
this is b
our body: ${caller.body()}
@@ -362,7 +362,7 @@ class CallTest(TemplateTest):
</%call>
- """)
+ """)
#print t.code
assert result_lines(t.render()) == [
"test 1",
@@ -384,7 +384,7 @@ class CallTest(TemplateTest):
"this is aa is done",
"this is aa is done"
]
-
+
def test_call_in_nested_2(self):
t = Template("""
<%def name="a()">
@@ -415,7 +415,7 @@ class CallTest(TemplateTest):
class SelfCacheTest(TemplateTest):
"""this test uses a now non-public API."""
-
+
def test_basic(self):
t = Template("""
<%!
@@ -435,7 +435,7 @@ class SelfCacheTest(TemplateTest):
return cached
%>
</%def>
-
+
${foo()}
${foo()}
""")
@@ -444,4 +444,4 @@ class SelfCacheTest(TemplateTest):
"cached:",
"this is foo"
]
-
+
diff --git a/test/test_decorators.py b/test/test_decorators.py
index 62ba360..fc8768b 100644
--- a/test/test_decorators.py
+++ b/test/test_decorators.py
@@ -12,11 +12,11 @@ class DecoratorTest(unittest.TestCase):
return "BAR" + runtime.capture(context, fn, *args, **kw) + "BAR"
return decorate
%>
-
+
<%def name="foo(y, x)" decorator="bar">
this is foo ${y} ${x}
</%def>
-
+
${foo(1, x=5)}
""")
@@ -56,7 +56,7 @@ class DecoratorTest(unittest.TestCase):
%>
<%def name="foo()">
-
+
<%def name="bar()" decorator="bat">
this is bar
</%def>
@@ -67,7 +67,7 @@ class DecoratorTest(unittest.TestCase):
""")
assert flatten_result(template.render()) == "BAT this is bar BAT"
-
+
def test_toplevel_decorated_name(self):
template = Template("""
<%!
@@ -107,4 +107,4 @@ class DecoratorTest(unittest.TestCase):
""")
assert flatten_result(template.render()) == "function bar this is bar"
-
+
diff --git a/test/test_def.py b/test/test_def.py
index fa5908e..3ec63ff 100644
--- a/test/test_def.py
+++ b/test/test_def.py
@@ -6,13 +6,13 @@ from util import flatten_result, result_lines
class DefTest(TemplateTest):
def test_def_noargs(self):
template = Template("""
-
+
${mycomp()}
-
+
<%def name="mycomp()">
hello mycomp ${variable}
</%def>
-
+
""")
assert template.render(variable='hi').strip() == """hello mycomp hi"""
@@ -55,7 +55,7 @@ class DefTest(TemplateTest):
# check that "a" is declared in "b", but not in "c"
assert "a" not in template.module.render_c.func_code.co_varnames
assert "a" in template.module.render_b.func_code.co_varnames
-
+
# then test output
assert flatten_result(template.render()) == "im b and heres a: im a"
@@ -63,9 +63,9 @@ class DefTest(TemplateTest):
"""test calling a def from the top level"""
template = Template("""
-
+
this is the body
-
+
<%def name="a()">
this is a
</%def>
@@ -73,22 +73,22 @@ class DefTest(TemplateTest):
<%def name="b(x, y)">
this is b, ${x} ${y}
</%def>
-
+
""")
-
+
self._do_test(template.get_def("a"), "this is a", filters=flatten_result)
self._do_test(template.get_def("b"), "this is b, 10 15",
template_args={'x':10, 'y':15},
filters=flatten_result)
self._do_test(template.get_def("body"), "this is the body", filters=flatten_result)
-
+
# test that args outside of the dict can be used
self._do_test(template.get_def("a"), "this is a",
filters=flatten_result, template_args={'q':5,'zq':'test'})
-
+
class ScopeTest(TemplateTest):
"""test scoping rules. The key is, enclosing scope always takes precedence over contextual scope."""
-
+
def test_scope_one(self):
self._do_memory_test("""
<%def name="a()">
@@ -134,7 +134,7 @@ class ScopeTest(TemplateTest):
<%def name="a()">
this is a. x is ${x}.
</%def>
-
+
<%def name="b()">
<%
x = 9
@@ -142,11 +142,11 @@ class ScopeTest(TemplateTest):
this is b. x is ${x}.
calling a. ${a()}
</%def>
-
+
${b()}
""")
assert flatten_result(t.render()) == "this is b. x is 9. calling a. this is a. x is 5."
-
+
def test_scope_five(self):
"""test that variables are pulled from 'enclosing' scope before context."""
# same as test four, but adds a scope around it.
@@ -225,7 +225,7 @@ class ScopeTest(TemplateTest):
<%
x = 10
%>
-
+
b. x is ${x}. ${a()}
</%def>
@@ -237,7 +237,7 @@ class ScopeTest(TemplateTest):
def test_scope_nine(self):
"""test that 'enclosing scope' doesnt get exported to other templates"""
-
+
l = lookup.TemplateLookup()
l.put_string('main', """
<%
@@ -251,7 +251,7 @@ class ScopeTest(TemplateTest):
""")
assert flatten_result(l.get_template('main').render(x=2)) == "this is main. this is secondary. x is 2"
-
+
def test_scope_ten(self):
t = Template("""
<%def name="a()">
@@ -291,7 +291,7 @@ class ScopeTest(TemplateTest):
this is b, x is ${x}
</%def>
</%def>
-
+
${a(x=5)}
""")
assert result_lines(t.render(x=10)) == [
@@ -349,23 +349,23 @@ class ScopeTest(TemplateTest):
"""test that arguments passed to the body() function are accessible by top-level defs"""
l = lookup.TemplateLookup()
l.put_string("base", """
-
+
${next.body(x=12)}
-
+
""")
-
+
l.put_string("main", """
<%inherit file="base"/>
<%page args="x"/>
this is main. x is ${x}
-
+
${a()}
-
+
<%def name="a(**args)">
this is a, x is ${x}
</%def>
""")
-
+
# test via inheritance
#print l.get_template("main").code
assert result_lines(l.get_template("main").render()) == [
@@ -375,7 +375,7 @@ class ScopeTest(TemplateTest):
l.put_string("another", """
<%namespace name="ns" file="main"/>
-
+
${ns.body(x=15)}
""")
# test via namespace
@@ -389,15 +389,15 @@ class NestedDefTest(TemplateTest):
t = Template("""
${hi()}
-
+
<%def name="hi()">
hey, im hi.
and heres ${foo()}, ${bar()}
-
+
<%def name="foo()">
this is foo
</%def>
-
+
<%def name="bar()">
this is bar
</%def>
@@ -417,9 +417,9 @@ class NestedDefTest(TemplateTest):
</%def>
${a()}
""")
-
+
assert flatten_result(t.render(x=10)) == "x is 10 this is a, x is 10 this is b: 10"
-
+
def test_nested_with_args(self):
t = Template("""
${a()}
@@ -431,7 +431,7 @@ class NestedDefTest(TemplateTest):
</%def>
""")
assert flatten_result(t.render()) == "a b x is 5 y is 2"
-
+
def test_nested_def_2(self):
template = Template("""
${a()}
@@ -449,7 +449,7 @@ class NestedDefTest(TemplateTest):
def test_nested_nested_def(self):
t = Template("""
-
+
${a()}
<%def name="a()">
a
@@ -478,12 +478,12 @@ class NestedDefTest(TemplateTest):
</%def>
${c2()}
</%def>
-
+
${b1()} ${b2()} ${b3()}
</%def>
""")
assert flatten_result(t.render(x=5, y=None)) == "a a_b1 a_b2 a_b2_c1 a_b3 a_b3_c1 heres x: 5 y is 7 a_b3_c2 y is None c1 is a_b3_c1 heres x: 5 y is 7"
-
+
def test_nested_nested_def_2(self):
t = Template("""
<%def name="a()">
@@ -492,7 +492,7 @@ class NestedDefTest(TemplateTest):
this is b
${c()}
</%def>
-
+
<%def name="c()">
this is c
</%def>
@@ -514,16 +514,16 @@ class NestedDefTest(TemplateTest):
%>
c. x is ${x}. ${a()}
</%def>
-
+
b. ${c()}
</%def>
${b()}
-
+
x is ${x}
""")
assert flatten_result(t.render(x=5)) == "b. c. x is 10. a: x is 5 x is 5"
-
+
class ExceptionTest(TemplateTest):
def test_raise(self):
template = Template("""
@@ -540,11 +540,11 @@ class ExceptionTest(TemplateTest):
def handle(context, error):
context.write("error message is " + str(error))
return True
-
+
template = Template("""
<%
raise Exception("this is a test")
%>
""", error_handler=handle)
assert template.render().strip() == """error message is this is a test"""
-
+
diff --git a/test/test_exceptions.py b/test/test_exceptions.py
index 8adad6d..1ddca4f 100644
--- a/test/test_exceptions.py
+++ b/test/test_exceptions.py
@@ -53,11 +53,11 @@ class ExceptionsTest(TemplateTest):
assert ("CompileException: Fragment 'i = 0' is not a partial "
"control statement") in text_error
-
+
def test_utf8_html_error_template(self):
"""test the html_error_template with a Template containing utf8
chars"""
-
+
if util.py3k:
code = """# -*- coding: utf-8 -*-
% if 2 == 2: /an error
@@ -79,7 +79,7 @@ ${u'привет'}
"error' is not a partial control "
"statement at line: 2 char: 1") in \
html_error.decode('utf-8')
-
+
if util.py3k:
assert u"3 ${&#39;привет&#39;}".encode(sys.getdefaultencoding(),
'htmlentityreplace') in html_error
@@ -89,7 +89,7 @@ ${u'привет'}
else:
assert False, ("This function should trigger a CompileException, "
"but didn't")
-
+
def test_format_closures(self):
try:
exec "def foo():"\
@@ -99,7 +99,7 @@ ${u'привет'}
except:
html_error = exceptions.html_error_template().render()
assert "RuntimeError: test" in str(html_error)
-
+
def test_py_utf8_html_error_template(self):
try:
foo = u'日本'
@@ -134,11 +134,11 @@ ${foobar}
assert '<div class="sourceline">${foobar}</div>' in \
result_lines(l.get_template("foo.html").render_unicode())
-
+
def test_utf8_format_exceptions(self):
"""test that htmlentityreplace formatting is applied to
exceptions reported with format_exceptions=True"""
-
+
l = TemplateLookup(format_exceptions=True)
if util.py3k:
l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}""")
@@ -152,21 +152,21 @@ ${foobar}
assert '<div class="highlight">2 ${u&#39;&#x43F;&#x440;'\
'&#x438;&#x432;&#x435;&#x442;&#39; + foobar}</div>' \
in result_lines(l.get_template("foo.html").render().decode('utf-8'))
-
-
+
+
def test_custom_tback(self):
try:
raise RuntimeError("error 1")
foo('bar')
except:
t, v, tback = sys.exc_info()
-
+
try:
raise RuntimeError("error 2")
except:
html_error = exceptions.html_error_template().\
render_unicode(error=v, traceback=tback)
-
+
# obfuscate the text so that this text
# isn't in the 'wrong' exception
assert "".join(reversed(");93#&rab;93#&(oof")) in html_error
@@ -181,9 +181,9 @@ ${foobar}
if not util.py3k:
# blow away tracebaack info
sys.exc_clear()
-
+
# and don't even send what we have.
html_error = exceptions.html_error_template().\
render_unicode(error=v, traceback=None)
-
+
assert "local variable 'y' referenced" in html_error
diff --git a/test/test_filters.py b/test/test_filters.py
index 027d949..2958711 100644
--- a/test/test_filters.py
+++ b/test/test_filters.py
@@ -28,17 +28,17 @@ class FilterTest(TemplateTest):
${x | trim}
""")
assert flatten_result(t.render(x=5)) == "5"
-
+
def test_quoting(self):
t = Template("""
foo ${bar | h}
""")
-
+
eq_(
flatten_result(t.render(bar="<'some bar'>")),
"foo &lt;&#39;some bar&#39;&gt;"
)
-
+
@skip_if(lambda: util.py3k)
def test_quoting_non_unicode(self):
t = Template("""
@@ -49,8 +49,8 @@ class FilterTest(TemplateTest):
flatten_result(t.render(bar="<'привет'>")),
"foo &lt;&#39;привет&#39;&gt;"
)
-
-
+
+
def test_def(self):
t = Template("""
<%def name="foo()" filter="myfilter">
@@ -70,7 +70,7 @@ class FilterTest(TemplateTest):
""")
assert t.render().strip()=="trim this string: some string to trim continue"
-
+
def test_import_2(self):
t = Template("""
trim this string: ${" some string to trim " | filters.trim} continue\
@@ -84,18 +84,18 @@ class FilterTest(TemplateTest):
""", default_filters=['decode.utf8'])
#print t.code
assert t.render_unicode(x="voix m’a réveillé").strip() == u"some stuff.... voix m’a réveillé"
-
+
def test_custom_default(self):
t = Template("""
<%!
def myfilter(x):
return "->" + x + "<-"
%>
-
+
hi ${'there'}
""", default_filters=['myfilter'])
assert t.render().strip()=="hi ->there<-"
-
+
def test_global(self):
t = Template("""
<%page expression_filter="h"/>
@@ -120,7 +120,7 @@ class FilterTest(TemplateTest):
${"<tag>this is html</tag>" | n, h}
""")
assert t.render().strip() == "&lt;tag&gt;this is html&lt;/tag&gt;"
-
+
def testnonexpression(self):
t = Template("""
<%!
@@ -129,7 +129,7 @@ class FilterTest(TemplateTest):
def b(text):
return "this is b"
%>
-
+
${foo()}
<%def name="foo()" buffered="True">
this is text
@@ -144,7 +144,7 @@ class FilterTest(TemplateTest):
def b(text):
return "this is b"
%>
-
+
${'hi'}
${foo()}
<%def name="foo()" buffered="True">
@@ -167,7 +167,7 @@ class FilterTest(TemplateTest):
else:
return "this is b"
%>
-
+
${'hi'}
${foo()}
<%def name="foo()" buffered="True">
@@ -183,7 +183,7 @@ class FilterTest(TemplateTest):
def b(text):
return "this is b"
%>
-
+
${foo()}
${bar()}
<%def name="foo()" filter="b">
@@ -195,19 +195,19 @@ class FilterTest(TemplateTest):
""", buffer_filters=['a'])
assert flatten_result(t.render()) == "this is b this is a"
-
+
def test_builtins(self):
t = Template("""
${"this is <text>" | h}
""")
assert flatten_result(t.render()) == "this is &lt;text&gt;"
-
+
t = Template("""
http://foo.com/arg1=${"hi! this is a string." | u}
""")
assert flatten_result(t.render()) == "http://foo.com/arg1=hi%21+this+is+a+string."
-class BufferTest(unittest.TestCase):
+class BufferTest(unittest.TestCase):
def test_buffered_def(self):
t = Template("""
<%def name="foo()" buffered="True">
@@ -253,7 +253,7 @@ class BufferTest(unittest.TestCase):
assert False
except TypeError:
assert True
-
+
def test_buffered_exception(self):
template = Template("""
<%def name="a()" buffered="True">
@@ -261,16 +261,16 @@ class BufferTest(unittest.TestCase):
raise TypeError("hi")
%>
</%def>
-
+
${a()}
-
+
""")
try:
print template.render()
assert False
except TypeError:
assert True
-
+
def test_capture_ccall(self):
t = Template("""
<%def name="foo()">
@@ -284,7 +284,7 @@ class BufferTest(unittest.TestCase):
ccall body
</%call>
""")
-
+
#print t.render()
assert flatten_result(t.render()) == "this is foo. body: ccall body"
-
+
diff --git a/test/test_inheritance.py b/test/test_inheritance.py
index 9f978d2..a953847 100644
--- a/test/test_inheritance.py
+++ b/test/test_inheritance.py
@@ -52,7 +52,7 @@ main_body ${parent.d()}
full stack from the top:
${self.name} ${parent.name} ${parent.context['parent'].name} ${parent.context['parent'].context['parent'].name}
""")
-
+
collection.put_string('layout', """
<%inherit file="general"/>
<%def name="d()">layout_d</%def>
@@ -94,11 +94,11 @@ ${next.body()}
'full stack from the top:',
'self:main self:layout self:general self:base'
]
-
+
def test_includes(self):
"""test that an included template also has its full hierarchy invoked."""
collection = lookup.TemplateLookup()
-
+
collection.put_string("base", """
<%def name="a()">base_a</%def>
This is the base.
@@ -134,7 +134,7 @@ ${next.body()}
"""test that templates used via <%namespace> have access to an inheriting 'self', and that
the full 'self' is also exported."""
collection = lookup.TemplateLookup()
-
+
collection.put_string("base", """
<%def name="a()">base_a</%def>
<%def name="b()">base_b</%def>
@@ -194,7 +194,7 @@ ${next.body()}
<%def name="foo()">
${next.body(**context.kwargs)}
</%def>
-
+
${foo()}
""")
collection.put_string("index", """
@@ -202,7 +202,7 @@ ${next.body()}
<%page args="x, y, z=7"/>
print ${x}, ${y}, ${z}
""")
-
+
if util.py3k:
assert result_lines(collection.get_template('index').render_unicode(x=5,y=10)) == [
"this is the base.",
@@ -215,14 +215,14 @@ ${next.body()}
"pageargs: (type: <type 'dict'>) [('x', 5), ('y', 10)]",
"print 5, 10, 7"
]
-
+
def test_pageargs_2(self):
collection = lookup.TemplateLookup()
collection.put_string("base", """
this is the base.
-
+
${next.body(**context.kwargs)}
-
+
<%def name="foo(**kwargs)">
${next.body(**kwargs)}
</%def>
@@ -245,7 +245,7 @@ ${next.body()}
"pageargs: 12, 15, 8",
"pageargs: 5, 10, 16"
]
-
+
def test_pageargs_err(self):
collection = lookup.TemplateLookup()
collection.put_string("base", """
@@ -262,7 +262,7 @@ ${next.body()}
assert False
except TypeError:
assert True
-
+
def test_toplevel(self):
collection = lookup.TemplateLookup()
collection.put_string("base", """
@@ -305,7 +305,7 @@ ${next.body()}
'this is the base.',
'this is index.'
]
-
+
def test_in_call(self):
collection = lookup.TemplateLookup()
collection.put_string("/layout.html","""
@@ -332,7 +332,7 @@ ${next.body()}
</%def>
<%inherit file="/layout.html"/>
""")
-
+
collection.put_string("/subdir/renderedtemplate.html","""
Holy smokes!
<%inherit file="/subdir/layout.html"/>
diff --git a/test/test_lexer.py b/test/test_lexer.py
index f35b2ea..006abee 100644
--- a/test/test_lexer.py
+++ b/test/test_lexer.py
@@ -33,15 +33,15 @@ class %s(object):
", ".join(repr_arg(x) for x in self.args)
)
""" % clsname) in locals()
-
+
# NOTE: most assertion expressions were generated, then formatted
# by PyTidy, hence the dense formatting.
class LexerTest(TemplateTest):
-
+
def _compare(self, node, expected):
eq_(repr(node), repr(expected))
-
+
def test_text_and_tag(self):
template = """
<b>Hello world</b>
@@ -85,7 +85,7 @@ class LexerTest(TemplateTest):
"""
self.assertRaises(exceptions.SyntaxException,
Lexer(template).parse)
-
+
def test_noexpr_allowed(self):
template = \
"""
@@ -125,7 +125,7 @@ class LexerTest(TemplateTest):
"""
self.assertRaises(exceptions.CompileException,
Lexer(template).parse)
-
+
def test_percent_escape(self):
template = \
"""
@@ -143,7 +143,7 @@ class LexerTest(TemplateTest):
ControlLine(u'if', u'if foo:', False, (6, 1)),
ControlLine(u'if', u'endif', True, (7, 1)),
Text(u' ', (8, 1))]))
-
+
def test_text_tag(self):
template = \
"""
@@ -201,7 +201,7 @@ class LexerTest(TemplateTest):
"""
self.assertRaises(exceptions.CompileException,
Lexer(template).parse)
-
+
def test_def_syntax_2(self):
template = \
"""
@@ -240,7 +240,7 @@ class LexerTest(TemplateTest):
CallNamespaceTag(u'self:go', {u'x': u'1', u'y'
: u'2', u'z': u"${'hi' + ' ' + 'there'}"}, (3,
13), []), Text(u'\n ', (3, 64))]))
-
+
def test_ns_tag_empty(self):
template = \
"""
@@ -271,7 +271,7 @@ class LexerTest(TemplateTest):
this is the body
''',
(3, 46))]), Text(u'\n ', (5, 24))]))
-
+
def test_expr_in_attribute(self):
"""test some slightly trickier expressions.
@@ -386,7 +386,7 @@ more text
Code(u'\nimport foo\n \n', True, (8, 5)),
Text(u'\n', (10, 7))])
)
-
+
def test_code_and_tags(self):
template = \
"""
@@ -447,7 +447,7 @@ more text
Text(u'\n ', (4, 42))]), Text(u'\n '
, (5, 16)), Expression(u'hi()', [], (6, 9)),
Text(u'\n', (6, 16))]))
-
+
def test_tricky_expression(self):
template = """
@@ -556,7 +556,7 @@ print('''
"""comment\n \n""",
False, (1, 1)),
Text(u" '''and now some text '''", (10,11))]))
-
+
def test_control_lines(self):
template = \
"""
@@ -660,7 +660,7 @@ text text la la
"Keyword 'endlala' doesn't match keyword 'for' at line: 5 char: 1",
Lexer(template).parse
)
-
+
def test_ternary_control(self):
template = \
"""
@@ -685,7 +685,7 @@ text text la la
ControlLine(u'else', u'else:', False, (8, 1)),
Text(u' hi\n', (9, 1)),
ControlLine(u'if', u'endif', True, (10, 1))]))
-
+
def test_integration(self):
template = \
"""<%namespace name="foo" file="somefile.html"/>
@@ -731,7 +731,7 @@ text text la la
(17, 1)), Text(u' </tr>\n', (18, 1)),
ControlLine(u'for', u'endfor', True, (19, 1)),
Text(u'</table>\n', (20, 1))]))
-
+
def test_comment_after_statement(self):
template = \
"""
@@ -776,7 +776,7 @@ text text la la
)
assert flatten_result(Template(template).render()) \
== """<html> like the name says. 1 2 3 Dizzy </html>"""
-
+
def test_comments(self):
template = \
"""
@@ -811,7 +811,7 @@ hi
hi
''', (16, 8))]))
-
+
def test_docs(self):
template = \
"""
diff --git a/test/test_lookup.py b/test/test_lookup.py
index c62efd5..cfbb085 100644
--- a/test/test_lookup.py
+++ b/test/test_lookup.py
@@ -22,7 +22,7 @@ class LookupTest(unittest.TestCase):
assert tl.get_template('/subdir/index.html').module_id \
== '_subdir_index_html'
-
+
def test_updir(self):
t = tl.get_template('/subdir/foo/../bar/../index.html')
assert result_lines(t.render()) == [
@@ -30,15 +30,15 @@ class LookupTest(unittest.TestCase):
"this is include 2"
]
-
+
def test_directory_lookup(self):
"""test that hitting an existent directory still raises
LookupError."""
-
+
self.assertRaises(exceptions.TopLevelLookupException,
tl.get_template, "/subdir"
)
-
+
def test_no_lookup(self):
t = Template("hi <%include file='foo.html'/>")
try:
@@ -48,7 +48,7 @@ class LookupTest(unittest.TestCase):
assert str(e) == \
"Template 'memory:%s' has no TemplateLookup associated" % \
hex(id(t))
-
+
def test_uri_adjust(self):
tl = lookup.TemplateLookup(directories=['/foo/bar'])
assert tl.filename_to_uri('/foo/bar/etc/lala/index.html') == \
@@ -57,9 +57,9 @@ class LookupTest(unittest.TestCase):
tl = lookup.TemplateLookup(directories=['./foo/bar'])
assert tl.filename_to_uri('./foo/bar/etc/index.html') == \
'/etc/index.html'
-
+
def test_uri_cache(self):
"""test that the _uri_cache dictionary is available"""
tl._uri_cache[('foo', 'bar')] = '/some/path'
assert tl._uri_cache[('foo', 'bar')] == '/some/path'
-
+
diff --git a/test/test_lru.py b/test/test_lru.py
index e2b5c15..ade48a3 100644
--- a/test/test_lru.py
+++ b/test/test_lru.py
@@ -13,16 +13,16 @@ class item:
class LRUTest(unittest.TestCase):
- def testlru(self):
+ def testlru(self):
l = LRUCache(10, threshold=.2)
-
+
for id in range(1,20):
l[id] = item(id)
-
+
# first couple of items should be gone
- self.assert_(not l.has_key(1))
+ self.assert_(not l.has_key(1))
self.assert_(not l.has_key(2))
-
+
# next batch over the threshold of 10 should be present
for id in range(11,20):
self.assert_(l.has_key(id))
@@ -37,9 +37,9 @@ class LRUTest(unittest.TestCase):
self.assert_(not l.has_key(11))
self.assert_(not l.has_key(13))
-
+
for id in (25, 24, 23, 14, 12, 19, 18, 17, 16, 15):
- self.assert_(l.has_key(id))
+ self.assert_(l.has_key(id))
def _disabled_test_threaded(self):
size = 100
@@ -47,13 +47,13 @@ class LRUTest(unittest.TestCase):
all_elems = 2000
hot_zone = range(30,40)
cache = LRUCache(size, threshold)
-
+
# element to store
class Element(object):
def __init__(self, id):
self.id = id
self.regets = 0
-
+
# return an element. we will favor ids in the relatively small
# "hot zone" 25% of the time.
def get_elem():
@@ -61,7 +61,7 @@ class LRUTest(unittest.TestCase):
return hot_zone[random.randint(0, len(hot_zone) - 1)]
else:
return random.randint(1, all_elems)
-
+
total = [0]
# request thread.
def request_elem():
@@ -74,19 +74,19 @@ class LRUTest(unittest.TestCase):
except KeyError:
e = Element(id)
cache[id] = e
-
+
time.sleep(random.random() / 1000)
for x in range(0,20):
thread.start_new_thread(request_elem, ())
-
+
# assert size doesn't grow unbounded, doesnt shrink well below size
for x in range(0,5):
time.sleep(1)
print "size:", len(cache)
assert len(cache) < size + size * threshold * 2
assert len(cache) > size - (size * .1)
-
+
# computs the average number of times a range of elements were "reused",
# i.e. without being removed from the cache.
def average_regets_in_range(start, end):
@@ -99,13 +99,13 @@ class LRUTest(unittest.TestCase):
hotzone_avg = average_regets_in_range(30, 40)
control_avg = average_regets_in_range(450,760)
total_avg = average_regets_in_range(0, 2000)
-
+
# hotzone should be way above the others
print "total fetches", total[0], "hotzone", \
hotzone_avg, "control", \
control_avg, "total", total_avg
-
+
assert hotzone_avg > total_avg * 5 > control_avg * 5
-
-
+
+
diff --git a/test/test_namespace.py b/test/test_namespace.py
index 5e0d7a0..3c4c689 100644
--- a/test/test_namespace.py
+++ b/test/test_namespace.py
@@ -15,9 +15,9 @@ class NamespaceTest(TemplateTest):
this is x b, and heres ${a()}
</%def>
</%namespace>
-
+
${x.a()}
-
+
${x.b()}
""",
"this is x a this is x b, and heres this is x a",
@@ -98,13 +98,13 @@ class NamespaceTest(TemplateTest):
flatten_result(collection.get_template('a').render(b_def='b')),
"a. b: b."
)
-
+
def test_template(self):
collection = lookup.TemplateLookup()
collection.put_string('main.html', """
<%namespace name="comp" file="defs.html"/>
-
+
this is main. ${comp.def1("hi")}
${comp.def2("there")}
""")
@@ -113,14 +113,14 @@ class NamespaceTest(TemplateTest):
<%def name="def1(s)">
def1: ${s}
</%def>
-
+
<%def name="def2(x)">
def2: ${x}
</%def>
""")
assert flatten_result(collection.get_template('main.html').render()) == "this is main. def1: hi def2: there"
-
+
def test_module(self):
collection = lookup.TemplateLookup()
@@ -168,7 +168,7 @@ class NamespaceTest(TemplateTest):
""")
assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
-
+
def test_context(self):
"""test that namespace callables get access to the current context"""
collection = lookup.TemplateLookup()
@@ -191,7 +191,7 @@ class NamespaceTest(TemplateTest):
""")
assert flatten_result(collection.get_template('main.html').render(x="context x")) == "this is main. def1: x is context x def2: x is there"
-
+
def test_overload(self):
collection = lookup.TemplateLookup()
@@ -238,13 +238,13 @@ class NamespaceTest(TemplateTest):
collection = lookup.TemplateLookup()
collection.put_string("main.html", """
<%namespace name="foo" file="ns.html"/>
-
+
this is main. ${bar()}
<%def name="bar()">
this is bar, foo is ${foo.bar()}
</%def>
""")
-
+
collection.put_string("ns.html", """
<%def name="bar()">
this is ns.html->bar
@@ -274,24 +274,24 @@ class NamespaceTest(TemplateTest):
this is ns.html->bar
</%def>
""")
-
+
collection.put_string("index.html", """
<%namespace name="main" file="main.html"/>
-
+
this is index
${main.bar()}
""")
- assert result_lines(collection.get_template("index.html").render()) == [
+ assert result_lines(collection.get_template("index.html").render()) == [
"this is index",
"this is bar, foo is" ,
"this is ns.html->bar"
]
-
+
def test_dont_pollute_self(self):
# test that get_namespace() doesn't modify the original context
# incompatibly
-
+
collection = lookup.TemplateLookup()
collection.put_string("base.html", """
@@ -334,13 +334,13 @@ class NamespaceTest(TemplateTest):
"name via bar:",
"self:page.html"
]
-
+
def test_inheritance(self):
"""test namespace initialization in a base inherited template that doesnt otherwise access the namespace"""
collection = lookup.TemplateLookup()
collection.put_string("base.html", """
<%namespace name="foo" file="ns.html" inheritable="True"/>
-
+
${next.body()}
""")
collection.put_string("ns.html", """
@@ -351,11 +351,11 @@ class NamespaceTest(TemplateTest):
collection.put_string("index.html", """
<%inherit file="base.html"/>
-
+
this is index
${self.foo.bar()}
""")
-
+
assert result_lines(collection.get_template("index.html").render()) == [
"this is index",
"this is ns.html->bar"
@@ -367,7 +367,7 @@ class NamespaceTest(TemplateTest):
<%def name="foo()">
base.foo
</%def>
-
+
<%def name="bat()">
base.bat
</%def>
@@ -381,11 +381,11 @@ class NamespaceTest(TemplateTest):
${parent.bat()}
${self.bat()}
</%def>
-
+
<%def name="foo()">
lib.foo
</%def>
-
+
""")
collection.put_string("front.html", """
@@ -424,7 +424,7 @@ class NamespaceTest(TemplateTest):
<%
self.attr.lala = "base lala"
%>
-
+
${self.attr.basefoo}
${self.attr.foofoo}
${self.attr.onlyfoo}
@@ -448,7 +448,7 @@ class NamespaceTest(TemplateTest):
"base lala",
"foo lala",
]
-
+
def test_attr_raise(self):
l = lookup.TemplateLookup()
@@ -459,19 +459,19 @@ class NamespaceTest(TemplateTest):
l.put_string("bar.html", """
<%namespace name="foo" file="foo.html"/>
-
+
${foo.notfoo()}
""")
self.assertRaises(AttributeError, l.get_template("bar.html").render)
-
+
def test_custom_tag_1(self):
template = Template("""
-
+
<%def name="foo(x, y)">
foo: ${x} ${y}
</%def>
-
+
<%self:foo x="5" y="${7+8}"/>
""")
assert result_lines(template.render()) == ['foo: 5 15']
@@ -482,32 +482,32 @@ class NamespaceTest(TemplateTest):
<%def name="foo(x, y)">
foo: ${x} ${y}
</%def>
-
+
<%def name="bat(g)"><%
return "the bat! %s" % g
%></%def>
-
+
<%def name="bar(x)">
${caller.body(z=x)}
</%def>
""")
-
+
collection.put_string("index.html", """
<%namespace name="myns" file="base.html"/>
-
+
<%myns:foo x="${'some x'}" y="some y"/>
-
+
<%myns:bar x="${myns.bat(10)}" args="z">
record: ${z}
</%myns:bar>
-
+
""")
-
+
assert result_lines(collection.get_template("index.html").render()) == [
'foo: some x some y',
'record: the bat! 10'
]
-
+
def test_custom_tag_3(self):
collection = lookup.TemplateLookup()
collection.put_string("base.html", """
@@ -530,14 +530,14 @@ class NamespaceTest(TemplateTest):
call body
</%self.foo:bar>
""")
-
+
assert result_lines(collection.get_template("index.html").render()) == [
"this is index",
"this is ns.html->bar",
"caller body:",
"call body"
]
-
+
def test_custom_tag_case_sensitive(self):
t = Template("""
<%def name="renderPanel()">
@@ -549,21 +549,21 @@ class NamespaceTest(TemplateTest):
hi
</%self:renderPanel>
</%def>
-
+
<%self:renderTablePanel/>
""")
assert result_lines(t.render()) == ['panel', 'hi']
-
-
+
+
def test_expr_grouping(self):
"""test that parenthesis are placed around string-embedded expressions."""
-
+
template = Template("""
<%def name="bar(x, y)">
${x}
${y}
</%def>
-
+
<%self:bar x=" ${foo} " y="x${g and '1' or '2'}y"/>
""", input_encoding='utf-8')
@@ -573,7 +573,7 @@ class NamespaceTest(TemplateTest):
"x2y"
]
-
+
def test_ccall(self):
collection = lookup.TemplateLookup()
collection.put_string("base.html", """
@@ -652,11 +652,11 @@ class NamespaceTest(TemplateTest):
<%def name="foo()">
this is foo
</%def>
-
+
<%def name="bar()">
this is bar
</%def>
-
+
<%def name="lala()">
this is lala
</%def>
@@ -689,7 +689,7 @@ class NamespaceTest(TemplateTest):
"this is b",
"this is x"
]
-
+
def test_import_calledfromdef(self):
l = lookup.TemplateLookup()
l.put_string("a", """
@@ -712,29 +712,29 @@ class NamespaceTest(TemplateTest):
t = l.get_template("b")
assert flatten_result(t.render()) == "im table"
-
+
def test_closure_import(self):
collection = lookup.TemplateLookup()
collection.put_string("functions.html","""
<%def name="foo()">
this is foo
</%def>
-
+
<%def name="bar()">
this is bar
</%def>
""")
-
+
collection.put_string("index.html", """
<%namespace file="functions.html" import="*"/>
<%def name="cl1()">
${foo()}
</%def>
-
+
<%def name="cl2()">
${bar()}
</%def>
-
+
${cl1()}
${cl2()}
""")
@@ -750,26 +750,26 @@ class NamespaceTest(TemplateTest):
this is foo
</%def>
</%namespace>
-
+
${foo()}
-
+
""")
assert flatten_result(t.render()) == "this is foo"
-
+
def test_ccall_import(self):
collection = lookup.TemplateLookup()
collection.put_string("functions.html","""
<%def name="foo()">
this is foo
</%def>
-
+
<%def name="bar()">
this is bar.
${caller.body()}
${caller.lala()}
</%def>
""")
-
+
collection.put_string("index.html", """
<%namespace name="func" file="functions.html" import="*"/>
<%call expr="bar()">
diff --git a/test/test_pygen.py b/test/test_pygen.py
index 181140f..58265ff 100644
--- a/test/test_pygen.py
+++ b/test/test_pygen.py
@@ -179,8 +179,8 @@ print "hi" # a comment
# more comments
print g
-"""
-
+"""
+
def test_open_quotes_with_pound(self):
text = '''
print """ this is text
@@ -216,7 +216,7 @@ print '''
there
'''
# someone else's comment
-"""
+"""
def test_quotes_with_pound(self):
diff --git a/test/test_template.py b/test/test_template.py
index dbfd068..3d489f7 100644
--- a/test/test_template.py
+++ b/test/test_template.py
@@ -22,7 +22,7 @@ class EncodingTest(TemplateTest):
u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""",
output_encoding='utf-8'
)
-
+
def test_unicode_arg(self):
val = u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""
self._do_memory_test(
@@ -81,7 +81,7 @@ class EncodingTest(TemplateTest):
("## -*- coding: utf-8 -*-\n" + val).encode('utf-8'),
u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""
)
-
+
def test_unicode_text(self):
val = u"""<%text>Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »</%text>"""
self._do_memory_test(
@@ -102,7 +102,7 @@ class EncodingTest(TemplateTest):
u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""",
filters=flatten_result
)
-
+
def test_unicode_literal_in_expr(self):
if util.py3k:
self._do_memory_test(
@@ -149,7 +149,7 @@ class EncodingTest(TemplateTest):
u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""",
filters=lambda s:s.strip()
)
-
+
def test_unicode_literal_in_controlline(self):
if util.py3k:
self._do_memory_test(
@@ -177,7 +177,7 @@ class EncodingTest(TemplateTest):
u"""hi, drôle de petite voix m’a réveillé.""",
filters=lambda s:s.strip(),
)
-
+
def test_unicode_literal_in_tag(self):
self._do_file_test(
"unicode_arguments.html",
@@ -200,7 +200,7 @@ class EncodingTest(TemplateTest):
],
filters=result_lines
)
-
+
def test_unicode_literal_in_def(self):
if util.py3k:
self._do_memory_test(
@@ -237,7 +237,7 @@ class EncodingTest(TemplateTest):
u"""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""",
filters=flatten_result
)
-
+
self._do_memory_test(
u"""## -*- coding: utf-8 -*-
<%def name="hello(foo=u'árvíztűrő tükörfúrógép', bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
@@ -248,18 +248,18 @@ class EncodingTest(TemplateTest):
u"""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""",
filters=flatten_result
)
-
+
def test_input_encoding(self):
"""test the 'input_encoding' flag on Template, and that unicode
objects arent double-decoded"""
-
+
if util.py3k:
self._do_memory_test(
u"hello ${f('śląsk')}",
u"hello śląsk",
input_encoding='utf-8',
template_args={'f':lambda x:x}
- )
+ )
self._do_memory_test(
u"## -*- coding: utf-8 -*-\nhello ${f('śląsk')}",
@@ -272,7 +272,7 @@ class EncodingTest(TemplateTest):
u"hello śląsk",
input_encoding='utf-8',
template_args={'f':lambda x:x}
- )
+ )
self._do_memory_test(
u"## -*- coding: utf-8 -*-\nhello ${f(u'śląsk')}",
@@ -297,7 +297,7 @@ class EncodingTest(TemplateTest):
u"hello śląsk",
template_args={'x':u'śląsk'}
)
-
+
def test_encoding(self):
self._do_memory_test(
u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""",
@@ -313,7 +313,7 @@ class EncodingTest(TemplateTest):
output_encoding='iso-8859-1', encoding_errors='replace',
unicode_=False
)
-
+
def test_read_unicode(self):
lookup = TemplateLookup(directories=[template_base],
filesystem_checks=True, output_encoding='utf-8')
@@ -357,7 +357,7 @@ class PageArgsTest(TemplateTest):
def test_basic(self):
template = Template("""
<%page args="x, y, z=7"/>
-
+
this is page, ${x}, ${y}, ${z}
""")
@@ -368,7 +368,7 @@ class PageArgsTest(TemplateTest):
assert False
except TypeError, e:
assert True
-
+
def test_inherits(self):
lookup = TemplateLookup()
lookup.put_string("base.tmpl",
@@ -390,7 +390,7 @@ class PageArgsTest(TemplateTest):
"bar foo var",
filters=flatten_result,
template_args={'variable':'var', 'bar':'bar', 'foo':'foo'}
-
+
)
def test_includes(self):
@@ -421,7 +421,7 @@ class PageArgsTest(TemplateTest):
template_args={'variable':'var', 'bar':'bar', 'foo':'foo'}
)
-
+
def test_with_context(self):
template = Template("""
<%page args="x, y, z=7"/>
@@ -434,12 +434,12 @@ class PageArgsTest(TemplateTest):
def test_overrides_builtins(self):
template = Template("""
<%page args="id"/>
-
+
this is page, id is ${id}
""")
-
+
assert flatten_result(template.render(id="im the id")) == "this is page, id is im the id"
-
+
def test_canuse_builtin_names(self):
template = Template("""
exception: ${Exception}
@@ -465,7 +465,7 @@ class PageArgsTest(TemplateTest):
assert flatten_result(lookup.get_template(template).render()) == "foo"
assert flatten_result(lookup.get_template(template).render(id=5)) == "5"
assert flatten_result(lookup.get_template(template).render(id=id)) == "<built-in function id>"
-
+
def test_dict_locals(self):
template = Template("""
<%
@@ -501,8 +501,8 @@ class IncludeTest(TemplateTest):
this is b. ${a}, ${b}, ${c}
""")
assert flatten_result(lookup.get_template("a").render(a=7,b=8)) == "this is a this is b. 7, 8, 5"
-
- def test_viakwargs(self):
+
+ def test_viakwargs(self):
lookup = TemplateLookup()
lookup.put_string("a", """
this is a
@@ -526,7 +526,7 @@ class IncludeTest(TemplateTest):
this is b. ${a}, ${b}, ${c}
""")
assert flatten_result(lookup.get_template("a").render(a=7,b=8,i='b')) == "this is a this is b. 7, 8, 5"
-
+
def test_within_ccall(self):
lookup = TemplateLookup()
lookup.put_string("a", """this is a""")
@@ -553,7 +553,7 @@ class UndefinedVarsTest(TemplateTest):
x: ${x}
% endif
""")
-
+
assert result_lines(t.render(x=12)) == ["x: 12"]
assert result_lines(t.render(y=12)) == ["undefined"]
@@ -565,14 +565,14 @@ class UndefinedVarsTest(TemplateTest):
x: ${x}
% endif
""", strict_undefined=True)
-
+
assert result_lines(t.render(x=12)) == ['x: 12']
-
+
assert_raises(
NameError,
t.render, y=12
)
-
+
l = TemplateLookup(strict_undefined=True)
l.put_string("a", "some template")
l.put_string("b", """
@@ -585,41 +585,41 @@ class UndefinedVarsTest(TemplateTest):
""")
assert result_lines(t.render(x=12)) == ['x: 12']
-
+
assert_raises(
NameError,
t.render, y=12
)
-
+
def test_expression_declared(self):
t = Template("""
${",".join([t for t in ("a", "b", "c")])}
""", strict_undefined=True)
-
+
eq_(result_lines(t.render()), ['a,b,c'])
t = Template("""
<%self:foo value="${[(val, n) for val, n in [(1, 2)]]}"/>
-
+
<%def name="foo(value)">
${value}
</%def>
-
+
""", strict_undefined=True)
-
+
eq_(result_lines(t.render()), ['[(1, 2)]'])
t = Template("""
<%call expr="foo(value=[(val, n) for val, n in [(1, 2)]])" />
-
+
<%def name="foo(value)">
${value}
</%def>
-
+
""", strict_undefined=True)
-
+
eq_(result_lines(t.render()), ['[(1, 2)]'])
-
+
l = TemplateLookup(strict_undefined=True)
l.put_string("i", "hi, ${pageargs['y']}")
l.put_string("t", """
@@ -628,7 +628,7 @@ class UndefinedVarsTest(TemplateTest):
eq_(
result_lines(l.get_template("t").render()), ['hi, [0, 1, 2]']
)
-
+
l.put_string('q', """
<%namespace name="i" file="${(str([x for x in range(3)][2]) + 'i')[-1]}" />
${i.body(y='x')}
@@ -652,19 +652,19 @@ class UndefinedVarsTest(TemplateTest):
# is treated as an "undefined", so is pulled from the context.
t = Template("""
t is: ${t}
-
+
${",".join([t for t in ("a", "b", "c")])}
""")
-
+
eq_(
result_lines(t.render(t="T")),
['t is: T', 'a,b,c']
)
-
+
def test_traditional_assignment_plus_undeclared(self):
t = Template("""
t is: ${t}
-
+
<%
t = 12
%>
@@ -673,22 +673,22 @@ class UndefinedVarsTest(TemplateTest):
UnboundLocalError,
t.render, t="T"
)
-
+
def test_list_comprehensions_plus_undeclared_strict(self):
# with strict, a list comprehension now behaves
# like the undeclared case above.
t = Template("""
t is: ${t}
-
+
${",".join([t for t in ("a", "b", "c")])}
""", strict_undefined=True)
-
+
eq_(
result_lines(t.render(t="T")),
['t is: T', 'a,b,c']
)
-
-
+
+
class ControlTest(TemplateTest):
def test_control(self):
t = Template("""
@@ -706,7 +706,7 @@ class ControlTest(TemplateTest):
"no x does not have test",
"yes x has test"
]
-
+
def test_blank_control(self):
self._do_memory_test(
"""
@@ -716,7 +716,7 @@ class ControlTest(TemplateTest):
"",
filters=lambda s:s.strip()
)
-
+
def test_multiline_control(self):
t = Template("""
% for x in \\
@@ -726,7 +726,7 @@ class ControlTest(TemplateTest):
""")
#print t.code
assert flatten_result(t.render()) == "1 2 3"
-
+
class GlobalsTest(TemplateTest):
def test_globals(self):
self._do_memory_test(
@@ -741,7 +741,7 @@ class GlobalsTest(TemplateTest):
)
class RichTracebackTest(TemplateTest):
-
+
def _do_test_traceback(self, utf8, memory, syntax):
if memory:
if syntax:
@@ -825,7 +825,7 @@ class ModuleDirTest(TemplateTest):
class FilenameToURITest(TemplateTest):
def test_windows_paths(self):
"""test that windows filenames are handled appropriately by Template."""
-
+
current_path = os.path
import ntpath
os.path = ntpath
@@ -834,11 +834,11 @@ class FilenameToURITest(TemplateTest):
def _compile_from_file(self, path, filename):
self.path = path
return Template("foo bar").module
-
+
t1 = NoCompileTemplate(
filename="c:\\foo\\template.html",
module_directory="c:\\modules\\")
-
+
eq_(t1.uri, "/foo/template.html")
eq_(t1.path, "c:\\modules\\foo\\template.html.py")
@@ -846,7 +846,7 @@ class FilenameToURITest(TemplateTest):
filename="c:\\path\\to\\templates\\template.html",
uri = "/bar/template.html",
module_directory="c:\\modules\\")
-
+
eq_(t1.uri, "/bar/template.html")
eq_(t1.path, "c:\\modules\\bar\\template.html.py")
@@ -882,16 +882,16 @@ class FilenameToURITest(TemplateTest):
finally:
os.path = current_path
-
-
-
+
+
+
class ModuleTemplateTest(TemplateTest):
def test_module_roundtrip(self):
lookup = TemplateLookup()
template = Template("""
<%inherit file="base.html"/>
-
+
% for x in range(5):
${x}
% endfor
@@ -904,30 +904,30 @@ class ModuleTemplateTest(TemplateTest):
lookup.put_template("base.html", base)
lookup.put_template("template.html", template)
-
+
assert result_lines(template.render()) == [
"This is base.", "0", "1", "2", "3", "4"
]
-
+
lookup = TemplateLookup()
template = ModuleTemplate(template.module, lookup=lookup)
base = ModuleTemplate(base.module, lookup=lookup)
lookup.put_template("base.html", base)
lookup.put_template("template.html", template)
-
+
assert result_lines(template.render()) == [
"This is base.", "0", "1", "2", "3", "4"
]
-
-
+
+
class PreprocessTest(TemplateTest):
def test_old_comments(self):
t = Template("""
im a template
# old style comment
# more old style comment
-
+
## new style comment
- # not a comment
- ## not a comment
diff --git a/test/test_tgplugin.py b/test/test_tgplugin.py
index f611a37..3aa6122 100644
--- a/test/test_tgplugin.py
+++ b/test/test_tgplugin.py
@@ -36,7 +36,7 @@ class TestTGPlugin(TemplateTest):
]
assert tl.load_template('subdir.index').module_id == '_subdir_index_html'
-
+
def test_string(self):
t = tl.load_template('foo', "hello world")
assert t.render() == "hello world"