Update mako to 1.1.0

This commit is contained in:
JonnyWong16 2019-11-23 18:57:21 -08:00
parent 84ce4758d1
commit f2d7beec90
27 changed files with 2424 additions and 1890 deletions

View file

@ -1,5 +1,5 @@
# mako/runtime.py
# Copyright (C) 2006-2015 the Mako authors and contributors <see AUTHORS file>
# Copyright 2006-2019 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
@ -7,12 +7,17 @@
"""provides runtime services for templates, including Context,
Namespace, and various helper functions."""
from mako import exceptions, util, compat
from mako.compat import compat_builtins
import functools
import sys
from mako import compat
from mako import exceptions
from mako import util
from mako.compat import compat_builtins
class Context(object):
"""Provides runtime namespace, output buffer, and various
callstacks for templates.
@ -33,18 +38,19 @@ class Context(object):
# "capture" function which proxies to the
# generic "capture" function
self._data['capture'] = compat.partial(capture, self)
self._data["capture"] = functools.partial(capture, self)
# "caller" stack used by def calls with content
self.caller_stack = self._data['caller'] = CallerStack()
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))
"Reserved words passed to render(): %s"
% ", ".join(illegal_names)
)
@property
def lookup(self):
@ -80,7 +86,6 @@ class Context(object):
"""Push a ``caller`` callable onto the callstack for
this :class:`.Context`."""
self.caller_stack.append(caller)
def pop_caller(self):
@ -177,11 +182,12 @@ class Context(object):
c = self._copy()
x = c._data
x.pop('self', None)
x.pop('parent', None)
x.pop('next', None)
x.pop("self", None)
x.pop("parent", None)
x.pop("next", None)
return c
class CallerStack(list):
def __init__(self):
self.nextcaller = None
@ -211,6 +217,7 @@ class CallerStack(list):
class Undefined(object):
"""Represents an undefined value in a template.
All template modules have a constant value
@ -218,6 +225,7 @@ class Undefined(object):
object.
"""
def __str__(self):
raise NameError("Undefined")
@ -227,9 +235,13 @@ class Undefined(object):
def __bool__(self):
return False
UNDEFINED = Undefined()
STOP_RENDERING = ""
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
"""
@ -269,6 +281,7 @@ class LoopStack(object):
class LoopContext(object):
"""A magic loop variable.
Automatically accessible in any ``% for`` block.
@ -336,6 +349,7 @@ class LoopContext(object):
class _NSAttr(object):
def __init__(self, parent):
self.__parent = parent
def __getattr__(self, key):
ns = self.__parent
while ns:
@ -345,7 +359,9 @@ class _NSAttr(object):
ns = ns.inherits
raise AttributeError(key)
class Namespace(object):
"""Provides access to collections of rendering methods, which
can be local, from other templates, or from imported modules.
@ -361,9 +377,15 @@ class Namespace(object):
"""
def __init__(self, name, context,
callables=None, inherits=None,
populate_self=True, calling_uri=None):
def __init__(
self,
name,
context,
callables=None,
inherits=None,
populate_self=True,
calling_uri=None,
):
self.name = name
self.context = context
self.inherits = inherits
@ -461,9 +483,12 @@ class Namespace(object):
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
@ -506,7 +531,7 @@ class Namespace(object):
def _populate(self, d, l):
for ident in l:
if ident == '*':
if ident == "*":
for (k, v) in self._get_star():
d[k] = v
else:
@ -524,17 +549,27 @@ class Namespace(object):
val = getattr(self.inherits, key)
else:
raise AttributeError(
"Namespace '%s' has no member '%s'" %
(self.name, key))
"Namespace '%s' has no member '%s'" % (self.name, key)
)
setattr(self, key, val)
return val
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,
populate_self=True, calling_uri=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
self.inherits = inherits
@ -542,8 +577,7 @@ class TemplateNamespace(Namespace):
self.callables = dict([(c.__name__, c) for c in callables])
if templateuri is not None:
self.template = _lookup_template(context, templateuri,
calling_uri)
self.template = _lookup_template(context, templateuri, calling_uri)
self._templateuri = self.template.module._template_uri
elif template is not None:
self.template = template
@ -552,9 +586,9 @@ class TemplateNamespace(Namespace):
raise TypeError("'template' argument is required.")
if populate_self:
lclcallable, lclcontext = \
_populate_self_namespace(context, self.template,
self_ns=self)
lclcallable, lclcontext = _populate_self_namespace(
context, self.template, self_ns=self
)
@property
def module(self):
@ -589,9 +623,11 @@ class TemplateNamespace(Namespace):
if self.callables:
for key in self.callables:
yield (key, self.callables[key])
def get(key):
callable_ = self.template._get_def_callable(key)
return compat.partial(callable_, self.context)
return functools.partial(callable_, self.context)
for k in self.template.module._exports:
yield (k, get(k))
@ -600,23 +636,32 @@ class TemplateNamespace(Namespace):
val = self.callables[key]
elif self.template.has_def(key):
callable_ = self.template._get_def_callable(key)
val = compat.partial(callable_, self.context)
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))
"Namespace '%s' has no member '%s'" % (self.name, key)
)
setattr(self, key, val)
return val
class ModuleNamespace(Namespace):
"""A :class:`.Namespace` specific to a Python module instance."""
def __init__(self, name, context, module,
callables=None, inherits=None,
populate_self=True, calling_uri=None):
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
@ -624,7 +669,7 @@ class ModuleNamespace(Namespace):
self.callables = dict([(c.__name__, c) for c in callables])
mod = __import__(module)
for token in module.split('.')[1:]:
for token in module.split(".")[1:]:
mod = getattr(mod, token)
self.module = mod
@ -640,27 +685,27 @@ class ModuleNamespace(Namespace):
for key in self.callables:
yield (key, self.callables[key])
for key in dir(self.module):
if key[0] != '_':
if key[0] != "_":
callable_ = getattr(self.module, key)
if compat.callable(callable_):
yield key, compat.partial(callable_, self.context)
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 = compat.partial(callable_, self.context)
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))
"Namespace '%s' has no member '%s'" % (self.name, key)
)
setattr(self, key, val)
return val
def supports_caller(func):
"""Apply a caller_stack compatibility decorator to a plain
Python function.
@ -675,8 +720,10 @@ def supports_caller(func):
return func(context, *args, **kwargs)
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.
@ -685,11 +732,11 @@ def capture(context, callable_, *args, **kwargs):
"""
if not compat.callable(callable_):
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)
@ -697,37 +744,56 @@ def capture(context, callable_, *args, **kwargs):
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:
# < Python 2.4
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):
"""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, **_kwargs_for_include(callable_, context._data, **kwargs))
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:
compat.reraise(*sys.exc_info())
else:
callable_(ctx, **kwargs)
def _inherit_from(context, uri, calling_uri):
"""called by the _inherit method in template modules to set
@ -737,51 +803,60 @@ def _inherit_from(context, uri, calling_uri):
if uri is None:
return None
template = _lookup_template(context, uri, calling_uri)
self_ns = context['self']
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)
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)
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)
"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:
raise exceptions.TemplateLookupException(str(compat.exception_as()))
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'):
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):
"""create a Context and return the string
output of the given template and template callable."""
@ -792,19 +867,26 @@ def _render(template, callable_, args, data, as_unicode=False):
buf = compat.StringIO()
else:
buf = util.FastEncodingBuffer(
as_unicode=as_unicode,
encoding=template.output_encoding,
errors=template.encoding_errors)
as_unicode=as_unicode,
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))
_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_func_args(callable_)
argspec = compat.inspect_getargspec(callable_)
# for normal pages, **pageargs is usually present
if argspec[2]:
return data
@ -813,20 +895,23 @@ def _kwargs_for_callable(callable_, 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:
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_func_args(callable_)
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:
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
# template with possibly updated context
if not isinstance(tmpl, template.DefTemplate):
@ -838,6 +923,7 @@ def _render_context(tmpl, callable_, context, *args, **kwargs):
(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
@ -847,8 +933,9 @@ def _exec_template(callable_, context, args=None, kwargs=None):
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
):
try:
callable_(context, *args, **kwargs)
except Exception:
@ -859,6 +946,7 @@ 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)
@ -868,11 +956,15 @@ def _render_error(template, context, error):
error_template = exceptions.html_error_template()
if context._outputting_as_unicode:
context._buffer_stack[:] = [
util.FastEncodingBuffer(as_unicode=True)]
util.FastEncodingBuffer(as_unicode=True)
]
else:
context._buffer_stack[:] = [util.FastEncodingBuffer(
error_template.output_encoding,
error_template.encoding_errors)]
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)