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