diff --git a/doc/build/caching.rst b/doc/build/caching.rst index 3ad35fff5059cce945d7f280a68eae7027af4fb5..0620d32fbec6d91b6c5d36bb4138e04de15ecab1 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 593902032efb1603fee516c7460f98b641322b19..0da3488e9ced543f30460e7254ab2d972067f7d8 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 595b05f21222678f12ee797d3ecb02510145959c..ffee5ea3b666b658df6005de06fb3009edf928dd 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 15848d8f10adad475bbe5490e2c47846cfb1cb0d..c1fd391a26e1688bdd2bd8e7f4bae4e6b2d26364 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 554531e2bd4061a09d3ba515edaa4e2cbbfd6e7d..68816f89a68a03ec73f9a14ebc9b3dbfe6297796 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 0be67fc124514134703ed23c7511b47b0bdb66f8..e596b4f85e04da39d0ccead787f06bde2bfe8a2e 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 0e286f9ae1467cb7560386c7199aa95d56011335..bc1f40b01d8b3eb97b138962fd62e762b3f88b3b 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 19afc0d66be3239c7be686fbc43c606bfc421e66..4c741b7579770cb408aa8bf17ab17a214be233da 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: