From fe823ebd9181077849eb64bc6d2202383bef5e2f Mon Sep 17 00:00:00 2001
From: Mike Bayer <mike_mp@zzzcomputing.com>
Date: Sat, 13 Nov 2010 15:07:22 -0500
Subject: [PATCH] - 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]

---
 doc/build/caching.rst    |   6 ++
 doc/build/namespaces.rst |  42 ----------
 mako/cache.py            |  55 +++++++++++++
 mako/lookup.py           |  91 ++++++++++++----------
 mako/parsetree.py        |  76 ++++++++++--------
 mako/runtime.py          | 161 ++++++++++++++++++++++++++++++++-------
 mako/template.py         |  99 +++++++++++++-----------
 mako/util.py             |  12 ++-
 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:
-- 
GitLab