[pypy-svn] r80089 - in pypy/benchmarks: lib/mako lib/mako/doc lib/mako/doc/build lib/mako/doc/build/builder lib/mako/doc/build/static lib/mako/doc/build/templates lib/mako/examples lib/mako/examples/bench lib/mako/examples/bench/cheetah lib/mako/examples/bench/django lib/mako/examples/bench/django/templates lib/mako/examples/bench/django/templatetags lib/mako/examples/bench/genshi lib/mako/examples/bench/kid lib/mako/examples/bench/mako lib/mako/examples/bench/mako_inheritance lib/mako/examples/bench/myghty lib/mako/examples/wsgi lib/mako/examples/wsgi/htdocs lib/mako/examples/wsgi/templates lib/mako/mako lib/mako/mako/ext lib/mako/scripts lib/mako/test lib/mako/test/foo lib/mako/test/templates lib/mako/test/templates/foo lib/mako/test/templates/subdir lib/mako/test/templates/subdir/foo own
fijal at codespeak.net
fijal at codespeak.net
Tue Dec 21 07:44:21 CET 2010
Author: fijal
Date: Tue Dec 21 07:44:16 2010
New Revision: 80089
Added:
pypy/benchmarks/lib/mako/
pypy/benchmarks/lib/mako/.hgignore (contents, props changed)
pypy/benchmarks/lib/mako/.hgtags
pypy/benchmarks/lib/mako/CHANGES
pypy/benchmarks/lib/mako/LICENSE
pypy/benchmarks/lib/mako/MANIFEST.in
pypy/benchmarks/lib/mako/README
pypy/benchmarks/lib/mako/README.py3k
pypy/benchmarks/lib/mako/distribute_setup.py
pypy/benchmarks/lib/mako/doc/
pypy/benchmarks/lib/mako/doc/build/
pypy/benchmarks/lib/mako/doc/build/Makefile
pypy/benchmarks/lib/mako/doc/build/builder/
pypy/benchmarks/lib/mako/doc/build/builder/__init__.py
pypy/benchmarks/lib/mako/doc/build/builder/builders.py
pypy/benchmarks/lib/mako/doc/build/builder/util.py
pypy/benchmarks/lib/mako/doc/build/caching.rst
pypy/benchmarks/lib/mako/doc/build/conf.py
pypy/benchmarks/lib/mako/doc/build/defs.rst
pypy/benchmarks/lib/mako/doc/build/filtering.rst
pypy/benchmarks/lib/mako/doc/build/index.rst
pypy/benchmarks/lib/mako/doc/build/inheritance.rst
pypy/benchmarks/lib/mako/doc/build/namespaces.rst
pypy/benchmarks/lib/mako/doc/build/runtime.rst
pypy/benchmarks/lib/mako/doc/build/static/
pypy/benchmarks/lib/mako/doc/build/static/docs.css
pypy/benchmarks/lib/mako/doc/build/syntax.rst
pypy/benchmarks/lib/mako/doc/build/templates/
pypy/benchmarks/lib/mako/doc/build/templates/genindex.mako
pypy/benchmarks/lib/mako/doc/build/templates/layout.mako
pypy/benchmarks/lib/mako/doc/build/templates/page.mako
pypy/benchmarks/lib/mako/doc/build/templates/search.mako
pypy/benchmarks/lib/mako/doc/build/templates/site_base.mako
pypy/benchmarks/lib/mako/doc/build/templates/static_base.mako
pypy/benchmarks/lib/mako/doc/build/unicode.rst
pypy/benchmarks/lib/mako/doc/build/usage.rst
pypy/benchmarks/lib/mako/examples/
pypy/benchmarks/lib/mako/examples/bench/
pypy/benchmarks/lib/mako/examples/bench/basic.py
pypy/benchmarks/lib/mako/examples/bench/cheetah/
pypy/benchmarks/lib/mako/examples/bench/cheetah/footer.tmpl
pypy/benchmarks/lib/mako/examples/bench/cheetah/header.tmpl
pypy/benchmarks/lib/mako/examples/bench/cheetah/template.tmpl
pypy/benchmarks/lib/mako/examples/bench/django/
pypy/benchmarks/lib/mako/examples/bench/django/templates/
pypy/benchmarks/lib/mako/examples/bench/django/templates/base.html
pypy/benchmarks/lib/mako/examples/bench/django/templates/template.html
pypy/benchmarks/lib/mako/examples/bench/django/templatetags/
pypy/benchmarks/lib/mako/examples/bench/django/templatetags/__init__.py
pypy/benchmarks/lib/mako/examples/bench/django/templatetags/bench.py
pypy/benchmarks/lib/mako/examples/bench/genshi/
pypy/benchmarks/lib/mako/examples/bench/genshi/base.html
pypy/benchmarks/lib/mako/examples/bench/genshi/template.html
pypy/benchmarks/lib/mako/examples/bench/kid/
pypy/benchmarks/lib/mako/examples/bench/kid/base.kid
pypy/benchmarks/lib/mako/examples/bench/kid/template.kid
pypy/benchmarks/lib/mako/examples/bench/mako/
pypy/benchmarks/lib/mako/examples/bench/mako/footer.html
pypy/benchmarks/lib/mako/examples/bench/mako/header.html
pypy/benchmarks/lib/mako/examples/bench/mako/template.html
pypy/benchmarks/lib/mako/examples/bench/mako_inheritance/
pypy/benchmarks/lib/mako/examples/bench/mako_inheritance/base.html
pypy/benchmarks/lib/mako/examples/bench/mako_inheritance/template.html
pypy/benchmarks/lib/mako/examples/bench/myghty/
pypy/benchmarks/lib/mako/examples/bench/myghty/base.myt
pypy/benchmarks/lib/mako/examples/bench/myghty/template.myt
pypy/benchmarks/lib/mako/examples/wsgi/
pypy/benchmarks/lib/mako/examples/wsgi/htdocs/
pypy/benchmarks/lib/mako/examples/wsgi/htdocs/index.html
pypy/benchmarks/lib/mako/examples/wsgi/run_wsgi.py
pypy/benchmarks/lib/mako/examples/wsgi/templates/
pypy/benchmarks/lib/mako/examples/wsgi/templates/root.html
pypy/benchmarks/lib/mako/mako/
pypy/benchmarks/lib/mako/mako/__init__.py
pypy/benchmarks/lib/mako/mako/_ast_util.py
pypy/benchmarks/lib/mako/mako/ast.py
pypy/benchmarks/lib/mako/mako/cache.py
pypy/benchmarks/lib/mako/mako/codegen.py
pypy/benchmarks/lib/mako/mako/exceptions.py
pypy/benchmarks/lib/mako/mako/ext/
pypy/benchmarks/lib/mako/mako/ext/__init__.py
pypy/benchmarks/lib/mako/mako/ext/autohandler.py
pypy/benchmarks/lib/mako/mako/ext/babelplugin.py
pypy/benchmarks/lib/mako/mako/ext/preprocessors.py
pypy/benchmarks/lib/mako/mako/ext/pygmentplugin.py
pypy/benchmarks/lib/mako/mako/ext/turbogears.py
pypy/benchmarks/lib/mako/mako/filters.py
pypy/benchmarks/lib/mako/mako/lexer.py
pypy/benchmarks/lib/mako/mako/lookup.py
pypy/benchmarks/lib/mako/mako/parsetree.py
pypy/benchmarks/lib/mako/mako/pygen.py
pypy/benchmarks/lib/mako/mako/pyparser.py
pypy/benchmarks/lib/mako/mako/runtime.py
pypy/benchmarks/lib/mako/mako/template.py
pypy/benchmarks/lib/mako/mako/util.py
pypy/benchmarks/lib/mako/scripts/
pypy/benchmarks/lib/mako/scripts/mako-render
pypy/benchmarks/lib/mako/setup.cfg
pypy/benchmarks/lib/mako/setup.py
pypy/benchmarks/lib/mako/test/
pypy/benchmarks/lib/mako/test/__init__.py
pypy/benchmarks/lib/mako/test/foo/
pypy/benchmarks/lib/mako/test/foo/__init__.py
pypy/benchmarks/lib/mako/test/foo/test_ns.py
pypy/benchmarks/lib/mako/test/sample_module_namespace.py
pypy/benchmarks/lib/mako/test/templates/
pypy/benchmarks/lib/mako/test/templates/badbom.html
pypy/benchmarks/lib/mako/test/templates/bom.html
pypy/benchmarks/lib/mako/test/templates/bommagic.html
pypy/benchmarks/lib/mako/test/templates/chs_unicode.html
pypy/benchmarks/lib/mako/test/templates/chs_unicode_py3k.html
pypy/benchmarks/lib/mako/test/templates/chs_utf8.html
pypy/benchmarks/lib/mako/test/templates/crlf.html
pypy/benchmarks/lib/mako/test/templates/foo/
pypy/benchmarks/lib/mako/test/templates/foo/modtest.html.py
pypy/benchmarks/lib/mako/test/templates/gettext.mako
pypy/benchmarks/lib/mako/test/templates/index.html
pypy/benchmarks/lib/mako/test/templates/internationalization.html
pypy/benchmarks/lib/mako/test/templates/modtest.html
pypy/benchmarks/lib/mako/test/templates/read_unicode.html
pypy/benchmarks/lib/mako/test/templates/read_unicode_py3k.html
pypy/benchmarks/lib/mako/test/templates/runtimeerr.html
pypy/benchmarks/lib/mako/test/templates/runtimeerr_py3k.html
pypy/benchmarks/lib/mako/test/templates/subdir/
pypy/benchmarks/lib/mako/test/templates/subdir/foo/
pypy/benchmarks/lib/mako/test/templates/subdir/foo/modtest.html.py
pypy/benchmarks/lib/mako/test/templates/subdir/incl.html
pypy/benchmarks/lib/mako/test/templates/subdir/index.html
pypy/benchmarks/lib/mako/test/templates/subdir/modtest.html
pypy/benchmarks/lib/mako/test/templates/unicode.html
pypy/benchmarks/lib/mako/test/templates/unicode_arguments.html
pypy/benchmarks/lib/mako/test/templates/unicode_arguments_py3k.html
pypy/benchmarks/lib/mako/test/templates/unicode_code.html
pypy/benchmarks/lib/mako/test/templates/unicode_code_py3k.html
pypy/benchmarks/lib/mako/test/templates/unicode_expr.html
pypy/benchmarks/lib/mako/test/templates/unicode_expr_py3k.html
pypy/benchmarks/lib/mako/test/templates/unicode_runtime_error.html
pypy/benchmarks/lib/mako/test/templates/unicode_syntax_error.html
pypy/benchmarks/lib/mako/test/test_ast.py
pypy/benchmarks/lib/mako/test/test_babelplugin.py
pypy/benchmarks/lib/mako/test/test_cache.py
pypy/benchmarks/lib/mako/test/test_call.py
pypy/benchmarks/lib/mako/test/test_decorators.py
pypy/benchmarks/lib/mako/test/test_def.py
pypy/benchmarks/lib/mako/test/test_exceptions.py
pypy/benchmarks/lib/mako/test/test_filters.py
pypy/benchmarks/lib/mako/test/test_inheritance.py
pypy/benchmarks/lib/mako/test/test_lexer.py
pypy/benchmarks/lib/mako/test/test_lookup.py
pypy/benchmarks/lib/mako/test/test_lru.py
pypy/benchmarks/lib/mako/test/test_namespace.py
pypy/benchmarks/lib/mako/test/test_pygen.py
pypy/benchmarks/lib/mako/test/test_template.py
pypy/benchmarks/lib/mako/test/test_tgplugin.py
pypy/benchmarks/lib/mako/test/util.py
pypy/benchmarks/own/bm_mako.py
Log:
Add bm_mako benchmark by virhilo (Thanks!)
Added: pypy/benchmarks/lib/mako/.hgignore
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/.hgignore Tue Dec 21 07:44:16 2010
@@ -0,0 +1,7 @@
+syntax:regexp
+^build/
+^doc/build/output
+.pyc$
+.orig$
+Mako.egg-info
+easy-install.pth
Added: pypy/benchmarks/lib/mako/.hgtags
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/.hgtags Tue Dec 21 07:44:16 2010
@@ -0,0 +1,24 @@
+1a2fbc26abfb1c216e7f1f8573c248205f143013 rel_0_2_5
+2bfdc3433515dcc421042ded67a333582dd4592a rel_0_1_3
+2ff9213bd63b6cd292d9b0e941e3e9c324cf3af0 rel_0_1_10
+38685d993e502775a4d832968f9480b75bb0f7d8 rel_0_2_3
+46da51a23d57f7bb8efa24a07d6100bc427e2a0b rel_0_2_2
+4fcd99d1050a7ee0fe5eea80344489074b5ac8ad rel_0_1_4
+6d1bd90f12a504639d900094ddf099f7e857561f rel_0_2_1
+75a1033deb54b628b709d92d0ad1ce285555fa2e rel_0_3_1
+7cbfc1c08433a3975f2485bee10990eccfdb11fc rel_0_1_7
+7da58ced3378bf42f74764127c71f803521fe342 rel_0_1_8
+7f9dc96e795b9ad8280cd4da767c8b2913514f09 rel_0_1_5
+8707e18ae54e7714cf68c1cac93392a475d2bc34 rel_0_2_4
+8cd4e83283f6b6cf91f9eea5eb5960875ef04a80 rel_0_1_1
+9a5a8567b72afb86365b36b9f1db669a4052735c rel_0_1_9
+a1a4cc82d055d91bc6cd0c9c258dabfd9e9598bf rel_0_3_2
+a7beb4bb473e973aa1f3e489e23f745a170d7d56 rel_0_1_2
+adef1dd150ce6fbdd0e648746918c1674b7b2ae8 rel_0_2_0
+d8455afdac7ba997847e52bd4ecf5664bc1f5242 rel_0_3_0
+dcc5516f65a3f667f102751d8964ad2eb3bfc483 rel_0_1_0
+e62bc10997e49697f21ea6eaacea34464893a877 rel_0_1_6
+6efa09cec79f8ac79c3be054573f30904d439c74 rel_0_3_3
+7c0d449fb0aa7cf4e178f9a6bf21fff9570b791e rel_0_3_4
+3c97a5d3dbd317a6019e6ea5d046905ce358b93b rel_0_3_5
+26df51c4fc72a70e5e1420660d79b58fed06ccd6 rel_0_3_6
Added: pypy/benchmarks/lib/mako/CHANGES
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/CHANGES Tue Dec 21 07:44:16 2010
@@ -0,0 +1,590 @@
+0.3.6
+- Documentation is on Sphinx.
+ [ticket:126]
+
+- Beaker is now part of "extras" in
+ setup.py instead of "install_requires".
+ This to produce a lighter weight install
+ for those who don't use the caching
+ as well as to conform to Pyramid
+ deployment practices. [ticket:154]
+
+- The Beaker import (or attempt thereof)
+ is delayed until actually needed;
+ this to remove the performance penalty
+ from startup, particularly for
+ "single execution" environments
+ such as shell scripts. [ticket:153]
+
+- Patch to lexer to not generate an empty
+ '' write in the case of backslash-ended
+ lines. [ticket:155]
+
+- Fixed missing **extra collection in
+ 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
+ raise a NameError immediately, instead of
+ defaulting to the UNDEFINED value.
+
+- The range of Python identifiers that
+ are considered "undefined", meaning they
+ are pulled from the context, has been
+ trimmed back to not include variables
+ declared inside of expressions (i.e. from
+ list comprehensions), as well as
+ in the argument list of lambdas. This
+ to better support the strict_undefined
+ feature. The change should be
+ fully backwards-compatible but involved
+ a little bit of tinkering in the AST code,
+ which hadn't really been touched for
+ a couple of years, just FYI.
+
+0.3.5
+- The <%namespace> tag allows expressions
+ for the `file` argument, i.e. with ${}.
+ The `context` variable, if needed,
+ must be referenced explicitly.
+ [ticket:141]
+
+- ${} 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
+ them raises a CompileException instead of
+ silently failing.
+
+- Added a try/except around "import markupsafe".
+ This to support GAE which can't run markupsafe.
+ [ticket:151] No idea whatsoever if the
+ install_requires in setup.py also breaks GAE,
+ couldn't get an answer on this.
+
+0.3.4
+- Now using MarkupSafe for HTML escaping,
+ i.e. in place of cgi.escape(). Faster
+ C-based implementation and also escapes
+ 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
+ and sys.exc_info() has been reset,
+ 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
+ Python 2.4 [ticket:131]
+
+- Fixed broken @property decorator on
+ template.last_modified
+
+- Fixed error formatting when a stacktrace
+ line contains no line number, as in when
+ inside an eval/exec-generated function.
+ [ticket:132]
+
+- When a .py is being created, the tempfile
+ where the source is stored temporarily is
+ now made in the same directory as that of
+ the .py file. This ensures that the two
+ files share the same filesystem, thus
+ 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]
+
+0.3
+- Python 2.3 support is dropped. [ticket:123]
+
+- Python 3 support is added ! See README.py3k
+ for installation and testing notes.
+ [ticket:119]
+
+- Unit tests now run with nose. [ticket:127]
+
+- Source code escaping has been simplified.
+ In particular, module source files are now
+ generated with the Python "magic encoding
+ comment", and source code is passed through
+ mostly unescaped, except for that code which
+ is regenerated from parsed Python source.
+ This fixes usage of unicode in
+ <%namespace:defname> tags. [ticket:99]
+
+- RichTraceback(), html_error_template().render(),
+ text_error_template().render() now accept "error"
+ and "traceback" as optional arguments, and
+ 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(),
+ or an encoded string if during render().
+
+- A percent sign can be emitted as the first
+ non-whitespace character on a line by escaping
+ it as in "%%". [ticket:112]
+
+- Template accepts empty control structure, i.e.
+ % if: %endif, etc. [ticket:94]
+
+- The <%page args> tag can now be used in a base
+ inheriting template - the full set of render()
+ arguments are passed down through the inherits
+ chain. Undeclared arguments go into **pageargs
+ as usual. [ticket:116]
+
+- defs declared within a <%namespace> section, an
+ uncommon feature, have been improved. The defs
+ no longer get doubly-rendered in the body() scope,
+ and now allow local variable assignment without
+ breakage. [ticket:109]
+
+- Windows paths are handled correctly if a Template
+ is passed only an absolute filename (i.e. with c:
+ drive etc.) and no URI - the URI is converted
+ to a forward-slash path and module_directory
+ is treated as a windows path. [ticket:128]
+
+- TemplateLookup raises TopLevelLookupException for
+ a given path that is a directory, not a filename,
+ instead of passing through to the template to
+ generate IOError. [ticket:73]
+
+0.2.6
+
+- Fix mako function decorators to preserve the
+ original function's name in all cases. Patch
+ from Scott Torborg.
+
+- Support the <%namespacename:defname> syntax in
+ the babel extractor. [ticket:118]
+
+- Further fixes to unicode handling of .py files with the
+ html_error_template. [ticket:88]
+
+0.2.5
+- Added a "decorator" kw argument to <%def>,
+ allows custom decoration functions to wrap
+ rendering callables. Mainly intended for
+ custom caching algorithms, not sure what
+ other uses there may be (but there may be).
+ Examples are in the "filtering" docs.
+
+- When Mako creates subdirectories in which
+ to store templates, it uses the more
+ permissive mode of 0775 instead of 0750,
+ helping out with certain multi-process
+ 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]
+
+- Fixed lexing support for whitespace
+ around '=' sign in defs. [ticket:102]
+
+- Removed errant "lower()" in the lexer which
+ was causing tags to compile with
+ case-insensitive names, thus messing up
+ custom <%call> names. [ticket:108]
+
+- added "mako.__version__" attribute to
+ the base module. [ticket:110]
+
+0.2.4
+- Fixed compatibility with Jython 2.5b1.
+
+0.2.3
+- the <%namespacename:defname> syntax described at
+ http://techspot.zzzeek.org/?p=28 has now
+ been added as a built in syntax, and is recommended
+ as a more modern syntax versus <%call expr="expression">.
+ The %call tag itself will always remain,
+ with <%namespacename:defname> presenting a more HTML-like
+ alternative to calling defs, both plain and
+ nested. Many examples of the new syntax are in the
+ "Calling a def with embedded content" section
+ of the docs.
+
+- added support for Jython 2.5.
+
+- cache module now uses Beaker's CacheManager
+ object directly, so that all cache types are included.
+ memcached is available as both "ext:memcached" and
+ "memcached", the latter for backwards compatibility.
+
+- added "cache" accessor to Template, Namespace.
+ e.g. ${local.cache.get('somekey')} or
+ template.cache.invalidate_body()
+
+- added "cache_enabled=True" flag to Template,
+ TemplateLookup. Setting this to False causes cache
+ operations to "pass through" and execute every time;
+ this flag should be integrated in Pylons with its own
+ cache_enabled configuration setting.
+
+- the Cache object now supports invalidate_def(name),
+ invalidate_body(), invalidate_closure(name),
+ invalidate(key), which will remove the given key
+ from the cache, if it exists. The cache arguments
+ (i.e. storage type) are derived from whatever has
+ been already persisted for that template.
+ [ticket:92]
+
+- For cache changes to work fully, Beaker 1.1 is required.
+ 1.0.1 and up will work as well with the exception of
+ cache expiry. Note that Beaker 1.1 is **required**
+ for applications which use dynamically generated keys,
+ since previous versions will permanently store state in memory
+ for each individual key, thus consuming all available
+ memory for an arbitrarily large number of distinct
+ keys.
+
+- fixed bug whereby an <%included> template with
+ <%page> args named the same as a __builtin__ would not
+ honor the default value specified in <%page> [ticket:93]
+
+- fixed the html_error_template not handling tracebacks from
+ normal .py files with a magic encoding comment [ticket:88]
+
+- RichTraceback() now accepts an optional traceback object
+ to be used in place of sys.exc_info()[2]. html_error_template()
+ 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
+ as templates with no compilation step. Source code
+ and template source are optional but allow error reporting
+ to work correctly.
+
+- fixed Python 2.3 compat. in mako.pyparser [ticket:90]
+
+- fix Babel 0.9.3 compatibility; stripping comment tags is now
+ optional (and enabled by default).
+
+
+0.2.2
+- cached blocks now use the current context when rendering
+an expired section, instead of the original context
+passed in [ticket:87]
+- fixed a critical issue regarding caching, whereby
+a cached block would raise an error when called within a
+cache-refresh operation that was initiated after the
+initiating template had completed rendering.
+
+0.2.1
+- fixed bug where 'output_encoding' parameter would prevent
+render_unicode() from returning a unicode object.
+- bumped magic number, which forces template recompile for
+this version (fixes incompatible compile symbols from 0.1
+series).
+- added a few docs for cache options, specifically those that
+help with memcached.
+
+0.2.0
+- Speed improvements (as though we needed them, but people
+ contributed and there you go):
+
+ - added "bytestring passthru" mode, via
+ `disable_unicode=True` argument passed to Template or
+ TemplateLookup. All unicode-awareness and filtering is
+ turned off, and template modules are generated with
+ the appropriate magic encoding comment. In this mode,
+ template expressions can only receive raw bytestrings
+ or Unicode objects which represent straight ASCII, and
+ render_unicode() may not be used if multibyte
+ characters are present. When enabled, speed
+ improvement around 10-20%. [ticket:77] (courtesy
+ anonymous guest)
+
+ - inlined the "write" function of Context into a local
+ 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}
+
+ 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}"/>
+ [ticket:78]
+
+ - some functions on Context are now private:
+ _push_buffer(), _pop_buffer(),
+ caller_stack._push_frame(), caller_stack._pop_frame().
+
+ - added a runner script "mako-render" which renders
+ standard input as a template to stdout [ticket:81]
+ [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]
+
+ - fixed codegen bug which occured when using <%page>
+ level caching, combined with an expression-based
+ cache_key, combined with the usage of <%namespace
+ import="*"/> - fixed lexer exceptions not cleaning up
+ temporary files, which could lead to a maximum number
+ of file descriptors used in the process [ticket:69]
+
+ - 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]
+
+0.1.10
+- fixed propagation of 'caller' such that nested %def calls
+ within a <%call> tag's argument list propigates 'caller'
+ to the %call function itself (propigates to the inner
+ calls too, this is a slight side effect which previously
+ existed anyway)
+- fixed bug where local.get_namespace() could put an
+ incorrect "self" in the current context
+- fixed another namespace bug where the namespace functions
+ did not have access to the correct context containing
+ their 'self' and 'parent'
+
+0.1.9
+- filters.Decode filter can also accept a non-basestring
+object and will call str() + unicode() on it [ticket:47]
+- comments can be placed at the end of control lines,
+i.e. if foo: # a comment, [ticket:53], thanks to
+Paul Colomiets
+- fixed expressions and page tag arguments and with embedded
+newlines in CRLF templates, follow up to [ticket:16], thanks
+Eric Woroshow
+- added an IOError catch for source file not found in RichTraceback
+exception reporter [ticket:51]
+
+0.1.8
+- variable names declared in render methods by internal
+codegen prefixed by "__M_" to prevent name collisions
+with user code
+- added a Babel (http://babel.edgewall.org/) extractor entry
+point, allowing extraction of gettext messages directly from
+mako templates via Babel [ticket:45]
+- fix to turbogears plugin to work with dot-separated names
+(i.e. load_template('foo.bar')). also takes file extension
+as a keyword argument (default is 'mak').
+- more tg fix: fixed [ticket:35], allowing string-based
+templates with tgplugin even if non-compatible args were sent
+
+0.1.7
+- one small fix to the unit tests to support python 2.3
+- a slight hack to how cache.py detects Beaker's memcached,
+works around unexplained import behavior observed on some
+python 2.3 installations
+
+0.1.6
+- caching is now supplied directly by Beaker, which has
+ all of MyghtyUtils merged into it now. The latest Beaker
+ (0.7.1) also fixes a bug related to how Mako was using the
+ cache API.
+- fix to module_directory path generation when the path is "./"
+ [ticket:34]
+- TGPlugin passes options to string-based templates [ticket:35]
+- added an explicit stack frame step to template runtime, which
+ allows much simpler and hopefully bug-free tracking of 'caller',
+ fixes #28
+- if plain Python defs are used with <%call>, a decorator
+ @runtime.supports_callable exists to ensure that the "caller"
+ stack is properly handled for the def.
+- fix to RichTraceback and exception reporting to get template
+ source code as a unicode object #37
+- html_error_template includes options "full=True", "css=True"
+ which control generation of HTML tags, CSS [ticket:39]
+- added the 'encoding_errors' parameter to Template/TemplateLookup
+ for specifying the error handler associated with encoding to
+ 'output_encoding' [ticket:40]
+- the Template returned by html_error_template now defaults to
+ output_encoding=sys.getdefaultencoding(),
+ encoding_errors='htmlentityreplace' [ticket:37]
+- control lines, i.e. % lines, support backslashes to continue long
+ 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]
+- AST parsing, properly detects imports of the form "import foo.bar"
+ [ticket:27]
+- fix to lexing of <%docs> tag nested in other tags
+- fix to context-arguments inside of <%include> tag which broke
+during 0.1.4 [ticket:29]
+- added "n" filter, disables *all* filters normally applied to an expression
+via <%page> or default_filters (but not those within the filter)
+- added buffer_filters argument, defines filters applied to the return value
+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
+ may contain quote characters [ticket:23]
+- fix to variable scoping for identifiers only referenced within
+ functions
+- added a path normalization step to lookup so URIs like
+ "/foo/bar/../etc/../foo" pre-process the ".." tokens before checking
+ the filesystem
+- fixed/improved "caller" semantics so that undefined caller is
+ "UNDEFINED", propigates __nonzero__ method so it evaulates to False if
+ not present, True otherwise. this way you can say % if caller:\n
+ ${caller.body()}\n% endif
+- <%include> has an "args" attribute that can pass arguments to the
+ called template (keyword arguments only, must be declared in that
+ page's <%page> tag.)
+- <%include> plus arguments is also programmatically available via
+ self.include_file(<filename>, **kwargs)
+- further escaping added for multibyte expressions in %def, %call
+ attributes [ticket:24]
+
+
+0.1.3
+- ***Small Syntax Change*** - the single line comment character is now
+*two* hash signs, i.e. "## this is a comment". This avoids a common
+collection with CSS selectors.
+- the magic "coding" comment (i.e. # coding:utf-8) will still work with
+either one "#" sign or two for now; two is preferred going forward, i.e.
+## coding:<someencoding>.
+- new multiline comment form: "<%doc> a comment </%doc>"
+- UNDEFINED evaluates to False
+- improvement to scoping of "caller" variable when using <%call> tag
+- added lexer error for unclosed control-line (%) line
+- added "preprocessor" argument to Template, TemplateLookup - is a single
+ callable or list of callables which will be applied to the template text
+ before lexing. given the text as an argument, returns the new text.
+- 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
+ encoding, are expanded into backslash-escaped glyphs before being AST
+ parsed [ticket:11]
+- all template lexing converts the template to unicode first, to
+ immediately catch any encoding issues and ensure internal unicode
+ representation.
+- added module_filename argument to Template to allow specification of a
+ specific module file
+- added modulename_callable to TemplateLookup to allow a function to
+ determine module filenames (takes filename, uri arguments). used for
+ [ticket:14]
+- added optional input_encoding flag to Template, to allow sending a
+ unicode() object with no magic encoding comment
+- "expression_filter" argument in <%page> applies only to expressions
+- added "default_filters" argument to Template, TemplateLookup. applies only
+ to expressions, gets prepended to "expression_filter" arg from <%page>.
+ defaults to ["unicode"], so that all expressions get stringified into u''
+ by default (this is what Mako already does). By setting to [], expressions
+ are passed through raw.
+- added "imports" argument to Template, TemplateLookup. so you can predefine
+ a list of import statements at the top of the template. can be used in
+ conjunction with default_filters.
+- support for CRLF templates...whoops ! welcome to all the windows users.
+ [ticket:16]
+- small fix to local variable propigation for locals that are conditionally
+ declared
+- got "top level" def calls to work, i.e. template.get_def("somedef").render()
+
+0.1.1
+- buffet plugin supports string-based templates, allows ToscaWidgets to work
+ [ticket:8]
+- AST parsing fixes: fixed TryExcept identifier parsing
+- removed textmate tmbundle from contrib and into separate SVN location;
+ windows users cant handle those files, setuptools not very good at
+ "pruning" certain directories
+- fix so that "cache_timeout" parameter is propigated
+- fix to expression filters so that string conversion (actually unicode)
+ properly occurs before filtering
+- better error message when a lookup is attempted with a template that has no
+ lookup
+- implemented "module" attribute for namespace
+- fix to code generation to correctly track multiple defs with the same name
+- "directories" can be passed to TemplateLookup as a scalar in which case it
+ gets converted to a list [ticket:9]
+
+0.1.0
+
+Initial release.
Added: pypy/benchmarks/lib/mako/LICENSE
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/LICENSE Tue Dec 21 07:44:16 2010
@@ -0,0 +1,20 @@
+This is the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer and contributors.
+Mako is a trademark of Michael Bayer.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or
+substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
Added: pypy/benchmarks/lib/mako/MANIFEST.in
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/MANIFEST.in Tue Dec 21 07:44:16 2010
@@ -0,0 +1,12 @@
+# any kind of "*" pulls in __init__.pyc files,
+# so all extensions are explicit.
+
+recursive-include doc *.html *.css *.txt *.js *.jpg *.png *.py Makefile *.rst *.mako *.sty autohandler
+recursive-include examples *.py *.xml *.mako *.myt *.kid *.tmpl
+recursive-include test *.py *.dat *.html *.mako
+
+include README* LICENSE distribute_setup.py ez_setup.py CHANGES*
+
+# when we go to sphinx
+#prune doc/build/output
+
Added: pypy/benchmarks/lib/mako/README
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/README Tue Dec 21 07:44:16 2010
@@ -0,0 +1,25 @@
+Mako is licensed under an MIT-style license (see LICENSE).
+Other incorporated projects may be licensed under different licenses.
+All licenses allow for non-commercial and commercial use.
+
+To install:
+
+ python setup.py install
+
+SVN checkouts also inlcude setup.cfg file allowing setuptools to create
+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
+
+For Python 3 information, see README.py3k.
+
+good luck !
+
Added: pypy/benchmarks/lib/mako/README.py3k
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/README.py3k Tue Dec 21 07:44:16 2010
@@ -0,0 +1,56 @@
+=================
+PYTHON 3 SUPPORT
+=================
+
+Python 3 support in Mako is provided by the Python 2to3 script.
+
+Installing Distribute
+---------------------
+
+Distribute should be installed with the Python3 installation. The
+distribute bootloader is included.
+
+Running as a user with permission to modify the Python distribution,
+install Distribute:
+
+ python3 distribute_setup.py
+
+Installing Mako in Python 3
+---------------------------------
+
+Once Distribute is installed, Mako can be installed directly.
+The 2to3 process will kick in which takes several minutes:
+
+ python3 setup.py install
+
+Converting Tests, Examples, Source to Python 3
+----------------------------------------------
+
+To convert all files in the source distribution, run
+the 2to3 script:
+
+ 2to3 -w mako test
+
+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
+-------------
+
+To run the unit tests, ensure Distribute is installed as above,
+and also that at least the ./mako/ and ./test/ directories have been converted
+to Python 3 using the source tool above. A Python 3 version of Nose
+can be acquired from Bitbucket using Mercurial:
+
+ hg clone http://bitbucket.org/jpellerin/nose3/
+ cd nose3
+ python3 setup.py install
+
+The tests can then be run using the "nosetests3" script installed
+by the above (python3 setup.py test doesn't seem to be working with
+nose3).
+
Added: pypy/benchmarks/lib/mako/distribute_setup.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/distribute_setup.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,485 @@
+#!python
+"""Bootstrap distribute installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from distribute_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import sys
+import time
+import fnmatch
+import tempfile
+import tarfile
+from distutils import log
+
+try:
+ from site import USER_SITE
+except ImportError:
+ USER_SITE = None
+
+try:
+ import subprocess
+
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ return subprocess.call(args) == 0
+
+except ImportError:
+ # will be used for python 2.3
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ # quoting arguments if windows
+ if sys.platform == 'win32':
+ def quote(arg):
+ if ' ' in arg:
+ return '"%s"' % arg
+ return arg
+ args = [quote(arg) for arg in args]
+ return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
+
+DEFAULT_VERSION = "0.6.13"
+DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
+SETUPTOOLS_FAKED_VERSION = "0.6c11"
+
+SETUPTOOLS_PKG_INFO = """\
+Metadata-Version: 1.0
+Name: setuptools
+Version: %s
+Summary: xxxx
+Home-page: xxx
+Author: xxx
+Author-email: xxx
+License: xxx
+Description: xxx
+""" % SETUPTOOLS_FAKED_VERSION
+
+
+def _install(tarball):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # installing
+ log.warn('Installing Distribute')
+ if not _python_cmd('setup.py', 'install'):
+ log.warn('Something went wrong during the installation.')
+ log.warn('See the error message above.')
+ finally:
+ os.chdir(old_wd)
+
+
+def _build_egg(egg, tarball, to_dir):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # building an egg
+ log.warn('Building a Distribute egg in %s', to_dir)
+ _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+ finally:
+ os.chdir(old_wd)
+ # returning the result
+ log.warn(egg)
+ if not os.path.exists(egg):
+ raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+ egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
+ % (version, sys.version_info[0], sys.version_info[1]))
+ if not os.path.exists(egg):
+ tarball = download_setuptools(version, download_base,
+ to_dir, download_delay)
+ _build_egg(egg, tarball, to_dir)
+ sys.path.insert(0, egg)
+ import setuptools
+ setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, download_delay=15, no_fake=True):
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ was_imported = 'pkg_resources' in sys.modules or \
+ 'setuptools' in sys.modules
+ try:
+ try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ if not no_fake:
+ _fake_setuptools()
+ raise ImportError
+ except ImportError:
+ return _do_download(version, download_base, to_dir, download_delay)
+ try:
+ pkg_resources.require("distribute>="+version)
+ return
+ except pkg_resources.VersionConflict:
+ e = sys.exc_info()[1]
+ if was_imported:
+ sys.stderr.write(
+ "The required version of distribute (>=%s) is not available,\n"
+ "and can't be installed while this script is running. Please\n"
+ "install a more recent version first, using\n"
+ "'easy_install -U distribute'."
+ "\n\n(Currently using %r)\n" % (version, e.args[0]))
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ except pkg_resources.DistributionNotFound:
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ finally:
+ if not no_fake:
+ _create_fake_setuptools_pkg_info(to_dir)
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, delay=15):
+ """Download distribute from a specified location and return its filename
+
+ `version` should be a valid distribute version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download
+ attempt.
+ """
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+ tgz_name = "distribute-%s.tar.gz" % version
+ url = download_base + tgz_name
+ saveto = os.path.join(to_dir, tgz_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ log.warn("Downloading %s", url)
+ src = urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = src.read()
+ dst = open(saveto, "wb")
+ dst.write(data)
+ finally:
+ if src:
+ src.close()
+ if dst:
+ dst.close()
+ return os.path.realpath(saveto)
+
+def _no_sandbox(function):
+ def __no_sandbox(*args, **kw):
+ try:
+ from setuptools.sandbox import DirectorySandbox
+ if not hasattr(DirectorySandbox, '_old'):
+ def violation(*args):
+ pass
+ DirectorySandbox._old = DirectorySandbox._violation
+ DirectorySandbox._violation = violation
+ patched = True
+ else:
+ patched = False
+ except ImportError:
+ patched = False
+
+ try:
+ return function(*args, **kw)
+ finally:
+ if patched:
+ DirectorySandbox._violation = DirectorySandbox._old
+ del DirectorySandbox._old
+
+ return __no_sandbox
+
+def _patch_file(path, content):
+ """Will backup the file then patch it"""
+ existing_content = open(path).read()
+ if existing_content == content:
+ # already patched
+ log.warn('Already patched.')
+ return False
+ log.warn('Patching...')
+ _rename_path(path)
+ f = open(path, 'w')
+ try:
+ f.write(content)
+ finally:
+ f.close()
+ return True
+
+_patch_file = _no_sandbox(_patch_file)
+
+def _same_content(path, content):
+ return open(path).read() == content
+
+def _rename_path(path):
+ new_name = path + '.OLD.%s' % time.time()
+ log.warn('Renaming %s into %s', path, new_name)
+ os.rename(path, new_name)
+ return new_name
+
+def _remove_flat_installation(placeholder):
+ if not os.path.isdir(placeholder):
+ log.warn('Unkown installation at %s', placeholder)
+ return False
+ found = False
+ for file in os.listdir(placeholder):
+ if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
+ found = True
+ break
+ if not found:
+ log.warn('Could not locate setuptools*.egg-info')
+ return
+
+ log.warn('Removing elements out of the way...')
+ pkg_info = os.path.join(placeholder, file)
+ if os.path.isdir(pkg_info):
+ patched = _patch_egg_dir(pkg_info)
+ else:
+ patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
+
+ if not patched:
+ log.warn('%s already patched.', pkg_info)
+ return False
+ # now let's move the files out of the way
+ for element in ('setuptools', 'pkg_resources.py', 'site.py'):
+ element = os.path.join(placeholder, element)
+ if os.path.exists(element):
+ _rename_path(element)
+ else:
+ log.warn('Could not find the %s element of the '
+ 'Setuptools distribution', element)
+ return True
+
+_remove_flat_installation = _no_sandbox(_remove_flat_installation)
+
+def _after_install(dist):
+ log.warn('After install bootstrap.')
+ placeholder = dist.get_command_obj('install').install_purelib
+ _create_fake_setuptools_pkg_info(placeholder)
+
+def _create_fake_setuptools_pkg_info(placeholder):
+ if not placeholder or not os.path.exists(placeholder):
+ log.warn('Could not find the install location')
+ return
+ pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
+ setuptools_file = 'setuptools-%s-py%s.egg-info' % \
+ (SETUPTOOLS_FAKED_VERSION, pyver)
+ pkg_info = os.path.join(placeholder, setuptools_file)
+ if os.path.exists(pkg_info):
+ log.warn('%s already exists', pkg_info)
+ return
+
+ log.warn('Creating %s', pkg_info)
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+
+ pth_file = os.path.join(placeholder, 'setuptools.pth')
+ log.warn('Creating %s', pth_file)
+ f = open(pth_file, 'w')
+ try:
+ f.write(os.path.join(os.curdir, setuptools_file))
+ finally:
+ f.close()
+
+_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
+
+def _patch_egg_dir(path):
+ # let's check if it's already patched
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ if os.path.exists(pkg_info):
+ if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
+ log.warn('%s already patched.', pkg_info)
+ return False
+ _rename_path(path)
+ os.mkdir(path)
+ os.mkdir(os.path.join(path, 'EGG-INFO'))
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+ return True
+
+_patch_egg_dir = _no_sandbox(_patch_egg_dir)
+
+def _before_install():
+ log.warn('Before install bootstrap.')
+ _fake_setuptools()
+
+
+def _under_prefix(location):
+ if 'install' not in sys.argv:
+ return True
+ args = sys.argv[sys.argv.index('install')+1:]
+ for index, arg in enumerate(args):
+ for option in ('--root', '--prefix'):
+ if arg.startswith('%s=' % option):
+ top_dir = arg.split('root=')[-1]
+ return location.startswith(top_dir)
+ elif arg == option:
+ if len(args) > index:
+ top_dir = args[index+1]
+ return location.startswith(top_dir)
+ if arg == '--user' and USER_SITE is not None:
+ return location.startswith(USER_SITE)
+ return True
+
+
+def _fake_setuptools():
+ log.warn('Scanning installed packages')
+ try:
+ import pkg_resources
+ except ImportError:
+ # we're cool
+ log.warn('Setuptools or Distribute does not seem to be installed.')
+ return
+ ws = pkg_resources.working_set
+ try:
+ setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
+ replacement=False))
+ except TypeError:
+ # old distribute API
+ setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
+
+ if setuptools_dist is None:
+ log.warn('No setuptools distribution found')
+ return
+ # detecting if it was already faked
+ setuptools_location = setuptools_dist.location
+ log.warn('Setuptools installation detected at %s', setuptools_location)
+
+ # if --root or --preix was provided, and if
+ # setuptools is not located in them, we don't patch it
+ if not _under_prefix(setuptools_location):
+ log.warn('Not patching, --root or --prefix is installing Distribute'
+ ' in another location')
+ return
+
+ # let's see if its an egg
+ if not setuptools_location.endswith('.egg'):
+ log.warn('Non-egg installation')
+ res = _remove_flat_installation(setuptools_location)
+ if not res:
+ return
+ else:
+ log.warn('Egg installation')
+ pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
+ if (os.path.exists(pkg_info) and
+ _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
+ log.warn('Already patched.')
+ return
+ log.warn('Patching...')
+ # let's create a fake egg replacing setuptools one
+ res = _patch_egg_dir(setuptools_location)
+ if not res:
+ return
+ log.warn('Patched done.')
+ _relaunch()
+
+
+def _relaunch():
+ log.warn('Relaunching...')
+ # we have to relaunch the process
+ # pip marker to avoid a relaunch bug
+ if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
+ sys.argv[0] = 'setup.py'
+ args = [sys.executable] + sys.argv
+ sys.exit(subprocess.call(args))
+
+
+def _extractall(self, path=".", members=None):
+ """Extract all members from the archive to the current working
+ directory and set owner, modification time and permissions on
+ directories afterwards. `path' specifies a different directory
+ to extract to. `members' is optional and must be a subset of the
+ list returned by getmembers().
+ """
+ import copy
+ import operator
+ from tarfile import ExtractError
+ directories = []
+
+ if members is None:
+ members = self
+
+ for tarinfo in members:
+ if tarinfo.isdir():
+ # Extract directories with a safe mode.
+ directories.append(tarinfo)
+ tarinfo = copy.copy(tarinfo)
+ tarinfo.mode = 448 # decimal for oct 0700
+ self.extract(tarinfo, path)
+
+ # Reverse sort directories.
+ if sys.version_info < (2, 4):
+ def sorter(dir1, dir2):
+ return cmp(dir1.name, dir2.name)
+ directories.sort(sorter)
+ directories.reverse()
+ else:
+ directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+ # Set correct owner, mtime and filemode on directories.
+ for tarinfo in directories:
+ dirpath = os.path.join(path, tarinfo.name)
+ try:
+ self.chown(tarinfo, dirpath)
+ self.utime(tarinfo, dirpath)
+ self.chmod(tarinfo, dirpath)
+ except ExtractError:
+ e = sys.exc_info()[1]
+ if self.errorlevel > 1:
+ raise
+ else:
+ self._dbg(1, "tarfile: %s" % e)
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ tarball = download_setuptools()
+ _install(tarball)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
Added: pypy/benchmarks/lib/mako/doc/build/Makefile
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/Makefile Tue Dec 21 07:44:16 2010
@@ -0,0 +1,143 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = output
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest dist-html site-mako
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dist-html same as html, but places files in /doc"
+ @echo " site-mako build Mako files for usage on the Mako site"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html -A mako_layout=html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dist-html:
+ $(SPHINXBUILD) -b html -A mako_layout=html $(ALLSPHINXOPTS) ..
+ @echo
+ @echo "Build finished. The HTML pages are in ../."
+
+site-mako:
+ $(SPHINXBUILD) -b html -A mako_layout=site $(ALLSPHINXOPTS) $(BUILDDIR)/site
+ @echo
+ @echo "Build finished. The Mako pages are in $(BUILDDIR)/site."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SQLAlchemy.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SQLAlchemy.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/SQLAlchemy"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SQLAlchemy"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ cp texinputs/* $(BUILDDIR)/latex/
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) .
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
Added: pypy/benchmarks/lib/mako/doc/build/builder/__init__.py
==============================================================================
Added: pypy/benchmarks/lib/mako/doc/build/builder/builders.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/builder/builders.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,69 @@
+from sphinx.application import TemplateBridge
+from sphinx.builders.html import StandaloneHTMLBuilder
+from sphinx.highlighting import PygmentsBridge
+from pygments import highlight
+from pygments.lexer import RegexLexer, bygroups, using
+from pygments.token import *
+from pygments.filter import Filter, apply_filters
+from pygments.lexers import PythonLexer, PythonConsoleLexer
+from pygments.formatters import HtmlFormatter, LatexFormatter
+import re
+from mako.lookup import TemplateLookup
+from mako.template import Template
+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)
+ context['nexttopic'] = context.pop('next', None)
+ context['mako_layout'] = self.layout == 'html' and 'static_base.mako' or 'site_base.mako'
+ # 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)
+ context['mako_layout'] = self.layout == 'html' and 'static_base.mako' or 'site_base.mako'
+ # sphinx 1.0b2 doesn't seem to be providing _ for some reason...
+ context.setdefault('_', lambda x:x)
+ return Template(template, lookup=self.lookup,
+ format_exceptions=True,
+ imports=[
+ "from builder import util"
+ ]
+ ).render_unicode(**context)
+
+class StripDocTestFilter(Filter):
+ def filter(self, lexer, stream):
+ for ttype, value in stream:
+ if ttype is Token.Comment and re.match(r'#\s*doctest:', value):
+ continue
+ yield ttype, value
+
+
+def autodoc_skip_member(app, what, name, obj, skip, options):
+ if what == 'class' and skip and name == '__init__':
+ return False
+ else:
+ return skip
+
+def setup(app):
+# app.connect('autodoc-skip-member', autodoc_skip_member)
+ # 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
Added: pypy/benchmarks/lib/mako/doc/build/builder/util.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/builder/util.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,12 @@
+import re
+
+def striptags(text):
+ return re.compile(r'<[^>]*>').sub('', 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)
+
Added: pypy/benchmarks/lib/mako/doc/build/caching.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/caching.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,127 @@
+.. _caching_toplevel:
+
+========
+Caching
+========
+
+Any template or component can be cached using the ``cache``
+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`
+method will return content directly from the cache. When the
+:class:`.Template` object itself falls out of scope, its corresponding
+cache is garbage collected along with the template.
+
+Caching requires that the ``beaker`` package be installed on the
+system.
+
+The caching flag and all its options can be used with the
+``<%def>`` tag.
+
+.. sourcecode:: mako
+
+ <%def name="mycomp" cached="True" cache_timeout="30" cache_type="memory">
+ other text
+ </%def>
+
+Cache arguments
+================
+
+The various cache arguments are cascaded from their default
+values, to the arguments specified programmatically to the
+:class:`.Template` or its originating :class:`.TemplateLookup`, then to those
+defined in the ``<%page>`` tag of an individual template, and
+finally to an individual ``<%def>`` tag within the template. This
+means you can define, for example, a cache type of ``dbm`` on your
+:class:`.TemplateLookup`, a cache timeout of 60 seconds in a particular
+template's ``<%page>`` tag, and within one of that template's
+``<%def>`` tags ``cache=True``, and that one particular def will
+then cache its data using a ``dbm`` cache and a data timeout of 60
+seconds.
+
+The options available are:
+
+* ``cached="False|True"`` - turn caching on
+* ``cache_timeout`` - number of seconds in which to invalidate the
+ cached data. after this timeout, the content is re-generated
+ on the next call.
+* ``cache_type`` - type of caching. ``memory``, ``file``, ``dbm``, or
+ ``memcached``.
+* ``cache_url`` - (only used for ``memcached`` but required) a single
+ IP address or a semi-colon separated list of IP address of
+ memcache servers to use.
+* ``cache_dir`` - In the case of the ``file`` and ``dbm`` cache types,
+ this is the filesystem directory with which to store data
+ files. If this option is not present, the value of
+ ``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
+ in the cache. the total namespace of keys within the cache is
+ local to the current template, and the default value of "key"
+ is the name of the def which is storing its data. It is an
+ evaluable tag, so you can put a Python expression to calculate
+ 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
+===================
+
+The :class:`.Template`, as well as any template-derived namespace, has
+an accessor called ``cache`` which returns the ``Cache`` object
+for that template. This object is a facade on top of the Beaker
+internal cache object, and provides some very rudimental
+capabilities, such as the ability to get and put arbitrary
+values:
+
+.. sourcecode:: mako
+
+ <%
+ 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.
+
+More commonly the ``cache`` object is used to invalidate cached
+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
+==============
+
+.. autoclass:: mako.cache.Cache
+ :members:
+ :show-inheritance:
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/doc/build/conf.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/conf.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,280 @@
+# -*- coding: utf-8 -*-
+#
+# Mako documentation build configuration file
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('../..'))
+sys.path.insert(0, os.path.abspath('.'))
+
+import mako
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode',
+# 'sphinx.ext.doctest', 'builder.builders']
+
+extensions = ['sphinx.ext.autodoc',
+ 'sphinx.ext.doctest', 'builder.builders']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['templates']
+
+nitpicky = True
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+template_bridge = "builder.builders.MakoBridge"
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Mako'
+copyright = u'the Mako authors and contributors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = mako.__version__
+# The full version, including alpha/beta/rc tags.
+release = mako.__version__
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "%s %s Documentation" % (project, release)
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%m/%d/%Y %H:%M:%S'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_domain_indices = False
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Makodoc'
+
+#autoclass_content = 'both'
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'mako_%s.tex' % release.replace('.', '_'), ur'Mako Documentation',
+ ur'Mike Bayer', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+# sets TOC depth to 2.
+latex_preamble = '\setcounter{tocdepth}{3}'
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+#latex_elements = {
+# 'papersize': 'letterpaper',
+# 'pointsize': '10pt',
+#}
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'mako', u'Mako Documentation',
+ [u'Mako authors'], 1)
+]
+
+
+# -- Options for Epub output ---------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'Mako'
+epub_author = u'Mako authors'
+epub_publisher = u'Mako authors'
+epub_copyright = u'Mako authors'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+#epub_exclude_files = []
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
Added: pypy/benchmarks/lib/mako/doc/build/defs.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/defs.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,436 @@
+.. _defs_toplevel:
+
+====
+Defs
+====
+
+``<%def>`` is the single tag used to demarcate any block of text
+and/or code. It exists within generated Python as a callable
+function:
+
+.. sourcecode:: mako
+
+ <%def name="hello()">
+ hello world
+ </%def>
+
+They are normally called as expressions:
+
+.. sourcecode:: mako
+
+ the def: ${hello()}
+
+If the ``<%def>`` is not nested inside of another ``<%def>``,
+its known as a **top level def** and can be accessed anywhere in
+the template, including above where it was defined.
+
+All defs, top level or not, have access to the current
+contextual namespace in exactly the same way their containing
+template does. Suppose the template below is executed with the
+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
+ </%def>
+
+The ``username`` and ``accountdata`` variables are present
+within the main template body as well as the body of the
+``account()`` def.
+
+Since defs are just Python functions, you can define and pass
+arguments to them as well:
+
+.. sourcecode:: mako
+
+ ${account(accountname='john')}
+
+ <%def name="account(accountname, type='regular')">
+ account name: ${accountname}, type ${type}
+ </%def>
+
+When you declare an argument signature for your def, they are
+required to follow normal Python conventions (i.e., all
+arguments are required except keyword arguments with a default
+value). This is in contrast to using context-level variables,
+which evaluate to ``UNDEFINED`` if you reference a name that
+does not exist.
+
+Calling defs from Other Files
+==============================
+
+Top level ``<%defs>`` are **exported** by your template's
+module, and can be called from the outside; including from other
+templates, as well as normal Python code. Calling a ``<%def>``
+from another template is something like using an ``<%include>``
+- except you are calling a specific function within the
+template, not the whole template.
+
+The remote ``<%def>`` call is also a little bit like calling
+functions from other modules in Python. There is an "import"
+step to pull the names from another template into your own
+template; then the function or functions are available.
+
+To import another template, use the ``<%namespace>`` tag:
+
+.. sourcecode:: mako
+
+ <%namespace name="mystuff" file="mystuff.html"/>
+
+The above tag adds a local variable "mystuff" to the current
+scope.
+
+Then, just call the defs off of ``mystuff``:
+
+.. sourcecode:: mako
+
+ ${mystuff.somedef(x=5,y=7)}
+
+The ``<%namespace>`` tag also supports some of the other
+semantics of Python's ``import`` statement, including pulling
+names into the local variable space, or using ``*`` to represent
+all names, using the ``import`` attribute:
+
+.. sourcecode:: mako
+
+ <%namespace file="mystuff.html" import="foo, bar"/>
+
+This is just a quick intro to the concept of a **namespace**,
+which is a central Mako concept that has its own chapter in
+these docs. For more detail and examples, see
+:ref:`namespaces_toplevel`.
+
+Calling defs programmatically
+==============================
+
+You can call def's programmatically from any :class:`.Template` object
+using the :meth:`~.Template.get_def()` method, which returns a :class:`.DefTemplate`
+object. This is a :class:`.Template` subclass which the parent
+:class:`.Template` creates, and is usable like any other template:
+
+.. 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
+================
+
+The def model follows regular Python rules for closures.
+Declaring ``<%def>`` inside another ``<%def>`` declares it
+within the parent's **enclosing scope**:
+
+.. sourcecode:: mako
+
+ <%def name="mydef()">
+ <%def name="subdef()">
+ a sub def
+ </%def>
+
+ im the def, and the subcomponent is ${subdef()}
+ </%def>
+
+Just like Python, names that exist outside the inner ``<%def>``
+exist inside it as well:
+
+.. sourcecode:: mako
+
+ <%
+ x = 12
+ %>
+ <%def name="outer()">
+ <%
+ y = 15
+ %>
+ <%def name="inner()">
+ inner, x is ${x}, y is ${y}
+ </%def>
+
+ outer, x is ${x}, y is ${y}
+ </%def>
+
+Assigning to a name inside of a def declares that name as local
+to the scope of that def (again, like Python itself). This means
+the following code will raise an error:
+
+.. sourcecode:: mako
+
+ <%
+ x = 10
+ %>
+ <%def name="somedef()">
+ ## error !
+ somedef, x is ${x}
+ <%
+ x = 27
+ %>
+ </%def>
+
+...because the assignment to ``x`` declares x as local to the
+scope of ``somedef``, rendering the "outer" version unreachable
+in the expression that tries to render it.
+
+.. _defs_with_content:
+
+Calling a def with embedded content and/or other defs
+=====================================================
+
+A flip-side to def within def is a def call with content. This
+is where you call a def, and at the same time declare a block of
+content (or multiple blocks) that can be used by the def being
+called. The main point of such a call is to create custom,
+nestable tags, just like any other template language's
+custom-tag creation system - where the external tag controls the
+execution of the nested tags and can communicate state to them.
+Only with Mako, you don't have to use any external Python
+modules, you can define arbitrarily nestable tags right in your
+templates.
+
+To achieve this, the target def is invoked using the form
+``<%namepacename:defname>`` instead of the normal ``${}``
+syntax. This syntax, introduced in Mako 0.2.3, is functionally
+equivalent another tag known as ``call``, which takes the form
+``<%call expr='namespacename.defname(args)'>``. While ``%call``
+is available in all versions of Mako, the newer style is
+probably more familiar looking. The ``namespace`` portion of the
+call is the name of the **namespace** in which the def is
+defined - in the most simple cases, this can be ``local`` or
+``self`` to reference the current template's namespace (the
+difference between ``local`` and ``self`` is one of inheritance
+- see :ref:`namespaces_builtin` for details).
+
+When the target def is invoked, a variable ``caller`` is placed
+in its context which contains another namespace containing the
+body and other defs defined by the caller. The body itself is
+referenced by the method ``body()``. Below, we build a ``%def``
+that operates upon ``caller.body()`` to invoke the body of the
+custom tag:
+
+.. sourcecode:: mako
+
+ <%def name="buildtable()">
+ <table>
+ <tr><td>
+ ${caller.body()}
+ </td></tr>
+ </table>
+ </%def>
+
+ <%self:buildtable>
+ I am the table body.
+ </%self:buildtable>
+
+This produces the output (whitespace formatted):
+
+.. sourcecode:: html
+
+ <table>
+ <tr><td>
+ I am the table body.
+ </td></tr>
+ </table>
+
+Using the older ``%call`` syntax looks like:
+
+.. sourcecode:: mako
+
+ <%def name="buildtable()">
+ <table>
+ <tr><td>
+ ${caller.body()}
+ </td></tr>
+ </table>
+ </%def>
+
+ <%call expr="buildtable()">
+ I am the table body.
+ </%call>
+
+The ``body()`` can be executed multiple times or not at all.
+This means you can use def-call-with-content to build iterators,
+conditionals, etc:
+
+.. sourcecode:: mako
+
+ <%def name="lister(count)">
+ % for x in range(count):
+ ${caller.body()}
+ % endfor
+ </%def>
+
+ <%self:lister count="${3}">
+ hi
+ </%self:lister>
+
+Produces:
+
+.. sourcecode:: html
+
+ hi
+ hi
+ hi
+
+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)">
+ % if expression:
+ ${caller.body()}
+ % endif
+ </%def>
+
+ <%self:conditional expression="${4==4}">
+ im the result
+ </%self:conditional>
+
+Produces:
+
+.. sourcecode:: html
+
+ im the result
+
+But that's not all. The ``body()`` function also can handle
+arguments, which will augment the local namespace of the body
+callable. The caller must define the arguments which it expects
+to receive from its target def using the ``args`` attribute,
+which is a comma-separated list of argument names. Below, our
+``<%def>`` calls the ``body()`` of its caller, passing in an
+element of data from its argument:
+
+.. sourcecode:: mako
+
+ <%def name="layoutdata(somedata)">
+ <table>
+ % for item in somedata:
+ <tr>
+ % for col in item:
+ <td>${caller.body(col=col)}</td>
+ % endfor
+ </tr>
+ % endfor
+ </table>
+ </%def>
+
+ <%self:layoutdata somedata="${[[1,2,3],[4,5,6],[7,8,9]]}" args="col">\
+ Body data: ${col}\
+ </%self:layoutdata>
+
+Produces:
+
+.. sourcecode:: html
+
+ <table>
+ <tr>
+ <td>Body data: 1</td>
+ <td>Body data: 2</td>
+ <td>Body data: 3</td>
+ </tr>
+ <tr>
+ <td>Body data: 4</td>
+ <td>Body data: 5</td>
+ <td>Body data: 6</td>
+ </tr>
+ <tr>
+ <td>Body data: 7</td>
+ <td>Body data: 8</td>
+ <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:
+
+.. sourcecode:: mako
+
+ <%def name="layout()">
+ ## a layout def
+ <div class="mainlayout">
+ <div class="header">
+ ${caller.header()}
+ </div>
+ <div class="sidebar">
+ ${caller.sidebar()}
+ </div>
+ <div class="content">
+ ${caller.body()}
+ </div>
+ </div>
+ </%def>
+
+ ## calls the layout def
+ <%self:layout>
+ <%def name="header()">
+ I am the header
+ </%def>
+ <%def name="sidebar()">
+ <ul>
+ <li>sidebar 1</li>
+ <li>sidebar 2</li>
+ </ul>
+ </%def>
+
+ this is the body
+ </%self:layout>
+
+The above layout would produce:
+
+.. sourcecode:: html
+
+ <div class="mainlayout">
+ <div class="header">
+ I am the header
+ </div>
+
+ <div class="sidebar">
+ <ul>
+ <li>sidebar 1</li>
+ <li>sidebar 2</li>
+ </ul>
+ </div>
+
+ <div class="content">
+ this is the body
+ </div>
+ </div>
+
+The number of things you can do with ``<%call>`` and/or the
+``<%namespacename:defname>`` calling syntax is enormous. You can
+create form widget libraries, such as an enclosing ``<FORM>``
+tag and nested HTML input elements, or portable wrapping schemes
+using ``<div>`` or other elements. You can create tags that
+interpret rows of data, such as from a database, providing the
+individual columns of each row to a ``body()`` callable which
+lays out the row any way it wants. Basically anything you'd do
+with a "custom tag" or tag library in some other system, Mako
+provides via ``<%def>`` tags and plain Python callables which are
+invoked via ``<%namespacename:defname>`` or ``<%call>``.
+
+
+
Added: pypy/benchmarks/lib/mako/doc/build/filtering.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/filtering.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,340 @@
+.. _filtering_toplevel:
+
+=======================
+Filtering and Buffering
+=======================
+
+Expression Filtering
+=====================
+
+As described in the chapter :ref:`syntax_toplevel`, the "``|``" operator can be
+applied to a "``${}``" expression to apply escape filters to the
+output:
+
+.. sourcecode:: mako
+
+ ${"this is some text" | u}
+
+The above expression applies URL escaping to the expression, and
+produces ``this+is+some+text``.
+
+The built-in escape flags are:
+
+* ``u`` : URL escaping, provided by
+ ``urllib.quote_plus(string.encode('utf-8'))``
+* ``h`` : HTML escaping, provided by
+ ``markupsafe.escape(string)`` (new as of 0.3.4 - prior
+ versions use ``cgi.escape(string, True)``)
+* ``x`` : XML escaping
+* ``trim`` : whitespace trimming, provided by ``string.strip()``
+* ``entity`` : produces HTML entity references for applicable
+ strings, derived from ``htmlentitydefs``
+* ``unicode`` (``str`` on Python 3): produces a Python unicode
+ string (this function is applied by default).
+* ``decode.<some encoding>`` : decode input into a Python
+ unicode with the specified encoding
+* ``n`` : disable all default filtering; only filters specified
+ in the local expression tag will be applied.
+
+To apply more than one filter, separate them by a comma:
+
+.. sourcecode:: mako
+
+ ${" <tag>some value</tag> " | h,trim}
+
+The above produces ``<tag>some value</tag>``, with
+no leading or trailing whitespace. The HTML escaping function is
+applied first, the "trim" function second.
+
+Naturally, you can make your own filters too. A filter is just a
+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
+
+ <%!
+ 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
+
+ Escaped text: <html>some html</html>
+
+.. _filtering_default_filters:
+
+The default_filters Argument
+----------------------------
+
+In addition to the ``expression_filter`` argument, the
+``default_filters`` argument to both ``Template`` and
+``TemplateLookup`` can specify filtering for all expression tags
+at the programmatic level. This array-based argument, when given
+its default argument of ``None``, will be internally set to
+``["unicode"]`` (or ``["str"]`` on Python 3), except when
+``disable_unicode=True`` is set in which case it defaults to
+``["str"]``:
+
+.. sourcecode:: python
+
+ t = TemplateLookup(directories=['/tmp'], default_filters=['unicode'])
+
+To replace the usual ``unicode``/``str`` function with a
+specific encoding, the ``decode`` filter can be substituted:
+
+.. sourcecode:: python
+
+ t = TemplateLookup(directories=['/tmp'], default_filters=['decode.utf8'])
+
+To disable ``default_filters`` entirely, set it to an empty
+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
+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:
+
+.. sourcecode:: python
+
+ t = TemplateLookup(directories=['/tmp'],
+ default_filters=['unicode', 'myfilter'],
+ imports=['from mypackage import myfilter'])
+
+The above will generate templates something like this:
+
+.. sourcecode:: python
+
+ # ....
+ from mypackage import myfilter
+
+ def render_body(context):
+ context.write(myfilter(unicode("some text")))
+
+Turning off Filtering with the "n" filter
+------------------------------------------
+
+In all cases the special ``n`` filter, used locally within an
+expression, will **disable** all filters declared in the
+``<%page>`` tag as well ``default_filters``. Such as:
+
+.. sourcecode:: mako
+
+ ${'myexpression' | n}
+
+Will render ``myexpression`` with no filtering of any kind, and
+
+.. sourcecode:: mako
+
+ ${'myexpression' | n, trim}
+
+will render ``myexpression`` using the ``trim`` filter only.
+
+Filtering Defs
+=================
+
+The ``%def`` tag has a filter argument which will apply the
+given list of filter functions to the output of the ``%def``:
+
+.. sourcecode:: mako
+
+ <%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.
+
+Buffering
+==========
+
+One of Mako's central design goals is speed. To this end, all of
+the textual content within a template and its various callables
+is by default piped directly to the single buffer that is stored
+within the ``Context`` object. While this normally is easy to
+miss, it has certain side effects. The main one is that when you
+call a def using the normal expression syntax, i.e.
+``${somedef()}``, it may appear that the return value of the
+function is the content it produced, which is then delivered to
+your template just like any other expression substitution,
+except that normally, this is not the case; the return value of
+``${somedef()}`` is simply the empty string ``''``. By the time
+you receive this empty string, the output of ``somedef()`` has
+been sent to the underlying buffer.
+
+You may not want this effect, if for example you are doing
+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
+middle expression.
+
+Mako provides two ways to work around this. One is by applying
+buffering to the ``%def`` itself:
+
+.. sourcecode:: mako
+
+ <%def name="somedef()" buffered="True">
+ somedef's results
+ </%def>
+
+The above definition will generate code similar to this:
+
+.. sourcecode:: python
+
+ def somedef():
+ context.push_buffer()
+ try:
+ context.write("somedef's results")
+ 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
+apparent.
+
+Note that the ``filter`` argument on %def also causes the def to
+be buffered. This is so that the final content of the %def can
+be delivered to the escaping function in one batch, which
+reduces method calls and also produces more deterministic
+behavior for the filtering function itself, which can possibly
+be useful for a filtering function that wishes to apply a
+transformation to the text as a whole.
+
+The other way to buffer the output of a def or any Mako callable
+is by using the built-in ``capture`` function. This function
+performs an operation similar to the above buffering operation
+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
+calling the target function, after setting up a buffered
+environment. To send arguments to the function, just send them
+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
+===========
+
+This is a feature that's new as of version 0.2.5. Somewhat like
+a filter for a %def but more flexible, the ``decorator``
+argument to ``%def`` allows the creation of a function that will
+work in a similar manner to a Python decorator. The function can
+control whether or not the function executes. The original
+intent of this function is to allow the creation of custom cache
+logic, but there may be other uses as well.
+
+``decorator`` is intended to be used with a regular Python
+function, such as one defined in a library module. Here we'll
+illustrate the python function defined in the template for
+simplicities' sake:
+
+.. sourcecode:: mako
+
+ <%!
+ def bar(fn):
+ def decorate(context, *args, **kw):
+ context.write("BAR")
+ fn(*args, **kw)
+ context.write("BAR")
+ 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
+write to the context. To capture its output, use the ``capture``
+callable in the ``mako.runtime`` module (available in templates
+as just ``runtime``):
+
+.. sourcecode:: mako
+
+ <%!
+ def bar(fn):
+ def decorate(context, *args, **kw):
+ return "BAR" + runtime.capture(context, fn, *args, **kw) + "BAR"
+ return decorate
+ %>
+
+ <%def name="foo()" decorator="bar">
+ this is foo
+ </%def>
+
+ ${foo()}
+
+The decorator can be used with top-level defs as well as nested
+defs. Note that when calling a top-level def from the
+``Template`` api, i.e. ``template.get_def('somedef').render()``,
+the decorator has to write the output to the ``context``, i.e.
+as in the first example. The return value gets discarded.
Added: pypy/benchmarks/lib/mako/doc/build/index.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/index.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,21 @@
+Table of Contents
+=================
+
+.. toctree::
+ :maxdepth: 2
+
+ usage
+ syntax
+ defs
+ runtime
+ namespaces
+ inheritance
+ filtering
+ unicode
+ caching
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`search`
Added: pypy/benchmarks/lib/mako/doc/build/inheritance.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/inheritance.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,321 @@
+.. _inheritance_toplevel:
+
+===========
+Inheritance
+===========
+
+Using template inheritance, two or more templates can organize
+themselves into an **inheritance chain**, where content and
+functions from all involved templates can be intermixed. The
+general paradigm of template inheritance is this: if a template
+``A`` inherits from template ``B``, then template ``A`` agrees
+to send the executional control to template ``B`` at runtime
+(``A`` is called the **inheriting** template). Template ``B``,
+the **inherited** template, then makes decisions as to what
+resources from ``A`` shall be executed.
+
+In practice, it looks like this. Heres a hypothetical inheriting
+template, ``index.html``:
+
+.. sourcecode:: mako
+
+ ## 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
+
+ ## base.html
+ <html>
+ <body>
+ <div class="header">
+ ${self.header()}
+ </div>
+
+ ${self.body()}
+
+ <div class="footer">
+ ${self.footer()}
+ </div>
+ </body>
+ </html>
+
+ <%def name="footer()">
+ this is the footer
+ </%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,
+ then calls the method ``header()`` off of a built in namespace
+ called ``self`` (this namespace was first introduced in the
+ Namespaces chapter in
+ :ref:`namespace_self`). Since
+ ``index.html`` is the topmost template and also defines a def
+ called ``header()``, its this ``header()`` def that gets
+ executed.
+* Control comes back to ``base.html``. Some more HTML is
+ rendered.
+* ``base.html`` executes ``self.body()``. The ``body()``
+ function on all template-based namespaces refers to the main
+ body of the template, therefore the main body of
+ ``index.html`` is rendered.
+* Control comes back to ``base.html``. More HTML is rendered,
+ then the ``self.footer()`` expression is invoked.
+* The ``footer`` def is only defined in ``base.html``, so being
+ the topmost definition of ``footer``, its the one that
+ executes. If ``index.html`` also specified ``footer``, then
+ its version would **override** that of the base.
+* ``base.html`` finishes up rendering its HTML and the template
+ is complete, producing:
+
+.. sourcecode:: html
+
+ <html>
+ <body>
+ <div class="header">
+ this is some header content
+ </div>
+
+ this is the body content.
+
+ <div class="footer">
+ this is the footer
+ </div>
+ </body>
+ </html>
+
+...and that is template inheritance in a nutshell. The main idea
+is that the methods that you call upon ``self`` always
+correspond to the topmost definition of that method. Very much
+the way ``self`` works in a Python class, even though Mako is
+not actually using Python class inheritance to implement this
+functionality. (Mako doesn't take the "inheritance" metaphor too
+seriously; while useful to setup some commonly recognized
+semantics, a textual template is not very much like an
+object-oriented class construct in practice).
+
+Using the "next" namespace to produce content wrapping
+=======================================================
+
+Sometimes you have an inheritance chain that spans more than two
+templates. Or maybe you don't, but youd like to build your
+system such that extra inherited templates can be inserted in
+the middle of a chain where they would be smoothly integrated.
+If each template wants to define its layout just within its main
+body, you can't just call ``self.body()`` to get at the
+inheriting template's body, since that is only the topmost body.
+To get at the body of the *next* template, you call upon the
+namespace ``next``, which is the namespace of the template
+**immediately following** the current template.
+
+Lets change the line in ``base.html`` which calls upon
+``self.body()`` to instead call upon ``next.body()``:
+
+.. sourcecode:: mako
+
+ ## base.html
+ <html>
+ <body>
+ <div class="header">
+ ${self.header()}
+ </div>
+
+ ${next.body()}
+
+ <div class="footer">
+ ${self.footer()}
+ </div>
+ </body>
+ </html>
+
+ <%def name="footer()">
+ this is the footer
+ </%def>
+
+Lets also add an intermediate template called ``layout.html``,
+which inherits from ``base.html``:
+
+.. sourcecode:: mako
+
+ ## layout.html
+ <%inherit file="base.html"/>
+ <ul>
+ ${self.toolbar()}
+ </ul>
+ <div class="mainlayout">
+ ${next.body()}
+ </div>
+
+ <%def name="toolbar()">
+ <li>selection 1</li>
+ <li>selection 2</li>
+ <li>selection 3</li>
+ </%def>
+
+And finally change ``index.html`` to inherit from
+``layout.html`` instead:
+
+.. sourcecode:: mako
+
+ ## 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
+is still first passed to the bottommost template ``base.html``,
+and ``self`` still references the topmost definition of any
+particular def.
+
+The output we get would be:
+
+.. sourcecode:: html
+
+ <html>
+ <body>
+ <div class="header">
+ this is some header content
+ </div>
+
+ <ul>
+ <li>selection 1</li>
+ <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>
+ </body>
+ </html>
+
+So above, we have the ``<html>``, ``<body>`` and
+``header``/``footer`` layout of ``base.html``, we have the
+``<ul>`` and ``mainlayout`` section of ``layout.html``, and the
+main body of ``index.html`` as well as its overridden ``header``
+def. The ``layout.html`` template is inserted into the middle of
+the chain without ``base.html`` having to change anything.
+Without the ``next`` namespace, only the main body of
+``index.html`` could be used; there would be no way to call
+``layout.html``'s body content.
+
+Using the "parent" namespace to augment defs
+=============================================
+
+Lets now look at the other inheritance-specific namespace, the
+opposite of ``next`` called ``parent``. ``parent`` is the
+namespace of the template **immediately preceding** the current
+template. What is most useful about this namespace is the
+methods within it which can be accessed within overridden
+versions of those methods. This is not as hard as it sounds and
+is very much like using the ``super`` keyword in Python. Lets
+modify ``index.html`` to augment the list of selections provided
+by the ``toolbar`` function in ``layout.html``:
+
+.. sourcecode:: mako
+
+ ## index.html
+ <%inherit file="layout.html"/>
+
+ <%def name="header()">
+ this is some header content
+ </%def>
+
+ <%def name="toolbar()">
+ ## call the parent's toolbar first
+ ${parent.toolbar()}
+ <li>selection 4</li>
+ <li>selection 5</li>
+ </%def>
+
+ this is the body content.
+
+Above, we implemented a ``toolbar()`` function, which is meant
+to override the definition of ``toolbar`` within the inherited
+template ``layout.html``. However, since we want the content
+from that of ``layout.html`` as well, we call it via the
+``parent`` namespace whenever we want it's content, in this case
+before we add our own selections. So the output for the whole
+thing is now:
+
+.. sourcecode:: html
+
+ <html>
+ <body>
+ <div class="header">
+ this is some header content
+ </div>
+
+ <ul>
+ <li>selection 1</li>
+ <li>selection 2</li>
+ <li>selection 3</li>
+ <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>
+ </body>
+ </html>
+
+and you're now a template inheritance ninja !
+
+Inheritable Attributes
+======================
+
+The ``attr`` accessor of the :class:`.Namespace` object allows access
+to module level variables declared in a template. By accessing
+``self.attr``, you can access regular attributes from the
+inheritance chain as declared in ``<%! %>`` sections. Such as:
+
+.. sourcecode:: mako
+
+ <%!
+ class_ = "grey"
+ %>
+
+ <div class="${self.attr.class_}">
+ ${self.body()}
+ </div>
+
+If a an inheriting template overrides ``class_`` to be
+``white``, as in:
+
+.. sourcecode:: mako
+
+ <%!
+ class_ = "white"
+ %>
+ <%inherit file="parent.html"/>
+
+ This is the body
+
+You'll get output like:
+
+.. sourcecode:: html
+
+ <div class="white">
+ This is the body
+ </div>
Added: pypy/benchmarks/lib/mako/doc/build/namespaces.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/namespaces.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,341 @@
+.. _namespaces_toplevel:
+
+==========
+Namespaces
+==========
+
+Namespaces are used to organize groups of components into
+categories, and also to "import" components from other files.
+
+If the file ``components.html`` defines these two components:
+
+.. sourcecode:: mako
+
+ ## components.html
+ <%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``:
+
+.. sourcecode:: mako
+
+ ## index.html
+ <%namespace name="comp" file="components.html"/>
+
+ Heres comp1: ${comp.comp1()}
+ Heres comp2: ${comp.comp2(x=5)}
+
+The ``comp`` variable above is an instance of
+:class:`.Namespace`, a **proxy object** which delivers
+method calls to the underlying template callable using the
+current context.
+
+``<%namespace>`` also provides an ``import`` attribute which can
+be used to pull the names into the local namespace, removing the
+need to call it via the ".". When ``import`` is used, the
+``name`` attribute is optional.
+
+.. sourcecode:: mako
+
+ <%namespace file="components.html" import="comp1, comp2"/>
+
+ Heres comp1: ${comp1()}
+ Heres comp2: ${comp2(x=5)}
+
+``import`` also supports the "*" operator:
+
+.. sourcecode:: mako
+
+ <%namespace file="components.html" import="*"/>
+
+ Heres comp1: ${comp1()}
+ Heres comp2: ${comp2(x=5)}
+
+The names imported by the ``import`` attribute take precedence
+over any names that exist within the current context.
+
+.. note:: in current versions of Mako, usage of ``import='*'`` is
+ known to decrease performance of the template. This will be
+ fixed in a future release.
+
+The ``file`` argument allows expressions - if looking for
+context variables, the ``context`` must be named explicitly:
+
+.. sourcecode:: mako
+
+ <%namespace name="dyn" file="${context['namespace_name']}"/>
+
+Ways to Call Namespaces
+========================
+
+There are essentially four ways to call a function from a
+namespace.
+
+The "expression" format, as described previously. Namespaces are
+just Python objects with functions on them, and can be used in
+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
+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:
+
+.. sourcecode:: mako
+
+ <%mynamespace:somefunction arg1="${someobject.format()}" arg2="${somedef(5, 12)}"/>
+
+The "custom tag" format is intended mainly for namespace
+functions which recognize body content, which in Mako is known
+as a "def with embedded content":
+
+.. sourcecode:: mako
+
+ <%mynamespace:somefunction arg1="some argument" args="x, y">
+ Some record: ${x}, ${y}
+ </%mynamespace:somefunction>
+
+The "classic" way to call defs with embedded content is the ``<%call>`` tag:
+
+.. sourcecode:: mako
+
+ <%call expr="mynamespace.somefunction(arg1='some argument')" args="x, y">
+ Some record: ${x}, ${y}
+ </%call>
+
+For information on how to construct defs that embed content from
+the caller, see :ref:`defs_with_content`.
+
+.. _namespaces_python_modules:
+
+Namespaces from Regular Python Modules
+========================================
+
+Namespaces can also import regular Python functions from
+modules. These callables need to take at least one argument,
+``context``, an instance of :class:`.Context`. A module file
+``some/module.py`` might contain the callable:
+
+.. sourcecode:: python
+
+ def my_tag(context):
+ context.write("hello world")
+ 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
+dump a ``None`` into the output stream - the return value of any
+def is rendered after the def completes, in addition to whatever
+was passed to :meth:`.Context.write` within its body.
+
+If your def is to be called in an "embedded content" context,
+that is as described in :ref:`defs_with_content`, you should use
+the :func:`.supports_caller` decorator, which will ensure that Mako
+will ensure the correct "caller" variable is available when your
+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:
+
+.. sourcecode:: python
+
+ from mako.runtime import supports_caller, capture
+
+ @supports_caller
+ def my_tag(context):
+ return "<div>%s</div>" % \
+ capture(context, context['caller'].body, x="foo", y="bar")
+
+Declaring defs in namespaces
+=============================
+
+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
+ <%namespace name="stuff">
+ <%def name="comp1()">
+ comp1
+ </%def>
+ </%namespace>
+
+ ## then call it
+ ${stuff.comp1()}
+
+.. _namespaces_body:
+
+The "body()" method
+=====================
+
+Every namespace that is generated from a template contains a
+method called ``body()``. This method corresponds to the main
+body of the template, and plays its most important roles when
+using inheritance relationships as well as
+def-calls-with-content.
+
+Since the ``body()`` method is available from a namespace just
+like all the other defs defined in a template, what happens if
+you send arguments to it ? By default, the ``body()`` method
+accepts no positional arguments, and for usefulness in
+inheritance scenarios will by default dump all keyword arguments
+into a dictionary called ``pageargs``. But if you actually want
+to get at the keyword arguments, Mako recommends you define your
+own argument signature explicitly. You do this via using the
+``<%page>`` tag:
+
+.. 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
+receive all other keyword arguments. If ``**kwargs`` or similar
+is not present, the argument ``**pageargs`` gets tacked on by
+Mako. When the template is called as a top-level template (i.e.
+via :meth:`~.Template.render`) or via the ``<%include>`` tag, the
+values for these arguments will be pulled from the ``Context``.
+In all other cases, i.e. via calling the ``body()`` method, the
+arguments are taken as ordinary arguments from the method call.
+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:
+
+.. sourcecode:: mako
+
+ ${next.body(**context.kwargs)}
+
+The usefulness of calls like the above become more apparent when
+one works with inheriting templates. For more information on
+this, as well as the meanings of the names ``self`` and
+``next``, see :ref:`inheritance_toplevel`.
+
+.. _namespaces_builtin:
+
+Built-in Namespaces
+====================
+
+The namespace is so great that Mako gives your template one (or
+two) for free. The names of these namespaces are ``local`` and
+``self``. Other built-in namespaces include ``parent`` and
+``next``, which are optional and are described in
+:ref:`inheritance_toplevel`.
+
+.. _namespace_local:
+
+local
+-----
+
+The ``local`` namespace is basically the namespace for the
+currently executing template. This means that all of the top
+level defs defined in your template, as well as your template's
+``body()`` function, are also available off of the ``local``
+namespace.
+
+The ``local`` namespace is also where properties like ``uri``,
+``filename``, and ``module`` and the ``get_namespace`` method
+can be particularly useful.
+
+.. _namespace_self:
+
+self
+-----
+
+The ``self`` namespace, in the case of a template that does not
+use inheritance, is synonomous with ``local``. If inheritance is
+used, then ``self`` references the topmost template in the
+inheritance chain, where it is most useful for providing the
+ultimate form of various "method" calls which may have been
+overridden at various points in an inheritance chain. See
+:ref:`inheritance_toplevel`.
+
+Inheritable Namespaces
+========================
+
+The ``<%namespace>`` tag includes an optional attribute
+``inheritable="True"``, which will cause the namespace to be
+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
+that its inheriting templates can get to, without them having to
+explicitly load those namespaces themselves.
+
+The ``import="*"`` part of the ``<%namespace>`` tag doesn't yet
+interact with the ``inheritable`` flag, so currently you have to
+use the explicit namespace name off of ``self``, followed by the
+desired function name. But more on this in a future release.
+
+API Reference
+==============
+
+.. autoclass:: mako.runtime.Namespace
+ :show-inheritance:
+ :members:
+
+.. autofunction:: mako.runtime.supports_caller
+
+.. autofunction:: mako.runtime.capture
+
Added: pypy/benchmarks/lib/mako/doc/build/runtime.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/runtime.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,238 @@
+.. _runtime_toplevel:
+
+=============================
+The Mako Runtime Environment
+=============================
+
+This section describes a little bit about the objects and
+built-in functions that are available in templates.
+
+Context
+=======
+
+The :class:`.Context` is the central object that is created when
+a template is first executed, and is responsible for handling
+all communication with the outside world. This includes two
+major components, one of which is the output buffer, which is a
+file-like object such as Python's ``StringIO`` or similar, and
+the other a dictionary of variables that can be freely
+referenced within a template; this dictionary is a combination
+of the arguments sent to the :meth:`~.Template.render` function and
+some built-in variables provided by Mako's runtime environment.
+
+The Buffer
+----------
+
+The buffer is stored within the :class:`.Context`, and writing
+to it is achieved by calling :meth:`.Context.write`. You usually
+don't need to care about this as all text within a template, as
+well as all expressions provided by ``${}``, automatically send
+everything to this method. The cases you might want to be aware
+of its existence are if you are dealing with various
+filtering/buffering scenarios, which are described in
+:ref:`filtering_toplevel`, or if you want to programmatically
+send content to the output stream, such as within a ``<% %>``
+block.
+
+.. sourcecode:: mako
+
+ <%
+ context.write("some programmatic text")
+ %>
+
+The actual buffer may or may not be the original buffer sent to
+the :class:`.Context` object, as various filtering/caching
+scenarios may "push" a new buffer onto the context's underlying
+buffer stack. For this reason, just stick with
+:meth:`.Context.write` and content will always go to the topmost
+buffer.
+
+Context Variables
+------------------
+
+When your template is compiled into a Python module, the body
+content is enclosed within a Python function called
+``render_body``. Other top-level defs defined in the template are
+defined within their own function bodies which are named after
+the def's name with the prefix ``render_`` (i.e. ``render_mydef``).
+One of the first things that happens within these functions is
+that all variable names that are referenced within the function
+which are not defined in some other way (i.e. such as via
+assignment, module level imports, etc.) are pulled from the
+:class:`.Context` object's dictionary of variables. This is how you're
+able to freely reference variable names in a template which
+automatically correspond to what was passed into the current
+:class:`.Context`.
+
+* **What happens if I reference a variable name that is not in
+ the current context?** - the value you get back is a special
+ value called ``UNDEFINED``, or if the ``strict_undefined=True`` flag
+ is used a ``NameError`` is raised. ``UNDEFINED`` is just a simple global
+ variable with the class ``mako.runtime.Undefined``. The
+ ``UNDEFINED`` object throws an error when you call ``str()`` on
+ it, which is what happens if you try to use it in an
+ expression.
+* **UNDEFINED makes it hard for me to find what name is missing** - An alternative
+ introduced in version 0.3.6 is to specify the option
+ ``strict_undefined=True``
+ to the :class:`.Template` or :class:`.TemplateLookup`. This will cause
+ any non-present variables to raise an immediate ``NameError``
+ which includes the name of the variable in its message
+ when :meth:`~.Template.render` is called - ``UNDEFINED`` is not used.
+* **Why not just return None?** Using ``UNDEFINED``, or
+ raising a ``NameError`` is more
+ explicit and allows differentiation between a value of ``None``
+ that was explicitly passed to the :class:`.Context` and a value that
+ wasn't present at all.
+* **Why raise an exception when you call str() on it ? Why not
+ just return a blank string?** - Mako tries to stick to the
+ Python philosophy of "explicit is better than implicit". In
+ this case, its decided that the template author should be made
+ to specifically handle a missing value rather than
+ experiencing what may be a silent failure. Since ``UNDEFINED``
+ is a singleton object just like Python's ``True`` or ``False``,
+ you can use the ``is`` operator to check for it:
+
+ .. sourcecode:: mako
+
+ % if someval is UNDEFINED:
+ someval is: no value
+ % 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
+its Python, you can hack around this and change values in the
+context's internal dictionary, but this will probably will not
+work as well as you'd think. The reason for this is that Mako in
+many cases creates copies of the :class:`.Context` object, which
+get sent to various elements of the template and inheriting
+templates used in an execution. So changing the value in your
+local :class:`.Context` will not necessarily make that value
+available in other parts of the template's execution. Examples
+of where Mako creates copies of the :class:`.Context` include
+within top-level def calls from the main body of the template
+(the context is used to propagate locally assigned variables
+into the scope of defs; since in the template's body they appear
+as inlined functions, Mako tries to make them act that way), and
+within an inheritance chain (each template in an inheritance
+chain has a different notion of ``parent`` and ``next``, which
+are all stored in unique :class:`.Context` instances).
+
+* **So what if I want to set values that are global to everyone
+ within a template request?** - All you have to do is provide a
+ dictionary to your :class:`.Context` when the template first
+ runs, and everyone can just get/set variables from that. Lets
+ say its called ``attributes``.
+
+ Running the template looks like:
+
+ .. sourcecode:: python
+
+ output = template.render(attributes={})
+
+ Within a template, just reference the dictionary:
+
+ .. sourcecode:: mako
+
+ <%
+ 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.
+ Perhaps you don't want your templates to use this technique of
+ assigning and sharing data, or perhaps you have a different
+ notion of the names and kinds of data structures that should
+ be passed around. Once again Mako would rather ask the user to
+ be explicit.
+
+Context Methods and Accessors
+------------------------------
+
+Significant members off of :class:`.Context` include:
+
+* ``context[key]`` / ``context.get(key, default=None)`` -
+ dictionary-like accessors for the context. Normally, any
+ variable you use in your template is automatically pulled from
+ the context if it isnt defined somewhere already. Use the
+ dictionary accessor and/or ``get`` method when you want a
+ variable that *is* already defined somewhere else, such as in
+ the local arguments sent to a %def call. If a key is not
+ present, like a dictionary it raises ``KeyError``.
+* ``keys()`` - all the names defined within this context.
+* ``kwargs`` - this returns a **copy** of the context's
+ dictionary of variables. This is useful when you want to
+ propagate the variables in the current context to a function
+ as keyword arguments, i.e.:
+
+.. sourcecode:: mako
+
+ ${next.body(**context.kwargs)}
+
+* ``write(text)`` - write some text to the current output
+ stream.
+* ``lookup`` - returns the :class:`.TemplateLookup` instance that is
+ used for all file-lookups within the current execution (even
+ though individual :class:`.Template` instances can conceivably have
+ different instances of a :class:`.TemplateLookup`, only the
+ :class:`.TemplateLookup` of the originally-called :class:`.Template` gets
+ used in a particular execution).
+
+All the built-in names
+======================
+
+A one-stop shop for all the names Mako defines. Most of these
+names are instances of :class:`.Namespace`, which are described
+in the next section, :ref:`namespaces_toplevel`. Also, most of
+these names other than :class:`.Context` and ``UNDEFINED`` are
+also present *within* the :class:`.Context` itself.
+
+* ``local`` - the namespace of the current template, described
+ in :ref:`namespaces_builtin`.
+* ``self`` - the namespace of the topmost template in an
+ inheritance chain (if any, otherwise the same as ``local``),
+ mostly described in :ref:`inheritance_toplevel`.
+* ``parent`` - the namespace of the parent template in an
+ inheritance chain (otherwise undefined); see
+ :ref:`inheritance_toplevel`.
+* ``next`` - the namespace of the next template in an
+ inheritance chain (otherwise undefined); see
+ :ref:`inheritance_toplevel`.
+* ``caller`` - a "mini" namespace created when using the
+ ``<%call>`` tag to define a "def call with content"; described
+ in :ref:`defs_with_content`.
+* ``capture`` - a function that calls a given def and captures
+ its resulting content into a string, which is returned. Usage
+ is described in :ref:`filtering_toplevel`.
+* ``UNDEFINED`` - a global singleton that is applied to all
+ otherwise uninitialized template variables that were not
+ located within the :class:`.Context` when rendering began,
+ unless the :class:`.Template` flag ``strict_undefined``
+ is set to ``True``. ``UNDEFINED`` is
+ an instance of :class:`.Undefined`, and raises an
+ exception when its ``__str__()`` method is called.
+* ``pageargs`` - this is a dictionary which is present in a
+ template which does not define any \**kwargs section in its
+ ``<%page>`` tag. All keyword arguments sent to the ``body()``
+ function of a template (when used via namespaces) go here by
+ default unless otherwise defined as a page argument. If this
+ makes no sense, it shouldn't; read the section
+ :ref:`namespaces_body`.
+
+API Reference
+==============
+
+.. autoclass:: mako.runtime.Context
+ :show-inheritance:
+ :members:
+
+.. autoclass:: mako.runtime.Undefined
+ :show-inheritance:
+
+
+
Added: pypy/benchmarks/lib/mako/doc/build/static/docs.css
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/static/docs.css Tue Dec 21 07:44:16 2010
@@ -0,0 +1,288 @@
+/* documentation section styles */
+
+body, td {
+ font-family: Tahoma,Geneva,sans-serif;
+}
+
+body {
+ background-color: #FDFBFC;
+ margin:38px;
+ color:#333333;
+}
+
+form {
+ display:inline;
+}
+
+p {
+ margin-top:10px;
+ margin-bottom:10px;
+}
+
+
+a {
+ font-weight:normal;
+ text-decoration:none;
+}
+a:link {color:#0000FF;}
+a:visited {color:#0000FF;}
+a:active {color:#0000FF;}
+a:hover {color:#700000;}
+
+
+strong a {
+ font-weight: bold;
+}
+
+#search {
+ float:right;
+}
+
+#searchform {
+ padding:20px;
+}
+
+#pagecontrol {
+ float:right;
+}
+
+.topnav {
+ background-color: #eeeeee;
+ border: solid 1px #ccc;
+ padding:10px;
+ margin:10px 0px 10px 0px;
+}
+
+.bottomnav {
+ background-color: #eeeeee;
+ border:1px solid #CCCCCC;
+ float:right;
+ margin: 1em 0 1em 5px;
+ padding:10px;
+}
+
+.document {
+ border: solid 1px #ccc;
+}
+
+.topnav .prevnext {
+ padding: 5px 0px 0px 0px;
+ /*font-size: 0.8em*/
+}
+
+h1, h2, h3, h4, h5 {
+ font-weight:bold;
+}
+
+h1 {
+ font-size:1.6em;
+ font-weight:bold;
+}
+.document h1, .document h2, .document h3, .document h4, .document h5 {
+ font-size: 1.2em;
+}
+
+.document img {
+ display:block;
+ margin: 0 auto;
+}
+
+.document h1 {
+ display:none;
+}
+
+.topnav h2 {
+ margin:26px 4px 0px 5px;
+ font-size:1.6em;
+ font-weight:normal;
+ line-height:1.6em;
+}
+
+.topnav h3 {
+ font-weight: bold;
+ font-size: 1.4em;
+ margin:0px;
+ display:inline;
+}
+
+.topnav li,
+li.toctree-l1,
+li.toctree-l1 li
+{
+ list-style-type:disc;
+ margin:0px;
+ padding:1px 8px;
+}
+
+
+.topnav li ul,
+li.toctree-l1 ul
+{
+ padding:0px 0px 0px 20px;
+}
+
+.topnav li ul li li,
+li.toctree-l1 ul li li
+{
+ /*font-size:.90em;*/
+}
+
+.sourcelink {
+ font-size:.8em;
+ text-align:right;
+ padding-top:10px;
+}
+
+.section {
+ line-height: 1.5em;
+ padding:8px 10px 20px 10px;
+ margin:10px 0px 0px;
+}
+
+.section .section {
+ margin:0px 0px 0px 0px;
+ padding: 0px;
+}
+
+.section .section .section {
+ margin:0px 0px 0px 20px;
+}
+
+.section .section .section .section {
+ margin:0px 0px 0px 20px;
+}
+
+th.field-name {
+ text-align:right;
+}
+
+div.note, div.warning, p.deprecated {
+ background-color:#EEFFEF;
+}
+
+
+div.admonition, div.topic, p.deprecated {
+ border:1px solid #CCCCCC;
+ margin:5px 5px 5px 5px;
+ padding:5px 5px 5px 35px;
+ font-size:.9em;
+}
+
+div.warning .admonition-title {
+ color:#FF0000;
+}
+
+div.admonition .admonition-title {
+ font-weight:bold;
+}
+
+
+.totoc {
+
+}
+
+.doc_copyright {
+ font-size:.85em;
+ padding:10px 0px 10px 0px;
+}
+
+pre {
+ background-color: #f0f0f0;
+ border: solid 1px #ccc;
+ padding:10px;
+ margin: 5px 5px 5px 5px;
+ overflow:auto;
+ line-height:1.3em;
+}
+
+.versionheader {
+ margin-top: 0.5em;
+}
+.versionnum {
+ font-weight: bold;
+}
+
+.viewcode-back, .viewcode-link {
+ float:right;
+}
+.prerelease {
+ border: solid #c25757 2px;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ background-color: #c21a1a;
+ color: white;
+ padding: 0.05em 0.2em;
+}
+
+dl.function > dt,
+dl.attribute > dt,
+dl.classmethod > dt,
+dl.method > dt,
+dl.class > dt,
+dl.exception > dt
+{
+ background-color:#F0F0F0;
+ margin:0px -10px;
+ padding: 0px 10px;
+}
+
+
+dt:target, span.highlight {
+ background-color:#FBE54E;
+}
+
+a.headerlink {
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+a.headerlink:hover {
+ background-color: #00f;
+ color: white;
+}
+
+.clearboth {
+ clear:both;
+}
+
+tt.descname {
+ background-color:transparent;
+ font-size:1.2em;
+ font-weight:bold;
+}
+
+tt.descclassname {
+ background-color:transparent;
+}
+
+tt {
+ background-color:#ECF0F3;
+ padding:0 1px;
+}
+
+ at media print {
+ #nav { display: none; }
+ #pagecontrol { display: none; }
+ .topnav .prevnext { display: none; }
+ .bottomnav { display: none; }
+ .totoc { display: none; }
+ .topnav ul li a { text-decoration: none; color: #000; }
+}
+
+/* syntax highlighting overrides */
+.k, .kn {color:#0908CE;}
+.o {color:#BF0005;}
+.go {color:#804049;}
Added: pypy/benchmarks/lib/mako/doc/build/syntax.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/syntax.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,417 @@
+.. _syntax_toplevel:
+
+======
+Syntax
+======
+
+A Mako template is parsed from a text stream containing any kind
+of content, XML, HTML, email text, etc. The template can further
+contain Mako-specific directives which represent variable and/or
+expression substitutions, control structures (i.e. conditionals
+and loops), server-side comments, full blocks of Python code, as
+well as various tags that offer additional functionality. All of
+these constructs compile into real Python code. This means that
+you can leverage the full power of Python in almost every aspect
+of a Mako template.
+
+Expression Substitution
+========================
+
+The simplest expression is just a variable substitution. The
+syntax for this is the ``${}`` construct, which is inspired by
+Perl, Genshi, JSP EL, and others:
+
+.. sourcecode:: mako
+
+ this is x: ${x}
+
+Above, the string representation of ``x`` is applied to the
+template's output stream. If you're wondering where ``x`` comes
+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
+result.
+
+Expression Escaping
+===================
+
+
+Mako includes a number of built-in escaping mechanisms,
+including HTML, URI and XML escaping, as well as a "trim"
+function. These escapes can be added to an expression
+substituion using the ``|`` operator:
+
+.. sourcecode:: mako
+
+ ${"this is some text" | u}
+
+The above expression applies URL escaping to the expression, and
+produces ``this+is+some+text``. The ``u`` name indicates URL
+escaping, whereas ``h`` represents HTML escaping, ``x``
+represents XML escaping, and ``trim`` applies a trim function.
+
+Read more about built in filtering functions, including how to
+make your own filter functions, in :ref:`filtering_toplevel`.
+
+Control Structures
+==================
+
+A control structure refers to all those things that control the
+flow of a program - conditionals (i.e. if/else), loops (like
+while and for), as well as things like ``try/except``. In Mako,
+control structures are written using the ``%`` marker followed
+by a regular Python control expression, and are "closed" by
+using another ``%`` marker with the tag "``end<name>``", where
+"``<name>``" is the keyword of the expression:
+
+.. sourcecode:: mako
+
+ % 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
+``if/elif/else``, ``while``, ``for``, and even ``def``, although
+Mako has a built-in tag for defs which is more full-featured.
+
+.. sourcecode:: mako
+
+ % for a in ['one', 'two', 'three', 'four', 'five']:
+ % if a[0] == 't':
+ its two or three
+ % elif a[0] == 'f':
+ four/five
+ % else:
+ one
+ %endif
+ % endfor
+
+The ``%`` sign can also be "escaped", if you actually want to
+emit a percent sign as the first non whitespace character on a
+line, by escaping it as in ``%%``:
+
+.. sourcecode:: mako
+
+ %% some text
+
+ %% some more text
+
+Comments
+========
+
+Comments come in two varieties. The single line comment uses
+``##`` as the first non-space characters on a line:
+
+.. sourcecode:: mako
+
+ ## this is a comment.
+ ...text ...
+
+A multiline version exists using ``<%doc> ...text... </%doc>``:
+
+.. sourcecode:: mako
+
+ <%doc>
+ these are comments
+ more comments
+ </%doc>
+
+Newline Filters
+================
+
+The backslash ("``\``") character, placed at the end of any
+line, will consume the newline character before continuing to
+the next line:
+
+.. sourcecode:: mako
+
+ 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
+=============
+
+Any arbitrary block of python can be dropped in using the ``<%
+%>`` tags:
+
+.. sourcecode:: mako
+
+ this is a template
+ <%
+ x = db.get_resource('foo')
+ y = [z.element for z in x if x.frobnizzle==5]
+ %>
+ % 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.
+Mako's compiler will adjust the block of Python to be consistent
+with the surrounding generated Python code.
+
+Module-level Blocks
+====================
+
+A variant on ``<% %>`` is the module-level code block, denoted
+by ``<%! %>``. Code within these tags is executed at the module
+level of the template, and not within the rendering function of
+the template. Therefore, this code does not have access to the
+template's context and is only executed when the template is
+loaded into memory (which can be only once per application, or
+more, depending on the runtime environment). Use the ``<%! %>``
+tags to declare your template's imports, as well as any
+pure-Python functions you might want to declare:
+
+.. sourcecode:: mako
+
+ <%!
+ 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,
+in the order in which they appear in the source template.
+
+Tags
+====
+
+The rest of what Mako offers takes place in the form of tags.
+All tags use the same syntax, which is similar to an XML tag
+except that the first character of the tag name is a ``%``
+character. The tag is closed either by a contained slash
+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
+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
+expression in is to try it ! The lexer will tell you if its not
+valid.
+
+Heres a quick summary of all the tags:
+
+<%page>
+-------
+
+This tag defines general characteristics of the template,
+including caching arguments, and optional lists of arguments
+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"/>
+
+Currently, only one ``<%page>`` tag gets used per template, the
+rest get ignored. While this will be improved in a future
+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>
+-----------
+
+A tag that is familiar from other template languages, %include
+is a regular joe that just accepts a file argument and calls in
+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:
+
+.. sourcecode:: mako
+
+ <%include file="toolbar.html" args="current_section='members', username='ed'"/>
+
+<%def>
+------
+
+The ``%def`` tag defines a Python function which contains a set
+of content, that can be called at some other point in the
+template. The basic idea is simple:
+
+.. sourcecode:: mako
+
+ <%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
+as template "methods", automatic propagation of the current
+``Context``, buffering/filtering/caching flags, and def calls
+with content, which enable packages of defs to be sent as
+arguments to other def calls (not as hard as it sounds). Get the
+full deal on what %def can do in :ref:`defs_toplevel`.
+
+<%namespace>
+-------------
+
+%namespace is Mako's equivalent of Python's ``import``
+statement. It allows access to all the rendering functions and
+metadata of other template files, plain Python modules, as well
+as locally defined "packages" of functions.
+
+.. sourcecode:: mako
+
+ <%namespace file="functions.html" import="*"/>
+
+The underlying object generated by %namespace, an instance of
+:class:`.mako.runtime.Namespace`, is a central construct used in
+templates to reference template-specific information such as the
+current URI, inheritance structures, and other things that are
+not as hard as they sound right here. Namespaces are described
+in :ref:`namespaces_toplevel`.
+
+<%inherit>
+----------
+
+Inherit allows templates to arrange themselves in **inheritance
+chains**. This is a concept familiar in many other template
+languages.
+
+.. sourcecode:: mako
+
+ <%inherit file="base.html"/>
+
+When using the %inherit tag, control is passed to the topmost
+inherited template first, which then decides how to handle
+calling areas of content from its inheriting templates. Mako
+offers a lot of flexbility in this area, including dynamic
+inheritance, content wrapping, and polymorphic method calls.
+Check it out in :ref:`inheritance_toplevel`.
+
+<%namespacename:defname>
+-------------------------
+
+As of Mako 0.2.3, any user-defined "tag" can be created against
+a namespace by using a tag with a name of the form
+``<%<namespacename>:<defname>>``. The closed and open formats of such a
+tag are equivalent to an inline expression and the ``<%call>``
+tag, respectively.
+
+.. sourcecode:: mako
+
+ <%mynamespace:somedef param="some value">
+ this is the body
+ </%mynamespace:somedef>
+
+To create custom tags which accept a body, see
+:ref:`defs_with_content`.
+
+<%call>
+-------
+
+The call tag is the "classic" form of a user-defined tag, and is
+roughly equiavlent to the ``<%namespacename:defname>`` syntax
+described above. This tag is also described in `defs_with_content`.
+
+<%doc>
+------
+
+The doc tag handles multiline comments:
+
+.. sourcecode:: mako
+
+ <%doc>
+ these are comments
+ more comments
+ </%doc>
+
+Also the ``##`` symbol as the first non-space characters on a line can be used for single line comments.
+
+<%text>
+-------
+
+This tag suspends the Mako lexer's normal parsing of Mako
+template directives, and returns its entire body contents as
+plain text. It is used pretty much to write documentation about
+Mako:
+
+.. sourcecode:: mako
+
+ <%text filter="h">
+ heres some fake mako ${syntax}
+ <%def name="x()">${x}</%def>
+ %CLOSETEXT
+
+Returning early from a template
+===============================
+
+Sometimes you want to stop processing a template or ``<%def>``
+method in the middle and just use the text you've accumulated so
+far. You can use a ````return```` statement inside a Python
+block to do that.
+
+.. sourcecode:: mako
+
+ % if not len(records):
+ No records found.
+ <% return %>
+ % endif
+
+Or perhaps:
+
+.. sourcecode:: mako
+
+ <%
+ if not len(records):
+ return
+ %>
+
Added: pypy/benchmarks/lib/mako/doc/build/templates/genindex.mako
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/templates/genindex.mako Tue Dec 21 07:44:16 2010
@@ -0,0 +1,72 @@
+<%inherit file="layout.mako"/>
+
+<%def name="show_title()">${_('Index')}</%def>
+
+ <h1 id="index">${_('Index')}</h1>
+
+ % for i, (key, dummy) in enumerate(genindexentries):
+ ${i != 0 and '| ' or ''}<a href="#${key}"><strong>${key}</strong></a>
+ % endfor
+
+ <hr />
+
+ % for i, (key, entries) in enumerate(genindexentries):
+<h2 id="${key}">${key}</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+ <%
+ breakat = genindexcounts[i] // 2
+ numcols = 1
+ numitems = 0
+ %>
+% for entryname, (links, subitems) in entries:
+
+<dt>
+ % if links:
+ <a href="${links[0]}">${entryname|h}</a>
+ % for link in links[1:]:
+ , <a href="${link}">[${i}]</a>
+ % endfor
+ % else:
+ ${entryname|h}
+ % endif
+
+ % if subitems:
+ <dd><dl>
+ % for subentryname, subentrylinks in subitems:
+ <dt><a href="${subentrylinks[0]}">${subentryname|h}</a>
+ % for j, link in enumerate(subentrylinks[1:]):
+ <a href="${link}">[${j}]</a>
+ % endfor
+ </dt>
+ % endfor
+ </dl></dd>
+ % endif
+ <%
+ numitems = numitems + 1 + len(subitems)
+ %>
+ % if numcols <2 and numitems > breakat:
+ <%
+ numcols = numcols + 1
+ %>
+ </dl></td><td width="33%" valign="top"><dl>
+% endif
+
+% endfor
+</dl></td></tr></table>
+% endfor
+
+<%def name="sidebarrel()">
+% if split_index:
+ <h4>${_('Index')}</h4>
+ <p>
+ % for i, (key, dummy) in enumerate(genindexentries):
+ ${i > 0 and '| ' or ''}
+ <a href="${pathto('genindex-' + key)}"><strong>${key}</strong></a>
+ % endfor
+ </p>
+
+ <p><a href="${pathto('genindex-all')}"><strong>${_('Full index on one page')}</strong></a></p>
+% endif
+ ${parent.sidebarrel()}
+</%def>
Added: pypy/benchmarks/lib/mako/doc/build/templates/layout.mako
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/templates/layout.mako Tue Dec 21 07:44:16 2010
@@ -0,0 +1,130 @@
+## coding: utf-8
+<%inherit file="${context['mako_layout']}"/>
+
+<%def name="headers()">
+ <link rel="stylesheet" href="${pathto('_static/pygments.css', 1)}" type="text/css" />
+ <link rel="stylesheet" href="${pathto('_static/docs.css', 1)}" type="text/css" />
+
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '${pathto("", 1)}',
+ VERSION: '${release|h}',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '${file_suffix}'
+ };
+ </script>
+ % for scriptfile in script_files + self.attr.local_script_files:
+ <script type="text/javascript" src="${pathto(scriptfile, 1)}"></script>
+ % endfor
+ <script type="text/javascript" src="${pathto('_static/init.js', 1)}"></script>
+ % if hasdoc('about'):
+ <link rel="author" title="${_('About these documents')}" href="${pathto('about')}" />
+ % endif
+ <link rel="index" title="${_('Index')}" href="${pathto('genindex')}" />
+ <link rel="search" title="${_('Search')}" href="${pathto('search')}" />
+ % if hasdoc('copyright'):
+ <link rel="copyright" title="${_('Copyright')}" href="${pathto('copyright')}" />
+ % endif
+ <link rel="top" title="${docstitle|h}" href="${pathto('index')}" />
+ % if parents:
+ <link rel="up" title="${parents[-1]['title']|util.striptags}" href="${parents[-1]['link']|h}" />
+ % endif
+ % if nexttopic:
+ <link rel="next" title="${nexttopic['title']|util.striptags}" href="${nexttopic['link']|h}" />
+ % endif
+ % if prevtopic:
+ <link rel="prev" title="${prevtopic['title']|util.striptags}" href="${prevtopic['link']|h}" />
+ % endif
+ ${self.extrahead()}
+</%def>
+<%def name="extrahead()"></%def>
+
+ <h1>${docstitle|h}</h1>
+
+ <div id="search">
+ Search:
+ <form class="search" action="${pathto('search')}" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="${_('Search')}" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ </div>
+
+ <div class="versionheader">
+ Version: <span class="versionnum">${release}</span> Last Updated: ${last_updated}
+ </div>
+ <div class="clearboth"></div>
+
+ <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:
+ % for parent in parents:
+ » <a href="${parent['link']|h}" title="${parent['title']}">${parent['title']}</a>
+ % endfor
+ % endif
+ % if current_page_name != master_doc:
+ » ${self.show_title()}
+ % endif
+
+ ${prevnext()}
+ <h2>
+ ${self.show_title()}
+ </h2>
+ </div>
+ % if display_toc and not current_page_name.startswith('index'):
+ ${toc}
+ % endif
+ <div class="clearboth"></div>
+ </div>
+
+ <div class="document">
+ <div class="body">
+ ${next.body()}
+ </div>
+ </div>
+
+ <%def name="footer()">
+ <div class="bottomnav">
+ ${prevnext()}
+ <div class="doc_copyright">
+ % if hasdoc('copyright'):
+ © <a href="${pathto('copyright')}">Copyright</a> ${copyright|h}.
+ % else:
+ © Copyright ${copyright|h}.
+ % endif
+ % if show_sphinx:
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> ${sphinx_version|h}.
+ % endif
+ </div>
+ </div>
+ </%def>
+ ${self.footer()}
+
+<%def name="prevnext()">
+<div class="prevnext">
+ % if prevtopic:
+ Previous:
+ <a href="${prevtopic['link']|h}" title="${_('previous chapter')}">${prevtopic['title']}</a>
+ % endif
+ % if nexttopic:
+ Next:
+ <a href="${nexttopic['link']|h}" title="${_('next chapter')}">${nexttopic['title']}</a>
+ % endif
+</div>
+</%def>
+
+<%def name="show_title()">
+% if title:
+ ${title}
+% endif
+</%def>
+
Added: pypy/benchmarks/lib/mako/doc/build/templates/page.mako
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/templates/page.mako Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+<%inherit file="layout.mako"/>
+${body| util.strip_toplevel_anchors}
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/doc/build/templates/search.mako
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/templates/search.mako Tue Dec 21 07:44:16 2010
@@ -0,0 +1,22 @@
+<%inherit file="layout.mako"/>
+
+<%!
+ local_script_files = ['_static/searchtools.js']
+%>
+<%def name="show_title()">${_('Search')}</%def>
+
+<div id="searchform">
+<h3>Enter Search Terms:</h3>
+<form class="search" action="${pathto('search')}" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="${_('Search')}" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+</form>
+</div>
+
+<div id="search-results"></div>
+
+<%def name="footer()">
+ ${parent.footer()}
+ <script type="text/javascript" src="searchindex.js"></script>
+</%def>
Added: pypy/benchmarks/lib/mako/doc/build/templates/site_base.mako
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/templates/site_base.mako Tue Dec 21 07:44:16 2010
@@ -0,0 +1,30 @@
+<%text>#coding:utf-8
+<%inherit file="/root.html"/>
+<%page cache_type="file" cached="True"/>
+<%!
+ in_docs=True
+%>
+</%text>
+
+<%doc>
+## TODO: pdf
+<div style="text-align:right">
+<b>PDF Download:</b> <a href="${pathto('sqlalchemy_' + release.replace('.', '_') + '.pdf', 1)}">download</a>
+</div>
+</%doc>
+
+${'<%text>'}
+${next.body()}
+${'</%text>'}
+
+<%text><%def name="style()"></%text>
+ ${self.headers()}
+ <%text>${parent.style()}</%text>
+ <link href="/css/site_docs.css" rel="stylesheet" type="text/css"></link>
+<%text></%def></%text>
+
+<%text><%def name="title()"></%text>${capture(self.show_title)|util.striptags} — ${docstitle|h}<%text></%def></%text>
+
+<%!
+ local_script_files = []
+%>
Added: pypy/benchmarks/lib/mako/doc/build/templates/static_base.mako
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/templates/static_base.mako Tue Dec 21 07:44:16 2010
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ ${metatags and metatags or ''}
+ <title>${capture(self.show_title)|util.striptags} — ${docstitle|h}</title>
+ ${self.headers()}
+ </head>
+ <body>
+ ${next.body()}
+ </body>
+</html>
+
+
+<%!
+ local_script_files = []
+%>
Added: pypy/benchmarks/lib/mako/doc/build/unicode.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/unicode.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,337 @@
+.. _unicode_toplevel:
+
+===================
+The Unicode Chapter
+===================
+
+The Python language supports two ways of representing what we
+know as "strings", i.e. series of characters. In Python 2, the
+two types are ``string`` and ``unicode``, and in Python 3 they are
+``bytes`` and ``string``. A key aspect of the Python 2 ``string`` and
+Python 3 ``bytes`` types are that they contain no information
+regarding what **encoding** the data is stored in. For this
+reason they were commonly referred to as **byte strings** on
+Python 2, and Python 3 makes this name more explicit. The
+origins of this come from Python's background of being developed
+before the Unicode standard was even available, back when
+strings were C-style strings and were just that, a series of
+bytes. Strings that had only values below 128 just happened to
+be **ascii** strings and were printable on the console, whereas
+strings with values above 128 would produce all kinds of
+graphical characters and bells.
+
+Contrast the "bytestring" types with the "unicode/string" type.
+Objects of this type are created whenever you say something like
+``u"hello world"`` (or in Python 3, just ``"hello world"``). In this
+case, Python represents each character in the string internally
+using multiple bytes per character (something similar to
+UTF-16). Whats important is that when using the
+``unicode``/``string`` type to store strings, Python knows the
+data's encoding; its in its own internal format. Whereas when
+using the ``string``/``bytes`` type, it does not.
+
+When Python 2 attempts to treat a byte-string as a string, which
+means its attempting to compare/parse its characters, to coerce
+it into another encoding, or to decode it to a unicode object,
+it has to guess what the encoding is. In this case, it will
+pretty much always guess the encoding as ``ascii``...and if the
+bytestring contains bytes above value 128, you'll get an error.
+Python 3 eliminates much of this confusion by just raising an
+error unconditionally if a bytestring is used in a
+character-aware context.
+
+There is one operation that Python *can* do with a non-ascii
+bytestring, and its a great source of confusion: it can dump the
+bytestring straight out to a stream or a file, with nary a care
+what the encoding is. To Python, this is pretty much like
+dumping any other kind of binary data (like an image) to a
+stream somewhere. In Python 2, it is common to see programs that
+embed all kinds of international characters and encodings into
+plain byte-strings (i.e. using ``"hello world"`` style literals)
+can fly right through their run, sending reams of strings out to
+whereever they are going, and the programmer, seeing the same
+output as was expressed in the input, is now under the illusion
+that his or her program is Unicode-compliant. In fact, their
+program has no unicode awareness whatsoever, and similarly has
+no ability to interact with libraries that *are* unicode aware.
+Python 3 makes this much less likely by defaulting to unicode as
+the storage format for strings.
+
+The "pass through encoded data" scheme is what template
+languages like Cheetah and earlier versions of Myghty do by
+default. Mako as of version 0.2 also supports this mode of
+operation when using Python 2, using the "disable_unicode=True"
+flag. However, when using Mako in its default mode of
+unicode-aware, it requires explicitness when dealing with
+non-ascii encodings. Additionally, if you ever need to handle
+unicode strings and other kinds of encoding conversions more
+intelligently, the usage of raw bytestrings quickly becomes a
+nightmare, since you are sending the Python interpreter
+collections of bytes for which it can make no intelligent
+decisions with regards to encoding. In Python 3 Mako only allows
+usage of native, unicode strings.
+
+In normal Mako operation, all parsed template constructs and
+output streams are handled internally as Python ``unicode``
+objects. Its only at the point of :meth:`~.Template.render` that this unicode
+stream may be rendered into whatever the desired output encoding
+is. The implication here is that the template developer must
+ensure that the encoding of all non-ascii templates is explicit
+(still required in Python 3), that all non-ascii-encoded
+expressions are in one way or another converted to unicode (not
+much of a burden in Python 3), and that the output stream of the
+template is handled as a unicode stream being encoded to some
+encoding (still required in Python 3).
+
+Specifying the Encoding of a Template File
+===========================================
+
+This is the most basic encoding-related setting, and it is
+equivalent to Python's "magic encoding comment", as described in
+`pep-0263 <http://www.python.org/dev/peps/pep-0263/>`_. Any
+template that contains non-ascii characters requires that this
+comment be present so that Mako can decode to unicode (and also
+make usage of Python's AST parsing services). Mako's lexer will
+use this encoding in order to convert the template source into a
+``unicode`` object before continuing its parsing:
+
+.. sourcecode:: mako
+
+ ## -*- coding: utf-8 -*-
+
+ 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! »
+
+For the picky, the regular expression used is derived from that
+of the abovementioned pep:
+
+.. sourcecode:: python
+
+ #.*coding[:=]\s*([-\w.]+).*\n
+
+The lexer will convert to unicode in all cases, so that if any
+characters exist in the template that are outside of the
+specified encoding (or the default of ``ascii``), the error will
+be immediate.
+
+As an alternative, the template encoding can be specified
+programmatically to either :class:`.Template` or :class:`.TemplateLookup` via
+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.
+
+Handling Expressions
+=====================
+
+The next area that encoding comes into play is in expression
+constructs. By default, Mako's treatment of an expression like
+this:
+
+.. sourcecode:: mako
+
+ ${"hello world"}
+
+looks something like this:
+
+.. sourcecode:: python
+
+ context.write(unicode("hello world"))
+
+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
+both the purpose of rendering non-string expressions into
+strings (such as integers or objects which contain ``__str()__``
+methods), and to ensure that the final output stream is
+constructed as a unicode object. The main implication of this is
+that **any raw bytestrings that contain an encoding other than
+ascii must first be decoded to a Python unicode object**. It
+means you can't say this in Python 2:
+
+.. sourcecode:: mako
+
+ ${"voix m’a réveillé."} ## error in Python 2!
+
+You must instead say this:
+
+.. sourcecode:: mako
+
+ ${u"voix m’a réveillé."} ## OK !
+
+Similarly, if you are reading data from a file that is streaming
+bytes, or returning data from some object that is returning a
+Python bytestring containing a non-ascii encoding, you have to
+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
+this.
+
+If you want a certain encoding applied to *all* expressions,
+override the ``unicode`` builtin with the ``decode`` builtin at the
+:class:`.Template` or :class:`.TemplateLookup` level:
+
+.. sourcecode:: python
+
+ t = Template(templatetext, default_filters=['decode.utf8'])
+
+Note that the built-in ``decode`` object is slower than the
+``unicode`` function, since unlike ``unicode`` its not a Python
+builtin, and it also checks the type of the incoming data to
+determine if string conversion is needed first.
+
+The ``default_filters`` argument can be used to entirely customize
+the filtering process of expressions. This argument is described
+in :ref:`filtering_default_filters`.
+
+Defining Output Encoding
+=========================
+
+Now that we have a template which produces a pure unicode output
+stream, all the hard work is done. We can take the output and do
+anything with it.
+
+As stated in the "Usage" chapter, both :class:`.Template` and
+:class:`.TemplateLookup` accept ``output_encoding`` and ``encoding_errors``
+parameters which can be used to encode the output in any Python
+supported codec:
+
+.. sourcecode:: python
+
+ 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()
+
+:meth:`~.Template.render` will return a ``bytes`` object in Python 3 if an output
+encoding is specified. By default it performs no encoding and
+returns a native string.
+
+:meth:`~.Template.render_unicode` will return the template output as a Python
+``unicode`` object (or ``string`` in Python 3):
+
+.. 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
+-----------------
+
+Mako does play some games with the style of buffering used
+internally, to maximize performance. Since the buffer is by far
+the most heavily used object in a render operation, its
+important!
+
+When calling :meth:`~.Template.render` on a template that does not specify any
+output encoding (i.e. its ``ascii``), Python's ``cStringIO`` module,
+which cannot handle encoding of non-ascii ``unicode`` objects
+(even though it can send raw bytestrings through), is used for
+buffering. Otherwise, a custom Mako class called
+``FastEncodingBuffer`` is used, which essentially is a super
+dumbed-down version of ``StringIO`` that gathers all strings into
+a list and uses ``u''.join(elements)`` to produce the final output
+- its markedly faster than ``StringIO``.
+
+.. _unicode_disabled:
+
+Saying to Heck with it: Disabling the usage of Unicode entirely
+================================================================
+
+Some segements of Mako's userbase choose to make no usage of
+Unicode whatsoever, and instead would prefer the "passthru"
+approach; all string expressions in their templates return
+encoded bytestrings, and they would like these strings to pass
+right through. The only advantage to this approach is that
+templates need not use ``u""`` for literal strings; there's an
+arguable speed improvement as well since raw bytestrings
+generally perform slightly faster than unicode objects in
+Python. For these users, assuming they're sticking with Python
+2, they can hit the ``disable_unicode=True`` flag as so:
+
+.. sourcecode:: 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
+
+The ``disable_unicode`` mode is strictly a Python 2 thing. It is
+not supported at all in Python 3.
+
+The generated module source code will contain elements like
+these:
+
+.. sourcecode:: python
+
+ # -*- encoding:utf-8 -*-
+ # ...more generated code ...
+
+ def render_body(context,**pageargs):
+ context.caller_stack.push_frame()
+ try:
+ __M_locals = dict(pageargs=pageargs)
+ # SOURCE LINE 1
+ context.write('dr\xc3\xb4le de petite voix m\xe2\x80\x99a r\xc3\xa9veill\xc3\xa9.')
+ return ''
+ finally:
+ context.caller_stack.pop_frame()
+
+Where above that the string literal used within :meth:`.Context.write`
+is a regular bytestring.
+
+When ``disable_unicode=True`` is turned on, the ``default_filters``
+argument which normally defaults to ``["unicode"]`` now defaults
+to ``["str"]`` instead. Setting default_filters to the empty list
+``[]`` can remove the overhead of the ``str`` call. Also, in this
+mode you **cannot** safely call :meth:`~.Template.render_unicode` - you'll get
+unicode/decode errors.
+
+The ``h`` filter (html escape) uses a less performant pure Python
+escape function in non-unicode mode (note that in versions prior
+to 0.3.4, it used cgi.escape(), which has been replaced with a
+function that also escapes single quotes). This because
+MarkupSafe only supports Python unicode objects for non-ascii
+strings.
+
+**Rules for using disable_unicode=True**
+
+* don't use this mode unless you really, really want to and you
+ absolutely understand what you're doing
+* don't use this option just because you don't want to learn to
+ use Unicode properly; we aren't supporting user issues in this
+ mode of operation. We will however offer generous help for the
+ 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.
+
+
+
Added: pypy/benchmarks/lib/mako/doc/build/usage.rst
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/doc/build/usage.rst Tue Dec 21 07:44:16 2010
@@ -0,0 +1,484 @@
+.. _usage_toplevel:
+
+=====
+Usage
+=====
+
+Basic Usage
+===========
+
+This section describes the Python API for Mako templates. If you
+are using Mako within a web framework such as Pylons, the work
+of integrating Mako's API is already done for you, in which case
+you can skip to the next section, :ref:`syntax_toplevel`.
+
+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
+template. When ``mytemplate.render()`` is called, Mako sets up a
+runtime environment for the template and calls the
+``render_body()`` function, capturing the output into a buffer and
+returning its string contents.
+
+
+The code inside the ``render_body()`` function has access to a
+namespace of variables. You can specify these variables by
+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.
+You can create this :class:`.Context` yourself and have the template
+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")
+ mytemplate.render_context(ctx)
+ print buf.getvalue()
+
+Using File-Based Templates
+===========================
+
+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
+file). To do this, just add the ``module_directory`` argument to
+the template::
+
+ from mako.template import Template
+
+ mytemplate = Template(filename='/docs/mytmpl.txt', module_directory='/tmp/mako_modules')
+ print mytemplate.render()
+
+When the above code is rendered, a file
+``/tmp/mako_modules/docs/mytmpl.txt.py`` is created containing the
+source code for the module. The next time a :class:`.Template` with the
+same arguments is created, this module file will be
+automatically re-used.
+
+.. _usage_templatelookup:
+
+Using TemplateLookup
+====================
+
+All of the examples thus far have dealt with the usage of a
+single :class:`.Template` object. If the code within those templates
+tries to locate another template resource, it will need some way
+to find them, using simple URI strings. For this need, the
+resolution of other templates from within a template is
+accomplished by the :class:`.TemplateLookup` class. This class is
+constructed given a list of directories in which to search for
+templates, as well as keyword arguments that will be passed to
+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)
+
+Above, we created a textual template which includes the file
+``"header.txt"``. In order for it to have somewhere to look for
+``"header.txt"``, we passed a :class:`.TemplateLookup` object to it, which
+will search in the directory ``/docs`` for the file ``"header.txt"``.
+
+Usually, an application will store most or all of its templates
+as text files on the filesystem. So far, all of our examples
+have been a little bit contrived in order to illustrate the
+basic concepts. But a real application would get most or all of
+its templates directly from the :class:`.TemplateLookup`, using the
+aptly named :meth:`~.TemplateLookup.get_template` method, which accepts the URI of the
+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)
+
+In the example above, we create a :class:`.TemplateLookup` which will
+look for templates in the ``/docs`` directory, and will store
+generated module files in the ``/tmp/mako_modules`` directory. The
+lookup locates templates by appending the given URI to each of
+its search directories; so if you gave it a URI of
+``/etc/beans/info.txt``, it would search for the file
+``/docs/etc/beans/info.txt``, else raise a :class:`.TopLevelNotFound`
+exception, which is a custom Mako exception.
+
+When the lookup locates templates, it will also assign a ``uri``
+property to the :class:`.Template` which is the uri passed to the
+:meth:`~.TemplateLookup.get_template()` call. :class:`.Template` uses this uri to calculate the
+name of its module file. So in the above example, a
+``templatename`` argument of ``/etc/beans/info.txt`` will create a
+module file ``/tmp/mako_modules/etc/beans/info.txt.py``.
+
+Setting the Collection Size
+---------------------------
+
+The :class:`.TemplateLookup` also serves the important need of caching a
+fixed set of templates in memory at a given time, so that
+successive uri lookups do not result in full template
+compilations and/or module reloads on each request. By default,
+the :class:`.TemplateLookup` size is unbounded. You can specify a fixed
+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
+recently used scheme.
+
+Setting Filesystem Checks
+--------------------------
+
+Another important flag on :class:`.TemplateLookup` is
+``filesystem_checks``. This defaults to ``True``, and says that each
+time a template is returned by the :meth:`~.TemplateLookup.get_template()` method, the
+revision time of the original template file is checked against
+the last time the template was loaded, and if the file is newer
+will reload its contents and recompile the template. On a
+production system, setting ``filesystem_checks`` to ``False`` can
+afford a small to moderate performance increase (depending on
+the type of filesystem used).
+
+.. _usage_unicode:
+
+Using Unicode and Encoding
+===========================
+
+Both :class:`.Template` and :class:`.TemplateLookup` accept ``output_encoding``
+and ``encoding_errors`` parameters which can be used to encode the
+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()
+
+When using Python 3, the :meth:`~.Template.render` method will return a ``bytes``
+object, **if** ``output_encoding`` is set. Otherwise it returns a
+``string``.
+
+Additionally, the :meth:`~.Template.render_unicode()` method exists which will
+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
+fully in :ref:`unicode_toplevel`.
+
+.. _handling_exceptions:
+
+Handling Exceptions
+====================
+
+Template exceptions can occur in two distinct places. One is
+when you **lookup, parse and compile** the template, the other
+is when you **run** the template. Within the running of a
+template, exceptions are thrown normally from whatever Python
+code originated the issue. Mako has its own set of exception
+classes which mostly apply to the lookup and lexer/compiler
+stages of template construction. Mako provides some library
+routines that can be used to help provide Mako-specific
+information about any exception's stack trace, as well as
+formatting the exception within textual or HTML format. In all
+cases, the main value of these handlers is that of converting
+Python filenames, line numbers, and code samples into Mako
+template filenames, line numbers, and code samples. All lines
+within a stack trace which correspond to a Mako template module
+will be converted to be against the originating template file.
+
+To format exception traces, the :func:`.text_error_template` and
+:func:`.html_error_template` functions are provided. They make usage of
+``sys.exc_info()`` to get at the most recently thrown exception.
+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
+
+ try:
+ template = lookup.get_template(uri)
+ print template.render()
+ except:
+ print exceptions.html_error_template().render()
+
+The :func:`.html_error_template` template accepts two options:
+specifying ``full=False`` causes only a section of an HTML
+document to be rendered. Specifying ``css=False`` will disable the
+default stylesheet from being rendered.
+
+E.g.::
+
+ print exceptions.html_error_template().render(full=False)
+
+The HTML render function is also available built-in to
+:class:`.Template` using the ``format_exceptions`` flag. In this case, any
+exceptions raised within the **render** stage of the template
+will result in the output being substituted with the output of
+:func:`.html_error_template`::
+
+ 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
+lookup/parse/compile stage will not be handled and will
+propagate normally. While the pre-render traceback usually will
+not include any Mako-specific lines anyway, it will mean that
+exceptions which occur previous to rendering and those which
+occur within rendering will be handled differently...so the
+try/except patterns described previously are probably of more
+general use.
+
+The underlying object used by the error template functions is
+the :class:`.RichTraceback` object. This object can also be used
+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()
+ except:
+ traceback = RichTraceback()
+ for (filename, lineno, function, line) in traceback.traceback:
+ 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
+=============================
+
+The Mako distribution includes a little bit of helper code for
+the purpose of using Mako in some popular web framework
+scenarios. This is a brief description of whats included.
+
+WSGI
+----
+
+A sample WSGI application is included in the distrubution in the
+file ``examples/wsgi/run_wsgi.py``. This runner is set up to pull
+files from a `templates` as well as an `htdocs` directory and
+includes a rudimental two-file layout. The WSGI runner acts as a
+fully functional standalone web server, using ``wsgiutils`` to run
+itself, and propagates GET and POST arguments from the request
+into the :class:`.Context`, can serve images, css files and other kinds
+of files, and also displays errors using Mako's included
+exception-handling utilities.
+
+Pygments
+---------
+
+A `Pygments <http://pygments.pocoo.org>`_-compatible syntax
+highlighting module is included under :mod:`mako.ext.pygmentplugin`.
+This module is used in the generation of Mako documentation and
+also contains various setuptools entry points under the heading
+``pygments.lexers``, including ``mako``, ``html+mako``, ``xml+mako``
+(see the ``setup.py`` file for all the entry points).
+
+Babel
+------
+
+Mako provides support for extracting gettext messages from
+templates via a `Babel`_ extractor
+entry point under `mako.ext.babelplugin`.
+
+Gettext messages are extracted from all Python code sections,
+including those of control lines and expressions embedded
+in tags.
+
+`Translator
+comments <http://babel.edgewall.org/wiki/Documentation/messages.html#comments-tags-and-translator-comments-explanation>`_
+may also be extracted from Mako templates when a comment tag is
+specified to `Babel`_ (such as with
+the -c option).
+
+For example, a project ``"myproj"`` contains the following Mako
+template at ``myproj/myproj/templates/name.html``:
+
+.. sourcecode:: mako
+
+ <div id="name">
+ Name:
+ ## TRANSLATORS: This is a proper name. See the gettext
+ ## manual, section Names.
+ ${_('Francois Pinard')}
+ </div>
+
+To extract gettext messages from this template the project needs
+a Mako section in its `Babel Extraction Method Mapping
+file <http://babel.edgewall.org/wiki/Documentation/messages.html#extraction-method-mapping-and-configuration>`_
+(typically located at ``myproj/babel.cfg``)::
+
+ # Extraction from Python source files
+
+ [python: myproj/**.py]
+
+ # Extraction from Mako templates
+
+ [mako: myproj/templates/**.html]
+ input_encoding = utf-8
+
+The Mako extractor supports an optional ``input_encoding``
+parameter specifying the encoding of the templates (identical to
+:class:`.Template`/:class:`.TemplateLookup`'s ``input_encoding`` parameter).
+
+Invoking `Babel`_'s extractor at the
+command line in the project's root directory::
+
+ myproj$ pybabel extract -F babel.cfg -c "TRANSLATORS:" .
+
+Will output a gettext catalog to stdout including the following::
+
+ #. TRANSLATORS: This is a proper name. See the gettext
+ #. manual, section Names.
+ #: myproj/templates/name.html:5
+ msgid "Francois Pinard"
+ msgstr ""
+
+This is only a basic example:
+`Babel`_ can be invoked from setup.py
+and its command line options specified in the accompanying
+setup.cfg via `Babel Distutils/Setuptools
+Integration <http://babel.edgewall.org/wiki/Documentation/setup.html>`_.
+
+Comments must immediately precede a gettext message to be
+extracted. In the following case the TRANSLATORS: comment would
+not have been extracted:
+
+.. sourcecode:: mako
+
+ <div id="name">
+ ## TRANSLATORS: This is a proper name. See the gettext
+ ## manual, section Names.
+ Name: ${_('Francois Pinard')}
+ </div>
+
+See the `Babel User
+Guide <http://babel.edgewall.org/wiki/Documentation/index.html>`_
+for more information.
+
+.. _babel: http://babel.edgewall.org/
+
+
+API Reference
+=================
+
+.. autoclass:: mako.template.Template
+ :show-inheritance:
+ :members:
+
+.. autoclass:: mako.template.DefTemplate
+ :show-inheritance:
+ :members:
+
+.. autoclass:: mako.lookup.TemplateCollection
+ :show-inheritance:
+ :members:
+
+.. autoclass:: mako.lookup.TemplateLookup
+ :show-inheritance:
+ :members:
+
+.. autoclass:: mako.exceptions.RichTraceback
+ :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.
+ 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
+
+
+
Added: pypy/benchmarks/lib/mako/examples/bench/basic.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/basic.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,161 @@
+# basic.py - basic benchmarks adapted from Genshi
+# Copyright (C) 2006 Edgewall Software
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# 3. The name of the author may not be used to endorse or promote
+# products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from cgi import escape
+import os
+from StringIO import StringIO
+import sys
+import timeit
+
+__all__ = ['mako', 'mako_inheritance', 'cheetah', 'django', 'myghty', 'genshi', 'kid']
+
+def genshi(dirname, verbose=False):
+ from genshi.template import TemplateLoader
+ loader = TemplateLoader([dirname], auto_reload=False)
+ template = loader.load('template.html')
+ def render():
+ data = dict(title='Just a test', user='joe',
+ items=['Number %d' % num for num in range(1, 15)])
+ return template.generate(**data).render('xhtml')
+
+ if verbose:
+ print render()
+ return render
+
+def myghty(dirname, verbose=False):
+ from myghty import interp
+ interpreter = interp.Interpreter(component_root=dirname)
+ def render():
+ data = dict(title='Just a test', user='joe',
+ items=['Number %d' % num for num in range(1, 15)])
+ buffer = StringIO()
+ interpreter.execute("template.myt", request_args=data, out_buffer=buffer)
+ return buffer.getvalue()
+ if verbose:
+ print render()
+ return render
+
+def mako(dirname, verbose=False):
+ from mako.template import Template
+ from mako.lookup import TemplateLookup
+ lookup = TemplateLookup(directories=[dirname], filesystem_checks=False, disable_unicode=True)
+ template = lookup.get_template('template.html')
+ def render():
+ return template.render(title="Just a test", user="joe", list_items=[u'Number %d' % num for num in range(1,15)])
+ if verbose:
+ print template.code, render()
+ return render
+mako_inheritance = mako
+
+def cheetah(dirname, verbose=False):
+ from Cheetah.Template import Template
+ filename = os.path.join(dirname, 'template.tmpl')
+ template = Template(file=filename)
+ def render():
+ template.__dict__.update({'title': 'Just a test', 'user': 'joe',
+ 'list_items': [u'Number %d' % num for num in range(1, 15)]})
+ return template.respond()
+
+ if verbose:
+ print dir(template)
+ print template.generatedModuleCode()
+ print render()
+ return render
+
+def django(dirname, verbose=False):
+ from django.conf import settings
+ settings.configure(TEMPLATE_DIRS=[os.path.join(dirname, 'templates')])
+ from django import template, templatetags
+ from django.template import loader
+ templatetags.__path__.append(os.path.join(dirname, 'templatetags'))
+ tmpl = loader.get_template('template.html')
+
+ def render():
+ data = {'title': 'Just a test', 'user': 'joe',
+ 'items': ['Number %d' % num for num in range(1, 15)]}
+ return tmpl.render(template.Context(data))
+
+ if verbose:
+ print render()
+ return render
+
+def kid(dirname, verbose=False):
+ import kid
+ kid.path = kid.TemplatePath([dirname])
+ template = kid.Template(file='template.kid')
+ def render():
+ template = kid.Template(file='template.kid',
+ title='Just a test', user='joe',
+ items=['Number %d' % num for num in range(1, 15)])
+ return template.serialize(output='xhtml')
+
+ if verbose:
+ print render()
+ return render
+
+
+def run(engines, number=2000, verbose=False):
+ basepath = os.path.abspath(os.path.dirname(__file__))
+ for engine in engines:
+ dirname = os.path.join(basepath, engine)
+ if verbose:
+ print '%s:' % engine.capitalize()
+ print '--------------------------------------------------------'
+ else:
+ print '%s:' % engine.capitalize(),
+ 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 '--------------------------------------------------------'
+ print '%.2f ms' % (1000 * time)
+ if verbose:
+ print '--------------------------------------------------------'
+
+
+if __name__ == '__main__':
+ engines = [arg for arg in sys.argv[1:] if arg[0] != '-']
+ if not engines:
+ engines = __all__
+
+ verbose = '-v' in sys.argv
+
+ if '-p' in sys.argv:
+ import hotshot, hotshot.stats
+ prof = hotshot.Profile("template.prof")
+ benchtime = prof.runcall(run, engines, number=100, verbose=verbose)
+ stats = hotshot.stats.load("template.prof")
+ stats.strip_dirs()
+ stats.sort_stats('time', 'calls')
+ stats.print_stats()
+ else:
+ run(engines, verbose=verbose)
Added: pypy/benchmarks/lib/mako/examples/bench/cheetah/footer.tmpl
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/cheetah/footer.tmpl Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+<div id="footer">
+</div>
Added: pypy/benchmarks/lib/mako/examples/bench/cheetah/header.tmpl
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/cheetah/header.tmpl Tue Dec 21 07:44:16 2010
@@ -0,0 +1,5 @@
+<div id="header">
+ <h1>$title</h1>
+</div>
+
+
Added: pypy/benchmarks/lib/mako/examples/bench/cheetah/template.tmpl
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/cheetah/template.tmpl Tue Dec 21 07:44:16 2010
@@ -0,0 +1,31 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+ <head>
+ <title>${title}</title>
+ </head>
+ <body>
+
+ #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>
+ #for $list_item in $list_items
+ <li #if $list_item is $list_items[-1] then "class='last'" else ""#>$list_item</li>
+ #end for
+ </ul>
+ #end if
+
+ #include "cheetah/footer.tmpl"
+ </body>
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/django/templates/base.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/django/templates/base.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,14 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+
+ {% block body %}
+ <div id="header">
+ <h1>{{ title|escape }}</h1>
+ </div>
+ {{ block.super }}
+ <div id="footer"></div>
+ {% endblock %}
+
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/django/templates/template.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/django/templates/template.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,22 @@
+{% extends "base.html" %}
+{% load bench %}
+
+<head>
+ <title>${title|escape}</title>
+</head>
+
+{% block body %}
+ <div>{% greeting user %}</div>
+ <div>{% greeting "me" %}</div>
+ <div>{% greeting "world" %}</div>
+
+ <h2>Loop</h2>
+ {% if items %}
+ <ul>
+ {% for item in items %}
+ <li{% if forloop.last %} class="last"{% endif %}>{{ item }}</li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+
+{% endblock %}
Added: pypy/benchmarks/lib/mako/examples/bench/django/templatetags/__init__.py
==============================================================================
Added: pypy/benchmarks/lib/mako/examples/bench/django/templatetags/bench.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/django/templatetags/bench.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,8 @@
+from django.template import Library, Node, resolve_variable
+from django.utils.html import escape
+
+register = Library()
+
+def greeting(name):
+ return 'Hello, %s!' % escape(name)
+greeting = register.simple_tag(greeting)
Added: pypy/benchmarks/lib/mako/examples/bench/genshi/base.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/genshi/base.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,17 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ py:strip="">
+
+ <p py:def="greeting(name)">
+ Hello, ${name}!
+ </p>
+
+ <body py:match="body">
+ <div id="header">
+ <h1>${title}</h1>
+ </div>
+ ${select('*')}
+ <div id="footer" />
+ </body>
+
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/genshi/template.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/genshi/template.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,24 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ lang="en">
+ <xi:include href="base.html" />
+ <head>
+ <title>${title}</title>
+ </head>
+ <body>
+ <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"
+ class="${idx + 1 == len(items) and 'last' or None}" />
+ </ul>
+
+ </body>
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/kid/base.kid
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/kid/base.kid Tue Dec 21 07:44:16 2010
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://purl.org/kid/ns#">
+
+ <p py:def="greeting(name)">
+ Hello, ${name}!
+ </p>
+
+ <body py:match="item.tag == '{http://www.w3.org/1999/xhtml}body'" py:strip="">
+ <div id="header">
+ <h1>${title}</h1>
+ </div>
+ ${item}
+ <div id="footer" />
+ </body>
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/kid/template.kid
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/kid/template.kid Tue Dec 21 07:44:16 2010
@@ -0,0 +1,22 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://purl.org/kid/ns#"
+ py:extends="'base.kid'"
+ lang="en">
+ <head>
+ <title>${title}</title>
+ </head>
+ <body>
+ <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"
+ class="${idx + 1 == len(items) and 'last' or None}" />
+ </ul>
+ </body>
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/mako/footer.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/mako/footer.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+<div id="footer">
+</div>
Added: pypy/benchmarks/lib/mako/examples/bench/mako/header.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/mako/header.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,5 @@
+<div id="header">
+ <h1>${title}</h1>
+</div>
+
+
Added: pypy/benchmarks/lib/mako/examples/bench/mako/template.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/mako/template.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,31 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+ <head>
+ <title>${title}</title>
+ </head>
+ <body>
+
+<%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>
+ % for i, list_item in enumerate(list_items):
+ <li ${i+1==len(list_items) and "class='last'" or ""}>${list_item}</li>
+ % endfor
+ </ul>
+ % endif
+
+ <%include file="footer.html"/>
+ </body>
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/mako_inheritance/base.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/mako_inheritance/base.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,24 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+ <head>
+ <title>${title}</title>
+ </head>
+ <body>
+
+<%def name="greeting(name)">
+ <p>hello ${name}!</p>
+</%def>
+
+<div id="header">
+ <h1>${title}</h1>
+</div>
+
+ ${self.body()}
+
+ <div id="footer">
+ </div>
+
+ </body>
+</html>
Added: pypy/benchmarks/lib/mako/examples/bench/mako_inheritance/template.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/mako_inheritance/template.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,15 @@
+<%inherit file="base.html"/>
+
+ ${parent.greeting(user)}
+ ${parent.greeting('me')}
+ ${parent.greeting('world')}
+
+ <h2>Loop</h2>
+ % if list_items:
+ <ul>
+ % for list_item in list_items:
+ <li>${list_item}</li>
+ % endfor
+ </ul>
+ % endif
+
Added: pypy/benchmarks/lib/mako/examples/bench/myghty/base.myt
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/myghty/base.myt Tue Dec 21 07:44:16 2010
@@ -0,0 +1,29 @@
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<%args scope="request">
+ title
+</%args>
+
+<& REQUEST:header &>
+
+<body>
+<div id="header">
+ <h1><% title %></h1>
+</div>
+
+% m.call_next()
+
+<div id="footer"></div>
+
+</body>
+</html>
+
+
+<%method greeting>
+<%args>
+ name
+</%args>
+Hello, <% name | h %>
+</%method>
Added: pypy/benchmarks/lib/mako/examples/bench/myghty/template.myt
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/bench/myghty/template.myt Tue Dec 21 07:44:16 2010
@@ -0,0 +1,30 @@
+<%flags>inherit="base.myt"</%flags>
+<%args>
+ title
+ items
+ user
+</%args>
+
+<%method header>
+ <%args scope="request">
+ title
+ </%args>
+<head>
+ <title><% title %></title>
+</head>
+</%method>
+
+ <div><& base.myt:greeting, name=user &></div>
+ <div><& base.myt:greeting, name="me"&></div>
+ <div><& base.myt:greeting, name="world" &></div>
+
+ <h2>Loop</h2>
+%if items:
+ <ul>
+% for i, item in enumerate(items):
+ <li <% i+1==len(items) and "class='last'" or ""%>><% item %></li>
+%
+ </ul>
+%
+
+
Added: pypy/benchmarks/lib/mako/examples/wsgi/htdocs/index.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/wsgi/htdocs/index.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,8 @@
+<%
+%>
+
+<%inherit file="root.html"/>
+
+This is index.html
+
+c is ${c is not UNDEFINED and c or "undefined"}
Added: pypy/benchmarks/lib/mako/examples/wsgi/run_wsgi.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/wsgi/run_wsgi.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+
+import cgi, re, os, posixpath, mimetypes
+from mako.lookup import TemplateLookup
+from mako import exceptions
+
+root = './'
+port = 8000
+error_style = 'html' # select 'text' for plaintext error reporting
+
+lookup = TemplateLookup(directories=[root + 'templates', root + 'htdocs'], filesystem_checks=True, module_directory='./modules')
+
+def serve(environ, start_response):
+ """serves requests using the WSGI callable interface."""
+ fieldstorage = cgi.FieldStorage(
+ fp = environ['wsgi.input'],
+ environ = environ,
+ keep_blank_values = True
+ )
+ d = dict([(k, getfield(fieldstorage[k])) for k in fieldstorage])
+
+ uri = environ.get('PATH_INFO', '/')
+ if not uri:
+ uri = '/index.html'
+ else:
+ uri = re.sub(r'^/$', '/index.html', uri)
+
+ if re.match(r'.*\.html$', uri):
+ try:
+ template = lookup.get_template(uri)
+ start_response("200 OK", [('Content-type','text/html')])
+ return [template.render(**d)]
+ except exceptions.TopLevelLookupException:
+ start_response("404 Not Found", [])
+ return ["Cant find template '%s'" % uri]
+ except:
+ if error_style == 'text':
+ start_response("200 OK", [('Content-type','text/plain')])
+ return [exceptions.text_error_template().render()]
+ else:
+ start_response("200 OK", [('Content-type','text/html')])
+ return [exceptions.html_error_template().render()]
+ else:
+ u = re.sub(r'^\/+', '', uri)
+ 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):
+ return [getfield(x) for x in f]
+ else:
+ return f.value
+
+extensions_map = mimetypes.types_map.copy()
+extensions_map.update({
+'': 'text/html', # Default
+})
+
+def guess_type(path):
+ """return a mimetype for the given path based on file extension."""
+ base, ext = posixpath.splitext(path)
+ if ext in extensions_map:
+ return extensions_map[ext]
+ ext = ext.lower()
+ if ext in extensions_map:
+ return extensions_map[ext]
+ else:
+ return extensions_map['']
+
+if __name__ == '__main__':
+ import wsgiref.simple_server
+ server = wsgiref.simple_server.make_server('', port, serve)
+ print "Server listening on port %d" % port
+ server.serve_forever()
+
+
Added: pypy/benchmarks/lib/mako/examples/wsgi/templates/root.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/examples/wsgi/templates/root.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,7 @@
+<html>
+
+<head><title>hi</title></head>
+<body>
+ ${next.body()}
+</body>
+</html>
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/mako/__init__.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/__init__.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,9 @@
+# __init__.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+
+__version__ = '0.3.6'
+
Added: pypy/benchmarks/lib/mako/mako/_ast_util.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/_ast_util.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,834 @@
+# -*- coding: utf-8 -*-
+"""
+ ast
+ ~~~
+
+ The `ast` module helps Python applications to process trees of the Python
+ abstract syntax grammar. The abstract syntax itself might change with
+ each Python release; this module helps to find out programmatically what
+ the current grammar looks like and allows modifications of it.
+
+ An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
+ a flag to the `compile()` builtin function or by using the `parse()`
+ function from this module. The result will be a tree of objects whose
+ classes all inherit from `ast.AST`.
+
+ A modified abstract syntax tree can be compiled into a Python code object
+ using the built-in `compile()` function.
+
+ Additionally various helper functions are provided that make working with
+ the trees simpler. The main intention of the helper functions and this
+ module in general is to provide an easy to use interface for libraries
+ that work tightly with the python syntax (template engines for example).
+
+
+ :copyright: Copyright 2008 by Armin Ronacher.
+ :license: Python License.
+"""
+from _ast import *
+
+
+BOOLOP_SYMBOLS = {
+ And: 'and',
+ Or: 'or'
+}
+
+BINOP_SYMBOLS = {
+ Add: '+',
+ Sub: '-',
+ Mult: '*',
+ Div: '/',
+ FloorDiv: '//',
+ Mod: '%',
+ LShift: '<<',
+ RShift: '>>',
+ BitOr: '|',
+ BitAnd: '&',
+ BitXor: '^'
+}
+
+CMPOP_SYMBOLS = {
+ Eq: '==',
+ Gt: '>',
+ GtE: '>=',
+ In: 'in',
+ Is: 'is',
+ IsNot: 'is not',
+ Lt: '<',
+ LtE: '<=',
+ NotEq: '!=',
+ NotIn: 'not in'
+}
+
+UNARYOP_SYMBOLS = {
+ Invert: '~',
+ Not: 'not',
+ UAdd: '+',
+ USub: '-'
+}
+
+ALL_SYMBOLS = {}
+ALL_SYMBOLS.update(BOOLOP_SYMBOLS)
+ALL_SYMBOLS.update(BINOP_SYMBOLS)
+ALL_SYMBOLS.update(CMPOP_SYMBOLS)
+ALL_SYMBOLS.update(UNARYOP_SYMBOLS)
+
+
+def parse(expr, filename='<unknown>', mode='exec'):
+ """Parse an expression into an AST node."""
+ return compile(expr, filename, mode, PyCF_ONLY_AST)
+
+
+def to_source(node, indent_with=' ' * 4):
+ """
+ This function can convert a node tree back into python sourcecode. This
+ is useful for debugging purposes, especially if you're dealing with custom
+ asts not generated by python itself.
+
+ It could be that the sourcecode is evaluable when the AST itself is not
+ compilable / evaluable. The reason for this is that the AST contains some
+ more data than regular sourcecode does, which is dropped during
+ conversion.
+
+ Each level of indentation is replaced with `indent_with`. Per default this
+ parameter is equal to four spaces as suggested by PEP 8, but it might be
+ adjusted to match the application's styleguide.
+ """
+ generator = SourceGenerator(indent_with)
+ generator.visit(node)
+ return ''.join(generator.result)
+
+
+def dump(node):
+ """
+ A very verbose representation of the node passed. This is useful for
+ debugging purposes.
+ """
+ def _format(node):
+ if isinstance(node, AST):
+ return '%s(%s)' % (node.__class__.__name__,
+ ', '.join('%s=%s' % (a, _format(b))
+ for a, b in iter_fields(node)))
+ elif isinstance(node, list):
+ return '[%s]' % ', '.join(_format(x) for x in node)
+ return repr(node)
+ if not isinstance(node, AST):
+ raise TypeError('expected AST, got %r' % node.__class__.__name__)
+ return _format(node)
+
+
+def copy_location(new_node, old_node):
+ """
+ Copy the source location hint (`lineno` and `col_offset`) from the
+ old to the new node if possible and return the new one.
+ """
+ for attr in 'lineno', 'col_offset':
+ if attr in old_node._attributes and attr in new_node._attributes \
+ and hasattr(old_node, attr):
+ setattr(new_node, attr, getattr(old_node, attr))
+ return new_node
+
+
+def fix_missing_locations(node):
+ """
+ Some nodes require a line number and the column offset. Without that
+ information the compiler will abort the compilation. Because it can be
+ a dull task to add appropriate line numbers and column offsets when
+ adding new nodes this function can help. It copies the line number and
+ column offset of the parent node to the child nodes without this
+ information.
+
+ Unlike `copy_location` this works recursive and won't touch nodes that
+ already have a location information.
+ """
+ def _fix(node, lineno, col_offset):
+ if 'lineno' in node._attributes:
+ if not hasattr(node, 'lineno'):
+ node.lineno = lineno
+ else:
+ lineno = node.lineno
+ if 'col_offset' in node._attributes:
+ if not hasattr(node, 'col_offset'):
+ node.col_offset = col_offset
+ else:
+ col_offset = node.col_offset
+ for child in iter_child_nodes(node):
+ _fix(child, lineno, col_offset)
+ _fix(node, 1, 0)
+ return node
+
+
+def increment_lineno(node, n=1):
+ """
+ Increment the line numbers of all nodes by `n` if they have line number
+ attributes. This is useful to "move code" to a different location in a
+ file.
+ """
+ for node in zip((node,), walk(node)):
+ if 'lineno' in node._attributes:
+ node.lineno = getattr(node, 'lineno', 0) + n
+
+
+def iter_fields(node):
+ """Iterate over all fields of a node, only yielding existing fields."""
+ # CPython 2.5 compat
+ if not hasattr(node, '_fields') or not node._fields:
+ return
+ for field in node._fields:
+ try:
+ yield field, getattr(node, field)
+ except AttributeError:
+ pass
+
+
+def get_fields(node):
+ """Like `iter_fiels` but returns a dict."""
+ return dict(iter_fields(node))
+
+
+def iter_child_nodes(node):
+ """Iterate over all child nodes or a node."""
+ for name, field in iter_fields(node):
+ if isinstance(field, AST):
+ yield field
+ elif isinstance(field, list):
+ for item in field:
+ if isinstance(item, AST):
+ yield item
+
+
+def get_child_nodes(node):
+ """Like `iter_child_nodes` but returns a list."""
+ return list(iter_child_nodes(node))
+
+
+def get_compile_mode(node):
+ """
+ Get the mode for `compile` of a given node. If the node is not a `mod`
+ node (`Expression`, `Module` etc.) a `TypeError` is thrown.
+ """
+ if not isinstance(node, mod):
+ raise TypeError('expected mod node, got %r' % node.__class__.__name__)
+ return {
+ Expression: 'eval',
+ Interactive: 'single'
+ }.get(node.__class__, 'expr')
+
+
+def get_docstring(node):
+ """
+ Return the docstring for the given node or `None` if no docstring can be
+ found. If the node provided does not accept docstrings a `TypeError`
+ will be raised.
+ """
+ if not isinstance(node, (FunctionDef, ClassDef, Module)):
+ raise TypeError("%r can't have docstrings" % node.__class__.__name__)
+ if node.body and isinstance(node.body[0], Str):
+ return node.body[0].s
+
+
+def walk(node):
+ """
+ Iterate over all nodes. This is useful if you only want to modify nodes in
+ place and don't care about the context or the order the nodes are returned.
+ """
+ from collections import deque
+ todo = deque([node])
+ while todo:
+ node = todo.popleft()
+ todo.extend(iter_child_nodes(node))
+ yield node
+
+
+class NodeVisitor(object):
+ """
+ Walks the abstract syntax tree and call visitor functions for every node
+ found. The visitor functions may return values which will be forwarded
+ by the `visit` method.
+
+ Per default the visitor functions for the nodes are ``'visit_'`` +
+ class name of the node. So a `TryFinally` node visit function would
+ be `visit_TryFinally`. This behavior can be changed by overriding
+ the `get_visitor` function. If no visitor function exists for a node
+ (return value `None`) the `generic_visit` visitor is used instead.
+
+ Don't use the `NodeVisitor` if you want to apply changes to nodes during
+ traversing. For this a special visitor exists (`NodeTransformer`) that
+ allows modifications.
+ """
+
+ def get_visitor(self, node):
+ """
+ Return the visitor function for this node or `None` if no visitor
+ exists for this node. In that case the generic visit function is
+ used instead.
+ """
+ method = 'visit_' + node.__class__.__name__
+ return getattr(self, method, None)
+
+ def visit(self, node):
+ """Visit a node."""
+ f = self.get_visitor(node)
+ if f is not None:
+ return f(node)
+ return self.generic_visit(node)
+
+ def generic_visit(self, node):
+ """Called if no explicit visitor function exists for a node."""
+ for field, value in iter_fields(node):
+ if isinstance(value, list):
+ for item in value:
+ if isinstance(item, AST):
+ self.visit(item)
+ elif isinstance(value, AST):
+ self.visit(value)
+
+
+class NodeTransformer(NodeVisitor):
+ """
+ Walks the abstract syntax tree and allows modifications of nodes.
+
+ The `NodeTransformer` will walk the AST and use the return value of the
+ visitor functions to replace or remove the old node. If the return
+ value of the visitor function is `None` the node will be removed
+ from the previous location otherwise it's replaced with the return
+ value. The return value may be the original node in which case no
+ replacement takes place.
+
+ Here an example transformer that rewrites all `foo` to `data['foo']`::
+
+ class RewriteName(NodeTransformer):
+
+ def visit_Name(self, node):
+ return copy_location(Subscript(
+ value=Name(id='data', ctx=Load()),
+ slice=Index(value=Str(s=node.id)),
+ ctx=node.ctx
+ ), node)
+
+ Keep in mind that if the node you're operating on has child nodes
+ you must either transform the child nodes yourself or call the generic
+ visit function for the node first.
+
+ Nodes that were part of a collection of statements (that applies to
+ all statement nodes) may also return a list of nodes rather than just
+ a single node.
+
+ Usually you use the transformer like this::
+
+ node = YourTransformer().visit(node)
+ """
+
+ def generic_visit(self, node):
+ for field, old_value in iter_fields(node):
+ old_value = getattr(node, field, None)
+ if isinstance(old_value, list):
+ new_values = []
+ for value in old_value:
+ if isinstance(value, AST):
+ value = self.visit(value)
+ if value is None:
+ continue
+ elif not isinstance(value, AST):
+ new_values.extend(value)
+ continue
+ new_values.append(value)
+ old_value[:] = new_values
+ elif isinstance(old_value, AST):
+ new_node = self.visit(old_value)
+ if new_node is None:
+ delattr(node, field)
+ else:
+ setattr(node, field, new_node)
+ return node
+
+
+class SourceGenerator(NodeVisitor):
+ """
+ This visitor is able to transform a well formed syntax tree into python
+ sourcecode. For more details have a look at the docstring of the
+ `node_to_source` function.
+ """
+
+ def __init__(self, indent_with):
+ self.result = []
+ self.indent_with = indent_with
+ self.indentation = 0
+ self.new_lines = 0
+
+ def write(self, x):
+ if self.new_lines:
+ if self.result:
+ self.result.append('\n' * self.new_lines)
+ self.result.append(self.indent_with * self.indentation)
+ self.new_lines = 0
+ self.result.append(x)
+
+ def newline(self, n=1):
+ self.new_lines = max(self.new_lines, n)
+
+ def body(self, statements):
+ self.new_line = True
+ self.indentation += 1
+ for stmt in statements:
+ self.visit(stmt)
+ self.indentation -= 1
+
+ def body_or_else(self, node):
+ self.body(node.body)
+ if node.orelse:
+ self.newline()
+ self.write('else:')
+ self.body(node.orelse)
+
+ def signature(self, node):
+ want_comma = []
+ def write_comma():
+ if want_comma:
+ self.write(', ')
+ else:
+ want_comma.append(True)
+
+ padding = [None] * (len(node.args) - len(node.defaults))
+ for arg, default in zip(node.args, padding + node.defaults):
+ write_comma()
+ self.visit(arg)
+ if default is not None:
+ self.write('=')
+ self.visit(default)
+ if node.vararg is not None:
+ write_comma()
+ self.write('*' + node.vararg)
+ if node.kwarg is not None:
+ write_comma()
+ self.write('**' + node.kwarg)
+
+ def decorators(self, node):
+ for decorator in node.decorator_list:
+ self.newline()
+ self.write('@')
+ self.visit(decorator)
+
+ # Statements
+
+ def visit_Assign(self, node):
+ self.newline()
+ for idx, target in enumerate(node.targets):
+ if idx:
+ self.write(', ')
+ self.visit(target)
+ self.write(' = ')
+ self.visit(node.value)
+
+ def visit_AugAssign(self, node):
+ self.newline()
+ self.visit(node.target)
+ self.write(BINOP_SYMBOLS[type(node.op)] + '=')
+ self.visit(node.value)
+
+ def visit_ImportFrom(self, node):
+ self.newline()
+ self.write('from %s%s import ' % ('.' * node.level, node.module))
+ for idx, item in enumerate(node.names):
+ if idx:
+ self.write(', ')
+ self.write(item)
+
+ def visit_Import(self, node):
+ self.newline()
+ for item in node.names:
+ self.write('import ')
+ self.visit(item)
+
+ def visit_Expr(self, node):
+ self.newline()
+ self.generic_visit(node)
+
+ def visit_FunctionDef(self, node):
+ self.newline(n=2)
+ self.decorators(node)
+ self.newline()
+ self.write('def %s(' % node.name)
+ self.signature(node.args)
+ self.write('):')
+ self.body(node.body)
+
+ def visit_ClassDef(self, node):
+ have_args = []
+ def paren_or_comma():
+ if have_args:
+ self.write(', ')
+ else:
+ have_args.append(True)
+ self.write('(')
+
+ self.newline(n=3)
+ self.decorators(node)
+ self.newline()
+ self.write('class %s' % node.name)
+ for base in node.bases:
+ paren_or_comma()
+ self.visit(base)
+ # XXX: the if here is used to keep this module compatible
+ # with python 2.6.
+ if hasattr(node, 'keywords'):
+ for keyword in node.keywords:
+ paren_or_comma()
+ self.write(keyword.arg + '=')
+ self.visit(keyword.value)
+ if node.starargs is not None:
+ paren_or_comma()
+ self.write('*')
+ self.visit(node.starargs)
+ if node.kwargs is not None:
+ paren_or_comma()
+ self.write('**')
+ self.visit(node.kwargs)
+ self.write(have_args and '):' or ':')
+ self.body(node.body)
+
+ def visit_If(self, node):
+ self.newline()
+ self.write('if ')
+ self.visit(node.test)
+ self.write(':')
+ self.body(node.body)
+ while True:
+ else_ = node.orelse
+ if len(else_) == 1 and isinstance(else_[0], If):
+ node = else_[0]
+ self.newline()
+ self.write('elif ')
+ self.visit(node.test)
+ self.write(':')
+ self.body(node.body)
+ else:
+ self.newline()
+ self.write('else:')
+ self.body(else_)
+ break
+
+ def visit_For(self, node):
+ self.newline()
+ self.write('for ')
+ self.visit(node.target)
+ self.write(' in ')
+ self.visit(node.iter)
+ self.write(':')
+ self.body_or_else(node)
+
+ def visit_While(self, node):
+ self.newline()
+ self.write('while ')
+ self.visit(node.test)
+ self.write(':')
+ self.body_or_else(node)
+
+ def visit_With(self, node):
+ self.newline()
+ self.write('with ')
+ self.visit(node.context_expr)
+ if node.optional_vars is not None:
+ self.write(' as ')
+ self.visit(node.optional_vars)
+ self.write(':')
+ self.body(node.body)
+
+ def visit_Pass(self, node):
+ self.newline()
+ self.write('pass')
+
+ def visit_Print(self, node):
+ # XXX: python 2.6 only
+ self.newline()
+ self.write('print ')
+ want_comma = False
+ if node.dest is not None:
+ self.write(' >> ')
+ self.visit(node.dest)
+ want_comma = True
+ for value in node.values:
+ if want_comma:
+ self.write(', ')
+ self.visit(value)
+ want_comma = True
+ if not node.nl:
+ self.write(',')
+
+ def visit_Delete(self, node):
+ self.newline()
+ self.write('del ')
+ for idx, target in enumerate(node):
+ if idx:
+ self.write(', ')
+ self.visit(target)
+
+ def visit_TryExcept(self, node):
+ self.newline()
+ self.write('try:')
+ self.body(node.body)
+ for handler in node.handlers:
+ self.visit(handler)
+
+ def visit_TryFinally(self, node):
+ self.newline()
+ self.write('try:')
+ self.body(node.body)
+ self.newline()
+ self.write('finally:')
+ self.body(node.finalbody)
+
+ def visit_Global(self, node):
+ self.newline()
+ self.write('global ' + ', '.join(node.names))
+
+ def visit_Nonlocal(self, node):
+ self.newline()
+ self.write('nonlocal ' + ', '.join(node.names))
+
+ def visit_Return(self, node):
+ self.newline()
+ self.write('return ')
+ self.visit(node.value)
+
+ def visit_Break(self, node):
+ self.newline()
+ self.write('break')
+
+ def visit_Continue(self, node):
+ self.newline()
+ self.write('continue')
+
+ def visit_Raise(self, node):
+ # XXX: Python 2.6 / 3.0 compatibility
+ self.newline()
+ self.write('raise')
+ if hasattr(node, 'exc') and node.exc is not None:
+ self.write(' ')
+ self.visit(node.exc)
+ if node.cause is not None:
+ self.write(' from ')
+ self.visit(node.cause)
+ elif hasattr(node, 'type') and node.type is not None:
+ self.visit(node.type)
+ if node.inst is not None:
+ self.write(', ')
+ self.visit(node.inst)
+ if node.tback is not None:
+ self.write(', ')
+ self.visit(node.tback)
+
+ # Expressions
+
+ def visit_Attribute(self, node):
+ self.visit(node.value)
+ self.write('.' + node.attr)
+
+ def visit_Call(self, node):
+ want_comma = []
+ def write_comma():
+ if want_comma:
+ self.write(', ')
+ else:
+ want_comma.append(True)
+
+ self.visit(node.func)
+ self.write('(')
+ for arg in node.args:
+ write_comma()
+ self.visit(arg)
+ for keyword in node.keywords:
+ write_comma()
+ self.write(keyword.arg + '=')
+ self.visit(keyword.value)
+ if node.starargs is not None:
+ write_comma()
+ self.write('*')
+ self.visit(node.starargs)
+ if node.kwargs is not None:
+ write_comma()
+ self.write('**')
+ self.visit(node.kwargs)
+ self.write(')')
+
+ def visit_Name(self, node):
+ self.write(node.id)
+
+ def visit_Str(self, node):
+ self.write(repr(node.s))
+
+ def visit_Bytes(self, node):
+ self.write(repr(node.s))
+
+ def visit_Num(self, node):
+ self.write(repr(node.n))
+
+ def visit_Tuple(self, node):
+ self.write('(')
+ idx = -1
+ for idx, item in enumerate(node.elts):
+ if idx:
+ self.write(', ')
+ self.visit(item)
+ self.write(idx and ')' or ',)')
+
+ def sequence_visit(left, right):
+ def visit(self, node):
+ self.write(left)
+ for idx, item in enumerate(node.elts):
+ if idx:
+ self.write(', ')
+ self.visit(item)
+ self.write(right)
+ return visit
+
+ visit_List = sequence_visit('[', ']')
+ visit_Set = sequence_visit('{', '}')
+ del sequence_visit
+
+ def visit_Dict(self, node):
+ self.write('{')
+ for idx, (key, value) in enumerate(zip(node.keys, node.values)):
+ if idx:
+ self.write(', ')
+ self.visit(key)
+ self.write(': ')
+ self.visit(value)
+ self.write('}')
+
+ def visit_BinOp(self, node):
+ self.write('(')
+ self.visit(node.left)
+ self.write(' %s ' % BINOP_SYMBOLS[type(node.op)])
+ self.visit(node.right)
+ self.write(')')
+
+ def visit_BoolOp(self, node):
+ self.write('(')
+ for idx, value in enumerate(node.values):
+ if idx:
+ self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)])
+ self.visit(value)
+ self.write(')')
+
+ def visit_Compare(self, node):
+ self.write('(')
+ self.visit(node.left)
+ for op, right in zip(node.ops, node.comparators):
+ self.write(' %s ' % CMPOP_SYMBOLS[type(op)])
+ self.visit(right)
+ self.write(')')
+
+ def visit_UnaryOp(self, node):
+ self.write('(')
+ op = UNARYOP_SYMBOLS[type(node.op)]
+ self.write(op)
+ if op == 'not':
+ self.write(' ')
+ self.visit(node.operand)
+ self.write(')')
+
+ def visit_Subscript(self, node):
+ self.visit(node.value)
+ self.write('[')
+ self.visit(node.slice)
+ self.write(']')
+
+ def visit_Slice(self, node):
+ if node.lower is not None:
+ self.visit(node.lower)
+ self.write(':')
+ if node.upper is not None:
+ self.visit(node.upper)
+ if node.step is not None:
+ self.write(':')
+ if not (isinstance(node.step, Name) and node.step.id == 'None'):
+ self.visit(node.step)
+
+ def visit_ExtSlice(self, node):
+ for idx, item in node.dims:
+ if idx:
+ self.write(', ')
+ self.visit(item)
+
+ def visit_Yield(self, node):
+ self.write('yield ')
+ self.visit(node.value)
+
+ def visit_Lambda(self, node):
+ self.write('lambda ')
+ self.signature(node.args)
+ self.write(': ')
+ self.visit(node.body)
+
+ def visit_Ellipsis(self, node):
+ self.write('Ellipsis')
+
+ def generator_visit(left, right):
+ def visit(self, node):
+ self.write(left)
+ self.visit(node.elt)
+ for comprehension in node.generators:
+ self.visit(comprehension)
+ self.write(right)
+ return visit
+
+ visit_ListComp = generator_visit('[', ']')
+ visit_GeneratorExp = generator_visit('(', ')')
+ visit_SetComp = generator_visit('{', '}')
+ del generator_visit
+
+ def visit_DictComp(self, node):
+ self.write('{')
+ self.visit(node.key)
+ self.write(': ')
+ self.visit(node.value)
+ for comprehension in node.generators:
+ self.visit(comprehension)
+ self.write('}')
+
+ def visit_IfExp(self, node):
+ self.visit(node.body)
+ self.write(' if ')
+ self.visit(node.test)
+ self.write(' else ')
+ self.visit(node.orelse)
+
+ def visit_Starred(self, node):
+ self.write('*')
+ self.visit(node.value)
+
+ def visit_Repr(self, node):
+ # XXX: python 2.6 only
+ self.write('`')
+ self.visit(node.value)
+ self.write('`')
+
+ # Helper Nodes
+
+ def visit_alias(self, node):
+ self.write(node.name)
+ if node.asname is not None:
+ self.write(' as ' + node.asname)
+
+ def visit_comprehension(self, node):
+ self.write(' for ')
+ self.visit(node.target)
+ self.write(' in ')
+ self.visit(node.iter)
+ if node.ifs:
+ for if_ in node.ifs:
+ self.write(' if ')
+ self.visit(if_)
+
+ def visit_excepthandler(self, node):
+ self.newline()
+ self.write('except')
+ if node.type is not None:
+ self.write(' ')
+ self.visit(node.type)
+ if node.name is not None:
+ self.write(' as ')
+ self.visit(node.name)
+ self.write(':')
+ self.body(node.body)
Added: pypy/benchmarks/lib/mako/mako/ast.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/ast.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,143 @@
+# ast.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""utilities for analyzing expressions and blocks of Python
+code, as well as generating Python from AST nodes"""
+
+from mako import exceptions, pyparser, util
+import re
+
+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,
+ # code.co_names has several advantages:
+ # - we can locate an identifier as "undeclared" even if
+ # its declared later in the same block of code
+ # - AST is less likely to break with version changes
+ # (for example, the behavior of co_names changed a little bit
+ # in python version 2.5)
+ if isinstance(code, basestring):
+ expr = pyparser.parse(code.lstrip(), "exec", **exception_kwargs)
+ else:
+ expr = code
+
+ f = pyparser.FindIdentifiers(self, **exception_kwargs)
+ f.visit(expr)
+
+class ArgumentList(object):
+ """parses a fragment of code as a comma-separated list of expressions"""
+ def __init__(self, code, **exception_kwargs):
+ self.codeargs = []
+ self.args = []
+ self.declared_identifiers = set()
+ self.undeclared_identifiers = set()
+ if isinstance(code, basestring):
+ if re.match(r"\S", code) and not re.match(r",\s*$", code):
+ # if theres text and no trailing comma, insure its parsed
+ # as a tuple by adding a trailing comma
+ code += ","
+ expr = pyparser.parse(code, "exec", **exception_kwargs)
+ else:
+ expr = code
+
+ 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:
+ except (MyException, e):
+ etc.
+ """
+ def __init__(self, code, **exception_kwargs):
+ m = re.match(r'^(\w+)(?:\s+(.*?))?:\s*(#|$)', code.strip(), re.S)
+ if not m:
+ raise exceptions.CompileException(
+ "Fragment '%s' is not a partial control statement" %
+ code, **exception_kwargs)
+ if m.group(3):
+ code = code[:m.start(3)]
+ (keyword, expr) = m.group(1,2)
+ if keyword in ['for','if', 'while']:
+ code = code + "pass"
+ elif keyword == 'try':
+ code = code + "pass\nexcept:pass"
+ elif keyword == 'elif' or keyword == 'else':
+ code = "if False:pass\n" + code + "pass"
+ elif keyword == 'except':
+ code = "try:pass\n" + code + "pass"
+ else:
+ raise exceptions.CompileException(
+ "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'):
+ raise exceptions.CompileException(
+ "Code '%s' is not a function declaration" % code,
+ **exception_kwargs)
+ if not allow_kwargs and self.kwargs:
+ 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
+ varargs = self.varargs
+ argnames = [f for f in self.argnames]
+ argnames.reverse()
+ for arg in argnames:
+ default = None
+ if kwargs:
+ arg = "**" + arg
+ kwargs = False
+ elif varargs:
+ arg = "*" + arg
+ varargs = False
+ else:
+ default = len(defaults) and defaults.pop() or None
+ if include_defaults and default:
+ namedecls.insert(0, "%s=%s" %
+ (arg,
+ pyparser.ExpressionGenerator(default).value()
+ )
+ )
+ else:
+ namedecls.insert(0, arg)
+ return namedecls
+
+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)
Added: pypy/benchmarks/lib/mako/mako/cache.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/cache.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,118 @@
+from mako import exceptions
+
+cache = None
+
+class BeakerMissing(object):
+ def get_cache(self, name, **kwargs):
+ raise exceptions.RuntimeException("the Beaker package is required to use cache functionality.")
+
+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:
+ try:
+ from beaker import cache as beaker_cache
+ cache = beaker_cache.CacheManager()
+ except ImportError:
+ # keep a fake cache around so subsequent
+ # calls don't attempt to re-import
+ cache = BeakerMissing()
+
+ if type == 'memcached':
+ type = 'ext:memcached'
+ if not type:
+ (type, kw) = self.def_regions.get(defname, ('memory', {}))
+ else:
+ self.def_regions[defname] = (type, kw)
+ return cache.get_cache(self.id, type=type, **kw)
+
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/mako/codegen.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/codegen.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,958 @@
+# codegen.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""provides functionality for rendering a parsetree constructing into module source code."""
+
+import time
+import re
+from mako.pygen import PythonPrinter
+from mako import util, ast, parsetree, filters
+
+MAGIC_NUMBER = 5
+
+def compile(node,
+ uri,
+ filename=None,
+ default_filters=None,
+ buffer_filters=None,
+ imports=None,
+ source_encoding=None,
+ generate_magic_comment=True,
+ disable_unicode=False,
+ strict_undefined=False):
+
+ """Generate module source code given a parsetree node,
+ uri, and optional source filename"""
+
+ # if on Py2K, push the "source_encoding" string to be
+ # a bytestring itself, as we will be embedding it into
+ # the generated source and we don't want to coerce the
+ # result into a unicode object, in "disable_unicode" mode
+ if not util.py3k and isinstance(source_encoding, unicode):
+ source_encoding = source_encoding.encode(source_encoding)
+
+
+ buf = util.FastEncodingBuffer()
+
+ printer = PythonPrinter(buf)
+ _GenerateRenderMethod(printer,
+ _CompileContext(uri,
+ filename,
+ default_filters,
+ buffer_filters,
+ imports,
+ source_encoding,
+ generate_magic_comment,
+ disable_unicode,
+ strict_undefined),
+ node)
+ return buf.getvalue()
+
+class _CompileContext(object):
+ def __init__(self,
+ uri,
+ filename,
+ default_filters,
+ buffer_filters,
+ imports,
+ source_encoding,
+ generate_magic_comment,
+ disable_unicode,
+ strict_undefined):
+ self.uri = uri
+ self.filename = filename
+ self.default_filters = default_filters
+ self.buffer_filters = buffer_filters
+ self.imports = imports
+ self.source_encoding = source_encoding
+ 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
+ self.last_source_line = -1
+ self.compiler = compiler
+ self.node = node
+ self.identifier_stack = [None]
+
+ self.in_def = isinstance(node, parsetree.DefTag)
+
+ if self.in_def:
+ name = "render_" + node.name
+ args = node.function_decl.get_argument_expressions()
+ filtered = len(node.filter_args.args) > 0
+ buffered = eval(node.attributes.get('buffered', 'False'))
+ cached = eval(node.attributes.get('cached', 'False'))
+ defs = None
+ pagetag = None
+ else:
+ defs = self.write_toplevel()
+ pagetag = self.compiler.pagetag
+ name = "render_body"
+ if pagetag is not None:
+ args = pagetag.body_decl.get_argument_expressions()
+ if not pagetag.body_decl.kwargs:
+ args += ['**pageargs']
+ cached = eval(pagetag.attributes.get('cached', 'False'))
+ else:
+ args = ['**pageargs']
+ cached = False
+ buffered = filtered = False
+ if args is None:
+ 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 = {}
+ module_code = []
+ encoding =[None]
+
+ self.compiler.pagetag = None
+
+ class FindTopLevel(object):
+ def visitInheritTag(s, node):
+ inherit.append(node)
+ def visitNamespaceTag(s, node):
+ namespaces[node.name] = node
+ def visitPageTag(s, node):
+ self.compiler.pagetag = node
+ def visitCode(s, node):
+ if node.ismodule:
+ module_code.append(node)
+
+ f = FindTopLevel()
+ for n in self.node.nodes:
+ n.accept_visitor(f)
+
+ self.compiler.namespaces = namespaces
+
+ module_ident = set()
+ for n in module_code:
+ module_ident = module_ident.union(n.declared_identifiers())
+
+ 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")
+ self.printer.writeline("__M_locals_builtin = locals")
+ self.printer.writeline("_magic_number = %r" % MAGIC_NUMBER)
+ self.printer.writeline("_modified_time = %r" % time.time())
+ self.printer.writeline(
+ "_template_filename=%r" % self.compiler.filename)
+ self.printer.writeline("_template_uri=%r" % self.compiler.uri)
+ self.printer.writeline(
+ "_template_cache=cache.Cache(__name__, _modified_time)")
+ self.printer.writeline(
+ "_source_encoding=%r" % self.compiler.source_encoding)
+ if self.compiler.imports:
+ buf = ''
+ for imp in self.compiler.imports:
+ buf += imp + "\n"
+ self.printer.writeline(imp)
+ impcode = ast.PythonCode(
+ buf,
+ source='', lineno=0,
+ pos=0,
+ filename='template defined imports')
+ else:
+ impcode = None
+
+ main_identifiers = module_identifiers.branch(self.node)
+ module_identifiers.topleveldefs = \
+ module_identifiers.topleveldefs.\
+ union(main_identifiers.topleveldefs)
+ 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
+ main_identifiers.topleveldefs.values()]
+ )
+ self.printer.write("\n\n")
+
+ if len(module_code):
+ self.write_module_code(module_code)
+
+ if len(inherit):
+ self.write_namespaces(namespaces)
+ self.write_inherit(inherit[-1])
+ elif len(namespaces):
+ self.write_namespaces(namespaces)
+
+ return main_identifiers.topleveldefs.values()
+
+ 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()",
+ "try:"
+ )
+ 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')
+
+ if not self.in_def and (
+ len(self.identifiers.locally_assigned) > 0 or
+ len(self.identifiers.argument_declared) > 0
+ ):
+ self.printer.writeline("__M_locals = __M_dict_builtin(%s)" %
+ ','.join([
+ "%s=%s" % (x, x) for x in
+ self.identifiers.argument_declared
+ ]))
+
+ self.write_variable_declares(self.identifiers, toplevel=True)
+
+ for n in self.node.nodes:
+ n.accept_visitor(self)
+
+ self.write_def_finish(self.node, buffered, filtered, cached)
+ self.printer.writeline(None)
+ self.printer.write("\n\n")
+ if cached:
+ self.write_cache_decorator(
+ 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."""
+ for n in module_code:
+ self.write_source_comment(n)
+ self.printer.write_indented_block(n.text)
+
+ def write_inherit(self, node):
+ """write the module-level inheritance-determination callable."""
+
+ self.printer.writelines(
+ "def _mako_inherit(template, context):",
+ "_mako_generate_namespaces(context)",
+ "return runtime._inherit_from(context, %s, _template_uri)" %
+ (node.parsed_attributes['file']),
+ None
+ )
+
+ def write_namespaces(self, namespaces):
+ """write the module-level namespace-generating callable."""
+ self.printer.writelines(
+ "def _mako_get_namespace(context, name):",
+ "try:",
+ "return context.namespaces[(__name__, name)]",
+ "except KeyError:",
+ "_mako_generate_namespaces(context)",
+ "return context.namespaces[(__name__, name)]",
+ None,None
+ )
+ 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
+ self.write_source_comment(node)
+ if len(node.nodes):
+ self.printer.writeline("def make_namespace():")
+ export = []
+ identifiers = self.compiler.identifiers.branch(node)
+ self.in_def = True
+ class NSDefVisitor(object):
+ def visitDefTag(s, node):
+ self.write_inline_def(node, identifiers, nested=False)
+ export.append(node.name)
+ vis = NSDefVisitor()
+ for n in node.nodes:
+ n.accept_visitor(vis)
+ self.printer.writeline("return [%s]" % (','.join(export)))
+ self.printer.writeline(None)
+ self.in_def = False
+ callable_name = "make_namespace()"
+ else:
+ callable_name = "None"
+ self.printer.writeline(
+ "ns = runtime.Namespace(%r, context._clean_inheritance_tokens(),"
+ " templateuri=%s, callables=%s, calling_uri=_template_uri, module=%s)" %
+ (
+ node.name,
+ node.parsed_attributes.get('file', 'None'),
+ callable_name,
+ node.parsed_attributes.get('module', 'None'))
+ )
+ 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
+ on the names that are referenced in the function body,
+ which don't otherwise have any explicit assignment
+ 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()])
+
+ # remove identifiers that are declared in the argument
+ # signature of the callable
+ to_write = to_write.difference(identifiers.argument_declared)
+
+ # remove identifiers that we are going to assign to.
+ # 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.
+ 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
+ for ident, ns in self.compiler.namespaces.iteritems():
+ if ns.attributes.has_key('import'):
+ self.printer.writeline(
+ "_mako_get_namespace(context, %r)._populate(_import_ns, %r)" %
+ (
+ ident,
+ re.split(r'\s*,\s*', ns.attributes['import'])
+ ))
+
+ for ident in to_write:
+ if ident in comp_idents:
+ comp = comp_idents[ident]
+ if comp.is_root():
+ self.write_def_decl(comp, identifiers)
+ else:
+ self.write_inline_def(comp, identifiers, nested=True)
+ elif ident in self.compiler.namespaces:
+ self.printer.writeline(
+ "%s = _mako_get_namespace(context, %r)" %
+ (ident, ident)
+ )
+ else:
+ if getattr(self.compiler, 'has_ns_imports', False):
+ if self.compiler.strict_undefined:
+ self.printer.writelines(
+ "%s = _import_ns.get(%r, UNDEFINED)" %
+ (ident, ident),
+ "if %s is UNDEFINED:" % ident,
+ "try:",
+ "%s = context[%r]" % (ident, ident),
+ "except KeyError:",
+ "raise NameError(\"'%s' is not defined\")" %
+ ident,
+ None, None
+ )
+ else:
+ self.printer.writeline(
+ "%s = _import_ns.get(%r, context.get(%r, UNDEFINED))" %
+ (ident, ident, ident))
+ else:
+ if self.compiler.strict_undefined:
+ self.printer.writelines(
+ "try:",
+ "%s = context[%r]" % (ident, ident),
+ "except KeyError:",
+ "raise NameError(\"'%s' is not defined\")" %
+ ident,
+ None
+ )
+ else:
+ 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:
+ self.printer.writeline("# SOURCE LINE %d" % node.lineno)
+ self.last_source_line = node.lineno
+
+ def write_def_decl(self, node, identifiers):
+ """write a locally-available callable referencing a top-level def"""
+ 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):
+ nameargs.insert(0, 'context.locals_(__M_locals)')
+ else:
+ nameargs.insert(0, 'context')
+ 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)
+ self.printer.writeline("def %s(%s):" % (node.name, ",".join(namedecls)))
+ filtered = len(node.filter_args.args) > 0
+ buffered = eval(node.attributes.get('buffered', 'False'))
+ cached = eval(node.attributes.get('cached', 'False'))
+ self.printer.writelines(
+ "context.caller_stack._push_frame()",
+ "try:"
+ )
+ if buffered or filtered or cached:
+ self.printer.writelines(
+ "context._push_buffer()",
+ )
+
+ 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:
+ self.printer.writelines(
+ "finally:",
+ "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
+ # from the context after popping; assume the caching
+ # implemenation might be using a context with no
+ # extra buffers
+ self.printer.writelines(
+ "finally:",
+ "__M_buf = context._pop_buffer()"
+ )
+ else:
+ self.printer.writelines(
+ "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)
+ self.printer.writeline(None)
+ if buffered and not cached:
+ s = self.create_filter_callable(self.compiler.buffer_filters, s, False)
+ if buffered or cached:
+ self.printer.writeline("return %s" % s)
+ else:
+ self.printer.writelines(
+ "__M_writer(%s)" % s,
+ "return ''"
+ )
+
+ def write_cache_decorator(self, node_or_pagetag, name,
+ args, buffered, identifiers,
+ inline=False, toplevel=False):
+ """write a post-function decorator to replace a rendering
+ 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 = {}
+ for arg in (
+ ('cache_type', 'type'), ('cache_dir', 'data_dir'),
+ ('cache_timeout', 'expiretime'), ('cache_url', 'url')):
+ val = node_or_pagetag.parsed_attributes.get(arg[0], None)
+ if val is not None:
+ if arg[1] == 'expiretime':
+ cacheargs[arg[1]] = int(eval(val))
+ else:
+ cacheargs[arg[1]] = val
+ else:
+ if self.compiler.pagetag is not None:
+ val = self.compiler.pagetag.parsed_attributes.get(arg[0], None)
+ if val is not None:
+ if arg[1] == 'expiretime':
+ 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
+ for a in args
+ ]
+
+ self.write_variable_declares(
+ identifiers,
+ toplevel=toplevel,
+ limit=node_or_pagetag.undeclared_identifiers()
+ )
+ if buffered:
+ s = "context.get('local')."\
+ "get_cached(%s, defname=%r, %screatefunc=lambda:__M_%s(%s))" % \
+ (cachekey, name,
+ ''.join(["%s=%s, " % (k,v) for k, v in cacheargs.iteritems()]),
+ name, ','.join(pass_args))
+ # apply buffer_filters
+ s = self.create_filter_callable(self.compiler.buffer_filters, s, False)
+ self.printer.writelines("return " + s,None)
+ else:
+ self.printer.writelines(
+ "__M_writer(context.get('local')."
+ "get_cached(%s, defname=%r, %screatefunc=lambda:__M_%s(%s)))" %
+ (cachekey, name,
+ ''.join(["%s=%s, " % (k,v) for k, v in cacheargs.iteritems()]),
+ name, ','.join(pass_args)),
+ "return ''",
+ None
+ )
+
+ def create_filter_callable(self, args, target, is_expression):
+ """write a filter-applying expression based on the filters
+ present in the given filter names, adjusting for the global
+ 'default' filter aliases as needed."""
+
+ def locate_encode(name):
+ if re.match(r'decode\..+', name):
+ return "filters." + name
+ elif self.compiler.disable_unicode:
+ 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:
+ args = self.compiler.pagetag.filter_args.args + args
+ if self.compiler.default_filters:
+ args = self.compiler.default_filters + args
+ for e in args:
+ # if filter given as a function, get just the identifier portion
+ if e == 'n':
+ continue
+ m = re.match(r'(.+?)(\(.*\))', e)
+ if m:
+ (ident, fargs) = m.group(1,2)
+ f = locate_encode(ident)
+ e = f + fargs
+ else:
+ x = e
+ e = locate_encode(e)
+ 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 \
+ (
+ self.compiler.pagetag is not None and
+ 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():
+ self.printer.writeline("pass")
+ self.printer.writeline(None)
+ 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:
+ self.printer.writelines(
+ "__M_writer = context._push_writer()",
+ "try:",
+ )
+ for n in node.nodes:
+ n.accept_visitor(self)
+ if filtered:
+ self.printer.writelines(
+ "finally:",
+ "__M_buf, __M_writer = context._pop_buffer_and_writer()",
+ "__M_writer(%s)" %
+ self.create_filter_callable(
+ node.filter_args.args,
+ "__M_buf.getvalue()",
+ False),
+ None
+ )
+
+ def visitCode(self, node):
+ if not node.ismodule:
+ self.write_source_comment(node)
+ self.printer.write_indented_block(node.text)
+
+ if not self.in_def and len(self.identifiers.locally_assigned) > 0:
+ # if we are the "template" def, fudge locally
+ # declared/modified variables into the "__M_locals" dictionary,
+ # which is used for def calls within the same template,
+ # to simulate "enclosing scope"
+ self.printer.writeline('__M_locals_builtin_stored = __M_locals_builtin()')
+ self.printer.writeline(
+ '__M_locals.update(__M_dict_builtin([(__M_key,'
+ ' __M_locals_builtin_stored[__M_key]) for '
+ '__M_key in [%s] if __M_key in __M_locals_builtin_stored]))' %
+ ','.join([repr(x) for x in node.declared_identifiers()]))
+
+ def visitIncludeTag(self, node):
+ self.write_source_comment(node)
+ args = node.attributes.get('args')
+ if args:
+ self.printer.writeline(
+ "runtime._include_file(context, %s, _template_uri, %s)" %
+ (node.parsed_attributes['file'], args))
+ else:
+ self.printer.writeline(
+ "runtime._include_file(context, %s, _template_uri)" %
+ (node.parsed_attributes['file']))
+
+ def visitNamespaceTag(self, node):
+ pass
+
+ def visitDefTag(self, node):
+ pass
+
+ def visitCallNamespaceTag(self, node):
+ # TODO: we can put namespace-specific checks here, such
+ # as ensure the given namespace will be imported,
+ # pre-import the namespace, etc.
+ self.visitCallTag(node)
+
+ def visitCallTag(self, node):
+ self.printer.writeline("def ccall(caller):")
+ export = ['body']
+ callable_identifiers = self.identifiers.branch(node, nested=True)
+ body_identifiers = callable_identifiers.branch(node, nested=False)
+ # we want the 'caller' passed to ccall to be used
+ # for the body() function, but for other non-body()
+ # <%def>s within <%call> we want the current caller
+ # off the call stack (if any)
+ body_identifiers.add_declared('caller')
+
+ self.identifier_stack.append(body_identifiers)
+ class DefVisitor(object):
+ def visitDefTag(s, node):
+ self.write_inline_def(node, callable_identifiers, nested=False)
+ export.append(node.name)
+ # remove defs that are within the <%call> from the "closuredefs" defined
+ # in the body, so they dont render twice
+ if node.name in body_identifiers.closuredefs:
+ del body_identifiers.closuredefs[node.name]
+
+ vis = DefVisitor()
+ for n in node.nodes:
+ n.accept_visitor(vis)
+ self.identifier_stack.pop()
+
+ 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
+ if buffered:
+ self.printer.writelines(
+ "context._push_buffer()",
+ "try:"
+ )
+ 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,
+ "return [%s]" % (','.join(export)),
+ None
+ )
+
+ self.printer.writelines(
+ # get local reference to current caller, if any
+ "caller = context.caller_stack._get_caller()",
+ # push on caller for nested call
+ "context.caller_stack.nextcaller = "
+ "runtime.Namespace('caller', context, callables=ccall(caller))",
+ "try:")
+ self.write_source_comment(node)
+ self.printer.writelines(
+ "__M_writer(%s)" % self.create_filter_callable([], node.expression, True),
+ "finally:",
+ "context.caller_stack.nextcaller = None",
+ None
+ )
+
+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().
+ if isinstance(node, parsetree.NamespaceTag):
+ self.declared = set()
+ self.topleveldefs = util.SetLikeDict()
+ else:
+ # things that have already been declared
+ # in an enclosing namespace (i.e. names we can just use)
+ self.declared = set(parent.declared).\
+ union([c.name for c in parent.closuredefs.values()]).\
+ union(parent.locally_declared).\
+ union(parent.argument_declared)
+
+ # if these identifiers correspond to a "nested"
+ # scope, it means whatever the parent identifiers
+ # had as undeclared will have been declared by that parent,
+ # 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.
+ # 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)" %\
+ (
+ list(self.declared),
+ list(self.locally_declared),
+ list(self.undeclared),
+ [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
+ # write_namespaces()
+ 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
+ elif node is not self.node:
+ self.closuredefs[node.name] = node
+
+ 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():
+ if ident != 'context' and ident not in self.declared.union(self.locally_declared):
+ self.undeclared.add(ident)
+ for ident in node.declared_identifiers():
+ self.argument_declared.add(ident)
+ for n in node.nodes:
+ n.accept_visitor(self)
+ else:
+ for ident in node.undeclared_identifiers():
+ if ident != 'context' and ident not in self.declared.union(self.locally_declared):
+ self.undeclared.add(ident)
+
Added: pypy/benchmarks/lib/mako/mako/exceptions.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/exceptions.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,309 @@
+# exceptions.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""exception classes"""
+
+import traceback, sys, re
+from mako import util
+
+class MakoException(Exception):
+ pass
+
+class RuntimeException(MakoException):
+ pass
+
+def _format_filepos(lineno, pos, filename):
+ if filename is None:
+ 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))
+ self.lineno =lineno
+ 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))
+ self.lineno =lineno
+ self.pos = pos
+ self.filename = filename
+ self.source = source
+
+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:
+ self.message = unicode(self.error)
+ except UnicodeError:
+ try:
+ self.message = str(self.error)
+ except UnicodeEncodeError:
+ # Fallback to args as neither unicode nor
+ # str(Exception(u'\xe6')) work in Python < 2.6
+ self.message = self.error.args[0]
+ if not isinstance(self.message, unicode):
+ self.message = unicode(self.message, 'ascii', 'replace')
+
+ def _get_reformatted_records(self, records):
+ for rec in records:
+ if rec[6] is not None:
+ 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):
+ """format a traceback from sys.exc_info() into 7-item tuples,
+ containing the regular four traceback tuple items, plus the original
+ template filename, the line number adjusted relative to the template
+ source, and code line from that line number of the template."""
+
+ import mako.template
+ mods = {}
+ rawrecords = traceback.extract_tb(trcback)
+ new_trcback = []
+ for filename, lineno, function, line in rawrecords:
+ if not line:
+ line = ''
+ try:
+ (line_map, template_lines) = mods[filename]
+ except KeyError:
+ try:
+ info = mako.template._get_module_info(filename)
+ module_source = info.code
+ template_source = info.source
+ template_filename = info.template_filename or filename
+ except KeyError:
+ # A normal .py file (not a Template)
+ if not util.py3k:
+ try:
+ fp = open(filename, 'rb')
+ encoding = util.parse_encoding(fp)
+ fp.close()
+ except IOError:
+ encoding = None
+ if encoding:
+ line = line.decode(encoding)
+ else:
+ line = line.decode('ascii', 'replace')
+ new_trcback.append((filename, lineno, function, line,
+ None, None, None, None))
+ continue
+
+ template_ln = module_ln = 1
+ line_map = {}
+ for line in module_source.split("\n"):
+ match = re.match(r'\s*# SOURCE LINE (\d+)', line)
+ if match:
+ template_ln = int(match.group(1))
+ else:
+ template_ln += 1
+ module_ln += 1
+ line_map[module_ln] = template_ln
+ template_lines = [line for line in
+ template_source.split("\n")]
+ mods[filename] = (line_map, template_lines)
+
+ template_ln = line_map[lineno]
+ if template_ln <= len(template_lines):
+ template_line = template_lines[template_ln - 1]
+ else:
+ template_line = None
+ new_trcback.append((filename, lineno, function,
+ line, template_filename, template_ln,
+ template_line, template_source))
+ if not self.source:
+ for l in range(len(new_trcback)-1, 0, -1):
+ if new_trcback[l][5]:
+ self.source = new_trcback[l][7]
+ self.lineno = new_trcback[l][5]
+ break
+ else:
+ if new_trcback:
+ try:
+ # A normal .py file (not a Template)
+ fp = open(new_trcback[-1][0], 'rb')
+ encoding = util.parse_encoding(fp)
+ fp.seek(0)
+ self.source = fp.read()
+ fp.close()
+ if encoding:
+ self.source = self.source.decode(encoding)
+ except IOError:
+ self.source = ''
+ 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"""
+<%page args="error=None, traceback=None"/>
+<%!
+ from mako.exceptions import RichTraceback
+%>\
+<%
+ tback = RichTraceback(error=error, traceback=traceback)
+%>\
+Traceback (most recent call last):
+% for (filename, lineno, function, line) in tback.traceback:
+ File "${filename}", line ${lineno}, in ${function or '?'}
+ ${line | trim}
+% endfor
+${tback.errorname}: ${tback.message}
+""")
+
+def html_error_template():
+ """Provides a template that renders a stack trace in an HTML format,
+ providing an excerpt of code as well as substituting source template
+ filenames, line numbers and code for that of the originating source
+ template, as applicable.
+
+ The template's default encoding_errors value is 'htmlentityreplace'. the
+ 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"""
+<%!
+ from mako.exceptions import RichTraceback
+%>
+<%page args="full=True, css=True, error=None, traceback=None"/>
+% if full:
+<html>
+<head>
+ <title>Mako Runtime Error</title>
+% endif
+% if css:
+ <style>
+ body { font-family:verdana; margin:10px 30px 10px 30px;}
+ .stacktrace { margin:5px 5px 5px 5px; }
+ .highlight { padding:0px 10px 0px 10px; background-color:#9F9FDF; }
+ .nonhighlight { padding:0px; background-color:#DFDFDF; }
+ .sample { padding:10px; margin:10px 10px 10px 10px; font-family:monospace; }
+ .sampleline { padding:0px 10px 0px 10px; }
+ .sourceline { margin:5px 5px 10px 5px; font-family:monospace;}
+ .location { font-size:80%; }
+ </style>
+% endif
+% if full:
+</head>
+<body>
+% endif
+
+<h2>Error !</h2>
+<%
+ tback = RichTraceback(error=error, traceback=traceback)
+ src = tback.source
+ line = tback.lineno
+ if src:
+ lines = src.split('\n')
+ else:
+ lines = None
+%>
+<h3>${tback.errorname}: ${tback.message}</h3>
+
+% if lines:
+ <div class="sample">
+ <div class="nonhighlight">
+% for index in range(max(0, line-4),min(len(lines), line+5)):
+ % if index + 1 == line:
+<div class="highlight">${index + 1} ${lines[index] | h}</div>
+ % else:
+<div class="sampleline">${index + 1} ${lines[index] | h}</div>
+ % endif
+% endfor
+ </div>
+ </div>
+% endif
+
+<div class="stacktrace">
+% for (filename, lineno, function, line) in tback.reverse_traceback:
+ <div class="location">${filename}, line ${lineno}:</div>
+ <div class="sourceline">${line | h}</div>
+% endfor
+</div>
+
+% if full:
+</body>
+</html>
+% endif
+""", output_encoding=sys.getdefaultencoding(), encoding_errors='htmlentityreplace')
Added: pypy/benchmarks/lib/mako/mako/ext/__init__.py
==============================================================================
Added: pypy/benchmarks/lib/mako/mako/ext/autohandler.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/ext/autohandler.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,59 @@
+"""adds autohandler functionality to Mako templates.
+
+requires that the TemplateLookup class is used with templates.
+
+usage:
+
+<%!
+ from mako.ext.autohandler import autohandler
+%>
+<%inherit file="${autohandler(template, context)}"/>
+
+
+or with custom autohandler filename:
+
+<%!
+ from mako.ext.autohandler import autohandler
+%>
+<%inherit file="${autohandler(template, context, name='somefilename')}"/>
+
+"""
+
+import posixpath, os, re
+
+def autohandler(template, context, name='autohandler'):
+ lookup = context.lookup
+ _template_uri = template.module._template_uri
+ if not lookup.filesystem_checks:
+ try:
+ return lookup._uri_cache[(autohandler, _template_uri, name)]
+ except KeyError:
+ pass
+
+ tokens = re.findall(r'([^/]+)', posixpath.dirname(_template_uri)) + [name]
+ while len(tokens):
+ path = '/' + '/'.join(tokens)
+ if path != _template_uri and _file_exists(lookup, path):
+ if not lookup.filesystem_checks:
+ return lookup._uri_cache.setdefault(
+ (autohandler, _template_uri, name), path)
+ else:
+ return path
+ if len(tokens) == 1:
+ break
+ tokens[-2:] = [name]
+
+ if not lookup.filesystem_checks:
+ return lookup._uri_cache.setdefault(
+ (autohandler, _template_uri, name), None)
+ else:
+ return None
+
+def _file_exists(lookup, path):
+ psub = re.sub(r'^/', '',path)
+ for d in lookup.directories:
+ if os.path.exists(d + '/' + psub):
+ return True
+ else:
+ return False
+
Added: pypy/benchmarks/lib/mako/mako/ext/babelplugin.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/ext/babelplugin.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,123 @@
+"""gettext message extraction via Babel: http://babel.edgewall.org/"""
+from StringIO import StringIO
+
+from babel.messages.extract import extract_python
+
+from mako import lexer, parsetree
+
+def extract(fileobj, keywords, comment_tags, options):
+ """Extract messages from Mako templates.
+
+ :param fileobj: the file-like object the messages should be extracted from
+ :param keywords: a list of keywords (i.e. function names) that should be
+ recognized as translation functions
+ :param comment_tags: a list of translator tags to search for and include
+ in the results
+ :param options: a dictionary of additional options (optional)
+ :return: an iterator over ``(lineno, funcname, message, comments)`` tuples
+ :rtype: ``iterator``
+ """
+ encoding = options.get('input_encoding', options.get('encoding', None))
+
+ template_node = lexer.Lexer(fileobj.read(),
+ input_encoding=encoding).parse()
+ for extracted in extract_nodes(template_node.get_children(),
+ keywords, comment_tags, options):
+ yield extracted
+
+def extract_nodes(nodes, keywords, comment_tags, options):
+ """Extract messages from Mako's lexer node objects
+
+ :param nodes: an iterable of Mako parsetree.Node objects to extract from
+ :param keywords: a list of keywords (i.e. function names) that should be
+ recognized as translation functions
+ :param comment_tags: a list of translator tags to search for and include
+ in the results
+ :param options: a dictionary of additional options (optional)
+ :return: an iterator over ``(lineno, funcname, message, comments)`` tuples
+ :rtype: ``iterator``
+ """
+ translator_comments = []
+ in_translator_comments = False
+
+ for node in nodes:
+ child_nodes = None
+ if in_translator_comments and isinstance(node, parsetree.Text) and \
+ not node.content.strip():
+ # Ignore whitespace within translator comments
+ continue
+
+ if isinstance(node, parsetree.Comment):
+ value = node.text.strip()
+ if in_translator_comments:
+ translator_comments.extend(_split_comment(node.lineno, value))
+ continue
+ for comment_tag in comment_tags:
+ if value.startswith(comment_tag):
+ in_translator_comments = True
+ translator_comments.extend(_split_comment(node.lineno,
+ value))
+ continue
+
+ if isinstance(node, parsetree.DefTag):
+ code = node.function_decl.code
+ child_nodes = node.nodes
+ elif isinstance(node, parsetree.CallTag):
+ code = node.code.code
+ child_nodes = node.nodes
+ elif isinstance(node, parsetree.PageTag):
+ code = node.body_decl.code
+ elif isinstance(node, parsetree.CallNamespaceTag):
+ attribs = ', '.join(['%s=%s' % (key, val)
+ for key, val in node.attributes.iteritems()])
+ code = '{%s}' % attribs
+ child_nodes = node.nodes
+ elif isinstance(node, parsetree.ControlLine):
+ if node.isend:
+ translator_comments = []
+ in_translator_comments = False
+ continue
+ code = node.text
+ elif isinstance(node, parsetree.Code):
+ # <% and <%! blocks would provide their own translator comments
+ translator_comments = []
+ in_translator_comments = False
+
+ code = node.code.code
+ elif isinstance(node, parsetree.Expression):
+ code = node.code.code
+ else:
+ translator_comments = []
+ in_translator_comments = False
+ continue
+
+ # Comments don't apply unless they immediately preceed the message
+ if translator_comments and \
+ translator_comments[-1][0] < node.lineno - 1:
+ translator_comments = []
+ else:
+ translator_comments = \
+ [comment[1] for comment in translator_comments]
+
+ if isinstance(code, unicode):
+ code = code.encode('ascii', 'backslashreplace')
+ code = StringIO(code)
+ for lineno, funcname, messages, python_translator_comments \
+ in extract_python(code, keywords, comment_tags, options):
+ yield (node.lineno + (lineno - 1), funcname, messages,
+ translator_comments + python_translator_comments)
+
+ translator_comments = []
+ in_translator_comments = False
+
+ if child_nodes:
+ for extracted in extract_nodes(child_nodes, keywords, comment_tags,
+ options):
+ yield extracted
+
+
+def _split_comment(lineno, comment):
+ """Return the multiline comment at lineno split into a list of comment line
+ numbers and the accompanying comment line"""
+ return [(lineno + index, line) for index, line in
+ enumerate(comment.splitlines())]
Added: pypy/benchmarks/lib/mako/mako/ext/preprocessors.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/ext/preprocessors.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,14 @@
+"""preprocessing functions, used with the 'preprocessor'
+argument on Template, TemplateLookup"""
+
+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)
+
Added: pypy/benchmarks/lib/mako/mako/ext/pygmentplugin.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/ext/pygmentplugin.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,101 @@
+import re
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+from pygments.lexers.web import \
+ HtmlLexer, XmlLexer, JavascriptLexer, CssLexer
+from pygments.lexers.agile import PythonLexer
+from pygments.lexer import Lexer, DelegatingLexer, RegexLexer, bygroups, \
+ include, using, this
+from pygments.token import Error, Punctuation, \
+ Text, Comment, Operator, Keyword, Name, String, Number, Other, Literal
+from pygments.util import html_doctype_matches, looks_like_xml
+
+class MakoLexer(RegexLexer):
+ name = 'Mako'
+ aliases = ['mako']
+ filenames = ['*.mao']
+
+ tokens = {
+ 'root': [
+ (r'(\s*)(\%)(\s*end(?:\w+))(\n|\Z)',
+ bygroups(Text, Comment.Preproc, Keyword, Other)),
+ (r'(\s*)(\%(?!%))([^\n]*)(\n|\Z)',
+ bygroups(Text, Comment.Preproc, using(PythonLexer), Other)),
+ (r'(\s*)(##[^\n]*)(\n|\Z)',
+ bygroups(Text, Comment.Preproc, Other)),
+ (r'''(?s)<%doc>.*?</%doc>''', Comment.Preproc),
+ (r'(<%)([\w\.\:]+)', bygroups(Comment.Preproc, Name.Builtin), 'tag'),
+ (r'(</%)([\w\.\:]+)(>)', bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc)),
+ (r'<%(?=([\w\.\:]+))', Comment.Preproc, 'ondeftags'),
+ (r'(<%(?:!?))(.*?)(%>)(?s)', bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
+ (r'(\$\{)(.*?)(\})',
+ bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
+ (r'''(?sx)
+ (.+?) # anything, followed by:
+ (?:
+ (?<=\n)(?=%(?!%)|\#\#) | # an eval or comment line
+ (?=\#\*) | # multiline comment
+ (?=</?%) | # a python block
+ # call start or end
+ (?=\$\{) | # a substitution
+ (?<=\n)(?=\s*%) |
+ # - don't consume
+ (\\\n) | # an escaped newline
+ \Z # end of string
+ )
+ ''', bygroups(Other, Operator)),
+ (r'\s+', Text),
+ ],
+ 'ondeftags': [
+ (r'<%', Comment.Preproc),
+ (r'(?<=<%)(include|inherit|namespace|page)', Name.Builtin),
+ include('tag'),
+ ],
+ 'tag': [
+ (r'((?:\w+)\s*=)\s*(".*?")',
+ bygroups(Name.Attribute, String)),
+ (r'/?\s*>', Comment.Preproc, '#pop'),
+ (r'\s+', Text),
+ ],
+ 'attr': [
+ ('".*?"', String, '#pop'),
+ ("'.*?'", String, '#pop'),
+ (r'[^\s>]+', String, '#pop'),
+ ],
+ }
+
+
+class MakoHtmlLexer(DelegatingLexer):
+ name = 'HTML+Mako'
+ aliases = ['html+mako']
+
+ def __init__(self, **options):
+ super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer,
+ **options)
+
+class MakoXmlLexer(DelegatingLexer):
+ name = 'XML+Mako'
+ aliases = ['xml+mako']
+
+ def __init__(self, **options):
+ super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer,
+ **options)
+
+class MakoJavascriptLexer(DelegatingLexer):
+ name = 'JavaScript+Mako'
+ aliases = ['js+mako', 'javascript+mako']
+
+ def __init__(self, **options):
+ super(MakoJavascriptLexer, self).__init__(JavascriptLexer,
+ MakoLexer, **options)
+
+class MakoCssLexer(DelegatingLexer):
+ name = 'CSS+Mako'
+ aliases = ['css+mako']
+
+ def __init__(self, **options):
+ super(MakoCssLexer, self).__init__(CssLexer, MakoLexer,
+ **options)
Added: pypy/benchmarks/lib/mako/mako/ext/turbogears.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/ext/turbogears.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,50 @@
+import re, inspect
+from mako.lookup import TemplateLookup
+from mako.template import Template
+
+class TGPlugin(object):
+ """TurboGears compatible Template Plugin."""
+
+ def __init__(self, extra_vars_func=None, options=None, extension='mak'):
+ self.extra_vars_func = extra_vars_func
+ self.extension = extension
+ if not options:
+ options = {}
+
+ # Pull the options out and initialize the lookup
+ lookup_options = {}
+ for k, v in options.iteritems():
+ if k.startswith('mako.'):
+ lookup_options[k[5:]] = v
+ 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
+ for kw in inspect.getargspec(Template.__init__)[0]:
+ if kw in lookup_options:
+ self.tmpl_options[kw] = lookup_options[kw]
+
+ def load_template(self, templatename, template_string=None):
+ """Loads a template from a file or a string"""
+ if template_string is not None:
+ return Template(template_string, **self.tmpl_options)
+ # Translate TG dot notation to normal / template path
+ if '/' not in templatename:
+ templatename = '/' + templatename.replace('.', '/') + '.' + self.extension
+
+ # Lookup template
+ return self.lookup.get_template(templatename)
+
+ def render(self, info, format="html", fragment=False, template=None):
+ if isinstance(template, basestring):
+ template = self.load_template(template)
+
+ # Load extra vars func if provided
+ if self.extra_vars_func:
+ info.update(self.extra_vars_func())
+
+ return template.render(**info)
+
Added: pypy/benchmarks/lib/mako/mako/filters.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/filters.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,189 @@
+# filters.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Geoffrey T. Dairiki <dairiki at dairiki.org> and Michael Bayer <mike_mp at zzzcomputing.com>
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+
+import re, urllib, htmlentitydefs, codecs
+from StringIO import StringIO
+from mako import util
+
+xml_escapes = {
+ '&' : '&',
+ '>' : '>',
+ '<' : '<',
+ '"' : '"', # also " in html-only
+ "'" : ''' # also ' in html-only
+}
+
+# XXX: " is valid in HTML and XML
+# ' is not valid HTML, but is valid XML
+
+def legacy_html_escape(string):
+ """legacy HTML escape for non-unicode mode."""
+
+ return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string)
+
+try:
+ import markupsafe
+ def html_escape(string):
+ return markupsafe.escape(string)
+except ImportError:
+ html_escape = legacy_html_escape
+
+
+def xml_escape(string):
+ return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string)
+
+def url_escape(string):
+ # convert into a list of octets
+ string = string.encode("utf8")
+ return urllib.quote_plus(string)
+
+def url_unescape(string):
+ text = urllib.unquote_plus(string)
+ if not is_ascii_str(text):
+ text = text.decode("utf8")
+ return text
+
+def trim(string):
+ return string.strip()
+
+
+class Decode(object):
+ def __getattr__(self, key):
+ def decode(x):
+ if isinstance(x, unicode):
+ return x
+ elif not isinstance(x, str):
+ return unicode(str(x), encoding=key)
+ else:
+ 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):
+ self.codepoint2entity = dict([(c, u'&%s;' % n)
+ for c,n in codepoint2name.iteritems()])
+ self.name2codepoint = name2codepoint
+
+ def escape_entities(self, text):
+ """Replace characters with their character entity references.
+
+ Only characters corresponding to a named entity are replaced.
+ """
+ return unicode(text).translate(self.codepoint2entity)
+
+ def __escape(self, m):
+ codepoint = ord(m.group())
+ try:
+ return self.codepoint2entity[codepoint]
+ except (KeyError, IndexError):
+ return '&#x%X;' % codepoint
+
+
+ __escapable = re.compile(r'["&<>]|[^\x00-\x7f]')
+
+ def escape(self, text):
+ """Replace characters with their character references.
+
+ Replace characters by their named entity references.
+ Non-ASCII characters, if they do not have a named entity reference,
+ are replaced by numerical character references.
+
+ The return value is guaranteed to be ASCII.
+ """
+ return self.__escapable.sub(self.__escape, unicode(text)
+ ).encode('ascii')
+
+ # XXX: This regexp will not match all valid XML entity names__.
+ # (It punts on details involving involving CombiningChars and Extenders.)
+ #
+ # .. __: http://www.w3.org/TR/2000/REC-xml-20001006#NT-EntityRef
+ __characterrefs = re.compile(r'''& (?:
+ \#(\d+)
+ | \#x([\da-f]+)
+ | ( (?!\d) [:\w] [-.:\w]+ )
+ ) ;''',
+ re.X | re.UNICODE)
+
+ def __unescape(self, m):
+ dval, hval, name = m.groups()
+ if dval:
+ codepoint = int(dval)
+ elif hval:
+ codepoint = int(hval, 16)
+ else:
+ codepoint = self.name2codepoint.get(name, 0xfffd)
+ # U+FFFD = "REPLACEMENT CHARACTER"
+ if codepoint < 128:
+ return chr(codepoint)
+ return unichr(codepoint)
+
+ def unescape(self, text):
+ """Unescape character references.
+
+ All character references (both entity references and numerical
+ character references) are unescaped.
+ """
+ return self.__characterrefs.sub(self.__unescape, text)
+
+
+_html_entities_escaper = XMLEntityEscaper(htmlentitydefs.codepoint2name,
+ htmlentitydefs.name2codepoint)
+
+html_entities_escape = _html_entities_escaper.escape_entities
+html_entities_unescape = _html_entities_escaper.unescape
+
+
+def htmlentityreplace_errors(ex):
+ """An encoding error handler.
+
+ This python `codecs`_ error handler replaces unencodable
+ characters with HTML entities, or, if no HTML entity exists for
+ the character, XML character references.
+
+ >>> u'The cost was \u20ac12.'.encode('latin1', 'htmlentityreplace')
+ 'The cost was €12.'
+ """
+ if isinstance(ex, UnicodeEncodeError):
+ # Handle encoding errors
+ bad_text = ex.object[ex.start:ex.end]
+ text = _html_entities_escaper.escape(bad_text)
+ return (unicode(text), ex.end)
+ raise ex
+
+codecs.register_error('htmlentityreplace', htmlentityreplace_errors)
+
+
+# TODO: options to make this dynamic per-compilation will be added in a later release
+DEFAULT_ESCAPES = {
+ 'x':'filters.xml_escape',
+ 'h':'filters.html_escape',
+ 'u':'filters.url_escape',
+ 'trim':'filters.trim',
+ 'entity':'filters.html_entities_escape',
+ 'unicode':'unicode',
+ 'decode':'decode',
+ 'str':'str',
+ 'n':'n'
+}
+
+if util.py3k:
+ DEFAULT_ESCAPES.update({
+ 'unicode':'str'
+ })
+
+NON_UNICODE_ESCAPES = DEFAULT_ESCAPES.copy()
+NON_UNICODE_ESCAPES['h'] = 'filters.legacy_html_escape'
+
Added: pypy/benchmarks/lib/mako/mako/lexer.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/lexer.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,415 @@
+# lexer.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""provides the Lexer class for parsing template strings into parse trees."""
+
+import re, codecs
+from mako import parsetree, exceptions, util
+from mako.pygen import adjust_whitespace
+
+_regexp_cache = {}
+
+class Lexer(object):
+ def __init__(self, text, filename=None,
+ disable_unicode=False,
+ input_encoding=None, preprocessor=None):
+ self.text = text
+ self.filename = filename
+ self.template = parsetree.TemplateNode(self.filename)
+ self.matched_lineno = 1
+ self.matched_charpos = 0
+ self.lineno = 1
+ self.match_position = 0
+ self.tag = []
+ 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:
+ if flags:
+ reg = re.compile(regexp, flags)
+ 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
+
+ match = reg.match(self.text, self.match_position)
+ if match:
+ (start, end) = match.span()
+ if end == start:
+ self.match_position = end + 1
+ else:
+ self.match_position = end
+ self.matched_lineno = self.lineno
+ lines = re.findall(r"\n", self.text[mp:self.match_position])
+ cp = mp - 1
+ while (cp >= 0 and cp<self.textlength and self.text[cp] != '\n'):
+ cp -=1
+ self.matched_charpos = mp - cp
+ self.lineno += len(lines)
+ #print "MATCHED:", match.group(0), "LINE START:",
+ # self.matched_lineno, "LINE END:", self.lineno
+ #print "MATCH:", regexp, "\n", self.text[mp : mp + 15], (match and "TRUE" or "FALSE")
+ return match
+
+ def parse_until_text(self, *text):
+ startpos = self.match_position
+ while True:
+ match = self.match(r'#.*\n')
+ if match:
+ continue
+ match = self.match(r'(\"\"\"|\'\'\'|\"|\')')
+ if match:
+ m = self.match(r'.*?%s' % match.group(1), re.S)
+ if not m:
+ raise exceptions.SyntaxException(
+ "Unmatched '%s'" %
+ match.group(1),
+ **self.exception_kwargs)
+ else:
+ match = self.match(r'(%s)' % r'|'.join(text))
+ if match:
+ return \
+ self.text[startpos:self.match_position-len(match.group(1))],\
+ match.group(1)
+ else:
+ match = self.match(r".*?(?=\"|\'|#|%s)" % r'|'.join(text), re.S)
+ if not match:
+ raise exceptions.SyntaxException(
+ "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)
+ kwargs.setdefault('pos', self.matched_charpos)
+ kwargs['filename'] = self.filename
+ node = nodecls(*args, **kwargs)
+ if len(self.tag):
+ self.tag[-1].nodes.append(node)
+ else:
+ self.template.nodes.append(node)
+ if isinstance(node, parsetree.Tag):
+ if len(self.tag):
+ node.parent = self.tag[-1]
+ self.tag.append(node)
+ elif isinstance(node, parsetree.ControlLine):
+ if node.isend:
+ self.control_line.pop()
+ elif node.is_primary:
+ self.control_line.append(node)
+ elif len(self.control_line) and \
+ not self.control_line[-1].is_ternary(node.keyword):
+ raise exceptions.SyntaxException(
+ "Keyword '%s' not a legal ternary for keyword '%s'" %
+ (node.keyword, self.control_line[-1].keyword),
+ **self.exception_kwargs)
+
+ _coding_re = re.compile(r'#.*coding[:=]\s*([-\w.]+).*\r?\n')
+
+ def decode_raw_stream(self, text, decode_raw, known_encoding, filename):
+ """given string/unicode or bytes/string, determine encoding
+ from magic encoding comment, return body as unicode
+ or raw if decode_raw=False
+
+ """
+ if isinstance(text, unicode):
+ m = self._coding_re.match(text)
+ encoding = m and m.group(1) or known_encoding or 'ascii'
+ return encoding, text
+
+ if text.startswith(codecs.BOM_UTF8):
+ text = text[len(codecs.BOM_UTF8):]
+ parsed_encoding = 'utf-8'
+ m = self._coding_re.match(text.decode('utf-8', 'ignore'))
+ if m is not None and m.group(1) != 'utf-8':
+ raise exceptions.CompileException(
+ "Found utf-8 BOM in file, with conflicting "
+ "magic encoding comment of '%s'" % m.group(1),
+ text.decode('utf-8', 'ignore'),
+ 0, 0, filename)
+ else:
+ m = self._coding_re.match(text.decode('utf-8', 'ignore'))
+ if m:
+ parsed_encoding = m.group(1)
+ else:
+ parsed_encoding = known_encoding or 'ascii'
+
+ if decode_raw:
+ try:
+ text = text.decode(parsed_encoding)
+ except UnicodeDecodeError, e:
+ raise exceptions.CompileException(
+ "Unicode decode operation of encoding '%s' failed" %
+ parsed_encoding,
+ text.decode('utf-8', 'ignore'),
+ 0, 0, filename)
+
+ return parsed_encoding, text
+
+ def parse(self):
+ self.encoding, self.text = self.decode_raw_stream(self.text,
+ not self.disable_unicode,
+ self.encoding,
+ self.filename,)
+
+ 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():
+ continue
+ if self.match_control_line():
+ continue
+ if self.match_comment():
+ continue
+ if self.match_tag_start():
+ continue
+ if self.match_tag_end():
+ continue
+ if self.match_python_block():
+ 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,
+ **self.exception_kwargs)
+ if len(self.control_line):
+ raise exceptions.SyntaxException("Unterminated control keyword: '%s'" %
+ self.control_line[-1].keyword,
+ self.text,
+ self.control_line[-1].lineno,
+ self.control_line[-1].pos, self.filename)
+ return self.template
+
+ 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
+ attributes = {}
+ if attr:
+ for att in re.findall(r"\s*(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\")", attr):
+ key, val1, val2 = att
+ text = val1 or val2
+ text = text.replace('\r\n', '\n')
+ attributes[key] = text
+ self.append_node(parsetree.Tag, keyword, attributes)
+ if isend:
+ self.tag.pop()
+ else:
+ if keyword == 'text':
+ match = self.match(r'(.*?)(?=\</%text>)', re.S)
+ if not match:
+ raise exceptions.SyntaxException(
+ "Unclosed tag: <%%%s>" %
+ self.tag[-1].keyword,
+ **self.exception_kwargs)
+ self.append_node(parsetree.Text, match.group(1))
+ return self.match_tag_end()
+ return True
+ else:
+ return False
+
+ def match_tag_end(self):
+ match = self.match(r'\</%[\t ]*(.+?)[\t ]*>')
+ if match:
+ if not len(self.tag):
+ raise exceptions.SyntaxException(
+ "Closing tag without opening tag: </%%%s>" %
+ match.group(1),
+ **self.exception_kwargs)
+ elif self.tag[-1].keyword != match.group(1):
+ raise exceptions.SyntaxException(
+ "Closing tag </%%%s> does not match tag: <%%%s>" %
+ (match.group(1), self.tag[-1].keyword),
+ **self.exception_kwargs)
+ self.tag.pop()
+ return True
+ else:
+ return False
+
+ def match_end(self):
+ match = self.match(r'\Z', re.S)
+ if match:
+ string = match.group()
+ if string:
+ return string
+ else:
+ return True
+ else:
+ return False
+
+ def match_text(self):
+ match = self.match(r"""
+ (.*?) # anything, followed by:
+ (
+ (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based
+ # comment preceded by a
+ # consumed newline and whitespace
+ |
+ (?=\${) # an expression
+ |
+ (?=\#\*) # multiline comment
+ |
+ (?=</?[%&]) # a substitution or block or call start or end
+ # - don't consume
+ |
+ (\\\r?\n) # an escaped newline - throw away
+ |
+ \Z # end of string
+ )""", re.X | re.S)
+
+ if match:
+ text = match.group(1)
+ if text:
+ self.append_node(parsetree.Text, text)
+ return True
+ else:
+ return False
+
+ def match_python_block(self):
+ match = self.match(r"<%(!)?")
+ if match:
+ line, pos = self.matched_lineno, self.matched_charpos
+ text, end = self.parse_until_text(r'%>')
+ # the trailing newline helps
+ # compiler.parse() not complain about indentation
+ text = adjust_whitespace(text) + "\n"
+ self.append_node(
+ parsetree.Code,
+ text,
+ match.group(1)=='!', lineno=line, pos=pos)
+ return True
+ else:
+ return False
+
+ def match_expression(self):
+ match = self.match(r"\${")
+ if match:
+ line, pos = self.matched_lineno, self.matched_charpos
+ text, end = self.parse_until_text(r'\|', r'}')
+ if end == '|':
+ escapes, end = self.parse_until_text(r'}')
+ else:
+ escapes = ""
+ text = text.replace('\r\n', '\n')
+ self.append_node(
+ parsetree.Expression,
+ text, escapes.strip(),
+ lineno=line, pos=pos)
+ return True
+ else:
+ return False
+
+ def match_control_line(self):
+ match = self.match(r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)(?:\r?\n|\Z)", re.M)
+ if match:
+ operator = match.group(1)
+ text = match.group(2)
+ if operator == '%':
+ m2 = re.match(r'(end)?(\w+)\s*(.*)', text)
+ if not m2:
+ raise exceptions.SyntaxException(
+ "Invalid control line: '%s'" %
+ text,
+ **self.exception_kwargs)
+ isend, keyword = m2.group(1, 2)
+ isend = (isend is not None)
+
+ if isend:
+ if not len(self.control_line):
+ raise exceptions.SyntaxException(
+ "No starting keyword '%s' for '%s'" %
+ (keyword, text),
+ **self.exception_kwargs)
+ elif self.control_line[-1].keyword != keyword:
+ raise exceptions.SyntaxException(
+ "Keyword '%s' doesn't match keyword '%s'" %
+ (text, self.control_line[-1].keyword),
+ **self.exception_kwargs)
+ self.append_node(parsetree.ControlLine, keyword, isend, text)
+ else:
+ self.append_node(parsetree.Comment, text)
+ return True
+ else:
+ return False
+
+ def match_comment(self):
+ """matches the multiline version of a comment"""
+ match = self.match(r"<%doc>(.*?)</%doc>", re.S)
+ if match:
+ self.append_node(parsetree.Comment, match.group(1))
+ return True
+ else:
+ return False
+
Added: pypy/benchmarks/lib/mako/mako/lookup.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/lookup.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,321 @@
+# lookup.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer
+# mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+import os, stat, posixpath, re
+from mako import exceptions, util
+from mako.template import Template
+
+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):
+ """Return ``True`` if this :class:`.TemplateLookup` is
+ capable of returning a :class:`.Template` object for the
+ given URL.
+
+ :param uri: String uri of the template to be resolved.
+
+ """
+ try:
+ self.get_template(uri)
+ return True
+ except exceptions.TemplateLookupException:
+ return False
+
+ 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
+ TemplateCollection subclass can place any string
+ 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
+ relate URI strings to :class:`.Template` instances.
+ 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
+ which an existing :class:`.Template` object was created.
+ This allows the :class:`.TemplateLookup` to regenerate a
+ 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
+ generated Python module file. This is used to inject
+ 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,
+ filesystem_checks=True,
+ collection_size=-1,
+ format_exceptions=False,
+ error_handler=None,
+ disable_unicode=False,
+ output_encoding=None,
+ encoding_errors='strict',
+ cache_type=None,
+ cache_dir=None, cache_url=None,
+ cache_enabled=True,
+ modulename_callable=None,
+ default_filters=None,
+ buffer_filters=(),
+ strict_undefined=False,
+ imports=None,
+ input_encoding=None,
+ preprocessor=None):
+
+ self.directories = [posixpath.normpath(d) for d in
+ util.to_list(directories, ())
+ ]
+ self.module_directory = module_directory
+ self.modulename_callable = modulename_callable
+ self.filesystem_checks = filesystem_checks
+ self.collection_size = collection_size
+
+ self.template_args = {
+ 'format_exceptions':format_exceptions,
+ 'error_handler':error_handler,
+ 'disable_unicode':disable_unicode,
+ 'output_encoding':output_encoding,
+ 'encoding_errors':encoding_errors,
+ 'input_encoding':input_encoding,
+ 'module_directory':module_directory,
+ 'cache_type':cache_type,
+ 'cache_dir':cache_dir or module_directory,
+ 'cache_url':cache_url,
+ 'cache_enabled':cache_enabled,
+ 'default_filters':default_filters,
+ 'buffer_filters':buffer_filters,
+ 'strict_undefined':strict_undefined,
+ 'imports':imports,
+ 'preprocessor':preprocessor}
+
+ if collection_size == -1:
+ self._collection = {}
+ self._uri_cache = {}
+ else:
+ 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])
+ else:
+ return self._collection[uri]
+ except KeyError:
+ u = re.sub(r'^\/+', '', uri)
+ for dir in self.directories:
+ srcfile = posixpath.normpath(posixpath.join(dir, u))
+ if os.path.isfile(srcfile):
+ return self._load(srcfile, uri)
+ else:
+ raise exceptions.TopLevelLookupException(
+ "Cant locate template for uri %r" % uri)
+
+ 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)
+ else:
+ return '/' + uri
+ else:
+ return uri
+
+
+ def filename_to_uri(self, filename):
+ """Convert the given filename to a uri relative to
+ this TemplateCollection."""
+
+ try:
+ return self._uri_cache[filename]
+ except KeyError:
+ 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:
+ try:
+ # try returning from collection one
+ # more time in case concurrent thread already loaded
+ return self._collection[uri]
+ except KeyError:
+ pass
+ try:
+ if self.modulename_callable is not None:
+ module_filename = self.modulename_callable(filename, uri)
+ else:
+ module_filename = None
+ self._collection[uri] = template = Template(
+ uri=uri,
+ filename=posixpath.normpath(filename),
+ lookup=self,
+ module_filename=module_filename,
+ **self.template_args)
+ return template
+ except:
+ # if compilation fails etc, ensure
+ # template is removed from collection,
+ # re-raise
+ self._collection.pop(uri, None)
+ raise
+ finally:
+ self._mutex.release()
+
+ def _check(self, uri, template):
+ if template.filename is None:
+ return template
+ if not os.path.exists(template.filename):
+ self._collection.pop(uri, None)
+ raise exceptions.TemplateLookupException(
+ "Cant locate template for uri %r" % uri)
+ elif template.module._modified_time < \
+ os.stat(template.filename)[stat.ST_MTIME]:
+ self._collection.pop(uri, None)
+ 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
+
Added: pypy/benchmarks/lib/mako/mako/parsetree.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/parsetree.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,499 @@
+# parsetree.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""defines the parse tree components for Mako templates."""
+
+from mako import exceptions, ast, util, filters
+import re
+
+class Node(object):
+ """base class for a Node in the parse tree."""
+ def __init__(self, source, lineno, pos, filename):
+ self.source = source
+ 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():
+ n.accept_visitor(visitor)
+ method = getattr(visitor, "visit" + self.__class__.__name__, traverse)
+ method(self)
+
+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):
+ super(ControlLine, self).__init__(**kwargs)
+ self.text = text
+ self.keyword = keyword
+ self.isend = isend
+ self.is_primary = keyword in ['for','if', 'while', 'try']
+ if self.isend:
+ self._declared_identifiers = []
+ self._undeclared_identifiers = []
+ else:
+ code = ast.PythonFragment(text, **self.exception_kwargs)
+ self._declared_identifiers = code.declared_identifiers
+ self._undeclared_identifiers = code.undeclared_identifiers
+
+ def declared_identifiers(self):
+ return self._declared_identifiers
+
+ def undeclared_identifiers(self):
+ return self._undeclared_identifiers
+
+ def is_ternary(self, keyword):
+ """return true if the given keyword is a ternary keyword
+ for this ControlLine"""
+
+ return keyword in {
+ 'if':set(['else', 'elif']),
+ 'try':set(['except', 'finally']),
+ 'for':set(['else'])
+ }.get(self.keyword, [])
+
+ def __repr__(self):
+ return "ControlLine(%r, %r, %r, %r)" % (
+ self.keyword,
+ self.text,
+ self.isend,
+ (self.lineno, self.pos)
+ )
+
+class Text(Node):
+ """defines plain text in the template."""
+
+ def __init__(self, content, **kwargs):
+ super(Text, self).__init__(**kwargs)
+ self.content = content
+
+ def __repr__(self):
+ return "Text(%r, %r)" % (self.content, (self.lineno, self.pos))
+
+class Code(Node):
+ """defines a Python code block, either inline or module level.
+
+ e.g.::
+
+ inline:
+ <%
+ x = 12
+ %>
+
+ module level:
+ <%!
+ import logger
+ %>
+
+ """
+
+ def __init__(self, text, ismodule, **kwargs):
+ super(Code, self).__init__(**kwargs)
+ self.text = text
+ self.ismodule = ismodule
+ self.code = ast.PythonCode(text, **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return self.code.declared_identifiers
+
+ def undeclared_identifiers(self):
+ return self.code.undeclared_identifiers
+
+ def __repr__(self):
+ return "Code(%r, %r, %r)" % (
+ self.text,
+ self.ismodule,
+ (self.lineno, self.pos)
+ )
+
+class Comment(Node):
+ """defines a comment line.
+
+ # this is a comment
+
+ """
+
+ def __init__(self, text, **kwargs):
+ super(Comment, self).__init__(**kwargs)
+ self.text = text
+
+ def __repr__(self):
+ return "Comment(%r, %r)" % (self.text, (self.lineno, self.pos))
+
+class Expression(Node):
+ """defines an inline expression.
+
+ ${x+y}
+
+ """
+
+ def __init__(self, text, escapes, **kwargs):
+ super(Expression, self).__init__(**kwargs)
+ self.text = text
+ self.escapes = escapes
+ self.escapes_code = ast.ArgumentList(escapes, **self.exception_kwargs)
+ self.code = ast.PythonCode(text, **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return []
+
+ def undeclared_identifiers(self):
+ # TODO: make the "filter" shortcut list configurable at parse/gen time
+ return self.code.undeclared_identifiers.union(
+ self.escapes_code.undeclared_identifiers.difference(
+ set(filters.DEFAULT_ESCAPES.keys())
+ )
+ ).difference(self.code.declared_identifiers)
+
+ def __repr__(self):
+ return "Expression(%r, %r, %r)" % (
+ self.text,
+ self.escapes_code.args,
+ (self.lineno, self.pos)
+ )
+
+class _TagMeta(type):
+ """metaclass to allow Tag to produce a subclass according to
+ its keyword"""
+
+ _classmap = {}
+
+ def __init__(cls, clsname, bases, dict):
+ if cls.__keyword__ is not None:
+ cls._classmap[cls.__keyword__] = cls
+ super(_TagMeta, cls).__init__(clsname, bases, dict)
+
+ def __call__(cls, keyword, attributes, **kwargs):
+ if ":" in keyword:
+ ns, defname = keyword.split(':')
+ return type.__call__(CallNamespaceTag, ns, defname,
+ attributes, **kwargs)
+
+ try:
+ cls = _TagMeta._classmap[keyword]
+ except KeyError:
+ raise exceptions.CompileException(
+ "No such tag: '%s'" % keyword,
+ source=kwargs['source'],
+ lineno=kwargs['lineno'],
+ pos=kwargs['pos'],
+ 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
+ self.attributes = attributes
+ self._parse_attributes(expressions, nonexpressions)
+ missing = [r for r in required if r not in self.parsed_attributes]
+ if len(missing):
+ raise exceptions.CompileException(
+ "Missing attribute(s): %s" %
+ ",".join([repr(m) for m in missing]),
+ **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 = {}
+ for key in self.attributes:
+ if key in expressions:
+ expr = []
+ for x in re.compile(r'(\${.+?})',
+ re.S).split(self.attributes[key]):
+ m = re.compile(r'^\${(.+?)}$', re.S).match(x)
+ if m:
+ code = ast.PythonCode(m.group(1).rstrip(),
+ **self.exception_kwargs)
+ # we aren't discarding "declared_identifiers" here,
+ # which we do so that list comprehension-declared
+ # variables aren't counted. As yet can't find a
+ # condition that requires it here.
+ undeclared_identifiers = \
+ undeclared_identifiers.union(
+ code.undeclared_identifiers)
+ expr.append('(%s)' % m.group(1))
+ else:
+ if x:
+ expr.append(repr(x))
+ self.parsed_attributes[key] = " + ".join(expr) or repr('')
+ elif key in nonexpressions:
+ if re.search(r'\${.+?}', self.attributes[key]):
+ raise exceptions.CompileException(
+ "Attibute '%s' in tag '%s' does not allow embedded "
+ "expressions" % (key, self.keyword),
+ **self.exception_kwargs)
+ self.parsed_attributes[key] = repr(self.attributes[key])
+ else:
+ raise exceptions.CompileException(
+ "Invalid attribute for tag '%s': '%s'" %
+ (self.keyword, key),
+ **self.exception_kwargs)
+ self.expression_undeclared_identifiers = undeclared_identifiers
+
+ def declared_identifiers(self):
+ return []
+
+ def undeclared_identifiers(self):
+ return self.expression_undeclared_identifiers
+
+ def __repr__(self):
+ return "%s(%r, %s, %r, %r)" % (self.__class__.__name__,
+ self.keyword,
+ util.sorted_dict_repr(self.attributes),
+ (self.lineno, self.pos),
+ self.nodes
+ )
+
+class IncludeTag(Tag):
+ __keyword__ = 'include'
+
+ def __init__(self, keyword, attributes, **kwargs):
+ super(IncludeTag, self).__init__(
+ keyword,
+ attributes,
+ ('file', 'import', 'args'),
+ (), ('file',), **kwargs)
+ self.page_args = ast.PythonCode(
+ "__DUMMY(%s)" % attributes.get('args', ''),
+ **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return []
+
+ def undeclared_identifiers(self):
+ identifiers = self.page_args.undeclared_identifiers.\
+ difference(set(["__DUMMY"])).\
+ difference(self.page_args.declared_identifiers)
+ return identifiers.union(super(IncludeTag, self).
+ undeclared_identifiers())
+
+class NamespaceTag(Tag):
+ __keyword__ = 'namespace'
+
+ def __init__(self, keyword, attributes, **kwargs):
+ super(NamespaceTag, self).__init__(
+ keyword, attributes,
+ ('file',),
+ ('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(
+ "'name' and/or 'import' attributes are required "
+ "for <%namespace>",
+ **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return []
+
+class TextTag(Tag):
+ __keyword__ = 'text'
+
+ def __init__(self, keyword, attributes, **kwargs):
+ super(TextTag, self).__init__(
+ keyword,
+ attributes, (),
+ ('filter'), (), **kwargs)
+ self.filter_args = ast.ArgumentList(
+ attributes.get('filter', ''),
+ **self.exception_kwargs)
+
+class DefTag(Tag):
+ __keyword__ = 'def'
+
+ def __init__(self, keyword, attributes, **kwargs):
+ super(DefTag, self).__init__(
+ keyword,
+ attributes,
+ ('buffered', 'cached', 'cache_key', 'cache_timeout',
+ 'cache_type', 'cache_dir', 'cache_url'),
+ ('name','filter', 'decorator'),
+ ('name',),
+ **kwargs)
+ name = attributes['name']
+ if re.match(r'^[\w_]+$',name):
+ raise exceptions.CompileException(
+ "Missing parenthesis in %def",
+ **self.exception_kwargs)
+ self.function_decl = ast.FunctionDecl("def " + name + ":pass",
+ **self.exception_kwargs)
+ self.name = self.function_decl.funcname
+ self.decorator = attributes.get('decorator', '')
+ self.filter_args = ast.ArgumentList(
+ attributes.get('filter', ''),
+ **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return self.function_decl.argnames
+
+ def undeclared_identifiers(self):
+ res = []
+ for c in self.function_decl.defaults:
+ res += list(ast.PythonCode(c, **self.exception_kwargs).
+ undeclared_identifiers)
+ return res + list(self.filter_args.\
+ undeclared_identifiers.\
+ difference(filters.DEFAULT_ESCAPES.keys())
+ )
+
+class CallTag(Tag):
+ __keyword__ = 'call'
+
+ def __init__(self, keyword, attributes, **kwargs):
+ super(CallTag, self).__init__(keyword, attributes,
+ ('args'), ('expr',), ('expr',), **kwargs)
+ self.expression = attributes['expr']
+ self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
+ self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+ **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return self.code.declared_identifiers.union(self.body_decl.argnames)
+
+ def undeclared_identifiers(self):
+ return self.code.undeclared_identifiers.\
+ difference(self.code.declared_identifiers)
+
+class CallNamespaceTag(Tag):
+
+ def __init__(self, namespace, defname, attributes, **kwargs):
+ super(CallNamespaceTag, self).__init__(
+ namespace + ":" + defname,
+ attributes,
+ tuple(attributes.keys()) + ('args', ),
+ (),
+ (),
+ **kwargs)
+
+ self.expression = "%s.%s(%s)" % (
+ namespace,
+ defname,
+ ",".join(["%s=%s" % (k, v) for k, v in
+ self.parsed_attributes.iteritems()
+ if k != 'args'])
+ )
+ self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
+ self.body_decl = ast.FunctionArgs(
+ attributes.get('args', ''),
+ **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return self.code.declared_identifiers.union(self.body_decl.argnames)
+
+ def undeclared_identifiers(self):
+ return self.code.undeclared_identifiers.\
+ difference(self.code.declared_identifiers)
+
+class InheritTag(Tag):
+ __keyword__ = 'inherit'
+
+ def __init__(self, keyword, attributes, **kwargs):
+ super(InheritTag, self).__init__(
+ keyword, attributes,
+ ('file',), (), ('file',), **kwargs)
+
+class PageTag(Tag):
+ __keyword__ = 'page'
+
+ def __init__(self, keyword, attributes, **kwargs):
+ super(PageTag, self).__init__(
+ keyword,
+ attributes,
+ ('cached', 'cache_key', 'cache_timeout',
+ 'cache_type', 'cache_dir', 'cache_url',
+ 'args', 'expression_filter'),
+ (),
+ (),
+ **kwargs)
+ self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+ **self.exception_kwargs)
+ self.filter_args = ast.ArgumentList(
+ attributes.get('expression_filter', ''),
+ **self.exception_kwargs)
+
+ def declared_identifiers(self):
+ return self.body_decl.argnames
+
+
Added: pypy/benchmarks/lib/mako/mako/pygen.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/pygen.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,285 @@
+# pygen.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""utilities for generating and formatting literal Python code."""
+
+import re, string
+from StringIO import StringIO
+from mako import exceptions
+
+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.
+
+ """
+
+ if not self.in_indent_lines:
+ self._flush_adjusted_lines()
+ self.in_indent_lines = True
+
+ decreased_indent = False
+
+ if (line is None or
+ re.match(r"^\s*#",line) or
+ re.match(r"^\s*$", line)
+ ):
+ hastext = False
+ else:
+ 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:
+ 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.
+
+ if re.search(r":[ \t]*(?:#.*)?$", line):
+ # increment indentation count, and also
+ # keep track of what the keyword was that indented us,
+ # if it is a python compound statement keyword
+ # where we might have to look for an "unindent" keyword
+ match = re.match(r"^\s*(if|try|elif|while|for)", line)
+ if match:
+ # its a "compound" keyword, so we will check for "unindentors"
+ indentor = match.group(1)
+ self.indent +=1
+ self.indent_detail.append(indentor)
+ else:
+ indentor = None
+ # its not a "compound" keyword. but lets also
+ # test for valid Python keywords that might be indenting us,
+ # else assume its a non-indenting line
+ m2 = re.match(r"^\s*(def|class|else|elif|except|finally)", line)
+ if m2:
+ self.indent += 1
+ self.indent_detail.append(indentor)
+
+ 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'),
+ # (r'try', r'except|finally|else'),
+ # (r'while|for', r'else'),
+ #]:
+ # 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."""
+
+ return re.sub(r"^%s" % stripspace, self.indentstring
+ * self.indent, line)
+
+ def _reset_multi_line_flags(self):
+ """reset the flags which would indicate we are in a backslashed
+ 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."""
+
+ # we are only looking for explicitly joined lines here, not
+ # implicit ones (i.e. brackets, braces etc.). this is just to
+ # 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")
+ else:
+ entry = entry.expandtabs()
+ 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)
+ if m:
+ state[triplequoted] = False
+ else:
+ m, line = match(r".*?(?=%s|$)" % state[triplequoted], line)
+ else:
+ 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 = ''):
+ return re.sub(r"^%s" % stripspace, '', line)
+
+ lines = []
+ stripspace = None
+
+ for line in re.split(r'\r?\n', text):
+ if in_multi_line(line):
+ lines.append(line)
+ else:
+ line = line.expandtabs()
+ if stripspace is None and re.search(r"^[ \t]*[^# \t]", line):
+ stripspace = re.match(r"^([ \t]*)", line).group(1)
+ lines.append(_indent_line(line, stripspace))
+ return "\n".join(lines)
Added: pypy/benchmarks/lib/mako/mako/pyparser.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/pyparser.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,533 @@
+# ast.py
+# Copyright (C) Mako developers
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""Handles parsing of Python code.
+
+Parsing to AST is done via _ast on Python > 2.5, otherwise the compiler
+module is used.
+"""
+
+from StringIO import StringIO
+from mako import exceptions, util
+import operator
+
+if util.py3k:
+ # words that cannot be assigned to (notably
+ # smaller than the total keys in __builtins__)
+ reserved = set(['True', 'False', 'None', 'print'])
+
+ # the "id" attribute on a function node
+ arg_id = operator.attrgetter('arg')
+else:
+ # words that cannot be assigned to (notably
+ # smaller than the total keys in __builtins__)
+ reserved = set(['True', 'False', 'None'])
+
+ # the "id" attribute on a function node
+ arg_id = operator.attrgetter('id')
+
+
+try:
+ import _ast
+ util.restore__ast(_ast)
+ import _ast_util
+except ImportError:
+ _ast = None
+ from compiler import parse as compiler_parse
+ from compiler import visitor
+
+
+def parse(code, mode='exec', **exception_kwargs):
+ """Parse an expression into AST"""
+
+
+ try:
+ if _ast:
+ return _ast_util.parse(code, '<unknown>', mode)
+ else:
+ if isinstance(code, unicode):
+ code = code.encode('ascii', 'backslashreplace')
+ return compiler_parse(code, mode)
+ except Exception, e:
+ raise exceptions.SyntaxException(
+ "(%s) %s (%r)" % (
+ e.__class__.__name__,
+ e,
+ code[0:50]
+ ), **exception_kwargs)
+
+
+if _ast:
+ class FindIdentifiers(_ast_util.NodeVisitor):
+
+ def __init__(self, listener, **exception_kwargs):
+ self.in_function = False
+ self.in_assign_targets = False
+ self.local_ident_stack = {}
+ self.listener = listener
+ self.exception_kwargs = exception_kwargs
+
+ def _add_declared(self, name):
+ if not self.in_function:
+ self.listener.declared_identifiers.add(name)
+
+ def visit_ClassDef(self, node):
+ self._add_declared(node.name)
+
+ def visit_Assign(self, node):
+
+ # flip around the visiting of Assign so the expression gets
+ # evaluated first, in the case of a clause like "x=x+5" (x
+ # is undeclared)
+
+ self.visit(node.value)
+ in_a = self.in_assign_targets
+ self.in_assign_targets = True
+ for n in node.targets:
+ self.visit(n)
+ self.in_assign_targets = in_a
+
+ if util.py3k:
+
+ # ExceptHandler is in Python 2, but this block only works in
+ # Python 3 (and is required there)
+
+ def visit_ExceptHandler(self, node):
+ if node.name is not None:
+ self._add_declared(node.name)
+ if node.type is not None:
+ self.listener.undeclared_identifiers.add(node.type.id)
+ for statement in node.body:
+ self.visit(statement)
+
+ def visit_Lambda(self, node, *args):
+ self._visit_function(node, True)
+
+ def visit_FunctionDef(self, node):
+ self._add_declared(node.name)
+ self._visit_function(node, False)
+
+ def _visit_function(self, node, islambda):
+
+ # push function state onto stack. dont log any more
+ # identifiers as "declared" until outside of the function,
+ # but keep logging identifiers as "undeclared". track
+ # argument names in each function header so they arent
+ # counted as "undeclared"
+
+ saved = {}
+ inf = self.in_function
+ self.in_function = True
+ for arg in node.args.args:
+ if arg_id(arg) in self.local_ident_stack:
+ saved[arg_id(arg)] = True
+ else:
+ self.local_ident_stack[arg_id(arg)] = True
+ if islambda:
+ self.visit(node.body)
+ else:
+ for n in node.body:
+ self.visit(n)
+ self.in_function = inf
+ for arg in node.args.args:
+ if arg_id(arg) not in saved:
+ del self.local_ident_stack[arg_id(arg)]
+
+ def visit_For(self, node):
+
+ # flip around visit
+
+ self.visit(node.iter)
+ self.visit(node.target)
+ for statement in node.body:
+ self.visit(statement)
+ for statement in node.orelse:
+ self.visit(statement)
+
+ def visit_Name(self, node):
+ if isinstance(node.ctx, _ast.Store):
+ self._add_declared(node.id)
+ if node.id not in reserved and node.id \
+ not in self.listener.declared_identifiers and node.id \
+ not in self.local_ident_stack:
+ self.listener.undeclared_identifiers.add(node.id)
+
+ def visit_Import(self, node):
+ for name in node.names:
+ if name.asname is not None:
+ self._add_declared(name.asname)
+ else:
+ self._add_declared(name.name.split('.')[0])
+
+ def visit_ImportFrom(self, node):
+ for name in node.names:
+ if name.asname is not None:
+ self._add_declared(name.asname)
+ else:
+ if name.name == '*':
+ raise exceptions.CompileException(
+ "'import *' is not supported, since all identifier "
+ "names must be explicitly declared. Please use the "
+ "form 'from <modulename> import <name1>, <name2>, "
+ "...' instead.", **self.exception_kwargs)
+ self._add_declared(name.name)
+
+
+ class FindTuple(_ast_util.NodeVisitor):
+
+ def __init__(self, listener, code_factory, **exception_kwargs):
+ self.listener = listener
+ self.exception_kwargs = exception_kwargs
+ self.code_factory = code_factory
+
+ def visit_Tuple(self, node):
+ for n in node.elts:
+ p = self.code_factory(n, **self.exception_kwargs)
+ self.listener.codeargs.append(p)
+ self.listener.args.append(ExpressionGenerator(n).value())
+ self.listener.declared_identifiers = \
+ self.listener.declared_identifiers.union(
+ p.declared_identifiers)
+ self.listener.undeclared_identifiers = \
+ self.listener.undeclared_identifiers.union(
+ p.undeclared_identifiers)
+
+
+ class ParseFunc(_ast_util.NodeVisitor):
+
+ def __init__(self, listener, **exception_kwargs):
+ self.listener = listener
+ self.exception_kwargs = exception_kwargs
+
+ def visit_FunctionDef(self, node):
+ self.listener.funcname = node.name
+ argnames = [arg_id(arg) for arg in node.args.args]
+ if node.args.vararg:
+ argnames.append(node.args.vararg)
+ if node.args.kwarg:
+ argnames.append(node.args.kwarg)
+ self.listener.argnames = argnames
+ self.listener.defaults = node.args.defaults # ast
+ self.listener.varargs = node.args.vararg
+ self.listener.kwargs = node.args.kwarg
+
+
+ class ExpressionGenerator(object):
+
+ def __init__(self, astnode):
+ self.generator = _ast_util.SourceGenerator(' ' * 4)
+ self.generator.visit(astnode)
+
+ def value(self):
+ return ''.join(self.generator.result)
+else:
+ class FindIdentifiers(object):
+
+ def __init__(self, listener, **exception_kwargs):
+ self.in_function = False
+ self.local_ident_stack = {}
+ self.listener = listener
+ self.exception_kwargs = exception_kwargs
+
+ def _add_declared(self, name):
+ if not self.in_function:
+ self.listener.declared_identifiers.add(name)
+
+ def visitClass(self, node, *args):
+ self._add_declared(node.name)
+
+ def visitAssName(self, node, *args):
+ self._add_declared(node.name)
+
+ def visitAssign(self, node, *args):
+
+ # flip around the visiting of Assign so the expression gets
+ # evaluated first, in the case of a clause like "x=x+5" (x
+ # is undeclared)
+
+ self.visit(node.expr, *args)
+ for n in node.nodes:
+ self.visit(n, *args)
+
+ def visitLambda(self, node, *args):
+ self._visit_function(node, args)
+
+ def visitFunction(self, node, *args):
+ self._add_declared(node.name)
+ self._visit_function(node, args)
+
+ def _visit_function(self, node, args):
+
+ # push function state onto stack. dont log any more
+ # identifiers as "declared" until outside of the function,
+ # but keep logging identifiers as "undeclared". track
+ # argument names in each function header so they arent
+ # counted as "undeclared"
+
+ saved = {}
+ inf = self.in_function
+ self.in_function = True
+ for arg in node.argnames:
+ if arg in self.local_ident_stack:
+ saved[arg] = True
+ else:
+ self.local_ident_stack[arg] = True
+ for n in node.getChildNodes():
+ self.visit(n, *args)
+ self.in_function = inf
+ for arg in node.argnames:
+ if arg not in saved:
+ del self.local_ident_stack[arg]
+
+ def visitFor(self, node, *args):
+
+ # flip around visit
+
+ self.visit(node.list, *args)
+ self.visit(node.assign, *args)
+ self.visit(node.body, *args)
+
+ def visitName(self, node, *args):
+ if node.name not in reserved and node.name \
+ not in self.listener.declared_identifiers and node.name \
+ not in self.local_ident_stack:
+ self.listener.undeclared_identifiers.add(node.name)
+
+ def visitImport(self, node, *args):
+ for mod, alias in node.names:
+ if alias is not None:
+ self._add_declared(alias)
+ else:
+ self._add_declared(mod.split('.')[0])
+
+ def visitFrom(self, node, *args):
+ for mod, alias in node.names:
+ if alias is not None:
+ self._add_declared(alias)
+ else:
+ if mod == '*':
+ raise exceptions.CompileException(
+ "'import *' is not supported, since all identifier "
+ "names must be explicitly declared. Please use the "
+ "form 'from <modulename> import <name1>, <name2>, "
+ "...' instead.", **self.exception_kwargs)
+ self._add_declared(mod)
+
+ def visit(self, expr):
+ visitor.walk(expr, self) # , walker=walker())
+
+
+ class FindTuple(object):
+
+ def __init__(self, listener, code_factory, **exception_kwargs):
+ self.listener = listener
+ self.exception_kwargs = exception_kwargs
+ self.code_factory = code_factory
+
+ def visitTuple(self, node, *args):
+ for n in node.nodes:
+ p = self.code_factory(n, **self.exception_kwargs)
+ self.listener.codeargs.append(p)
+ self.listener.args.append(ExpressionGenerator(n).value())
+ self.listener.declared_identifiers = \
+ self.listener.declared_identifiers.union(p.declared_identifiers)
+ self.listener.undeclared_identifiers = \
+ self.listener.undeclared_identifiers.union(p.undeclared_identifiers)
+
+ def visit(self, expr):
+ visitor.walk(expr, self) # , walker=walker())
+
+
+ class ParseFunc(object):
+
+ def __init__(self, listener, **exception_kwargs):
+ self.listener = listener
+ self.exception_kwargs = exception_kwargs
+
+ def visitFunction(self, node, *args):
+ self.listener.funcname = node.name
+ self.listener.argnames = node.argnames
+ self.listener.defaults = node.defaults
+ self.listener.varargs = node.varargs
+ self.listener.kwargs = node.kwargs
+
+ def visit(self, expr):
+ visitor.walk(expr, self)
+
+
+ class ExpressionGenerator(object):
+
+ """given an AST node, generates an equivalent literal Python
+ expression."""
+
+ def __init__(self, astnode):
+ self.buf = StringIO()
+ visitor.walk(astnode, self) # , walker=walker())
+
+ def value(self):
+ return self.buf.getvalue()
+
+ def operator(self, op, node, *args):
+ self.buf.write('(')
+ self.visit(node.left, *args)
+ self.buf.write(' %s ' % op)
+ self.visit(node.right, *args)
+ self.buf.write(')')
+
+ def booleanop(self, op, node, *args):
+ self.visit(node.nodes[0])
+ for n in node.nodes[1:]:
+ self.buf.write(' ' + op + ' ')
+ self.visit(n, *args)
+
+ def visitConst(self, node, *args):
+ self.buf.write(repr(node.value))
+
+ def visitAssName(self, node, *args):
+
+ # TODO: figure out OP_ASSIGN, other OP_s
+
+ self.buf.write(node.name)
+
+ def visitName(self, node, *args):
+ self.buf.write(node.name)
+
+ def visitMul(self, node, *args):
+ self.operator('*', node, *args)
+
+ def visitAnd(self, node, *args):
+ self.booleanop('and', node, *args)
+
+ def visitOr(self, node, *args):
+ self.booleanop('or', node, *args)
+
+ def visitBitand(self, node, *args):
+ self.booleanop('&', node, *args)
+
+ def visitBitor(self, node, *args):
+ self.booleanop('|', node, *args)
+
+ def visitBitxor(self, node, *args):
+ self.booleanop('^', node, *args)
+
+ def visitAdd(self, node, *args):
+ self.operator('+', node, *args)
+
+ def visitGetattr(self, node, *args):
+ self.visit(node.expr, *args)
+ self.buf.write('.%s' % node.attrname)
+
+ def visitSub(self, node, *args):
+ self.operator('-', node, *args)
+
+ def visitNot(self, node, *args):
+ self.buf.write('not ')
+ self.visit(node.expr)
+
+ def visitDiv(self, node, *args):
+ self.operator('/', node, *args)
+
+ def visitFloorDiv(self, node, *args):
+ self.operator('//', node, *args)
+
+ def visitSubscript(self, node, *args):
+ self.visit(node.expr)
+ self.buf.write('[')
+ [self.visit(x) for x in node.subs]
+ self.buf.write(']')
+
+ def visitUnarySub(self, node, *args):
+ self.buf.write('-')
+ self.visit(node.expr)
+
+ def visitUnaryAdd(self, node, *args):
+ self.buf.write('-')
+ self.visit(node.expr)
+
+ def visitSlice(self, node, *args):
+ self.visit(node.expr)
+ self.buf.write('[')
+ if node.lower is not None:
+ self.visit(node.lower)
+ self.buf.write(':')
+ if node.upper is not None:
+ self.visit(node.upper)
+ self.buf.write(']')
+
+ def visitDict(self, node):
+ self.buf.write('{')
+ c = node.getChildren()
+ for i in range(0, len(c), 2):
+ self.visit(c[i])
+ self.buf.write(': ')
+ self.visit(c[i + 1])
+ if i < len(c) - 2:
+ self.buf.write(', ')
+ self.buf.write('}')
+
+ def visitTuple(self, node):
+ self.buf.write('(')
+ c = node.getChildren()
+ for i in range(0, len(c)):
+ self.visit(c[i])
+ if i < len(c) - 1:
+ self.buf.write(', ')
+ self.buf.write(')')
+
+ def visitList(self, node):
+ self.buf.write('[')
+ c = node.getChildren()
+ for i in range(0, len(c)):
+ self.visit(c[i])
+ if i < len(c) - 1:
+ self.buf.write(', ')
+ self.buf.write(']')
+
+ def visitListComp(self, node):
+ self.buf.write('[')
+ self.visit(node.expr)
+ self.buf.write(' ')
+ for n in node.quals:
+ self.visit(n)
+ self.buf.write(']')
+
+ def visitListCompFor(self, node):
+ self.buf.write(' for ')
+ self.visit(node.assign)
+ self.buf.write(' in ')
+ self.visit(node.list)
+ for n in node.ifs:
+ self.visit(n)
+
+ def visitListCompIf(self, node):
+ self.buf.write(' if ')
+ self.visit(node.test)
+
+ def visitCompare(self, node):
+ self.visit(node.expr)
+ for tup in node.ops:
+ self.buf.write(tup[0])
+ self.visit(tup[1])
+
+ def visitCallFunc(self, node, *args):
+ self.visit(node.node)
+ self.buf.write('(')
+ if len(node.args):
+ self.visit(node.args[0])
+ for a in node.args[1:]:
+ self.buf.write(', ')
+ self.visit(a)
+ self.buf.write(')')
+
+
+ class walker(visitor.ASTVisitor):
+
+ def dispatch(self, node, *args):
+ print 'Node:', str(node)
+
+ # print "dir:", dir(node)
+
+ return visitor.ASTVisitor.dispatch(self, node, *args)
Added: pypy/benchmarks/lib/mako/mako/runtime.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/runtime.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,650 @@
+# runtime.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""provides runtime services for templates, including Context,
+Namespace, and various helper functions."""
+
+from mako import exceptions, util
+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)
+ self._kwargs = data.copy()
+ 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
+
+ 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"""
+
+ return self._buffer_stack[-1].write
+
+ def _copy(self):
+ c = Context.__new__(Context)
+ c._buffer_stack = self._buffer_stack
+ c._data = self._data.copy()
+ c._orig = self._orig
+ c._kwargs = self._kwargs
+ c._with_template = self._with_template
+ c._outputting_as_unicode = self._outputting_as_unicode
+ 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."""
+
+ c = self._copy()
+ x = c._data
+ x.pop('self', None)
+ x.pop('parent', None)
+ x.pop('next', None)
+ return c
+
+class CallerStack(list):
+ def __init__(self):
+ self.nextcaller = None
+ def __nonzero__(self):
+ return self._get_caller() and True or False
+ def _get_caller(self):
+ return self[-1]
+ def __getattr__(self, key):
+ return getattr(self._get_caller(), key)
+ def _push_frame(self):
+ self.append(self.nextcaller or None)
+ 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")
+ def __nonzero__(self):
+ return False
+
+UNDEFINED = Undefined()
+
+class _NSAttr(object):
+ def __init__(self, parent):
+ self.__parent = parent
+ def __getattr__(self, key):
+ ns = self.__parent
+ while ns:
+ if hasattr(ns.module, key):
+ return getattr(ns.module, key)
+ else:
+ ns = ns.inherits
+ 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,
+ populate_self=True, calling_uri=None):
+ self.name = name
+ if module is not None:
+ mod = __import__(module)
+ for token in module.split('.')[1:]:
+ mod = getattr(mod, token)
+ self._module = mod
+ else:
+ self._module = None
+ if templateuri is not None:
+ self.template = _lookup_template(context, templateuri, calling_uri)
+ self._templateuri = self.template.module._template_uri
+ else:
+ self.template = template
+ if self.template is not None:
+ self._templateuri = self.template.module._template_uri
+ self.context = context
+ self.inherits = inherits
+ if callables is not None:
+ self.callables = dict([(c.func_name, c) for c in callables])
+ else:
+ self.callables = None
+ 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.
+
+ """
+
+ 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
+ can traverse an entire chain of templates that inherit from
+ 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`.
+
+ """
+ return self.template.uri
+
+ @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
+ :ref:`inheritance_toplevel`.
+
+ """
+ if not hasattr(self, '_attr'):
+ self._attr = _NSAttr(self)
+ return self._attr
+
+ 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
+ method is therefore mostly useful off of the built-in
+ ``local`` namespace, described in :ref:`namespace_local`
+
+ In
+ most cases, a template wouldn't need this function, and
+ should instead use the ``<%namespace>`` tag to load
+ namespaces. However, since all ``<%namespace>`` tags are
+ evaulated before the body of a template ever runs,
+ this method can be used to locate namespaces using
+ 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):
+ return self.context.namespaces[key]
+ else:
+ ns = Namespace(uri, self.context._copy(),
+ templateuri=uri,
+ calling_uri=self._templateuri)
+ self.context.namespaces[key] = ns
+ return ns
+
+ def get_template(self, uri):
+ """Return a :class:`.Template` from the given uri.
+
+ 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)
+ if createfunc:
+ return createfunc()
+ else:
+ return None
+
+ if self.template.cache_dir:
+ kwargs.setdefault('data_dir', self.template.cache_dir)
+ if self.template.cache_type:
+ kwargs.setdefault('type', self.template.cache_type)
+ 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 == '*':
+ for (k, v) in self._get_star():
+ d[k] = v
+ else:
+ d[ident] = getattr(self, ident)
+
+ def _get_star(self):
+ if self.callables:
+ for key in self.callables:
+ yield (key, self.callables[key])
+ if self.template:
+ def get(key):
+ callable_ = self.template._get_def_callable(key)
+ return util.partial(callable_, self.context)
+ for k in self.template.module._exports:
+ yield (k, get(k))
+ if self._module:
+ def get(key):
+ callable_ = getattr(self._module, key)
+ return util.partial(callable_, self.context)
+ 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]
+
+ if self.template and self.template.has_def(key):
+ callable_ = self.template._get_def_callable(key)
+ return util.partial(callable_, self.context)
+
+ if self._module and hasattr(self._module, key):
+ callable_ = getattr(self._module, key)
+ return util.partial(callable_, self.context)
+
+ if self.inherits is not None:
+ return getattr(self.inherits, key)
+ raise AttributeError(
+ "Namespace '%s' has no member '%s'" %
+ (self.name, key))
+
+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:
+ return func(context, *args, **kwargs)
+ 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 "
+ "its argument (i.e. capture(func, *args, **kwargs))"
+ )
+ context._push_buffer()
+ try:
+ callable_(*args, **kwargs)
+ finally:
+ buf = context._pop_buffer()
+ return buf.getvalue()
+
+def _decorate_toplevel(fn):
+ def decorate_render(render_fn):
+ def go(context, *args, **kw):
+ def y(*args, **kw):
+ return render_fn(context, *args, **kw)
+ try:
+ y.__name__ = render_fn.__name__[7:]
+ except TypeError:
+ # < Python 2.4
+ pass
+ 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)
+ def go(*args, **kw):
+ 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
+ execution."""
+
+ if uri is None:
+ return None
+ template = _lookup_template(context, uri, calling_uri)
+ self_ns = context['self']
+ ih = self_ns
+ while ih.inherits is not None:
+ ih = ih.inherits
+ lclcontext = context.locals_({'next':ih})
+ ih.inherits = Namespace("self:%s" % template.uri,
+ lclcontext,
+ template = template,
+ populate_self=False)
+ context._data['parent'] = lclcontext._data['local'] = ih.inherits
+ callable_ = getattr(template.module, '_mako_inherit', None)
+ if callable_ is not None:
+ ret = callable_(template, lclcontext)
+ if ret:
+ return ret
+
+ gen_ns = getattr(template.module, '_mako_generate_namespaces', None)
+ if gen_ns is not None:
+ gen_ns(context)
+ return (template.callable_, lclcontext)
+
+def _lookup_template(context, uri, relativeto):
+ lookup = context._with_template.lookup
+ if lookup is None:
+ raise exceptions.TemplateLookupException(
+ "Template '%s' has no TemplateLookup associated" %
+ context._with_template.uri)
+ uri = lookup.adjust_uri(uri, relativeto)
+ try:
+ return lookup.get_template(uri)
+ except exceptions.TopLevelLookupException, e:
+ raise exceptions.TemplateLookupException(str(e))
+
+def _populate_self_namespace(context, template, self_ns=None):
+ if self_ns is None:
+ self_ns = Namespace('self:%s' % template.uri,
+ context, template=template,
+ populate_self=False)
+ context._data['self'] = context._data['local'] = self_ns
+ if hasattr(template.module, '_mako_inherit'):
+ ret = template.module._mako_inherit(template, context)
+ if ret:
+ return ret
+ return (template.callable_, context)
+
+def _render(template, callable_, args, data, as_unicode=False):
+ """create a Context and return the string
+ output of the given template and template callable."""
+
+ if as_unicode:
+ buf = util.FastEncodingBuffer(unicode=True)
+ elif template.output_encoding:
+ buf = util.FastEncodingBuffer(
+ unicode=as_unicode,
+ encoding=template.output_encoding,
+ errors=template.encoding_errors)
+ else:
+ buf = util.StringIO()
+ 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()
+
+def _kwargs_for_callable(callable_, data):
+ argspec = inspect.getargspec(callable_)
+ # 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 = {}
+ for arg in namedargs:
+ if arg != 'context' and arg in data and arg not in kwargs:
+ kwargs[arg] = data[arg]
+ return kwargs
+
+def _kwargs_for_include(callable_, data, **kwargs):
+ argspec = inspect.getargspec(callable_)
+ namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
+ for arg in namedargs:
+ 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
+ # template with possibly updated context
+ if not isinstance(tmpl, template.DefTemplate):
+ # if main render method, call from the base of the inheritance stack
+ (inherit, lclcontext) = _populate_self_namespace(context, tmpl)
+ _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
+ else:
+ # 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
+
+ the contextual Template will be located if it exists, and
+ the error handling options specified on that Template will
+ be interpreted here.
+ """
+ template = context._with_template
+ if template is not None and \
+ (template.format_exceptions or template.error_handler):
+ error = None
+ try:
+ callable_(context, *args, **kwargs)
+ except Exception, e:
+ _render_error(template, context, e)
+ except:
+ e = sys.exc_info()[0]
+ _render_error(template, context, e)
+ else:
+ callable_(context, *args, **kwargs)
+
+def _render_error(template, context, error):
+ if template.error_handler:
+ result = template.error_handler(context, error)
+ if not result:
+ raise error
+ else:
+ error_template = exceptions.html_error_template()
+ if context._outputting_as_unicode:
+ context._buffer_stack[:] = [util.FastEncodingBuffer(unicode=True)]
+ else:
+ 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)
Added: pypy/benchmarks/lib/mako/mako/template.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/template.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,510 @@
+# template.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer
+# mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""Provides the Template class, a facade for parsing, generating and executing
+template strings, as well as template runtime operations."""
+
+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
+ generated Python module (i.e. the ``.code`` attribute),
+ as well as a reference to an actual Python module.
+
+ :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.
+
+ :param filename: filename of the source template. This argument is
+ mutually exclusive versus the "text" parameter.
+
+ :param buffer_filters: string list of filters to be applied
+ to the output of %defs which are buffered, cached, or otherwise
+ filtered, 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.
+
+ :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`.
+
+ :param default_filters: List of string filter names that will
+ be applied to all expressions. See :ref:`filtering_default_filters`.
+
+ :param disable_unicode: Disables all awareness of Python Unicode
+ objects. See :ref:`unicode_disabled`.
+
+ :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
+ callable returns ``True``, the exception is considered to
+ 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
+ in :ref:`filtering_default_filters`.
+
+ :param input_encoding: Encoding of the template's source code. Can
+ 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.
+ 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,
+ uri=None,
+ format_exceptions=False,
+ error_handler=None,
+ lookup=None,
+ output_encoding=None,
+ encoding_errors='strict',
+ module_directory=None,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
+ module_filename=None,
+ input_encoding=None,
+ disable_unicode=False,
+ default_filters=None,
+ buffer_filters=(),
+ strict_undefined=False,
+ imports=None,
+ preprocessor=None,
+ cache_enabled=True):
+ if uri:
+ self.module_id = re.sub(r'\W', "_", uri)
+ self.uri = uri
+ elif filename:
+ self.module_id = re.sub(r'\W', "_", filename)
+ drive, path = os.path.splitdrive(filename)
+ path = os.path.normpath(path).replace(os.path.sep, "/")
+ self.uri = path
+ 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
+ self.disable_unicode = disable_unicode
+ self.strict_undefined = strict_undefined
+
+ if util.py3k and disable_unicode:
+ 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']
+ else:
+ self.default_filters = ['unicode']
+ 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)
+ self._code = code
+ self._source = text
+ ModuleInfo(module, None, self, filename, code, text)
+ elif filename is not None:
+ # if template filename and a module directory, load
+ # a filesystem-based module file, generating if needed
+ if module_filename is not None:
+ path = module_filename
+ elif module_directory is not None:
+ u = self.uri
+ if u[0] == '/':
+ u = u[1:]
+ path = os.path.abspath(
+ os.path.join(
+ os.path.normpath(module_directory),
+ os.path.normpath(u) + ".py"
+ )
+ )
+ else:
+ path = None
+
+ module = self._compile_from_file(path, filename)
+ else:
+ raise exceptions.RuntimeException(
+ "Template requires text or filename")
+
+ self.module = module
+ self.filename = filename
+ self.callable_ = self.module.render_body
+ self.format_exceptions = format_exceptions
+ self.error_handler = error_handler
+ self.lookup = lookup
+ self.cache_type = cache_type
+ 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))
+ filemtime = os.stat(filename)[stat.ST_MTIME]
+ if not os.path.exists(path) or \
+ os.stat(path)[stat.ST_MTIME] < filemtime:
+ _compile_module_file(
+ self,
+ open(filename, 'rb').read(),
+ filename,
+ path)
+ module = imp.load_source(self.module_id, path, open(path, 'rb'))
+ del sys.modules[self.module_id]
+ if module._magic_number != codegen.MAGIC_NUMBER:
+ _compile_module_file(
+ self,
+ open(filename, 'rb').read(),
+ filename,
+ path)
+ module = imp.load_source(self.module_id, path, open(path, 'rb'))
+ del sys.modules[self.module_id]
+ ModuleInfo(module, path, self, filename, None, None)
+ else:
+ # template filename and no module directory, compile code
+ # in memory
+ code, module = _compile_text(
+ self,
+ open(filename, 'rb').read(),
+ filename)
+ self._source = None
+ self._code = code
+ ModuleInfo(module, None, self, filename, code, None)
+ return module
+
+ @property
+ def source(self):
+ """return the template source code for this 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
+ characters). a Context object is created corresponding
+ 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.
+
+ the data is written to the context's buffer.
+
+ """
+ if getattr(context, '_with_template', None) is None:
+ context._with_template = self
+ runtime._render_context(self,
+ self.callable_,
+ context,
+ *args,
+ **kwargs)
+
+ def has_def(self, name):
+ return hasattr(self.module, "render_%s" % name)
+
+ def get_def(self, name):
+ """Return a def of this template as a :class:`.DefTemplate`."""
+
+ return DefTemplate(self, getattr(self.module, "render_%s" % name))
+
+ def _get_def_callable(self, name):
+ return getattr(self.module, "render_%s" % name)
+
+ @property
+ def last_modified(self):
+ return self.module._modified_time
+
+class ModuleTemplate(Template):
+ """A Template which is constructed given an existing Python module.
+
+ e.g.::
+
+ t = Template("this is a template")
+ f = file("mymodule.py", "w")
+ f.write(t.code)
+ f.close()
+
+ import mymodule
+
+ t = ModuleTemplate(mymodule)
+ print t.render()
+
+ """
+
+ def __init__(self, module,
+ module_filename=None,
+ template=None,
+ template_filename=None,
+ module_source=None,
+ template_source=None,
+ output_encoding=None,
+ encoding_errors='strict',
+ disable_unicode=False,
+ format_exceptions=False,
+ error_handler=None,
+ lookup=None,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
+ cache_enabled=True
+ ):
+ self.module_id = re.sub(r'\W', "_", module._template_uri)
+ self.uri = module._template_uri
+ self.input_encoding = module._source_encoding
+ self.output_encoding = output_encoding
+ self.encoding_errors = encoding_errors
+ self.disable_unicode = disable_unicode
+ self.module = module
+ self.filename = template_filename
+ ModuleInfo(module,
+ module_filename,
+ self,
+ template_filename,
+ module_source,
+ template_source)
+
+ self.callable_ = self.module.render_body
+ self.format_exceptions = format_exceptions
+ self.error_handler = error_handler
+ self.lookup = lookup
+ self.cache_type = cache_type
+ 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_
+ self.output_encoding = parent.output_encoding
+ self.module = parent.module
+ self.encoding_errors = parent.encoding_errors
+ self.format_exceptions = parent.format_exceptions
+ self.error_handler = parent.error_handler
+ self.lookup = parent.lookup
+
+ def get_def(self, name):
+ return self.parent.get_def(name)
+
+class ModuleInfo(object):
+ """Stores information about a module currently loaded into
+ memory, provides reverse lookups of template source, module
+ source code based on a module's identifier.
+
+ """
+ _modules = weakref.WeakValueDictionary()
+
+ def __init__(self,
+ module,
+ module_filename,
+ template,
+ template_filename,
+ module_source,
+ template_source):
+ self.module = module
+ self.module_filename = module_filename
+ self.template_filename = template_filename
+ self.module_source = module_source
+ self.template_source = template_source
+ 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:
+ if self.module._source_encoding and \
+ not isinstance(self.template_source, unicode):
+ return self.template_source.decode(
+ self.module._source_encoding)
+ else:
+ return self.template_source
+ else:
+ if self.module._source_encoding:
+ return open(self.template_filename, 'rb').read().\
+ 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,
+ filename,
+ disable_unicode=template.disable_unicode,
+ input_encoding=template.input_encoding,
+ preprocessor=template.preprocessor)
+ node = lexer.parse()
+
+ source = codegen.compile(node,
+ template.uri,
+ filename,
+ default_filters=template.default_filters,
+ buffer_filters=template.buffer_filters,
+ imports=template.imports,
+ source_encoding=lexer.encoding,
+ generate_magic_comment=template.disable_unicode,
+ disable_unicode=template.disable_unicode,
+ strict_undefined=template.strict_undefined)
+
+ cid = identifier
+ if not util.py3k and isinstance(cid, unicode):
+ cid = cid.encode()
+ module = types.ModuleType(cid)
+ code = compile(source, cid, 'exec')
+ exec code in module.__dict__, module.__dict__
+ return (source, module)
+
+def _compile_module_file(template, text, filename, outputpath):
+ identifier = template.module_id
+ lexer = Lexer(text,
+ filename,
+ disable_unicode=template.disable_unicode,
+ input_encoding=template.input_encoding,
+ preprocessor=template.preprocessor)
+
+ node = lexer.parse()
+ source = codegen.compile(node,
+ template.uri,
+ filename,
+ default_filters=template.default_filters,
+ buffer_filters=template.buffer_filters,
+ imports=template.imports,
+ source_encoding=lexer.encoding,
+ 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]
+
Added: pypy/benchmarks/lib/mako/mako/util.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/mako/util.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,316 @@
+# util.py
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp at zzzcomputing.com
+#
+# This module is part of Mako and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+import sys
+
+
+py3k = getattr(sys, 'py3kwarning', False) or sys.version_info >= (3, 0)
+py24 = sys.version_info >= (2, 4) and sys.version_info < (2, 5)
+jython = sys.platform.startswith('java')
+win32 = sys.platform.startswith('win')
+
+if py3k:
+ from io import StringIO
+else:
+ try:
+ from cStringIO import StringIO
+ except:
+ from StringIO import StringIO
+
+import codecs, re, weakref, os, time, operator
+
+try:
+ import threading
+ import thread
+except ImportError:
+ import dummy_threading as threading
+ import dummy_thread as thread
+
+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__.
+
+ Will assign to __name__ and return the original function if possible on
+ the Python implementation, otherwise a new function will be constructed.
+
+ """
+ fn.__name__ = name
+ return fn
+
+try:
+ from functools import partial
+except:
+ def partial(func, *args, **keywords):
+ def newfunc(*fargs, **fkeywords):
+ newkeywords = keywords.copy()
+ newkeywords.update(fkeywords)
+ return func(*(args + fargs), **newkeywords)
+ return newfunc
+
+if py24:
+ def exception_name(exc):
+ try:
+ return exc.__class__.__name__
+ except AttributeError:
+ return exc.__name__
+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
+ os.makedirs(dir, 0775)
+ except:
+ if tries > 5:
+ raise
+
+def to_list(x, default=None):
+ if x is None:
+ return default
+ if not isinstance(x, (list, tuple)):
+ return [x]
+ else:
+ 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)
+ return x
+
+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
+ if unicode:
+ self.delim = u''
+ else:
+ self.delim = ''
+ 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)
+ else:
+ return self.delim.join(self.data)
+
+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
+ self.value = value
+ 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:
+ item = self._Item(key, value)
+ dict.__setitem__(self, key, item)
+ 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),
+ key=operator.attrgetter('timestamp'), reverse=True)
+ for item in bytime[self.capacity:]:
+ try:
+ del self[item.key]
+ except KeyError:
+ # if we couldnt find a key, most likely some other thread broke in
+ # on us. loop around and try again
+ break
+
+# Regexp to match python magic encoding line
+_PYTHON_MAGIC_COMMENT_re = re.compile(
+ r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)',
+ re.VERBOSE)
+
+def parse_encoding(fp):
+ """Deduce the encoding of a Python source file (binary mode) from magic comment.
+
+ It does this in the same way as the `Python interpreter`__
+
+ .. __: http://docs.python.org/ref/encodings.html
+
+ The ``fp`` argument should be a seekable file object in binary mode.
+ """
+ pos = fp.tell()
+ fp.seek(0)
+ try:
+ line1 = fp.readline()
+ has_bom = line1.startswith(codecs.BOM_UTF8)
+ if has_bom:
+ line1 = line1[len(codecs.BOM_UTF8):]
+
+ m = _PYTHON_MAGIC_COMMENT_re.match(line1.decode('ascii', 'ignore'))
+ if not m:
+ try:
+ import parser
+ parser.suite(line1.decode('ascii', 'ignore'))
+ except (ImportError, SyntaxError):
+ # Either it's a real syntax error, in which case the source
+ # is not valid python source, or line2 is a continuation of
+ # line1, in which case we don't want to scan line2 for a magic
+ # comment.
+ pass
+ else:
+ line2 = fp.readline()
+ m = _PYTHON_MAGIC_COMMENT_re.match(line2.decode('ascii', 'ignore'))
+
+ if has_bom:
+ if m:
+ raise SyntaxError, \
+ "python refuses to compile code with both a UTF8" \
+ " byte-order-mark and a magic encoding comment"
+ return 'utf_8'
+ elif m:
+ return m.group(1)
+ else:
+ return None
+ finally:
+ fp.seek(pos)
+
+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
+ """
+ if hasattr(_ast, 'AST'):
+ return
+ _ast.PyCF_ONLY_AST = 2 << 9
+ m = compile("""\
+def foo(): pass
+class Bar(object): pass
+if False: pass
+baz = 'mako'
+1 + 2 - 3 * 4 / 5
+6 // 7 % 8 << 9 >> 10
+11 & 12 ^ 13 | 14
+15 and 16 or 17
+-baz + (not +18) - ~17
+baz and 'foo' or 'bar'
+(mako is baz == baz) is not baz != mako
+mako > baz < mako >= baz <= mako
+mako in baz not in mako""", '<unknown>', 'exec', _ast.PyCF_ONLY_AST)
+ _ast.Module = type(m)
+
+ for cls in _ast.Module.__mro__:
+ if cls.__name__ == 'mod':
+ _ast.mod = cls
+ elif cls.__name__ == 'AST':
+ _ast.AST = cls
+
+ _ast.FunctionDef = type(m.body[0])
+ _ast.ClassDef = type(m.body[1])
+ _ast.If = type(m.body[2])
+
+ _ast.Name = type(m.body[3].targets[0])
+ _ast.Store = type(m.body[3].targets[0].ctx)
+ _ast.Str = type(m.body[3].value)
+
+ _ast.Sub = type(m.body[4].value.op)
+ _ast.Add = type(m.body[4].value.left.op)
+ _ast.Div = type(m.body[4].value.right.op)
+ _ast.Mult = type(m.body[4].value.right.left.op)
+
+ _ast.RShift = type(m.body[5].value.op)
+ _ast.LShift = type(m.body[5].value.left.op)
+ _ast.Mod = type(m.body[5].value.left.left.op)
+ _ast.FloorDiv = type(m.body[5].value.left.left.left.op)
+
+ _ast.BitOr = type(m.body[6].value.op)
+ _ast.BitXor = type(m.body[6].value.left.op)
+ _ast.BitAnd = type(m.body[6].value.left.left.op)
+
+ _ast.Or = type(m.body[7].value.op)
+ _ast.And = type(m.body[7].value.values[0].op)
+
+ _ast.Invert = type(m.body[8].value.right.op)
+ _ast.Not = type(m.body[8].value.left.right.op)
+ _ast.UAdd = type(m.body[8].value.left.right.operand.op)
+ _ast.USub = type(m.body[8].value.left.left.op)
+
+ _ast.Or = type(m.body[9].value.op)
+ _ast.And = type(m.body[9].value.values[0].op)
+
+ _ast.IsNot = type(m.body[10].value.ops[0])
+ _ast.NotEq = type(m.body[10].value.ops[1])
+ _ast.Is = type(m.body[10].value.left.ops[0])
+ _ast.Eq = type(m.body[10].value.left.ops[1])
+
+ _ast.Gt = type(m.body[11].value.ops[0])
+ _ast.Lt = type(m.body[11].value.ops[1])
+ _ast.GtE = type(m.body[11].value.ops[2])
+ _ast.LtE = type(m.body[11].value.ops[3])
+
+ _ast.In = type(m.body[12].value.ops[0])
+ _ast.NotIn = type(m.body[12].value.ops[1])
Added: pypy/benchmarks/lib/mako/scripts/mako-render
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/scripts/mako-render Tue Dec 21 07:44:16 2010
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+def render(data):
+ from mako.template import Template
+ from mako.lookup import TemplateLookup
+
+ lookup = TemplateLookup(["."])
+ return Template(data, lookup=lookup).render()
+
+def main(argv=None):
+ from os.path import isfile
+ from sys import stdin
+
+ if argv is None:
+ import sys
+ argv = sys.argv
+
+ from optparse import OptionParser
+
+ parser = OptionParser("usage: %prog [FILENAME]")
+
+ opts, args = parser.parse_args(argv[1:])
+ if len(args) not in (0, 1):
+ parser.error("wrong number of arguments") # Will exit
+
+ if (len(args) == 0) or (args[0] == "-"):
+ fo = stdin
+ else:
+ filename = args[0]
+ if not isfile(filename):
+ raise SystemExit("error: can't find %s" % filename)
+ fo = open(filename)
+
+ data = fo.read()
+ print render(data)
+
+if __name__ == "__main__":
+ main()
Added: pypy/benchmarks/lib/mako/setup.cfg
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/setup.cfg Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+[egg_info]
+tag_build = dev
Added: pypy/benchmarks/lib/mako/setup.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/setup.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,68 @@
+from setuptools import setup, find_packages
+import os
+import re
+import sys
+
+extra = {}
+if sys.version_info >= (3, 0):
+ extra.update(
+ use_2to3=True,
+ )
+
+v = open(os.path.join(os.path.dirname(__file__), 'mako', '__init__.py'))
+VERSION = re.compile(r".*__version__ = '(.*?)'", re.S).match(v.read()).group(1)
+v.close()
+
+setup(name='Mako',
+ version=VERSION,
+ description="A super-fast templating language that borrows the \
+ best ideas from the existing templating languages.",
+ long_description="""\
+Mako is a template library written in Python. It provides a familiar, non-XML
+syntax which compiles into Python modules for maximum performance. Mako's
+syntax and API borrows from the best ideas of many others, including Django
+templates, Cheetah, Myghty, and Genshi. Conceptually, Mako is an embedded
+Python (i.e. Python Server Page) language, which refines the familiar ideas
+of componentized layout and inheritance to produce one of the most
+straightforward and flexible models available, while also maintaining close
+ties to Python calling and scoping semantics.
+
+""",
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+ ],
+ keywords='wsgi myghty mako',
+ author='Mike Bayer',
+ author_email='mike at zzzcomputing.com',
+ url='http://www.makotemplates.org/',
+ license='MIT',
+ packages=find_packages('.', exclude=['examples*', 'test*']),
+ scripts=['scripts/mako-render'],
+ tests_require = ['nose >= 0.11'],
+ test_suite = "nose.collector",
+ zip_safe=False,
+ install_requires=[
+ 'MarkupSafe>=0.9.2',
+ ],
+ extras_require = {'beaker':['Beaker>=1.1']},
+ entry_points="""
+ [python.templating.engines]
+ mako = mako.ext.turbogears:TGPlugin
+
+ [pygments.lexers]
+ mako = mako.ext.pygmentplugin:MakoLexer
+ html+mako = mako.ext.pygmentplugin:MakoHtmlLexer
+ xml+mako = mako.ext.pygmentplugin:MakoXmlLexer
+ js+mako = mako.ext.pygmentplugin:MakoJavascriptLexer
+ css+mako = mako.ext.pygmentplugin:MakoCssLexer
+
+ [babel.extractors]
+ mako = mako.ext.babelplugin:extract
+ """,
+ **extra
+)
Added: pypy/benchmarks/lib/mako/test/__init__.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/__init__.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,93 @@
+from mako.template import Template
+import unittest, os
+from mako.util import function_named, py3k
+import re
+
+from nose import SkipTest
+
+
+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 = {}
+ if unicode_:
+ 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)
+
+def teardown():
+ import shutil
+ shutil.rmtree(module_base, True)
+
+def assert_raises(except_cls, callable_, *args, **kw):
+ try:
+ 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"
+
+def assert_raises_message(except_cls, msg, callable_, *args, **kwargs):
+ try:
+ callable_(*args, **kwargs)
+ assert False, "Callable did not raise an exception"
+ except except_cls, e:
+ assert re.search(msg, str(e)), "%r !~ %s" % (msg, e)
+ print str(e)
+
+def skip_if(predicate, reason=None):
+ """Skip a test if predicate is true."""
+ reason = reason or predicate.__name__
+
+ def decorate(fn):
+ fn_name = fn.__name__
+ def maybe(*args, **kw):
+ if predicate():
+ msg = "'%s' skipped: %s" % (
+ fn_name, reason)
+ raise SkipTest(msg)
+ else:
+ return fn(*args, **kw)
+ return function_named(maybe, fn_name)
+ return decorate
Added: pypy/benchmarks/lib/mako/test/foo/__init__.py
==============================================================================
Added: pypy/benchmarks/lib/mako/test/foo/test_ns.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/foo/test_ns.py Tue Dec 21 07:44:16 2010
@@ -0,0 +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
Added: pypy/benchmarks/lib/mako/test/sample_module_namespace.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/sample_module_namespace.py Tue Dec 21 07:44:16 2010
@@ -0,0 +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
Added: pypy/benchmarks/lib/mako/test/templates/badbom.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/badbom.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+## -*- coding: ascii -*-
+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! »
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/bom.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/bom.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1 @@
+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! »
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/bommagic.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/bommagic.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+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! »
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/chs_unicode.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/chs_unicode.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,11 @@
+## -*- encoding:utf8 -*-
+<%
+ msg = u'新中国的主席'
+%>
+
+<%def name="welcome(who, place=u'北京')">
+Welcome ${who} to ${place}.
+</%def>
+
+${name} 是 ${msg}<br/>
+${welcome(u'你')}
Added: pypy/benchmarks/lib/mako/test/templates/chs_unicode_py3k.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/chs_unicode_py3k.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,11 @@
+## -*- encoding:utf8 -*-
+<%
+ msg = '新中国的主席'
+%>
+
+<%def name="welcome(who, place='北京')">
+Welcome ${who} to ${place}.
+</%def>
+
+${name} 是 ${msg}<br/>
+${welcome('你')}
Added: pypy/benchmarks/lib/mako/test/templates/chs_utf8.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/chs_utf8.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,17 @@
+## -*- encoding:utf8 -*-
+<%
+ msg = '新中国的主席'
+%>
+
+<%def name="welcome(who, place='北京')">
+Welcome ${who} to ${place}.
+</%def>
+
+<%def name="welcome_buffered(who, place='北京')" buffered="True">
+Welcome ${who} to ${place}.
+</%def>
+
+${name} 是 ${msg}<br/>
+${welcome('你')}
+${welcome_buffered('你')}
+
Added: pypy/benchmarks/lib/mako/test/templates/crlf.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/crlf.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,19 @@
+<html>
+
+<%page args="a=['foo',
+ 'bar']"/>
+
+like the name says.
+
+ % for x in [1,2,3]:
+ ${x}\
+ % endfor
+
+${trumpeter == 'Miles' and trumpeter or \
+ 'Dizzy'}
+
+<%def name="hi()">
+ hi!
+</%def>
+
+</html>
Added: pypy/benchmarks/lib/mako/test/templates/foo/modtest.html.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/foo/modtest.html.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,25 @@
+from mako import runtime, filters, cache
+UNDEFINED = runtime.UNDEFINED
+__M_dict_builtin = dict
+__M_locals_builtin = locals
+_magic_number = 5
+_modified_time = 1267565427.7968459
+_template_filename='/Users/classic/dev/mako/test/templates/modtest.html'
+_template_uri='/modtest.html'
+_template_cache=cache.Cache(__name__, _modified_time)
+_source_encoding=None
+_exports = []
+
+
+def render_body(context,**pageargs):
+ context.caller_stack._push_frame()
+ try:
+ __M_locals = __M_dict_builtin(pageargs=pageargs)
+ __M_writer = context.writer()
+ # SOURCE LINE 1
+ __M_writer(u'this is a test')
+ return ''
+ finally:
+ context.caller_stack._pop_frame()
+
+
Added: pypy/benchmarks/lib/mako/test/templates/gettext.mako
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/gettext.mako Tue Dec 21 07:44:16 2010
@@ -0,0 +1,83 @@
+<%page args="x, y=_('Page arg 1'), z=_('Page arg 2')"/>
+<%!
+import random
+def gettext(message): return message
+_ = gettext
+def ungettext(s, p, c):
+ if c == 1:
+ return s
+ return p
+top = gettext('Begin')
+%>
+<%
+ # TRANSLATOR: Hi there!
+ hithere = _('Hi there!')
+
+ # TRANSLATOR: you should not be seeing this in the .po
+ rows = [[v for v in range(0,10)] for row in range(0,10)]
+
+ hello = _('Hello')
+%>
+<div id="header">
+ ${_('Welcome')}
+</div>
+<table>
+ % for row in (hithere, hello, _('Yo')):
+ ${makerow(row)}
+ % endfor
+ ${makerow(count=2)}
+</table>
+
+
+<div id="main">
+
+## TRANSLATOR: Ensure so and
+## so, thanks
+ ${_('The')} fuzzy ${ungettext('bunny', 'bunnies', random.randint(1, 2))}
+</div>
+
+<div id="footer">
+ ## TRANSLATOR: Good bye
+ ${_('Goodbye')}
+</div>
+
+<%def name="makerow(row=_('Babel'), count=1)">
+ <!-- ${ungettext('hella', 'hellas', count)} -->
+ % for i in range(count):
+ <tr>
+ % for name in row:
+ <td>${name}</td>\
+ % endfor
+ </tr>
+ % endfor
+</%def>
+
+<%def name="comment()">
+ <!-- ${caller.body()} -->
+</%def>
+
+<%call expr="comment">
+ P.S.
+ ## TRANSLATOR: HTML comment
+ ${_('Goodbye, really!')}
+</%call>
+
+<!-- ${_('P.S. byebye')} -->
+
+<div id="end">
+ <a href="#top">
+ ## TRANSLATOR: you won't see this either
+
+ ${_('Top')}
+ </a>
+</div>
+
+<%def name="panel()">
+
+${_(u'foo')} <%self:block_tpl title="123", name="_(u'baz')">
+
+${_(u'bar')}
+
+</%self:block_tpl>
+
+</%def>
Added: pypy/benchmarks/lib/mako/test/templates/index.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/index.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1 @@
+this is index
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/internationalization.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/internationalization.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,920 @@
+<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>
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>James Gardner</td></tr>
+<tr class="field"><th class="docinfo-name">updated:</th><td class="field-body">2006-12-11</td>
+</tr>
+</tbody>
+</table>
+
+ <div class="note">
+<p class="first admonition-title">Note</p>
+<p>This is a work in progress. We hope the internationalization, localization
+and Unicode support in Pylons is now robust and flexible but we would
+appreciate hearing about any issues we have. Just drop a line to the
+pylons-discuss mailing list on Google Groups.</p>
+<p class="last">This is the first draft of the full document including Unicode. Expect
+some typos and spelling mistakes!</p>
+</div>
+<div class="contents topic">
+<p class="topic-title first"><a id="table-of-contents" name="table-of-contents">Table of Contents</a></p>
+<ul class="auto-toc simple">
+<li><a href="#understanding-unicode" id="id1" name="id1" class="reference">1 Understanding Unicode</a><ul class="auto-toc">
+<li><a href="#what-is-unicode" id="id2" name="id2" class="reference">1.1 What is Unicode?</a></li>
+<li><a href="#unicode-in-python" id="id3" name="id3" class="reference">1.2 Unicode in Python</a></li>
+<li><a href="#unicode-literals-in-python-source-code" id="id4" name="id4" class="reference">1.3 Unicode Literals in Python Source Code</a></li>
+<li><a href="#input-and-output" id="id5" name="id5" class="reference">1.4 Input and Output</a></li>
+<li><a href="#unicode-filenames" id="id6" name="id6" class="reference">1.5 Unicode Filenames</a></li>
+</ul>
+</li>
+<li><a href="#applying-this-to-web-programming" id="id7" name="id7" class="reference">2 Applying this to Web Programming</a><ul class="auto-toc">
+<li><a href="#request-parameters" id="id8" name="id8" class="reference">2.1 Request Parameters</a></li>
+<li><a href="#templating" id="id9" name="id9" class="reference">2.2 Templating</a></li>
+<li><a href="#output-encoding" id="id10" name="id10" class="reference">2.3 Output Encoding</a></li>
+<li><a href="#databases" id="id11" name="id11" class="reference">2.4 Databases</a></li>
+</ul>
+</li>
+<li><a href="#internationalization-and-localization" id="id12" name="id12" class="reference">3 Internationalization and Localization</a><ul class="auto-toc">
+<li><a href="#getting-started" id="id13" name="id13" class="reference">3.1 Getting Started</a></li>
+<li><a href="#testing-the-application" id="id14" name="id14" class="reference">3.2 Testing the Application</a></li>
+<li><a href="#missing-translations" id="id15" name="id15" class="reference">3.3 Missing Translations</a></li>
+<li><a href="#translations-within-templates" id="id16" name="id16" class="reference">3.4 Translations Within Templates</a></li>
+<li><a href="#producing-a-python-egg" id="id17" name="id17" class="reference">3.5 Producing a Python Egg</a></li>
+<li><a href="#plural-forms" id="id18" name="id18" class="reference">3.6 Plural Forms</a></li>
+</ul>
+</li>
+<li><a href="#summary" id="id19" name="id19" class="reference">4 Summary</a></li>
+<li><a href="#further-reading" id="id20" name="id20" class="reference">5 Further Reading</a></li>
+</ul>
+</div>
+<p>Internationalization and localization are means of adapting software for
+non-native environments, especially for other nations and cultures.</p>
+<p>Parts of an application which might need to be localized might include:</p>
+<blockquote>
+<ul class="simple">
+<li>Language</li>
+<li>Date/time format</li>
+<li>Formatting of numbers e.g. decimal points, positioning of separators,
+character used as separator</li>
+<li>Time zones (UTC in internationalized environments)</li>
+<li>Currency</li>
+<li>Weights and measures</li>
+</ul>
+</blockquote>
+<p>The distinction between internationalization and localization is subtle but
+important. Internationalization is the adaptation of products for potential use
+virtually everywhere, while localization is the addition of special features
+for use in a specific locale.</p>
+<p>For example, in terms of language used in software, internationalization is the
+process of marking up all strings that might need to be translated whilst
+localization is the process of producing translations for a particular locale.</p>
+<p>Pylons provides built-in support to enable you to internationalize language but
+leaves you to handle any other aspects of internationalization which might be
+appropriate to your application.</p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Internationalization is often abbreviated as I18N (or i18n or I18n) where the
+number 18 refers to the number of letters omitted.
+Localization is often abbreviated L10n or l10n in the same manner. These
+abbreviations also avoid picking one spelling (internationalisation vs.
+internationalization, etc.) over the other.</p>
+</div>
+<p>In order to represent characters from multiple languages, you will need to use
+Unicode so this documentation will start with a description of why Unicode is
+useful, its history and how to use Unicode in Python.</p>
+<div class="section">
+<h1><a href="#id1" id="understanding-unicode" name="understanding-unicode" class="toc-backref">1 Understanding Unicode</a></h1>
+<p>If you've ever come across text in a foreign language that contains lots of
+<tt class="docutils literal"><span class="pre">????</span></tt> characters or have written some Python code and received a message
+such as <tt class="docutils literal"><span class="pre">UnicodeDecodeError:</span> <span class="pre">'ascii'</span> <span class="pre">codec</span> <span class="pre">can't</span> <span class="pre">decode</span> <span class="pre">byte</span> <span class="pre">0xff</span> <span class="pre">in</span> <span class="pre">position</span>
+<span class="pre">6:</span> <span class="pre">ordinal</span> <span class="pre">not</span> <span class="pre">in</span> <span class="pre">range(128)</span></tt> then you have run into a problem with character
+sets, encodings, Unicode and the like.</p>
+<p>The truth is that many developers are put off by Unicode because most of the
+time it is possible to muddle through rather than take the time to learn the
+basics. To make the problem worse if you have a system that manages to fudge
+the issues and just about work and then start trying to do things properly with
+Unicode it often highlights problems in other parts of your code.</p>
+<p>The good news is that Python has great Unicode support, so the rest of
+this article will show you how to correctly use Unicode in Pylons to avoid
+unwanted <tt class="docutils literal"><span class="pre">?</span></tt> characters and <tt class="docutils literal"><span class="pre">UnicodeDecodeErrors</span></tt>.</p>
+<div class="section">
+<h2><a href="#id2" id="what-is-unicode" name="what-is-unicode" class="toc-backref">1.1 What is Unicode?</a></h2>
+<p>When computers were first being used the characters that were most important
+were unaccented English letters. Each of these letters could be represented by
+a number between 32 and 127 and thus was born ASCII, a character set where
+space was 32, the letter "A" was 65 and everything could be stored in 7 bits.</p>
+<p>Most computers in those days were using 8-bit bytes so people quickly realized
+that they could use the codes 128-255 for their own purposes. Different people
+used the codes 128-255 to represent different characters and before long these
+different sets of characters were also standardized into <em>code pages</em>. This
+meant that if you needed some non-ASCII characters in a document you could also
+specify a codepage which would define which extra characters were available.
+For example Israel DOS used a code page called 862, while Greek users used 737.
+This just about worked for Western languages provided you didn't want to write
+an Israeli document with Greek characters but it didn't work at all for Asian
+languages where there are many more characters than can be represented in 8
+bits.</p>
+<p>Unicode is a character set that solves these problems by uniquely defining
+<em>every</em> character that is used anywhere in the world. Rather than defining a
+character as a particular combination of bits in the way ASCII does, each
+character is assigned a <em>code point</em>. For example the word <tt class="docutils literal"><span class="pre">hello</span></tt> is made
+from code points <tt class="docutils literal"><span class="pre">U+0048</span> <span class="pre">U+0065</span> <span class="pre">U+006C</span> <span class="pre">U+006C</span> <span class="pre">U+006F</span></tt>. The full list of code
+points can be found at <a href="http://www.unicode.org/charts/" class="reference">http://www.unicode.org/charts/</a>.</p>
+<p>There are lots of different ways of encoding Unicode code points into bits but
+the most popular encoding is UTF-8. Using UTF-8, every code point from 0-127 is
+stored in a single byte. Only code points 128 and above are stored using 2, 3,
+in fact, up to 6 bytes. This has the useful side effect that English text looks
+exactly the same in UTF-8 as it did in ASCII, because for every
+ASCII character with hexadecimal value 0xXY, the corresponding Unicode
+code point is U+00XY. This backwards compatibility is why if you are developing
+an application that is only used by English speakers you can often get away
+without handling characters properly and still expect things to work most of
+the time. Of course, if you use a different encoding such as UTF-16 this
+doesn't apply since none of the code points are encoded to 8 bits.</p>
+<p>The important things to note from the discussion so far are that:</p>
+<ul>
+<li><p class="first">Unicode can represent pretty much any character in any writing system in
+widespread use today</p>
+</li>
+<li><p class="first">Unicode uses code points to represent characters and the way these map to bits
+in memory depends on the encoding</p>
+</li>
+<li><dl class="first docutils">
+<dt>The most popular encoding is UTF-8 which has several convenient properties:</dt>
+<dd><ol class="first last arabic simple">
+<li>It can handle any Unicode code point</li>
+<li>A Unicode string is turned into a string of bytes containing no embedded
+zero bytes. This avoids byte-ordering issues, and means UTF-8 strings can be
+processed by C functions such as strcpy() and sent through protocols that can't
+handle zero bytes</li>
+<li>A string of ASCII text is also valid UTF-8 text</li>
+<li>UTF-8 is fairly compact; the majority of code points are turned into two
+bytes, and values less than 128 occupy only a single byte.</li>
+<li>If bytes are corrupted or lost, it's possible to determine the start of
+the next UTF-8-encoded code point and resynchronize.</li>
+</ol>
+</dd>
+</dl>
+</li>
+</ul>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Since Unicode 3.1, some extensions have even been defined so that the
+defined range is now U+000000 to U+10FFFF (21 bits), and formally, the
+character set is defined as 31-bits to allow for future expansion. It is a myth
+that there are 65,536 Unicode code points and that every Unicode letter can
+really be squeezed into two bytes. It is also incorrect to think that UTF-8 can
+represent less characters than UTF-16. UTF-8 simply uses a variable number of
+bytes for a character, sometimes just one byte (8 bits).</p>
+</div>
+</div>
+<div class="section">
+<h2><a href="#id3" id="unicode-in-python" name="unicode-in-python" class="toc-backref">1.2 Unicode in Python</a></h2>
+<p>In Python Unicode strings are expressed as instances of the built-in
+<tt class="docutils literal"><span class="pre">unicode</span></tt> type. Under the hood, Python represents Unicode strings as either
+16 or 32 bit integers, depending on how the Python interpreter was compiled.</p>
+<p>The <tt class="docutils literal"><span class="pre">unicode()</span></tt> constructor has the signature <tt class="docutils literal"><span class="pre">unicode(string[,</span> <span class="pre">encoding,</span>
+<span class="pre">errors])</span></tt>. All of its arguments should be 8-bit strings. The first argument is
+converted to Unicode using the specified encoding; if you leave off the
+encoding argument, the ASCII encoding is used for the conversion, so characters
+greater than 127 will be treated as errors:</p>
+<pre class="literal-block">
+>>> unicode('hello')
+u'hello'
+>>> s = unicode('hello')
+>>> type(s)
+<type 'unicode'>
+>>> unicode('hello' + chr(255))
+Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 6:
+ ordinal not in range(128)
+</pre>
+<p>The <tt class="docutils literal"><span class="pre">errors</span></tt> argument specifies what to do if the string can't be decoded to
+ascii. Legal values for this argument are <tt class="docutils literal"><span class="pre">'strict'</span></tt> (raise a
+<tt class="docutils literal"><span class="pre">UnicodeDecodeError</span></tt> exception), <tt class="docutils literal"><span class="pre">'replace'</span></tt> (replace the character that
+can't be decoded with another one), or <tt class="docutils literal"><span class="pre">'ignore'</span></tt> (just leave the character
+out of the Unicode result).</p>
+<blockquote>
+<pre class="doctest-block">
+>>> unicode('\x80abc', errors='strict')
+Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0:
+ ordinal not in range(128)
+>>> unicode('\x80abc', errors='replace')
+u'\ufffdabc'
+>>> unicode('\x80abc', errors='ignore')
+u'abc'
+</pre>
+</blockquote>
+<p>It is important to understand the difference between <em>encoding</em> and <em>decoding</em>.
+Unicode strings are considered to be the Unicode code points but any
+representation of the Unicode string has to be encoded to something else, for
+example UTF-8 or ASCII. So when you are converting an ASCII or UTF-8 string to
+Unicode you are <em>decoding</em> it and when you are converting from Unicode to UTF-8
+or ASCII you are <em>encoding</em> it. This is why the error in the example above says
+that the ASCII codec cannot decode the byte <tt class="docutils literal"><span class="pre">0x80</span></tt> from ASCII to Unicode
+because it is not in the range(128) or 0-127. In fact <tt class="docutils literal"><span class="pre">0x80</span></tt> is hex for 128
+which the first number outside the ASCII range. However if we tell Python that
+the character <tt class="docutils literal"><span class="pre">0x80</span></tt> is encoded with the <tt class="docutils literal"><span class="pre">'latin-1'</span></tt>, <tt class="docutils literal"><span class="pre">'iso_8859_1'</span></tt> or
+<tt class="docutils literal"><span class="pre">'8859'</span></tt> character sets (which incidentally are different names for the same
+thing) we get the result we expected:</p>
+<textarea name="code" class="python">
+>>> unicode('\x80', encoding='latin-1')
+u'\x80'
+</textarea><div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">The character encodings Python supports are listed at
+<a href="http://docs.python.org/lib/standard-encodings.html" class="reference">http://docs.python.org/lib/standard-encodings.html</a></p>
+</div>
+<p>Unicode objects in Python have most of the same methods that normal Python
+strings provide. Python will try to use the <tt class="docutils literal"><span class="pre">'ascii'</span></tt> codec to convert
+strings to Unicode if you do an operation on both types:</p>
+<textarea name="code" class="python">
+>>> a = 'hello'
+>>> b = unicode(' world!')
+>>> print a + b
+u'hello world!'
+</textarea><p>You can encode a Unicode string using a particular encoding like this:</p>
+<textarea name="code" class="python">
+>>> u'Hello World!'.encode('UTF-8')
+'Hello World!'
+</textarea></div>
+<div class="section">
+<h2><a href="#id4" id="unicode-literals-in-python-source-code" name="unicode-literals-in-python-source-code" class="toc-backref">1.3 Unicode Literals in Python Source Code</a></h2>
+<p>In Python source code, Unicode literals are written as strings prefixed with
+the 'u' or 'U' character:</p>
+<textarea name="code" class="python">
+>>> u'abcdefghijk'
+>>> U'lmnopqrstuv'
+</textarea><p>You can also use <tt class="docutils literal"><span class="pre">"</span></tt>, <tt class="docutils literal"><span class="pre">"""`</span></tt> or <tt class="docutils literal"><span class="pre">'''</span></tt> versions too. For example:</p>
+<textarea name="code" class="python">
+>>> u"""This
+... is a really long
+... Unicode string"""
+</textarea><p>Specific code points can be written using the <tt class="docutils literal"><span class="pre">\u</span></tt> escape sequence, which is
+followed by four hex digits giving the code point. If you use <tt class="docutils literal"><span class="pre">\U</span></tt> instead
+you specify 8 hex digits instead of 4. Unicode literals can also use the same
+escape sequences as 8-bit strings, including <tt class="docutils literal"><span class="pre">\x</span></tt>, but <tt class="docutils literal"><span class="pre">\x</span></tt> only takes two
+hex digits so it can't express all the available code points. You can add
+characters to Unicode strings using the <tt class="docutils literal"><span class="pre">unichr()</span></tt> built-in function and find
+out what the ordinal is with <tt class="docutils literal"><span class="pre">ord()</span></tt>.</p>
+<p>Here is an example demonstrating the different alternatives:</p>
+<textarea name="code" class="python">
+>>> s = u"\x66\u0072\u0061\U0000006e" + unichr(231) + u"ais"
+>>> # ^^^^ two-digit hex escape
+>>> # ^^^^^^ four-digit Unicode escape
+>>> # ^^^^^^^^^^ eight-digit Unicode escape
+>>> for c in s: print ord(c),
+...
+97 102 114 97 110 231 97 105 115
+>>> print s
+franÁais
+</textarea><p>Using escape sequences for code points greater than 127 is fine in small doses
+but Python 2.4 and above support writing Unicode literals in any encoding as
+long as you declare the encoding being used by including a special comment as
+either the first or second line of the source file:</p>
+<textarea name="code" class="python">
+#!/usr/bin/env python
+# -*- coding: latin-1 -*-
+
+u = u'abcdÈ'
+print ord(u[-1])
+</textarea><p>If you don't include such a comment, the default encoding used will be ASCII.
+Versions of Python before 2.4 were Euro-centric and assumed Latin-1 as a
+default encoding for string literals; in Python 2.4, characters greater than
+127 still work but result in a warning. For example, the following program has
+no encoding declaration:</p>
+<textarea name="code" class="python">
+#!/usr/bin/env python
+u = u'abcdÈ'
+print ord(u[-1])
+</textarea><p>When you run it with Python 2.4, it will output the following warning:</p>
+<pre class="literal-block">
+sys:1: DeprecationWarning: Non-ASCII character '\xe9' in file testas.py on line
+2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for de
+tails
+</pre>
+<p>and then the following output:</p>
+<pre class="literal-block">
+233
+</pre>
+<p>For real world use it is recommended that you use the UTF-8 encoding for your
+file but you must be sure that your text editor actually saves the file as
+UTF-8 otherwise the Python interpreter will try to parse UTF-8 characters but
+they will actually be stored as something else.</p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Windows users who use the <a href="http://www.scintilla.org/SciTE.html" class="reference">SciTE</a>
+editor can specify the encoding of their file from the menu using the
+<tt class="docutils literal"><span class="pre">File->Encoding</span></tt>.</p>
+</div>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">If you are working with Unicode in detail you might also be interested in
+the <tt class="docutils literal"><span class="pre">unicodedata</span></tt> module which can be used to find out Unicode properties
+such as a character's name, category, numeric value and the like.</p>
+</div>
+</div>
+<div class="section">
+<h2><a href="#id5" id="input-and-output" name="input-and-output" class="toc-backref">1.4 Input and Output</a></h2>
+<p>We now know how to use Unicode in Python source code but input and output can
+also be different using Unicode. Of course, some libraries natively support
+Unicode and if these libraries return Unicode objects you will not have to do
+anything special to support them. XML parsers and SQL databases frequently
+support Unicode for example.</p>
+<p>If you remember from the discussion earlier, Unicode data consists of code
+points. In order to send Unicode data via a socket or write it to a file you
+usually need to encode it to a series of bytes and then decode the data back to
+Unicode when reading it. You can of course perform the encoding manually
+reading a byte at the time but since encodings such as UTF-8 can have variable
+numbers of bytes per character it is usually much easier to use Python's
+built-in support in the form of the <tt class="docutils literal"><span class="pre">codecs</span></tt> module.</p>
+<p>The codecs module includes a version of the <tt class="docutils literal"><span class="pre">open()</span></tt> function that
+returns a file-like object that assumes the file's contents are in a specified
+encoding and accepts Unicode parameters for methods such as <tt class="docutils literal"><span class="pre">.read()</span></tt> and
+<tt class="docutils literal"><span class="pre">.write()</span></tt>.</p>
+<p>The function's parameters are open(filename, mode='rb', encoding=None,
+errors='strict', buffering=1). <tt class="docutils literal"><span class="pre">mode</span></tt> can be 'r', 'w', or 'a', just like the
+corresponding parameter to the regular built-in <tt class="docutils literal"><span class="pre">open()</span></tt> function. You can
+add a <tt class="docutils literal"><span class="pre">+</span></tt> character to update the file. <tt class="docutils literal"><span class="pre">buffering</span></tt> is similar to the
+standard function's parameter. <tt class="docutils literal"><span class="pre">encoding</span></tt> is a string giving the encoding to
+use, if not specified or specified as <tt class="docutils literal"><span class="pre">None</span></tt>, a regular Python file object
+that accepts 8-bit strings is returned. Otherwise, a wrapper object is
+returned, and data written to or read from the wrapper object will be converted
+as needed. <tt class="docutils literal"><span class="pre">errors</span></tt> specifies the action for encoding errors and can be one
+of the usual values of <tt class="docutils literal"><span class="pre">'strict'</span></tt>, <tt class="docutils literal"><span class="pre">'ignore'</span></tt>, or <tt class="docutils literal"><span class="pre">'replace'</span></tt> which we
+saw right at the begining of this document when we were encoding strings in
+Python source files.</p>
+<p>Here is an example of how to read Unicode from a UTF-8 encoded file:</p>
+<textarea name="code" class="python">
+import codecs
+f = codecs.open('unicode.txt', encoding='utf-8')
+for line in f:
+ print repr(line)
+</textarea><p>It's also possible to open files in update mode, allowing both reading and writing:</p>
+<textarea name="code" class="python">
+f = codecs.open('unicode.txt', encoding='utf-8', mode='w+')
+f.write(u"\x66\u0072\u0061\U0000006e" + unichr(231) + u"ais")
+f.seek(0)
+print repr(f.readline()[:1])
+f.close()
+</textarea><p>Notice that we used the <tt class="docutils literal"><span class="pre">repr()</span></tt> function to display the Unicode data. This
+is very useful because if you tried to print the Unicode data directly, Python
+would need to encode it before it could be sent the console and depending on
+which characters were present and the character set used by the console, an
+error might be raised. This is avoided if you use <tt class="docutils literal"><span class="pre">repr()</span></tt>.</p>
+<p>The Unicode character <tt class="docutils literal"><span class="pre">U+FEFF</span></tt> is used as a byte-order mark or BOM, and is often
+written as the first character of a file in order to assist with auto-detection
+of the file's byte ordering. Some encodings, such as UTF-16, expect a BOM to be
+present at the start of a file, but with others such as UTF-8 it isn't necessary.</p>
+<p>When such an encoding is used, the BOM will be automatically written as the
+first character and will be silently dropped when the file is read. There are
+variants of these encodings, such as 'utf-16-le' and 'utf-16-be' for
+little-endian and big-endian encodings, that specify one particular byte
+ordering and don't skip the BOM.</p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">Some editors including SciTE will put a byte order mark (BOM) in the text
+file when saved as UTF-8, which is strange because UTF-8 doesn't need BOMs.</p>
+</div>
+</div>
+<div class="section">
+<h2><a href="#id6" id="unicode-filenames" name="unicode-filenames" class="toc-backref">1.5 Unicode Filenames</a></h2>
+<p>Most modern operating systems support the use of Unicode filenames. The
+filenames are transparently converted to the underlying filesystem encoding.
+The type of encoding depends on the operating system.</p>
+<p>On Windows 9x, the encoding is <tt class="docutils literal"><span class="pre">mbcs</span></tt>.</p>
+<p>On Mac OS X, the encoding is <tt class="docutils literal"><span class="pre">utf-8</span></tt>.</p>
+<p>On Unix, the encoding is the user's preference according to the
+result of nl_langinfo(CODESET), or None if the nl_langinfo(CODESET) failed.</p>
+<p>On Windows NT+, file names are Unicode natively, so no conversion is performed.
+getfilesystemencoding still returns <tt class="docutils literal"><span class="pre">mbcs</span></tt>, as this is the encoding that
+applications should use when they explicitly want to convert Unicode strings to
+byte strings that are equivalent when used as file names.</p>
+<p><tt class="docutils literal"><span class="pre">mbcs</span></tt> is a special encoding for Windows that effectively means "use
+whichever encoding is appropriate". In Python 2.3 and above you can find out
+the system encoding with <tt class="docutils literal"><span class="pre">sys.getfilesystemencoding()</span></tt>.</p>
+<p>Most file and directory functions and methods support Unicode. For example:</p>
+<textarea name="code" class="python">
+filename = u"\x66\u0072\u0061\U0000006e" + unichr(231) + u"ais"
+f = open(filename, 'w')
+f.write('Some data\n')
+f.close()
+</textarea><p>Other functions such as <tt class="docutils literal"><span class="pre">os.listdir()</span></tt> will return Unicode if you pass a
+Unicode argument and will try to return strings if you pass an ordinary 8 bit
+string. For example running this example as <tt class="docutils literal"><span class="pre">test.py</span></tt>:</p>
+<textarea name="code" class="python">
+filename = u"Sample " + unichar(5000)
+f = open(filename, 'w')
+f.close()
+
+import os
+print os.listdir('.')
+print os.listdir(u'.')
+</textarea><p>will produce the following output:</p>
+<blockquote>
+['Sample?', 'test.py']
+[u'Sampleu1388', u'test.py']</blockquote>
+</div>
+</div>
+<div class="section">
+<h1><a href="#id7" id="applying-this-to-web-programming" name="applying-this-to-web-programming" class="toc-backref">2 Applying this to Web Programming</a></h1>
+<p>So far we've seen how to use encoding in source files and seen how to decode
+text to Unicode and encode it back to text. We've also seen that Unicode
+objects can be manipulated in similar ways to strings and we've seen how to
+perform input and output operations on files. Next we are going to look at how
+best to use Unicode in a web app.</p>
+<p>The main rule is this:</p>
+<pre class="literal-block">
+Your application should use Unicode for all strings internally, decoding
+any input to Unicode as soon as it enters the application and encoding the
+Unicode to UTF-8 or another encoding only on output.
+</pre>
+<p>If you fail to do this you will find that <tt class="docutils literal"><span class="pre">UnicodeDecodeError</span></tt> s will start
+popping up in unexpected places when Unicode strings are used with normal 8-bit
+strings because Python's default encoding is ASCII and it will try to decode
+the text to ASCII and fail. It is always better to do any encoding or decoding
+at the edges of your application otherwise you will end up patching lots of
+different parts of your application unnecessarily as and when errors pop up.</p>
+<p>Unless you have a very good reason not to it is wise to use UTF-8 as the
+default encoding since it is so widely supported.</p>
+<p>The second rule is:</p>
+<pre class="literal-block">
+Always test your application with characters above 127 and above 255
+wherever possible.
+</pre>
+<p>If you fail to do this you might think your application is working fine, but as
+soon as your users do put in non-ASCII characters you will have problems.
+Using arabic is always a good test and www.google.ae is a good source of sample
+text.</p>
+<p>The third rule is:</p>
+<pre class="literal-block">
+Always do any checking of a string for illegal characters once it's in the
+form that will be used or stored, otherwise the illegal characters might be
+disguised.
+</pre>
+<p>For example, let's say you have a content management system that takes a
+Unicode filename, and you want to disallow paths with a '/' character. You
+might write this code:</p>
+<textarea name="code" class="python">
+def read_file(filename, encoding):
+ if '/' in filename:
+ raise ValueError("'/' not allowed in filenames")
+ unicode_name = filename.decode(encoding)
+ f = open(unicode_name, 'r')
+ # ... return contents of file ...
+</textarea><p>This is INCORRECT. If an attacker could specify the 'base64' encoding, they
+could pass <tt class="docutils literal"><span class="pre">L2V0Yy9wYXNzd2Q=</span></tt> which is the base-64 encoded form of the string
+<tt class="docutils literal"><span class="pre">'/etc/passwd'</span></tt> which is a file you clearly don't want an attacker to get
+hold of. The above code looks for <tt class="docutils literal"><span class="pre">/</span></tt> characters in the encoded form and
+misses the dangerous character in the resulting decoded form.</p>
+<p>Those are the three basic rules so now we will look at some of the places you
+might want to perform Unicode decoding in a Pylons application.</p>
+<div class="section">
+<h2><a href="#id8" id="request-parameters" name="request-parameters" class="toc-backref">2.1 Request Parameters</a></h2>
+<p>Currently the Pylons input values come from <tt class="docutils literal"><span class="pre">request.params</span></tt> but these are
+not decoded to Unicode by default because not all input should be assumed to be
+Unicode data.</p>
+<p>If you would like However you can use the two functions below:</p>
+<textarea name="code" class="python">
+def decode_multi_dict(md, encoding="UTF-8", errors="strict"):
+ """Given a MultiDict, decode all its parts from the given encoding.
+
+ This modifies the MultiDict in place.
+
+ encoding, strict
+ These are passed to the decode function.
+
+ """
+ items = md.items()
+ md.clear()
+ for (k, v) in items:
+ md.add(k.decode(encoding, errors),
+ v.decode(encoding, errors))
+
+
+def decode_request(request, encoding="UTF-8", errors="strict"):
+ """Given a request object, decode GET and POST in place.
+
+ This implicitly takes care of params as well.
+
+ """
+ decode_multi_dict(request.GET, encoding, errors)
+ decode_multi_dict(request.POST, encoding, errors)
+</textarea><p>These can then be used as follows:</p>
+<textarea name="code" class="python">
+unicode_params = decode_request(request.params)
+</textarea><p>This code is discussed in <a href="http://pylonshq.com/project/pylonshq/ticket/135" class="reference">ticket 135</a> but shouldn't be used with
+file uploads since these shouldn't ordinarily be decoded to Unicode.</p>
+</div>
+<div class="section">
+<h2><a href="#id9" id="templating" name="templating" class="toc-backref">2.2 Templating</a></h2>
+<p>Pylons uses Myghty as its default templating language and Myghty 1.1 and above
+fully support Unicode. The Myghty documentation explains how to use Unicode and
+you at <a href="http://www.myghty.org/docs/unicode.myt" class="reference">http://www.myghty.org/docs/unicode.myt</a> but the important idea is that
+you can Unicode literals pretty much anywhere you can use normal 8-bit strings
+including in <tt class="docutils literal"><span class="pre">m.write()</span></tt> and <tt class="docutils literal"><span class="pre">m.comp()</span></tt>. You can also pass Unicode data to
+Pylons' <tt class="docutils literal"><span class="pre">render_response()</span></tt> and <tt class="docutils literal"><span class="pre">Response()</span></tt> callables.</p>
+<p>Any Unicode data output by Myghty is automatically decoded to whichever
+encoding you have chosen. The default is UTF-8 but you can choose which
+encoding to use by editing your project's <tt class="docutils literal"><span class="pre">config/environment.py</span></tt> file and
+adding an option like this:</p>
+<textarea name="code" class="python">
+# Add your own Myghty config options here, note that all config options will override
+# any Pylons config options
+
+myghty['output_encoding'] = 'UTF-8'
+</textarea><p>replacing <tt class="docutils literal"><span class="pre">UTF-8</span></tt> with the encoding you wish to use.</p>
+<p>If you need to disable Unicode support altogether you can set this:</p>
+<textarea name="code" class="python">
+myghty['disable_unicode'] = True
+</textarea><p>but again, you would have to have a good reason to want to do this.</p>
+</div>
+<div class="section">
+<h2><a href="#id10" id="output-encoding" name="output-encoding" class="toc-backref">2.3 Output Encoding</a></h2>
+<p>Web pages should be generated with a specific encoding, most likely UTF-8. At
+the very least, that means you should specify the following in the <tt class="docutils literal"><span class="pre"><head></span></tt>
+section:</p>
+<pre class="literal-block">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+</pre>
+<p>You should also set the charset in the <tt class="docutils literal"><span class="pre">Content-Type</span></tt> header:</p>
+<textarea name="code" class="python">
+respones = Response(...)
+response.headers['Content-type'] = 'text/html; charset=utf-8'
+</textarea><p>If you specify that your output is UTF-8, generally the web browser will
+give you UTF-8. If you want the browser to submit data using a different
+character set, you can set the encoding by adding the <tt class="docutils literal"><span class="pre">accept-encoding</span></tt>
+tag to your form. Here is an example:</p>
+<pre class="literal-block">
+<form accept-encoding="US-ASCII" ...>
+</pre>
+<p>However, be forewarned that if the user tries to give you non-ASCII
+text, then:</p>
+<blockquote>
+<ul class="simple">
+<li>Firefox will translate the non-ASCII text into HTML entities.</li>
+<li>IE will ignore your suggested encoding and give you UTF-8 anyway.</li>
+</ul>
+</blockquote>
+<p>The lesson to be learned is that if you output UTF-8, you had better be
+prepared to accept UTF-8 by decoding the data in <tt class="docutils literal"><span class="pre">request.params</span></tt> as
+described in the section above entitled "Request Parameters".</p>
+<p>Another technique which is sometimes used to determine the character set is to
+use an algorithm to analyse the input and guess the encoding based on
+probabilities.</p>
+<p>For instance, if you get a file, and you don't know what encoding it is encoded
+in, you can often rename the file with a .txt extension and then try to open it
+in Firefox. Then you can use the "View->Character Encoding" menu to try to
+auto-detect the encoding.</p>
+</div>
+<div class="section">
+<h2><a href="#id11" id="databases" name="databases" class="toc-backref">2.4 Databases</a></h2>
+<p>Your database driver should automatically convert from Unicode objects to a
+particular charset when writing and back again when reading. Again it is normal
+to use UTF-8 which is well supported.</p>
+<p>You should check your database's documentation for information on how it handles
+Unicode.</p>
+<p>For example MySQL's Unicode documentation is here
+<a href="http://dev.mysql.com/doc/refman/5.0/en/charset-unicode.html" class="reference">http://dev.mysql.com/doc/refman/5.0/en/charset-unicode.html</a></p>
+<p>Also note that you need to consider both the encoding of the database
+and the encoding used by the database driver.</p>
+<p>If you're using MySQL together with SQLAlchemy, see the following, as
+there are some bugs in MySQLdb that you'll need to work around:</p>
+<p><a href="http://www.mail-archive.com/sqlalchemy@googlegroups.com/msg00366.html" class="reference">http://www.mail-archive.com/sqlalchemy@googlegroups.com/msg00366.html</a></p>
+</div>
+</div>
+<div class="section">
+<h1><a href="#id12" id="internationalization-and-localization" name="internationalization-and-localization" class="toc-backref">3 Internationalization and Localization</a></h1>
+<p>By now you should have a good idea of what Unicode is, how to use it in Python
+and which areas of you application need to pay specific attention to decoding and
+encoding Unicode data.</p>
+<p>This final section will look at the issue of making your application work with
+multiple languages.</p>
+<div class="section">
+<h2><a href="#id13" id="getting-started" name="getting-started" class="toc-backref">3.1 Getting Started</a></h2>
+<p>Everywhere in your code where you want strings to be available in different
+languages you wrap them in the <tt class="docutils literal"><span class="pre">_()</span></tt> function. There
+are also a number of other translation functions which are documented in the API reference at
+<a href="http://pylonshq.com/docs/module-pylons.i18n.translation.html" class="reference">http://pylonshq.com/docs/module-pylons.i18n.translation.html</a></p>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">The <tt class="docutils literal"><span class="pre">_()</span></tt> function is a reference to the <tt class="docutils literal"><span class="pre">ugettext()</span></tt> function.
+<tt class="docutils literal"><span class="pre">_()</span></tt> is a convention for marking text to be translated and saves on keystrokes.
+<tt class="docutils literal"><span class="pre">ugettext()</span></tt> is the Unicode version of <tt class="docutils literal"><span class="pre">gettext()</span></tt>.</p>
+</div>
+<p>In our example we want the string <tt class="docutils literal"><span class="pre">'Hello'</span></tt> to appear in three different
+languages: English, French and Spanish. We also want to display the word
+<tt class="docutils literal"><span class="pre">'Hello'</span></tt> in the default language. We'll then go on to use some pural words
+too.</p>
+<p>Lets call our project <tt class="docutils literal"><span class="pre">translate_demo</span></tt>:</p>
+<pre class="literal-block">
+paster create --template=pylons translate_demo
+</pre>
+<p>Now lets add a friendly controller that says hello:</p>
+<pre class="literal-block">
+cd translate_demo
+paster controller hello
+</pre>
+<p>Edit <tt class="docutils literal"><span class="pre">controllers/hello.py</span></tt> controller to look like this making use of the
+<tt class="docutils literal"><span class="pre">_()</span></tt> function everywhere where the string <tt class="docutils literal"><span class="pre">Hello</span></tt> appears:</p>
+<textarea name="code" class="python">
+from translate_demo.lib.base import *
+
+class HelloController(BaseController):
+
+ def index(self):
+ resp = Response()
+ resp.write('Default: %s<br />' % _('Hello'))
+ for lang in ['fr','en','es']:
+ h.set_lang(lang)
+ resp.write("%s: %s<br />" % (h.get_lang(), _('Hello')))
+ return resp
+</textarea><p>When writing your controllers it is important not to piece sentences together manually because
+certain languages might need to invert the grammars. As an example this is bad:</p>
+<textarea name="code" class="python">
+# BAD!
+msg = _("He told her ")
+msg += _("not to go outside.")
+</textarea><p>but this is perfectly acceptable:</p>
+<textarea name="code" class="python">
+# GOOD
+msg = _("He told her not to go outside")
+</textarea><p>The controller has now been internationalized but it will raise a <tt class="docutils literal"><span class="pre">LanguageError</span></tt>
+until we have specified the alternative languages.</p>
+<p>Pylons uses <a href="http://www.gnu.org/software/gettext/" class="reference">GNU gettext</a> to handle
+internationalization. GNU gettext use three types of files in the
+translation framework.</p>
+<p>POT (Portable Object Template) files</p>
+<blockquote>
+The first step in the localization process. A program is used to search through
+your project's source code and pick out every string passed to one of the
+translation functions, such as <tt class="docutils literal"><span class="pre">_()</span></tt>. This list is put together in a
+specially-formatted template file that will form the basis of all
+translations. This is the <tt class="docutils literal"><span class="pre">.pot</span></tt> file.</blockquote>
+<p>PO (Portable Object) files</p>
+<blockquote>
+The second step in the localization process. Using the POT file as a template,
+the list of messages are translated and saved as a <tt class="docutils literal"><span class="pre">.po</span></tt> file.</blockquote>
+<p>MO (Machine Object) files</p>
+<blockquote>
+The final step in the localization process. The PO file is run through a
+program that turns it into an optimized machine-readable binary file, which is
+the <tt class="docutils literal"><span class="pre">.mo</span></tt> file. Compiling the translations to machine code makes the
+localized program much faster in retrieving the translations while it is
+running.</blockquote>
+<p>Versions of Pylons prior to 0.9.4 came with a setuptools extension to help with
+the extraction of strings and production of a <tt class="docutils literal"><span class="pre">.mo</span></tt> file. The implementation
+did not support Unicode nor the ungettext function and was therfore dropped in
+Python 0.9.4.</p>
+<p>You will therefore need to use an external program to perform these tasks. You
+may use whichever you prefer but <tt class="docutils literal"><span class="pre">xgettext</span></tt> is highly recommended. Python's
+gettext utility has some bugs, especially regarding plurals.</p>
+<p>Here are some compatible tools and projects:</p>
+<p>The Rosetta Project (<a href="https://launchpad.ubuntu.com/rosetta/" class="reference">https://launchpad.ubuntu.com/rosetta/</a>)</p>
+<blockquote>
+The Ubuntu Linux project has a web site that allows you to translate
+messages without even looking at a PO or POT file, and export directly to a MO.</blockquote>
+<p>poEdit (<a href="http://www.poedit.org/" class="reference">http://www.poedit.org/</a>)</p>
+<blockquote>
+An open source program for Windows and UNIX/Linux which provides an easy-to-use
+GUI for editing PO files and generating MO files.</blockquote>
+<p>KBabel (<a href="http://i18n.kde.org/tools/kbabel/" class="reference">http://i18n.kde.org/tools/kbabel/</a>)</p>
+<blockquote>
+Another open source PO editing program for KDE.</blockquote>
+<p>GNU Gettext (<a href="http://www.gnu.org/software/gettext/" class="reference">http://www.gnu.org/software/gettext/</a>)</p>
+<blockquote>
+The official Gettext tools package contains command-line tools for creating
+POTs, manipulating POs, and generating MOs. For those comfortable with a
+command shell.</blockquote>
+<p>As an example we will quickly discuss the use of poEdit which is cross platform
+and has a GUI which makes it easier to get started with.</p>
+<p>To use poEdit with the <tt class="docutils literal"><span class="pre">translate_demo</span></tt> you would do the following:</p>
+<ol class="arabic simple">
+<li>Download and install poEdit.</li>
+<li>A dialog pops up. Fill in <em>all</em> the fields you can on the <tt class="docutils literal"><span class="pre">Project</span> <span class="pre">Info</span></tt> tab, enter the path to your project on the <tt class="docutils literal"><span class="pre">Paths</span></tt> tab (ie <tt class="docutils literal"><span class="pre">/path/to/translate_demo</span></tt>) and enter the following keywords on separate lines on the <tt class="docutils literal"><span class="pre">keywords</span></tt> tab: <tt class="docutils literal"><span class="pre">_</span></tt>, <tt class="docutils literal"><span class="pre">N_</span></tt>, <tt class="docutils literal"><span class="pre">ugettext</span></tt>, <tt class="docutils literal"><span class="pre">gettext</span></tt>, <tt class="docutils literal"><span class="pre">ngettext</span></tt>, <tt class="docutils literal"><span class="pre">ungettext</span></tt>.</li>
+<li>Click OK</li>
+</ol>
+<p>poEdit will search your source tree and find all the strings you have marked
+up. You can then enter your translations in whatever charset you chose in
+the project info tab. UTF-8 is a good choice.</p>
+<p>Finally, after entering your translations you then save the catalog and rename
+the <tt class="docutils literal"><span class="pre">.mo</span></tt> file produced to <tt class="docutils literal"><span class="pre">translate_demo.mo</span></tt> and put it in the
+<tt class="docutils literal"><span class="pre">translate_demo/i18n/es/LC_MESSAGES</span></tt> directory or whatever is appropriate for
+your translation.</p>
+<p>You will need to repeat the process of creating a <tt class="docutils literal"><span class="pre">.mo</span></tt> file for the <tt class="docutils literal"><span class="pre">fr</span></tt>,
+<tt class="docutils literal"><span class="pre">es</span></tt> and <tt class="docutils literal"><span class="pre">en</span></tt> translations.</p>
+<p>The relevant lines from <tt class="docutils literal"><span class="pre">i18n/en/LC_MESSAGES/translate_demo.po</span></tt> look like this:</p>
+<pre class="literal-block">
+#: translate_demo\controllers\hello.py:6 translate_demo\controllers\hello.py:9
+msgid "Hello"
+msgstr "Hello"
+</pre>
+<p>The relevant lines from <tt class="docutils literal"><span class="pre">i18n/es/LC_MESSAGES/translate_demo.po</span></tt> look like this:</p>
+<pre class="literal-block">
+#: translate_demo\controllers\hello.py:6 translate_demo\controllers\hello.py:9
+msgid "Hello"
+msgstr "°Hola!"
+</pre>
+<p>The relevant lines from <tt class="docutils literal"><span class="pre">i18n/fr/LC_MESSAGES/translate_demo.po</span></tt> look like this:</p>
+<pre class="literal-block">
+#: translate_demo\controllers\hello.py:6 translate_demo\controllers\hello.py:9
+msgid "Hello"
+msgstr "Bonjour"
+</pre>
+<p>Whichever tools you use you should end up with an <tt class="docutils literal"><span class="pre">i18n</span></tt> directory that looks
+like this when you have finished:</p>
+<pre class="literal-block">
+i18n/en/LC_MESSAGES/translate_demo.po
+i18n/en/LC_MESSAGES/translate_demo.mo
+i18n/es/LC_MESSAGES/translate_demo.po
+i18n/es/LC_MESSAGES/translate_demo.mo
+i18n/fr/LC_MESSAGES/translate_demo.po
+i18n/fr/LC_MESSAGES/translate_demo.mo
+</pre>
+</div>
+<div class="section">
+<h2><a href="#id14" id="testing-the-application" name="testing-the-application" class="toc-backref">3.2 Testing the Application</a></h2>
+<p>Start the server with the following command:</p>
+<pre class="literal-block">
+paster serve --reload development.ini
+</pre>
+<p>Test your controller by visiting <a href="http://localhost:5000/hello" class="reference">http://localhost:5000/hello</a>. You should see
+the following output:</p>
+<pre class="literal-block">
+Default: Hello
+fr: Bonjour
+en: Hello
+es: °Hola!
+</pre>
+<p>You can now set the language used in a controller on the fly.</p>
+<p>For example this could be used to allow a user to set which language they
+wanted your application to work in. You could save the value to the session
+object:</p>
+<textarea name="code" class="python">
+session['lang'] = 'en'
+</textarea><p>then on each controller call the language to be used could be read from the
+session and set in your controller's <tt class="docutils literal"><span class="pre">__before__()</span></tt> method so that the pages
+remained in the same language that was previously set:</p>
+<textarea name="code" class="python">
+def __before__(self, action):
+ if session.has_key('lang'):
+ h.set_lang(session['lang'])
+</textarea><p>One more useful thing to be able to do is to set the default language to be
+used in the configuration file. Just add a <tt class="docutils literal"><span class="pre">lang</span></tt> variable together with the
+code of the language you wanted to use in your <tt class="docutils literal"><span class="pre">development.ini</span></tt> file. For
+example to set the default language to Spanish you would add <tt class="docutils literal"><span class="pre">lang</span> <span class="pre">=</span> <span class="pre">es</span></tt> to
+your <tt class="docutils literal"><span class="pre">development.ini</span></tt>. The relevant part from the file might look something
+like this:</p>
+<textarea name="code" class="pasteini">
+[app:main]
+use = egg:translate_demo
+lang = es
+</textarea><p>If you are running the server with the <tt class="docutils literal"><span class="pre">--reload</span></tt> option the server will
+automatically restart if you change the <tt class="docutils literal"><span class="pre">development.ini</span></tt> file. Otherwise
+restart the server manually and the output would this time be as follows:</p>
+<pre class="literal-block">
+Default: °Hola!
+fr: Bonjour
+en: Hello
+es: °Hola!
+</pre>
+</div>
+<div class="section">
+<h2><a href="#id15" id="missing-translations" name="missing-translations" class="toc-backref">3.3 Missing Translations</a></h2>
+<p>If your code calls <tt class="docutils literal"><span class="pre">_()</span></tt> with a string that doesn't exist in your language
+catalogue, the string passed to <tt class="docutils literal"><span class="pre">_()</span></tt> is returned instead.</p>
+<p>Modify the last line of the hello controller to look like this:</p>
+<textarea name="code" class="python">
+resp.write("%s: %s %s<br />" % (h.get_lang(), _('Hello'), _('World!')))
+</textarea><div class="warning">
+<p class="first admonition-title">Warning</p>
+<p class="last">Of course, in real life breaking up sentences in this way is very dangerous because some
+grammars might require the order of the words to be different.</p>
+</div>
+<p>If you run the example again the output will be:</p>
+<pre class="literal-block">
+Default: °Hola!
+fr: Bonjour World!
+en: Hello World!
+es: °Hola! World!
+</pre>
+<p>This is because we never provided a translation for the string <tt class="docutils literal"><span class="pre">'World!'</span></tt> so
+the string itself is used.</p>
+</div>
+<div class="section">
+<h2><a href="#id16" id="translations-within-templates" name="translations-within-templates" class="toc-backref">3.4 Translations Within Templates</a></h2>
+<p>You can also use the <tt class="docutils literal"><span class="pre">_()</span></tt> function within templates in exactly the same way
+you do in code. For example:</p>
+<textarea name="code" class="html">
+<% _('Hello') %>
+</textarea><p>would produce the string <tt class="docutils literal"><span class="pre">'Hello'</span></tt> in the language you had set.</p>
+<p>There is one complication though. gettext's <tt class="docutils literal"><span class="pre">xgettext</span></tt> command can only extract
+strings that need translating from Python code in <tt class="docutils literal"><span class="pre">.py</span></tt> files. This means
+that if you write <tt class="docutils literal"><span class="pre">_('Hello')</span></tt> in a template such as a Myghty template,
+<tt class="docutils literal"><span class="pre">xgettext</span></tt> will not find the string <tt class="docutils literal"><span class="pre">'Hello'</span></tt> as one which needs
+translating.</p>
+<p>As long as <tt class="docutils literal"><span class="pre">xgettext</span></tt> can find a string marked for translation with one
+of the translation functions and defined in Python code in your project
+filesystem it will manage the translation when the same string is defined in a
+Myghty template and marked for translation.</p>
+<p>One solution to ensure all strings are picked up for translation is to create a
+file in <tt class="docutils literal"><span class="pre">lib</span></tt> with an appropriate filename, <tt class="docutils literal"><span class="pre">i18n.py</span></tt> for example, and then
+add a list of all the strings which appear in your templates so that your
+translation tool can then extract the strings in <tt class="docutils literal"><span class="pre">lib/i18n.py</span></tt> for
+translation and use the translated versions in your templates as well.</p>
+<p>For example if you wanted to ensure the translated string <tt class="docutils literal"><span class="pre">'Good</span> <span class="pre">Morning'</span></tt>
+was available in all templates you could create a <tt class="docutils literal"><span class="pre">lib/i18n.py</span></tt> file that
+looked something like this:</p>
+<textarea name="code" class="python">
+from base import _
+_('Good Morning')
+</textarea><p>This approach requires quite a lot of work and is rather fragile. The best
+solution if you are using a templating system such as Myghty or Cheetah which
+uses compiled Python files is to use a Makefile to ensure that every template
+is compiled to Python before running the extraction tool to make sure that
+every template is scanned.</p>
+<p>Of course, if your cache directory is in the default location or elsewhere
+within your project's filesystem, you will probably find that all templates
+have been compiled as Python files during the course of the development process.
+This means that your tool's extraction command will successfully pick up
+strings to translate from the cached files anyway.</p>
+<p>You may also find that your extraction tool is capable of extracting the
+strings correctly from the template anyway, particularly if the templating
+langauge is quite similar to Python. It is best not to rely on this though.</p>
+</div>
+<div class="section">
+<h2><a href="#id17" id="producing-a-python-egg" name="producing-a-python-egg" class="toc-backref">3.5 Producing a Python Egg</a></h2>
+<p>Finally you can produce an egg of your project which includes the translation
+files like this:</p>
+<pre class="literal-block">
+python setup.py bdist_egg
+</pre>
+<p>The <tt class="docutils literal"><span class="pre">setup.py</span></tt> automatically includes the <tt class="docutils literal"><span class="pre">.mo</span></tt> language catalogs your
+application needs so that your application can be distributed as an egg. This
+is done with the following line in your <tt class="docutils literal"><span class="pre">setup.py</span></tt> file:</p>
+<pre class="literal-block">
+package_data={'translate_demo': ['i18n/*/LC_MESSAGES/*.mo']},
+</pre>
+<p>Internationalization support is zip safe so your application can be run
+directly from the egg without the need for <tt class="docutils literal"><span class="pre">easy_install</span></tt> to extract it.</p>
+</div>
+<div class="section">
+<h2><a href="#id18" id="plural-forms" name="plural-forms" class="toc-backref">3.6 Plural Forms</a></h2>
+<p>Pylons also defines <tt class="docutils literal"><span class="pre">ungettext()</span></tt> and <tt class="docutils literal"><span class="pre">ngettext()</span></tt> functions which can be imported
+from <tt class="docutils literal"><span class="pre">pylons.i18n</span></tt>. They are designed for internationalizing plural words and can be
+used as follows:</p>
+<textarea name="code" class="python">
+from pylons.i18n import ungettext
+
+ungettext(
+ 'There is %(num)d file here',
+ 'There are %(num)d files here',
+ n
+) % {'num': n}
+</textarea><p>If you wish to use plural forms in your application you need to add the appropriate
+headers to the <tt class="docutils literal"><span class="pre">.po</span></tt> files for the language you are using. You can read more about
+this at <a href="http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150" class="reference">http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150</a></p>
+<p>One thing to keep in mind is that other languages don't have the same
+plural forms as English. While English only has 2 pulral forms, singular and
+plural, Slovenian has 4! That means that you must use gettext's
+support for pluralization if you hope to get pluralization right.
+Specifically, the following will not work:</p>
+<textarea name="code" class="python">
+# BAD!
+ if n == 1:
+ msg = _("There was no dog.")
+ else:
+ msg = _("There were no dogs.")
+</textarea></div>
+</div>
+<div class="section">
+<h1><a href="#id19" id="summary" name="summary" class="toc-backref">4 Summary</a></h1>
+<p>Hopefully you now understand the history of Unicode, how to use it in Python
+and where to apply Unicode encoding and decoding in a Pylons application. You
+should also be able to use Unicode in your web app remembering the basic rule to
+use UTF-8 to talk to the world, do the encode and decode at the edge of your
+application.</p>
+<p>You should also be able to internationalize and then localize your application
+using Pylons' support for GNU gettext.</p>
+</div>
+<div class="section">
+<h1><a href="#id20" id="further-reading" name="further-reading" class="toc-backref">5 Further Reading</a></h1>
+<p>This information is based partly on the following articles which can be
+consulted for further information.:</p>
+<p><a href="http://www.joelonsoftware.com/articles/Unicode.html" class="reference">http://www.joelonsoftware.com/articles/Unicode.html</a></p>
+<p><a href="http://www.amk.ca/python/howto/unicode" class="reference">http://www.amk.ca/python/howto/unicode</a></p>
+<p><a href="http://en.wikipedia.org/wiki/Internationalization" class="reference">http://en.wikipedia.org/wiki/Internationalization</a></p>
+<p>Please feel free to report any mistakes to the Pylons mailing list or to the
+author. Any corrections or clarifications would be gratefully received.</p>
+</div>
+
+</div>
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/modtest.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/modtest.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1 @@
+this is a test
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/read_unicode.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/read_unicode.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,10 @@
+<%
+try:
+ file_content = open(path)
+except:
+ raise "Should never execute here"
+doc_content = ''.join(file_content.readlines())
+file_content.close()
+%>
+
+${unicode(doc_content, encoding='utf-8')}
Added: pypy/benchmarks/lib/mako/test/templates/read_unicode_py3k.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/read_unicode_py3k.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,10 @@
+<%
+try:
+ file_content = open(path)
+except:
+ raise "Should never execute here"
+doc_content = ''.join(file_content.readlines())
+file_content.close()
+%>
+
+${bytes(doc_content, encoding='utf-8')}
Added: pypy/benchmarks/lib/mako/test/templates/runtimeerr.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/runtimeerr.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,4 @@
+<%
+ print y
+ y = 10
+%>
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/runtimeerr_py3k.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/runtimeerr_py3k.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,4 @@
+<%
+ print(y)
+ y = 10
+%>
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/subdir/foo/modtest.html.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/subdir/foo/modtest.html.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,25 @@
+from mako import runtime, filters, cache
+UNDEFINED = runtime.UNDEFINED
+__M_dict_builtin = dict
+__M_locals_builtin = locals
+_magic_number = 5
+_modified_time = 1267565427.799504
+_template_filename='/Users/classic/dev/mako/test/templates/subdir/modtest.html'
+_template_uri='/subdir/modtest.html'
+_template_cache=cache.Cache(__name__, _modified_time)
+_source_encoding=None
+_exports = []
+
+
+def render_body(context,**pageargs):
+ context.caller_stack._push_frame()
+ try:
+ __M_locals = __M_dict_builtin(pageargs=pageargs)
+ __M_writer = context.writer()
+ # SOURCE LINE 1
+ __M_writer(u'this is a test')
+ return ''
+ finally:
+ context.caller_stack._pop_frame()
+
+
Added: pypy/benchmarks/lib/mako/test/templates/subdir/incl.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/subdir/incl.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+
+ this is include 2
Added: pypy/benchmarks/lib/mako/test/templates/subdir/index.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/subdir/index.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,3 @@
+
+ this is sub index
+ <%include file="incl.html"/>
Added: pypy/benchmarks/lib/mako/test/templates/subdir/modtest.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/subdir/modtest.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1 @@
+this is a test
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/unicode.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+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! »
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/unicode_arguments.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_arguments.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,10 @@
+# coding: utf-8
+
+<%def name="my_def(x)">
+ x is: ${x}
+</%def>
+
+${my_def(u'drôle de petite voix m’a réveillé')}
+<%self:my_def x='drôle de petite voix m’a réveillé'/>
+<%self:my_def x="${u'drôle de petite voix m’a réveillé'}"/>
+<%call expr="my_def(u'drôle de petite voix m’a réveillé')"/>
Added: pypy/benchmarks/lib/mako/test/templates/unicode_arguments_py3k.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_arguments_py3k.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,10 @@
+# coding: utf-8
+
+<%def name="my_def(x)">
+ x is: ${x}
+</%def>
+
+${my_def('drôle de petite voix m’a réveillé')}
+<%self:my_def x='drôle de petite voix m’a réveillé'/>
+<%self:my_def x="${'drôle de petite voix m’a réveillé'}"/>
+<%call expr="my_def('drôle de petite voix m’a réveillé')"/>
Added: pypy/benchmarks/lib/mako/test/templates/unicode_code.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_code.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,7 @@
+## -*- coding: utf-8 -*-
+<%
+ x = u"drôle de petite voix m’a réveillé."
+%>
+% if x==u"drôle de petite voix m’a réveillé.":
+ hi, ${x}
+% endif
Added: pypy/benchmarks/lib/mako/test/templates/unicode_code_py3k.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_code_py3k.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,7 @@
+## -*- coding: utf-8 -*-
+<%
+ x = "drôle de petite voix m’a réveillé."
+%>
+% if x=="drôle de petite voix m’a réveillé.":
+ hi, ${x}
+% endif
Added: pypy/benchmarks/lib/mako/test/templates/unicode_expr.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_expr.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+## -*- coding: 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! »"}
Added: pypy/benchmarks/lib/mako/test/templates/unicode_expr_py3k.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_expr_py3k.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+${"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! »"}
Added: pypy/benchmarks/lib/mako/test/templates/unicode_runtime_error.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_runtime_error.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+<% print '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! »' + int(5/0) %>
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/templates/unicode_syntax_error.html
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/templates/unicode_syntax_error.html Tue Dec 21 07:44:16 2010
@@ -0,0 +1,2 @@
+## -*- coding: utf-8 -*-
+<% print '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! » %>
\ No newline at end of file
Added: pypy/benchmarks/lib/mako/test/test_ast.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_ast.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,273 @@
+import unittest
+
+from mako import ast, exceptions, pyparser, util
+from test import eq_
+
+exception_kwargs = {'source':'', 'lineno':0, 'pos':0, 'filename':''}
+
+class AstParseTest(unittest.TestCase):
+
+ def test_locate_identifiers(self):
+ """test the location of identifiers in a python code string"""
+ code = """
+a = 10
+b = 5
+c = x * 5 + a + b + q
+(g,h,i) = (1,2,3)
+[u,k,j] = [4,5,6]
+foo.hoho.lala.bar = 7 + gah.blah + u + blah
+for lar in (1,2,3):
+ gh = 5
+ x = 12
+("hello world, ", a, b)
+("Another expr", c)
+"""
+ 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()
+
+ def test_locate_identifiers_2(self):
+ code = """
+import foobar
+from lala import hoho, yaya
+import bleep as foo
+result = []
+data = get_data()
+for x in data:
+ result.append(x+7)
+"""
+ parsed = ast.PythonCode(code, **exception_kwargs)
+ assert parsed.undeclared_identifiers == set(['get_data'])
+ assert parsed.declared_identifiers == set(['result', 'data', 'x', 'hoho', 'foobar', 'foo', 'yaya'])
+
+ def test_locate_identifiers_3(self):
+ """test that combination assignment/expressions of the same identifier log the ident as 'undeclared'"""
+ code = """
+x = x + 5
+for y in range(1, y):
+ ("hi",)
+[z for z in range(1, z)]
+(q for q in range (1, q))
+"""
+ 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 = """
+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 = """
+try:
+ print(x)
+except:
+ print(y)
+"""
+ else:
+
+ code = """
+try:
+ print x
+except:
+ print y
+"""
+ parsed = ast.PythonCode(code, **exception_kwargs)
+ assert parsed.undeclared_identifiers == set(['x', 'y'])
+
+ def test_locate_identifiers_6(self):
+ code = """
+def foo():
+ return bar()
+"""
+ parsed = ast.PythonCode(code, **exception_kwargs)
+ assert parsed.undeclared_identifiers == set(['bar'])
+
+ if util.py3k:
+ code = """
+def lala(x, y):
+ return x, y, z
+print(x)
+"""
+ else:
+ code = """
+def lala(x, y):
+ return x, y, z
+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):
+ def hoho():
+ def bar():
+ z = 7
+print(z)
+"""
+ else:
+ code = """
+def lala(x, y):
+ def hoho():
+ def bar():
+ z = 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
+"""
+ parsed = ast.PythonCode(code, **exception_kwargs)
+ assert parsed.declared_identifiers == set(['foo'])
+ assert parsed.undeclared_identifiers == set()
+
+ def test_locate_identifiers_8(self):
+ code = """
+class Hi(object):
+ foo = 7
+ def hoho(self):
+ x = 5
+"""
+ 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")])
+"""
+ 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
+"""
+ 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):
+ return q + 5
+"""
+ parsed = ast.PythonCode(code, **exception_kwargs)
+ eq_(parsed.declared_identifiers, set(['x']))
+ eq_(parsed.undeclared_identifiers, set())
+
+ def test_no_global_imports(self):
+ code = """
+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:
+ parsed = ast.PythonFragment("except MyException as e:", **exception_kwargs)
+ else:
+ 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'])
+ assert [x for x in parsed.args] == ["3", "5", "'hi'", "(x + 5)", "context.get('lala')"]
+
+ parsed = ast.ArgumentList("h", **exception_kwargs)
+ assert parsed.args == ["h"]
+
+ def test_function_decl(self):
+ """test getting the arguments from a function"""
+ code = "def foo(a, b, c=None, d='hi', e=x, f=y+7):pass"
+ parsed = ast.FunctionDecl(code, **exception_kwargs)
+ assert parsed.funcname=='foo'
+ assert parsed.argnames==['a', 'b', 'c', 'd', 'e', 'f']
+
+ def test_function_decl_2(self):
+ """test getting the arguments from a function"""
+ code = "def foo(a, b, c=None, *args, **kwargs):pass"
+ 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
+ y = 2
+ class F(object):
+ def bar(self, a,b):
+ return a + b
+ 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]
+ local_dict = dict(a=a,hoho=hoho,g=g)
+ code = "a[2] + hoho['somevalue'] + repr(g[3:5]) + repr(g[3:]) + repr(g[:5])"
+ 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)
+ newcode = pyparser.ExpressionGenerator(astnode).value()
+ assert(eval(code, local_dict)) == eval(newcode, local_dict)
+
+ for code in ["repr({'x':7,'y':18})", "repr([])", "repr({})", "repr([{3:[]}])", "repr({'x':37*2 + len([6,7,8])})", "repr([1, 2, {}, {'x':'7'}])", "repr({'x':-1})", "repr(((1,2,3), (4,5,6)))", "repr(1 and 2 and 3 and 4)", "repr(True and False or 55)", "repr(1 & 2 | 3)", "repr(3//5)", "repr(3^5)", "repr([q.endswith('e') for q in ['one', 'two', 'three']])", "repr([x for x in (5,6,7) if x == 6])", "repr(not False)"]:
+ local_dict={}
+ astnode = pyparser.parse(code)
+ newcode = pyparser.ExpressionGenerator(astnode).value()
+ assert(eval(code, local_dict)) == eval(newcode, local_dict), "%s != %s" % (code, newcode)
+
+
+
Added: pypy/benchmarks/lib/mako/test/test_babelplugin.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_babelplugin.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,42 @@
+
+from test import TemplateTest, template_base, skip_if
+
+try:
+ import babel
+ 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,
+ 'ungettext': (1, 2)},
+ ['TRANSLATOR:'], {}))
+ expected = \
+ [(1, '_', u'Page arg 1', []),
+ (1, '_', u'Page arg 2', []),
+ (10, 'gettext', u'Begin', []),
+ (14, '_', u'Hi there!', [u'TRANSLATOR: Hi there!']),
+ (19, '_', u'Hello', []),
+ (22, '_', u'Welcome', []),
+ (25, '_', u'Yo', []),
+ (36, '_', u'The', [u'TRANSLATOR: Ensure so and', u'so, thanks']),
+ (36, 'ungettext', (u'bunny', u'bunnies', None), []),
+ (41, '_', u'Goodbye', [u'TRANSLATOR: Good bye']),
+ (44, '_', u'Babel', []),
+ (45, 'ungettext', (u'hella', u'hellas', None), []),
+ (62, '_', u'Goodbye, really!', [u'TRANSLATOR: HTML comment']),
+ (65, '_', u'P.S. byebye', []),
+ (71, '_', u'Top', []),
+ (77, '_', u'foo', []),
+ (77, '_', u'baz', []),
+ (79, '_', u'bar', [])
+ ]
+ self.assertEqual(expected, messages)
+
Added: pypy/benchmarks/lib/mako/test/test_cache.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_cache.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,404 @@
+from mako.template import Template
+from mako.lookup import TemplateLookup
+from mako import lookup
+import shutil, unittest, os
+from util import result_lines
+from test import TemplateTest, template_base, module_base
+
+try:
+ import beaker
+except:
+ from nose import SkipTest
+ raise SkipTest("Beaker is required for these tests.")
+
+class MockCache(object):
+ def __init__(self, realcache):
+ self.realcache = realcache
+ def get(self, key, **kwargs):
+ self.key = key
+ self.kwargs = kwargs.copy()
+ 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("""
+ <%!
+ callcount = [0]
+ %>
+ <%def name="foo()" cached="True">
+ this is foo
+ <%
+ callcount[0] += 1
+ %>
+ </%def>
+
+ ${foo()}
+ ${foo()}
+ ${foo()}
+ callcount: ${callcount}
+""")
+ m = self._install_mock_cache(t)
+ assert result_lines(t.render()) == [
+ 'this is foo',
+ 'this is foo',
+ 'this is foo',
+ 'callcount: [1]',
+ ]
+ assert m.kwargs == {}
+
+ def test_cache_enable(self):
+ t = Template("""
+ <%!
+ callcount = [0]
+ %>
+ <%def name="foo()" cached="True">
+ <% callcount[0] += 1 %>
+ </%def>
+ ${foo()}
+ ${foo()}
+ callcount: ${callcount}
+ """, cache_enabled=False)
+ m = self._install_mock_cache(t)
+
+ assert t.render().strip() =="callcount: [2]"
+
+ def test_nested_def(self):
+ t = Template("""
+ <%!
+ callcount = [0]
+ %>
+ <%def name="foo()">
+ <%def name="bar()" cached="True">
+ this is foo
+ <%
+ callcount[0] += 1
+ %>
+ </%def>
+ ${bar()}
+ </%def>
+
+ ${foo()}
+ ${foo()}
+ ${foo()}
+ callcount: ${callcount}
+""")
+ m = self._install_mock_cache(t)
+ assert result_lines(t.render()) == [
+ 'this is foo',
+ 'this is foo',
+ 'this is foo',
+ 'callcount: [1]',
+ ]
+ assert m.kwargs == {}
+
+ def test_page(self):
+ t = Template("""
+ <%!
+ callcount = [0]
+ %>
+ <%page cached="True"/>
+ this is foo
+ <%
+ callcount[0] += 1
+ %>
+ callcount: ${callcount}
+""")
+ m = self._install_mock_cache(t)
+ t.render()
+ t.render()
+ assert result_lines(t.render()) == [
+ "this is foo",
+ "callcount: [1]"
+ ]
+ assert m.kwargs == {}
+
+ def test_dynamic_key_with_funcargs(self):
+ t = Template("""
+ <%def name="foo(num=5)" cached="True" cache_key="foo_${str(num)}">
+ hi
+ </%def>
+
+ ${foo()}
+ """)
+ m = self._install_mock_cache(t)
+ t.render()
+ t.render()
+ assert result_lines(t.render()) == ['hi']
+ assert m.key == "foo_5"
+
+ t = Template("""
+ <%def name="foo(*args, **kwargs)" cached="True" cache_key="foo_${kwargs['bar']}">
+ hi
+ </%def>
+
+ ${foo(1, 2, bar='lala')}
+ """)
+ m = self._install_mock_cache(t)
+ t.render()
+ assert result_lines(t.render()) == ['hi']
+ assert m.key == "foo_lala"
+
+ t = Template('''
+ <%page args="bar='hi'" cache_key="foo_${bar}" cached="True"/>
+ hi
+ ''')
+ m = self._install_mock_cache(t)
+ t.render()
+ 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", """
+ <%!
+ callcount = [0]
+ %>
+ <%namespace file="ns.html" import="*"/>
+ <%page cached="True" cache_key="${foo}"/>
+ this is foo
+ <%
+ callcount[0] += 1
+ %>
+ callcount: ${callcount}
+""")
+ lookup.put_string("ns.html", """""")
+ t = lookup.get_template("foo.html")
+ m = self._install_mock_cache(t)
+ t.render(foo='somekey')
+ t.render(foo='somekey')
+ assert result_lines(t.render(foo='somekey')) == [
+ "this is foo",
+ "callcount: [1]"
+ ]
+ assert m.kwargs == {}
+
+ def test_fileargs_implicit(self):
+ l = lookup.TemplateLookup(module_directory=module_base)
+ l.put_string("test","""
+ <%!
+ callcount = [0]
+ %>
+ <%def name="foo()" cached="True" cache_type='dbm'>
+ this is foo
+ <%
+ callcount[0] += 1
+ %>
+ </%def>
+
+ ${foo()}
+ ${foo()}
+ ${foo()}
+ callcount: ${callcount}
+ """)
+
+ m = self._install_mock_cache(l.get_template('test'))
+ assert result_lines(l.get_template('test').render()) == [
+ 'this is foo',
+ 'this is foo',
+ 'this is foo',
+ 'callcount: [1]',
+ ]
+ assert m.kwargs == {'type':'dbm', 'data_dir':module_base}
+
+ def test_fileargs_deftag(self):
+ t = Template("""
+ <%%!
+ callcount = [0]
+ %%>
+ <%%def name="foo()" cached="True" cache_type='file' cache_dir='%s'>
+ this is foo
+ <%%
+ callcount[0] += 1
+ %%>
+ </%%def>
+
+ ${foo()}
+ ${foo()}
+ ${foo()}
+ callcount: ${callcount}
+""" % module_base)
+ m = self._install_mock_cache(t)
+ assert result_lines(t.render()) == [
+ 'this is foo',
+ 'this is foo',
+ 'this is foo',
+ 'callcount: [1]',
+ ]
+ assert m.kwargs == {'type':'file','data_dir':module_base}
+
+ def test_fileargs_pagetag(self):
+ t = Template("""
+ <%%page cache_dir='%s' cache_type='dbm'/>
+ <%%!
+ callcount = [0]
+ %%>
+ <%%def name="foo()" cached="True">
+ this is foo
+ <%%
+ callcount[0] += 1
+ %%>
+ </%%def>
+
+ ${foo()}
+ ${foo()}
+ ${foo()}
+ callcount: ${callcount}
+""" % module_base)
+ m = self._install_mock_cache(t)
+ assert result_lines(t.render()) == [
+ 'this is foo',
+ 'this is foo',
+ 'this is foo',
+ 'callcount: [1]',
+ ]
+ assert m.kwargs == {'data_dir':module_base, 'type':'dbm'}
+
+ def test_args_complete(self):
+ t = Template("""
+ <%%def name="foo()" cached="True" cache_timeout="30" cache_dir="%s" cache_type="file" cache_key='somekey'>
+ this is foo
+ </%%def>
+
+ ${foo()}
+""" % module_base)
+ 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
+ """ % module_base)
+ m = self._install_mock_cache(t2)
+ t2.render()
+ assert m.kwargs == {'data_dir':module_base, 'type':'file', 'expiretime':30}
+
+ def test_fileargs_lookup(self):
+ l = lookup.TemplateLookup(cache_dir=module_base, cache_type='file')
+ l.put_string("test","""
+ <%!
+ callcount = [0]
+ %>
+ <%def name="foo()" cached="True">
+ this is foo
+ <%
+ callcount[0] += 1
+ %>
+ </%def>
+
+ ${foo()}
+ ${foo()}
+ ${foo()}
+ callcount: ${callcount}
+ """)
+
+ t = l.get_template('test')
+ m = self._install_mock_cache(t)
+ assert result_lines(l.get_template('test').render()) == [
+ 'this is foo',
+ 'this is foo',
+ 'this is foo',
+ 'callcount: [1]',
+ ]
+ assert m.kwargs == {'data_dir':module_base, 'type':'file'}
+
+ def test_buffered(self):
+ t = Template("""
+ <%!
+ def a(text):
+ return "this is a " + text.strip()
+ %>
+ ${foo()}
+ ${foo()}
+ <%def name="foo()" cached="True" buffered="True">
+ this is a test
+ </%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()}
+ <%def name="foo()" cached="True" cache_timeout="2">
+ 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()}
+ <%def name="foo()" cached="True" cache_timeout="2">
+ foo: ${x}
+ </%def>
+ """)
+
+ import time
+ x1 = t.render(x=1)
+ time.sleep(3)
+ x2 = t.render(x=2)
+ assert x1.strip() == "foo: 1"
+ assert x2.strip() == "foo: 2"
+
+ def test_namespace_access(self):
+ t = Template("""
+ <%def name="foo(x)" cached="True">
+ foo: ${x}
+ </%def>
+
+ <%
+ foo(1)
+ foo(2)
+ local.cache.invalidate_def('foo')
+ foo(3)
+ foo(4)
+ %>
+ """)
+ assert result_lines(t.render()) == ['foo: 1', 'foo: 1', 'foo: 3', 'foo: 3']
+
+ def test_invalidate(self):
+ t = Template("""
+ <%%def name="foo()" cached="True">
+ foo: ${x}
+ </%%def>
+
+ <%%def name="bar()" cached="True" cache_type='dbm' cache_dir='%s'>
+ bar: ${x}
+ </%%def>
+ ${foo()} ${bar()}
+ """ % module_base)
+ assert result_lines(t.render(x=1)) == ["foo: 1", "bar: 1"]
+ assert result_lines(t.render(x=2)) == ["foo: 1", "bar: 1"]
+ t.cache.invalidate_def('foo')
+ 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"]
+ assert result_lines(t.render(x=2)) == ["page: 1"]
+ 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
+ return m
Added: pypy/benchmarks/lib/mako/test/test_call.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_call.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,447 @@
+from mako.template import Template
+from mako import util
+from util import result_lines, flatten_result
+from test import TemplateTest, eq_
+
+class CallTest(TemplateTest):
+ def test_call(self):
+ t = Template("""
+ <%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>
+""")
+ assert result_lines(t.render()) == ['hi im foo', 'this is the body, y is 5']
+
+
+ def test_compound_call(self):
+ t = Template("""
+
+ <%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}
+ </%def>
+ this is the body, ${comp1(6)}
+ </%call>
+ ${bar()}
+
+""")
+ assert result_lines(t.render()) == ['foo calling comp1:', 'this is comp1, 5', 'foo calling body:', 'this is the body,', 'this is comp1, 6', 'this is bar']
+
+ 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}
+ ${y}
+ ${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()">
+ OUTER BEGIN
+ <%call expr="caller.inner_func()">
+ INNER CALL
+ </%call>
+ OUTER END
+ </%def>
+
+ <%call expr="outer_func()">
+ <%def name="inner_func()">
+ INNER BEGIN
+ ${caller.body()}
+ INNER END
+ </%def>
+ </%call>
+
+ """)
+ #print t.code
+ assert result_lines(t.render()) == [
+ "OUTER BEGIN",
+ "INNER BEGIN",
+ "INNER CALL",
+ "INNER END",
+ "OUTER END",
+ ]
+
+ def test_stack_pop(self):
+ t = Template("""
+ <%def name="links()" buffered="True">
+ Some links
+ </%def>
+
+ <%def name="wrapper(links)">
+ <h1>${caller.body()}</h1>
+ ${links}
+ </%def>
+
+ ## links() pushes a stack frame on. when complete,
+ ## 'nextcaller' must be restored
+ <%call expr="wrapper(links())">
+ Some title
+ </%call>
+
+ """)
+
+ assert result_lines(t.render()) == [
+ "<h1>",
+ "Some title",
+ "</h1>",
+ "Some links"
+ ]
+
+ def test_conditional_call(self):
+ """test that 'caller' is non-None only if the immediate <%def> was called via <%call>"""
+
+ t = Template("""
+ <%def name="a()">
+ % if caller:
+ ${ caller.body() } \\
+ % endif
+ AAA
+ ${ b() }
+ </%def>
+
+ <%def name="b()">
+ % if caller:
+ ${ caller.body() } \\
+ % endif
+ BBB
+ ${ c() }
+ </%def>
+
+ <%def name="c()">
+ % if caller:
+ ${ caller.body() } \\
+ % endif
+ CCC
+ </%def>
+
+ <%call expr="a()">
+ CALL
+ </%call>
+
+ """)
+ assert result_lines(t.render()) == [
+ "CALL",
+ "AAA",
+ "BBB",
+ "CCC"
+ ]
+
+ def test_chained_call(self):
+ """test %calls that are chained through their targets"""
+ t = Template("""
+ <%def name="a()">
+ this is a.
+ <%call expr="b()">
+ this is a's ccall. heres my body: ${caller.body()}
+ </%call>
+ </%def>
+ <%def name="b()">
+ this is b. heres my body: ${caller.body()}
+ 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.',
+ 'this is b. heres my body:',
+ "this is a's ccall. heres my body:",
+ 'heres the main templ call',
+ "whats in the body's caller's body ?",
+ 'heres the main templ call'
+ ]
+
+ def test_nested_call(self):
+ """test %calls that are nested inside each other"""
+ t = Template("""
+ <%def name="foo()">
+ ${caller.body(x=10)}
+ </%def>
+
+ x is ${x}
+ <%def name="bar()">
+ bar: ${caller.body()}
+ </%def>
+
+ <%call expr="foo()" args="x">
+ this is foo body: ${x}
+
+ <%call expr="bar()">
+ this is bar body: ${x}
+ </%call>
+ </%call>
+""")
+ assert result_lines(t.render(x=5)) == [
+ "x is 5",
+ "this is foo body: 10",
+ "bar:",
+ "this is bar body: 10"
+ ]
+
+ def test_nested_call_2(self):
+ t = Template("""
+ x is ${x}
+ <%def name="foo()">
+ ${caller.foosub(x=10)}
+ </%def>
+
+ <%def name="bar()">
+ bar: ${caller.barsub()}
+ </%def>
+
+ <%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>
+""")
+ assert result_lines(t.render(x=5)) == [
+ "x is 5",
+ "this is foo body: 10",
+ "bar:",
+ "this is bar body: 10"
+ ]
+
+ def test_nested_call_3(self):
+ template = Template('''\
+ <%def name="A()">
+ ${caller.body()}
+ </%def>
+
+ <%def name="B()">
+ ${caller.foo()}
+ </%def>
+
+ <%call expr="A()">
+ <%call expr="B()">
+ <%def name="foo()">
+ foo
+ </%def>
+ </%call>
+ </%call>
+
+ ''')
+ assert flatten_result(template.render()) == "foo"
+
+ def test_chained_call_in_nested(self):
+ t = Template("""
+ <%def name="embedded()">
+ <%def name="a()">
+ this is a.
+ <%call expr="b()">
+ this is a's ccall. heres my body: ${caller.body()}
+ </%call>
+ </%def>
+ <%def name="b()">
+ this is b. heres my body: ${caller.body()}
+ whats in the body's caller's body ? ${context.caller_stack[-2].body()}
+ </%def>
+
+ <%call expr="a()">
+ heres the main templ call
+ </%call>
+ </%def>
+ ${embedded()}
+""")
+ #print t.code
+ #print result_lines(t.render())
+ assert result_lines(t.render()) == [
+ 'this is a.',
+ 'this is b. heres my body:',
+ "this is a's ccall. heres my body:",
+ 'heres the main templ call',
+ "whats in the body's caller's body ?",
+ 'heres the main templ call'
+ ]
+
+ def test_call_in_nested(self):
+ t = Template("""
+ <%def name="a()">
+ this is a ${b()}
+ <%def name="b()">
+ this is b
+ <%call expr="c()">
+ this is the body in b's call
+ </%call>
+ </%def>
+ <%def name="c()">
+ this is c: ${caller.body()}
+ </%def>
+ </%def>
+ ${a()}
+""")
+ assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call"]
+
+ def test_regular_defs(self):
+ t = Template("""
+ <%!
+ @runtime.supports_caller
+ def a(context):
+ context.write("this is a")
+ if context['caller']:
+ context['caller'].body()
+ context.write("a is done")
+ return ''
+ %>
+
+ <%def name="b()">
+ this is b
+ our body: ${caller.body()}
+ ${a(context)}
+ </%def>
+ test 1
+ <%call expr="a(context)">
+ this is the body
+ </%call>
+ test 2
+ <%call expr="b()">
+ this is the body
+ </%call>
+ test 3
+ <%call expr="b()">
+ this is the body
+ <%call expr="b()">
+ this is the nested body
+ </%call>
+ </%call>
+
+
+ """)
+ #print t.code
+ assert result_lines(t.render()) == [
+ "test 1",
+ "this is a",
+ "this is the body",
+ "a is done",
+ "test 2",
+ "this is b",
+ "our body:",
+ "this is the body",
+ "this is aa is done",
+ "test 3",
+ "this is b",
+ "our body:",
+ "this is the body",
+ "this is b",
+ "our body:",
+ "this is the nested body",
+ "this is aa is done",
+ "this is aa is done"
+ ]
+
+ def test_call_in_nested_2(self):
+ t = Template("""
+ <%def name="a()">
+ <%def name="d()">
+ not this d
+ </%def>
+ this is a ${b()}
+ <%def name="b()">
+ <%def name="d()">
+ not this d either
+ </%def>
+ this is b
+ <%call expr="c()">
+ <%def name="d()">
+ this is d
+ </%def>
+ this is the body in b's call
+ </%call>
+ </%def>
+ <%def name="c()">
+ this is c: ${caller.body()}
+ the embedded "d" is: ${caller.d()}
+ </%def>
+ </%def>
+ ${a()}
+""")
+ assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call", 'the embedded "d" is:', 'this is d']
+
+class SelfCacheTest(TemplateTest):
+ """this test uses a now non-public API."""
+
+ def test_basic(self):
+ t = Template("""
+ <%!
+ cached = None
+ %>
+ <%def name="foo()">
+ <%
+ global cached
+ if cached:
+ return "cached: " + cached
+ __M_writer = context._push_writer()
+ %>
+ this is foo
+ <%
+ buf, __M_writer = context._pop_buffer_and_writer()
+ cached = buf.getvalue()
+ return cached
+ %>
+ </%def>
+
+ ${foo()}
+ ${foo()}
+""")
+ assert result_lines(t.render()) == [
+ "this is foo",
+ "cached:",
+ "this is foo"
+ ]
+
Added: pypy/benchmarks/lib/mako/test/test_decorators.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_decorators.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,110 @@
+from mako.template import Template
+from mako import lookup
+import unittest
+from util import flatten_result, result_lines
+
+class DecoratorTest(unittest.TestCase):
+ def test_toplevel(self):
+ template = Template("""
+ <%!
+ def bar(fn):
+ def decorate(context, *args, **kw):
+ 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)}
+ """)
+
+ assert flatten_result(template.render()) == "BAR this is foo 1 5 BAR"
+
+ def test_toplevel_contextual(self):
+ template = Template("""
+ <%!
+ def bar(fn):
+ def decorate(context):
+ context.write("BAR")
+ fn()
+ context.write("BAR")
+ return ''
+ return decorate
+ %>
+
+ <%def name="foo()" decorator="bar">
+ this is foo
+ </%def>
+
+ ${foo()}
+ """)
+
+ assert flatten_result(template.render()) == "BAR this is foo BAR"
+
+ assert flatten_result(template.get_def('foo').render()) == "BAR this is foo BAR"
+
+
+ def test_nested(self):
+ template = Template("""
+ <%!
+ def bat(fn):
+ def decorate(context):
+ return "BAT" + runtime.capture(context, fn) + "BAT"
+ return decorate
+ %>
+
+ <%def name="foo()">
+
+ <%def name="bar()" decorator="bat">
+ this is bar
+ </%def>
+ ${bar()}
+ </%def>
+
+ ${foo()}
+ """)
+
+ assert flatten_result(template.render()) == "BAT this is bar BAT"
+
+ def test_toplevel_decorated_name(self):
+ template = Template("""
+ <%!
+ def bar(fn):
+ def decorate(context, *args, **kw):
+ return "function " + fn.__name__ + " " + runtime.capture(context, fn, *args, **kw)
+ return decorate
+ %>
+
+ <%def name="foo(y, x)" decorator="bar">
+ this is foo ${y} ${x}
+ </%def>
+
+ ${foo(1, x=5)}
+ """)
+
+ assert flatten_result(template.render()) == "function foo this is foo 1 5"
+
+ def test_nested_decorated_name(self):
+ template = Template("""
+ <%!
+ def bat(fn):
+ def decorate(context):
+ return "function " + fn.__name__ + " " + runtime.capture(context, fn)
+ return decorate
+ %>
+
+ <%def name="foo()">
+
+ <%def name="bar()" decorator="bat">
+ this is bar
+ </%def>
+ ${bar()}
+ </%def>
+
+ ${foo()}
+ """)
+
+ assert flatten_result(template.render()) == "function bar this is bar"
+
Added: pypy/benchmarks/lib/mako/test/test_def.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_def.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,550 @@
+from mako.template import Template
+from mako import lookup
+from test import TemplateTest
+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"""
+
+ def test_def_blankargs(self):
+ template = Template("""
+ <%def name="mycomp()">
+ hello mycomp ${variable}
+ </%def>
+
+ ${mycomp()}""")
+ assert template.render(variable='hi').strip() == """hello mycomp hi"""
+
+ def test_def_args(self):
+ template = Template("""
+ <%def name="mycomp(a, b)">
+ hello mycomp ${variable}, ${a}, ${b}
+ </%def>
+
+ ${mycomp(5, 6)}""")
+ assert template.render(variable='hi', a=5, b=6).strip() == """hello mycomp hi, 5, 6"""
+
+ def test_inter_def(self):
+ """test defs calling each other"""
+ template = Template("""
+ ${b()}
+
+ <%def name="a()">\
+ im a
+ </%def>
+
+ <%def name="b()">
+ im b
+ and heres a: ${a()}
+ </%def>
+
+ <%def name="c()">
+ im c
+ </%def>
+""")
+ # 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"
+
+ def test_toplevel(self):
+ """test calling a def from the top level"""
+
+ template = Template("""
+
+ this is the body
+
+ <%def name="a()">
+ this is a
+ </%def>
+
+ <%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()">
+ this is a, and y is ${y}
+ </%def>
+
+ ${a()}
+
+ <%
+ y = 7
+ %>
+
+ ${a()}
+
+""",
+ "this is a, and y is None this is a, and y is 7",
+ filters=flatten_result,
+ template_args={'y':None}
+ )
+
+ def test_scope_two(self):
+ t = Template("""
+ y is ${y}
+
+ <%
+ y = 7
+ %>
+
+ y is ${y}
+""")
+ try:
+ t.render(y=None)
+ assert False
+ except UnboundLocalError:
+ assert True
+
+ def test_scope_four(self):
+ """test that variables are pulled from 'enclosing' scope before context."""
+ t = Template("""
+ <%
+ x = 5
+ %>
+ <%def name="a()">
+ this is a. x is ${x}.
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 9
+ %>
+ 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.
+ t = Template("""
+ <%def name="enclosing()">
+ <%
+ x = 5
+ %>
+ <%def name="a()">
+ this is a. x is ${x}.
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 9
+ %>
+ this is b. x is ${x}.
+ calling a. ${a()}
+ </%def>
+
+ ${b()}
+ </%def>
+ ${enclosing()}
+""")
+ assert flatten_result(t.render()) == "this is b. x is 9. calling a. this is a. x is 5."
+
+ def test_scope_six(self):
+ """test that the initial context counts as 'enclosing' scope, for plain defs"""
+ t = Template("""
+
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 10
+ %>
+ b. x is ${x}. ${a()}
+ </%def>
+
+ ${b()}
+ """)
+ assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 5"
+
+ def test_scope_seven(self):
+ """test that the initial context counts as 'enclosing' scope, for nested defs"""
+ t = Template("""
+ <%def name="enclosing()">
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 10
+ %>
+ b. x is ${x}. ${a()}
+ </%def>
+
+ ${b()}
+ </%def>
+ ${enclosing()}
+ """)
+ assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 5"
+
+ def test_scope_eight(self):
+ """test that the initial context counts as 'enclosing' scope, for nested defs"""
+ t = Template("""
+ <%def name="enclosing()">
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%
+ x = 10
+ %>
+
+ b. x is ${x}. ${a()}
+ </%def>
+
+ ${b()}
+ </%def>
+ ${enclosing()}
+ """)
+ assert flatten_result(t.render(x=5)) == "b. x is 10. a: x is 5"
+
+ def test_scope_nine(self):
+ """test that 'enclosing scope' doesnt get exported to other templates"""
+
+ l = lookup.TemplateLookup()
+ l.put_string('main', """
+ <%
+ x = 5
+ %>
+ this is main. <%include file="secondary"/>
+""")
+
+ l.put_string('secondary', """
+ this is secondary. x is ${x}
+""")
+
+ 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()">
+ <%def name="b()">
+ <%
+ y = 19
+ %>
+ b/c: ${c()}
+ b/y: ${y}
+ </%def>
+ <%def name="c()">
+ c/y: ${y}
+ </%def>
+
+ <%
+ # we assign to "y". but the 'enclosing scope' of "b" and "c" is from the "y" on the outside
+ y = 10
+ %>
+ a/y: ${y}
+ a/b: ${b()}
+ </%def>
+
+ <%
+ y = 7
+ %>
+ main/a: ${a()}
+ main/y: ${y}
+ """)
+ assert flatten_result(t.render()) == "main/a: a/y: 10 a/b: b/c: c/y: 10 b/y: 19 main/y: 7"
+
+ def test_scope_eleven(self):
+ t = Template("""
+ x is ${x}
+ <%def name="a(x)">
+ this is a, ${b()}
+ <%def name="b()">
+ this is b, x is ${x}
+ </%def>
+ </%def>
+
+ ${a(x=5)}
+""")
+ assert result_lines(t.render(x=10)) == [
+ "x is 10",
+ "this is a,",
+ "this is b, x is 5"
+ ]
+
+ def test_unbound_scope(self):
+ t = Template("""
+ <%
+ y = 10
+ %>
+ <%def name="a()">
+ y is: ${y}
+ <%
+ # should raise error ?
+ y = 15
+ %>
+ y is ${y}
+ </%def>
+ ${a()}
+""")
+ try:
+ print t.render()
+ assert False
+ except UnboundLocalError:
+ assert True
+
+ def test_unbound_scope_two(self):
+ t = Template("""
+ <%def name="enclosing()">
+ <%
+ y = 10
+ %>
+ <%def name="a()">
+ y is: ${y}
+ <%
+ # should raise error ?
+ y = 15
+ %>
+ y is ${y}
+ </%def>
+ ${a()}
+ </%def>
+ ${enclosing()}
+""")
+ try:
+ print t.render()
+ assert False
+ except UnboundLocalError:
+ assert True
+
+ def test_canget_kwargs(self):
+ """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()) == [
+ "this is main. x is 12",
+ "this is a, x is 12"
+ ]
+
+ l.put_string("another", """
+ <%namespace name="ns" file="main"/>
+
+ ${ns.body(x=15)}
+ """)
+ # test via namespace
+ assert result_lines(l.get_template("another").render()) == [
+ "this is main. x is 15",
+ "this is a, x is 15"
+ ]
+
+class NestedDefTest(TemplateTest):
+ def test_nested_def(self):
+ 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>
+ </%def>
+""")
+ assert flatten_result(t.render()) == "hey, im hi. and heres this is foo , this is bar"
+
+ def test_nested_2(self):
+ t = Template("""
+ x is ${x}
+ <%def name="a()">
+ this is a, x is ${x}
+ ${b()}
+ <%def name="b()">
+ this is b: ${x}
+ </%def>
+ </%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()}
+ <%def name="a()">
+ <%def name="b(x, y=2)">
+ b x is ${x} y is ${y}
+ </%def>
+ a ${b(5)}
+ </%def>
+""")
+ assert flatten_result(t.render()) == "a b x is 5 y is 2"
+
+ def test_nested_def_2(self):
+ template = Template("""
+ ${a()}
+ <%def name="a()">
+ <%def name="b()">
+ <%def name="c()">
+ comp c
+ </%def>
+ ${c()}
+ </%def>
+ ${b()}
+ </%def>
+""")
+ assert flatten_result(template.render()) == "comp c"
+
+ def test_nested_nested_def(self):
+ t = Template("""
+
+ ${a()}
+ <%def name="a()">
+ a
+ <%def name="b1()">
+ a_b1
+ </%def>
+ <%def name="b2()">
+ a_b2 ${c1()}
+ <%def name="c1()">
+ a_b2_c1
+ </%def>
+ </%def>
+ <%def name="b3()">
+ a_b3 ${c1()}
+ <%def name="c1()">
+ a_b3_c1 heres x: ${x}
+ <%
+ y = 7
+ %>
+ y is ${y}
+ </%def>
+ <%def name="c2()">
+ a_b3_c2
+ y is ${y}
+ c1 is ${c1()}
+ </%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()">
+ this is a ${b()}
+ <%def name="b()">
+ this is b
+ ${c()}
+ </%def>
+
+ <%def name="c()">
+ this is c
+ </%def>
+ </%def>
+ ${a()}
+""" )
+ assert flatten_result(t.render()) == "this is a this is b this is c"
+
+ def test_outer_scope(self):
+ t = Template("""
+ <%def name="a()">
+ a: x is ${x}
+ </%def>
+
+ <%def name="b()">
+ <%def name="c()">
+ <%
+ x = 10
+ %>
+ 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("""
+ <%
+ raise Exception("this is a test")
+ %>
+ """, format_exceptions=False)
+ try:
+ template.render()
+ assert False
+ except Exception, e:
+ assert str(e) == "this is a test"
+ def test_handler(self):
+ 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"""
+
Added: pypy/benchmarks/lib/mako/test/test_exceptions.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_exceptions.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,189 @@
+# -*- coding: utf-8 -*-
+import sys
+import unittest
+
+from mako import exceptions, util
+from mako.template import Template
+from mako.lookup import TemplateLookup
+from util import result_lines
+from test import template_base, module_base, TemplateTest
+
+class ExceptionsTest(TemplateTest):
+ def test_html_error_template(self):
+ """test the html_error_template"""
+ code = """
+% i = 0
+"""
+ try:
+ template = Template(code)
+ template.render_unicode()
+ assert False
+ except exceptions.CompileException, ce:
+ html_error = exceptions.html_error_template().render_unicode()
+ assert ("CompileException: Fragment 'i = 0' is not a partial "
+ "control statement") in html_error
+ assert '<style>' in html_error
+ html_error_stripped = html_error.strip()
+ assert html_error_stripped.startswith('<html>')
+ assert html_error_stripped.endswith('</html>')
+
+ not_full = exceptions.html_error_template().\
+ render_unicode(full=False)
+ assert '<html>' not in not_full
+ assert '<style>' in not_full
+
+ no_css = exceptions.html_error_template().\
+ render_unicode(css=False)
+ assert '<style>' not in no_css
+ else:
+ assert False, ("This function should trigger a CompileException, "
+ "but didn't")
+
+ def test_text_error_template(self):
+ code = """
+% i = 0
+"""
+ try:
+ template = Template(code)
+ template.render_unicode()
+ assert False
+ except exceptions.CompileException, ce:
+ text_error = exceptions.text_error_template().render_unicode()
+ assert 'Traceback (most recent call last):' in text_error
+ 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
+${'привет'}
+% endif
+"""
+ else:
+ code = """# -*- coding: utf-8 -*-
+% if 2 == 2: /an error
+${u'привет'}
+% endif
+"""
+ try:
+ template = Template(code)
+ template.render_unicode()
+ except exceptions.CompileException, ce:
+ html_error = exceptions.html_error_template().render()
+ assert ("CompileException: Fragment 'if 2 == 2: /an "
+ "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
+ else:
+ assert u"3 ${u'привет'}".encode(sys.getdefaultencoding(),
+ 'htmlentityreplace') in html_error
+ else:
+ assert False, ("This function should trigger a CompileException, "
+ "but didn't")
+
+ def test_format_closures(self):
+ try:
+ exec "def foo():"\
+ " raise RuntimeError('test')"\
+ in locals()
+ foo()
+ 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'日本'
+ raise RuntimeError('test')
+ except:
+ html_error = exceptions.html_error_template().render()
+ if util.py3k:
+ assert 'RuntimeError: test' in html_error.decode('utf-8')
+ assert u"foo = '日本'" in html_error.decode('utf-8')
+ else:
+ assert 'RuntimeError: test' in html_error
+ assert "foo = u'日本'" in html_error
+
+ def test_py_unicode_error_html_error_template(self):
+ try:
+ raise RuntimeError(u'日本')
+ except:
+ html_error = exceptions.html_error_template().render()
+ assert u"RuntimeError: 日本".encode('ascii', 'ignore') in html_error
+
+ def test_format_exceptions(self):
+ l = TemplateLookup(format_exceptions=True)
+
+ l.put_string("foo.html", """
+<%inherit file="base.html"/>
+${foobar}
+ """)
+
+ l.put_string("base.html", """
+ ${self.body()}
+ """)
+
+ 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}""")
+ else:
+ l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""")
+
+ if util.py3k:
+ assert u'<div class="sourceline">${'привет' + foobar}</div>'\
+ in result_lines(l.get_template("foo.html").render().decode('utf-8'))
+ else:
+ 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
+
+ def test_tback_no_trace(self):
+ try:
+ t = self._file_template("runtimeerr.html")
+ t.render()
+ except:
+ t, v, tback = sys.exc_info()
+
+ 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
Added: pypy/benchmarks/lib/mako/test/test_filters.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_filters.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,290 @@
+# -*- coding: utf-8 -*-
+
+from mako.template import Template
+import unittest
+from mako import util
+from test import TemplateTest, eq_, skip_if
+from util import result_lines, flatten_result
+
+class FilterTest(TemplateTest):
+ def test_basic(self):
+ t = Template("""
+ ${x | myfilter}
+""")
+ assert flatten_result(t.render(x="this is x", myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)) == "MYFILTER->this is x<-MYFILTER"
+
+ def test_expr(self):
+ """test filters that are themselves expressions"""
+ t = Template("""
+ ${x | myfilter(y)}
+""")
+ def myfilter(y):
+ return lambda x: "MYFILTER->%s<-%s" % (x, y)
+ assert flatten_result(t.render(x="this is x", myfilter=myfilter, y="this is y")) == "MYFILTER->this is x<-this is y"
+
+ def test_convert_str(self):
+ """test that string conversion happens in expressions before sending to filters"""
+ t = Template("""
+ ${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("""
+ foo ${bar | h}
+ """, disable_unicode=True)
+
+ eq_(
+ flatten_result(t.render(bar="<'привет'>")),
+ "foo <'привет'>"
+ )
+
+
+ def test_def(self):
+ t = Template("""
+ <%def name="foo()" filter="myfilter">
+ this is foo
+ </%def>
+ ${foo()}
+""")
+
+ assert flatten_result(t.render(x="this is x", myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)) == "MYFILTER-> this is foo <-MYFILTER"
+
+ def test_import(self):
+ t = Template("""
+ <%!
+ from mako import filters
+ %>\
+ trim this string: ${" some string to trim " | filters.trim} continue\
+ """)
+
+ 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\
+ """, imports=["from mako import filters"])
+ #print t.code
+ assert t.render().strip()=="trim this string: some string to trim continue"
+
+ def test_encode_filter(self):
+ t = Template("""# coding: utf-8
+ some stuff.... ${x}
+ """, 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"/>
+ ${"<tag>this is html</tag>"}
+ """)
+ assert t.render().strip() == "<tag>this is html</tag>"
+
+ def test_nflag(self):
+ t = Template("""
+ ${"<tag>this is html</tag>" | n}
+ """, default_filters=['h', 'unicode'])
+ assert t.render().strip() == "<tag>this is html</tag>"
+
+ t = Template("""
+ <%page expression_filter="h"/>
+ ${"<tag>this is html</tag>" | n}
+ """)
+ assert t.render().strip() == "<tag>this is html</tag>"
+
+ t = Template("""
+ <%page expression_filter="h"/>
+ ${"<tag>this is html</tag>" | n, h}
+ """)
+ assert t.render().strip() == "<tag>this is html</tag>"
+
+ def testnonexpression(self):
+ t = Template("""
+ <%!
+ def a(text):
+ return "this is a"
+ def b(text):
+ return "this is b"
+ %>
+
+ ${foo()}
+ <%def name="foo()" buffered="True">
+ this is text
+ </%def>
+ """, buffer_filters=['a'])
+ assert t.render().strip() == "this is a"
+
+ t = Template("""
+ <%!
+ def a(text):
+ return "this is a"
+ def b(text):
+ return "this is b"
+ %>
+
+ ${'hi'}
+ ${foo()}
+ <%def name="foo()" buffered="True">
+ this is text
+ </%def>
+ """, buffer_filters=['a'], default_filters=['b'])
+ assert flatten_result(t.render()) == "this is b this is b"
+
+ t = Template("""
+ <%!
+ class Foo(object):
+ foo = True
+ def __str__(self):
+ return "this is a"
+ def a(text):
+ return Foo()
+ def b(text):
+ if hasattr(text, 'foo'):
+ return str(text)
+ else:
+ return "this is b"
+ %>
+
+ ${'hi'}
+ ${foo()}
+ <%def name="foo()" buffered="True">
+ this is text
+ </%def>
+ """, buffer_filters=['a'], default_filters=['b'])
+ assert flatten_result(t.render()) == "this is b this is a"
+
+ t = Template("""
+ <%!
+ def a(text):
+ return "this is a"
+ def b(text):
+ return "this is b"
+ %>
+
+ ${foo()}
+ ${bar()}
+ <%def name="foo()" filter="b">
+ this is text
+ </%def>
+ <%def name="bar()" filter="b" buffered="True">
+ this is text
+ </%def>
+ """, 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):
+ def test_buffered_def(self):
+ t = Template("""
+ <%def name="foo()" buffered="True">
+ this is foo
+ </%def>
+ ${"hi->" + foo() + "<-hi"}
+""")
+ assert flatten_result(t.render()) == "hi-> this is foo <-hi"
+
+ def test_unbuffered_def(self):
+ t = Template("""
+ <%def name="foo()" buffered="False">
+ this is foo
+ </%def>
+ ${"hi->" + foo() + "<-hi"}
+""")
+ assert flatten_result(t.render()) == "this is foo hi-><-hi"
+
+ def test_capture(self):
+ t = Template("""
+ <%def name="foo()" buffered="False">
+ this is foo
+ </%def>
+ ${"hi->" + capture(foo) + "<-hi"}
+""")
+ assert flatten_result(t.render()) == "hi-> this is foo <-hi"
+
+ def test_capture_exception(self):
+ template = Template("""
+ <%def name="a()">
+ this is a
+ <%
+ raise TypeError("hi")
+ %>
+ </%def>
+ <%
+ c = capture(a)
+ %>
+ a->${c}<-a
+ """)
+ try:
+ template.render()
+ assert False
+ except TypeError:
+ assert True
+
+ def test_buffered_exception(self):
+ template = Template("""
+ <%def name="a()" buffered="True">
+ <%
+ 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()">
+ <%
+ x = capture(caller.body)
+ %>
+ this is foo. body: ${x}
+ </%def>
+
+ <%call expr="foo()">
+ ccall body
+ </%call>
+""")
+
+ #print t.render()
+ assert flatten_result(t.render()) == "this is foo. body: ccall body"
+
Added: pypy/benchmarks/lib/mako/test/test_inheritance.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_inheritance.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,350 @@
+from mako.template import Template
+from mako import lookup, util
+import unittest
+from util import flatten_result, result_lines
+
+class InheritanceTest(unittest.TestCase):
+ def test_basic(self):
+ collection = lookup.TemplateLookup()
+
+ collection.put_string('main', """
+<%inherit file="base"/>
+
+<%def name="header()">
+ main header.
+</%def>
+
+this is the content.
+""")
+
+ collection.put_string('base', """
+This is base.
+
+header: ${self.header()}
+
+body: ${self.body()}
+
+footer: ${self.footer()}
+
+<%def name="footer()">
+ this is the footer. header again ${next.header()}
+</%def>
+""")
+
+ assert result_lines(collection.get_template('main').render()) == [
+ 'This is base.',
+ 'header:',
+ 'main header.',
+ 'body:',
+ 'this is the content.',
+ 'footer:',
+ 'this is the footer. header again',
+ 'main header.'
+ ]
+
+ def test_multilevel_nesting(self):
+ collection = lookup.TemplateLookup()
+
+ collection.put_string('main', """
+<%inherit file="layout"/>
+<%def name="d()">main_d</%def>
+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>
+layout_body
+parent name: ${parent.name}
+${parent.d()}
+${parent.context['parent'].d()}
+${next.body()}
+""")
+
+ collection.put_string('general', """
+<%inherit file="base"/>
+<%def name="d()">general_d</%def>
+general_body
+${next.d()}
+${next.context['next'].d()}
+${next.body()}
+""")
+ collection.put_string('base', """
+base_body
+full stack from the base:
+ ${self.name} ${self.context['parent'].name} ${self.context['parent'].context['parent'].name} ${self.context['parent'].context['parent'].context['parent'].name}
+${next.body()}
+<%def name="d()">base_d</%def>
+""")
+
+ assert result_lines(collection.get_template('main').render()) == [
+ 'base_body',
+ 'full stack from the base:',
+ 'self:main self:layout self:general self:base',
+ 'general_body',
+ 'layout_d',
+ 'main_d',
+ 'layout_body',
+ 'parent name: self:general',
+ 'general_d',
+ 'base_d',
+ 'main_body layout_d',
+ '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.
+ ${next.body()}
+ End base.
+""")
+
+ collection.put_string("index","""
+ <%inherit file="base"/>
+ this is index.
+ a is: ${self.a()}
+ <%include file="secondary"/>
+""")
+
+ collection.put_string("secondary","""
+ <%inherit file="base"/>
+ this is secondary.
+ a is: ${self.a()}
+""")
+
+ assert result_lines(collection.get_template("index").render()) == [
+ 'This is the base.',
+ 'this is index.',
+ 'a is: base_a',
+ 'This is the base.',
+ 'this is secondary.',
+ 'a is: base_a',
+ 'End base.',
+ 'End base.'
+ ]
+
+ def test_namespaces(self):
+ """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>
+ This is the base.
+ ${next.body()}
+""")
+
+ collection.put_string("layout", """
+ <%inherit file="base"/>
+ <%def name="a()">layout_a</%def>
+ This is the layout..
+ ${next.body()}
+""")
+
+ collection.put_string("index","""
+ <%inherit file="base"/>
+ <%namespace name="sc" file="secondary"/>
+ this is index.
+ a is: ${self.a()}
+ sc.a is: ${sc.a()}
+ sc.b is: ${sc.b()}
+ sc.c is: ${sc.c()}
+ sc.body is: ${sc.body()}
+""")
+
+ collection.put_string("secondary","""
+ <%inherit file="layout"/>
+ <%def name="c()">secondary_c. a is ${self.a()} b is ${self.b()} d is ${self.d()}</%def>
+ <%def name="d()">secondary_d.</%def>
+ this is secondary.
+ a is: ${self.a()}
+ c is: ${self.c()}
+""")
+
+ assert result_lines(collection.get_template('index').render()) == ['This is the base.',
+ 'this is index.',
+ 'a is: base_a',
+ 'sc.a is: layout_a',
+ 'sc.b is: base_b',
+ 'sc.c is: secondary_c. a is layout_a b is base_b d is secondary_d.',
+ 'sc.body is:',
+ 'this is secondary.',
+ 'a is: layout_a',
+ 'c is: secondary_c. a is layout_a b is base_b d is secondary_d.'
+ ]
+
+ def test_pageargs(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base", """
+ this is the base.
+
+ <%
+ sorted_ = pageargs.items()
+ sorted_ = sorted(sorted_)
+ %>
+ pageargs: (type: ${type(pageargs)}) ${sorted_}
+ <%def name="foo()">
+ ${next.body(**context.kwargs)}
+ </%def>
+
+ ${foo()}
+ """)
+ collection.put_string("index", """
+ <%inherit file="base"/>
+ <%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.",
+ "pageargs: (type: <class 'dict'>) [('x', 5), ('y', 10)]",
+ "print 5, 10, 7"
+ ]
+ else:
+ assert result_lines(collection.get_template('index').render_unicode(x=5,y=10)) == [
+ "this is the base.",
+ "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>
+
+ <%def name="bar(**otherargs)">
+ ${next.body(z=16, **context.kwargs)}
+ </%def>
+
+ ${foo(x=12, y=15, z=8)}
+ ${bar(x=19, y=17)}
+ """)
+ collection.put_string("index", """
+ <%inherit file="base"/>
+ <%page args="x, y, z=7"/>
+ pageargs: ${x}, ${y}, ${z}
+ """)
+ assert result_lines(collection.get_template('index').render(x=5,y=10)) == [
+ "this is the base.",
+ "pageargs: 5, 10, 7",
+ "pageargs: 12, 15, 8",
+ "pageargs: 5, 10, 16"
+ ]
+
+ def test_pageargs_err(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base", """
+ this is the base.
+ ${next.body()}
+ """)
+ collection.put_string("index", """
+ <%inherit file="base"/>
+ <%page args="x, y, z=7"/>
+ print ${x}, ${y}, ${z}
+ """)
+ try:
+ print collection.get_template('index').render(x=5,y=10)
+ assert False
+ except TypeError:
+ assert True
+
+ def test_toplevel(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base", """
+ this is the base.
+ ${next.body()}
+ """)
+ collection.put_string("index", """
+ <%inherit file="base"/>
+ this is the body
+ """)
+ assert result_lines(collection.get_template('index').render()) == [
+ "this is the base.",
+ "this is the body"
+ ]
+ assert result_lines(collection.get_template('index').get_def("body").render()) == [
+ "this is the body"
+ ]
+
+ def test_dynamic(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base", """
+ this is the base.
+ ${next.body()}
+ """)
+ collection.put_string("index", """
+ <%!
+ def dyn(context):
+ if context.get('base', None) is not None:
+ return 'base'
+ else:
+ return None
+ %>
+ <%inherit file="${dyn(context)}"/>
+ this is index.
+ """)
+ assert result_lines(collection.get_template('index').render()) == [
+ 'this is index.'
+ ]
+ assert result_lines(collection.get_template('index').render(base=True)) == [
+ 'this is the base.',
+ 'this is index.'
+ ]
+
+ def test_in_call(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("/layout.html","""
+ Super layout!
+ <%call expr="self.grid()">
+ ${next.body()}
+ </%call>
+ Oh yea!
+
+ <%def name="grid()">
+ Parent grid
+ ${caller.body()}
+ End Parent
+ </%def>
+ """)
+
+
+ collection.put_string("/subdir/layout.html", """
+ ${next.body()}
+ <%def name="grid()">
+ Subdir grid
+ ${caller.body()}
+ End subdir
+ </%def>
+ <%inherit file="/layout.html"/>
+ """)
+
+ collection.put_string("/subdir/renderedtemplate.html","""
+ Holy smokes!
+ <%inherit file="/subdir/layout.html"/>
+ """)
+
+ #print collection.get_template("/layout.html").code
+ #print collection.get_template("/subdir/renderedtemplate.html").render()
+ assert result_lines(collection.get_template("/subdir/renderedtemplate.html").render()) == [
+ "Super layout!",
+ "Subdir grid",
+ "Holy smokes!",
+ "End subdir",
+ "Oh yea!"
+ ]
+
Added: pypy/benchmarks/lib/mako/test/test_lexer.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_lexer.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,854 @@
+import unittest
+
+from mako.lexer import Lexer
+from mako import exceptions, util
+from util import flatten_result, result_lines
+from mako.template import Template
+import re
+from test import TemplateTest, template_base, skip_if, eq_, assert_raises_message
+
+# create fake parsetree classes which are constructed
+# exactly as the repr() of a real parsetree object.
+# this allows us to use a Python construct as the source
+# of a comparable repr(), which is also hit by the 2to3 tool.
+
+def repr_arg(x):
+ if isinstance(x, dict):
+ return util.sorted_dict_repr(x)
+ else:
+ return repr(x)
+
+from mako import parsetree
+for cls in parsetree.__dict__.values():
+ if isinstance(cls, type) and \
+ issubclass(cls, parsetree.Node):
+ clsname = cls.__name__
+ exec ("""
+class %s(object):
+ def __init__(self, *args):
+ self.args = args
+ def __repr__(self):
+ return "%%s(%%s)" %% (
+ self.__class__.__name__,
+ ", ".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>
+ <%def name="foo()">
+ this is a def.
+ </%def>
+
+ and some more text.
+"""
+ node = Lexer(template).parse()
+ self._compare(node, TemplateNode({},
+ [Text(u'''\n<b>Hello world</b>\n ''', (1,
+ 1)), DefTag(u'def', {u'name': u'foo()'}, (3, 9),
+ [Text(u'''\n this is a def.\n ''',
+ (3, 28))]),
+ Text(u'''\n \n and some more text.\n''',
+ (5, 16))]))
+
+ def test_unclosed_tag(self):
+ template = """
+
+ <%def name="foo()">
+ other text
+ """
+ try:
+ nodes = Lexer(template).parse()
+ assert False
+ except exceptions.SyntaxException, e:
+ assert str(e) == "Unclosed tag: <%def> at line: 5 char: 9"
+
+ def test_onlyclosed_tag(self):
+ template = \
+ """
+ <%def name="foo()">
+ foo
+ </%def>
+
+ </%namespace>
+
+ hi.
+ """
+ self.assertRaises(exceptions.SyntaxException,
+ Lexer(template).parse)
+
+ def test_noexpr_allowed(self):
+ template = \
+ """
+ <%namespace name="${foo}"/>
+ """
+ self.assertRaises(exceptions.CompileException,
+ Lexer(template).parse)
+
+ def test_unmatched_tag(self):
+ template = \
+ """
+ <%namespace name="bar">
+ <%def name="foo()">
+ foo
+ </%namespace>
+ </%def>
+
+
+ hi.
+"""
+ self.assertRaises(exceptions.SyntaxException,
+ Lexer(template).parse)
+
+ def test_nonexistent_tag(self):
+ template = """
+ <%lala x="5"/>
+ """
+ self.assertRaises(exceptions.CompileException,
+ Lexer(template).parse)
+
+ def test_wrongcase_tag(self):
+ template = \
+ """
+ <%DEF name="foo()">
+ </%def>
+
+ """
+ self.assertRaises(exceptions.CompileException,
+ Lexer(template).parse)
+
+ def test_percent_escape(self):
+ template = \
+ """
+
+%% some whatever.
+
+ %% more some whatever
+ % if foo:
+ % endif
+ """
+ node = Lexer(template).parse()
+ self._compare(node, TemplateNode({}, [Text(u'''\n \n''',
+ (1, 1)), Text(u'''% some whatever.\n\n''', (3, 2)),
+ Text(u' %% more some whatever\n', (5, 2)),
+ 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 = \
+ """
+ ## comment
+ % if foo:
+ hi
+ % endif
+ <%text>
+ # more code
+
+ % more code
+ <%illegal compionent>/></>
+ <%def name="laal()">def</%def>
+
+
+ </%text>
+
+ <%def name="foo()">this is foo</%def>
+
+ % if bar:
+ code
+ % endif
+ """
+ node = Lexer(template).parse()
+ self._compare(node,
+ TemplateNode({}, [Text(u'\n', (1, 1)),
+ Comment(u'comment', (2, 1)),
+ ControlLine(u'if', u'if foo:', False, (3, 1)),
+ Text(u' hi\n', (4, 1)),
+ ControlLine(u'if', u'endif', True, (5, 1)),
+ Text(u' ', (6, 1)), TextTag(u'text', {},
+ (6, 9),
+ [Text(u'''\n # more code\n '''
+ '''\n % more code\n '''
+ '''<%illegal compionent>/></>\n '''
+ '''<%def name="laal()">def</%def>\n '''
+ ''' \n \n ''',
+ (6, 16))]), Text(u'''
+
+ ''', (14, 17)),
+ DefTag(u'def', {u'name': u'foo()'}, (16, 9),
+ [Text(u'this is foo', (16, 28))]),
+ Text(u'''\n \n''', (16, 46)),
+ ControlLine(u'if', u'if bar:', False, (18, 1)),
+ Text(u' code\n', (19, 1)),
+ ControlLine(u'if', u'endif', True, (20, 1)),
+ Text(u' ', (21, 1))]))
+
+ def test_def_syntax(self):
+ template = \
+ """
+ <%def lala>
+ hi
+ </%def>
+"""
+ self.assertRaises(exceptions.CompileException,
+ Lexer(template).parse)
+
+ def test_def_syntax_2(self):
+ template = \
+ """
+ <%def name="lala">
+ hi
+ </%def>
+ """
+ self.assertRaises(exceptions.CompileException,
+ Lexer(template).parse)
+
+ def test_whitespace_equals(self):
+ template = \
+ """
+ <%def name = "adef()" >
+ adef
+ </%def>
+ """
+ node = Lexer(template).parse()
+ self._compare(node, TemplateNode({}, [Text(u'\n ',
+ (1, 1)), DefTag(u'def', {u'name': u'adef()'}, (2,
+ 13),
+ [Text(u'''\n adef\n ''',
+ (2, 36))]), Text(u'\n ', (4, 20))]))
+
+ def test_ns_tag_closed(self):
+ template = \
+ """
+
+ <%self:go x="1" y="2" z="${'hi' + ' ' + 'there'}"/>
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Text(u'''
+
+ ''', (1, 1)),
+ 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 = \
+ """
+ <%form:option value=""></%form:option>
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [Text(u'\n ',
+ (1, 1)), CallNamespaceTag(u'form:option',
+ {u'value': u''}, (2, 13), []), Text(u'\n '
+ , (2, 51))]))
+
+ def test_ns_tag_open(self):
+ template = \
+ """
+
+ <%self:go x="1" y="${process()}">
+ this is the body
+ </%self:go>
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Text(u'''
+
+ ''', (1, 1)),
+ CallNamespaceTag(u'self:go', {u'x': u'1', u'y'
+ : u'${process()}'}, (3, 13),
+ [Text(u'''
+ this is the body
+ ''',
+ (3, 46))]), Text(u'\n ', (5, 24))]))
+
+ def test_expr_in_attribute(self):
+ """test some slightly trickier expressions.
+
+ you can still trip up the expression parsing, though, unless we
+ integrated really deeply somehow with AST."""
+
+ template = \
+ """
+ <%call expr="foo>bar and 'lala' or 'hoho'"/>
+ <%call expr='foo<bar and hoho>lala and "x" + "y"'/>
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [Text(u'\n ',
+ (1, 1)), CallTag(u'call', {u'expr'
+ : u"foo>bar and 'lala' or 'hoho'"}, (2, 13), []),
+ Text(u'\n ', (2, 57)), CallTag(u'call'
+ , {u'expr': u'foo<bar and hoho>lala and "x" + "y"'
+ }, (3, 13), []), Text(u'\n ', (3, 64))]))
+
+ def test_pagetag(self):
+ template = \
+ """
+ <%page cached="True", args="a, b"/>
+
+ some template
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [Text(u'\n ',
+ (1, 1)), PageTag(u'page', {u'args': u'a, b',
+ u'cached': u'True'}, (2, 13), []),
+ Text(u'''
+
+ some template
+ ''',
+ (2, 48))]))
+
+ def test_nesting(self):
+ template = \
+ """
+
+ <%namespace name="ns">
+ <%def name="lala(hi, there)">
+ <%call expr="something()"/>
+ </%def>
+ </%namespace>
+
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Text(u'''
+
+ ''', (1, 1)),
+ NamespaceTag(u'namespace', {u'name': u'ns'}, (3,
+ 9), [Text(u'\n ', (3, 31)),
+ DefTag(u'def', {u'name': u'lala(hi, there)'}, (4,
+ 13), [Text(u'\n ', (4, 42)),
+ CallTag(u'call', {u'expr': u'something()'}, (5,
+ 17), []), Text(u'\n ', (5, 44))]),
+ Text(u'\n ', (6, 20))]),
+ Text(u'''
+
+ ''', (7, 22))]))
+
+ if util.py3k:
+ def test_code(self):
+ template = \
+"""text
+ <%
+ print("hi")
+ for x in range(1,5):
+ print x
+ %>
+more text
+ <%!
+ import foo
+ %>
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes,
+ TemplateNode({}, [
+ Text(u'text\n ', (1, 1)),
+ Code(u'\nprint("hi")\nfor x in range(1,5):\n '
+ 'print x\n \n', False, (2, 5)),
+ Text(u'\nmore text\n ', (6, 7)),
+ Code(u'\nimport foo\n \n', True, (8, 5)),
+ Text(u'\n', (10, 7))])
+ )
+
+
+ else:
+
+ def test_code(self):
+ template = \
+"""text
+ <%
+ print "hi"
+ for x in range(1,5):
+ print x
+ %>
+more text
+ <%!
+ import foo
+ %>
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes,
+ TemplateNode({}, [
+ Text(u'text\n ', (1, 1)),
+ Code(u'\nprint "hi"\nfor x in range(1,5):\n '
+ 'print x\n \n', False, (2, 5)),
+ Text(u'\nmore text\n ', (6, 7)),
+ Code(u'\nimport foo\n \n', True, (8, 5)),
+ Text(u'\n', (10, 7))])
+ )
+
+ def test_code_and_tags(self):
+ template = \
+ """
+<%namespace name="foo">
+ <%def name="x()">
+ this is x
+ </%def>
+ <%def name="y()">
+ this is y
+ </%def>
+</%namespace>
+
+<%
+ result = []
+ data = get_data()
+ for x in data:
+ result.append(x+7)
+%>
+
+ result: <%call expr="foo.x(result)"/>
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [Text(u'\n', (1, 1)),
+ NamespaceTag(u'namespace', {u'name': u'foo'}, (2,
+ 1), [Text(u'\n ', (2, 24)), DefTag(u'def',
+ {u'name': u'x()'}, (3, 5),
+ [Text(u'''\n this is x\n ''', (3, 22))]),
+ Text(u'\n ', (5, 12)), DefTag(u'def', {u'name'
+ : u'y()'}, (6, 5),
+ [Text(u'''\n this is y\n ''', (6, 22))]),
+ Text(u'\n', (8, 12))]), Text(u'''\n\n''', (9, 14)),
+ Code(u'''\nresult = []\ndata = get_data()\n'''
+ '''for x in data:\n result.append(x+7)\n\n''',
+ False, (11, 1)), Text(u'''\n\n result: ''', (16,
+ 3)), CallTag(u'call', {u'expr': u'foo.x(result)'
+ }, (18, 13), []), Text(u'\n', (18, 42))]))
+
+ def test_expression(self):
+ template = \
+ """
+ this is some ${text} and this is ${textwith | escapes, moreescapes}
+ <%def name="hi()">
+ give me ${foo()} and ${bar()}
+ </%def>
+ ${hi()}
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Text(u'\n this is some ', (1, 1)),
+ Expression(u'text', [], (2, 22)),
+ Text(u' and this is ', (2, 29)),
+ Expression(u'textwith ', ['escapes', 'moreescapes'
+ ], (2, 42)), Text(u'\n ', (2, 76)),
+ DefTag(u'def', {u'name': u'hi()'}, (3, 9),
+ [Text(u'\n give me ', (3, 27)),
+ Expression(u'foo()', [], (4, 21)), Text(u' and ',
+ (4, 29)), Expression(u'bar()', [], (4, 34)),
+ 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 = """
+
+ ${x and "|" or "hi"}
+ """
+ nodes = Lexer(template).parse()
+ self._compare(
+ nodes,
+ TemplateNode({}, [
+ Text(u'\n \n ', (1, 1)),
+ Expression(u'x and "|" or "hi"', [], (3, 13)),
+ Text(u'\n ', (3, 33))
+ ])
+ )
+
+ template = """
+
+ ${hello + '''heres '{|}' text | | }''' | escape1}
+ """
+ nodes = Lexer(template).parse()
+ self._compare(
+ nodes,
+ TemplateNode({}, [
+ Text(u'\n \n ', (1, 1)),
+ Expression(u"hello + '''heres '{|}' text | | }''' ",
+ ['escape1'], (3, 13)),
+ Text(u'\n ', (3, 62))
+ ])
+ )
+
+ def test_tricky_code(self):
+ if util.py3k:
+ template = """<% print('hi %>') %>"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Code(u"print('hi %>') \n", False, (1, 1))]))
+ else:
+ template = """<% print 'hi %>' %>"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Code(u"print 'hi %>' \n", False, (1, 1))]))
+
+ def test_tricky_code_2(self):
+ template = \
+ """<%
+ # someone's comment
+ %>
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Code(u"""
+ # someone's comment
+
+""",
+ False, (1, 1)), Text(u'\n ', (3, 11))]))
+
+ if util.py3k:
+ def test_tricky_code_3(self):
+ template = \
+ """<%
+ print('hi')
+ # this is a comment
+ # another comment
+ x = 7 # someone's '''comment
+ print('''
+ there
+ ''')
+ # someone else's comment
+ %> '''and now some text '''"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Code(u"""
+print('hi')
+# this is a comment
+# another comment
+x = 7 # someone's '''comment
+print('''
+ there
+ ''')
+# someone else's comment
+
+""",
+ False, (1, 1)),
+ Text(u" '''and now some text '''", (10,
+ 11))]))
+ else:
+ def test_tricky_code_3(self):
+ template = \
+ """<%
+ print 'hi'
+ # this is a comment
+ # another comment
+ x = 7 # someone's '''comment
+ print '''
+ there
+ '''
+ # someone else's comment
+ %> '''and now some text '''"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Code(u"""\nprint 'hi'\n# this is a comment\n"""
+ """# another comment\nx = 7 """
+ """# someone's '''comment\nprint '''\n """
+ """there\n '''\n# someone else's """
+ """comment\n \n""",
+ False, (1, 1)),
+ Text(u" '''and now some text '''", (10,11))]))
+
+ def test_control_lines(self):
+ template = \
+ """
+text text la la
+% if foo():
+ mroe text la la blah blah
+% endif
+
+ and osme more stuff
+ % for l in range(1,5):
+ tex tesl asdl l is ${l} kfmas d
+ % endfor
+ tetx text
+
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Text(u'''\ntext text la la\n''', (1, 1)),
+ ControlLine(u'if', u'if foo():', False, (3, 1)),
+ Text(u' mroe text la la blah blah\n', (4, 1)),
+ ControlLine(u'if', u'endif', True, (5, 1)),
+ Text(u'''\n and osme more stuff\n''', (6,
+ 1)), ControlLine(u'for', u'for l in range(1,5):',
+ False, (8, 1)), Text(u' tex tesl asdl l is ',
+ (9, 1)), Expression(u'l', [], (9, 24)),
+ Text(u' kfmas d\n', (9, 28)), ControlLine(u'for',
+ u'endfor', True, (10, 1)),
+ Text(u''' tetx text\n \n''', (11, 1))]))
+
+ def test_control_lines_2(self):
+ template = \
+"""% for file in requestattr['toc'].filenames:
+ x
+% endfor
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [ControlLine(u'for',
+ u"for file in requestattr['toc'].filenames:",
+ False, (1, 1)), Text(u' x\n', (2, 1)),
+ ControlLine(u'for', u'endfor', True, (3, 1))]))
+
+ def test_long_control_lines(self):
+ template = \
+ """
+ % for file in \\
+ requestattr['toc'].filenames:
+ x
+ % endfor
+ """
+ nodes = Lexer(template).parse()
+ self._compare(
+ nodes,
+ TemplateNode({}, [
+ Text(u'\n', (1, 1)),
+ ControlLine(u'for', u"for file in \\\n "
+ "requestattr['toc'].filenames:",
+ False, (2, 1)),
+ Text(u' x\n', (4, 1)),
+ ControlLine(u'for', u'endfor', True, (5, 1)),
+ Text(u' ', (6, 1))
+ ])
+ )
+
+ def test_unmatched_control(self):
+ template = """
+
+ % if foo:
+ % for x in range(1,5):
+ % endif
+"""
+ assert_raises_message(
+ exceptions.SyntaxException,
+ "Keyword 'endif' doesn't match keyword 'for' at line: 5 char: 1",
+ Lexer(template).parse
+ )
+
+ def test_unmatched_control_2(self):
+ template = """
+
+ % if foo:
+ % for x in range(1,5):
+ % endfor
+"""
+
+ assert_raises_message(
+ exceptions.SyntaxException,
+ "Unterminated control keyword: 'if' at line: 3 char: 1",
+ Lexer(template).parse
+ )
+
+ def test_unmatched_control_3(self):
+ template = """
+
+ % if foo:
+ % for x in range(1,5):
+ % endlala
+ % endif
+"""
+ assert_raises_message(
+ exceptions.SyntaxException,
+ "Keyword 'endlala' doesn't match keyword 'for' at line: 5 char: 1",
+ Lexer(template).parse
+ )
+
+ def test_ternary_control(self):
+ template = \
+ """
+ % if x:
+ hi
+ % elif y+7==10:
+ there
+ % elif lala:
+ lala
+ % else:
+ hi
+ % endif
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [Text(u'\n', (1, 1)),
+ ControlLine(u'if', u'if x:', False, (2, 1)),
+ Text(u' hi\n', (3, 1)),
+ ControlLine(u'elif', u'elif y+7==10:', False, (4,
+ 1)), Text(u' there\n', (5, 1)),
+ ControlLine(u'elif', u'elif lala:', False, (6,
+ 1)), Text(u' lala\n', (7, 1)),
+ 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"/>
+ ## inherit from foobar.html
+<%inherit file="foobar.html"/>
+
+<%def name="header()">
+ <div>header</div>
+</%def>
+<%def name="footer()">
+ <div> footer</div>
+</%def>
+
+<table>
+ % for j in data():
+ <tr>
+ % for x in j:
+ <td>Hello ${x| h}</td>
+ % endfor
+ </tr>
+ % endfor
+</table>
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [NamespaceTag(u'namespace'
+ , {u'file': u'somefile.html', u'name': u'foo'},
+ (1, 1), []), Text(u'\n', (1, 46)),
+ Comment(u'inherit from foobar.html', (2, 1)),
+ InheritTag(u'inherit', {u'file': u'foobar.html'},
+ (3, 1), []), Text(u'''\n\n''', (3, 31)),
+ DefTag(u'def', {u'name': u'header()'}, (5, 1),
+ [Text(u'''\n <div>header</div>\n''', (5,
+ 23))]), Text(u'\n', (7, 8)), DefTag(u'def',
+ {u'name': u'footer()'}, (8, 1),
+ [Text(u'''\n <div> footer</div>\n''', (8,
+ 23))]), Text(u'''\n\n<table>\n''', (10, 8)),
+ ControlLine(u'for', u'for j in data():', False,
+ (13, 1)), Text(u' <tr>\n', (14, 1)),
+ ControlLine(u'for', u'for x in j:', False, (15,
+ 1)), Text(u' <td>Hello ', (16, 1)),
+ Expression(u'x', ['h'], (16, 23)), Text(u'</td>\n'
+ , (16, 30)), ControlLine(u'for', u'endfor', True,
+ (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 = \
+ """
+ % if x: #comment
+ hi
+ % else: #next
+ hi
+ % endif #end
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({}, [Text(u'\n', (1, 1)),
+ ControlLine(u'if', u'if x: #comment', False, (2,
+ 1)), Text(u' hi\n', (3, 1)),
+ ControlLine(u'else', u'else: #next', False, (4,
+ 1)), Text(u' hi\n', (5, 1)),
+ ControlLine(u'if', u'endif #end', True, (6, 1))]))
+
+ def test_crlf(self):
+ template = open(self._file_path("crlf.html"), 'rb').read()
+ nodes = Lexer(template).parse()
+ self._compare(
+ nodes,
+ TemplateNode({}, [
+ Text(u'<html>\r\n\r\n', (1, 1)),
+ PageTag(u'page', {
+ u'args': u"a=['foo',\n 'bar']"
+ }, (3, 1), []),
+ Text(u'\r\n\r\nlike the name says.\r\n\r\n', (4, 26)),
+ ControlLine(u'for', u'for x in [1,2,3]:', False, (8, 1)),
+ Text(u' ', (9, 1)),
+ Expression(u'x', [], (9, 9)),
+ ControlLine(u'for', u'endfor', True, (10, 1)),
+ Text(u'\r\n', (11, 1)),
+ Expression(u"trumpeter == 'Miles' and "
+ "trumpeter or \\\n 'Dizzy'",
+ [], (12, 1)),
+ Text(u'\r\n\r\n', (13, 15)),
+ DefTag(u'def', {u'name': u'hi()'}, (15, 1), [
+ Text(u'\r\n hi!\r\n', (15, 19))]),
+ Text(u'\r\n\r\n</html>\r\n', (17, 8))
+ ])
+ )
+ assert flatten_result(Template(template).render()) \
+ == """<html> like the name says. 1 2 3 Dizzy </html>"""
+
+ def test_comments(self):
+ template = \
+ """
+<style>
+ #someselector
+ # other non comment stuff
+</style>
+## a comment
+
+# also not a comment
+
+ ## this is a comment
+
+this is ## not a comment
+
+<%doc> multiline
+comment
+</%doc>
+
+hi
+"""
+ nodes = Lexer(template).parse()
+ self._compare(nodes, TemplateNode({},
+ [Text(u'''\n<style>\n #someselector\n # '''
+ '''other non comment stuff\n</style>\n''',
+ (1, 1)), Comment(u'a comment', (6, 1)),
+ Text(u'''\n# also not a comment\n\n''', (7, 1)),
+ Comment(u'this is a comment', (10, 1)),
+ Text(u''' \nthis is ## not a comment\n\n''', (11,
+ 1)), Comment(u''' multiline\ncomment\n''', (14,
+ 1)), Text(u'''
+
+hi
+''', (16, 8))]))
+
+ def test_docs(self):
+ template = \
+ """
+ <%doc>
+ this is a comment
+ </%doc>
+ <%def name="foo()">
+ <%doc>
+ this is the foo func
+ </%doc>
+ </%def>
+ """
+ nodes = Lexer(template).parse()
+ self._compare(nodes,
+ TemplateNode({}, [Text(u'\n ', (1,
+ 1)),
+ Comment(u'''\n this is a comment\n ''',
+ (2, 9)), Text(u'\n ', (4, 16)),
+ DefTag(u'def', {u'name': u'foo()'}, (5, 9),
+ [Text(u'\n ', (5, 28)),
+ Comment(u'''\n this is the foo func\n'''
+ ''' ''',
+ (6, 13)), Text(u'\n ', (8, 20))]),
+ Text(u'\n ', (9, 16))]))
+
+ def test_preprocess(self):
+
+ def preproc(text):
+ return re.sub(r'(?<=\n)\s*#[^#]', '##', text)
+
+ template = \
+ """
+ hi
+ # old style comment
+# another comment
+"""
+ nodes = Lexer(template, preprocessor=preproc).parse()
+ self._compare(nodes, TemplateNode({}, [Text(u'''\n hi\n''',
+ (1, 1)), Comment(u'old style comment', (3, 1)),
+ Comment(u'another comment', (4, 1))]))
Added: pypy/benchmarks/lib/mako/test/test_lookup.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_lookup.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,65 @@
+from mako.template import Template
+from mako import lookup, exceptions
+from util import flatten_result, result_lines
+import unittest
+
+from test import TemplateTest, template_base, module_base
+
+tl = lookup.TemplateLookup(directories=[template_base])
+class LookupTest(unittest.TestCase):
+ def test_basic(self):
+ t = tl.get_template('index.html')
+ assert result_lines(t.render()) == [
+ "this is index"
+ ]
+ def test_subdir(self):
+ t = tl.get_template('/subdir/index.html')
+ assert result_lines(t.render()) == [
+ "this is sub index",
+ "this is include 2"
+
+ ]
+
+ 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()) == [
+ "this is sub index",
+ "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:
+ t.render()
+ assert False
+ except exceptions.TemplateLookupException, e:
+ 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') == \
+ '/etc/lala/index.html'
+
+ 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'
+
Added: pypy/benchmarks/lib/mako/test/test_lru.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_lru.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,111 @@
+from mako.util import LRUCache
+import string, unittest, time, random
+
+import thread
+
+class item:
+ def __init__(self, id):
+ self.id = id
+
+ def __str__(self):
+ return "item id %d" % self.id
+
+class LRUTest(unittest.TestCase):
+
+
+ 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(2))
+
+ # next batch over the threshold of 10 should be present
+ for id in range(11,20):
+ self.assert_(l.has_key(id))
+
+ l[12]
+ l[15]
+ l[23] = item(23)
+ l[24] = item(24)
+ l[25] = item(25)
+ l[26] = item(26)
+ l[27] = item(27)
+
+ 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))
+
+ def _disabled_test_threaded(self):
+ size = 100
+ threshold = .5
+ 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():
+ if random.randint(1,4) == 1:
+ return hot_zone[random.randint(0, len(hot_zone) - 1)]
+ else:
+ return random.randint(1, all_elems)
+
+ total = [0]
+ # request thread.
+ def request_elem():
+ while True:
+ total[0] += 1
+ id = get_elem()
+ try:
+ elem = cache[id]
+ elem.regets += 1
+ 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):
+ elem = [e for e in cache.values() if e.id >= start and e.id <= end]
+ if len(elem) == 0:
+ return 0
+ avg = sum([e.regets for e in elem]) / len(elem)
+ return avg
+
+ 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
+
+
+
Added: pypy/benchmarks/lib/mako/test/test_namespace.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_namespace.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,792 @@
+from mako.template import Template
+from mako import lookup
+from util import flatten_result, result_lines
+from test import TemplateTest, eq_
+
+class NamespaceTest(TemplateTest):
+ def test_inline_crossreference(self):
+ self._do_memory_test(
+ """
+ <%namespace name="x">
+ <%def name="a()">
+ this is x a
+ </%def>
+ <%def name="b()">
+ 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",
+ filters=flatten_result
+ )
+
+ def test_inline_assignment(self):
+ self._do_memory_test(
+ """
+ <%namespace name="x">
+ <%def name="a()">
+ <%
+ x = 5
+ %>
+ this is x: ${x}
+ </%def>
+ </%namespace>
+
+ ${x.a()}
+
+ """,
+ "this is x: 5",
+ filters=flatten_result
+ )
+
+ def test_inline_arguments(self):
+ self._do_memory_test(
+ """
+ <%namespace name="x">
+ <%def name="a(x, y)">
+ <%
+ result = x * y
+ %>
+ result: ${result}
+ </%def>
+ </%namespace>
+
+ ${x.a(5, 10)}
+
+ """,
+ "result: 50",
+ filters=flatten_result
+ )
+
+ def test_inline_not_duped(self):
+ self._do_memory_test(
+ """
+ <%namespace name="x">
+ <%def name="a()">
+ foo
+ </%def>
+ </%namespace>
+
+ <%
+ assert x.a is not UNDEFINED, "namespace x.a wasn't defined"
+ assert a is UNDEFINED, "name 'a' is in the body locals"
+ %>
+
+ """,
+ "",
+ filters=flatten_result
+ )
+
+ def test_dynamic(self):
+ collection = lookup.TemplateLookup()
+
+ collection.put_string('a', """
+ <%namespace name="b" file="${context['b_def']}"/>
+
+ a. b: ${b.body()}
+""")
+
+ collection.put_string('b', """
+ b.
+""")
+
+ eq_(
+ 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")}
+""")
+
+ collection.put_string('defs.html', """
+ <%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()
+
+ collection.put_string('main.html', """
+ <%namespace name="comp" module="test.sample_module_namespace"/>
+
+ this is main. ${comp.foo1()}
+ ${comp.foo2("hi")}
+""")
+
+ assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
+
+ def test_module_2(self):
+ collection = lookup.TemplateLookup()
+
+ collection.put_string('main.html', """
+ <%namespace name="comp" module="test.foo.test_ns"/>
+
+ this is main. ${comp.foo1()}
+ ${comp.foo2("hi")}
+""")
+
+ assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
+
+ def test_module_imports(self):
+ collection = lookup.TemplateLookup()
+
+ collection.put_string('main.html', """
+ <%namespace import="*" module="test.foo.test_ns"/>
+
+ this is main. ${foo1()}
+ ${foo2("hi")}
+""")
+
+ assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi"
+
+ def test_module_imports_2(self):
+ collection = lookup.TemplateLookup()
+
+ collection.put_string('main.html', """
+ <%namespace import="foo1, foo2" module="test.foo.test_ns"/>
+
+ this is main. ${foo1()}
+ ${foo2("hi")}
+""")
+
+ 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()
+
+ collection.put_string('main.html', """
+ <%namespace name="comp" file="defs.html"/>
+
+ this is main. ${comp.def1()}
+ ${comp.def2("there")}
+""")
+
+ collection.put_string('defs.html', """
+ <%def name="def1()">
+ def1: x is ${x}
+ </%def>
+
+ <%def name="def2(x)">
+ def2: x is ${x}
+ </%def>
+""")
+
+ 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()
+
+ collection.put_string('main.html', """
+ <%namespace name="comp" file="defs.html">
+ <%def name="def1(x, y)">
+ overridden def1 ${x}, ${y}
+ </%def>
+ </%namespace>
+
+ this is main. ${comp.def1("hi", "there")}
+ ${comp.def2("there")}
+ """)
+
+ collection.put_string('defs.html', """
+ <%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. overridden def1 hi, there def2: there"
+
+ def test_getattr(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("main.html", """
+ <%namespace name="foo" file="ns.html"/>
+ <%
+ if hasattr(foo, 'lala'):
+ foo.lala()
+ if not hasattr(foo, 'hoho'):
+ context.write('foo has no hoho.')
+ %>
+ """)
+ collection.put_string("ns.html", """
+ <%def name="lala()">this is lala.</%def>
+ """)
+ assert flatten_result(collection.get_template("main.html").render()) == "this is lala.foo has no hoho."
+
+ def test_in_def(self):
+ 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
+ </%def>
+ """)
+
+ assert result_lines(collection.get_template("main.html").render()) == [
+ "this is main.",
+ "this is bar, foo is" ,
+ "this is ns.html->bar"
+ ]
+
+
+ def test_in_remote_def(self):
+ 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
+ </%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()) == [
+ "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", """
+
+ <%def name="foo()">
+ <%
+ foo = local.get_namespace("foo.html")
+ %>
+ </%def>
+
+ name: ${self.name}
+ name via bar: ${bar()}
+
+ ${next.body()}
+
+ name: ${self.name}
+ name via bar: ${bar()}
+ <%def name="bar()">
+ ${self.name}
+ </%def>
+
+
+ """)
+
+ collection.put_string("page.html", """
+ <%inherit file="base.html"/>
+
+ ${self.foo()}
+
+ hello world
+
+ """)
+
+ collection.put_string("foo.html", """<%inherit file="base.html"/>""")
+ assert result_lines(collection.get_template("page.html").render()) == [
+ "name: self:page.html",
+ "name via bar:",
+ "self:page.html",
+ "hello world",
+ "name: self:page.html",
+ "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", """
+ <%def name="bar()">
+ this is ns.html->bar
+ </%def>
+ """)
+
+ 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"
+ ]
+
+ def test_inheritance_two(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base.html", """
+ <%def name="foo()">
+ base.foo
+ </%def>
+
+ <%def name="bat()">
+ base.bat
+ </%def>
+""")
+ collection.put_string("lib.html", """
+ <%inherit file="base.html"/>
+ <%def name="bar()">
+ lib.bar
+ ${parent.foo()}
+ ${self.foo()}
+ ${parent.bat()}
+ ${self.bat()}
+ </%def>
+
+ <%def name="foo()">
+ lib.foo
+ </%def>
+
+ """)
+
+ collection.put_string("front.html", """
+ <%namespace name="lib" file="lib.html"/>
+ ${lib.bar()}
+ """)
+
+ assert result_lines(collection.get_template("front.html").render()) == ['lib.bar', 'base.foo', 'lib.foo', 'base.bat', 'base.bat']
+
+ def test_attr(self):
+ l = lookup.TemplateLookup()
+
+ l.put_string("foo.html", """
+ <%!
+ foofoo = "foo foo"
+ onlyfoo = "only foo"
+ %>
+ <%inherit file="base.html"/>
+ <%def name="setup()">
+ <%
+ self.attr.foolala = "foo lala"
+ %>
+ </%def>
+ ${self.attr.basefoo}
+ ${self.attr.foofoo}
+ ${self.attr.onlyfoo}
+ ${self.attr.lala}
+ ${self.attr.foolala}
+ """)
+
+ l.put_string("base.html", """
+ <%!
+ basefoo = "base foo 1"
+ foofoo = "base foo 2"
+ %>
+ <%
+ self.attr.lala = "base lala"
+ %>
+
+ ${self.attr.basefoo}
+ ${self.attr.foofoo}
+ ${self.attr.onlyfoo}
+ ${self.attr.lala}
+ ${self.setup()}
+ ${self.attr.foolala}
+ body
+ ${self.body()}
+ """)
+
+ assert result_lines(l.get_template("foo.html").render()) == [
+ "base foo 1",
+ "foo foo",
+ "only foo",
+ "base lala",
+ "foo lala",
+ "body",
+ "base foo 1",
+ "foo foo",
+ "only foo",
+ "base lala",
+ "foo lala",
+ ]
+
+ def test_attr_raise(self):
+ l = lookup.TemplateLookup()
+
+ l.put_string("foo.html", """
+ <%def name="foo()">
+ </%def>
+ """)
+
+ 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']
+
+ def test_custom_tag_2(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base.html", """
+ <%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", """
+ <%namespace name="foo" file="ns.html" inheritable="True"/>
+
+ ${next.body()}
+ """)
+ collection.put_string("ns.html", """
+ <%def name="bar()">
+ this is ns.html->bar
+ caller body: ${caller.body()}
+ </%def>
+ """)
+
+ collection.put_string("index.html", """
+ <%inherit file="base.html"/>
+
+ this is index
+ <%self.foo:bar>
+ 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()">
+ panel ${caller.body()}
+ </%def>
+
+ <%def name="renderTablePanel()">
+ <%self:renderPanel>
+ 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')
+
+ # the concat has to come out as "x + (g and '1' or '2') + y"
+ assert result_lines(template.render(foo='this is foo', g=False)) == [
+ "this is foo",
+ "x2y"
+ ]
+
+
+ def test_ccall(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base.html", """
+ <%namespace name="foo" file="ns.html" inheritable="True"/>
+
+ ${next.body()}
+ """)
+ collection.put_string("ns.html", """
+ <%def name="bar()">
+ this is ns.html->bar
+ caller body: ${caller.body()}
+ </%def>
+ """)
+
+ collection.put_string("index.html", """
+ <%inherit file="base.html"/>
+
+ this is index
+ <%call expr="self.foo.bar()">
+ call body
+ </%call>
+ """)
+
+ assert result_lines(collection.get_template("index.html").render()) == [
+ "this is index",
+ "this is ns.html->bar",
+ "caller body:",
+ "call body"
+ ]
+
+ def test_ccall_2(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("base.html", """
+ <%namespace name="foo" file="ns1.html" inheritable="True"/>
+
+ ${next.body()}
+ """)
+ collection.put_string("ns1.html", """
+ <%namespace name="foo2" file="ns2.html"/>
+ <%def name="bar()">
+ <%call expr="foo2.ns2_bar()">
+ this is ns1.html->bar
+ caller body: ${caller.body()}
+ </%call>
+ </%def>
+ """)
+
+ collection.put_string("ns2.html", """
+ <%def name="ns2_bar()">
+ this is ns2.html->bar
+ caller body: ${caller.body()}
+ </%def>
+ """)
+
+ collection.put_string("index.html", """
+ <%inherit file="base.html"/>
+
+ this is index
+ <%call expr="self.foo.bar()">
+ call body
+ </%call>
+ """)
+
+ assert result_lines(collection.get_template("index.html").render()) == [
+ "this is index",
+ "this is ns2.html->bar",
+ "caller body:",
+ "this is ns1.html->bar",
+ "caller body:",
+ "call body"
+ ]
+
+ def test_import(self):
+ collection = lookup.TemplateLookup()
+ collection.put_string("functions.html","""
+ <%def name="foo()">
+ this is foo
+ </%def>
+
+ <%def name="bar()">
+ this is bar
+ </%def>
+
+ <%def name="lala()">
+ this is lala
+ </%def>
+ """)
+
+ collection.put_string("func2.html", """
+ <%def name="a()">
+ this is a
+ </%def>
+ <%def name="b()">
+ this is b
+ </%def>
+ """)
+ collection.put_string("index.html", """
+ <%namespace file="functions.html" import="*"/>
+ <%namespace file="func2.html" import="a, b"/>
+ ${foo()}
+ ${bar()}
+ ${lala()}
+ ${a()}
+ ${b()}
+ ${x}
+ """)
+
+ assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [
+ "this is foo",
+ "this is bar",
+ "this is lala",
+ "this is a",
+ "this is b",
+ "this is x"
+ ]
+
+ def test_import_calledfromdef(self):
+ l = lookup.TemplateLookup()
+ l.put_string("a", """
+ <%def name="table()">
+ im table
+ </%def>
+ """)
+
+ l.put_string("b","""
+ <%namespace file="a" import="table"/>
+
+ <%
+ def table2():
+ table()
+ return ""
+ %>
+
+ ${table2()}
+ """)
+
+ 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()}
+ """)
+ assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [
+ "this is foo",
+ "this is bar",
+ ]
+
+ def test_import_local(self):
+ t = Template("""
+ <%namespace import="*">
+ <%def name="foo()">
+ 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()">
+ this is index embedded
+ foo is ${foo()}
+ <%def name="lala()">
+ this is lala ${foo()}
+ </%def>
+ </%call>
+ """)
+ #print collection.get_template("index.html").code
+ #print collection.get_template("functions.html").code
+ assert result_lines(collection.get_template("index.html").render()) == [
+ "this is bar.",
+ "this is index embedded",
+ "foo is",
+ "this is foo",
+ "this is lala",
+ "this is foo"
+ ]
Added: pypy/benchmarks/lib/mako/test/test_pygen.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_pygen.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,252 @@
+import unittest
+
+from mako.pygen import PythonPrinter, adjust_whitespace
+from StringIO import StringIO
+
+class GeneratePythonTest(unittest.TestCase):
+ def test_generate_normal(self):
+ stream = StringIO()
+ printer = PythonPrinter(stream)
+ printer.writeline("import lala")
+ printer.writeline("for x in foo:")
+ printer.writeline("print x")
+ printer.writeline(None)
+ printer.writeline("print y")
+ assert stream.getvalue() == \
+"""import lala
+for x in foo:
+ print x
+print y
+"""
+ def test_generate_adjusted(self):
+ block = """
+ x = 5 +6
+ if x > 7:
+ for y in range(1,5):
+ print "<td>%s</td>" % y
+"""
+ stream = StringIO()
+ printer = PythonPrinter(stream)
+ printer.write_indented_block(block)
+ printer.close()
+ #print stream.getvalue()
+ assert stream.getvalue() == \
+"""
+x = 5 +6
+if x > 7:
+ for y in range(1,5):
+ print "<td>%s</td>" % y
+
+"""
+ def test_generate_combo(self):
+ block = \
+"""
+ x = 5 +6
+ if x > 7:
+ for y in range(1,5):
+ print "<td>%s</td>" % y
+ print "hi"
+ print "there"
+ foo(lala)
+ """
+ stream = StringIO()
+ printer = PythonPrinter(stream)
+ printer.writeline("import lala")
+ printer.writeline("for x in foo:")
+ printer.writeline("print x")
+ printer.write_indented_block(block)
+ printer.writeline(None)
+ printer.writeline("print y")
+ printer.close()
+ #print "->" + stream.getvalue().replace(' ', '#') + "<-"
+ assert stream.getvalue() == \
+"""import lala
+for x in foo:
+ print x
+
+ x = 5 +6
+ if x > 7:
+ for y in range(1,5):
+ print "<td>%s</td>" % y
+ print "hi"
+ print "there"
+ foo(lala)
+
+print y
+"""
+ def test_multi_line(self):
+ block = \
+"""
+ if test:
+ print ''' this is a block of stuff.
+this is more stuff in the block.
+and more block.
+'''
+ do_more_stuff(g)
+"""
+ stream = StringIO()
+ printer = PythonPrinter(stream)
+ printer.write_indented_block(block)
+ printer.close()
+ #print stream.getvalue()
+ assert stream.getvalue() == \
+"""
+if test:
+ print ''' this is a block of stuff.
+this is more stuff in the block.
+and more block.
+'''
+ do_more_stuff(g)
+
+"""
+
+ def test_false_unindentor(self):
+ stream = StringIO()
+ printer = PythonPrinter(stream)
+ for line in [
+ "try:",
+ "elsemyvar = 12",
+ "if True:",
+ "print 'hi'",
+ None,
+ "finally:",
+ "dosomething",
+ None
+ ]:
+ printer.writeline(line)
+
+ assert stream.getvalue() == \
+"""try:
+ elsemyvar = 12
+ if True:
+ print 'hi'
+finally:
+ dosomething
+""" , stream.getvalue()
+
+
+ def test_backslash_line(self):
+ block = \
+"""
+ # comment
+ if test:
+ if (lala + hoho) + \\
+(foobar + blat) == 5:
+ print "hi"
+ print "more indent"
+"""
+ stream = StringIO()
+ printer = PythonPrinter(stream)
+ printer.write_indented_block(block)
+ printer.close()
+ assert stream.getvalue() == \
+"""
+ # comment
+if test:
+ if (lala + hoho) + \\
+(foobar + blat) == 5:
+ print "hi"
+print "more indent"
+
+"""
+
+class WhitespaceTest(unittest.TestCase):
+ def test_basic(self):
+ text = """
+ for x in range(0,15):
+ print x
+ print "hi"
+ """
+ assert adjust_whitespace(text) == \
+"""
+for x in range(0,15):
+ print x
+print "hi"
+"""
+
+ def test_blank_lines(self):
+ text = """
+ print "hi" # a comment
+
+ # more comments
+
+ print g
+"""
+ assert adjust_whitespace(text) == \
+"""
+print "hi" # a comment
+
+# more comments
+
+print g
+"""
+
+ def test_open_quotes_with_pound(self):
+ text = '''
+ print """ this is text
+ # and this is text
+ # and this is too """
+'''
+ assert adjust_whitespace(text) == \
+'''
+print """ this is text
+ # and this is text
+ # and this is too """
+'''
+
+ def test_quote_with_comments(self):
+ text= """
+ print 'hi'
+ # this is a comment
+ # another comment
+ x = 7 # someone's '''comment
+ print '''
+ there
+ '''
+ # someone else's comment
+"""
+
+ assert adjust_whitespace(text) == \
+"""
+print 'hi'
+# this is a comment
+# another comment
+x = 7 # someone's '''comment
+print '''
+ there
+ '''
+# someone else's comment
+"""
+
+
+ def test_quotes_with_pound(self):
+ text = '''
+ if True:
+ """#"""
+ elif False:
+ "bar"
+'''
+ assert adjust_whitespace(text) == \
+'''
+if True:
+ """#"""
+elif False:
+ "bar"
+'''
+
+ def test_quotes(self):
+ text = """
+ print ''' aslkjfnas kjdfn
+askdjfnaskfd fkasnf dknf sadkfjn asdkfjna sdakjn
+asdkfjnads kfajns '''
+ if x:
+ print y
+"""
+ assert adjust_whitespace(text) == \
+"""
+print ''' aslkjfnas kjdfn
+askdjfnaskfd fkasnf dknf sadkfjn asdkfjna sdakjn
+asdkfjnads kfajns '''
+if x:
+ print y
+"""
Added: pypy/benchmarks/lib/mako/test/test_template.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_template.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,936 @@
+# -*- coding: utf-8 -*-
+
+from mako.template import Template, ModuleTemplate
+from mako.lookup import TemplateLookup
+from mako.ext.preprocessors import convert_comments
+from mako import exceptions, util
+import re, os
+from util import flatten_result, result_lines
+import codecs
+from test import TemplateTest, eq_, template_base, module_base, skip_if, assert_raises
+
+class EncodingTest(TemplateTest):
+ def test_unicode(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! »""",
+ 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_encoding_doesnt_conflict(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! »""",
+ 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(
+ "${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! »""",
+ template_args={'val':val}
+ )
+
+ def test_unicode_file(self):
+ self._do_file_test(
+ "unicode.html",
+ 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_file_code(self):
+ self._do_file_test(
+ 'unicode_code.html',
+ u"""hi, drôle de petite voix m’a réveillé.""",
+ filters=flatten_result
+ )
+
+ def test_unicode_file_lookup(self):
+ lookup = TemplateLookup(
+ directories=[template_base],
+ output_encoding='utf-8',
+ default_filters=['decode.utf8'])
+ if util.py3k:
+ template = lookup.get_template('/chs_unicode_py3k.html')
+ else:
+ template = lookup.get_template('/chs_unicode.html')
+ eq_(
+ flatten_result(template.render_unicode(name='毛泽东')),
+ u'毛泽东 是 新中国的主席<br/> Welcome 你 to 北京.'
+ )
+
+ def test_unicode_bom(self):
+ self._do_file_test(
+ 'bom.html',
+ 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_file_test(
+ 'bommagic.html',
+ 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.assertRaises(
+ exceptions.CompileException,
+ Template, filename=self._file_path('badbom.html'),
+ module_directory=module_base
+ )
+
+ def test_unicode_memory(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(
+ ("## -*- 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(
+ ("## -*- 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_ccall(self):
+ val = u"""
+ <%def name="foo()">
+ ${capture(caller.body)}
+ </%def>
+ <%call expr="foo()">
+ <%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>
+ </%call>"""
+ self._do_memory_test(
+ ("## -*- 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! »""",
+ filters=flatten_result
+ )
+
+ def test_unicode_literal_in_expr(self):
+ if util.py3k:
+ self._do_memory_test(
+ u"""## -*- coding: utf-8 -*-
+ ${"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! »"}
+ """.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! »""",
+ filters = lambda s:s.strip()
+ )
+ else:
+ self._do_memory_test(
+ u"""## -*- coding: 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! »"}
+ """.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! »""",
+ filters = lambda s:s.strip()
+ )
+
+ def test_unicode_literal_in_expr_file(self):
+ self._do_file_test(
+ 'unicode_expr.html',
+ 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! »""",
+ lambda t:t.strip()
+ )
+
+ def test_unicode_literal_in_code(self):
+ if util.py3k:
+ self._do_memory_test(
+ u"""## -*- coding: utf-8 -*-
+ <%
+ context.write("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! »")
+ %>
+ """.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! »""",
+ filters=lambda s:s.strip()
+ )
+ else:
+ self._do_memory_test(
+ u"""## -*- coding: utf-8 -*-
+ <%
+ context.write(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! »")
+ %>
+ """.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! »""",
+ filters=lambda s:s.strip()
+ )
+
+ def test_unicode_literal_in_controlline(self):
+ if util.py3k:
+ self._do_memory_test(
+ u"""## -*- coding: utf-8 -*-
+ <%
+ x = "drôle de petite voix m’a réveillé."
+ %>
+ % if x=="drôle de petite voix m’a réveillé.":
+ hi, ${x}
+ % endif
+ """.encode('utf-8'),
+ u"""hi, drôle de petite voix m’a réveillé.""",
+ filters=lambda s:s.strip(),
+ )
+ else:
+ self._do_memory_test(
+ u"""## -*- coding: utf-8 -*-
+ <%
+ x = u"drôle de petite voix m’a réveillé."
+ %>
+ % if x==u"drôle de petite voix m’a réveillé.":
+ hi, ${x}
+ % endif
+ """.encode('utf-8'),
+ 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",
+ [
+ u'x is: drôle de petite voix m’a réveillé',
+ u'x is: drôle de petite voix m’a réveillé',
+ u'x is: drôle de petite voix m’a réveillé',
+ u'x is: drôle de petite voix m’a réveillé',
+ ],
+ filters=result_lines
+ )
+
+ self._do_memory_test(
+ open(self._file_path("unicode_arguments.html"), 'rb').read(),
+ [
+ u'x is: drôle de petite voix m’a réveillé',
+ u'x is: drôle de petite voix m’a réveillé',
+ u'x is: drôle de petite voix m’a réveillé',
+ u'x is: drôle de petite voix m’a réveillé',
+ ],
+ filters=result_lines
+ )
+
+ def test_unicode_literal_in_def(self):
+ if util.py3k:
+ self._do_memory_test(
+ u"""## -*- coding: utf-8 -*-
+ <%def name="bello(foo, bar)">
+ Foo: ${ foo }
+ Bar: ${ bar }
+ </%def>
+ <%call expr="bello(foo='árvíztűrő tükörfúrógép', bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+ </%call>""".encode('utf-8'),
+ 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='árvíztűrő tükörfúrógép', bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+ Foo: ${ foo }
+ Bar: ${ bar }
+ </%def>
+ ${ hello() }""".encode('utf-8'),
+ u"""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""",
+ filters=flatten_result
+ )
+ else:
+ self._do_memory_test(
+ u"""## -*- coding: utf-8 -*-
+ <%def name="bello(foo, bar)">
+ Foo: ${ foo }
+ Bar: ${ bar }
+ </%def>
+ <%call expr="bello(foo=u'árvíztűrő tükörfúrógép', bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">
+ </%call>""".encode('utf-8'),
+ 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')">
+ Foo: ${ foo }
+ Bar: ${ bar }
+ </%def>
+ ${ hello() }""".encode('utf-8'),
+ 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')}",
+ u"hello śląsk",
+ template_args={'f':lambda x:x}
+ )
+ else:
+ self._do_memory_test(
+ u"hello ${f(u'ś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(u'śląsk')}",
+ u"hello śląsk",
+ template_args={'f':lambda x:x}
+ )
+
+ def test_raw_strings(self):
+ """test that raw strings go straight thru with default_filters turned off"""
+
+ self._do_memory_test(
+ u"## -*- coding: utf-8 -*-\nhello ${x}",
+ "hello śląsk",
+ default_filters=[],
+ template_args={'x':'śląsk'},
+ unicode_=False
+ )
+
+ # now, the way you *should* be doing it....
+ self._do_memory_test(
+ u"## -*- coding: utf-8 -*-\nhello ${x}",
+ 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! »""",
+ 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! »""".encode('utf-8'),
+ output_encoding='utf-8',
+ unicode_=False
+ )
+
+ def test_encoding_errors(self):
+ self._do_memory_test(
+ u"""KGB (transliteration of "КГБ") is the Russian-language abbreviation for Committee for State Security, (Russian: Комит́ет Госуд́арственной Безоп́асности (help·info); Komitet Gosudarstvennoy Bezopasnosti)""",
+ u"""KGB (transliteration of "КГБ") is the Russian-language abbreviation for Committee for State Security, (Russian: Комит́ет Госуд́арственной Безоп́асности (help·info); Komitet Gosudarstvennoy Bezopasnosti)""".encode('iso-8859-1', 'replace'),
+ 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')
+ if util.py3k:
+ template = lookup.get_template('/read_unicode_py3k.html')
+ else:
+ template = lookup.get_template('/read_unicode.html')
+ data = template.render(path=self._file_path('internationalization.html'))
+
+ @skip_if(lambda: util.py3k)
+ def test_bytestring_passthru(self):
+ self._do_file_test(
+ 'chs_utf8.html',
+ '毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.',
+ default_filters=[],
+ disable_unicode=True,
+ template_args={'name':'毛泽东'},
+ filters=flatten_result,
+ unicode_=False
+ )
+
+ self._do_file_test(
+ 'chs_utf8.html',
+ '毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.',
+ disable_unicode=True,
+ template_args={'name':'毛泽东'},
+ filters=flatten_result,
+ unicode_=False
+ )
+
+ template = self._file_template('chs_utf8.html', disable_unicode=True)
+ self.assertRaises(UnicodeDecodeError, template.render_unicode, name='毛泽东')
+
+ template = Template("""${'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! »'}""", disable_unicode=True, input_encoding='utf-8')
+ assert template.render() == """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! »"""
+ template = Template("""${'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! »'}""", input_encoding='utf8', output_encoding='utf8', disable_unicode=False, default_filters=[])
+ self.assertRaises(UnicodeDecodeError, template.render) # raises because expression contains an encoded bytestring which cannot be decoded
+
+
+class PageArgsTest(TemplateTest):
+ def test_basic(self):
+ template = Template("""
+ <%page args="x, y, z=7"/>
+
+ this is page, ${x}, ${y}, ${z}
+""")
+
+ assert flatten_result(template.render(x=5, y=10)) == "this is page, 5, 10, 7"
+ assert flatten_result(template.render(x=5, y=10, z=32)) == "this is page, 5, 10, 32"
+ try:
+ template.render(y=10)
+ assert False
+ except TypeError, e:
+ assert True
+
+ def test_inherits(self):
+ lookup = TemplateLookup()
+ lookup.put_string("base.tmpl",
+ """
+ <%page args="bar" />
+ ${bar}
+ ${pageargs['foo']}
+ ${self.body(**pageargs)}
+ """
+ )
+ lookup.put_string("index.tmpl", """
+ <%inherit file="base.tmpl" />
+ <%page args="variable" />
+ ${variable}
+ """)
+
+ self._do_test(
+ lookup.get_template("index.tmpl"),
+ "bar foo var",
+ filters=flatten_result,
+ template_args={'variable':'var', 'bar':'bar', 'foo':'foo'}
+
+ )
+
+ def test_includes(self):
+ lookup = TemplateLookup()
+ lookup.put_string("incl1.tmpl",
+ """
+ <%page args="bar" />
+ ${bar}
+ ${pageargs['foo']}
+ """
+ )
+ lookup.put_string("incl2.tmpl",
+ """
+ ${pageargs}
+ """
+ )
+ lookup.put_string("index.tmpl", """
+ <%include file="incl1.tmpl" args="**pageargs"/>
+ <%page args="variable" />
+ ${variable}
+ <%include file="incl2.tmpl" />
+ """)
+
+ self._do_test(
+ lookup.get_template("index.tmpl"),
+ "bar foo var {}",
+ filters=flatten_result,
+ template_args={'variable':'var', 'bar':'bar', 'foo':'foo'}
+
+ )
+
+ def test_with_context(self):
+ template = Template("""
+ <%page args="x, y, z=7"/>
+
+ this is page, ${x}, ${y}, ${z}, ${w}
+""")
+ #print template.code
+ assert flatten_result(template.render(x=5, y=10, w=17)) == "this is page, 5, 10, 7, 17"
+
+ 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}
+ id: ${id}
+ """)
+ assert flatten_result(template.render(id='some id', Exception='some exception')) == "exception: some exception id: some id"
+
+ def test_builtin_names_dont_clobber_defaults_in_includes(self):
+ lookup = TemplateLookup()
+ lookup.put_string("test.mako",
+ """
+ <%include file="test1.mako"/>
+
+ """)
+
+ lookup.put_string("test1.mako", """
+ <%page args="id='foo'"/>
+
+ ${id}
+ """)
+
+ for template in ("test.mako", "test1.mako"):
+ 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("""
+ <%
+ dict = "this is dict"
+ locals = "this is locals"
+ %>
+ dict: ${dict}
+ locals: ${locals}
+ """)
+ assert flatten_result(template.render()) == "dict: this is dict locals: this is locals"
+
+class IncludeTest(TemplateTest):
+ def test_basic(self):
+ lookup = TemplateLookup()
+ lookup.put_string("a", """
+ this is a
+ <%include file="b" args="a=3,b=4,c=5"/>
+ """)
+ lookup.put_string("b", """
+ <%page args="a,b,c"/>
+ this is b. ${a}, ${b}, ${c}
+ """)
+ assert flatten_result(lookup.get_template("a").render()) == "this is a this is b. 3, 4, 5"
+
+ def test_localargs(self):
+ lookup = TemplateLookup()
+ lookup.put_string("a", """
+ this is a
+ <%include file="b" args="a=a,b=b,c=5"/>
+ """)
+ lookup.put_string("b", """
+ <%page args="a,b,c"/>
+ 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):
+ lookup = TemplateLookup()
+ lookup.put_string("a", """
+ this is a
+ <%include file="b" args="c=5, **context.kwargs"/>
+ """)
+ lookup.put_string("b", """
+ <%page args="a,b,c"/>
+ this is b. ${a}, ${b}, ${c}
+ """)
+ #print lookup.get_template("a").code
+ assert flatten_result(lookup.get_template("a").render(a=7,b=8)) == "this is a this is b. 7, 8, 5"
+
+ def test_include_withargs(self):
+ lookup = TemplateLookup()
+ lookup.put_string("a", """
+ this is a
+ <%include file="${i}" args="c=5, **context.kwargs"/>
+ """)
+ lookup.put_string("b", """
+ <%page args="a,b,c"/>
+ 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""")
+ lookup.put_string("b", """
+ <%def name="bar()">
+ bar: ${caller.body()}
+ <%include file="a"/>
+ </%def>
+ """)
+ lookup.put_string("c", """
+ <%namespace name="b" file="b"/>
+ <%b:bar>
+ calling bar
+ </%b:bar>
+ """)
+ assert flatten_result(lookup.get_template("c").render()) == "bar: calling bar this is a"
+
+class UndefinedVarsTest(TemplateTest):
+ def test_undefined(self):
+ t = Template("""
+ % if x is UNDEFINED:
+ undefined
+ % else:
+ x: ${x}
+ % endif
+ """)
+
+ assert result_lines(t.render(x=12)) == ["x: 12"]
+ assert result_lines(t.render(y=12)) == ["undefined"]
+
+ def test_strict(self):
+ t = Template("""
+ % if x is UNDEFINED:
+ undefined
+ % else:
+ 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", """
+ <%namespace name='a' file='a' import='*'/>
+ % if x is UNDEFINED:
+ undefined
+ % else:
+ x: ${x}
+ % endif
+ """)
+
+ 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", """
+ <%include file="i" args="y=[x for x in range(3)]" />
+ """)
+ 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')}
+ """)
+ eq_(
+ result_lines(l.get_template("q").render()), ['hi, x']
+ )
+
+ t = Template("""
+ <%
+ y = lambda q: str(q)
+ %>
+ ${y('hi')}
+ """, strict_undefined=True)
+ eq_(
+ result_lines(t.render()), ["hi"]
+ )
+
+ def test_list_comprehensions_plus_undeclared_nonstrict(self):
+ # traditional behavior. variable inside a list comprehension
+ # 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
+ %>
+ """)
+ assert_raises(
+ 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("""
+ ## this is a template.
+ % for x in y:
+ % if 'test' in x:
+ yes x has test
+ % else:
+ no x does not have test
+ %endif
+ %endfor
+""")
+ assert result_lines(t.render(y=[{'test':'one'}, {'foo':'bar'}, {'foo':'bar', 'test':'two'}])) == [
+ "yes x has test",
+ "no x does not have test",
+ "yes x has test"
+ ]
+
+ def test_blank_control(self):
+ self._do_memory_test(
+ """
+ % if True:
+ % endif
+ """,
+ "",
+ filters=lambda s:s.strip()
+ )
+
+ def test_multiline_control(self):
+ t = Template("""
+ % for x in \\
+ [y for y in [1,2,3]]:
+ ${x}
+ % endfor
+""")
+ #print t.code
+ assert flatten_result(t.render()) == "1 2 3"
+
+class GlobalsTest(TemplateTest):
+ def test_globals(self):
+ self._do_memory_test(
+ """
+ <%!
+ y = "hi"
+ %>
+ y is ${y}
+ """,
+ "y is hi",
+ filters=lambda t:t.strip()
+ )
+
+class RichTracebackTest(TemplateTest):
+
+ def _do_test_traceback(self, utf8, memory, syntax):
+ if memory:
+ if syntax:
+ source = u'## coding: utf-8\n<% print "m’a réveillé. '\
+ u'Elle disait: « S’il vous plaît… dessine-moi un mouton! » %>'
+ else:
+ source = u'## coding: utf-8\n<% print u"m’a réveillé. '\
+ u'Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + str(5/0) %>'
+ if utf8:
+ source = source.encode('utf-8')
+ else:
+ source = source
+ templateargs = {'text':source}
+ else:
+ if syntax:
+ filename = 'unicode_syntax_error.html'
+ else:
+ filename = 'unicode_runtime_error.html'
+ source = open(self._file_path(filename), 'rb').read()
+ if not utf8:
+ source = source.decode('utf-8')
+ templateargs = {'filename':self._file_path(filename)}
+ try:
+ template = Template(**templateargs)
+ if not syntax:
+ template.render_unicode()
+ assert False
+ except Exception, e:
+ tback = exceptions.RichTraceback()
+ if utf8:
+ assert tback.source == source.decode('utf-8')
+ else:
+ assert tback.source == source
+
+for utf8 in (True, False):
+ for memory in (True, False):
+ for syntax in (True, False):
+ def _do_test(self):
+ self._do_test_traceback(utf8, memory, syntax)
+ name = 'test_%s_%s_%s' % (utf8 and 'utf8' or 'unicode',
+ memory and 'memory' or 'file',
+ syntax and 'syntax' or 'runtime')
+ _do_test.__name__ = name
+ setattr(RichTracebackTest, name, _do_test)
+ del _do_test
+
+class ModuleDirTest(TemplateTest):
+ def test_basic(self):
+ t = self._file_template("modtest.html")
+ t2 = self._file_template('subdir/modtest.html')
+
+ eq_(
+ t.module.__file__,
+ os.path.join(module_base, 'modtest.html.py')
+ )
+ eq_(
+ t2.module.__file__,
+ os.path.join(module_base, 'subdir', 'modtest.html.py')
+ )
+
+ def test_callable(self):
+ def get_modname(filename, uri):
+ return os.path.join(
+ module_base,
+ os.path.dirname(uri)[1:],
+ 'foo',
+ os.path.basename(filename) + ".py")
+
+ lookup = TemplateLookup(template_base, modulename_callable=get_modname)
+ t = lookup.get_template('/modtest.html')
+ t2 = lookup.get_template('/subdir/modtest.html')
+ eq_(
+ t.module.__file__,
+ os.path.join(module_base, 'foo', 'modtest.html.py')
+ )
+ eq_(
+ t2.module.__file__,
+ os.path.join(module_base, 'subdir', 'foo', 'modtest.html.py')
+ )
+
+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
+ try:
+ class NoCompileTemplate(Template):
+ 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")
+
+ t1 = NoCompileTemplate(
+ 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")
+
+ finally:
+ os.path = current_path
+
+ def test_posix_paths(self):
+ """test that posixs filenames are handled appropriately by Template."""
+
+ current_path = os.path
+ import posixpath
+ os.path = posixpath
+ try:
+ class NoCompileTemplate(Template):
+ def _compile_from_file(self, path, filename):
+ self.path = path
+ return Template("foo bar").module
+
+ t1 = NoCompileTemplate(
+ filename="/var/www/htdocs/includes/template.html",
+ module_directory="/var/lib/modules")
+
+ eq_(t1.uri, "/var/www/htdocs/includes/template.html")
+ eq_(t1.path, "/var/lib/modules/var/www/htdocs/includes/template.html.py")
+
+ t1 = NoCompileTemplate(
+ filename="/var/www/htdocs/includes/template.html",
+ uri = "/bar/template.html",
+ module_directory="/var/lib/modules")
+
+ eq_(t1.uri, "/bar/template.html")
+ eq_(t1.path, "/var/lib/modules/bar/template.html.py")
+
+ 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
+""", lookup=lookup)
+
+ base = Template("""
+ This is base.
+ ${self.body()}
+""", 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"
+ ]
+
+ 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
+""", preprocessor=convert_comments)
+
+ assert flatten_result(t.render()) == "im a template - # not a comment - ## not a comment"
Added: pypy/benchmarks/lib/mako/test/test_tgplugin.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/test_tgplugin.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,42 @@
+import unittest
+
+from mako.ext.turbogears import TGPlugin
+from util import flatten_result, result_lines
+from test import TemplateTest, template_base
+
+tl = TGPlugin(options=dict(directories=[template_base]), extension='html')
+
+class TestTGPlugin(TemplateTest):
+ def test_basic(self):
+ t = tl.load_template('/index.html')
+ assert result_lines(t.render()) == [
+ "this is index"
+ ]
+ def test_subdir(self):
+ t = tl.load_template('/subdir/index.html')
+ assert result_lines(t.render()) == [
+ "this is sub index",
+ "this is include 2"
+
+ ]
+
+ assert tl.load_template('/subdir/index.html').module_id == '_subdir_index_html'
+
+ def test_basic_dot(self):
+ t = tl.load_template('index')
+ assert result_lines(t.render()) == [
+ "this is index"
+ ]
+ def test_subdir_dot(self):
+ t = tl.load_template('subdir.index')
+ assert result_lines(t.render()) == [
+ "this is sub index",
+ "this is include 2"
+
+ ]
+
+ 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"
Added: pypy/benchmarks/lib/mako/test/util.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/lib/mako/test/util.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,7 @@
+import re
+
+def flatten_result(result):
+ return re.sub(r'[\s\r\n]+', ' ', result).strip()
+
+def result_lines(result):
+ return [x.strip() for x in re.split(r'\r?\n', re.sub(r' +', ' ', result)) if x.strip() != '']
\ No newline at end of file
Added: pypy/benchmarks/own/bm_mako.py
==============================================================================
--- (empty file)
+++ pypy/benchmarks/own/bm_mako.py Tue Dec 21 07:44:16 2010
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+
+"""
+Benchmark for test the performance of Mako templates engine.
+Includes:
+ -two template inherences
+ -HTML escaping, XML escaping, URL escaping, whitespace trimming
+ -function defitions and calls
+ -forloops
+"""
+
+__author__ = "virhilo at gmail.com (Lukasz Fidosz)"
+
+# Python imports
+import os
+import sys
+import optparse
+import time
+
+# Local imports
+import util
+
+def relative(*args):
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), *args)
+
+sys.path.insert(0, relative('..', 'lib'))
+
+# Mako imports
+from mako.template import Template
+from mako.lookup import TemplateLookup
+
+
+LOREM_IPSUM = """Quisque lobortis hendrerit posuere. Curabitur
+aliquet consequat sapien molestie pretium. Nunc adipiscing luc
+tus mi, viverra porttitor lorem vulputate et. Ut at purus sem,
+sed tincidunt ante. Vestibulum ante ipsum primis in faucibus
+orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar
+sodales justo at congue. Praesent aliquet facilisis nisl a
+molestie. Sed tempus nisl ut augue eleifend tincidunt. Sed a
+lacinia nulla. Cras tortor est, mollis et consequat at,
+vulputate et orci. Nulla sollicitudin"""
+
+BASE_TEMPLATE = """
+<%def name="render_table(table)">
+ <table>
+ % for row in table:
+ <tr>
+ % for col in row:
+ <td>${col|h}</td>
+ % endfor
+ </tr>
+ % endfor
+ </table>
+</%def>
+<%def name="img(src, alt)">
+ <img src="${src|u}" alt="${alt}" />
+</%def>
+<html>
+ <head><title>${title|h,trim}</title></head>
+ <body>
+ ${next.body()}
+ </body>
+<html>
+"""
+
+PAGE_TEMPLATE = """
+<%inherit file="base.mako"/>
+<table>
+ % for row in table:
+ <tr>
+ % for col in row:
+ <td>${col}</td>
+ % endfor
+ </tr>
+ % endfor
+</table>
+% for nr in xrange(img_count):
+ ${parent.img('/foo/bar/baz.png', 'no image :o')}
+% endfor
+${next.body()}
+% for nr in paragraphs:
+ <p>${lorem|x}</p>
+% endfor
+${parent.render_table(table)}
+"""
+
+CONTENT_TEMPLATE = """
+<%inherit file="page.mako"/>
+<%def name="fun1()">
+ <span>fun1</span>
+</%def>
+<%def name="fun2()">
+ <span>fun2</span>
+</%def>
+<%def name="fun3()">
+ <span>foo3</span>
+</%def>
+<%def name="fun4()">
+ <span>foo4</span>
+</%def>
+<%def name="fun5()">
+ <span>foo5</span>
+</%def>
+<%def name="fun6()">
+ <span>foo6</span>
+</%def>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+Nam laoreet justo in velit faucibus lobortis. Sed dictum sagittis
+volutpat. Sed adipiscing vestibulum consequat. Nullam laoreet, ante
+nec pretium varius, libero arcu porttitor orci, id cursus odio nibh
+nec leo. Vestibulum dapibus pellentesque purus, sed bibendum tortor
+laoreet id. Praesent quis sodales ipsum. Fusce ut ligula sed diam
+pretium sagittis vel at ipsum. Nulla sagittis sem quam, et volutpat
+velit. Fusce dapibus ligula quis lectus ultricies tempor. Pellente</p>
+${fun1()}
+${fun2()}
+${fun3()}
+${fun4()}
+${fun5()}
+${fun6()}
+"""
+
+
+def test_mako(count):
+
+ lookup = TemplateLookup()
+ lookup.put_string('base.mako', BASE_TEMPLATE)
+ lookup.put_string('page.mako', PAGE_TEMPLATE)
+
+ template = Template(CONTENT_TEMPLATE, lookup=lookup)
+
+ table = [xrange(150) for i in xrange(150)]
+ paragraphs = xrange(50)
+ title = 'Hello world!'
+
+ times = []
+ for i in range(count):
+ t0 = time.time()
+ data = template.render(table=table, paragraphs=paragraphs,
+ lorem=LOREM_IPSUM, title=title,
+ img_count=50)
+ t1 = time.time()
+ times.append(t1-t0)
+ return times
+
+if __name__ == "__main__":
+ parser = optparse.OptionParser(
+ usage="%prog [options]",
+ description=("Test the performance of Mako templates."))
+ util.add_standard_options_to(parser)
+ (options, args) = parser.parse_args()
+
+ util.run_benchmark(options, options.num_runs, test_mako)
More information about the Pypy-commit
mailing list