Updated mako libs to 0.7.2

This commit is contained in:
rembo10
2012-07-28 23:52:24 +05:30
parent 69f51241cc
commit 2141ab45b7
21 changed files with 2188 additions and 1387 deletions
+273 -167
View File
@@ -1,5 +1,5 @@
# mako/runtime.py
# Copyright (C) 2006-2011 the Mako authors and contributors <see AUTHORS file>
# Copyright (C) 2006-2012 the Mako authors and contributors <see AUTHORS file>
#
# This module is part of Mako and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -10,65 +10,75 @@ Namespace, and various helper functions."""
from mako import exceptions, util
import __builtin__, inspect, sys
class Context(object):
"""Provides runtime namespace, output buffer, and various
callstacks for templates.
See :ref:`runtime_toplevel` for detail on the usage of
See :ref:`runtime_toplevel` for detail on the usage of
:class:`.Context`.
"""
def __init__(self, buffer, **data):
self._buffer_stack = [buffer]
self._data = data
self._kwargs = data.copy()
self._with_template = None
self._outputting_as_unicode = None
self.namespaces = {}
# "capture" function which proxies to the
# "capture" function which proxies to the
# generic "capture" function
self._data['capture'] = util.partial(capture, self)
# "caller" stack used by def calls with content
self.caller_stack = self._data['caller'] = CallerStack()
def _set_with_template(self, t):
self._with_template = t
illegal_names = t.reserved_names.intersection(self._data)
if illegal_names:
raise exceptions.NameConflictError(
"Reserved words passed to render(): %s" %
", ".join(illegal_names))
@property
def lookup(self):
"""Return the :class:`.TemplateLookup` associated
"""Return the :class:`.TemplateLookup` associated
with this :class:`.Context`.
"""
return self._with_template.lookup
@property
def kwargs(self):
"""Return the dictionary of keyword argments associated with this
"""Return the dictionary of keyword arguments associated with this
:class:`.Context`.
"""
return self._kwargs.copy()
def push_caller(self, caller):
"""Pushes a 'caller' callable onto the callstack for
"""Push a ``caller`` callable onto the callstack for
this :class:`.Context`."""
self.caller_stack.append(caller)
def pop_caller(self):
"""Pops a 'caller' callable onto the callstack for this
"""Pop a ``caller`` callable onto the callstack for this
:class:`.Context`."""
del self.caller_stack[-1]
def keys(self):
"""Return a list of all names established in this :class:`.Context`."""
return self._data.keys()
def __getitem__(self, key):
if key in self._data:
return self._data[key]
@@ -78,45 +88,45 @@ class Context(object):
def _push_writer(self):
"""push a capturing buffer onto this Context and return
the new writer function."""
buf = util.FastEncodingBuffer()
self._buffer_stack.append(buf)
return buf.write
def _pop_buffer_and_writer(self):
"""pop the most recent capturing buffer from this Context
"""pop the most recent capturing buffer from this Context
and return the current writer after the pop.
"""
buf = self._buffer_stack.pop()
return buf, self._buffer_stack[-1].write
def _push_buffer(self):
"""push a capturing buffer onto this Context."""
self._push_writer()
def _pop_buffer(self):
"""pop the most recent capturing buffer from this Context."""
return self._buffer_stack.pop()
def get(self, key, default=None):
"""Return a value from this :class:`.Context`."""
return self._data.get(key,
return self._data.get(key,
__builtin__.__dict__.get(key, default)
)
def write(self, string):
"""Write a string to this :class:`.Context` object's
underlying output buffer."""
self._buffer_stack[-1].write(string)
def writer(self):
"""Return the current writer function"""
"""Return the current writer function."""
return self._buffer_stack[-1].write
@@ -130,17 +140,17 @@ class Context(object):
c.namespaces = self.namespaces
c.caller_stack = self.caller_stack
return c
def locals_(self, d):
"""create a new :class:`.Context` with a copy of this
:class:`Context`'s current state, updated with the given dictionary."""
"""Create a new :class:`.Context` with a copy of this
:class:`.Context`'s current state, updated with the given dictionary."""
if len(d) == 0:
return self
c = self._copy()
c._data.update(d)
return c
def _clean_inheritance_tokens(self):
"""create a new copy of this :class:`.Context`. with
tokens related to inheritance state removed."""
@@ -158,23 +168,27 @@ class CallerStack(list):
def __nonzero__(self):
return self._get_caller() and True or False
def _get_caller(self):
# this method can be removed once
# codegen MAGIC_NUMBER moves past 7
return self[-1]
def __getattr__(self, key):
return getattr(self._get_caller(), key)
def _push_frame(self):
self.append(self.nextcaller or None)
frame = self.nextcaller or None
self.append(frame)
self.nextcaller = None
return frame
def _pop_frame(self):
self.nextcaller = self.pop()
class Undefined(object):
"""Represents an undefined value in a template.
All template modules have a constant value
All template modules have a constant value
``UNDEFINED`` present which is an instance of this
object.
"""
def __str__(self):
raise NameError("Undefined")
@@ -183,6 +197,110 @@ class Undefined(object):
UNDEFINED = Undefined()
class LoopStack(object):
"""a stack for LoopContexts that implements the context manager protocol
to automatically pop off the top of the stack on context exit
"""
def __init__(self):
self.stack = []
def _enter(self, iterable):
self._push(iterable)
return self._top
def _exit(self):
self._pop()
return self._top
@property
def _top(self):
if self.stack:
return self.stack[-1]
else:
return self
def _pop(self):
return self.stack.pop()
def _push(self, iterable):
new = LoopContext(iterable)
if self.stack:
new.parent = self.stack[-1]
return self.stack.append(new)
def __getattr__(self, key):
raise exceptions.RuntimeException("No loop context is established")
def __iter__(self):
return iter(self._top)
class LoopContext(object):
"""A magic loop variable.
Automatically accessible in any ``% for`` block.
See the section :ref:`loop_context` for usage
notes.
:attr:`parent` -> :class:`.LoopContext` or ``None``
The parent loop, if one exists.
:attr:`index` -> `int`
The 0-based iteration count.
:attr:`reverse_index` -> `int`
The number of iterations remaining.
:attr:`first` -> `bool`
``True`` on the first iteration, ``False`` otherwise.
:attr:`last` -> `bool`
``True`` on the last iteration, ``False`` otherwise.
:attr:`even` -> `bool`
``True`` when ``index`` is even.
:attr:`odd` -> `bool`
``True`` when ``index`` is odd.
"""
def __init__(self, iterable):
self._iterable = iterable
self.index = 0
self.parent = None
def __iter__(self):
for i in self._iterable:
yield i
self.index += 1
@util.memoized_instancemethod
def __len__(self):
return len(self._iterable)
@property
def reverse_index(self):
return len(self) - self.index - 1
@property
def first(self):
return self.index == 0
@property
def last(self):
return self.index == len(self) - 1
@property
def even(self):
return not self.odd
@property
def odd(self):
return bool(self.index % 2)
def cycle(self, *values):
"""Cycle through values as the loop progresses.
"""
if not values:
raise ValueError("You must provide values to cycle through")
return values[self.index % len(values)]
class _NSAttr(object):
def __init__(self, parent):
self.__parent = parent
@@ -193,24 +311,26 @@ class _NSAttr(object):
return getattr(ns.module, key)
else:
ns = ns.inherits
raise AttributeError(key)
raise AttributeError(key)
class Namespace(object):
"""Provides access to collections of rendering methods, which
"""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::
To access a particular rendering method referenced by a
:class:`.Namespace`, use plain attribute access:
.. sourcecode:: mako
${some_namespace.foo(x, y, z)}
:class:`.Namespace` also contains several built-in attributes
:class:`.Namespace` also contains several built-in attributes
described here.
"""
def __init__(self, name, context,
callables=None, inherits=None,
def __init__(self, name, context,
callables=None, inherits=None,
populate_self=True, calling_uri=None):
self.name = name
self.context = context
@@ -221,7 +341,7 @@ class Namespace(object):
callables = ()
module = None
"""The Python module referenced by this Namespace.
"""The Python module referenced by this :class:`.Namespace`.
If the namespace references a :class:`.Template`, then
this module is the equivalent of ``template.module``,
@@ -236,8 +356,8 @@ class Namespace(object):
"""
context = None
"""The :class:`.Context` object for this namespace.
"""The :class:`.Context` object for this :class:`.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
@@ -245,24 +365,24 @@ class Namespace(object):
one-another.
"""
filename = None
"""The path of the filesystem file used for this
Namespace's module or template.
:class:`.Namespace`'s module or template.
If this is a pure module-based
Namespace, this evaluates to ``module.__file__``. If a
:class:`.Namespace`, this evaluates to ``module.__file__``. If a
template-based namespace, it evaluates to the original
template file location.
"""
uri = None
"""The uri for this Namespace's template.
"""The URI for this :class:`.Namespace`'s template.
I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
This is the equivalent of :attr:`Template.uri`.
This is the equivalent of :attr:`.Template.uri`.
"""
@@ -270,8 +390,8 @@ class Namespace(object):
@util.memoized_property
def attr(self):
"""Access module level attributes by name.
"""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
@@ -281,86 +401,72 @@ class Namespace(object):
return _NSAttr(self)
def get_namespace(self, uri):
"""Return a :class:`.Namespace` corresponding to the given uri.
If the given uri is a relative uri (i.e. it does not
contain ia leading slash ``/``), the uri is adjusted to
be relative to the uri of the namespace itself. This
"""Return a :class:`.Namespace` corresponding to the given ``uri``.
If the given ``uri`` is a relative URI (i.e. it does not
contain a leading slash ``/``), the ``uri`` is adjusted to
be relative to the ``uri`` of the namespace itself. This
method is therefore mostly useful off of the built-in
``local`` namespace, described in :ref:`namespace_local`
``local`` namespace, described in :ref:`namespace_local`.
In
most cases, a template wouldn't need this function, and
should instead use the ``<%namespace>`` tag to load
namespaces. However, since all ``<%namespace>`` tags are
evaulated before the body of a template ever runs,
evaluated before the body of a template ever runs,
this method can be used to locate namespaces using
expressions that were generated within the body code of
the template, or to conditionally use a particular
namespace.
"""
key = (self, uri)
if key in self.context.namespaces:
return self.context.namespaces[key]
else:
ns = TemplateNamespace(uri, self.context._copy(),
templateuri=uri,
calling_uri=self._templateuri)
ns = TemplateNamespace(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`
"""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
"""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
The advantage to this method versus direct access to the
:class:`.Cache` is that the configuration parameters
declared in ``<%page>`` take effect here, thereby calling
up the same configured backend as that configured
by ``<%page>``.
"""
if self.template:
if not self.template.cache_enabled:
createfunc = kwargs.get('createfunc', None)
if createfunc:
return createfunc()
else:
return None
if self.template.cache_dir:
kwargs.setdefault('data_dir', self.template.cache_dir)
if self.template.cache_type:
kwargs.setdefault('type', self.template.cache_type)
if self.template.cache_url:
kwargs.setdefault('url', self.template.cache_url)
return self.cache.get(key, **kwargs)
@property
def cache(self):
"""Return the :class:`.Cache` object referenced
by this :class:`.Namespace` object's
"""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):
for ident in l:
if ident == '*':
@@ -368,7 +474,7 @@ class Namespace(object):
d[k] = v
else:
d[ident] = getattr(self, ident)
def _get_star(self):
if self.callables:
for key in self.callables:
@@ -381,7 +487,7 @@ class Namespace(object):
val = getattr(self.inherits, key)
else:
raise AttributeError(
"Namespace '%s' has no member '%s'" %
"Namespace '%s' has no member '%s'" %
(self.name, key))
setattr(self, key, val)
return val
@@ -389,8 +495,8 @@ class Namespace(object):
class TemplateNamespace(Namespace):
"""A :class:`.Namespace` specific to a :class:`.Template` instance."""
def __init__(self, name, context, template=None, templateuri=None,
callables=None, inherits=None,
def __init__(self, name, context, template=None, templateuri=None,
callables=None, inherits=None,
populate_self=True, calling_uri=None):
self.name = name
self.context = context
@@ -399,7 +505,7 @@ class TemplateNamespace(Namespace):
self.callables = dict([(c.func_name, c) for c in callables])
if templateuri is not None:
self.template = _lookup_template(context, templateuri,
self.template = _lookup_template(context, templateuri,
calling_uri)
self._templateuri = self.template.module._template_uri
elif template is not None:
@@ -410,13 +516,13 @@ class TemplateNamespace(Namespace):
if populate_self:
lclcallable, lclcontext = \
_populate_self_namespace(context, self.template,
_populate_self_namespace(context, self.template,
self_ns=self)
@property
def module(self):
"""The Python module referenced by this Namespace.
"""The Python module referenced by this :class:`.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.
@@ -427,17 +533,17 @@ class TemplateNamespace(Namespace):
@property
def filename(self):
"""The path of the filesystem file used for this
Namespace's module or template.
:class:`.Namespace`'s module or template.
"""
return self.template.filename
@property
def uri(self):
"""The uri for this Namespace's template.
"""The URI for this :class:`.Namespace`'s template.
I.e. whatever was sent to :meth:`.TemplateLookup.get_template()`.
This is the equivalent of :attr:`Template.uri`.
This is the equivalent of :attr:`.Template.uri`.
"""
return self.template.uri
@@ -463,7 +569,7 @@ class TemplateNamespace(Namespace):
else:
raise AttributeError(
"Namespace '%s' has no member '%s'" %
"Namespace '%s' has no member '%s'" %
(self.name, key))
setattr(self, key, val)
return val
@@ -471,8 +577,8 @@ class TemplateNamespace(Namespace):
class ModuleNamespace(Namespace):
"""A :class:`.Namespace` specific to a Python module instance."""
def __init__(self, name, context, module,
callables=None, inherits=None,
def __init__(self, name, context, module,
callables=None, inherits=None,
populate_self=True, calling_uri=None):
self.name = name
self.context = context
@@ -488,7 +594,7 @@ class ModuleNamespace(Namespace):
@property
def filename(self):
"""The path of the filesystem file used for this
Namespace's module or template.
:class:`.Namespace`'s module or template.
"""
return self.module.__file__
@@ -513,7 +619,7 @@ class ModuleNamespace(Namespace):
val = getattr(self.inherits, key)
else:
raise AttributeError(
"Namespace '%s' has no member '%s'" %
"Namespace '%s' has no member '%s'" %
(self.name, key))
setattr(self, key, val)
return val
@@ -521,11 +627,11 @@ class ModuleNamespace(Namespace):
def supports_caller(func):
"""Apply a caller_stack compatibility decorator to a plain
Python function.
See the example in :ref:`namespaces_python_modules`.
"""
def wrap_stackframe(context, *args, **kwargs):
context.caller_stack._push_frame()
try:
@@ -533,19 +639,19 @@ def supports_caller(func):
finally:
context.caller_stack._pop_frame()
return wrap_stackframe
def capture(context, callable_, *args, **kwargs):
"""Execute the given template def, capturing the output into
a buffer.
See the example in :ref:`namespaces_python_modules`.
"""
if not callable(callable_):
raise exceptions.RuntimeException(
"capture() function expects a callable as "
"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:
@@ -567,7 +673,7 @@ def _decorate_toplevel(fn):
return fn(y)(context, *args, **kw)
return go
return decorate_render
def _decorate_inline(context, fn):
def decorate_render(render_fn):
dec = fn(render_fn)
@@ -575,17 +681,17 @@ def _decorate_inline(context, fn):
return dec(context, *args, **kw)
return go
return decorate_render
def _include_file(context, uri, calling_uri, **kwargs):
"""locate the template from the given uri and include it in
the current output."""
template = _lookup_template(context, uri, calling_uri)
(callable_, ctx) = _populate_self_namespace(
context._clean_inheritance_tokens(),
context._clean_inheritance_tokens(),
template)
callable_(ctx, **_kwargs_for_include(callable_, context._data, **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
@@ -599,9 +705,9 @@ def _inherit_from(context, uri, calling_uri):
while ih.inherits is not None:
ih = ih.inherits
lclcontext = context.locals_({'next':ih})
ih.inherits = TemplateNamespace("self:%s" % template.uri,
lclcontext,
template = template,
ih.inherits = TemplateNamespace("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)
@@ -619,7 +725,7 @@ def _lookup_template(context, uri, relativeto):
lookup = context._with_template.lookup
if lookup is None:
raise exceptions.TemplateLookupException(
"Template '%s' has no TemplateLookup associated" %
"Template '%s' has no TemplateLookup associated" %
context._with_template.uri)
uri = lookup.adjust_uri(uri, relativeto)
try:
@@ -629,8 +735,8 @@ def _lookup_template(context, uri, relativeto):
def _populate_self_namespace(context, template, self_ns=None):
if self_ns is None:
self_ns = TemplateNamespace('self:%s' % template.uri,
context, template=template,
self_ns = TemplateNamespace('self:%s' % template.uri,
context, template=template,
populate_self=False)
context._data['self'] = context._data['local'] = self_ns
if hasattr(template.module, '_mako_inherit'):
@@ -640,7 +746,7 @@ 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
"""create a Context and return the string
output of the given template and template callable."""
if as_unicode:
@@ -649,14 +755,14 @@ def _render(template, callable_, args, data, as_unicode=False):
buf = util.StringIO()
else:
buf = util.FastEncodingBuffer(
unicode=as_unicode,
encoding=template.output_encoding,
unicode=as_unicode,
encoding=template.output_encoding,
errors=template.encoding_errors)
context = Context(buf, **data)
context._outputting_as_unicode = as_unicode
context._with_template = template
_render_context(template, callable_, context, *args,
context._set_with_template(template)
_render_context(template, callable_, context, *args,
**_kwargs_for_callable(callable_, data))
return context._pop_buffer().getvalue()
@@ -665,7 +771,7 @@ def _kwargs_for_callable(callable_, data):
# for normal pages, **pageargs is usually present
if argspec[2]:
return data
# for rendering defs from the top level, figure out the args
namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
kwargs = {}
@@ -681,10 +787,10 @@ def _kwargs_for_include(callable_, data, **kwargs):
if arg != 'context' and arg in data and arg not in kwargs:
kwargs[arg] = data[arg]
return kwargs
def _render_context(tmpl, callable_, context, *args, **kwargs):
import mako.template as template
# create polymorphic 'self' namespace for this
# 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
@@ -694,7 +800,7 @@ def _render_context(tmpl, callable_, context, *args, **kwargs):
# otherwise, call the actual rendering method specified
(inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent)
_exec_template(callable_, context, args=args, kwargs=kwargs)
def _exec_template(callable_, context, args=None, kwargs=None):
"""execute a rendering callable given the callable, a
Context, and optional explicit arguments
@@ -711,7 +817,7 @@ def _exec_template(callable_, context, args=None, kwargs=None):
callable_(context, *args, **kwargs)
except Exception, e:
_render_error(template, context, e)
except:
except:
e = sys.exc_info()[0]
_render_error(template, context, e)
else:
@@ -730,6 +836,6 @@ def _render_error(template, context, error):
context._buffer_stack[:] = [util.FastEncodingBuffer(
error_template.output_encoding,
error_template.encoding_errors)]
context._with_template = error_template
context._set_with_template(error_template)
error_template.render_context(context, error=error)