summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES310
-rw-r--r--mako/ast.py42
-rw-r--r--mako/cache.py24
-rw-r--r--mako/codegen.py388
-rw-r--r--mako/exceptions.py42
-rw-r--r--mako/filters.py18
-rw-r--r--mako/lexer.py148
-rw-r--r--mako/lookup.py110
-rw-r--r--mako/parsetree.py244
-rw-r--r--mako/pygen.py114
-rw-r--r--mako/pyparser.py12
-rw-r--r--mako/runtime.py164
-rw-r--r--mako/template.py208
-rw-r--r--mako/util.py44
14 files changed, 934 insertions, 934 deletions
diff --git a/CHANGES b/CHANGES
index 535658b..a6d0509 100644
--- a/CHANGES
+++ b/CHANGES
@@ -14,7 +14,7 @@
Thanks to Ben Trofatter for all
the work on this [ticket:125]
-- [feature] Added a real check for "reserved"
+- [feature] Added a real check for "reserved"
names, that is names which are never pulled
from the context and cannot be passed to
the template.render() method. Current names
@@ -22,15 +22,15 @@
- [feature] The html_error_template() will now
apply Pygments highlighting to the source
- code displayed in the traceback, if Pygments
- if available. Courtesy Ben Trofatter
+ code displayed in the traceback, if Pygments
+ if available. Courtesy Ben Trofatter
[ticket:95]
- [feature] Added support for context managers,
i.e. "% with x as e:/ % endwith" support.
Courtesy Ben Trofatter [ticket:147]
-- [feature] Added class-level flag to CacheImpl
+- [feature] Added class-level flag to CacheImpl
"pass_context"; when True, the keyword argument
'context' will be passed to get_or_create()
containing the Mako Context object.
@@ -40,7 +40,7 @@
to filehandles being implicitly closed.
[ticket:182]
-- [bug] Fixed endless recursion bug when
+- [bug] Fixed endless recursion bug when
nesting multiple def-calls with content.
Thanks to Jeff Dairiki. [ticket:186]
@@ -56,7 +56,7 @@
0.6.1
- [bug] Added special compatibility for the 0.5.0
Cache() constructor, which was preventing file
- version checks and not allowing Mako 0.6 to
+ version checks and not allowing Mako 0.6 to
recompile the module files.
0.6.0
@@ -66,7 +66,7 @@
default plugin. Template and TemplateLookup
now accept a string "cache_impl" parameter which
refers to the name of a cache plugin, defaulting
- to the name 'beaker'. New plugins can be
+ to the name 'beaker'. New plugins can be
registered as pkg_resources entrypoints under
the group "mako.cache", or registered directly
using mako.cache.register_plugin(). The
@@ -75,7 +75,7 @@
- [feature] Added support for Beaker cache regions
in templates. Usage of regions should be considered
- as superseding the very obsolete idea of passing in
+ as superseding the very obsolete idea of passing in
backend options, timeouts, etc. within templates.
- [feature] The 'put' method on Cache is now
@@ -86,10 +86,10 @@
minus the "cache_" prefix will be passed as keyword
arguments to the CacheImpl methods.
-- [feature] Template and TemplateLookup now accept an argument
+- [feature] Template and TemplateLookup now accept an argument
cache_args, which refers to a dictionary containing
- cache parameters. The cache_dir, cache_url, cache_type,
- cache_timeout arguments are deprecated (will probably
+ cache parameters. The cache_dir, cache_url, cache_type,
+ cache_timeout arguments are deprecated (will probably
never be removed, however) and can be passed
now as cache_args={'url':<some url>, 'type':'memcached',
'timeout':50, 'dir':'/path/to/some/directory'}
@@ -102,11 +102,11 @@
then template.render(myfilter=some_callable)
[ticket:180]
-- [feature] Added "--var name=value" option to the mako-render
- script, allows passing of kw to the template from
+- [feature] Added "--var name=value" option to the mako-render
+ script, allows passing of kw to the template from
the command line. [ticket:178]
-- [feature] Added module_writer argument to Template,
+- [feature] Added module_writer argument to Template,
TemplateLookup, allows a callable to be passed which
takes over the writing of the template's module source
file, so that special environment-specific steps
@@ -120,33 +120,33 @@
[ticket:173]
- [bug] The "benchmark" example is now Python 3 compatible
- (even though several of those old template libs aren't
+ (even though several of those old template libs aren't
available on Py3K, so YMMV) [ticket:175]
0.5
- A Template is explicitly disallowed
from having a url that normalizes to relative outside
- of the root. That is, if the Lookup is based
+ of the root. That is, if the Lookup is based
at /home/mytemplates, an include that would place
- the ultimate template at
+ the ultimate template at
/home/mytemplates/../some_other_directory,
i.e. outside of /home/mytemplates,
is disallowed. This usage was never intended
despite the lack of an explicit check.
The main issue this causes
- is that module files can be written outside
+ is that module files can be written outside
of the module root (or raise an error, if file perms aren't
- set up), and can also lead to the same template being
- cached in the lookup under multiple, relative roots.
- TemplateLookup instead has always supported multiple
+ set up), and can also lead to the same template being
+ cached in the lookup under multiple, relative roots.
+ TemplateLookup instead has always supported multiple
file roots for this purpose.
[ticket:174]
0.4.2
- Fixed bug regarding <%call>/def calls w/ content
whereby the identity of the "caller" callable
- inside the <%def> would be corrupted by the
- presence of another <%call> in the same block.
+ inside the <%def> would be corrupted by the
+ presence of another <%call> in the same block.
[ticket:170]
- Fixed the babel plugin to accommodate <%block>
@@ -154,18 +154,18 @@
0.4.1
- New tag: <%block>. A variant on <%def> that
- evaluates its contents in-place.
+ evaluates its contents in-place.
Can be named or anonymous,
the named version is intended for inheritance
- layouts where any given section can be
+ layouts where any given section can be
surrounded by the <%block> tag in order for
it to become overrideable by inheriting
templates, without the need to specify a
top-level <%def> plus explicit call.
- Modified scoping and argument rules as well as a
- more strictly enforced usage scheme make it ideal
- for this purpose without at all replacing most
- other things that defs are still good for.
+ Modified scoping and argument rules as well as a
+ more strictly enforced usage scheme make it ideal
+ for this purpose without at all replacing most
+ other things that defs are still good for.
Lots of new docs. [ticket:164]
- a slight adjustment to the "highlight" logic
@@ -174,12 +174,12 @@
without any extra guessing. [ticket:165]
0.4.0
-- A 20% speedup for a basic two-page
+- A 20% speedup for a basic two-page
inheritance setup rendering
a table of escaped data
(see http://techspot.zzzeek.org/2010/11/19/quick-mako-vs.-jinja-speed-test/).
A few configurational changes which
- affect those in the I-don't-do-unicode
+ affect those in the I-don't-do-unicode
camp should be noted below.
- The FastEncodingBuffer is now used
@@ -187,30 +187,30 @@
regardless of whether output_encoding
is set to None or not. FEB is faster than
both. Only StringIO allows bytestrings
- of unknown encoding to pass right
- through, however - while it is of course
- not recommended to send bytestrings of unknown
+ of unknown encoding to pass right
+ through, however - while it is of course
+ not recommended to send bytestrings of unknown
encoding to the output stream, this
mode of usage can be re-enabled by
setting the flag bytestring_passthrough
to True.
-- disable_unicode mode requires that
+- disable_unicode mode requires that
output_encoding be set to None - it also
forces the bytestring_passthrough flag
to True.
- the <%namespace> tag raises an error
if the 'template' and 'module' attributes
- are specified at the same time in
- one tag. A different class is used
- for each case which allows a reduction in
+ are specified at the same time in
+ one tag. A different class is used
+ for each case which allows a reduction in
runtime conditional logic and function
call overhead. [ticket:156]
-- the keys() in the Context, as well as
+- the keys() in the Context, as well as
it's internal _data dictionary, now
- include just what was specified to
+ include just what was specified to
render() as well as Mako builtins
'caller', 'capture'. The contents
of __builtin__ are no longer copied.
@@ -225,45 +225,45 @@
setup.py instead of "install_requires".
This to produce a lighter weight install
for those who don't use the caching
- as well as to conform to Pyramid
+ as well as to conform to Pyramid
deployment practices. [ticket:154]
- The Beaker import (or attempt thereof)
- is delayed until actually needed;
- this to remove the performance penalty
- from startup, particularly for
+ is delayed until actually needed;
+ this to remove the performance penalty
+ from startup, particularly for
"single execution" environments
such as shell scripts. [ticket:153]
- Patch to lexer to not generate an empty
'' write in the case of backslash-ended
lines. [ticket:155]
-
-- Fixed missing **extra collection in
+
+- Fixed missing **extra collection in
setup.py which prevented setup.py
from running 2to3 on install.
[ticket:148]
-
-- New flag on Template, TemplateLookup -
+
+- New flag on Template, TemplateLookup -
strict_undefined=True, will cause
- variables not found in the context to
+ variables not found in the context to
raise a NameError immediately, instead of
defaulting to the UNDEFINED value.
- The range of Python identifiers that
are considered "undefined", meaning they
- are pulled from the context, has been
- trimmed back to not include variables
+ are pulled from the context, has been
+ trimmed back to not include variables
declared inside of expressions (i.e. from
- list comprehensions), as well as
+ list comprehensions), as well as
in the argument list of lambdas. This
to better support the strict_undefined
- feature. The change should be
+ feature. The change should be
fully backwards-compatible but involved
a little bit of tinkering in the AST code,
- which hadn't really been touched for
+ 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 ${}.
@@ -271,22 +271,22 @@
must be referenced explicitly.
[ticket:141]
-- ${} expressions embedded in tags,
- such as <%foo:bar x="${...}">, now
+- ${} 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
+
+- Fixed previously non-covered regular
+ expression, such that using a ${} expression
+ inside of a tag element that doesn't allow
them raises a CompileException instead of
silently failing.
- Added a try/except around "import markupsafe".
This to support GAE which can't run markupsafe.
- [ticket:151] No idea whatsoever if the
- install_requires in setup.py also breaks GAE,
+ [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
@@ -294,19 +294,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
+
+ Note that Pylons by default doesn't
+ use Mako's filter - check your
environment.py file.
-
-- Fixed call to "unicode.strip" in
+
+- 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
@@ -314,13 +314,13 @@
the formatter just returns blank
for the "traceback" portion.
[ticket:135]
-
-- Fixed sometimes incorrect usage of
+
+- Fixed sometimes incorrect usage of
exc.__class__.__name__
- in html/text error templates when using
+ in html/text error templates when using
Python 2.4 [ticket:131]
-- Fixed broken @property decorator on
+- Fixed broken @property decorator on
template.last_modified
- Fixed error formatting when a stacktrace
@@ -332,18 +332,18 @@
where the source is stored temporarily is
now made in the same directory as that of
the .py file. This ensures that the two
- files share the same filesystem, thus
+ 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
+- 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]
@@ -354,24 +354,24 @@
- 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.
- In particular, module source files are now
- generated with the Python "magic encoding
- comment", and source code is passed through
+ In particular, module source files are now
+ generated with the Python "magic encoding
+ comment", and source code is passed through
mostly unescaped, except for that code which
is regenerated from parsed Python source.
- This fixes usage of unicode in
+ This fixes usage of unicode in
<%namespace:defname> tags. [ticket:99]
- RichTraceback(), html_error_template().render(),
text_error_template().render() now accept "error"
- and "traceback" as optional arguments, and
+ and "traceback" as optional arguments, and
these are now actually used. [ticket:122]
-
-- The exception output generated when
+
+- The exception output generated when
format_exceptions=True will now be as a Python
unicode if it occurred during render_unicode(),
or an encoded string if during render().
@@ -379,11 +379,11 @@
- A percent sign can be emitted as the first
non-whitespace character on a line by escaping
it as in "%%". [ticket:112]
-
+
- Template accepts empty control structure, i.e.
% if: %endif, etc. [ticket:94]
-- The <%page args> tag can now be used in a base
+- The <%page args> tag can now be used in a base
inheriting template - the full set of render()
arguments are passed down through the inherits
chain. Undeclared arguments go into **pageargs
@@ -396,16 +396,16 @@
breakage. [ticket:109]
- Windows paths are handled correctly if a Template
- is passed only an absolute filename (i.e. with c:
+ is passed only an absolute filename (i.e. with c:
drive etc.) and no URI - the URI is converted
to a forward-slash path and module_directory
is treated as a windows path. [ticket:128]
- TemplateLookup raises TopLevelLookupException for
a given path that is a directory, not a filename,
- instead of passing through to the template to
+ instead of passing through to the template to
generate IOError. [ticket:73]
-
+
0.2.6
- Fix mako function decorators to preserve the
@@ -429,15 +429,15 @@
- When Mako creates subdirectories in which
to store templates, it uses the more
permissive mode of 0775 instead of 0750,
- helping out with certain multi-process
+ helping out with certain multi-process
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
+
+- 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]
@@ -446,28 +446,28 @@
around '=' sign in defs. [ticket:102]
- Removed errant "lower()" in the lexer which
- was causing tags to compile with
+ was causing tags to compile with
case-insensitive names, thus messing up
custom <%call> names. [ticket:108]
- added "mako.__version__" attribute to
the base module. [ticket:110]
-
+
0.2.4
- Fixed compatibility with Jython 2.5b1.
0.2.3
- the <%namespacename:defname> syntax described at
- http://techspot.zzzeek.org/?p=28 has now
+ http://techspot.zzzeek.org/?p=28 has now
been added as a built in syntax, and is recommended
as a more modern syntax versus <%call expr="expression">.
- The %call tag itself will always remain,
+ The %call tag itself will always remain,
with <%namespacename:defname> presenting a more HTML-like
- alternative to calling defs, both plain and
+ alternative to calling defs, both plain and
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
@@ -479,42 +479,42 @@
e.g. ${local.cache.get('somekey')} or
template.cache.invalidate_body()
-- added "cache_enabled=True" flag to Template,
+- added "cache_enabled=True" flag to Template,
TemplateLookup. Setting this to False causes cache
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
+ invalidate_body(), invalidate_closure(name),
+ invalidate(key), which will remove the given key
from the cache, if it exists. The cache arguments
(i.e. storage type) are derived from whatever has
been already persisted for that template.
[ticket:92]
- For cache changes to work fully, Beaker 1.1 is required.
- 1.0.1 and up will work as well with the exception of
+ 1.0.1 and up will work as well with the exception of
cache expiry. Note that Beaker 1.1 is **required**
for applications which use dynamically generated keys,
- since previous versions will permanently store state in memory
- for each individual key, thus consuming all available
- memory for an arbitrarily large number of distinct
+ since previous versions will permanently store state in memory
+ for each individual key, thus consuming all available
+ memory for an arbitrarily large number of distinct
keys.
-- fixed bug whereby an <%included> template with
+- 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]
- RichTraceback() now accepts an optional traceback object
- to be used in place of sys.exc_info()[2]. html_error_template()
+ to be used in place of sys.exc_info()[2]. html_error_template()
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
@@ -532,16 +532,16 @@
- cached blocks now use the current context when rendering
an expired section, instead of the original context
passed in [ticket:87]
-- fixed a critical issue regarding caching, whereby
+- fixed a critical issue regarding caching, whereby
a cached block would raise an error when called within a
-cache-refresh operation that was initiated after the
+cache-refresh operation that was initiated after the
initiating template had completed rendering.
0.2.1
-- fixed bug where 'output_encoding' parameter would prevent
+- fixed bug where 'output_encoding' parameter would prevent
render_unicode() from returning a unicode object.
-- bumped magic number, which forces template recompile for
-this version (fixes incompatible compile symbols from 0.1
+- bumped magic number, which forces template recompile for
+this version (fixes incompatible compile symbols from 0.1
series).
- added a few docs for cache options, specifically those that
help with memcached.
@@ -566,18 +566,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:
-
+
+- 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}
@@ -585,7 +585,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}"/>
@@ -595,18 +595,18 @@ help with memcached.
_push_buffer(), _pop_buffer(),
caller_stack._push_frame(), caller_stack._pop_frame().
- - added a runner script "mako-render" which renders
- standard input as a template to stdout [ticket:81]
+ - 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',
+ names without explicit declaration (i.e. 'id',
'exception', 'range', etc.) [ticket:83] [ticket:84]
-
- - can also use builtin names as local variable names
+
+ - 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]
@@ -621,10 +621,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]
@@ -635,17 +635,17 @@ help with memcached.
to the %call function itself (propigates to the inner
calls too, this is a slight side effect which previously
existed anyway)
-- fixed bug where local.get_namespace() could put an
+- fixed bug where local.get_namespace() could put an
incorrect "self" in the current context
- 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]
- comments can be placed at the end of control lines,
-i.e. if foo: # a comment, [ticket:53], thanks to
+i.e. if foo: # a comment, [ticket:53], thanks to
Paul Colomiets
- fixed expressions and page tag arguments and with embedded
newlines in CRLF templates, follow up to [ticket:16], thanks
@@ -654,7 +654,7 @@ Eric Woroshow
exception reporter [ticket:51]
0.1.8
-- variable names declared in render methods by internal
+- variable names declared in render methods by internal
codegen prefixed by "__M_" to prevent name collisions
with user code
- added a Babel (http://babel.edgewall.org/) extractor entry
@@ -668,14 +668,14 @@ templates with tgplugin even if non-compatible args were sent
0.1.7
- one small fix to the unit tests to support python 2.3
-- a slight hack to how cache.py detects Beaker's memcached,
-works around unexplained import behavior observed on some
+- a slight hack to how cache.py detects Beaker's memcached,
+works around unexplained import behavior observed on some
python 2.3 installations
-0.1.6
-- caching is now supplied directly by Beaker, which has
+0.1.6
+- caching is now supplied directly by Beaker, which has
all of MyghtyUtils merged into it now. The latest Beaker
- (0.7.1) also fixes a bug related to how Mako was using the
+ (0.7.1) also fixes a bug related to how Mako was using the
cache API.
- fix to module_directory path generation when the path is "./"
[ticket:34]
@@ -700,14 +700,14 @@ 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
+- AST expression generation - added in just about everything
expression-wise from the AST module [ticket:26]
- AST parsing, properly detects imports of the form "import foo.bar"
[ticket:27]
- fix to lexing of <%docs> tag nested in other tags
-- fix to context-arguments inside of <%include> tag which broke
+- fix to context-arguments inside of <%include> tag which broke
during 0.1.4 [ticket:29]
- added "n" filter, disables *all* filters normally applied to an expression
via <%page> or default_filters (but not those within the filter)
@@ -716,7 +716,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
@@ -742,10 +742,10 @@ via passing special attributes or objects.
0.1.3
- ***Small Syntax Change*** - the single line comment character is now
*two* hash signs, i.e. "## this is a comment". This avoids a common
-collection with CSS selectors.
+collection with CSS selectors.
- the magic "coding" comment (i.e. # coding:utf-8) will still work with
either one "#" sign or two for now; two is preferred going forward, i.e.
-## coding:<someencoding>.
+## coding:<someencoding>.
- new multiline comment form: "<%doc> a comment </%doc>"
- UNDEFINED evaluates to False
- improvement to scoping of "caller" variable when using <%call> tag
@@ -756,7 +756,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/mako/ast.py b/mako/ast.py
index d6fa215..76311e9 100644
--- a/mako/ast.py
+++ b/mako/ast.py
@@ -4,7 +4,7 @@
# This module is part of Mako and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""utilities for analyzing expressions and blocks of Python
+"""utilities for analyzing expressions and blocks of Python
code, as well as generating Python from AST nodes"""
from mako import exceptions, pyparser, util
@@ -14,23 +14,23 @@ 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,
+ # using AST to parse instead of using code.co_varnames,
# code.co_names has several advantages:
- # - we can locate an identifier as "undeclared" even if
+ # - we can locate an identifier as "undeclared" even if
# its declared later in the same block of code
- # - AST is less likely to break with version changes
+ # - AST is less likely to break with version changes
# (for example, the behavior of co_names changed a little bit
# in python version 2.5)
if isinstance(code, basestring):
@@ -59,12 +59,12 @@ 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.
+
+ e.g.
for x in 5:
elif y==9:
except (MyException, e):
@@ -74,7 +74,7 @@ class PythonFragment(PythonCode):
m = re.match(r'^(\w+)(?:\s+(.*?))?:\s*(#|$)', code.strip(), re.S)
if not m:
raise exceptions.CompileException(
- "Fragment '%s' is not a partial control statement" %
+ "Fragment '%s' is not a partial control statement" %
code, **exception_kwargs)
if m.group(3):
code = code[:m.start(3)]
@@ -91,17 +91,17 @@ class PythonFragment(PythonCode):
code = code + "pass"
else:
raise exceptions.CompileException(
- "Unsupported control keyword: '%s'" %
+ "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'):
@@ -110,13 +110,13 @@ class FunctionDecl(object):
**exception_kwargs)
if not allow_kwargs and self.kwargs:
raise exceptions.CompileException(
- "'**%s' keyword argument not allowed here" %
+ "'**%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
@@ -134,8 +134,8 @@ class FunctionDecl(object):
else:
default = len(defaults) and defaults.pop() or None
if include_defaults and default:
- namedecls.insert(0, "%s=%s" %
- (arg,
+ namedecls.insert(0, "%s=%s" %
+ (arg,
pyparser.ExpressionGenerator(default).value()
)
)
@@ -145,7 +145,7 @@ 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 09b04fb..f50ce58 100644
--- a/mako/cache.py
+++ b/mako/cache.py
@@ -82,14 +82,14 @@ class Cache(object):
return self._ctx_get_or_create(key, creation_function, None, **kw)
def _ctx_get_or_create(self, key, creation_function, context, **kw):
- """Retrieve a value from the cache, using the given creation function
+ """Retrieve a value from the cache, using the given creation function
to generate a new value."""
if not self.template.cache_enabled:
return creation_function()
- return self.impl.get_or_create(key,
- creation_function,
+ return self.impl.get_or_create(key,
+ creation_function,
**self._get_cache_kw(kw, context))
def set(self, key, value, **kw):
@@ -121,7 +121,7 @@ class Cache(object):
"""
return self.impl.get(key, **self._get_cache_kw(kw, None))
-
+
def invalidate(self, key, **kw):
"""Invalidate a value in the cache.
@@ -133,22 +133,22 @@ class Cache(object):
"""
self.impl.invalidate(key, **self._get_cache_kw(kw, None))
-
+
def invalidate_body(self):
"""Invalidate the cached content of the "body" method for this
template.
"""
self.invalidate('render_body', __M_defname='render_body')
-
+
def invalidate_def(self, name):
"""Invalidate the cached content of a particular ``<%def>`` within this
template.
"""
-
+
self.invalidate('render_%s' % name, __M_defname='render_%s' % name)
-
+
def invalidate_closure(self, name):
"""Invalidate a nested ``<%def>`` within this template.
@@ -159,9 +159,9 @@ class Cache(object):
each other.
"""
-
+
self.invalidate(name, __M_defname=name)
-
+
def _get_cache_kw(self, kw, context):
defname = kw.pop('__M_defname', None)
if not defname:
@@ -216,7 +216,7 @@ class CacheImpl(object):
"""
raise NotImplementedError()
-
+
def get(self, key, **kw):
"""Retrieve a value from the cache.
@@ -225,7 +225,7 @@ class CacheImpl(object):
"""
raise NotImplementedError()
-
+
def invalidate(self, key, **kw):
"""Invalidate a value in the cache.
diff --git a/mako/codegen.py b/mako/codegen.py
index 6ab6095..3cec0ee 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -14,61 +14,61 @@ from mako import util, ast, parsetree, filters, exceptions
MAGIC_NUMBER = 8
-# names which are hardwired into the
-# template and are not accessed via the
+# names which are hardwired into the
+# template and are not accessed via the
# context itself
RESERVED_NAMES = set(['context', 'loop', 'UNDEFINED'])
-def compile(node,
- uri,
- filename=None,
- default_filters=None,
- buffer_filters=None,
- imports=None,
- source_encoding=None,
+def compile(node,
+ uri,
+ filename=None,
+ default_filters=None,
+ buffer_filters=None,
+ imports=None,
+ source_encoding=None,
generate_magic_comment=True,
disable_unicode=False,
strict_undefined=False,
enable_loop=True,
reserved_names=()):
-
- """Generate module source code given a parsetree node,
+
+ """Generate module source code given a parsetree node,
uri, and optional source filename"""
# if on Py2K, push the "source_encoding" string to be
- # a bytestring itself, as we will be embedding it into
- # the generated source and we don't want to coerce the
+ # a bytestring itself, as we will be embedding it into
+ # the generated source and we don't want to coerce the
# 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)
- _GenerateRenderMethod(printer,
- _CompileContext(uri,
- filename,
- default_filters,
+ _GenerateRenderMethod(printer,
+ _CompileContext(uri,
+ filename,
+ default_filters,
buffer_filters,
- imports,
+ imports,
source_encoding,
generate_magic_comment,
disable_unicode,
strict_undefined,
enable_loop,
- reserved_names),
+ reserved_names),
node)
return buf.getvalue()
class _CompileContext(object):
- def __init__(self,
- uri,
- filename,
- default_filters,
- buffer_filters,
- imports,
- source_encoding,
+ def __init__(self,
+ uri,
+ filename,
+ default_filters,
+ buffer_filters,
+ imports,
+ source_encoding,
generate_magic_comment,
disable_unicode,
strict_undefined,
@@ -85,11 +85,11 @@ class _CompileContext(object):
self.strict_undefined = strict_undefined
self.enable_loop = enable_loop
self.reserved_names = reserved_names
-
+
class _GenerateRenderMethod(object):
- """A template visitor object which generates the
+ """A template visitor object which generates the
full module source for a template.
-
+
"""
def __init__(self, printer, compiler, node):
self.printer = printer
@@ -97,13 +97,13 @@ class _GenerateRenderMethod(object):
self.compiler = compiler
self.node = node
self.identifier_stack = [None]
-
+
self.in_def = isinstance(node, (parsetree.DefTag, parsetree.BlockTag))
if self.in_def:
name = "render_%s" % node.funcname
args = node.get_argument_expressions()
- filtered = len(node.filter_args.args) > 0
+ filtered = len(node.filter_args.args) > 0
buffered = eval(node.attributes.get('buffered', 'False'))
cached = eval(node.attributes.get('cached', 'False'))
defs = None
@@ -131,24 +131,24 @@ class _GenerateRenderMethod(object):
args = ['context']
else:
args = [a for a in ['context'] + args]
-
+
self.write_render_callable(
- pagetag or node,
- name, args,
+ 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 = {}
@@ -156,7 +156,7 @@ class _GenerateRenderMethod(object):
encoding =[None]
self.compiler.pagetag = None
-
+
class FindTopLevel(object):
def visitInheritTag(s, node):
inherit.append(node)
@@ -167,7 +167,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)
@@ -180,13 +180,13 @@ class _GenerateRenderMethod(object):
module_identifiers = _Identifiers(self.compiler)
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")
@@ -205,13 +205,13 @@ class _GenerateRenderMethod(object):
buf += imp + "\n"
self.printer.writeline(imp)
impcode = ast.PythonCode(
- buf,
- source='', lineno=0,
- pos=0,
+ buf,
+ source='', lineno=0,
+ pos=0,
filename='template defined imports')
else:
impcode = None
-
+
main_identifiers = module_identifiers.branch(self.node)
module_identifiers.topleveldefs = \
module_identifiers.topleveldefs.\
@@ -219,9 +219,9 @@ 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" %
+ self.printer.writeline("_exports = %r" %
[n.name for n in
main_identifiers.topleveldefs.values()]
)
@@ -241,15 +241,15 @@ 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)),
# push new frame, assign current frame to __M_caller
@@ -258,7 +258,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 or self.node.is_block) and '**pageargs' in args:
@@ -268,7 +268,7 @@ class _GenerateRenderMethod(object):
len(self.identifiers.locally_assigned) > 0 or
len(self.identifiers.argument_declared) > 0
):
- self.printer.writeline("__M_locals = __M_dict_builtin(%s)" %
+ self.printer.writeline("__M_locals = __M_dict_builtin(%s)" %
','.join([
"%s=%s" % (x, x) for x in
self.identifiers.argument_declared
@@ -284,12 +284,12 @@ class _GenerateRenderMethod(object):
self.printer.write("\n\n")
if cached:
self.write_cache_decorator(
- node, name,
- args, buffered,
+ node, name,
+ args, buffered,
self.identifiers, toplevel=True)
-
+
def write_module_code(self, module_code):
- """write module-level template code, i.e. that which
+ """write module-level template code, i.e. that which
is enclosed in <%! %> tags in the template."""
for n in module_code:
self.write_source_comment(n)
@@ -297,7 +297,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)",
@@ -319,7 +319,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
@@ -363,8 +363,8 @@ class _GenerateRenderMethod(object):
" calling_uri=_template_uri)" %
(
node.name,
- node.parsed_attributes.get('file', 'None'),
- callable_name,
+ node.parsed_attributes.get('file', 'None'),
+ callable_name,
)
)
elif 'module' in node.parsed_attributes:
@@ -375,7 +375,7 @@ class _GenerateRenderMethod(object):
" module=%s)" %
(
node.name,
- callable_name,
+ callable_name,
node.parsed_attributes.get('module', 'None')
)
)
@@ -386,22 +386,22 @@ class _GenerateRenderMethod(object):
" callables=%s, calling_uri=_template_uri)" %
(
node.name,
- callable_name,
+ callable_name,
)
)
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
@@ -410,36 +410,36 @@ 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.funcname, c) for c in identifiers.defs])
to_write = set()
-
- # write "context.get()" for all variables we are going to
+
+ # 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
+
+ # write closure functions for closures that we define
# right here
to_write = to_write.union(
[c.funcname for c in identifiers.closuredefs.values()])
- # remove identifiers that are declared in the argument
+ # remove identifiers that are declared in the argument
# 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
+ # 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 self.compiler.enable_loop:
@@ -447,7 +447,7 @@ class _GenerateRenderMethod(object):
to_write.discard("loop")
else:
has_loop = False
-
+
# 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:
@@ -487,20 +487,20 @@ class _GenerateRenderMethod(object):
elif ident in self.compiler.namespaces:
self.printer.writeline(
- "%s = _mako_get_namespace(context, %r)" %
+ "%s = _mako_get_namespace(context, %r)" %
(ident, ident)
)
else:
if getattr(self.compiler, 'has_ns_imports', False):
if self.compiler.strict_undefined:
self.printer.writelines(
- "%s = _import_ns.get(%r, UNDEFINED)" %
+ "%s = _import_ns.get(%r, UNDEFINED)" %
(ident, ident),
"if %s is UNDEFINED:" % ident,
"try:",
"%s = context[%r]" % (ident, ident),
"except KeyError:",
- "raise NameError(\"'%s' is not defined\")" %
+ "raise NameError(\"'%s' is not defined\")" %
ident,
None, None
)
@@ -514,7 +514,7 @@ class _GenerateRenderMethod(object):
"try:",
"%s = context[%r]" % (ident, ident),
"except KeyError:",
- "raise NameError(\"'%s' is not defined\")" %
+ "raise NameError(\"'%s' is not defined\")" %
ident,
None
)
@@ -522,9 +522,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."""
@@ -537,7 +537,7 @@ class _GenerateRenderMethod(object):
funcname = node.funcname
namedecls = node.get_argument_expressions()
nameargs = node.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):
@@ -548,19 +548,19 @@ class _GenerateRenderMethod(object):
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.get_argument_expressions()
-
+
decorator = node.decorator
if decorator:
self.printer.writeline(
"@runtime._decorate_inline(context, %s)" % decorator)
self.printer.writeline(
"def %s(%s):" % (node.funcname, ",".join(namedecls)))
- filtered = len(node.filter_args.args) > 0
+ filtered = len(node.filter_args.args) > 0
buffered = eval(node.attributes.get('buffered', 'False'))
cached = eval(node.attributes.get('cached', 'False'))
self.printer.writelines(
@@ -576,29 +576,29 @@ 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.funcname,
- namedecls, False, identifiers,
+ self.write_cache_decorator(node, node.funcname,
+ 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:
@@ -607,7 +607,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
@@ -623,10 +623,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,
@@ -643,12 +643,12 @@ class _GenerateRenderMethod(object):
"return ''"
)
- def write_cache_decorator(self, node_or_pagetag, name,
- args, buffered, identifiers,
+ def write_cache_decorator(self, node_or_pagetag, name,
+ args, buffered, identifiers,
inline=False, toplevel=False):
- """write a post-function decorator to replace a rendering
+ """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))
@@ -657,42 +657,42 @@ class _GenerateRenderMethod(object):
if self.compiler.pagetag is not None:
cache_args.update(
(
- pa[6:],
+ pa[6:],
self.compiler.pagetag.parsed_attributes[pa]
- )
- for pa in self.compiler.pagetag.parsed_attributes
+ )
+ for pa in self.compiler.pagetag.parsed_attributes
if pa.startswith('cache_') and pa != 'cache_key'
)
cache_args.update(
(
- pa[6:],
+ pa[6:],
node_or_pagetag.parsed_attributes[pa]
- ) for pa in node_or_pagetag.parsed_attributes
+ ) for pa in node_or_pagetag.parsed_attributes
if pa.startswith('cache_') and pa != 'cache_key'
)
if 'timeout' in cache_args:
cache_args['timeout'] = int(eval(cache_args['timeout']))
-
+
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
+ '=' in a and "%s=%s" % ((a.split('=')[0],)*2) or a
for a in args
]
self.write_variable_declares(
- identifiers,
- toplevel=toplevel,
+ identifiers,
+ toplevel=toplevel,
limit=node_or_pagetag.undeclared_identifiers()
)
if buffered:
s = "context.get('local')."\
"cache._ctx_get_or_create("\
"%s, lambda:__M_%s(%s), context, %s__M_defname=%r)" % \
- (cachekey, name, ','.join(pass_args),
- ''.join(["%s=%s, " % (k,v)
- for k, v in cache_args.items()]),
+ (cachekey, name, ','.join(pass_args),
+ ''.join(["%s=%s, " % (k,v)
+ for k, v in cache_args.items()]),
name
)
# apply buffer_filters
@@ -703,21 +703,21 @@ class _GenerateRenderMethod(object):
self.printer.writelines(
"__M_writer(context.get('local')."
"cache._ctx_get_or_create("\
- "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" %
- (cachekey, name, ','.join(pass_args),
- ''.join(["%s=%s, " % (k,v)
- for k, v in cache_args.items()]),
- name,
+ "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" %
+ (cachekey, name, ','.join(pass_args),
+ ''.join(["%s=%s, " % (k,v)
+ for k, v in cache_args.items()]),
+ name,
),
"return ''",
None
)
def create_filter_callable(self, args, target, is_expression):
- """write a filter-applying expression based on the filters
- present in the given filter names, adjusting for the global
+ """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
@@ -725,7 +725,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:
@@ -747,7 +747,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 \
@@ -756,13 +756,13 @@ 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:
self.printer.writeline(None)
@@ -791,11 +791,11 @@ class _GenerateRenderMethod(object):
for c in children
if isinstance(c, parsetree.ControlLine))):
self.printer.writeline("pass")
-
+
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:
@@ -809,23 +809,23 @@ class _GenerateRenderMethod(object):
self.printer.writelines(
"finally:",
"__M_buf, __M_writer = context._pop_buffer_and_writer()",
- "__M_writer(%s)" %
+ "__M_writer(%s)" %
self.create_filter_callable(
- node.filter_args.args,
- "__M_buf.getvalue()",
+ node.filter_args.args,
+ "__M_buf.getvalue()",
False),
None
)
-
+
def visitCode(self, node):
if not node.ismodule:
self.write_source_comment(node)
self.printer.write_indented_block(node.text)
if not self.in_def and len(self.identifiers.locally_assigned) > 0:
- # if we are the "template" def, fudge locally
+ # if we are the "template" def, fudge locally
# declared/modified variables into the "__M_locals" dictionary,
- # which is used for def calls within the same template,
+ # which is used for def calls within the same template,
# to simulate "enclosing scope"
self.printer.writeline(
'__M_locals_builtin_stored = __M_locals_builtin()')
@@ -846,10 +846,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
@@ -871,18 +871,18 @@ 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']
callable_identifiers = self.identifiers.branch(node, nested=True)
body_identifiers = callable_identifiers.branch(node, nested=False)
- # we want the 'caller' passed to ccall to be used
- # for the body() function, but for other non-body()
- # <%def>s within <%call> we want the current caller
+ # we want the 'caller' passed to ccall to be used
+ # for the body() function, but for other non-body()
+ # <%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):
@@ -904,11 +904,11 @@ 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
+
+ # TODO: figure out best way to specify
# buffering/nonbuffering (at call time would be better)
buffered = False
if buffered:
@@ -918,11 +918,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,
@@ -947,7 +947,7 @@ class _GenerateRenderMethod(object):
class _Identifiers(object):
"""tracks the status of identifier names as template code is rendered."""
-
+
def __init__(self, compiler, node=None, parent=None, nested=False):
if parent is not None:
# if we are the branch created in write_namespaces(),
@@ -956,20 +956,20 @@ class _Identifiers(object):
self.declared = set()
self.topleveldefs = util.SetLikeDict()
else:
- # things that have already been declared
+ # things that have already been declared
# in an enclosing namespace (i.e. names we can just use)
self.declared = set(parent.declared).\
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,
+
+ # 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:
@@ -978,29 +978,29 @@ class _Identifiers(object):
self.compiler = compiler
- # things within this level that are referenced before they
+ # 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
+
+ # 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.
- # these will be propagated to
+
+ # 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
+
+ # 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)
@@ -1008,20 +1008,20 @@ class _Identifiers(object):
self.locally_declared)
if illegal_names:
raise exceptions.NameConflictError(
- "Reserved words declared in template: %s" %
+ "Reserved words declared in template: %s" %
", ".join(illegal_names))
def branch(self, node, **kwargs):
- """create a new Identifiers for a new Node, with
+ """create a new Identifiers for a new Node, with
this Identifiers as the parent."""
-
+
return _Identifiers(self.compiler, 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, "\
@@ -1033,38 +1033,38 @@ 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
+ """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
+ # only traverse into the sub-elements of a
+ # <%namespace> tag if we are the branch created in
# write_namespaces()
if self.node is node:
for n in node.nodes:
@@ -1078,7 +1078,7 @@ class _Identifiers(object):
(node.is_block or existing.is_block):
raise exceptions.CompileException(
"%%def or %%block named '%s' already "
- "exists in this template." %
+ "exists in this template." %
node.funcname, **node.exception_kwargs)
def visitDefTag(self, node):
@@ -1091,7 +1091,7 @@ class _Identifiers(object):
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():
@@ -1106,19 +1106,19 @@ class _Identifiers(object):
if isinstance(self.node, parsetree.DefTag):
raise exceptions.CompileException(
- "Named block '%s' not allowed inside of def '%s'"
+ "Named block '%s' not allowed inside of def '%s'"
% (node.name, self.node.name), **node.exception_kwargs)
elif isinstance(self.node,
(parsetree.CallTag, parsetree.CallNamespaceTag)):
raise exceptions.CompileException(
- "Named block '%s' not allowed inside of <%%call> tag"
+ "Named block '%s' not allowed inside of <%%call> tag"
% (node.name, ), **node.exception_kwargs)
for ident in node.undeclared_identifiers():
if ident != 'context' and\
ident not in self.declared.union(self.locally_declared):
self.undeclared.add(ident)
-
+
if not node.is_anonymous:
self._check_name_exists(self.topleveldefs, node)
self.undeclared.add(node.funcname)
@@ -1131,15 +1131,15 @@ class _Identifiers(object):
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():
@@ -1155,7 +1155,7 @@ class _Identifiers(object):
if ident != 'context' and\
ident not in self.declared.union(self.locally_declared):
self.undeclared.add(ident)
-
+
_FOR_LOOP = re.compile(
r'^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*'
@@ -1186,7 +1186,7 @@ def mangle_mako_loop(node, printer):
class LoopVariable(object):
- """A node visitor which looks for the name 'loop' within undeclared
+ """A node visitor which looks for the name 'loop' within undeclared
identifiers."""
def __init__(self):
diff --git a/mako/exceptions.py b/mako/exceptions.py
index 0276957..b8d5ef3 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,
@@ -30,7 +30,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,
@@ -42,7 +42,7 @@ class SyntaxException(MakoException):
class UnsupportedError(MakoException):
"""raised when a retired feature is used."""
-
+
class NameConflictError(MakoException):
"""raised when a reserved word is used inappropriately"""
@@ -51,7 +51,7 @@ class TemplateLookupException(MakoException):
class TopLevelLookupException(TemplateLookupException):
pass
-
+
class RichTraceback(object):
"""Pull the current exception from the ``sys`` traceback and extracts
Mako-specific template information.
@@ -64,28 +64,28 @@ class RichTraceback(object):
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:
@@ -106,7 +106,7 @@ 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
@@ -115,16 +115,16 @@ class RichTraceback(object):
"""
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):
@@ -161,7 +161,7 @@ class RichTraceback(object):
line = line.decode(encoding)
else:
line = line.decode('ascii', 'replace')
- new_trcback.append((filename, lineno, function, line,
+ new_trcback.append((filename, lineno, function, line,
None, None, None, None))
continue
@@ -182,8 +182,8 @@ class RichTraceback(object):
template_line = template_lines[template_ln - 1]
else:
template_line = None
- new_trcback.append((filename, lineno, function,
- line, template_filename, template_ln,
+ new_trcback.append((filename, lineno, function,
+ line, template_filename, template_ln,
template_line, template_source))
if not self.source:
for l in range(len(new_trcback)-1, 0, -1):
@@ -207,13 +207,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"""
diff --git a/mako/filters.py b/mako/filters.py
index 514daf0..37c8fe4 100644
--- a/mako/filters.py
+++ b/mako/filters.py
@@ -11,10 +11,10 @@ from mako import util
xml_escapes = {
'&' : '&amp;',
- '>' : '&gt;',
- '<' : '&lt;',
+ '>' : '&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
@@ -31,7 +31,7 @@ try:
except ImportError:
html_escape = legacy_html_escape
-
+
def xml_escape(string):
return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string)
@@ -61,14 +61,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):
@@ -115,7 +115,7 @@ class XMLEntityEscaper(object):
| ( (?!\d) [:\w] [-.:\w]+ )
) ;''',
re.X | re.UNICODE)
-
+
def __unescape(self, m):
dval, hval, name = m.groups()
if dval:
@@ -128,7 +128,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 a445f47..267c0d1 100644
--- a/mako/lexer.py
+++ b/mako/lexer.py
@@ -13,8 +13,8 @@ from mako.pygen import adjust_whitespace
_regexp_cache = {}
class Lexer(object):
- def __init__(self, text, filename=None,
- disable_unicode=False,
+ def __init__(self, text, filename=None,
+ disable_unicode=False,
input_encoding=None, preprocessor=None):
self.text = text
self.filename = filename
@@ -28,29 +28,29 @@ class Lexer(object):
self.ternary_stack = []
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,
+ 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:
@@ -59,15 +59,15 @@ 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
@@ -86,12 +86,12 @@ class Lexer(object):
cp -=1
self.matched_charpos = mp - cp
self.lineno += len(lines)
- #print "MATCHED:", match.group(0), "LINE START:",
+ #print "MATCHED:", match.group(0), "LINE START:",
# 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
text_re = r'|'.join(text)
@@ -119,10 +119,10 @@ class Lexer(object):
brace_level -= match.group(1).count('}')
continue
raise exceptions.SyntaxException(
- "Expected: %s" %
- ','.join(text),
+ "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)
@@ -185,8 +185,8 @@ class Lexer(object):
if m is not None and m.group(1) != 'utf-8':
raise exceptions.CompileException(
"Found utf-8 BOM in file, with conflicting "
- "magic encoding comment of '%s'" % m.group(1),
- text.decode('utf-8', 'ignore'),
+ "magic encoding comment of '%s'" % m.group(1),
+ text.decode('utf-8', 'ignore'),
0, 0, filename)
else:
m = self._coding_re.match(text.decode('utf-8', 'ignore'))
@@ -201,31 +201,31 @@ class Lexer(object):
except UnicodeDecodeError, e:
raise exceptions.CompileException(
"Unicode decode operation of encoding '%s' failed" %
- parsed_encoding,
- text.decode('utf-8', 'ignore'),
+ parsed_encoding,
+ text.decode('utf-8', 'ignore'),
0, 0, filename)
return parsed_encoding, text
def parse(self):
- self.encoding, self.text = self.decode_raw_stream(self.text,
- not self.disable_unicode,
+ self.encoding, self.text = self.decode_raw_stream(self.text,
+ not self.disable_unicode,
self.encoding,
self.filename,)
for preproc in self.preprocessor:
self.text = preproc(self.text)
-
- # push the match marker past the
+
+ # 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:
+ if self.match_position > self.textlength:
break
-
+
if self.match_end():
break
if self.match_expression():
@@ -234,28 +234,28 @@ class Lexer(object):
continue
if self.match_comment():
continue
- if self.match_tag_start():
+ if self.match_tag_start():
continue
if self.match_tag_end():
continue
if self.match_python_block():
continue
- if self.match_text():
+ if self.match_text():
continue
-
- if self.match_position > self.textlength:
+
+ 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,
+ raise exceptions.SyntaxException("Unclosed tag: <%%%s>" %
+ self.tag[-1].keyword,
**self.exception_kwargs)
if len(self.control_line):
raise exceptions.SyntaxException(
"Unterminated control keyword: '%s'" %
- self.control_line[-1].keyword,
- self.text,
+ self.control_line[-1].keyword,
+ self.text,
self.control_line[-1].lineno,
self.control_line[-1].pos, self.filename)
return self.template
@@ -263,20 +263,20 @@ 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.groups()
self.keyword = keyword
@@ -296,22 +296,22 @@ class Lexer(object):
match = self.match(r'(.*?)(?=\</%text>)', re.S)
if not match:
raise exceptions.SyntaxException(
- "Unclosed tag: <%%%s>" %
- self.tag[-1].keyword,
+ "Unclosed tag: <%%%s>" %
+ self.tag[-1].keyword,
**self.exception_kwargs)
self.append_node(parsetree.Text, match.group(1))
return self.match_tag_end()
return True
- else:
+ else:
return False
-
+
def match_tag_end(self):
match = self.match(r'\</%[\t ]*(.+?)[\t ]*>')
if match:
if not len(self.tag):
raise exceptions.SyntaxException(
"Closing tag without opening tag: </%%%s>" %
- match.group(1),
+ match.group(1),
**self.exception_kwargs)
elif self.tag[-1].keyword != match.group(1):
raise exceptions.SyntaxException(
@@ -322,7 +322,7 @@ class Lexer(object):
return True
else:
return False
-
+
def match_end(self):
match = self.match(r'\Z', re.S)
if match:
@@ -333,13 +333,13 @@ class Lexer(object):
return True
else:
return False
-
+
def match_text(self):
match = self.match(r"""
(.*?) # anything, followed by:
(
- (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based
- # comment preceded by a
+ (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based
+ # comment preceded by a
# consumed newline and whitespace
|
(?=\${) # an expression
@@ -353,7 +353,7 @@ class Lexer(object):
|
\Z # end of string
)""", re.X | re.S)
-
+
if match:
text = match.group(1)
if text:
@@ -361,23 +361,23 @@ class Lexer(object):
return True
else:
return False
-
+
def match_python_block(self):
match = self.match(r"<%(!)?")
if match:
line, pos = self.matched_lineno, self.matched_charpos
text, end = self.parse_until_text(r'%>')
- # the trailing newline helps
+ # 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,
+ parsetree.Code,
+ text,
match.group(1)=='!', lineno=line, pos=pos)
return True
else:
return False
-
+
def match_expression(self):
match = self.match(r"\${")
if match:
@@ -389,8 +389,8 @@ class Lexer(object):
escapes = ""
text = text.replace('\r\n', '\n')
self.append_node(
- parsetree.Expression,
- text, escapes.strip(),
+ parsetree.Expression,
+ text, escapes.strip(),
lineno=line, pos=pos)
return True
else:
@@ -407,22 +407,22 @@ class Lexer(object):
m2 = re.match(r'(end)?(\w+)\s*(.*)', text)
if not m2:
raise exceptions.SyntaxException(
- "Invalid control line: '%s'" %
- text,
+ "Invalid control line: '%s'" %
+ text,
**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(
- "No starting keyword '%s' for '%s'" %
- (keyword, text),
+ "No starting keyword '%s' for '%s'" %
+ (keyword, text),
**self.exception_kwargs)
elif self.control_line[-1].keyword != keyword:
raise exceptions.SyntaxException(
- "Keyword '%s' doesn't match keyword '%s'" %
- (text, self.control_line[-1].keyword),
+ "Keyword '%s' doesn't match keyword '%s'" %
+ (text, self.control_line[-1].keyword),
**self.exception_kwargs)
self.append_node(parsetree.ControlLine, keyword, isend, text)
else:
@@ -439,4 +439,4 @@ class Lexer(object):
return True
else:
return False
-
+
diff --git a/mako/lookup.py b/mako/lookup.py
index 514ad9d..4d86696 100644
--- a/mako/lookup.py
+++ b/mako/lookup.py
@@ -12,13 +12,13 @@ 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
+ 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`
@@ -62,9 +62,9 @@ class TemplateCollection(object):
def filename_to_uri(self, uri, filename):
"""Convert the given ``filename`` to a URI relative to
this :class:`.TemplateCollection`."""
-
+
return uri
-
+
def adjust_uri(self, uri, filename):
"""Adjust the given ``uri`` based on the calling ``filename``.
@@ -78,7 +78,7 @@ class TemplateCollection(object):
"""
return uri
-
+
class TemplateLookup(TemplateCollection):
"""Represent a collection of templates that locates template source files
from the local filesystem.
@@ -143,36 +143,36 @@ class TemplateLookup(TemplateCollection):
to each new :class:`.Template`.
"""
-
- def __init__(self,
- directories=None,
- module_directory=None,
- filesystem_checks=True,
- collection_size=-1,
- format_exceptions=False,
- error_handler=None,
- disable_unicode=False,
+
+ def __init__(self,
+ directories=None,
+ module_directory=None,
+ filesystem_checks=True,
+ collection_size=-1,
+ format_exceptions=False,
+ error_handler=None,
+ disable_unicode=False,
bytestring_passthrough=False,
- output_encoding=None,
- encoding_errors='strict',
+ output_encoding=None,
+ encoding_errors='strict',
cache_args=None,
cache_impl='beaker',
cache_enabled=True,
- cache_type=None,
- cache_dir=None,
- cache_url=None,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
- modulename_callable=None,
+ modulename_callable=None,
module_writer=None,
- default_filters=None,
- buffer_filters=(),
+ default_filters=None,
+ buffer_filters=(),
strict_undefined=False,
- imports=None,
+ imports=None,
enable_loop=True,
- input_encoding=None,
+ input_encoding=None,
preprocessor=None):
-
+
self.directories = [posixpath.normpath(d) for d in
util.to_list(directories, ())
]
@@ -192,22 +192,22 @@ class TemplateLookup(TemplateCollection):
cache_args.setdefault('type', cache_type)
self.template_args = {
- 'format_exceptions':format_exceptions,
- 'error_handler':error_handler,
- 'disable_unicode':disable_unicode,
+ 'format_exceptions':format_exceptions,
+ 'error_handler':error_handler,
+ 'disable_unicode':disable_unicode,
'bytestring_passthrough':bytestring_passthrough,
- 'output_encoding':output_encoding,
+ 'output_encoding':output_encoding,
'cache_impl':cache_impl,
- 'encoding_errors':encoding_errors,
- 'input_encoding':input_encoding,
- 'module_directory':module_directory,
+ 'encoding_errors':encoding_errors,
+ 'input_encoding':input_encoding,
+ 'module_directory':module_directory,
'module_writer':module_writer,
'cache_args':cache_args,
- 'cache_enabled':cache_enabled,
- 'default_filters':default_filters,
- 'buffer_filters':buffer_filters,
+ 'cache_enabled':cache_enabled,
+ 'default_filters':default_filters,
+ 'buffer_filters':buffer_filters,
'strict_undefined':strict_undefined,
- 'imports':imports,
+ 'imports':imports,
'enable_loop':enable_loop,
'preprocessor':preprocessor}
@@ -218,7 +218,7 @@ 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
``uri``.
@@ -244,7 +244,7 @@ class TemplateLookup(TemplateCollection):
def adjust_uri(self, uri, relativeto):
"""Adjust the given ``uri`` based on the given relative URI."""
-
+
key = (uri, relativeto)
if key in self._uri_cache:
return self._uri_cache[key]
@@ -258,8 +258,8 @@ class TemplateLookup(TemplateCollection):
else:
v = self._uri_cache[key] = uri
return v
-
-
+
+
def filename_to_uri(self, filename):
"""Convert the given ``filename`` to a URI relative to
this :class:`.TemplateCollection`."""
@@ -270,25 +270,25 @@ 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'
+ """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:
try:
- # try returning from collection one
+ # try returning from collection one
# more time in case concurrent thread already loaded
return self._collection[uri]
except KeyError:
@@ -301,19 +301,19 @@ class TemplateLookup(TemplateCollection):
self._collection[uri] = template = Template(
uri=uri,
filename=posixpath.normpath(filename),
- lookup=self,
+ lookup=self,
module_filename=module_filename,
**self.template_args)
return template
except:
- # if compilation fails etc, ensure
+ # if compilation fails etc, ensure
# template is removed from collection,
# re-raise
self._collection.pop(uri, None)
raise
finally:
self._mutex.release()
-
+
def _check(self, uri, template):
if template.filename is None:
return template
@@ -331,7 +331,7 @@ class TemplateLookup(TemplateCollection):
raise exceptions.TemplateLookupException(
"Cant locate template for uri %r" % uri)
-
+
def put_string(self, uri, text):
"""Place a new :class:`.Template` object into this
:class:`.TemplateLookup`, based on the given string of
@@ -339,11 +339,11 @@ class TemplateLookup(TemplateCollection):
"""
self._collection[uri] = Template(
- text,
- lookup=self,
- uri=uri,
+ 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
@@ -351,4 +351,4 @@ class TemplateLookup(TemplateCollection):
"""
self._collection[uri] = template
-
+
diff --git a/mako/parsetree.py b/mako/parsetree.py
index e72ac04..9b488d3 100644
--- a/mako/parsetree.py
+++ b/mako/parsetree.py
@@ -8,7 +8,7 @@
from mako import exceptions, ast, util, filters
import re
-
+
class Node(object):
"""base class for a Node in the parse tree."""
@@ -17,15 +17,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,
+ 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():
@@ -36,29 +36,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),
+ 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
-
+
"""
has_loop_context = False
@@ -75,7 +75,7 @@ class ControlLine(Node):
self._undeclared_identifiers = []
else:
code = ast.PythonFragment(text, **self.exception_kwargs)
- self._declared_identifiers = code.declared_identifiers
+ self._declared_identifiers = code.declared_identifiers
self._undeclared_identifiers = code.undeclared_identifiers
def get_children(self):
@@ -86,50 +86,50 @@ 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,
- self.text,
- self.isend,
+ self.keyword,
+ self.text,
+ self.isend,
(self.lineno, self.pos)
)
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):
@@ -146,32 +146,32 @@ class Code(Node):
def __repr__(self):
return "Code(%r, %r, %r)" % (
- self.text,
- self.ismodule,
+ self.text,
+ 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
@@ -192,74 +192,74 @@ class Expression(Node):
def __repr__(self):
return "Expression(%r, %r, %r)" % (
- self.text,
- self.escapes_code.args,
+ self.text,
+ 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(':')
- return type.__call__(CallNamespaceTag, ns, defname,
+ return type.__call__(CallNamespaceTag, ns, defname,
attributes, **kwargs)
try:
cls = _TagMeta._classmap[keyword]
except KeyError:
raise exceptions.CompileException(
- "No such tag: '%s'" % keyword,
- source=kwargs['source'],
- lineno=kwargs['lineno'],
- pos=kwargs['pos'],
+ "No such tag: '%s'" % keyword,
+ source=kwargs['source'],
+ lineno=kwargs['lineno'],
+ pos=kwargs['pos'],
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,
+
+ 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,
+
+ :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
+
+ :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
@@ -268,18 +268,18 @@ class Tag(Node):
missing = [r for r in required if r not in self.parsed_attributes]
if len(missing):
raise exceptions.CompileException(
- "Missing attribute(s): %s" %
- ",".join([repr(m) for m in missing]),
+ "Missing attribute(s): %s" %
+ ",".join([repr(m) for m in missing]),
**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 = {}
@@ -293,8 +293,8 @@ class Tag(Node):
code = ast.PythonCode(m.group(1).rstrip(),
**self.exception_kwargs)
# we aren't discarding "declared_identifiers" here,
- # which we do so that list comprehension-declared
- # variables aren't counted. As yet can't find a
+ # which we do so that list comprehension-declared
+ # variables aren't counted. As yet can't find a
# condition that requires it here.
undeclared_identifiers = \
undeclared_identifiers.union(
@@ -308,13 +308,13 @@ class Tag(Node):
if re.search(r'\${.+?}', self.attributes[key]):
raise exceptions.CompileException(
"Attibute '%s' in tag '%s' does not allow embedded "
- "expressions" % (key, self.keyword),
+ "expressions" % (key, self.keyword),
**self.exception_kwargs)
self.parsed_attributes[key] = repr(self.attributes[key])
else:
raise exceptions.CompileException(
"Invalid attribute for tag '%s': '%s'" %
- (self.keyword, key),
+ (self.keyword, key),
**self.exception_kwargs)
self.expression_undeclared_identifiers = undeclared_identifiers
@@ -325,21 +325,21 @@ class Tag(Node):
return self.expression_undeclared_identifiers
def __repr__(self):
- return "%s(%r, %s, %r, %r)" % (self.__class__.__name__,
- self.keyword,
+ return "%s(%r, %s, %r, %r)" % (self.__class__.__name__,
+ self.keyword,
util.sorted_dict_repr(self.attributes),
- (self.lineno, self.pos),
+ (self.lineno, self.pos),
self.nodes
)
-
+
class IncludeTag(Tag):
__keyword__ = 'include'
def __init__(self, keyword, attributes, **kwargs):
super(IncludeTag, self).__init__(
- keyword,
- attributes,
- ('file', 'import', 'args'),
+ keyword,
+ attributes,
+ ('file', 'import', 'args'),
(), ('file',), **kwargs)
self.page_args = ast.PythonCode(
"__DUMMY(%s)" % attributes.get('args', ''),
@@ -354,18 +354,18 @@ class IncludeTag(Tag):
difference(self.page_args.declared_identifiers)
return identifiers.union(super(IncludeTag, self).
undeclared_identifiers())
-
+
class NamespaceTag(Tag):
__keyword__ = 'namespace'
def __init__(self, keyword, attributes, **kwargs):
super(NamespaceTag, self).__init__(
- keyword, attributes,
- ('file',),
+ keyword, attributes,
+ ('file',),
('name','inheritable',
- 'import','module'),
+ '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(
@@ -386,13 +386,13 @@ class TextTag(Tag):
def __init__(self, keyword, attributes, **kwargs):
super(TextTag, self).__init__(
- keyword,
- attributes, (),
+ keyword,
+ attributes, (),
('filter'), (), **kwargs)
self.filter_args = ast.ArgumentList(
- attributes.get('filter', ''),
+ attributes.get('filter', ''),
**self.exception_kwargs)
-
+
class DefTag(Tag):
__keyword__ = 'def'
@@ -402,23 +402,23 @@ class DefTag(Tag):
super(DefTag, self).__init__(
- keyword,
- attributes,
- expressions,
- ('name','filter', 'decorator'),
- ('name',),
+ keyword,
+ attributes,
+ expressions,
+ ('name','filter', 'decorator'),
+ ('name',),
**kwargs)
name = attributes['name']
if re.match(r'^[\w_]+$',name):
raise exceptions.CompileException(
- "Missing parenthesis in %def",
+ "Missing parenthesis in %def",
**self.exception_kwargs)
- self.function_decl = ast.FunctionDecl("def " + name + ":pass",
+ self.function_decl = ast.FunctionDecl("def " + name + ":pass",
**self.exception_kwargs)
self.name = self.function_decl.funcname
self.decorator = attributes.get('decorator', '')
self.filter_args = ast.ArgumentList(
- attributes.get('filter', ''),
+ attributes.get('filter', ''),
**self.exception_kwargs)
is_anonymous = False
@@ -455,29 +455,29 @@ class BlockTag(Tag):
c for c in attributes if c.startswith('cache_')]
super(BlockTag, self).__init__(
- keyword,
- attributes,
+ keyword,
+ attributes,
expressions,
- ('name','filter', 'decorator'),
- (),
+ ('name','filter', 'decorator'),
+ (),
**kwargs)
name = attributes.get('name')
if name and not re.match(r'^[\w_]+$',name):
raise exceptions.CompileException(
- "%block may not specify an argument signature",
+ "%block may not specify an argument signature",
**self.exception_kwargs)
if not name and attributes.get('args', None):
raise exceptions.CompileException(
"Only named %blocks may specify args",
**self.exception_kwargs
)
- self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+ self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
**self.exception_kwargs)
self.name = name
self.decorator = attributes.get('decorator', '')
self.filter_args = ast.ArgumentList(
- attributes.get('filter', ''),
+ attributes.get('filter', ''),
**self.exception_kwargs)
@@ -509,11 +509,11 @@ class CallTag(Tag):
__keyword__ = 'call'
def __init__(self, keyword, attributes, **kwargs):
- super(CallTag, self).__init__(keyword, attributes,
+ super(CallTag, self).__init__(keyword, attributes,
('args'), ('expr',), ('expr',), **kwargs)
self.expression = attributes['expr']
self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
- self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+ self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
**self.exception_kwargs)
def declared_identifiers(self):
@@ -527,23 +527,23 @@ class CallNamespaceTag(Tag):
def __init__(self, namespace, defname, attributes, **kwargs):
super(CallNamespaceTag, self).__init__(
- namespace + ":" + defname,
- attributes,
- tuple(attributes.keys()) + ('args', ),
- (),
- (),
+ namespace + ":" + defname,
+ attributes,
+ tuple(attributes.keys()) + ('args', ),
+ (),
+ (),
**kwargs)
-
+
self.expression = "%s.%s(%s)" % (
- namespace,
- defname,
+ namespace,
+ defname,
",".join(["%s=%s" % (k, v) for k, v in
- self.parsed_attributes.iteritems()
+ self.parsed_attributes.iteritems()
if k != 'args'])
)
self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
self.body_decl = ast.FunctionArgs(
- attributes.get('args', ''),
+ attributes.get('args', ''),
**self.exception_kwargs)
def declared_identifiers(self):
@@ -558,7 +558,7 @@ class InheritTag(Tag):
def __init__(self, keyword, attributes, **kwargs):
super(InheritTag, self).__init__(
- keyword, attributes,
+ keyword, attributes,
('file',), (), ('file',), **kwargs)
class PageTag(Tag):
@@ -569,13 +569,13 @@ class PageTag(Tag):
c for c in attributes if c.startswith('cache_')]
super(PageTag, self).__init__(
- keyword,
- attributes,
+ keyword,
+ attributes,
expressions,
- (),
- (),
+ (),
+ (),
**kwargs)
- self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+ self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
**self.exception_kwargs)
self.filter_args = ast.ArgumentList(
attributes.get('expression_filter', ''),
@@ -583,5 +583,5 @@ class PageTag(Tag):
def declared_identifiers(self):
return self.body_decl.argnames
-
-
+
+
diff --git a/mako/pygen.py b/mako/pygen.py
index 76e7f6a..e946de5 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
+
+ # 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
+ # 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."""
+ 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.
@@ -65,7 +65,7 @@ class PythonPrinter(object):
self._flush_adjusted_lines()
self.in_indent_lines = True
- if (line is None or
+ if (line is None or
re.match(r"^\s*#",line) or
re.match(r"^\s*$", line)
):
@@ -74,30 +74,30 @@ 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 is_comment and
+ if (not is_comment and
(not hastext or self._is_unindentor(line))
):
-
- if self.indent > 0:
+
+ 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
+ # note that a line can both decrase (before printing) and
# then increase (after printing) the indentation level.
if re.search(r":[ \t]*(?:#.*)?$", line):
@@ -125,53 +125,53 @@ 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',
+ """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:
+ if len(self.indent_detail) == 0:
return False
indentor = self.indent_detail[-1]
-
- # the last indent keyword we grabbed is not a
+
+ # the last indent keyword we grabbed is not a
# compound statement keyword; return False
- if indentor is None:
+ 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:
+ 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
+
+ # match the original indent keyword
#for crit in [
# (r'if|elif', r'else|elif'),
# (r'try', r'except|finally|else'),
# (r'while|for', r'else'),
#]:
- # if re.match(crit[0], indentor) and re.match(crit[1], keyword):
+ # 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."""
@@ -183,7 +183,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."""
@@ -193,24 +193,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)
-
+
+ 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")
@@ -219,32 +219,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)
@@ -256,14 +256,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 cd7d04f..95ec86a 100644
--- a/mako/pyparser.py
+++ b/mako/pyparser.py
@@ -15,17 +15,17 @@ from mako import exceptions, util
import operator
if util.py3k:
- # words that cannot be assigned to (notably
+ # words that cannot be assigned to (notably
# smaller than the total keys in __builtins__)
reserved = set(['True', 'False', 'None', 'print'])
# the "id" attribute on a function node
arg_id = operator.attrgetter('arg')
else:
- # words that cannot be assigned to (notably
+ # 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:
@@ -54,8 +54,8 @@ def parse(code, mode='exec', **exception_kwargs):
except Exception, e:
raise exceptions.SyntaxException(
"(%s) %s (%r)" % (
- e.__class__.__name__,
- e,
+ e.__class__.__name__,
+ e,
code[0:50]
), **exception_kwargs)
diff --git a/mako/runtime.py b/mako/runtime.py
index 640bc89..f890c80 100644
--- a/mako/runtime.py
+++ b/mako/runtime.py
@@ -19,21 +19,21 @@ class Context(object):
:class:`.Context`.
"""
-
+
def __init__(self, buffer, **data):
self._buffer_stack = [buffer]
-
+
self._data = data
self._kwargs = data.copy()
self._with_template = None
self._outputting_as_unicode = None
self.namespaces = {}
-
- # "capture" function which proxies to the
+
+ # "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()
@@ -42,7 +42,7 @@ class Context(object):
illegal_names = t.reserved_names.intersection(self._data)
if illegal_names:
raise exceptions.NameConflictError(
- "Reserved words passed to render(): %s" %
+ "Reserved words passed to render(): %s" %
", ".join(illegal_names))
@property
@@ -52,7 +52,7 @@ class Context(object):
"""
return self._with_template.lookup
-
+
@property
def kwargs(self):
"""Return the dictionary of keyword arguments associated with this
@@ -60,25 +60,25 @@ class Context(object):
"""
return self._kwargs.copy()
-
+
def push_caller(self, caller):
"""Push a ``caller`` callable onto the callstack for
this :class:`.Context`."""
-
-
+
+
self.caller_stack.append(caller)
-
+
def pop_caller(self):
"""Pop 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):
if key in self._data:
return self._data[key]
@@ -88,43 +88,43 @@ class Context(object):
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
def _pop_buffer_and_writer(self):
- """pop the most recent capturing buffer from this Context
+ """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,
+
+ return self._data.get(key,
__builtin__.__dict__.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."""
@@ -140,17 +140,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."""
@@ -180,8 +180,8 @@ class CallerStack(list):
return frame
def _pop_frame(self):
self.nextcaller = self.pop()
-
-
+
+
class Undefined(object):
"""Represents an undefined value in a template.
@@ -311,8 +311,8 @@ 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.
@@ -328,9 +328,9 @@ class Namespace(object):
described here.
"""
-
- def __init__(self, name, context,
- callables=None, inherits=None,
+
+ def __init__(self, name, context,
+ callables=None, inherits=None,
populate_self=True, calling_uri=None):
self.name = name
self.context = context
@@ -365,7 +365,7 @@ class Namespace(object):
one-another.
"""
-
+
filename = None
"""The path of the filesystem file used for this
:class:`.Namespace`'s module or template.
@@ -376,7 +376,7 @@ class Namespace(object):
template file location.
"""
-
+
uri = None
"""The URI for this :class:`.Namespace`'s template.
@@ -424,12 +424,12 @@ class Namespace(object):
if key in self.context.namespaces:
return self.context.namespaces[key]
else:
- ns = TemplateNamespace(uri, self.context._copy(),
- templateuri=uri,
- calling_uri=self._templateuri)
+ ns = TemplateNamespace(uri, self.context._copy(),
+ templateuri=uri,
+ calling_uri=self._templateuri)
self.context.namespaces[key] = ns
return ns
-
+
def get_template(self, uri):
"""Return a :class:`.Template` from the given ``uri``.
@@ -438,7 +438,7 @@ class Namespace(object):
"""
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`.
@@ -452,7 +452,7 @@ class Namespace(object):
"""
return self.cache.get(key, **kwargs)
-
+
@property
def cache(self):
"""Return the :class:`.Cache` object referenced
@@ -461,12 +461,12 @@ class Namespace(object):
"""
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 == '*':
@@ -474,7 +474,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:
@@ -487,7 +487,7 @@ class Namespace(object):
val = getattr(self.inherits, key)
else:
raise AttributeError(
- "Namespace '%s' has no member '%s'" %
+ "Namespace '%s' has no member '%s'" %
(self.name, key))
setattr(self, key, val)
return val
@@ -495,8 +495,8 @@ class Namespace(object):
class TemplateNamespace(Namespace):
"""A :class:`.Namespace` specific to a :class:`.Template` instance."""
- def __init__(self, name, context, template=None, templateuri=None,
- callables=None, inherits=None,
+ def __init__(self, name, context, template=None, templateuri=None,
+ callables=None, inherits=None,
populate_self=True, calling_uri=None):
self.name = name
self.context = context
@@ -505,7 +505,7 @@ class TemplateNamespace(Namespace):
self.callables = dict([(c.func_name, c) for c in callables])
if templateuri is not None:
- self.template = _lookup_template(context, templateuri,
+ self.template = _lookup_template(context, templateuri,
calling_uri)
self._templateuri = self.template.module._template_uri
elif template is not None:
@@ -516,7 +516,7 @@ class TemplateNamespace(Namespace):
if populate_self:
lclcallable, lclcontext = \
- _populate_self_namespace(context, self.template,
+ _populate_self_namespace(context, self.template,
self_ns=self)
@property
@@ -569,7 +569,7 @@ class TemplateNamespace(Namespace):
else:
raise AttributeError(
- "Namespace '%s' has no member '%s'" %
+ "Namespace '%s' has no member '%s'" %
(self.name, key))
setattr(self, key, val)
return val
@@ -577,8 +577,8 @@ class TemplateNamespace(Namespace):
class ModuleNamespace(Namespace):
"""A :class:`.Namespace` specific to a Python module instance."""
- def __init__(self, name, context, module,
- callables=None, inherits=None,
+ def __init__(self, name, context, module,
+ callables=None, inherits=None,
populate_self=True, calling_uri=None):
self.name = name
self.context = context
@@ -619,7 +619,7 @@ class ModuleNamespace(Namespace):
val = getattr(self.inherits, key)
else:
raise AttributeError(
- "Namespace '%s' has no member '%s'" %
+ "Namespace '%s' has no member '%s'" %
(self.name, key))
setattr(self, key, val)
return val
@@ -631,7 +631,7 @@ def supports_caller(func):
See the example in :ref:`namespaces_python_modules`.
"""
-
+
def wrap_stackframe(context, *args, **kwargs):
context.caller_stack._push_frame()
try:
@@ -639,7 +639,7 @@ 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.
@@ -647,7 +647,7 @@ def capture(context, callable_, *args, **kwargs):
See the example in :ref:`namespaces_python_modules`.
"""
-
+
if not callable(callable_):
raise exceptions.RuntimeException(
"capture() function expects a callable as "
@@ -673,7 +673,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)
@@ -681,17 +681,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(),
+ context._clean_inheritance_tokens(),
template)
callable_(ctx, **_kwargs_for_include(callable_, context._data, **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
@@ -705,9 +705,9 @@ def _inherit_from(context, uri, calling_uri):
while ih.inherits is not None:
ih = ih.inherits
lclcontext = context.locals_({'next':ih})
- ih.inherits = TemplateNamespace("self:%s" % template.uri,
- lclcontext,
- template = template,
+ ih.inherits = TemplateNamespace("self:%s" % template.uri,
+ lclcontext,
+ template = template,
populate_self=False)
context._data['parent'] = lclcontext._data['local'] = ih.inherits
callable_ = getattr(template.module, '_mako_inherit', None)
@@ -725,7 +725,7 @@ def _lookup_template(context, uri, relativeto):
lookup = context._with_template.lookup
if lookup is None:
raise exceptions.TemplateLookupException(
- "Template '%s' has no TemplateLookup associated" %
+ "Template '%s' has no TemplateLookup associated" %
context._with_template.uri)
uri = lookup.adjust_uri(uri, relativeto)
try:
@@ -735,8 +735,8 @@ def _lookup_template(context, uri, relativeto):
def _populate_self_namespace(context, template, self_ns=None):
if self_ns is None:
- self_ns = TemplateNamespace('self:%s' % template.uri,
- context, template=template,
+ self_ns = TemplateNamespace('self:%s' % template.uri,
+ context, template=template,
populate_self=False)
context._data['self'] = context._data['local'] = self_ns
if hasattr(template.module, '_mako_inherit'):
@@ -746,7 +746,7 @@ def _populate_self_namespace(context, template, self_ns=None):
return (template.callable_, context)
def _render(template, callable_, args, data, as_unicode=False):
- """create a Context and return the string
+ """create a Context and return the string
output of the given template and template callable."""
if as_unicode:
@@ -755,14 +755,14 @@ def _render(template, callable_, args, data, as_unicode=False):
buf = util.StringIO()
else:
buf = util.FastEncodingBuffer(
- unicode=as_unicode,
- encoding=template.output_encoding,
+ unicode=as_unicode,
+ encoding=template.output_encoding,
errors=template.encoding_errors)
context = Context(buf, **data)
context._outputting_as_unicode = as_unicode
context._set_with_template(template)
-
- _render_context(template, callable_, context, *args,
+
+ _render_context(template, callable_, context, *args,
**_kwargs_for_callable(callable_, data))
return context._pop_buffer().getvalue()
@@ -771,7 +771,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 = {}
@@ -787,10 +787,10 @@ 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
+ # create polymorphic 'self' namespace for this
# template with possibly updated context
if not isinstance(tmpl, template.DefTemplate):
# if main render method, call from the base of the inheritance stack
@@ -800,7 +800,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
@@ -817,7 +817,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:
@@ -836,6 +836,6 @@ def _render_error(template, context, error):
context._buffer_stack[:] = [util.FastEncodingBuffer(
error_template.output_encoding,
error_template.encoding_errors)]
-
+
context._set_with_template(error_template)
error_template.render_context(context, error=error)
diff --git a/mako/template.py b/mako/template.py
index 7ab6a46..b069139 100644
--- a/mako/template.py
+++ b/mako/template.py
@@ -11,7 +11,7 @@ from mako.lexer import Lexer
from mako import runtime, util, exceptions, codegen, cache
import os, re, shutil, stat, sys, tempfile, types, weakref
-
+
class Template(object):
"""Represents a compiled template.
@@ -86,7 +86,7 @@ class Template(object):
:param enable_loop: When ``True``, enable the ``loop`` context variable.
This can be set to ``False`` to support templates that may
be making usage of the name "``loop``". Individual templates can
- re-enable the "loop" context by placing the directive
+ re-enable the "loop" context by placing the directive
``enable_loop="True"`` inside the ``<%page>`` tag -- see
:ref:`migrating_loop`.
@@ -172,7 +172,7 @@ class Template(object):
result of the callable will be used as the template source
code.
- :param strict_undefined: Replaces the automatic usage of
+ :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
@@ -190,31 +190,31 @@ class Template(object):
"""
- def __init__(self,
- text=None,
- filename=None,
- uri=None,
- format_exceptions=False,
- error_handler=None,
- lookup=None,
- output_encoding=None,
- encoding_errors='strict',
- module_directory=None,
+ def __init__(self,
+ text=None,
+ filename=None,
+ uri=None,
+ format_exceptions=False,
+ error_handler=None,
+ lookup=None,
+ output_encoding=None,
+ encoding_errors='strict',
+ module_directory=None,
cache_args=None,
cache_impl='beaker',
cache_enabled=True,
- cache_type=None,
- cache_dir=None,
- cache_url=None,
- module_filename=None,
- input_encoding=None,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
+ module_filename=None,
+ input_encoding=None,
disable_unicode=False,
module_writer=None,
- bytestring_passthrough=False,
- default_filters=None,
- buffer_filters=(),
+ bytestring_passthrough=False,
+ default_filters=None,
+ buffer_filters=(),
strict_undefined=False,
- imports=None,
+ imports=None,
enable_loop=True,
preprocessor=None):
if uri:
@@ -264,10 +264,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)
@@ -282,7 +282,7 @@ class Template(object):
elif module_directory is not None:
path = os.path.abspath(
os.path.join(
- os.path.normpath(module_directory),
+ os.path.normpath(module_directory),
u_norm + ".py"
)
)
@@ -314,7 +314,7 @@ class Template(object):
else:
return codegen.RESERVED_NAMES.difference(['loop'])
- def _setup_cache_args(self,
+ def _setup_cache_args(self,
cache_impl, cache_enabled, cache_args,
cache_type, cache_dir, cache_url):
self.cache_impl = cache_impl
@@ -340,9 +340,9 @@ class Template(object):
os.stat(path)[stat.ST_MTIME] < filemtime:
data = util.read_file(filename)
_compile_module_file(
- self,
+ self,
data,
- filename,
+ filename,
path,
self.module_writer)
module = util.load_module(self.module_id, path)
@@ -350,9 +350,9 @@ class Template(object):
if module._magic_number != codegen.MAGIC_NUMBER:
data = util.read_file(filename)
_compile_module_file(
- self,
- data,
- filename,
+ self,
+ data,
+ filename,
path,
self.module_writer)
module = util.load_module(self.module_id, path)
@@ -363,26 +363,26 @@ class Template(object):
# in memory
data = util.read_file(filename)
code, module = _compile_text(
- self,
- data,
+ self,
+ data,
filename)
self._source = None
self._code = code
ModuleInfo(module, None, self, filename, code, None)
return module
-
+
@property
def source(self):
"""Return the template source code for this :class:`.Template`."""
-
+
return _get_module_info_from_callable(self.callable_).source
@property
def code(self):
"""Return the module source code for this :class:`.Template`."""
-
+
return _get_module_info_from_callable(self.callable_).code
-
+
@util.memoized_property
def cache(self):
return cache.Cache(self)
@@ -396,7 +396,7 @@ class Template(object):
@property
def cache_type(self):
return self.cache_args['type']
-
+
def render(self, *args, **data):
"""Render the output of this template as a string.
@@ -410,16 +410,16 @@ class Template(object):
"""
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,
+
+ return runtime._render(self,
+ self.callable_,
+ args,
+ data,
as_unicode=True)
-
+
def render_context(self, context, *args, **kwargs):
"""Render this :class:`.Template` with the given context.
@@ -428,63 +428,63 @@ class Template(object):
"""
if getattr(context, '_with_template', None) is None:
context._set_with_template(self)
- runtime._render_context(self,
- self.callable_,
- context,
- *args,
+ runtime._render_context(self,
+ self.callable_,
+ 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
-
+ def last_modified(self):
+ 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,
- template_filename=None,
- module_source=None,
+
+ def __init__(self, module,
+ module_filename=None,
+ template=None,
+ template_filename=None,
+ module_source=None,
template_source=None,
- output_encoding=None,
+ output_encoding=None,
encoding_errors='strict',
- disable_unicode=False,
+ disable_unicode=False,
bytestring_passthrough=False,
format_exceptions=False,
- error_handler=None,
- lookup=None,
+ error_handler=None,
+ lookup=None,
cache_args=None,
cache_impl='beaker',
cache_enabled=True,
- cache_type=None,
- cache_dir=None,
- cache_url=None,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
):
self.module_id = re.sub(r'\W', "_", module._template_uri)
self.uri = module._template_uri
@@ -506,13 +506,13 @@ class ModuleTemplate(Template):
self.module = module
self.filename = template_filename
- ModuleInfo(module,
- module_filename,
- self,
- template_filename,
- module_source,
+ ModuleInfo(module,
+ module_filename,
+ self,
+ template_filename,
+ module_source,
template_source)
-
+
self.callable_ = self.module.render_body
self.format_exceptions = format_exceptions
self.error_handler = error_handler
@@ -521,11 +521,11 @@ class ModuleTemplate(Template):
cache_impl, cache_enabled, cache_args,
cache_type, cache_dir, cache_url
)
-
+
class DefTemplate(Template):
"""A :class:`.Template` which represents a callable def in a parent
template."""
-
+
def __init__(self, parent, callable_):
self.parent = parent
self.callable_ = callable_
@@ -545,16 +545,16 @@ 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()
- def __init__(self,
- module,
- module_filename,
- template,
- template_filename,
- module_source,
+ def __init__(self,
+ module,
+ module_filename,
+ template,
+ template_filename,
+ module_source,
template_source):
self.module = module
self.module_filename = module_filename
@@ -564,14 +564,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 util.read_file(self.module_filename)
-
+
@property
def source(self):
if self.template_source is not None:
@@ -589,18 +589,18 @@ class ModuleInfo(object):
return data
def _compile(template, text, filename, generate_magic_comment):
- lexer = Lexer(text,
- filename,
+ lexer = Lexer(text,
+ filename,
disable_unicode=template.disable_unicode,
input_encoding=template.input_encoding,
preprocessor=template.preprocessor)
node = lexer.parse()
- source = codegen.compile(node,
- template.uri,
+ source = codegen.compile(node,
+ template.uri,
filename,
default_filters=template.default_filters,
- buffer_filters=template.buffer_filters,
- imports=template.imports,
+ buffer_filters=template.buffer_filters,
+ imports=template.imports,
source_encoding=lexer.encoding,
generate_magic_comment=generate_magic_comment,
disable_unicode=template.disable_unicode,
@@ -611,7 +611,7 @@ def _compile(template, text, filename, generate_magic_comment):
def _compile_text(template, text, filename):
identifier = template.module_id
- source, lexer = _compile(template, text, filename,
+ source, lexer = _compile(template, text, filename,
generate_magic_comment=template.disable_unicode)
cid = identifier
@@ -624,27 +624,27 @@ def _compile_text(template, text, filename):
def _compile_module_file(template, text, filename, outputpath, module_writer):
identifier = template.module_id
- source, lexer = _compile(template, text, filename,
+ source, lexer = _compile(template, text, filename,
generate_magic_comment=True)
-
+
if isinstance(source, unicode):
source = source.encode(lexer.encoding or 'ascii')
if module_writer:
module_writer(source, outputpath)
else:
- # make tempfiles in the same location as the ultimate
+ # 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))
-
+
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 dc070a0..df4bf4b 100644
--- a/mako/util.py
+++ b/mako/util.py
@@ -35,7 +35,7 @@ except ImportError:
if win32 or jython:
time_func = time.clock
else:
- time_func = time.time
+ time_func = time.time
def function_named(fn, name):
"""Return a function with a given __name__.
@@ -87,13 +87,13 @@ class PluginLoader(object):
else:
import pkg_resources
for impl in pkg_resources.iter_entry_points(
- self.group,
+ self.group,
name):
self.impls[name] = impl.load
return impl.load()
else:
raise exceptions.RuntimeException(
- "Can't load plugin %s %s" %
+ "Can't load plugin %s %s" %
(self.group, name))
def register(self, name, modulepath, objname):
@@ -106,9 +106,9 @@ class PluginLoader(object):
def verify_directory(dir):
"""create and/or verify a filesystem directory."""
-
+
tries = 0
-
+
while not os.path.exists(dir):
try:
tries += 1
@@ -170,16 +170,16 @@ 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)
return x
class FastEncodingBuffer(object):
- """a very rudimentary buffer that is faster than StringIO,
+ """a very rudimentary buffer that is faster than StringIO,
but doesn't crash on unicode data like cStringIO."""
-
+
def __init__(self, encoding=None, errors='strict', unicode=False):
self.data = collections.deque()
self.encoding = encoding
@@ -190,11 +190,11 @@ class FastEncodingBuffer(object):
self.unicode = unicode
self.errors = errors
self.write = self.data.append
-
+
def truncate(self):
self.data = collections.deque()
self.write = self.data.append
-
+
def getvalue(self):
if self.encoding:
return self.delim.join(self.data).encode(self.encoding,
@@ -205,12 +205,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
@@ -218,26 +218,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:
@@ -246,10 +246,10 @@ 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),
+ bytime = sorted(dict.values(self),
key=operator.attrgetter('timestamp'), reverse=True)
for item in bytime[self.capacity:]:
try:
@@ -313,14 +313,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