- get flake8 to pass fully for mako/ (tests are a much bigger deal)
diff --git a/mako/_ast_util.py b/mako/_ast_util.py
index efbc4fc..604b090 100644
--- a/mako/_ast_util.py
+++ b/mako/_ast_util.py
@@ -30,7 +30,7 @@
:copyright: Copyright 2008 by Armin Ronacher.
:license: Python License.
"""
-from _ast import *
+from _ast import * # noqa
from mako.compat import arg_stringname
BOOLOP_SYMBOLS = {
@@ -246,6 +246,7 @@
class NodeVisitor(object):
+
"""
Walks the abstract syntax tree and call visitor functions for every node
found. The visitor functions may return values which will be forwarded
@@ -290,6 +291,7 @@
class NodeTransformer(NodeVisitor):
+
"""
Walks the abstract syntax tree and allows modifications of nodes.
@@ -349,6 +351,7 @@
class SourceGenerator(NodeVisitor):
+
"""
This visitor is able to transform a well formed syntax tree into python
sourcecode. For more details have a look at the docstring of the
@@ -388,6 +391,7 @@
def signature(self, node):
want_comma = []
+
def write_comma():
if want_comma:
self.write(', ')
@@ -460,6 +464,7 @@
def visit_ClassDef(self, node):
have_args = []
+
def paren_or_comma():
if have_args:
self.write(', ')
@@ -631,6 +636,7 @@
def visit_Call(self, node):
want_comma = []
+
def write_comma():
if want_comma:
self.write(', ')
diff --git a/mako/ast.py b/mako/ast.py
index 65fd84d..c55b29c 100644
--- a/mako/ast.py
+++ b/mako/ast.py
@@ -10,8 +10,11 @@
from mako import exceptions, pyparser, compat
import re
+
class PythonCode(object):
+
"""represents information about a string containing Python code"""
+
def __init__(self, code, **exception_kwargs):
self.code = code
@@ -41,8 +44,11 @@
f = pyparser.FindIdentifiers(self, **exception_kwargs)
f.visit(expr)
+
class ArgumentList(object):
+
"""parses a fragment of code as a comma-separated list of expressions"""
+
def __init__(self, code, **exception_kwargs):
self.codeargs = []
self.args = []
@@ -52,7 +58,7 @@
if re.match(r"\S", code) and not re.match(r",\s*$", code):
# if theres text and no trailing comma, insure its parsed
# as a tuple by adding a trailing comma
- code += ","
+ code += ","
expr = pyparser.parse(code, "exec", **exception_kwargs)
else:
expr = code
@@ -60,7 +66,9 @@
f = pyparser.FindTuple(self, PythonCode, **exception_kwargs)
f.visit(expr)
+
class PythonFragment(PythonCode):
+
"""extends PythonCode to provide identifier lookups in partial control
statements
@@ -70,16 +78,17 @@
except (MyException, e):
etc.
"""
+
def __init__(self, code, **exception_kwargs):
m = re.match(r'^(\w+)(?:\s+(.*?))?:\s*(#|$)', code.strip(), re.S)
if not m:
raise exceptions.CompileException(
- "Fragment '%s' is not a partial control statement" %
- code, **exception_kwargs)
+ "Fragment '%s' is not a partial control statement" %
+ code, **exception_kwargs)
if m.group(3):
code = code[:m.start(3)]
- (keyword, expr) = m.group(1,2)
- if keyword in ['for','if', 'while']:
+ (keyword, expr) = m.group(1, 2)
+ if keyword in ['for', 'if', 'while']:
code = code + "pass"
elif keyword == 'try':
code = code + "pass\nexcept:pass"
@@ -91,13 +100,15 @@
code = code + "pass"
else:
raise exceptions.CompileException(
- "Unsupported control keyword: '%s'" %
- keyword, **exception_kwargs)
+ "Unsupported control keyword: '%s'" %
+ keyword, **exception_kwargs)
super(PythonFragment, self).__init__(code, **exception_kwargs)
class FunctionDecl(object):
+
"""function declaration"""
+
def __init__(self, code, allow_kwargs=True, **exception_kwargs):
self.code = code
expr = pyparser.parse(code, "exec", **exception_kwargs)
@@ -106,12 +117,12 @@
f.visit(expr)
if not hasattr(self, 'funcname'):
raise exceptions.CompileException(
- "Code '%s' is not a function declaration" % code,
- **exception_kwargs)
+ "Code '%s' is not a function declaration" % code,
+ **exception_kwargs)
if not allow_kwargs and self.kwargs:
raise exceptions.CompileException(
- "'**%s' keyword argument not allowed here" %
- self.kwargnames[-1], **exception_kwargs)
+ "'**%s' keyword argument not allowed here" %
+ self.kwargnames[-1], **exception_kwargs)
def get_argument_expressions(self, as_call=False):
"""Return the argument declarations of this FunctionDecl as a printable
@@ -170,9 +181,11 @@
def allargnames(self):
return tuple(self.argnames) + tuple(self.kwargnames)
+
class FunctionArgs(FunctionDecl):
+
"""the argument portion of a function declaration"""
def __init__(self, code, **kwargs):
super(FunctionArgs, self).__init__("def ANON(%s):pass" % code,
- **kwargs)
+ **kwargs)
diff --git a/mako/cache.py b/mako/cache.py
index c405c51..c7aabd2 100644
--- a/mako/cache.py
+++ b/mako/cache.py
@@ -13,6 +13,7 @@
class Cache(object):
+
"""Represents a data content cache made available to the module
space of a specific :class:`.Template` object.
@@ -181,6 +182,7 @@
class CacheImpl(object):
+
"""Provide a cache implementation for use by :class:`.Cache`."""
def __init__(self, cache):
diff --git a/mako/cmd.py b/mako/cmd.py
index 1a9ca56..50d47fc 100755
--- a/mako/cmd.py
+++ b/mako/cmd.py
@@ -10,26 +10,31 @@
from mako.lookup import TemplateLookup
from mako import exceptions
+
def varsplit(var):
if "=" not in var:
return (var, "")
return var.split("=", 1)
+
def _exit():
sys.stderr.write(exceptions.text_error_template().render())
sys.exit(1)
+
def cmdline(argv=None):
parser = ArgumentParser("usage: %prog [FILENAME]")
- parser.add_argument("--var", default=[], action="append",
- help="variable (can be used multiple times, use name=value)")
- parser.add_argument("--template-dir", default=[], action="append",
- help="Directory to use for template lookup (multiple "
- "directories may be provided). If not given then if the "
- "template is read from stdin, the value defaults to be "
- "the current directory, otherwise it defaults to be the "
- "parent directory of the file provided.")
+ parser.add_argument(
+ "--var", default=[], action="append",
+ help="variable (can be used multiple times, use name=value)")
+ parser.add_argument(
+ "--template-dir", default=[], action="append",
+ help="Directory to use for template lookup (multiple "
+ "directories may be provided). If not given then if the "
+ "template is read from stdin, the value defaults to be "
+ "the current directory, otherwise it defaults to be the "
+ "parent directory of the file provided.")
parser.add_argument('input', nargs='?', default='-')
options = parser.parse_args(argv)
diff --git a/mako/codegen.py b/mako/codegen.py
index 3c0bad4..bf86d79 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -22,20 +22,20 @@
TOPLEVEL_DECLARED = set(["UNDEFINED", "STOP_RENDERING"])
RESERVED_NAMES = set(['context', 'loop']).union(TOPLEVEL_DECLARED)
-def compile(node,
- uri,
- filename=None,
- default_filters=None,
- buffer_filters=None,
- imports=None,
- future_imports=None,
- source_encoding=None,
- generate_magic_comment=True,
- disable_unicode=False,
- strict_undefined=False,
- enable_loop=True,
- reserved_names=frozenset()):
+def compile(node,
+ uri,
+ filename=None,
+ default_filters=None,
+ buffer_filters=None,
+ imports=None,
+ future_imports=None,
+ source_encoding=None,
+ generate_magic_comment=True,
+ disable_unicode=False,
+ strict_undefined=False,
+ enable_loop=True,
+ reserved_names=frozenset()):
"""Generate module source code given a parsetree node,
uri, and optional source filename"""
@@ -46,40 +46,41 @@
if not compat.py3k and isinstance(source_encoding, compat.text_type):
source_encoding = source_encoding.encode(source_encoding)
-
buf = util.FastEncodingBuffer()
printer = PythonPrinter(buf)
_GenerateRenderMethod(printer,
- _CompileContext(uri,
- filename,
- default_filters,
- buffer_filters,
- imports,
- future_imports,
- source_encoding,
- generate_magic_comment,
- disable_unicode,
- strict_undefined,
- enable_loop,
- reserved_names),
- node)
+ _CompileContext(uri,
+ filename,
+ default_filters,
+ buffer_filters,
+ imports,
+ future_imports,
+ source_encoding,
+ generate_magic_comment,
+ disable_unicode,
+ strict_undefined,
+ enable_loop,
+ reserved_names),
+ node)
return buf.getvalue()
+
class _CompileContext(object):
+
def __init__(self,
- uri,
- filename,
- default_filters,
- buffer_filters,
- imports,
- future_imports,
- source_encoding,
- generate_magic_comment,
- disable_unicode,
- strict_undefined,
- enable_loop,
- reserved_names):
+ uri,
+ filename,
+ default_filters,
+ buffer_filters,
+ imports,
+ future_imports,
+ source_encoding,
+ generate_magic_comment,
+ disable_unicode,
+ strict_undefined,
+ enable_loop,
+ reserved_names):
self.uri = uri
self.filename = filename
self.default_filters = default_filters
@@ -93,11 +94,14 @@
self.enable_loop = enable_loop
self.reserved_names = reserved_names
+
class _GenerateRenderMethod(object):
+
"""A template visitor object which generates the
full module source for a template.
"""
+
def __init__(self, printer, compiler, node):
self.printer = printer
self.compiler = compiler
@@ -125,9 +129,9 @@
args += ['**pageargs']
cached = eval(pagetag.attributes.get('cached', 'False'))
self.compiler.enable_loop = self.compiler.enable_loop or eval(
- pagetag.attributes.get(
- 'enable_loop', 'False')
- )
+ pagetag.attributes.get(
+ 'enable_loop', 'False')
+ )
else:
args = ['**pageargs']
cached = False
@@ -138,9 +142,9 @@
args = [a for a in ['context'] + args]
self.write_render_callable(
- pagetag or node,
- name, args,
- buffered, filtered, cached)
+ pagetag or node,
+ name, args,
+ buffered, filtered, cached)
if defs is not None:
for node in defs:
@@ -151,7 +155,7 @@
def write_metadata_struct(self):
self.printer.source_map[self.printer.lineno] = \
- max(self.printer.source_map)
+ max(self.printer.source_map)
struct = {
"filename": self.compiler.filename,
"uri": self.compiler.uri,
@@ -182,12 +186,16 @@
self.compiler.pagetag = None
class FindTopLevel(object):
+
def visitInheritTag(s, node):
inherit.append(node)
+
def visitNamespaceTag(s, node):
namespaces[node.name] = node
+
def visitPageTag(s, node):
self.compiler.pagetag = node
+
def visitCode(s, node):
if node.ismodule:
module_code.append(node)
@@ -209,7 +217,7 @@
if self.compiler.generate_magic_comment and \
self.compiler.source_encoding:
self.printer.writeline("# -*- coding:%s -*-" %
- self.compiler.source_encoding)
+ self.compiler.source_encoding)
if self.compiler.future_imports:
self.printer.writeline("from __future__ import %s" %
@@ -223,36 +231,36 @@
self.printer.writeline("_modified_time = %r" % time.time())
self.printer.writeline("_enable_loop = %r" % self.compiler.enable_loop)
self.printer.writeline(
- "_template_filename = %r" % self.compiler.filename)
+ "_template_filename = %r" % self.compiler.filename)
self.printer.writeline("_template_uri = %r" % self.compiler.uri)
self.printer.writeline(
- "_source_encoding = %r" % self.compiler.source_encoding)
+ "_source_encoding = %r" % self.compiler.source_encoding)
if self.compiler.imports:
buf = ''
for imp in self.compiler.imports:
buf += imp + "\n"
self.printer.writeline(imp)
impcode = ast.PythonCode(
- buf,
- source='', lineno=0,
- pos=0,
- filename='template defined imports')
+ buf,
+ source='', lineno=0,
+ pos=0,
+ filename='template defined imports')
else:
impcode = None
main_identifiers = module_identifiers.branch(self.node)
module_identifiers.topleveldefs = \
module_identifiers.topleveldefs.\
- union(main_identifiers.topleveldefs)
+ union(main_identifiers.topleveldefs)
module_identifiers.declared.update(TOPLEVEL_DECLARED)
if impcode:
module_identifiers.declared.update(impcode.declared_identifiers)
self.compiler.identifiers = module_identifiers
self.printer.writeline("_exports = %r" %
- [n.name for n in
- main_identifiers.topleveldefs.values()]
- )
+ [n.name for n in
+ main_identifiers.topleveldefs.values()]
+ )
self.printer.write_blanks(2)
if len(module_code):
@@ -267,7 +275,7 @@
return list(main_identifiers.topleveldefs.values())
def write_render_callable(self, node, name, args, buffered, filtered,
- cached):
+ cached):
"""write a top-level render callable.
this could be the main render() method or that of a top-level def."""
@@ -276,30 +284,30 @@
decorator = node.decorator
if decorator:
self.printer.writeline(
- "@runtime._decorate_toplevel(%s)" % decorator)
+ "@runtime._decorate_toplevel(%s)" % decorator)
self.printer.start_source(node.lineno)
self.printer.writelines(
"def %s(%s):" % (name, ','.join(args)),
- # push new frame, assign current frame to __M_caller
- "__M_caller = context.caller_stack._push_frame()",
- "try:"
+ # push new frame, assign current frame to __M_caller
+ "__M_caller = context.caller_stack._push_frame()",
+ "try:"
)
if buffered or filtered or cached:
self.printer.writeline("context._push_buffer()")
self.identifier_stack.append(
- self.compiler.identifiers.branch(self.node))
+ self.compiler.identifiers.branch(self.node))
if (not self.in_def or self.node.is_block) and '**pageargs' in args:
self.identifier_stack[-1].argument_declared.add('pageargs')
if not self.in_def and (
- len(self.identifiers.locally_assigned) > 0 or
- len(self.identifiers.argument_declared) > 0
- ):
+ len(self.identifiers.locally_assigned) > 0 or
+ len(self.identifiers.argument_declared) > 0
+ ):
self.printer.writeline("__M_locals = __M_dict_builtin(%s)" %
- ','.join([
- "%s=%s" % (x, x) for x in
+ ','.join([
+ "%s=%s" % (x, x) for x in
self.identifiers.argument_declared
]))
@@ -313,9 +321,9 @@
self.printer.write_blanks(2)
if cached:
self.write_cache_decorator(
- node, name,
- args, buffered,
- self.identifiers, toplevel=True)
+ node, name,
+ args, buffered,
+ self.identifiers, toplevel=True)
def write_module_code(self, module_code):
"""write module-level template code, i.e. that which
@@ -329,26 +337,25 @@
self.printer.writelines(
"def _mako_inherit(template, context):",
- "_mako_generate_namespaces(context)",
- "return runtime._inherit_from(context, %s, _template_uri)" %
- (node.parsed_attributes['file']),
- None
+ "_mako_generate_namespaces(context)",
+ "return runtime._inherit_from(context, %s, _template_uri)" %
+ (node.parsed_attributes['file']),
+ None
)
def write_namespaces(self, namespaces):
"""write the module-level namespace-generating callable."""
self.printer.writelines(
"def _mako_get_namespace(context, name):",
- "try:",
- "return context.namespaces[(__name__, name)]",
- "except KeyError:",
- "_mako_generate_namespaces(context)",
- "return context.namespaces[(__name__, name)]",
+ "try:",
+ "return context.namespaces[(__name__, name)]",
+ "except KeyError:",
+ "_mako_generate_namespaces(context)",
+ "return context.namespaces[(__name__, name)]",
None, None
)
self.printer.writeline("def _mako_generate_namespaces(context):")
-
for node in namespaces.values():
if 'import' in node.attributes:
self.compiler.has_ns_imports = True
@@ -358,7 +365,9 @@
export = []
identifiers = self.compiler.identifiers.branch(node)
self.in_def = True
+
class NSDefVisitor(object):
+
def visitDefTag(s, node):
s.visitDefOrBase(node)
@@ -386,39 +395,39 @@
if 'file' in node.parsed_attributes:
self.printer.writeline(
- "ns = runtime.TemplateNamespace(%r,"
- " context._clean_inheritance_tokens(),"
- " templateuri=%s, callables=%s, "
- " calling_uri=_template_uri)" %
- (
- node.name,
- node.parsed_attributes.get('file', 'None'),
- callable_name,
- )
- )
+ "ns = runtime.TemplateNamespace(%r,"
+ " context._clean_inheritance_tokens(),"
+ " templateuri=%s, callables=%s, "
+ " calling_uri=_template_uri)" %
+ (
+ node.name,
+ node.parsed_attributes.get('file', 'None'),
+ callable_name,
+ )
+ )
elif 'module' in node.parsed_attributes:
self.printer.writeline(
- "ns = runtime.ModuleNamespace(%r,"
- " context._clean_inheritance_tokens(),"
- " callables=%s, calling_uri=_template_uri,"
- " module=%s)" %
- (
- node.name,
- callable_name,
- node.parsed_attributes.get(
- 'module', 'None')
- )
- )
+ "ns = runtime.ModuleNamespace(%r,"
+ " context._clean_inheritance_tokens(),"
+ " callables=%s, calling_uri=_template_uri,"
+ " module=%s)" %
+ (
+ node.name,
+ callable_name,
+ node.parsed_attributes.get(
+ 'module', 'None')
+ )
+ )
else:
self.printer.writeline(
- "ns = runtime.Namespace(%r,"
- " context._clean_inheritance_tokens(),"
- " callables=%s, calling_uri=_template_uri)" %
- (
- node.name,
- callable_name,
- )
- )
+ "ns = runtime.Namespace(%r,"
+ " context._clean_inheritance_tokens(),"
+ " callables=%s, calling_uri=_template_uri)" %
+ (
+ node.name,
+ callable_name,
+ )
+ )
if eval(node.attributes.get('inheritable', "False")):
self.printer.writeline("context['self'].%s = ns" % (node.name))
@@ -459,7 +468,7 @@
# write closure functions for closures that we define
# right here
to_write = to_write.union(
- [c.funcname for c in identifiers.closuredefs.values()])
+ [c.funcname for c in identifiers.closuredefs.values()])
# remove identifiers that are declared in the argument
# signature of the callable
@@ -489,12 +498,12 @@
for ident, ns in self.compiler.namespaces.items():
if 'import' in ns.attributes:
self.printer.writeline(
- "_mako_get_namespace(context, %r)."
- "_populate(_import_ns, %r)" %
- (
- ident,
- re.split(r'\s*,\s*', ns.attributes['import'])
- ))
+ "_mako_get_namespace(context, %r)."
+ "_populate(_import_ns, %r)" %
+ (
+ ident,
+ re.split(r'\s*,\s*', ns.attributes['import'])
+ ))
if has_loop:
self.printer.writeline(
@@ -517,35 +526,36 @@
elif ident in self.compiler.namespaces:
self.printer.writeline(
- "%s = _mako_get_namespace(context, %r)" %
- (ident, ident)
- )
+ "%s = _mako_get_namespace(context, %r)" %
+ (ident, ident)
+ )
else:
if getattr(self.compiler, 'has_ns_imports', False):
if self.compiler.strict_undefined:
self.printer.writelines(
- "%s = _import_ns.get(%r, UNDEFINED)" %
- (ident, ident),
- "if %s is UNDEFINED:" % ident,
+ "%s = _import_ns.get(%r, UNDEFINED)" %
+ (ident, ident),
+ "if %s is UNDEFINED:" % ident,
"try:",
- "%s = context[%r]" % (ident, ident),
+ "%s = context[%r]" % (ident, ident),
"except KeyError:",
- "raise NameError(\"'%s' is not defined\")" %
- ident,
+ "raise NameError(\"'%s' is not defined\")" %
+ ident,
None, None
)
else:
self.printer.writeline(
- "%s = _import_ns.get(%r, context.get(%r, UNDEFINED))" %
- (ident, ident, ident))
+ "%s = _import_ns.get"
+ "(%r, context.get(%r, UNDEFINED))" %
+ (ident, ident, ident))
else:
if self.compiler.strict_undefined:
self.printer.writelines(
"try:",
- "%s = context[%r]" % (ident, ident),
+ "%s = context[%r]" % (ident, ident),
"except KeyError:",
- "raise NameError(\"'%s' is not defined\")" %
- ident,
+ "raise NameError(\"'%s' is not defined\")" %
+ ident,
None
)
else:
@@ -562,14 +572,14 @@
nameargs = node.get_argument_expressions(as_call=True)
if not self.in_def and (
- len(self.identifiers.locally_assigned) > 0 or
- len(self.identifiers.argument_declared) > 0):
+ len(self.identifiers.locally_assigned) > 0 or
+ len(self.identifiers.argument_declared) > 0):
nameargs.insert(0, 'context._locals(__M_locals)')
else:
nameargs.insert(0, 'context')
self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls)))
self.printer.writeline(
- "return render_%s(%s)" % (funcname, ",".join(nameargs)))
+ "return render_%s(%s)" % (funcname, ",".join(nameargs)))
self.printer.writeline(None)
def write_inline_def(self, node, identifiers, nested):
@@ -580,9 +590,9 @@
decorator = node.decorator
if decorator:
self.printer.writeline(
- "@runtime._decorate_inline(context, %s)" % decorator)
+ "@runtime._decorate_inline(context, %s)" % decorator)
self.printer.writeline(
- "def %s(%s):" % (node.funcname, ",".join(namedecls)))
+ "def %s(%s):" % (node.funcname, ",".join(namedecls)))
filtered = len(node.filter_args.args) > 0
buffered = eval(node.attributes.get('buffered', 'False'))
cached = eval(node.attributes.get('cached', 'False'))
@@ -609,11 +619,11 @@
self.printer.writeline(None)
if cached:
self.write_cache_decorator(node, node.funcname,
- namedecls, False, identifiers,
- inline=True, toplevel=False)
+ namedecls, False, identifiers,
+ inline=True, toplevel=False)
def write_def_finish(self, node, buffered, filtered, cached,
- callstack=True):
+ callstack=True):
"""write the end section of a rendering function, either outermost or
inline.
@@ -627,7 +637,7 @@
if callstack:
self.printer.writelines(
"finally:",
- "context.caller_stack._pop_frame()",
+ "context.caller_stack._pop_frame()",
None
)
@@ -639,7 +649,7 @@
# extra buffers
self.printer.writelines(
"finally:",
- "__M_buf = context._pop_buffer()"
+ "__M_buf = context._pop_buffer()"
)
else:
self.printer.writelines(
@@ -667,8 +677,8 @@
)
def write_cache_decorator(self, node_or_pagetag, name,
- args, buffered, identifiers,
- inline=False, toplevel=False):
+ args, buffered, identifiers,
+ inline=False, toplevel=False):
"""write a post-function decorator to replace a rendering
callable with a cached version of itself."""
@@ -700,40 +710,40 @@
# form "arg1, arg2, arg3=arg3, arg4=arg4", etc.
pass_args = [
- "%s=%s" % ((a.split('=')[0],) * 2) if '=' in a else a
- for a in args
- ]
+ "%s=%s" % ((a.split('=')[0],) * 2) if '=' in a else a
+ for a in args
+ ]
self.write_variable_declares(
- identifiers,
- toplevel=toplevel,
- limit=node_or_pagetag.undeclared_identifiers()
- )
+ identifiers,
+ toplevel=toplevel,
+ limit=node_or_pagetag.undeclared_identifiers()
+ )
if buffered:
s = "context.get('local')."\
"cache._ctx_get_or_create("\
"%s, lambda:__M_%s(%s), context, %s__M_defname=%r)" % (
- cachekey, name, ','.join(pass_args),
- ''.join(["%s=%s, " % (k, v)
- for k, v in cache_args.items()]),
- name
- )
+ cachekey, name, ','.join(pass_args),
+ ''.join(["%s=%s, " % (k, v)
+ for k, v in cache_args.items()]),
+ name
+ )
# apply buffer_filters
s = self.create_filter_callable(self.compiler.buffer_filters, s,
False)
self.printer.writelines("return " + s, None)
else:
self.printer.writelines(
- "__M_writer(context.get('local')."
- "cache._ctx_get_or_create("
- "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" %
- (
- cachekey, name, ','.join(pass_args),
- ''.join(["%s=%s, " % (k, v)
- for k, v in cache_args.items()]),
- name,
- ),
- "return ''",
+ "__M_writer(context.get('local')."
+ "cache._ctx_get_or_create("
+ "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" %
+ (
+ cachekey, name, ','.join(pass_args),
+ ''.join(["%s=%s, " % (k, v)
+ for k, v in cache_args.items()]),
+ name,
+ ),
+ "return ''",
None
)
@@ -777,7 +787,7 @@
(
self.compiler.pagetag is not None and
len(self.compiler.pagetag.filter_args.args)
- ) or \
+ ) or \
len(self.compiler.default_filters):
s = self.create_filter_callable(node.escapes_code.args,
@@ -808,11 +818,11 @@
# 3) any control line with no content other than comments
if not children or (
compat.all(isinstance(c, (parsetree.Comment,
- parsetree.ControlLine))
- for c in children) and
+ parsetree.ControlLine))
+ for c in children) and
compat.all((node.is_ternary(c.keyword) or c.isend)
- for c in children
- if isinstance(c, parsetree.ControlLine))):
+ for c in children
+ if isinstance(c, parsetree.ControlLine))):
self.printer.writeline("pass")
def visitText(self, node):
@@ -834,9 +844,9 @@
"__M_buf, __M_writer = context._pop_buffer_and_writer()",
"__M_writer(%s)" %
self.create_filter_callable(
- node.filter_args.args,
- "__M_buf.getvalue()",
- False),
+ node.filter_args.args,
+ "__M_buf.getvalue()",
+ False),
None
)
@@ -863,12 +873,12 @@
args = node.attributes.get('args')
if args:
self.printer.writeline(
- "runtime._include_file(context, %s, _template_uri, %s)" %
- (node.parsed_attributes['file'], args))
+ "runtime._include_file(context, %s, _template_uri, %s)" %
+ (node.parsed_attributes['file'], args))
else:
self.printer.writeline(
- "runtime._include_file(context, %s, _template_uri)" %
- (node.parsed_attributes['file']))
+ "runtime._include_file(context, %s, _template_uri)" %
+ (node.parsed_attributes['file']))
def visitNamespaceTag(self, node):
pass
@@ -882,9 +892,10 @@
else:
nameargs = node.get_argument_expressions(as_call=True)
nameargs += ['**pageargs']
- self.printer.writeline("if 'parent' not in context._data or "
- "not hasattr(context._data['parent'], '%s'):"
- % node.funcname)
+ self.printer.writeline(
+ "if 'parent' not in context._data or "
+ "not hasattr(context._data['parent'], '%s'):"
+ % node.funcname)
self.printer.writeline(
"context['self'].%s(%s)" % (node.funcname, ",".join(nameargs)))
self.printer.writeline("\n")
@@ -907,7 +918,9 @@
body_identifiers.add_declared('caller')
self.identifier_stack.append(body_identifiers)
+
class DefVisitor(object):
+
def visitDefTag(s, node):
s.visitDefOrBase(node)
@@ -956,19 +969,21 @@
self.printer.writelines(
# push on caller for nested call
"context.caller_stack.nextcaller = "
- "runtime.Namespace('caller', context, "
- "callables=ccall(__M_caller))",
+ "runtime.Namespace('caller', context, "
+ "callables=ccall(__M_caller))",
"try:")
self.printer.start_source(node.lineno)
self.printer.writelines(
- "__M_writer(%s)" % self.create_filter_callable(
- [], node.expression, True),
+ "__M_writer(%s)" % self.create_filter_callable(
+ [], node.expression, True),
"finally:",
- "context.caller_stack.nextcaller = None",
+ "context.caller_stack.nextcaller = None",
None
)
+
class _Identifiers(object):
+
"""tracks the status of identifier names as template code is rendered."""
def __init__(self, compiler, node=None, parent=None, nested=False):
@@ -982,9 +997,9 @@
# things that have already been declared
# in an enclosing namespace (i.e. names we can just use)
self.declared = set(parent.declared).\
- union([c.name for c in parent.closuredefs.values()]).\
- union(parent.locally_declared).\
- union(parent.argument_declared)
+ union([c.name for c in parent.closuredefs.values()]).\
+ union(parent.locally_declared).\
+ union(parent.argument_declared)
# if these identifiers correspond to a "nested"
# scope, it means whatever the parent identifiers
@@ -1028,13 +1043,12 @@
node.accept_visitor(self)
illegal_names = self.compiler.reserved_names.intersection(
- self.locally_declared)
+ self.locally_declared)
if illegal_names:
raise exceptions.NameConflictError(
"Reserved words declared in template: %s" %
", ".join(illegal_names))
-
def branch(self, node, **kwargs):
"""create a new Identifiers for a new Node, with
this Identifiers as the parent."""
@@ -1047,15 +1061,15 @@
def __repr__(self):
return "Identifiers(declared=%r, locally_declared=%r, "\
- "undeclared=%r, topleveldefs=%r, closuredefs=%r, "\
- "argumentdeclared=%r)" %\
- (
- list(self.declared),
- list(self.locally_declared),
- list(self.undeclared),
- [c.name for c in self.topleveldefs.values()],
- [c.name for c in self.closuredefs.values()],
- self.argument_declared)
+ "undeclared=%r, topleveldefs=%r, closuredefs=%r, "\
+ "argumentdeclared=%r)" %\
+ (
+ list(self.declared),
+ list(self.locally_declared),
+ list(self.undeclared),
+ [c.name for c in self.topleveldefs.values()],
+ [c.name for c in self.closuredefs.values()],
+ self.argument_declared)
def check_declared(self, node):
"""update the state of this Identifiers with the undeclared
@@ -1083,7 +1097,7 @@
if not node.ismodule:
self.check_declared(node)
self.locally_assigned = self.locally_assigned.union(
- node.declared_identifiers())
+ node.declared_identifiers())
def visitNamespaceTag(self, node):
# only traverse into the sub-elements of a
@@ -1097,12 +1111,12 @@
existing = collection.get(node.funcname)
collection[node.funcname] = node
if existing is not None and \
- existing is not node and \
- (node.is_block or existing.is_block):
+ existing is not node and \
+ (node.is_block or existing.is_block):
raise exceptions.CompileException(
- "%%def or %%block named '%s' already "
- "exists in this template." %
- node.funcname, **node.exception_kwargs)
+ "%%def or %%block named '%s' already "
+ "exists in this template." %
+ node.funcname, **node.exception_kwargs)
def visitDefTag(self, node):
if node.is_root() and not node.is_anonymous:
@@ -1128,13 +1142,13 @@
if isinstance(self.node, parsetree.DefTag):
raise exceptions.CompileException(
- "Named block '%s' not allowed inside of def '%s'"
- % (node.name, self.node.name), **node.exception_kwargs)
+ "Named block '%s' not allowed inside of def '%s'"
+ % (node.name, self.node.name), **node.exception_kwargs)
elif isinstance(self.node,
(parsetree.CallTag, parsetree.CallNamespaceTag)):
raise exceptions.CompileException(
- "Named block '%s' not allowed inside of <%%call> tag"
- % (node.name, ), **node.exception_kwargs)
+ "Named block '%s' not allowed inside of <%%call> tag"
+ % (node.name, ), **node.exception_kwargs)
for ident in node.undeclared_identifiers():
if ident != 'context' and \
@@ -1173,7 +1187,7 @@
for ident in node.undeclared_identifiers():
if ident != 'context' and \
ident not in self.declared.union(
- self.locally_declared):
+ self.locally_declared):
self.undeclared.add(ident)
for ident in node.declared_identifiers():
self.argument_declared.add(ident)
@@ -1183,15 +1197,16 @@
for ident in node.undeclared_identifiers():
if ident != 'context' and \
ident not in self.declared.union(
- self.locally_declared):
+ self.locally_declared):
self.undeclared.add(ident)
_FOR_LOOP = re.compile(
- r'^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*'
- r'(?:\s*,\s*(?:[A-Za-z_][A-Za-z0-9_]*),??)*\s*(?:\)?))\s+in\s+(.*):'
+ r'^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*'
+ r'(?:\s*,\s*(?:[A-Za-z_][A-Za-z0-9_]*),??)*\s*(?:\)?))\s+in\s+(.*):'
)
+
def mangle_mako_loop(node, printer):
"""converts a for loop into a context manager wrapped around a for loop
when access to the `loop` variable has been detected in the for loop body
@@ -1203,9 +1218,9 @@
match = _FOR_LOOP.match(node.text)
if match:
printer.writelines(
- 'loop = __M_loop._enter(%s)' % match.group(2),
- 'try:'
- #'with __M_loop(%s) as loop:' % match.group(2)
+ 'loop = __M_loop._enter(%s)' % match.group(2),
+ 'try:'
+ # 'with __M_loop(%s) as loop:' % match.group(2)
)
text = 'for %s in loop:' % match.group(1)
else:
@@ -1216,6 +1231,7 @@
class LoopVariable(object):
+
"""A node visitor which looks for the name 'loop' within undeclared
identifiers."""
diff --git a/mako/compat.py b/mako/compat.py
index fe277bb..c00b100 100644
--- a/mako/compat.py
+++ b/mako/compat.py
@@ -30,7 +30,7 @@
return eval("0o" + lit)
else:
- import __builtin__ as compat_builtins
+ import __builtin__ as compat_builtins # noqa
try:
from cStringIO import StringIO
except:
@@ -38,14 +38,14 @@
byte_buffer = StringIO
- from urllib import quote_plus, unquote_plus
- from htmlentitydefs import codepoint2name, name2codepoint
- string_types = basestring,
+ from urllib import quote_plus, unquote_plus # noqa
+ from htmlentitydefs import codepoint2name, name2codepoint # noqa
+ string_types = basestring, # noqa
binary_type = str
- text_type = unicode
+ text_type = unicode # noqa
def u(s):
- return unicode(s, "utf-8")
+ return unicode(s, "utf-8") # noqa
def b(s):
return s
@@ -56,10 +56,12 @@
if py33:
from importlib import machinery
+
def load_module(module_id, path):
return machinery.SourceFileLoader(module_id, path).load_module()
else:
import imp
+
def load_module(module_id, path):
fp = open(path, 'rb')
try:
@@ -77,7 +79,7 @@
raise value
else:
exec("def reraise(tp, value, tb=None, cause=None):\n"
- " raise tp, value, tb\n")
+ " raise tp, value, tb\n")
def exception_as():
@@ -90,11 +92,11 @@
else:
import thread
except ImportError:
- import dummy_threading as threading
+ import dummy_threading as threading # noqa
if py3k:
import _dummy_thread as thread
else:
- import dummy_thread as thread
+ import dummy_thread as thread # noqa
if win32 or jython:
time_func = time.clock
@@ -113,13 +115,15 @@
all = all
-import json
+import json # noqa
+
def exception_name(exc):
return exc.__class__.__name__
try:
from inspect import CO_VARKEYWORDS, CO_VARARGS
+
def inspect_func_args(fn):
if py3k:
co = fn.__code__
@@ -144,6 +148,7 @@
return args, varargs, varkw, fn.func_defaults
except ImportError:
import inspect
+
def inspect_func_args(fn):
return inspect.getargspec(fn)
diff --git a/mako/exceptions.py b/mako/exceptions.py
index c531f21..84d2297 100644
--- a/mako/exceptions.py
+++ b/mako/exceptions.py
@@ -10,12 +10,15 @@
import sys
from mako import util, compat
+
class MakoException(Exception):
pass
+
class RuntimeException(MakoException):
pass
+
def _format_filepos(lineno, pos, filename):
if filename is None:
return " at line: %d char: %d" % (lineno, pos)
@@ -24,42 +27,56 @@
class CompileException(MakoException):
+
def __init__(self, message, source, lineno, pos, filename):
- MakoException.__init__(self,
- message + _format_filepos(lineno, pos, filename))
+ MakoException.__init__(
+ self,
+ message + _format_filepos(lineno, pos, filename))
self.lineno = lineno
self.pos = pos
self.filename = filename
self.source = source
+
class SyntaxException(MakoException):
+
def __init__(self, message, source, lineno, pos, filename):
- MakoException.__init__(self,
- message + _format_filepos(lineno, pos, filename))
+ MakoException.__init__(
+ self,
+ message + _format_filepos(lineno, pos, filename))
self.lineno = lineno
self.pos = pos
self.filename = filename
self.source = source
+
class UnsupportedError(MakoException):
+
"""raised when a retired feature is used."""
+
class NameConflictError(MakoException):
+
"""raised when a reserved word is used inappropriately"""
+
class TemplateLookupException(MakoException):
pass
+
class TopLevelLookupException(TemplateLookupException):
pass
+
class RichTraceback(object):
+
"""Pull the current exception from the ``sys`` traceback and extracts
Mako-specific template information.
See the usage examples in :ref:`handling_exceptions`.
"""
+
def __init__(self, error=None, traceback=None):
self.source, self.lineno = "", 0
@@ -162,18 +179,18 @@
else:
line = line.decode('ascii', 'replace')
new_trcback.append((filename, lineno, function, line,
- None, None, None, None))
+ None, None, None, None))
continue
template_ln = 1
source_map = mako.template.ModuleInfo.\
- get_module_source_metadata(
- module_source, full_line_map=True)
+ get_module_source_metadata(
+ module_source, full_line_map=True)
line_map = source_map['full_line_map']
- template_lines = [line for line in
- template_source.split("\n")]
+ template_lines = [line_ for line_ in
+ template_source.split("\n")]
mods[filename] = (line_map, template_lines)
template_ln = line_map[lineno - 1]
@@ -235,16 +252,19 @@
def _install_pygments():
global syntax_highlight, pygments_html_formatter
- from mako.ext.pygmentplugin import syntax_highlight,\
- pygments_html_formatter
+ from mako.ext.pygmentplugin import syntax_highlight # noqa
+ from mako.ext.pygmentplugin import pygments_html_formatter # noqa
+
def _install_fallback():
global syntax_highlight, pygments_html_formatter
from mako.filters import html_escape
pygments_html_formatter = None
+
def syntax_highlight(filename='', language=None):
return html_escape
+
def _install_highlighting():
try:
_install_pygments()
@@ -252,6 +272,7 @@
_install_fallback()
_install_highlighting()
+
def html_error_template():
"""Provides a template that renders a stack trace in an HTML format,
providing an excerpt of code as well as substituting source template
@@ -370,4 +391,4 @@
</html>
% endif
""", output_encoding=sys.getdefaultencoding(),
- encoding_errors='htmlentityreplace')
+ encoding_errors='htmlentityreplace')
diff --git a/mako/ext/autohandler.py b/mako/ext/autohandler.py
index 8deaae1..9ee780a 100644
--- a/mako/ext/autohandler.py
+++ b/mako/ext/autohandler.py
@@ -25,7 +25,10 @@
"""
-import posixpath, os, re
+import posixpath
+import os
+import re
+
def autohandler(template, context, name='autohandler'):
lookup = context.lookup
@@ -42,24 +45,24 @@
if path != _template_uri and _file_exists(lookup, path):
if not lookup.filesystem_checks:
return lookup._uri_cache.setdefault(
- (autohandler, _template_uri, name), path)
+ (autohandler, _template_uri, name), path)
else:
return path
if len(tokens) == 1:
break
tokens[-2:] = [name]
-
+
if not lookup.filesystem_checks:
return lookup._uri_cache.setdefault(
- (autohandler, _template_uri, name), None)
+ (autohandler, _template_uri, name), None)
else:
return None
+
def _file_exists(lookup, path):
- psub = re.sub(r'^/', '',path)
+ psub = re.sub(r'^/', '', path)
for d in lookup.directories:
if os.path.exists(d + '/' + psub):
return True
else:
return False
-
diff --git a/mako/ext/babelplugin.py b/mako/ext/babelplugin.py
index ead7081..53d62ba 100644
--- a/mako/ext/babelplugin.py
+++ b/mako/ext/babelplugin.py
@@ -10,14 +10,15 @@
class BabelMakoExtractor(MessageExtractor):
+
def __init__(self, keywords, comment_tags, options):
self.keywords = keywords
self.options = options
self.config = {
- 'comment-tags': u' '.join(comment_tags),
- 'encoding': options.get('input_encoding',
- options.get('encoding', None)),
- }
+ 'comment-tags': u' '.join(comment_tags),
+ 'encoding': options.get('input_encoding',
+ options.get('encoding', None)),
+ }
super(BabelMakoExtractor, self).__init__()
def __call__(self, fileobj):
@@ -27,7 +28,7 @@
comment_tags = self.config['comment-tags']
for lineno, funcname, messages, python_translator_comments \
in extract_python(code,
- self.keywords, comment_tags, self.options):
+ self.keywords, comment_tags, self.options):
yield (code_lineno + (lineno - 1), funcname, messages,
translator_strings + python_translator_comments)
diff --git a/mako/ext/beaker_cache.py b/mako/ext/beaker_cache.py
index 40ef774..c7c260d 100644
--- a/mako/ext/beaker_cache.py
+++ b/mako/ext/beaker_cache.py
@@ -15,6 +15,7 @@
class BeakerCacheImpl(CacheImpl):
+
"""A :class:`.CacheImpl` provided for the Beaker caching system.
This plugin is used by default, based on the default
diff --git a/mako/ext/extract.py b/mako/ext/extract.py
index 5ce5175..313c088 100644
--- a/mako/ext/extract.py
+++ b/mako/ext/extract.py
@@ -5,6 +5,7 @@
class MessageExtractor(object):
+
def process_file(self, fileobj):
template_node = lexer.Lexer(
fileobj.read(),
diff --git a/mako/ext/linguaplugin.py b/mako/ext/linguaplugin.py
index a809072..27a1984 100644
--- a/mako/ext/linguaplugin.py
+++ b/mako/ext/linguaplugin.py
@@ -7,6 +7,7 @@
class LinguaMakoExtractor(Extractor, MessageExtractor):
+
'''Mako templates'''
extensions = ['.mako']
default_config = {
diff --git a/mako/ext/preprocessors.py b/mako/ext/preprocessors.py
index c24893b..5624f70 100644
--- a/mako/ext/preprocessors.py
+++ b/mako/ext/preprocessors.py
@@ -4,17 +4,17 @@
# This module is part of Mako and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""preprocessing functions, used with the 'preprocessor'
+"""preprocessing functions, used with the 'preprocessor'
argument on Template, TemplateLookup"""
import re
+
def convert_comments(text):
"""preprocess old style comments.
-
+
example:
-
+
from mako.ext.preprocessors import convert_comments
t = Template(..., preprocessor=convert_comments)"""
return re.sub(r'(?<=\n)\s*#[^#]', "##", text)
-
diff --git a/mako/ext/pygmentplugin.py b/mako/ext/pygmentplugin.py
index 3adcfb8..1121c5d 100644
--- a/mako/ext/pygmentplugin.py
+++ b/mako/ext/pygmentplugin.py
@@ -5,16 +5,17 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from pygments.lexers.web import \
- HtmlLexer, XmlLexer, JavascriptLexer, CssLexer
+ HtmlLexer, XmlLexer, JavascriptLexer, CssLexer
from pygments.lexers.agile import PythonLexer, Python3Lexer
from pygments.lexer import DelegatingLexer, RegexLexer, bygroups, \
- include, using
+ include, using
from pygments.token import \
- Text, Comment, Operator, Keyword, Name, String, Other
+ Text, Comment, Operator, Keyword, Name, String, Other
from pygments.formatters.html import HtmlFormatter
from pygments import highlight
from mako import compat
+
class MakoLexer(RegexLexer):
name = 'Mako'
aliases = ['mako']
@@ -27,15 +28,15 @@
(r'(\s*)(\%(?!%))([^\n]*)(\n|\Z)',
bygroups(Text, Comment.Preproc, using(PythonLexer), Other)),
(r'(\s*)(##[^\n]*)(\n|\Z)',
- bygroups(Text, Comment.Preproc, Other)),
+ bygroups(Text, Comment.Preproc, Other)),
(r'''(?s)<%doc>.*?</%doc>''', Comment.Preproc),
(r'(<%)([\w\.\:]+)',
- bygroups(Comment.Preproc, Name.Builtin), 'tag'),
+ bygroups(Comment.Preproc, Name.Builtin), 'tag'),
(r'(</%)([\w\.\:]+)(>)',
- bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc)),
+ bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc)),
(r'<%(?=([\w\.\:]+))', Comment.Preproc, 'ondeftags'),
(r'(<%(?:!?))(.*?)(%>)(?s)',
- bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
+ bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
(r'(\$\{)(.*?)(\})',
bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)),
(r'''(?sx)
@@ -79,7 +80,8 @@
def __init__(self, **options):
super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer,
- **options)
+ **options)
+
class MakoXmlLexer(DelegatingLexer):
name = 'XML+Mako'
@@ -87,7 +89,8 @@
def __init__(self, **options):
super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer,
- **options)
+ **options)
+
class MakoJavascriptLexer(DelegatingLexer):
name = 'JavaScript+Mako'
@@ -95,7 +98,8 @@
def __init__(self, **options):
super(MakoJavascriptLexer, self).__init__(JavascriptLexer,
- MakoLexer, **options)
+ MakoLexer, **options)
+
class MakoCssLexer(DelegatingLexer):
name = 'CSS+Mako'
@@ -103,11 +107,13 @@
def __init__(self, **options):
super(MakoCssLexer, self).__init__(CssLexer, MakoLexer,
- **options)
+ **options)
pygments_html_formatter = HtmlFormatter(cssclass='syntax-highlighted',
linenos=True)
+
+
def syntax_highlight(filename='', language=None):
mako_lexer = MakoLexer()
if compat.py3k:
@@ -119,4 +125,3 @@
pygments_html_formatter)
return lambda string: highlight(string, python_lexer,
pygments_html_formatter)
-
diff --git a/mako/ext/turbogears.py b/mako/ext/turbogears.py
index d3976d9..1a9f656 100644
--- a/mako/ext/turbogears.py
+++ b/mako/ext/turbogears.py
@@ -9,7 +9,9 @@
from mako.lookup import TemplateLookup
from mako.template import Template
+
class TGPlugin(object):
+
"""TurboGears compatible Template Plugin."""
def __init__(self, extra_vars_func=None, options=None, extension='mak'):
@@ -41,7 +43,7 @@
# Translate TG dot notation to normal / template path
if '/' not in templatename:
templatename = '/' + templatename.replace('.', '/') + '.' +\
- self.extension
+ self.extension
# Lookup template
return self.lookup.get_template(templatename)
@@ -55,4 +57,3 @@
info.update(self.extra_vars_func())
return template.render(**info)
-
diff --git a/mako/filters.py b/mako/filters.py
index d79ce23..525aeb8 100644
--- a/mako/filters.py
+++ b/mako/filters.py
@@ -9,7 +9,7 @@
import codecs
from mako.compat import quote_plus, unquote_plus, codepoint2name, \
- name2codepoint
+ name2codepoint
from mako import compat
@@ -24,6 +24,7 @@
# XXX: " is valid in HTML and XML
# ' is not valid HTML, but is valid XML
+
def legacy_html_escape(s):
"""legacy HTML escape for non-unicode mode."""
s = s.replace("&", "&")
@@ -40,29 +41,35 @@
except ImportError:
html_escape = legacy_html_escape
+
def xml_escape(string):
return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string)
+
def url_escape(string):
# convert into a list of octets
string = string.encode("utf8")
return quote_plus(string)
+
def legacy_url_escape(string):
# convert into a list of octets
return quote_plus(string)
+
def url_unescape(string):
text = unquote_plus(string)
if not is_ascii_str(text):
text = text.decode("utf8")
return text
+
def trim(string):
return string.strip()
class Decode(object):
+
def __getattr__(self, key):
def decode(x):
if isinstance(x, compat.text_type):
@@ -77,12 +84,15 @@
_ASCII_re = re.compile(r'\A[\x00-\x7f]*\Z')
+
def is_ascii_str(text):
return isinstance(text, str) and _ASCII_re.match(text)
################################################################
+
class XMLEntityEscaper(object):
+
def __init__(self, codepoint2name, name2codepoint):
self.codepoint2entity = dict([(c, compat.text_type('&%s;' % n))
for c, n in codepoint2name.items()])
@@ -102,7 +112,6 @@
except (KeyError, IndexError):
return '&#x%X;' % codepoint
-
__escapable = re.compile(r'["&<>]|[^\x00-\x7f]')
def escape(self, text):
@@ -198,4 +207,3 @@
NON_UNICODE_ESCAPES = DEFAULT_ESCAPES.copy()
NON_UNICODE_ESCAPES['h'] = 'filters.legacy_html_escape'
NON_UNICODE_ESCAPES['u'] = 'filters.legacy_url_escape'
-
diff --git a/mako/lexer.py b/mako/lexer.py
index 1dda398..2fa08e4 100644
--- a/mako/lexer.py
+++ b/mako/lexer.py
@@ -13,10 +13,12 @@
_regexp_cache = {}
+
class Lexer(object):
+
def __init__(self, text, filename=None,
- disable_unicode=False,
- input_encoding=None, preprocessor=None):
+ disable_unicode=False,
+ input_encoding=None, preprocessor=None):
self.text = text
self.filename = filename
self.template = parsetree.TemplateNode(self.filename)
@@ -32,8 +34,8 @@
if compat.py3k and disable_unicode:
raise exceptions.UnsupportedError(
- "Mako for Python 3 does not "
- "support disabling Unicode")
+ "Mako for Python 3 does not "
+ "support disabling Unicode")
if preprocessor is None:
self.preprocessor = []
@@ -87,9 +89,9 @@
cp -= 1
self.matched_charpos = mp - cp
self.lineno += len(lines)
- #print "MATCHED:", match.group(0), "LINE START:",
+ # print "MATCHED:", match.group(0), "LINE START:",
# self.matched_lineno, "LINE END:", self.lineno
- #print "MATCH:", regexp, "\n", self.text[mp : mp + 15], \
+ # print "MATCH:", regexp, "\n", self.text[mp : mp + 15], \
# (match and "TRUE" or "FALSE")
return match
@@ -120,9 +122,9 @@
brace_level -= match.group(1).count('}')
continue
raise exceptions.SyntaxException(
- "Expected: %s" %
- ','.join(text),
- **self.exception_kwargs)
+ "Expected: %s" %
+ ','.join(text),
+ **self.exception_kwargs)
def append_node(self, nodecls, *args, **kwargs):
kwargs.setdefault('source', self.text)
@@ -162,9 +164,9 @@
elif self.control_line and \
not self.control_line[-1].is_ternary(node.keyword):
raise exceptions.SyntaxException(
- "Keyword '%s' not a legal ternary for keyword '%s'" %
- (node.keyword, self.control_line[-1].keyword),
- **self.exception_kwargs)
+ "Keyword '%s' not a legal ternary for keyword '%s'" %
+ (node.keyword, self.control_line[-1].keyword),
+ **self.exception_kwargs)
_coding_re = re.compile(r'#.*coding[:=]\s*([-\w.]+).*\r?\n')
@@ -185,10 +187,10 @@
m = self._coding_re.match(text.decode('utf-8', 'ignore'))
if m is not None and m.group(1) != 'utf-8':
raise exceptions.CompileException(
- "Found utf-8 BOM in file, with conflicting "
- "magic encoding comment of '%s'" % m.group(1),
- text.decode('utf-8', 'ignore'),
- 0, 0, filename)
+ "Found utf-8 BOM in file, with conflicting "
+ "magic encoding comment of '%s'" % m.group(1),
+ text.decode('utf-8', 'ignore'),
+ 0, 0, filename)
else:
m = self._coding_re.match(text.decode('utf-8', 'ignore'))
if m:
@@ -201,18 +203,19 @@
text = text.decode(parsed_encoding)
except UnicodeDecodeError:
raise exceptions.CompileException(
- "Unicode decode operation of encoding '%s' failed" %
- parsed_encoding,
- text.decode('utf-8', 'ignore'),
- 0, 0, filename)
+ "Unicode decode operation of encoding '%s' failed" %
+ parsed_encoding,
+ text.decode('utf-8', 'ignore'),
+ 0, 0, filename)
return parsed_encoding, text
def parse(self):
- self.encoding, self.text = self.decode_raw_stream(self.text,
- not self.disable_unicode,
- self.encoding,
- self.filename,)
+ self.encoding, self.text = self.decode_raw_stream(
+ self.text,
+ not self.disable_unicode,
+ self.encoding,
+ self.filename)
for preproc in self.preprocessor:
self.text = preproc(self.text)
@@ -250,15 +253,15 @@
if len(self.tag):
raise exceptions.SyntaxException("Unclosed tag: <%%%s>" %
- self.tag[-1].keyword,
- **self.exception_kwargs)
+ self.tag[-1].keyword,
+ **self.exception_kwargs)
if len(self.control_line):
raise exceptions.SyntaxException(
- "Unterminated control keyword: '%s'" %
- self.control_line[-1].keyword,
- self.text,
- self.control_line[-1].lineno,
- self.control_line[-1].pos, self.filename)
+ "Unterminated control keyword: '%s'" %
+ self.control_line[-1].keyword,
+ self.text,
+ self.control_line[-1].lineno,
+ self.control_line[-1].pos, self.filename)
return self.template
def match_tag_start(self):
@@ -276,7 +279,7 @@
''',
- re.I | re.S | re.X)
+ re.I | re.S | re.X)
if match:
keyword, attr, isend = match.groups()
@@ -284,7 +287,7 @@
attributes = {}
if attr:
for att in re.findall(
- r"\s*(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\")", attr):
+ r"\s*(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\")", attr):
key, val1, val2 = att
text = val1 or val2
text = text.replace('\r\n', '\n')
@@ -294,12 +297,12 @@
self.tag.pop()
else:
if keyword == 'text':
- match = self.match(r'(.*?)(?=\</%text>)', re.S)
+ match = self.match(r'(.*?)(?=\</%text>)', re.S)
if not match:
raise exceptions.SyntaxException(
- "Unclosed tag: <%%%s>" %
- self.tag[-1].keyword,
- **self.exception_kwargs)
+ "Unclosed tag: <%%%s>" %
+ self.tag[-1].keyword,
+ **self.exception_kwargs)
self.append_node(parsetree.Text, match.group(1))
return self.match_tag_end()
return True
@@ -311,14 +314,14 @@
if match:
if not len(self.tag):
raise exceptions.SyntaxException(
- "Closing tag without opening tag: </%%%s>" %
- match.group(1),
- **self.exception_kwargs)
+ "Closing tag without opening tag: </%%%s>" %
+ match.group(1),
+ **self.exception_kwargs)
elif self.tag[-1].keyword != match.group(1):
raise exceptions.SyntaxException(
- "Closing tag </%%%s> does not match tag: <%%%s>" %
- (match.group(1), self.tag[-1].keyword),
- **self.exception_kwargs)
+ "Closing tag </%%%s> does not match tag: <%%%s>" %
+ (match.group(1), self.tag[-1].keyword),
+ **self.exception_kwargs)
self.tag.pop()
return True
else:
@@ -370,9 +373,9 @@
# compiler.parse() not complain about indentation
text = adjust_whitespace(text) + "\n"
self.append_node(
- parsetree.Code,
- text,
- match.group(1) == '!', lineno=line, pos=pos)
+ parsetree.Code,
+ text,
+ match.group(1) == '!', lineno=line, pos=pos)
return True
else:
return False
@@ -388,17 +391,17 @@
escapes = ""
text = text.replace('\r\n', '\n')
self.append_node(
- parsetree.Expression,
- text, escapes.strip(),
- lineno=line, pos=pos)
+ parsetree.Expression,
+ text, escapes.strip(),
+ lineno=line, pos=pos)
return True
else:
return False
def match_control_line(self):
match = self.match(
- r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)"
- r"(?:\r?\n|\Z)", re.M)
+ r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)"
+ r"(?:\r?\n|\Z)", re.M)
if match:
operator = match.group(1)
text = match.group(2)
@@ -406,23 +409,23 @@
m2 = re.match(r'(end)?(\w+)\s*(.*)', text)
if not m2:
raise exceptions.SyntaxException(
- "Invalid control line: '%s'" %
- text,
- **self.exception_kwargs)
+ "Invalid control line: '%s'" %
+ text,
+ **self.exception_kwargs)
isend, keyword = m2.group(1, 2)
isend = (isend is not None)
if isend:
if not len(self.control_line):
raise exceptions.SyntaxException(
- "No starting keyword '%s' for '%s'" %
- (keyword, text),
- **self.exception_kwargs)
+ "No starting keyword '%s' for '%s'" %
+ (keyword, text),
+ **self.exception_kwargs)
elif self.control_line[-1].keyword != keyword:
raise exceptions.SyntaxException(
- "Keyword '%s' doesn't match keyword '%s'" %
- (text, self.control_line[-1].keyword),
- **self.exception_kwargs)
+ "Keyword '%s' doesn't match keyword '%s'" %
+ (text, self.control_line[-1].keyword),
+ **self.exception_kwargs)
self.append_node(parsetree.ControlLine, keyword, isend, text)
else:
self.append_node(parsetree.Comment, text)
@@ -438,4 +441,3 @@
return True
else:
return False
-
diff --git a/mako/lookup.py b/mako/lookup.py
index 2af5411..794d853 100644
--- a/mako/lookup.py
+++ b/mako/lookup.py
@@ -4,7 +4,10 @@
# This module is part of Mako and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-import os, stat, posixpath, re
+import os
+import stat
+import posixpath
+import re
from mako import exceptions, util
from mako.template import Template
@@ -13,7 +16,9 @@
except:
import dummy_threading as threading
+
class TemplateCollection(object):
+
"""Represent a collection of :class:`.Template` objects,
identifiable via URI.
@@ -79,7 +84,9 @@
"""
return uri
+
class TemplateLookup(TemplateCollection):
+
"""Represent a collection of templates that locates template source files
from the local filesystem.
@@ -145,35 +152,35 @@
"""
def __init__(self,
- directories=None,
- module_directory=None,
- filesystem_checks=True,
- collection_size=-1,
- format_exceptions=False,
- error_handler=None,
- disable_unicode=False,
- bytestring_passthrough=False,
- output_encoding=None,
- encoding_errors='strict',
+ directories=None,
+ module_directory=None,
+ filesystem_checks=True,
+ collection_size=-1,
+ format_exceptions=False,
+ error_handler=None,
+ disable_unicode=False,
+ bytestring_passthrough=False,
+ output_encoding=None,
+ encoding_errors='strict',
- cache_args=None,
- cache_impl='beaker',
- cache_enabled=True,
- cache_type=None,
- cache_dir=None,
- cache_url=None,
+ cache_args=None,
+ cache_impl='beaker',
+ cache_enabled=True,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
- modulename_callable=None,
- module_writer=None,
- default_filters=None,
- buffer_filters=(),
- strict_undefined=False,
- imports=None,
- future_imports=None,
- enable_loop=True,
- input_encoding=None,
- preprocessor=None,
- lexer_cls=None):
+ modulename_callable=None,
+ module_writer=None,
+ default_filters=None,
+ buffer_filters=(),
+ strict_undefined=False,
+ imports=None,
+ future_imports=None,
+ enable_loop=True,
+ input_encoding=None,
+ preprocessor=None,
+ lexer_cls=None):
self.directories = [posixpath.normpath(d) for d in
util.to_list(directories, ())
@@ -194,26 +201,26 @@
cache_args.setdefault('type', cache_type)
self.template_args = {
- 'format_exceptions':format_exceptions,
- 'error_handler':error_handler,
- 'disable_unicode':disable_unicode,
- 'bytestring_passthrough':bytestring_passthrough,
- 'output_encoding':output_encoding,
- 'cache_impl':cache_impl,
- 'encoding_errors':encoding_errors,
- 'input_encoding':input_encoding,
- 'module_directory':module_directory,
- 'module_writer':module_writer,
- 'cache_args':cache_args,
- 'cache_enabled':cache_enabled,
- 'default_filters':default_filters,
- 'buffer_filters':buffer_filters,
- 'strict_undefined':strict_undefined,
- 'imports':imports,
- 'future_imports':future_imports,
- 'enable_loop':enable_loop,
- 'preprocessor':preprocessor,
- 'lexer_cls':lexer_cls
+ 'format_exceptions': format_exceptions,
+ 'error_handler': error_handler,
+ 'disable_unicode': disable_unicode,
+ 'bytestring_passthrough': bytestring_passthrough,
+ 'output_encoding': output_encoding,
+ 'cache_impl': cache_impl,
+ 'encoding_errors': encoding_errors,
+ 'input_encoding': input_encoding,
+ 'module_directory': module_directory,
+ 'module_writer': module_writer,
+ 'cache_args': cache_args,
+ 'cache_enabled': cache_enabled,
+ 'default_filters': default_filters,
+ 'buffer_filters': buffer_filters,
+ 'strict_undefined': strict_undefined,
+ 'imports': imports,
+ 'future_imports': future_imports,
+ 'enable_loop': enable_loop,
+ 'preprocessor': preprocessor,
+ 'lexer_cls': lexer_cls
}
if collection_size == -1:
@@ -228,7 +235,8 @@
"""Return a :class:`.Template` object corresponding to the given
``uri``.
- .. note:: The ``relativeto`` argument is not supported here at the moment.
+ .. note:: The ``relativeto`` argument is not supported here at
+ the moment.
"""
@@ -245,7 +253,7 @@
return self._load(srcfile, uri)
else:
raise exceptions.TopLevelLookupException(
- "Cant locate template for uri %r" % uri)
+ "Cant locate template for uri %r" % uri)
def adjust_uri(self, uri, relativeto):
"""Adjust the given ``uri`` based on the given relative URI."""
@@ -257,14 +265,13 @@
if uri[0] != '/':
if relativeto is not None:
v = self._uri_cache[key] = posixpath.join(
- posixpath.dirname(relativeto), uri)
+ posixpath.dirname(relativeto), uri)
else:
v = self._uri_cache[key] = '/' + uri
else:
v = self._uri_cache[key] = uri
return v
-
def filename_to_uri(self, filename):
"""Convert the given ``filename`` to a URI relative to
this :class:`.TemplateCollection`."""
@@ -304,11 +311,11 @@
else:
module_filename = None
self._collection[uri] = template = Template(
- uri=uri,
- filename=posixpath.normpath(filename),
- lookup=self,
- module_filename=module_filename,
- **self.template_args)
+ uri=uri,
+ filename=posixpath.normpath(filename),
+ lookup=self,
+ module_filename=module_filename,
+ **self.template_args)
return template
except:
# if compilation fails etc, ensure
@@ -326,7 +333,7 @@
try:
template_stat = os.stat(template.filename)
if template.module._modified_time < \
- template_stat[stat.ST_MTIME]:
+ template_stat[stat.ST_MTIME]:
self._collection.pop(uri, None)
return self._load(template.filename, uri)
else:
@@ -334,8 +341,7 @@
except OSError:
self._collection.pop(uri, None)
raise exceptions.TemplateLookupException(
- "Cant locate template for uri %r" % uri)
-
+ "Cant locate template for uri %r" % uri)
def put_string(self, uri, text):
"""Place a new :class:`.Template` object into this
@@ -344,10 +350,10 @@
"""
self._collection[uri] = Template(
- text,
- lookup=self,
- uri=uri,
- **self.template_args)
+ text,
+ lookup=self,
+ uri=uri,
+ **self.template_args)
def put_template(self, uri, template):
"""Place a new :class:`.Template` object into this
@@ -356,4 +362,3 @@
"""
self._collection[uri] = template
-
diff --git a/mako/parsetree.py b/mako/parsetree.py
index 49ec4e0..e7af4bc 100644
--- a/mako/parsetree.py
+++ b/mako/parsetree.py
@@ -9,7 +9,9 @@
from mako import exceptions, ast, util, filters, compat
import re
+
class Node(object):
+
"""base class for a Node in the parse tree."""
def __init__(self, source, lineno, pos, filename):
@@ -34,7 +36,9 @@
method = getattr(visitor, "visit" + self.__class__.__name__, traverse)
method(self)
+
class TemplateNode(Node):
+
"""a 'container' node that stores the overall collection of nodes."""
def __init__(self, filename):
@@ -47,10 +51,12 @@
def __repr__(self):
return "TemplateNode(%s, %r)" % (
- util.sorted_dict_repr(self.page_attributes),
- self.nodes)
+ util.sorted_dict_repr(self.page_attributes),
+ self.nodes)
+
class ControlLine(Node):
+
"""defines a control line, a line-oriented python line or end tag.
e.g.::
@@ -92,9 +98,9 @@
for this ControlLine"""
return keyword in {
- 'if':set(['else', 'elif']),
- 'try':set(['except', 'finally']),
- 'for':set(['else'])
+ 'if': set(['else', 'elif']),
+ 'try': set(['except', 'finally']),
+ 'for': set(['else'])
}.get(self.keyword, [])
def __repr__(self):
@@ -105,7 +111,9 @@
(self.lineno, self.pos)
)
+
class Text(Node):
+
"""defines plain text in the template."""
def __init__(self, content, **kwargs):
@@ -115,7 +123,9 @@
def __repr__(self):
return "Text(%r, %r)" % (self.content, (self.lineno, self.pos))
+
class Code(Node):
+
"""defines a Python code block, either inline or module level.
e.g.::
@@ -151,7 +161,9 @@
(self.lineno, self.pos)
)
+
class Comment(Node):
+
"""defines a comment line.
# this is a comment
@@ -165,7 +177,9 @@
def __repr__(self):
return "Comment(%r, %r)" % (self.text, (self.lineno, self.pos))
+
class Expression(Node):
+
"""defines an inline expression.
${x+y}
@@ -185,10 +199,10 @@
def undeclared_identifiers(self):
# TODO: make the "filter" shortcut list configurable at parse/gen time
return self.code.undeclared_identifiers.union(
- self.escapes_code.undeclared_identifiers.difference(
- set(filters.DEFAULT_ESCAPES.keys())
- )
- ).difference(self.code.declared_identifiers)
+ self.escapes_code.undeclared_identifiers.difference(
+ set(filters.DEFAULT_ESCAPES.keys())
+ )
+ ).difference(self.code.declared_identifiers)
def __repr__(self):
return "Expression(%r, %r, %r)" % (
@@ -197,7 +211,9 @@
(self.lineno, self.pos)
)
+
class _TagMeta(type):
+
"""metaclass to allow Tag to produce a subclass according to
its keyword"""
@@ -212,7 +228,7 @@
if ":" in keyword:
ns, defname = keyword.split(':')
return type.__call__(CallNamespaceTag, ns, defname,
- attributes, **kwargs)
+ attributes, **kwargs)
try:
cls = _TagMeta._classmap[keyword]
@@ -226,7 +242,9 @@
)
return type.__call__(cls, keyword, attributes, **kwargs)
+
class Tag(compat.with_metaclass(_TagMeta, Node)):
+
"""abstract base class for tags.
<%sometag/>
@@ -239,7 +257,7 @@
__keyword__ = None
def __init__(self, keyword, attributes, expressions,
- nonexpressions, required, **kwargs):
+ nonexpressions, required, **kwargs):
"""construct a new Tag instance.
this constructor not called directly, and is only called
@@ -267,7 +285,7 @@
if len(missing):
raise exceptions.CompileException(
"Missing attribute(s): %s" %
- ",".join([repr(m) for m in missing]),
+ ",".join([repr(m) for m in missing]),
**self.exception_kwargs)
self.parent = None
self.nodes = []
@@ -289,14 +307,14 @@
m = re.compile(r'^\${(.+?)}$', re.S).match(x)
if m:
code = ast.PythonCode(m.group(1).rstrip(),
- **self.exception_kwargs)
+ **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.
undeclared_identifiers = \
undeclared_identifiers.union(
- code.undeclared_identifiers)
+ code.undeclared_identifiers)
expr.append('(%s)' % m.group(1))
else:
if x:
@@ -305,15 +323,15 @@
elif key in nonexpressions:
if re.search(r'\${.+?}', self.attributes[key]):
raise exceptions.CompileException(
- "Attibute '%s' in tag '%s' does not allow embedded "
- "expressions" % (key, self.keyword),
- **self.exception_kwargs)
+ "Attibute '%s' in tag '%s' does not allow embedded "
+ "expressions" % (key, self.keyword),
+ **self.exception_kwargs)
self.parsed_attributes[key] = repr(self.attributes[key])
else:
raise exceptions.CompileException(
- "Invalid attribute for tag '%s': '%s'" %
- (self.keyword, key),
- **self.exception_kwargs)
+ "Invalid attribute for tag '%s': '%s'" %
+ (self.keyword, key),
+ **self.exception_kwargs)
self.expression_undeclared_identifiers = undeclared_identifiers
def declared_identifiers(self):
@@ -324,48 +342,50 @@
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'
def __init__(self, keyword, attributes, **kwargs):
super(IncludeTag, self).__init__(
- keyword,
- attributes,
- ('file', 'import', 'args'),
- (), ('file',), **kwargs)
+ keyword,
+ attributes,
+ ('file', 'import', 'args'),
+ (), ('file',), **kwargs)
self.page_args = ast.PythonCode(
- "__DUMMY(%s)" % attributes.get('args', ''),
- **self.exception_kwargs)
+ "__DUMMY(%s)" % attributes.get('args', ''),
+ **self.exception_kwargs)
def declared_identifiers(self):
return []
def undeclared_identifiers(self):
identifiers = self.page_args.undeclared_identifiers.\
- difference(set(["__DUMMY"])).\
- difference(self.page_args.declared_identifiers)
+ difference(set(["__DUMMY"])).\
+ difference(self.page_args.declared_identifiers)
return identifiers.union(super(IncludeTag, self).
- undeclared_identifiers())
+ undeclared_identifiers())
+
class NamespaceTag(Tag):
__keyword__ = 'namespace'
def __init__(self, keyword, attributes, **kwargs):
super(NamespaceTag, self).__init__(
- keyword, attributes,
- ('file',),
- ('name','inheritable',
- 'import','module'),
- (), **kwargs)
+ keyword, attributes,
+ ('file',),
+ ('name', 'inheritable',
+ 'import', 'module'),
+ (), **kwargs)
self.name = attributes.get('name', '__anon_%s' % hex(abs(id(self))))
- if not 'name' in attributes and not 'import' in attributes:
+ if 'name' not in attributes and 'import' not in attributes:
raise exceptions.CompileException(
"'name' and/or 'import' attributes are required "
"for <%namespace>",
@@ -379,52 +399,53 @@
def declared_identifiers(self):
return []
+
class TextTag(Tag):
__keyword__ = 'text'
def __init__(self, keyword, attributes, **kwargs):
super(TextTag, self).__init__(
- keyword,
- attributes, (),
- ('filter'), (), **kwargs)
+ keyword,
+ attributes, (),
+ ('filter'), (), **kwargs)
self.filter_args = ast.ArgumentList(
- attributes.get('filter', ''),
- **self.exception_kwargs)
+ attributes.get('filter', ''),
+ **self.exception_kwargs)
def undeclared_identifiers(self):
return self.filter_args.\
- undeclared_identifiers.\
- difference(filters.DEFAULT_ESCAPES.keys()).union(
- self.expression_undeclared_identifiers
- )
+ undeclared_identifiers.\
+ difference(filters.DEFAULT_ESCAPES.keys()).union(
+ self.expression_undeclared_identifiers
+ )
+
class DefTag(Tag):
__keyword__ = 'def'
def __init__(self, keyword, attributes, **kwargs):
expressions = ['buffered', 'cached'] + [
- c for c in attributes if c.startswith('cache_')]
-
+ c for c in attributes if c.startswith('cache_')]
super(DefTag, self).__init__(
- keyword,
- attributes,
- expressions,
- ('name', 'filter', 'decorator'),
- ('name',),
- **kwargs)
+ keyword,
+ attributes,
+ expressions,
+ ('name', 'filter', 'decorator'),
+ ('name',),
+ **kwargs)
name = attributes['name']
if re.match(r'^[\w_]+$', name):
raise exceptions.CompileException(
- "Missing parenthesis in %def",
- **self.exception_kwargs)
+ "Missing parenthesis in %def",
+ **self.exception_kwargs)
self.function_decl = ast.FunctionDecl("def " + name + ":pass",
- **self.exception_kwargs)
+ **self.exception_kwargs)
self.name = self.function_decl.funcname
self.decorator = attributes.get('decorator', '')
self.filter_args = ast.ArgumentList(
- attributes.get('filter', ''),
- **self.exception_kwargs)
+ attributes.get('filter', ''),
+ **self.exception_kwargs)
is_anonymous = False
is_block = False
@@ -443,50 +464,50 @@
res = []
for c in self.function_decl.defaults:
res += list(ast.PythonCode(c, **self.exception_kwargs).
- undeclared_identifiers)
+ undeclared_identifiers)
return set(res).union(
- self.filter_args.\
- undeclared_identifiers.\
- difference(filters.DEFAULT_ESCAPES.keys())
+ self.filter_args.
+ undeclared_identifiers.
+ difference(filters.DEFAULT_ESCAPES.keys())
).union(
self.expression_undeclared_identifiers
).difference(
self.function_decl.allargnames
)
+
class BlockTag(Tag):
__keyword__ = 'block'
def __init__(self, keyword, attributes, **kwargs):
expressions = ['buffered', 'cached', 'args'] + [
- c for c in attributes if c.startswith('cache_')]
+ c for c in attributes if c.startswith('cache_')]
super(BlockTag, self).__init__(
- keyword,
- attributes,
- expressions,
- ('name','filter', 'decorator'),
- (),
- **kwargs)
+ keyword,
+ attributes,
+ expressions,
+ ('name', 'filter', 'decorator'),
+ (),
+ **kwargs)
name = attributes.get('name')
- if name and not re.match(r'^[\w_]+$',name):
+ if name and not re.match(r'^[\w_]+$', name):
raise exceptions.CompileException(
- "%block may not specify an argument signature",
- **self.exception_kwargs)
+ "%block may not specify an argument signature",
+ **self.exception_kwargs)
if not name and attributes.get('args', None):
raise exceptions.CompileException(
- "Only named %blocks may specify args",
- **self.exception_kwargs
- )
+ "Only named %blocks may specify args",
+ **self.exception_kwargs
+ )
self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
- **self.exception_kwargs)
+ **self.exception_kwargs)
self.name = name
self.decorator = attributes.get('decorator', '')
self.filter_args = ast.ArgumentList(
- attributes.get('filter', ''),
- **self.exception_kwargs)
-
+ attributes.get('filter', ''),
+ **self.exception_kwargs)
is_block = True
@@ -505,90 +526,91 @@
return self.body_decl.allargnames
def undeclared_identifiers(self):
- return (self.filter_args.\
- undeclared_identifiers.\
- difference(filters.DEFAULT_ESCAPES.keys())
+ return (self.filter_args.
+ undeclared_identifiers.
+ difference(filters.DEFAULT_ESCAPES.keys())
).union(self.expression_undeclared_identifiers)
-
class CallTag(Tag):
__keyword__ = 'call'
def __init__(self, keyword, attributes, **kwargs):
super(CallTag, self).__init__(keyword, attributes,
- ('args'), ('expr',), ('expr',), **kwargs)
+ ('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.exception_kwargs)
def declared_identifiers(self):
return self.code.declared_identifiers.union(self.body_decl.allargnames)
def undeclared_identifiers(self):
return self.code.undeclared_identifiers.\
- difference(self.code.declared_identifiers)
+ difference(self.code.declared_identifiers)
+
class CallNamespaceTag(Tag):
def __init__(self, namespace, defname, attributes, **kwargs):
super(CallNamespaceTag, self).__init__(
- namespace + ":" + defname,
- attributes,
- tuple(attributes.keys()) + ('args', ),
- (),
- (),
- **kwargs)
+ namespace + ":" + defname,
+ attributes,
+ tuple(attributes.keys()) + ('args', ),
+ (),
+ (),
+ **kwargs)
self.expression = "%s.%s(%s)" % (
- namespace,
- defname,
- ",".join(["%s=%s" % (k, v) for k, v in
- self.parsed_attributes.items()
- if k != 'args'])
- )
+ namespace,
+ defname,
+ ",".join(["%s=%s" % (k, v) for k, v in
+ self.parsed_attributes.items()
+ if k != 'args'])
+ )
self.code = ast.PythonCode(self.expression, **self.exception_kwargs)
self.body_decl = ast.FunctionArgs(
- attributes.get('args', ''),
- **self.exception_kwargs)
+ attributes.get('args', ''),
+ **self.exception_kwargs)
def declared_identifiers(self):
return self.code.declared_identifiers.union(self.body_decl.allargnames)
def undeclared_identifiers(self):
return self.code.undeclared_identifiers.\
- difference(self.code.declared_identifiers)
+ difference(self.code.declared_identifiers)
+
class InheritTag(Tag):
__keyword__ = 'inherit'
def __init__(self, keyword, attributes, **kwargs):
super(InheritTag, self).__init__(
- keyword, attributes,
- ('file',), (), ('file',), **kwargs)
+ keyword, attributes,
+ ('file',), (), ('file',), **kwargs)
+
class PageTag(Tag):
__keyword__ = 'page'
def __init__(self, keyword, attributes, **kwargs):
- expressions = ['cached', 'args', 'expression_filter', 'enable_loop'] + [
- c for c in attributes if c.startswith('cache_')]
+ expressions = \
+ ['cached', 'args', 'expression_filter', 'enable_loop'] + \
+ [c for c in attributes if c.startswith('cache_')]
super(PageTag, self).__init__(
- keyword,
- attributes,
- expressions,
- (),
- (),
- **kwargs)
+ keyword,
+ attributes,
+ expressions,
+ (),
+ (),
+ **kwargs)
self.body_decl = ast.FunctionArgs(attributes.get('args', ''),
- **self.exception_kwargs)
+ **self.exception_kwargs)
self.filter_args = ast.ArgumentList(
- attributes.get('expression_filter', ''),
- **self.exception_kwargs)
+ attributes.get('expression_filter', ''),
+ **self.exception_kwargs)
def declared_identifiers(self):
return self.body_decl.allargnames
-
-
diff --git a/mako/pygen.py b/mako/pygen.py
index 5ba5125..5d87bbd 100644
--- a/mako/pygen.py
+++ b/mako/pygen.py
@@ -9,7 +9,9 @@
import re
from mako import exceptions
+
class PythonPrinter(object):
+
def __init__(self, stream):
# indentation counter
self.indent = 0
@@ -80,10 +82,11 @@
self._flush_adjusted_lines()
self.in_indent_lines = True
- if (line is None or
- re.match(r"^\s*#",line) or
+ if (
+ line is None or
+ re.match(r"^\s*#", line) or
re.match(r"^\s*$", line)
- ):
+ ):
hastext = False
else:
hastext = True
@@ -91,9 +94,10 @@
is_comment = line and len(line) and line[0] == '#'
# see if this line should decrease the indentation level
- if (not is_comment and
+ if (
+ not is_comment and
(not hastext or self._is_unindentor(line))
- ):
+ ):
if self.indent > 0:
self.indent -= 1
@@ -102,7 +106,7 @@
# module wont compile.
if len(self.indent_detail) == 0:
raise exceptions.SyntaxException(
- "Too many whitespace closures")
+ "Too many whitespace closures")
self.indent_detail.pop()
if line is None:
@@ -172,18 +176,18 @@
# should we decide that its not good enough, heres
# more stuff to check.
- #keyword = match.group(1)
+ # keyword = match.group(1)
# match the original indent keyword
- #for crit in [
+ # for crit in [
# (r'if|elif', r'else|elif'),
# (r'try', r'except|finally|else'),
# (r'while|for', r'else'),
- #]:
+ # ]:
# if re.match(crit[0], indentor) and re.match(crit[1], keyword):
# return True
- #return False
+ # return False
def _indent_line(self, line, stripspace=''):
"""indent the given line according to the current indent level.
diff --git a/mako/pyparser.py b/mako/pyparser.py
index bfa46a9..96e5335 100644
--- a/mako/pyparser.py
+++ b/mako/pyparser.py
@@ -41,11 +41,11 @@
return _ast_util.parse(code, '<unknown>', mode)
except Exception:
raise exceptions.SyntaxException(
- "(%s) %s (%r)" % (
- compat.exception_as().__class__.__name__,
- compat.exception_as(),
- code[0:50]
- ), **exception_kwargs)
+ "(%s) %s (%r)" % (
+ compat.exception_as().__class__.__name__,
+ compat.exception_as(),
+ code[0:50]
+ ), **exception_kwargs)
class FindIdentifiers(_ast_util.NodeVisitor):
@@ -186,10 +186,10 @@
self.listener.args.append(ExpressionGenerator(n).value())
self.listener.declared_identifiers = \
self.listener.declared_identifiers.union(
- p.declared_identifiers)
+ p.declared_identifiers)
self.listener.undeclared_identifiers = \
self.listener.undeclared_identifiers.union(
- p.undeclared_identifiers)
+ p.undeclared_identifiers)
class ParseFunc(_ast_util.NodeVisitor):
@@ -222,6 +222,7 @@
self.listener.varargs = node.args.vararg
self.listener.kwargs = node.args.kwarg
+
class ExpressionGenerator(object):
def __init__(self, astnode):
diff --git a/mako/runtime.py b/mako/runtime.py
index 870efcc..8d2f4a9 100644
--- a/mako/runtime.py
+++ b/mako/runtime.py
@@ -13,6 +13,7 @@
class Context(object):
+
"""Provides runtime namespace, output buffer, and various
callstacks for templates.
@@ -80,7 +81,6 @@
"""Push a ``caller`` callable onto the callstack for
this :class:`.Context`."""
-
self.caller_stack.append(caller)
def pop_caller(self):
@@ -182,7 +182,9 @@
x.pop('next', None)
return c
+
class CallerStack(list):
+
def __init__(self):
self.nextcaller = None
@@ -211,6 +213,7 @@
class Undefined(object):
+
"""Represents an undefined value in a template.
All template modules have a constant value
@@ -218,6 +221,7 @@
object.
"""
+
def __str__(self):
raise NameError("Undefined")
@@ -230,7 +234,9 @@
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
"""
@@ -270,6 +276,7 @@
class LoopContext(object):
+
"""A magic loop variable.
Automatically accessible in any ``% for`` block.
@@ -335,8 +342,10 @@
class _NSAttr(object):
+
def __init__(self, parent):
self.__parent = parent
+
def __getattr__(self, key):
ns = self.__parent
while ns:
@@ -346,7 +355,9 @@
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.
@@ -363,8 +374,8 @@
"""
def __init__(self, name, context,
- callables=None, inherits=None,
- populate_self=True, calling_uri=None):
+ callables=None, inherits=None,
+ populate_self=True, calling_uri=None):
self.name = name
self.context = context
self.inherits = inherits
@@ -463,8 +474,8 @@
return self.context.namespaces[key]
else:
ns = TemplateNamespace(uri, self.context._copy(),
- templateuri=uri,
- calling_uri=self._templateuri)
+ templateuri=uri,
+ calling_uri=self._templateuri)
self.context.namespaces[key] = ns
return ns
@@ -525,17 +536,19 @@
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):
+ callables=None, inherits=None,
+ populate_self=True, calling_uri=None):
self.name = name
self.context = context
self.inherits = inherits
@@ -544,7 +557,7 @@
if templateuri is not None:
self.template = _lookup_template(context, templateuri,
- calling_uri)
+ calling_uri)
self._templateuri = self.template.module._template_uri
elif template is not None:
self.template = template
@@ -554,8 +567,8 @@
if populate_self:
lclcallable, lclcontext = \
- _populate_self_namespace(context, self.template,
- self_ns=self)
+ _populate_self_namespace(context, self.template,
+ self_ns=self)
@property
def module(self):
@@ -590,6 +603,7 @@
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)
@@ -607,17 +621,19 @@
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):
+ callables=None, inherits=None,
+ populate_self=True, calling_uri=None):
self.name = name
self.context = context
self.inherits = inherits
@@ -646,7 +662,6 @@
if compat.callable(callable_):
yield key, compat.partial(callable_, self.context)
-
def __getattr__(self, key):
if key in self.callables:
val = self.callables[key]
@@ -657,11 +672,12 @@
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.
@@ -678,6 +694,7 @@
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.
@@ -688,9 +705,9 @@
if not compat.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)
@@ -698,6 +715,7 @@
buf = context._pop_buffer()
return buf.getvalue()
+
def _decorate_toplevel(fn):
def decorate_render(render_fn):
def go(context, *args, **kw):
@@ -712,24 +730,28 @@
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)
+ 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
@@ -744,9 +766,9 @@
ih = ih.inherits
lclcontext = context._locals({'next': ih})
ih.inherits = TemplateNamespace("self:%s" % template.uri,
- lclcontext,
- template=template,
- populate_self=False)
+ 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:
@@ -759,23 +781,25 @@
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, 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)
@@ -783,6 +807,7 @@
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."""
@@ -793,17 +818,18 @@
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))
+ **_kwargs_for_callable(callable_, data))
return context._pop_buffer().getvalue()
+
def _kwargs_for_callable(callable_, data):
argspec = compat.inspect_func_args(callable_)
# for normal pages, **pageargs is usually present
@@ -818,6 +844,7 @@
kwargs[arg] = data[arg]
return kwargs
+
def _kwargs_for_include(callable_, data, **kwargs):
argspec = compat.inspect_func_args(callable_)
namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
@@ -826,6 +853,7 @@
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
@@ -839,6 +867,7 @@
(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
@@ -860,6 +889,7 @@
else:
callable_(context, *args, **kwargs)
+
def _render_error(template, context, error):
if template.error_handler:
result = template.error_handler(context, error)
@@ -869,11 +899,11 @@
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)]
+ error_template.output_encoding,
+ error_template.encoding_errors)]
context._set_with_template(error_template)
error_template.render_context(context, error=error)
diff --git a/mako/template.py b/mako/template.py
index fb61062..afb679a 100644
--- a/mako/template.py
+++ b/mako/template.py
@@ -20,6 +20,7 @@
class Template(object):
+
"""Represents a compiled template.
:class:`.Template` includes a reference to the original
@@ -215,34 +216,34 @@
lexer_cls = Lexer
def __init__(self,
- text=None,
- filename=None,
- uri=None,
- format_exceptions=False,
- error_handler=None,
- lookup=None,
- output_encoding=None,
- encoding_errors='strict',
- module_directory=None,
- cache_args=None,
- cache_impl='beaker',
- cache_enabled=True,
- cache_type=None,
- cache_dir=None,
- cache_url=None,
- module_filename=None,
- input_encoding=None,
- disable_unicode=False,
- module_writer=None,
- bytestring_passthrough=False,
- default_filters=None,
- buffer_filters=(),
- strict_undefined=False,
- imports=None,
- future_imports=None,
- enable_loop=True,
- preprocessor=None,
- lexer_cls=None):
+ text=None,
+ filename=None,
+ uri=None,
+ format_exceptions=False,
+ error_handler=None,
+ lookup=None,
+ output_encoding=None,
+ encoding_errors='strict',
+ module_directory=None,
+ cache_args=None,
+ cache_impl='beaker',
+ cache_enabled=True,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
+ module_filename=None,
+ input_encoding=None,
+ disable_unicode=False,
+ module_writer=None,
+ bytestring_passthrough=False,
+ default_filters=None,
+ buffer_filters=(),
+ strict_undefined=False,
+ imports=None,
+ future_imports=None,
+ enable_loop=True,
+ preprocessor=None,
+ lexer_cls=None):
if uri:
self.module_id = re.sub(r'\W', "_", uri)
self.uri = uri
@@ -261,9 +262,9 @@
u_norm = os.path.normpath(u_norm)
if u_norm.startswith(".."):
raise exceptions.TemplateLookupException(
- "Template uri \"%s\" is invalid - "
- "it cannot be relative outside "
- "of the root path." % self.uri)
+ "Template uri \"%s\" is invalid - "
+ "it cannot be relative outside "
+ "of the root path." % self.uri)
self.input_encoding = input_encoding
self.output_encoding = output_encoding
@@ -276,12 +277,12 @@
if compat.py3k and disable_unicode:
raise exceptions.UnsupportedError(
- "Mako for Python 3 does not "
- "support disabling Unicode")
+ "Mako for Python 3 does not "
+ "support disabling Unicode")
elif output_encoding and disable_unicode:
raise exceptions.UnsupportedError(
- "output_encoding must be set to "
- "None when disable_unicode is used.")
+ "output_encoding must be set to "
+ "None when disable_unicode is used.")
if default_filters is None:
if compat.py3k or self.disable_unicode:
self.default_filters = ['str']
@@ -311,17 +312,17 @@
path = module_filename
elif module_directory is not None:
path = os.path.abspath(
- os.path.join(
- os.path.normpath(module_directory),
- u_norm + ".py"
- )
- )
+ os.path.join(
+ os.path.normpath(module_directory),
+ u_norm + ".py"
+ )
+ )
else:
path = None
module = self._compile_from_file(path, filename)
else:
raise exceptions.RuntimeException(
- "Template requires text or filename")
+ "Template requires text or filename")
self.module = module
self.filename = filename
@@ -337,7 +338,6 @@
cache_type, cache_dir, cache_url
)
-
@util.memoized_property
def reserved_names(self):
if self.enable_loop:
@@ -346,8 +346,8 @@
return codegen.RESERVED_NAMES.difference(['loop'])
def _setup_cache_args(self,
- cache_impl, cache_enabled, cache_args,
- cache_type, cache_dir, cache_url):
+ cache_impl, cache_enabled, cache_args,
+ cache_type, cache_dir, cache_url):
self.cache_impl = cache_impl
self.cache_enabled = cache_enabled
if cache_args:
@@ -368,24 +368,24 @@
util.verify_directory(os.path.dirname(path))
filemtime = os.stat(filename)[stat.ST_MTIME]
if not os.path.exists(path) or \
- os.stat(path)[stat.ST_MTIME] < filemtime:
+ os.stat(path)[stat.ST_MTIME] < filemtime:
data = util.read_file(filename)
_compile_module_file(
- self,
- data,
- filename,
- path,
- self.module_writer)
+ self,
+ data,
+ filename,
+ path,
+ self.module_writer)
module = compat.load_module(self.module_id, path)
del sys.modules[self.module_id]
if module._magic_number != codegen.MAGIC_NUMBER:
data = util.read_file(filename)
_compile_module_file(
- self,
- data,
- filename,
- path,
- self.module_writer)
+ self,
+ data,
+ filename,
+ path,
+ self.module_writer)
module = compat.load_module(self.module_id, path)
del sys.modules[self.module_id]
ModuleInfo(module, path, self, filename, None, None)
@@ -394,9 +394,9 @@
# in memory
data = util.read_file(filename)
code, module = _compile_text(
- self,
- data,
- filename)
+ self,
+ data,
+ filename)
self._source = None
self._code = code
ModuleInfo(module, None, self, filename, code, None)
@@ -421,9 +421,11 @@
@property
def cache_dir(self):
return self.cache_args['dir']
+
@property
def cache_url(self):
return self.cache_args['url']
+
@property
def cache_type(self):
return self.cache_args['type']
@@ -446,10 +448,10 @@
"""Render the output of this template as a unicode object."""
return runtime._render(self,
- self.callable_,
- args,
- data,
- as_unicode=True)
+ self.callable_,
+ args,
+ data,
+ as_unicode=True)
def render_context(self, context, *args, **kwargs):
"""Render this :class:`.Template` with the given context.
@@ -480,7 +482,9 @@
def last_modified(self):
return self.module._modified_time
+
class ModuleTemplate(Template):
+
"""A Template which is constructed given an existing Python module.
e.g.::
@@ -498,25 +502,25 @@
"""
def __init__(self, module,
- module_filename=None,
- template=None,
- template_filename=None,
- module_source=None,
- template_source=None,
- output_encoding=None,
- encoding_errors='strict',
- disable_unicode=False,
- bytestring_passthrough=False,
- format_exceptions=False,
- error_handler=None,
- lookup=None,
- cache_args=None,
- cache_impl='beaker',
- cache_enabled=True,
- cache_type=None,
- cache_dir=None,
- cache_url=None,
- ):
+ module_filename=None,
+ template=None,
+ template_filename=None,
+ module_source=None,
+ template_source=None,
+ output_encoding=None,
+ encoding_errors='strict',
+ disable_unicode=False,
+ bytestring_passthrough=False,
+ format_exceptions=False,
+ error_handler=None,
+ lookup=None,
+ cache_args=None,
+ cache_impl='beaker',
+ cache_enabled=True,
+ cache_type=None,
+ cache_dir=None,
+ cache_url=None,
+ ):
self.module_id = re.sub(r'\W', "_", module._template_uri)
self.uri = module._template_uri
self.input_encoding = module._source_encoding
@@ -528,21 +532,21 @@
if compat.py3k and disable_unicode:
raise exceptions.UnsupportedError(
- "Mako for Python 3 does not "
- "support disabling Unicode")
+ "Mako for Python 3 does not "
+ "support disabling Unicode")
elif output_encoding and disable_unicode:
raise exceptions.UnsupportedError(
- "output_encoding must be set to "
- "None when disable_unicode is used.")
+ "output_encoding must be set to "
+ "None when disable_unicode is used.")
self.module = module
self.filename = template_filename
ModuleInfo(module,
- module_filename,
- self,
- template_filename,
- module_source,
- template_source)
+ module_filename,
+ self,
+ template_filename,
+ module_source,
+ template_source)
self.callable_ = self.module.render_body
self.format_exceptions = format_exceptions
@@ -553,7 +557,9 @@
cache_type, cache_dir, cache_url
)
+
class DefTemplate(Template):
+
"""A :class:`.Template` which represents a callable def in a parent
template."""
@@ -572,7 +578,9 @@
def get_def(self, name):
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.
@@ -581,12 +589,12 @@
_modules = weakref.WeakValueDictionary()
def __init__(self,
- module,
- module_filename,
- template,
- template_filename,
- module_source,
- template_source):
+ module,
+ module_filename,
+ template,
+ template_filename,
+ module_source,
+ template_source):
self.module = module
self.module_filename = module_filename
self.template_filename = template_filename
@@ -599,11 +607,12 @@
@classmethod
def get_module_source_metadata(cls, module_source, full_line_map=False):
source_map = re.search(
- r"__M_BEGIN_METADATA(.+?)__M_END_METADATA",
- module_source, re.S).group(1)
+ r"__M_BEGIN_METADATA(.+?)__M_END_METADATA",
+ module_source, re.S).group(1)
source_map = compat.json.loads(source_map)
- source_map['line_map'] = dict((int(k), int(v))
- for k, v in source_map['line_map'].items())
+ source_map['line_map'] = dict(
+ (int(k), int(v))
+ for k, v in source_map['line_map'].items())
if full_line_map:
f_line_map = source_map['full_line_map'] = []
line_map = source_map['line_map']
@@ -628,7 +637,7 @@
if self.module._source_encoding and \
not isinstance(self.template_source, compat.text_type):
return self.template_source.decode(
- self.module._source_encoding)
+ self.module._source_encoding)
else:
return self.template_source
else:
@@ -638,32 +647,34 @@
else:
return data
+
def _compile(template, text, filename, generate_magic_comment):
lexer = template.lexer_cls(text,
- filename,
- disable_unicode=template.disable_unicode,
- input_encoding=template.input_encoding,
- preprocessor=template.preprocessor)
+ filename,
+ disable_unicode=template.disable_unicode,
+ input_encoding=template.input_encoding,
+ preprocessor=template.preprocessor)
node = lexer.parse()
source = codegen.compile(node,
- template.uri,
- filename,
- default_filters=template.default_filters,
- buffer_filters=template.buffer_filters,
- imports=template.imports,
- future_imports=template.future_imports,
- source_encoding=lexer.encoding,
- generate_magic_comment=generate_magic_comment,
- disable_unicode=template.disable_unicode,
- strict_undefined=template.strict_undefined,
- enable_loop=template.enable_loop,
- reserved_names=template.reserved_names)
+ template.uri,
+ filename,
+ default_filters=template.default_filters,
+ buffer_filters=template.buffer_filters,
+ imports=template.imports,
+ future_imports=template.future_imports,
+ source_encoding=lexer.encoding,
+ generate_magic_comment=generate_magic_comment,
+ disable_unicode=template.disable_unicode,
+ strict_undefined=template.strict_undefined,
+ enable_loop=template.enable_loop,
+ reserved_names=template.reserved_names)
return source, lexer
+
def _compile_text(template, text, filename):
identifier = template.module_id
source, lexer = _compile(template, text, filename,
- generate_magic_comment=template.disable_unicode)
+ generate_magic_comment=template.disable_unicode)
cid = identifier
if not compat.py3k and isinstance(cid, compat.text_type):
@@ -675,9 +686,10 @@
exec(code, module.__dict__, module.__dict__)
return (source, module)
+
def _compile_module_file(template, text, filename, outputpath, module_writer):
source, lexer = _compile(template, text, filename,
- generate_magic_comment=True)
+ generate_magic_comment=True)
if isinstance(source, compat.text_type):
source = source.encode(lexer.encoding or 'ascii')
@@ -694,12 +706,13 @@
os.close(dest)
shutil.move(name, outputpath)
+
def _get_module_info_from_callable(callable_):
if compat.py3k:
return _get_module_info(callable_.__globals__['__name__'])
else:
return _get_module_info(callable_.func_globals['__name__'])
+
def _get_module_info(filename):
return ModuleInfo._modules[filename]
-
diff --git a/mako/util.py b/mako/util.py
index cba2ab7..c7dad65 100644
--- a/mako/util.py
+++ b/mako/util.py
@@ -11,6 +11,7 @@
from mako import compat
import operator
+
def update_wrapper(decorated, fn):
decorated.__wrapped__ = fn
decorated.__name__ = fn.__name__
@@ -18,6 +19,7 @@
class PluginLoader(object):
+
def __init__(self, group):
self.group = group
self.impls = {}
@@ -28,15 +30,15 @@
else:
import pkg_resources
for impl in pkg_resources.iter_entry_points(
- self.group,
- name):
+ self.group,
+ name):
self.impls[name] = impl.load
return impl.load()
else:
from mako import exceptions
raise exceptions.RuntimeException(
- "Can't load plugin %s %s" %
- (self.group, name))
+ "Can't load plugin %s %s" %
+ (self.group, name))
def register(self, name, modulepath, objname):
def load():
@@ -46,6 +48,7 @@
return getattr(mod, objname)
self.impls[name] = load
+
def verify_directory(dir):
"""create and/or verify a filesystem directory."""
@@ -59,6 +62,7 @@
if tries > 5:
raise
+
def to_list(x, default=None):
if x is None:
return default
@@ -69,7 +73,9 @@
class memoized_property(object):
+
"""A read-only @property that is only evaluated once."""
+
def __init__(self, fget, doc=None):
self.fget = fget
self.__doc__ = doc or fget.__doc__
@@ -81,7 +87,9 @@
obj.__dict__[self.__name__] = result = self.fget(obj)
return result
+
class memoized_instancemethod(object):
+
"""Decorate a method memoize its return value.
Best applied to no-arg methods: memoization is not sensitive to
@@ -89,6 +97,7 @@
called with different arguments.
"""
+
def __init__(self, fget, doc=None):
self.fget = fget
self.__doc__ = doc or fget.__doc__
@@ -97,6 +106,7 @@
def __get__(self, obj, cls):
if obj is None:
return self
+
def oneshot(*args, **kw):
result = self.fget(obj, *args, **kw)
memo = lambda *a, **kw: result
@@ -108,8 +118,11 @@
oneshot.__doc__ = self.__doc__
return oneshot
+
class SetLikeDict(dict):
+
"""a dictionary that has some setlike methods on it"""
+
def union(self, other):
"""produce a 'union' of this dict and another (at the key level).
@@ -118,7 +131,9 @@
x.update(other)
return x
+
class FastEncodingBuffer(object):
+
"""a very rudimentary buffer that is faster than StringIO,
but doesn't crash on unicode data like cStringIO."""
@@ -144,7 +159,9 @@
else:
return self.delim.join(self.data)
+
class LRUCache(dict):
+
"""A dictionary-like object that stores a limited number of items,
discarding lesser used items periodically.
@@ -154,10 +171,12 @@
"""
class _Item(object):
+
def __init__(self, key, value):
self.key = key
self.value = value
self.timestamp = compat.time_func()
+
def __repr__(self):
return repr(self.value)
@@ -206,6 +225,7 @@
r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)',
re.VERBOSE)
+
def parse_encoding(fp):
"""Deduce the encoding of a Python source file (binary mode) from magic
comment.
@@ -238,12 +258,13 @@
else:
line2 = fp.readline()
m = _PYTHON_MAGIC_COMMENT_re.match(
- line2.decode('ascii', 'ignore'))
+ line2.decode('ascii', 'ignore'))
if has_bom:
if m:
- raise SyntaxError("python refuses to compile code with both a UTF8" \
- " byte-order-mark and a magic encoding comment")
+ raise SyntaxError(
+ "python refuses to compile code with both a UTF8"
+ " byte-order-mark and a magic encoding comment")
return 'utf_8'
elif m:
return m.group(1)
@@ -252,6 +273,7 @@
finally:
fp.seek(pos)
+
def sorted_dict_repr(d):
"""repr() a dictionary with the keys in order.
@@ -262,6 +284,7 @@
keys.sort()
return "{" + ", ".join(["%r: %r" % (k, d[k]) for k in keys]) + "}"
+
def restore__ast(_ast):
"""Attempt to restore the required classes to the _ast module if it
appears to be missing them
@@ -338,7 +361,6 @@
_ast.NotIn = type(m.body[12].value.ops[1])
-
def read_file(path, mode='rb'):
fp = open(path, mode)
try:
@@ -347,6 +369,7 @@
finally:
fp.close()
+
def read_python_file(path):
fp = open(path, "rb")
try:
@@ -357,4 +380,3 @@
return data
finally:
fp.close()
-