summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-11-13 15:07:22 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2010-11-13 15:07:22 -0500
commitfe823ebd9181077849eb64bc6d2202383bef5e2f (patch)
treec899112107a283d33225f8b9e71d5c9517c051b0
parent7a8dfc0b533f80aa055f843f9bb408484045925d (diff)
downloadmako-fe823ebd9181077849eb64bc6d2202383bef5e2f.tar.gz
- more cleanup
- move Namespace docs inline to attributes on Namespace - document Cache methods, add to caching.rst - use functools.partial for partials, part of [ticket:156]
-rw-r--r--doc/build/caching.rst6
-rw-r--r--doc/build/namespaces.rst42
-rw-r--r--mako/cache.py55
-rw-r--r--mako/lookup.py91
-rw-r--r--mako/parsetree.py76
-rw-r--r--mako/runtime.py161
-rw-r--r--mako/template.py99
-rw-r--r--mako/util.py12
8 files changed, 355 insertions, 187 deletions
diff --git a/doc/build/caching.rst b/doc/build/caching.rst
index 3ad35ff..0620d32 100644
--- a/doc/build/caching.rst
+++ b/doc/build/caching.rst
@@ -119,3 +119,9 @@ sections programmatically:
# invalidate an arbitrary key
template.cache.invalidate('somekey')
+API Reference
+==============
+
+.. autoclass:: mako.cache.Cache
+ :members:
+ :show-inheritance: \ No newline at end of file
diff --git a/doc/build/namespaces.rst b/doc/build/namespaces.rst
index 5939020..0da3488 100644
--- a/doc/build/namespaces.rst
+++ b/doc/build/namespaces.rst
@@ -334,48 +334,6 @@ API Reference
.. autoclass:: mako.runtime.Namespace
:show-inheritance:
:members:
-
- .. py:attribute:: attr
-
- allows 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`.
-
- .. py:attribute:: module
-
- 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.
-
- .. py:attribute:: filename
-
- 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.
-
- .. py:attribute:: template
-
- the :class:`.Template` object referenced by this
- :class:`.Namespace`, if any.
-
- .. py:attribute:: uri
-
- 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`.
-
- .. py:attribute:: context
-
- 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.
.. autofunction:: mako.runtime.supports_caller
diff --git a/mako/cache.py b/mako/cache.py
index 595b05f..ffee5ea 100644
--- a/mako/cache.py
+++ b/mako/cache.py
@@ -7,12 +7,33 @@ class BeakerMissing(object):
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)
@@ -20,6 +41,16 @@ class Cache(object):
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)
@@ -27,6 +58,15 @@ class Cache(object):
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)
@@ -34,12 +74,27 @@ class Cache(object):
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):
diff --git a/mako/lookup.py b/mako/lookup.py
index 15848d8..c1fd391 100644
--- a/mako/lookup.py
+++ b/mako/lookup.py
@@ -31,8 +31,9 @@ class TemplateCollection(object):
"""
def has_template(self, uri):
- """Return ``True`` if this :class:`.TemplateLookup` is capable of
- returning a :class:`.Template` object for the given URL.
+ """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.
@@ -47,13 +48,14 @@ class TemplateCollection(object):
"""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.
+ 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.
+ :param relativeto: if present, the given URI is assumed to
+ be relative to this uri.
"""
raise NotImplementedError()
@@ -67,11 +69,13 @@ class TemplateCollection(object):
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.
+ 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
@@ -100,33 +104,40 @@ class TemplateLookup(TemplateCollection):
''')
- :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 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 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 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.
+ :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`.
+ 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`.
"""
@@ -289,8 +300,9 @@ class TemplateLookup(TemplateCollection):
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.
+ """Place a new :class:`.Template` object into this
+ :class:`.TemplateLookup`, based on the given string of
+ text.
"""
self._collection[uri] = Template(
@@ -300,8 +312,9 @@ class TemplateLookup(TemplateCollection):
**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.
+ """Place a new :class:`.Template` object into this
+ :class:`.TemplateLookup`, based on the given
+ :class:`.Template` object.
"""
self._collection[uri] = template
diff --git a/mako/parsetree.py b/mako/parsetree.py
index 554531e..68816f8 100644
--- a/mako/parsetree.py
+++ b/mako/parsetree.py
@@ -16,10 +16,11 @@ class Node(object):
self.lineno = lineno
self.pos = pos
self.filename = filename
-
+
+ @property
def exception_kwargs(self):
- return {'source':self.source, 'lineno':self.lineno, 'pos':self.pos, 'filename':self.filename}
- exception_kwargs = property(exception_kwargs)
+ return {'source':self.source, 'lineno':self.lineno,
+ 'pos':self.pos, 'filename':self.filename}
def get_children(self):
return []
@@ -43,7 +44,9 @@ class TemplateNode(Node):
return self.nodes
def __repr__(self):
- return "TemplateNode(%s, %r)" % (util.sorted_dict_repr(self.page_attributes), self.nodes)
+ 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.
@@ -77,7 +80,8 @@ class ControlLine(Node):
return self._undeclared_identifiers
def is_ternary(self, keyword):
- """return true if the given keyword is a ternary keyword for this ControlLine"""
+ """return true if the given keyword is a ternary keyword
+ for this ControlLine"""
return keyword in {
'if':set(['else', 'elif']),
@@ -186,7 +190,8 @@ class Expression(Node):
)
class _TagMeta(type):
- """metaclass to allow Tag to produce a subclass according to its keyword"""
+ """metaclass to allow Tag to produce a subclass according to
+ its keyword"""
_classmap = {}
@@ -198,7 +203,8 @@ class _TagMeta(type):
def __call__(cls, keyword, attributes, **kwargs):
if ":" in keyword:
ns, defname = keyword.split(':')
- return type.__call__(CallNamespaceTag, ns, defname, attributes, **kwargs)
+ return type.__call__(CallNamespaceTag, ns, defname,
+ attributes, **kwargs)
try:
cls = _TagMeta._classmap[keyword]
@@ -226,22 +232,25 @@ class Tag(Node):
__metaclass__ = _TagMeta
__keyword__ = None
- def __init__(self, keyword, attributes, expressions, nonexpressions, required, **kwargs):
+ 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.
+ this constructor not called directly, and is only called
+ by subclasses.
- keyword - the tag keyword
+ :param keyword: the tag keyword
- attributes - raw dictionary of attribute key/value pairs
+ :param attributes: raw dictionary of attribute key/value pairs
- expressions - a set of identifiers that are legal attributes,
- which can also contain embedded expressions
+ :param expressions: a set of identifiers that are legal attributes,
+ which can also contain embedded expressions
- nonexpressions - a set of identifiers that are legal attributes,
- which cannot contain embedded expressions
+ :param nonexpressions: a set of identifiers that are legal
+ attributes, which cannot contain embedded expressions
- \**kwargs - other arguments passed to the Node superclass (lineno, pos)
+ :param \**kwargs:
+ other arguments passed to the Node superclass (lineno, pos)
"""
super(Tag, self).__init__(**kwargs)
@@ -251,7 +260,8 @@ class Tag(Node):
missing = [r for r in required if r not in self.parsed_attributes]
if len(missing):
raise exceptions.CompileException(
- "Missing attribute(s): %s" % ",".join([repr(m) for m in missing]),
+ "Missing attribute(s): %s" %
+ ",".join([repr(m) for m in missing]),
**self.exception_kwargs)
self.parent = None
self.nodes = []
@@ -275,9 +285,9 @@ class Tag(Node):
code = ast.PythonCode(m.group(1).rstrip(),
**self.exception_kwargs)
# we aren't discarding "declared_identifiers" here,
- # which we do so that list comprehension-declared variables
- # aren't counted. As yet can't find a condition that
- # requires it 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)
@@ -308,11 +318,11 @@ class Tag(Node):
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
- )
+ self.keyword,
+ util.sorted_dict_repr(self.attributes),
+ (self.lineno, self.pos),
+ self.nodes
+ )
class IncludeTag(Tag):
__keyword__ = 'include'
@@ -334,7 +344,8 @@ class IncludeTag(Tag):
identifiers = self.page_args.undeclared_identifiers.\
difference(set(["__DUMMY"])).\
difference(self.page_args.declared_identifiers)
- return identifiers.union(super(IncludeTag, self).undeclared_identifiers())
+ return identifiers.union(super(IncludeTag, self).
+ undeclared_identifiers())
class NamespaceTag(Tag):
__keyword__ = 'namespace'
@@ -350,8 +361,8 @@ class NamespaceTag(Tag):
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>",
+ "'name' and/or 'import' attributes are required "
+ "for <%namespace>",
**self.exception_kwargs)
def declared_identifiers(self):
@@ -386,7 +397,8 @@ class DefTag(Tag):
raise exceptions.CompileException(
"Missing parenthesis in %def",
**self.exception_kwargs)
- self.function_decl = ast.FunctionDecl("def " + name + ":pass", **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(
@@ -414,7 +426,8 @@ class CallTag(Tag):
('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)
+ 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)
@@ -474,7 +487,8 @@ class PageTag(Tag):
(),
(),
**kwargs)
- self.body_decl = ast.FunctionArgs(attributes.get('args', ''), **self.exception_kwargs)
+ self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
+ **self.exception_kwargs)
self.filter_args = ast.ArgumentList(
attributes.get('expression_filter', ''),
**self.exception_kwargs)
diff --git a/mako/runtime.py b/mako/runtime.py
index 0be67fc..e596b4f 100644
--- a/mako/runtime.py
+++ b/mako/runtime.py
@@ -27,7 +27,7 @@ class Context(object):
self.namespaces = {}
# "capture" function which proxies to the generic "capture" function
- self._data['capture'] = lambda x, *args, **kwargs: capture(self, x, *args, **kwargs)
+ self._data['capture'] = util.partial(capture, self)
# "caller" stack used by def calls with content
self.caller_stack = self._data['caller'] = CallerStack()
@@ -185,6 +185,14 @@ 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,
@@ -213,14 +221,49 @@ class Namespace(object):
else:
self.callables = None
if populate_self and self.template is not None:
- (lclcallable, lclcontext) = _populate_self_namespace(context, self.template, self_ns=self)
+ 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:
@@ -228,10 +271,25 @@ class Namespace(object):
@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
@@ -260,14 +318,33 @@ class Namespace(object):
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)
+ 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)
@@ -286,10 +363,15 @@ class Namespace(object):
@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 a file at the given uri"""
+
_include_file(self.context, uri, self._templateuri, **kwargs)
def _populate(self, d, l):
@@ -307,13 +389,13 @@ class Namespace(object):
if self.template:
def get(key):
callable_ = self.template._get_def_callable(key)
- return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
+ 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 lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
+ return util.partial(callable_, self.context)
for k in dir(self._module):
if k[0] != '_':
yield (k, get(k))
@@ -324,18 +406,21 @@ class Namespace(object):
if self.template and self.template.has_def(key):
callable_ = self.template._get_def_callable(key)
- return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
+ return util.partial(callable_, self.context)
if self._module and hasattr(self._module, key):
callable_ = getattr(self._module, key)
- return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
+ 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))
+ 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.
+ """Apply a caller_stack compatibility decorator to a plain
+ Python function.
See the example in :ref:`namespaces_python_modules`.
@@ -350,7 +435,8 @@ def supports_caller(func):
return wrap_stackframe
def capture(context, callable_, *args, **kwargs):
- """Execute the given template def, capturing the output into a buffer.
+ """Execute the given template def, capturing the output into
+ a buffer.
See the example in :ref:`namespaces_python_modules`.
@@ -358,9 +444,9 @@ def capture(context, callable_, *args, **kwargs):
if not callable(callable_):
raise exceptions.RuntimeException(
- "capture() function expects a callable as "
- "its argument (i.e. capture(func, *args, **kwargs))"
- )
+ "capture() function expects a callable as "
+ "its argument (i.e. capture(func, *args, **kwargs))"
+ )
context._push_buffer()
try:
callable_(*args, **kwargs)
@@ -391,15 +477,20 @@ def _decorate_inline(context, fn):
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."""
+ """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) = _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."""
+ """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)
@@ -408,7 +499,10 @@ def _inherit_from(context, uri, calling_uri):
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)
+ 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:
@@ -424,7 +518,9 @@ def _inherit_from(context, uri, calling_uri):
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)
+ 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)
@@ -433,7 +529,9 @@ def _lookup_template(context, uri, relativeto):
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)
+ 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)
@@ -442,7 +540,8 @@ def _populate_self_namespace(context, template, self_ns=None):
return (template.callable_, context)
def _render(template, callable_, args, data, as_unicode=False):
- """create a Context and return the string output of the given template and template callable."""
+ """create a Context and return the string
+ output of the given template and template callable."""
if as_unicode:
buf = util.FastEncodingBuffer(unicode=True)
@@ -457,7 +556,8 @@ def _render(template, callable_, args, data, as_unicode=False):
context._outputting_as_unicode = as_unicode
context._with_template = template
- _render_context(template, callable_, context, *args, **_kwargs_for_callable(callable_, data))
+ _render_context(template, callable_, context, *args,
+ **_kwargs_for_callable(callable_, data))
return context._pop_buffer().getvalue()
def _kwargs_for_callable(callable_, data):
@@ -484,7 +584,8 @@ def _kwargs_for_include(callable_, data, **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
+ # 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)
@@ -495,13 +596,16 @@ def _render_context(tmpl, callable_, context, *args, **kwargs):
_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
+ """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.
+ 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):
+ if template is not None and \
+ (template.format_exceptions or template.error_handler):
error = None
try:
callable_(context, *args, **kwargs)
@@ -513,7 +617,6 @@ def _exec_template(callable_, context, args=None, kwargs=None):
else:
callable_(context, *args, **kwargs)
-
def _render_error(template, context, error):
if template.error_handler:
result = template.error_handler(context, error)
diff --git a/mako/template.py b/mako/template.py
index 0e286f9..bc1f40b 100644
--- a/mako/template.py
+++ b/mako/template.py
@@ -26,8 +26,8 @@ class Template(object):
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 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.
@@ -62,11 +62,12 @@ class Template(object):
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.
+ 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
@@ -75,42 +76,48 @@ class Template(object):
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`.
+ "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.
+ 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`.
+ 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_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 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 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 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.
+ :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.
"""
@@ -264,12 +271,13 @@ class Template(object):
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.
+ 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)
@@ -371,7 +379,8 @@ class ModuleTemplate(Template):
self.cache_enabled = cache_enabled
class DefTemplate(Template):
- """a Template which represents a callable def in a parent template."""
+ """a Template which represents a callable def in a parent
+ template."""
def __init__(self, parent, callable_):
self.parent = parent
@@ -387,11 +396,11 @@ class DefTemplate(Template):
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.
+ """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,
diff --git a/mako/util.py b/mako/util.py
index 19afc0d..4c741b7 100644
--- a/mako/util.py
+++ b/mako/util.py
@@ -43,7 +43,17 @@ def function_named(fn, name):
"""
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: