import builtins
import functools
import sys
from mako import compat
from mako import exceptions
from mako import util
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 = {}
self._data["capture"] = functools.partial(capture, self)
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 self._with_template.lookup
@property
def kwargs(self):
return self._kwargs.copy()
def push_caller(self, caller):
self.caller_stack.append(caller)
def pop_caller(self):
del self.caller_stack[-1]
def keys(self):
return list(self._data.keys())
def __getitem__(self, key):
if key in self._data:
return self._data[key]
else:
return builtins.__dict__[key]
def _push_writer(self):
buf = util.FastEncodingBuffer()
self._buffer_stack.append(buf)
return buf.write
def _pop_buffer_and_writer(self):
buf = self._buffer_stack.pop()
return buf, self._buffer_stack[-1].write
def _push_buffer(self):
self._push_writer()
def _pop_buffer(self):
return self._buffer_stack.pop()
def get(self, key, default=None):
return self._data.get(key, builtins.__dict__.get(key, default))
def write(self, string):
self._buffer_stack[-1].write(string)
def writer(self):
return self._buffer_stack[-1].write
def _copy(self):
c = Context.__new__(Context)
c._buffer_stack = self._buffer_stack
c._data = self._data.copy()
c._kwargs = self._kwargs
c._with_template = self._with_template
c._outputting_as_unicode = self._outputting_as_unicode
c.namespaces = self.namespaces
c.caller_stack = self.caller_stack
return c
def _locals(self, d):
if not d:
return self
c = self._copy()
c._data.update(d)
return c
def _clean_inheritance_tokens(self):
c = self._copy()
x = c._data
x.pop("self", None)
x.pop("parent", None)
x.pop("next", None)
return c
class CallerStack(list):
def __init__(self):
self.nextcaller = None
def __nonzero__(self):
return self.__bool__()
def __bool__(self):
return len(self) and self._get_caller() and True or False
def _get_caller(self):
return self[-1]
def __getattr__(self, key):
return getattr(self._get_caller(), key)
def _push_frame(self):
frame = self.nextcaller or None
self.append(frame)
self.nextcaller = None
return frame
def _pop_frame(self):
self.nextcaller = self.pop()
class Undefined:
def __str__(self):
raise NameError("Undefined")
def __nonzero__(self):
return self.__bool__()
def __bool__(self):
return False
UNDEFINED = Undefined()
STOP_RENDERING = ""
class LoopStack:
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:
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):
if not values:
raise ValueError("You must provide values to cycle through")
return values[self.index % len(values)]
class _NSAttr:
def __init__(self, parent):
self.__parent = parent
def __getattr__(self, key):
ns = self.__parent
while ns:
if hasattr(ns.module, key):
return getattr(ns.module, key)
else:
ns = ns.inherits
raise AttributeError(key)
class Namespace:
def __init__(
self,
name,
context,
callables=None,
inherits=None,
populate_self=True,
calling_uri=None,
):
self.name = name
self.context = context
self.inherits = inherits
if callables is not None:
self.callables = {c.__name__: c for c in callables}
callables = ()
module = None
template = None
context = None
filename = None
uri = None
_templateuri = None
@util.memoized_property
def attr(self):
return _NSAttr(self)
def get_namespace(self, uri):
key = (self, uri)
if key in self.context.namespaces:
return self.context.namespaces[key]
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 _lookup_template(self.context, uri, self._templateuri)
def get_cached(self, key, **kwargs):
return self.cache.get(key, **kwargs)
@property
def cache(self):
return self.template.cache
def include_file(self, uri, **kwargs):
_include_file(self.context, uri, self._templateuri, **kwargs)
def _populate(self, d, l):
for ident in l:
if ident == "*":
for (k, v) in self._get_star():
d[k] = v
else:
d[ident] = getattr(self, ident)
def _get_star(self):
if self.callables:
for key in self.callables:
yield (key, self.callables[key])
def __getattr__(self, key):
if key in self.callables:
val = self.callables[key]
elif self.inherits:
val = getattr(self.inherits, key)
else:
raise AttributeError(
"Namespace '%s' has no member '%s'" % (self.name, key)
)
setattr(self, key, val)
return val
class TemplateNamespace(Namespace):
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
self.inherits = inherits
if callables is not None:
self.callables = {c.__name__: c for c in callables}
if templateuri is not None:
self.template = _lookup_template(context, templateuri, calling_uri)
self._templateuri = self.template.module._template_uri
elif template is not None:
self.template = template
self._templateuri = template.module._template_uri
else:
raise TypeError("'template' argument is required.")
if populate_self:
lclcallable, lclcontext = _populate_self_namespace(
context, self.template, self_ns=self
)
@property
def module(self):
return self.template.module
@property
def filename(self):
return self.template.filename
@property
def uri(self):
return self.template.uri
def _get_star(self):
if self.callables:
for key in self.callables:
yield (key, self.callables[key])
def get(key):
callable_ = self.template._get_def_callable(key)
return functools.partial(callable_, self.context)
for k in self.template.module._exports:
yield (k, get(k))
def __getattr__(self, key):
if key in self.callables:
val = self.callables[key]
elif self.template.has_def(key):
callable_ = self.template._get_def_callable(key)
val = functools.partial(callable_, self.context)
elif self.inherits:
val = getattr(self.inherits, key)
else:
raise AttributeError(
"Namespace '%s' has no member '%s'" % (self.name, key)
)
setattr(self, key, val)
return val
class ModuleNamespace(Namespace):
def __init__(
self,
name,
context,
module,
callables=None,
inherits=None,
populate_self=True,
calling_uri=None,
):
self.name = name
self.context = context
self.inherits = inherits
if callables is not None:
self.callables = {c.__name__: c for c in callables}
mod = __import__(module)
for token in module.split(".")[1:]:
mod = getattr(mod, token)
self.module = mod
@property
def filename(self):
return self.module.__file__
def _get_star(self):
if self.callables:
for key in self.callables:
yield (key, self.callables[key])
for key in dir(self.module):
if key[0] != "_":
callable_ = getattr(self.module, key)
if callable(callable_):
yield key, functools.partial(callable_, self.context)
def __getattr__(self, key):
if key in self.callables:
val = self.callables[key]
elif hasattr(self.module, key):
callable_ = getattr(self.module, key)
val = functools.partial(callable_, self.context)
elif self.inherits:
val = getattr(self.inherits, key)
else:
raise AttributeError(
"Namespace '%s' has no member '%s'" % (self.name, key)
)
setattr(self, key, val)
return val
def supports_caller(func):
def wrap_stackframe(context, *args, **kwargs):
context.caller_stack._push_frame()
try:
return func(context, *args, **kwargs)
finally:
context.caller_stack._pop_frame()
return wrap_stackframe
def capture(context, callable_, *args, **kwargs):
if not callable(callable_):
raise exceptions.RuntimeException(
"capture() function expects a callable as "
"its argument (i.e. capture(func, *args, **kwargs))"
)
context._push_buffer()
try:
callable_(*args, **kwargs)
finally:
buf = context._pop_buffer()
return buf.getvalue()
def _decorate_toplevel(fn):
def decorate_render(render_fn):
def go(context, *args, **kw):
def y(*args, **kw):
return render_fn(context, *args, **kw)
try:
y.__name__ = render_fn.__name__[7:]
except TypeError:
pass
return fn(y)(context, *args, **kw)
return go
return decorate_render
def _decorate_inline(context, fn):
def decorate_render(render_fn):
dec = fn(render_fn)
def go(*args, **kw):
return dec(context, *args, **kw)
return go
return decorate_render
def _include_file(context, uri, calling_uri, **kwargs):
template = _lookup_template(context, uri, calling_uri)
(callable_, ctx) = _populate_self_namespace(
context._clean_inheritance_tokens(), template
)
kwargs = _kwargs_for_include(callable_, context._data, **kwargs)
if template.include_error_handler:
try:
callable_(ctx, **kwargs)
except Exception:
result = template.include_error_handler(ctx, compat.exception_as())
if not result:
raise
else:
callable_(ctx, **kwargs)
def _inherit_from(context, uri, calling_uri):
if uri is None:
return None
template = _lookup_template(context, uri, calling_uri)
self_ns = context["self"]
ih = self_ns
while ih.inherits is not None:
ih = ih.inherits
lclcontext = context._locals({"next": ih})
ih.inherits = 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)
if callable_ is not None:
ret = callable_(template, lclcontext)
if ret:
return ret
gen_ns = getattr(template.module, "_mako_generate_namespaces", None)
if gen_ns is not None:
gen_ns(context)
return (template.callable_, lclcontext)
def _lookup_template(context, uri, relativeto):
lookup = context._with_template.lookup
if lookup is None:
raise exceptions.TemplateLookupException(
"Template '%s' has no TemplateLookup associated"
% context._with_template.uri
)
uri = lookup.adjust_uri(uri, relativeto)
try:
return lookup.get_template(uri)
except exceptions.TopLevelLookupException as e:
raise exceptions.TemplateLookupException(
str(compat.exception_as())
) from e
def _populate_self_namespace(context, template, self_ns=None):
if self_ns is None:
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"):
ret = template.module._mako_inherit(template, context)
if ret:
return ret
return (template.callable_, context)
def _render(template, callable_, args, data, as_unicode=False):
if as_unicode:
buf = util.FastEncodingBuffer()
else:
buf = util.FastEncodingBuffer(
encoding=template.output_encoding, errors=template.encoding_errors
)
context = Context(buf, **data)
context._outputting_as_unicode = as_unicode
context._set_with_template(template)
_render_context(
template,
callable_,
context,
*args,
**_kwargs_for_callable(callable_, data),
)
return context._pop_buffer().getvalue()
def _kwargs_for_callable(callable_, data):
argspec = compat.inspect_getargspec(callable_)
if argspec[2]:
return data
namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
kwargs = {}
for arg in namedargs:
if arg != "context" and arg in data and arg not in kwargs:
kwargs[arg] = data[arg]
return kwargs
def _kwargs_for_include(callable_, data, **kwargs):
argspec = compat.inspect_getargspec(callable_)
namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
for arg in namedargs:
if arg != "context" and arg in data and arg not in kwargs:
kwargs[arg] = data[arg]
return kwargs
def _render_context(tmpl, callable_, context, *args, **kwargs):
import mako.template as template
if not isinstance(tmpl, template.DefTemplate):
(inherit, lclcontext) = _populate_self_namespace(context, tmpl)
_exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
else:
(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):
template = context._with_template
if template is not None and (
template.format_exceptions or template.error_handler
):
try:
callable_(context, *args, **kwargs)
except Exception:
_render_error(template, context, compat.exception_as())
except:
e = sys.exc_info()[0]
_render_error(template, context, e)
else:
callable_(context, *args, **kwargs)
def _render_error(template, context, error):
if template.error_handler:
result = template.error_handler(context, error)
if not result:
tp, value, tb = sys.exc_info()
if value and tb:
raise value.with_traceback(tb)
else:
raise error
else:
error_template = exceptions.html_error_template()
if context._outputting_as_unicode:
context._buffer_stack[:] = [util.FastEncodingBuffer()]
else:
context._buffer_stack[:] = [
util.FastEncodingBuffer(
error_template.output_encoding,
error_template.encoding_errors,
)
]
context._set_with_template(error_template)
error_template.render_context(context, error=error)