diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-05-29 18:18:04 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-05-31 14:03:02 -0400 |
commit | fb7f0437323ba836c68947d38f3604c3336e3a9b (patch) | |
tree | 756512a2b68f1c7270f028b487228fd0e3f13778 | |
parent | db498f217e03d772e0c0c37a526226d48ed790e2 (diff) | |
download | mako-fb7f0437323ba836c68947d38f3604c3336e3a9b.tar.gz |
Use tox / zimports
Change-Id: Ia047c7052a6d242c2cf1c7a83981f1e38ea4d928
56 files changed, 6203 insertions, 3987 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..f9b217e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/python/black/ + rev: 19.3b0 + hooks: + - id: black + args: [-l 79] + +- repo: https://github.com/sqlalchemyorg/zimports/ + rev: master + hooks: + - id: zimports + + diff --git a/mako/__init__.py b/mako/__init__.py index 2435b72..90a4b36 100644 --- a/mako/__init__.py +++ b/mako/__init__.py @@ -5,4 +5,4 @@ # the MIT License: http://www.opensource.org/licenses/mit-license.php -__version__ = '1.0.11' +__version__ = "1.0.11" diff --git a/mako/_ast_util.py b/mako/_ast_util.py index e2c7d24..be95bfb 100644 --- a/mako/_ast_util.py +++ b/mako/_ast_util.py @@ -30,47 +30,77 @@ :copyright: Copyright 2008 by Armin Ronacher. :license: Python License. """ -from _ast import * # noqa +from _ast import Add +from _ast import And +from _ast import AST +from _ast import BitAnd +from _ast import BitOr +from _ast import BitXor +from _ast import ClassDef +from _ast import Div +from _ast import Eq +from _ast import Expression +from _ast import FloorDiv +from _ast import FunctionDef +from _ast import Gt +from _ast import GtE +from _ast import If +from _ast import In +from _ast import Interactive +from _ast import Invert +from _ast import Is +from _ast import IsNot +from _ast import LShift +from _ast import Lt +from _ast import LtE +from _ast import Mod +from _ast import mod +from _ast import Module +from _ast import Mult +from _ast import Name +from _ast import Not +from _ast import NotEq +from _ast import NotIn +from _ast import Or +from _ast import PyCF_ONLY_AST +from _ast import RShift +from _ast import Str +from _ast import Sub +from _ast import UAdd +from _ast import USub + from mako.compat import arg_stringname -BOOLOP_SYMBOLS = { - And: 'and', - Or: 'or' -} +BOOLOP_SYMBOLS = {And: "and", Or: "or"} BINOP_SYMBOLS = { - Add: '+', - Sub: '-', - Mult: '*', - Div: '/', - FloorDiv: '//', - Mod: '%', - LShift: '<<', - RShift: '>>', - BitOr: '|', - BitAnd: '&', - BitXor: '^' + Add: "+", + Sub: "-", + Mult: "*", + Div: "/", + FloorDiv: "//", + Mod: "%", + LShift: "<<", + RShift: ">>", + BitOr: "|", + BitAnd: "&", + BitXor: "^", } CMPOP_SYMBOLS = { - Eq: '==', - Gt: '>', - GtE: '>=', - In: 'in', - Is: 'is', - IsNot: 'is not', - Lt: '<', - LtE: '<=', - NotEq: '!=', - NotIn: 'not in' + Eq: "==", + Gt: ">", + GtE: ">=", + In: "in", + Is: "is", + IsNot: "is not", + Lt: "<", + LtE: "<=", + NotEq: "!=", + NotIn: "not in", } -UNARYOP_SYMBOLS = { - Invert: '~', - Not: 'not', - UAdd: '+', - USub: '-' -} +UNARYOP_SYMBOLS = {Invert: "~", Not: "not", UAdd: "+", USub: "-"} ALL_SYMBOLS = {} ALL_SYMBOLS.update(BOOLOP_SYMBOLS) @@ -79,12 +109,12 @@ ALL_SYMBOLS.update(CMPOP_SYMBOLS) ALL_SYMBOLS.update(UNARYOP_SYMBOLS) -def parse(expr, filename='<unknown>', mode='exec'): +def parse(expr, filename="<unknown>", mode="exec"): """Parse an expression into an AST node.""" return compile(expr, filename, mode, PyCF_ONLY_AST) -def to_source(node, indent_with=' ' * 4): +def to_source(node, indent_with=" " * 4): """ This function can convert a node tree back into python sourcecode. This is useful for debugging purposes, especially if you're dealing with custom @@ -101,7 +131,7 @@ def to_source(node, indent_with=' ' * 4): """ generator = SourceGenerator(indent_with) generator.visit(node) - return ''.join(generator.result) + return "".join(generator.result) def dump(node): @@ -109,16 +139,21 @@ def dump(node): A very verbose representation of the node passed. This is useful for debugging purposes. """ + def _format(node): if isinstance(node, AST): - return '%s(%s)' % (node.__class__.__name__, - ', '.join('%s=%s' % (a, _format(b)) - for a, b in iter_fields(node))) + return "%s(%s)" % ( + node.__class__.__name__, + ", ".join( + "%s=%s" % (a, _format(b)) for a, b in iter_fields(node) + ), + ) elif isinstance(node, list): - return '[%s]' % ', '.join(_format(x) for x in node) + return "[%s]" % ", ".join(_format(x) for x in node) return repr(node) + if not isinstance(node, AST): - raise TypeError('expected AST, got %r' % node.__class__.__name__) + raise TypeError("expected AST, got %r" % node.__class__.__name__) return _format(node) @@ -127,9 +162,12 @@ def copy_location(new_node, old_node): Copy the source location hint (`lineno` and `col_offset`) from the old to the new node if possible and return the new one. """ - for attr in 'lineno', 'col_offset': - if attr in old_node._attributes and attr in new_node._attributes \ - and hasattr(old_node, attr): + for attr in "lineno", "col_offset": + if ( + attr in old_node._attributes + and attr in new_node._attributes + and hasattr(old_node, attr) + ): setattr(new_node, attr, getattr(old_node, attr)) return new_node @@ -146,19 +184,21 @@ def fix_missing_locations(node): Unlike `copy_location` this works recursive and won't touch nodes that already have a location information. """ + def _fix(node, lineno, col_offset): - if 'lineno' in node._attributes: - if not hasattr(node, 'lineno'): + if "lineno" in node._attributes: + if not hasattr(node, "lineno"): node.lineno = lineno else: lineno = node.lineno - if 'col_offset' in node._attributes: - if not hasattr(node, 'col_offset'): + if "col_offset" in node._attributes: + if not hasattr(node, "col_offset"): node.col_offset = col_offset else: col_offset = node.col_offset for child in iter_child_nodes(node): _fix(child, lineno, col_offset) + _fix(node, 1, 0) return node @@ -170,14 +210,14 @@ def increment_lineno(node, n=1): file. """ for node in zip((node,), walk(node)): - if 'lineno' in node._attributes: - node.lineno = getattr(node, 'lineno', 0) + n + if "lineno" in node._attributes: + node.lineno = getattr(node, "lineno", 0) + n def iter_fields(node): """Iterate over all fields of a node, only yielding existing fields.""" # CPython 2.5 compat - if not hasattr(node, '_fields') or not node._fields: + if not hasattr(node, "_fields") or not node._fields: return for field in node._fields: try: @@ -213,11 +253,10 @@ def get_compile_mode(node): node (`Expression`, `Module` etc.) a `TypeError` is thrown. """ if not isinstance(node, mod): - raise TypeError('expected mod node, got %r' % node.__class__.__name__) - return { - Expression: 'eval', - Interactive: 'single' - }.get(node.__class__, 'expr') + raise TypeError("expected mod node, got %r" % node.__class__.__name__) + return {Expression: "eval", Interactive: "single"}.get( + node.__class__, "expr" + ) def get_docstring(node): @@ -238,6 +277,7 @@ def walk(node): place and don't care about the context or the order the nodes are returned. """ from collections import deque + todo = deque([node]) while todo: node = todo.popleft() @@ -269,7 +309,7 @@ class NodeVisitor(object): exists for this node. In that case the generic visit function is used instead. """ - method = 'visit_' + node.__class__.__name__ + method = "visit_" + node.__class__.__name__ return getattr(self, method, None) def visit(self, node): @@ -367,7 +407,7 @@ class SourceGenerator(NodeVisitor): def write(self, x): if self.new_lines: if self.result: - self.result.append('\n' * self.new_lines) + self.result.append("\n" * self.new_lines) self.result.append(self.indent_with * self.indentation) self.new_lines = 0 self.result.append(x) @@ -386,7 +426,7 @@ class SourceGenerator(NodeVisitor): self.body(node.body) if node.orelse: self.newline() - self.write('else:') + self.write("else:") self.body(node.orelse) def signature(self, node): @@ -394,7 +434,7 @@ class SourceGenerator(NodeVisitor): def write_comma(): if want_comma: - self.write(', ') + self.write(", ") else: want_comma.append(True) @@ -403,19 +443,19 @@ class SourceGenerator(NodeVisitor): write_comma() self.visit(arg) if default is not None: - self.write('=') + self.write("=") self.visit(default) if node.vararg is not None: write_comma() - self.write('*' + arg_stringname(node.vararg)) + self.write("*" + arg_stringname(node.vararg)) if node.kwarg is not None: write_comma() - self.write('**' + arg_stringname(node.kwarg)) + self.write("**" + arg_stringname(node.kwarg)) def decorators(self, node): for decorator in node.decorator_list: self.newline() - self.write('@') + self.write("@") self.visit(decorator) # Statements @@ -424,29 +464,29 @@ class SourceGenerator(NodeVisitor): self.newline() for idx, target in enumerate(node.targets): if idx: - self.write(', ') + self.write(", ") self.visit(target) - self.write(' = ') + self.write(" = ") self.visit(node.value) def visit_AugAssign(self, node): self.newline() self.visit(node.target) - self.write(BINOP_SYMBOLS[type(node.op)] + '=') + self.write(BINOP_SYMBOLS[type(node.op)] + "=") self.visit(node.value) def visit_ImportFrom(self, node): self.newline() - self.write('from %s%s import ' % ('.' * node.level, node.module)) + self.write("from %s%s import " % ("." * node.level, node.module)) for idx, item in enumerate(node.names): if idx: - self.write(', ') + self.write(", ") self.write(item) def visit_Import(self, node): self.newline() for item in node.names: - self.write('import ') + self.write("import ") self.visit(item) def visit_Expr(self, node): @@ -457,9 +497,9 @@ class SourceGenerator(NodeVisitor): self.newline(n=2) self.decorators(node) self.newline() - self.write('def %s(' % node.name) + self.write("def %s(" % node.name) self.signature(node.args) - self.write('):') + self.write("):") self.body(node.body) def visit_ClassDef(self, node): @@ -467,200 +507,200 @@ class SourceGenerator(NodeVisitor): def paren_or_comma(): if have_args: - self.write(', ') + self.write(", ") else: have_args.append(True) - self.write('(') + self.write("(") self.newline(n=3) self.decorators(node) self.newline() - self.write('class %s' % node.name) + self.write("class %s" % node.name) for base in node.bases: paren_or_comma() self.visit(base) # XXX: the if here is used to keep this module compatible # with python 2.6. - if hasattr(node, 'keywords'): + if hasattr(node, "keywords"): for keyword in node.keywords: paren_or_comma() - self.write(keyword.arg + '=') + self.write(keyword.arg + "=") self.visit(keyword.value) if getattr(node, "starargs", None): paren_or_comma() - self.write('*') + self.write("*") self.visit(node.starargs) if getattr(node, "kwargs", None): paren_or_comma() - self.write('**') + self.write("**") self.visit(node.kwargs) - self.write(have_args and '):' or ':') + self.write(have_args and "):" or ":") self.body(node.body) def visit_If(self, node): self.newline() - self.write('if ') + self.write("if ") self.visit(node.test) - self.write(':') + self.write(":") self.body(node.body) while True: else_ = node.orelse if len(else_) == 1 and isinstance(else_[0], If): node = else_[0] self.newline() - self.write('elif ') + self.write("elif ") self.visit(node.test) - self.write(':') + self.write(":") self.body(node.body) else: self.newline() - self.write('else:') + self.write("else:") self.body(else_) break def visit_For(self, node): self.newline() - self.write('for ') + self.write("for ") self.visit(node.target) - self.write(' in ') + self.write(" in ") self.visit(node.iter) - self.write(':') + self.write(":") self.body_or_else(node) def visit_While(self, node): self.newline() - self.write('while ') + self.write("while ") self.visit(node.test) - self.write(':') + self.write(":") self.body_or_else(node) def visit_With(self, node): self.newline() - self.write('with ') + self.write("with ") self.visit(node.context_expr) if node.optional_vars is not None: - self.write(' as ') + self.write(" as ") self.visit(node.optional_vars) - self.write(':') + self.write(":") self.body(node.body) def visit_Pass(self, node): self.newline() - self.write('pass') + self.write("pass") def visit_Print(self, node): # XXX: python 2.6 only self.newline() - self.write('print ') + self.write("print ") want_comma = False if node.dest is not None: - self.write(' >> ') + self.write(" >> ") self.visit(node.dest) want_comma = True for value in node.values: if want_comma: - self.write(', ') + self.write(", ") self.visit(value) want_comma = True if not node.nl: - self.write(',') + self.write(",") def visit_Delete(self, node): self.newline() - self.write('del ') + self.write("del ") for idx, target in enumerate(node): if idx: - self.write(', ') + self.write(", ") self.visit(target) def visit_TryExcept(self, node): self.newline() - self.write('try:') + self.write("try:") self.body(node.body) for handler in node.handlers: self.visit(handler) def visit_TryFinally(self, node): self.newline() - self.write('try:') + self.write("try:") self.body(node.body) self.newline() - self.write('finally:') + self.write("finally:") self.body(node.finalbody) def visit_Global(self, node): self.newline() - self.write('global ' + ', '.join(node.names)) + self.write("global " + ", ".join(node.names)) def visit_Nonlocal(self, node): self.newline() - self.write('nonlocal ' + ', '.join(node.names)) + self.write("nonlocal " + ", ".join(node.names)) def visit_Return(self, node): self.newline() - self.write('return ') + self.write("return ") self.visit(node.value) def visit_Break(self, node): self.newline() - self.write('break') + self.write("break") def visit_Continue(self, node): self.newline() - self.write('continue') + self.write("continue") def visit_Raise(self, node): # XXX: Python 2.6 / 3.0 compatibility self.newline() - self.write('raise') - if hasattr(node, 'exc') and node.exc is not None: - self.write(' ') + self.write("raise") + if hasattr(node, "exc") and node.exc is not None: + self.write(" ") self.visit(node.exc) if node.cause is not None: - self.write(' from ') + self.write(" from ") self.visit(node.cause) - elif hasattr(node, 'type') and node.type is not None: + elif hasattr(node, "type") and node.type is not None: self.visit(node.type) if node.inst is not None: - self.write(', ') + self.write(", ") self.visit(node.inst) if node.tback is not None: - self.write(', ') + self.write(", ") self.visit(node.tback) # Expressions def visit_Attribute(self, node): self.visit(node.value) - self.write('.' + node.attr) + self.write("." + node.attr) def visit_Call(self, node): want_comma = [] def write_comma(): if want_comma: - self.write(', ') + self.write(", ") else: want_comma.append(True) self.visit(node.func) - self.write('(') + self.write("(") for arg in node.args: write_comma() self.visit(arg) for keyword in node.keywords: write_comma() - self.write(keyword.arg + '=') + self.write(keyword.arg + "=") self.visit(keyword.value) if getattr(node, "starargs", None): write_comma() - self.write('*') + self.write("*") self.visit(node.starargs) if getattr(node, "kwargs", None): write_comma() - self.write('**') + self.write("**") self.visit(node.kwargs) - self.write(')') + self.write(")") def visit_Name(self, node): self.write(node.id) @@ -685,105 +725,106 @@ class SourceGenerator(NodeVisitor): self.write(repr(node.value)) def visit_Tuple(self, node): - self.write('(') + self.write("(") idx = -1 for idx, item in enumerate(node.elts): if idx: - self.write(', ') + self.write(", ") self.visit(item) - self.write(idx and ')' or ',)') + self.write(idx and ")" or ",)") def sequence_visit(left, right): def visit(self, node): self.write(left) for idx, item in enumerate(node.elts): if idx: - self.write(', ') + self.write(", ") self.visit(item) self.write(right) + return visit - visit_List = sequence_visit('[', ']') - visit_Set = sequence_visit('{', '}') + visit_List = sequence_visit("[", "]") + visit_Set = sequence_visit("{", "}") del sequence_visit def visit_Dict(self, node): - self.write('{') + self.write("{") for idx, (key, value) in enumerate(zip(node.keys, node.values)): if idx: - self.write(', ') + self.write(", ") self.visit(key) - self.write(': ') + self.write(": ") self.visit(value) - self.write('}') + self.write("}") def visit_BinOp(self, node): - self.write('(') + self.write("(") self.visit(node.left) - self.write(' %s ' % BINOP_SYMBOLS[type(node.op)]) + self.write(" %s " % BINOP_SYMBOLS[type(node.op)]) self.visit(node.right) - self.write(')') + self.write(")") def visit_BoolOp(self, node): - self.write('(') + self.write("(") for idx, value in enumerate(node.values): if idx: - self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)]) + self.write(" %s " % BOOLOP_SYMBOLS[type(node.op)]) self.visit(value) - self.write(')') + self.write(")") def visit_Compare(self, node): - self.write('(') + self.write("(") self.visit(node.left) for op, right in zip(node.ops, node.comparators): - self.write(' %s ' % CMPOP_SYMBOLS[type(op)]) + self.write(" %s " % CMPOP_SYMBOLS[type(op)]) self.visit(right) - self.write(')') + self.write(")") def visit_UnaryOp(self, node): - self.write('(') + self.write("(") op = UNARYOP_SYMBOLS[type(node.op)] self.write(op) - if op == 'not': - self.write(' ') + if op == "not": + self.write(" ") self.visit(node.operand) - self.write(')') + self.write(")") def visit_Subscript(self, node): self.visit(node.value) - self.write('[') + self.write("[") self.visit(node.slice) - self.write(']') + self.write("]") def visit_Slice(self, node): if node.lower is not None: self.visit(node.lower) - self.write(':') + self.write(":") if node.upper is not None: self.visit(node.upper) if node.step is not None: - self.write(':') - if not (isinstance(node.step, Name) and node.step.id == 'None'): + self.write(":") + if not (isinstance(node.step, Name) and node.step.id == "None"): self.visit(node.step) def visit_ExtSlice(self, node): for idx, item in node.dims: if idx: - self.write(', ') + self.write(", ") self.visit(item) def visit_Yield(self, node): - self.write('yield ') + self.write("yield ") self.visit(node.value) def visit_Lambda(self, node): - self.write('lambda ') + self.write("lambda ") self.signature(node.args) - self.write(': ') + self.write(": ") self.visit(node.body) def visit_Ellipsis(self, node): - self.write('Ellipsis') + self.write("Ellipsis") def generator_visit(left, right): def visit(self, node): @@ -792,64 +833,65 @@ class SourceGenerator(NodeVisitor): for comprehension in node.generators: self.visit(comprehension) self.write(right) + return visit - visit_ListComp = generator_visit('[', ']') - visit_GeneratorExp = generator_visit('(', ')') - visit_SetComp = generator_visit('{', '}') + visit_ListComp = generator_visit("[", "]") + visit_GeneratorExp = generator_visit("(", ")") + visit_SetComp = generator_visit("{", "}") del generator_visit def visit_DictComp(self, node): - self.write('{') + self.write("{") self.visit(node.key) - self.write(': ') + self.write(": ") self.visit(node.value) for comprehension in node.generators: self.visit(comprehension) - self.write('}') + self.write("}") def visit_IfExp(self, node): self.visit(node.body) - self.write(' if ') + self.write(" if ") self.visit(node.test) - self.write(' else ') + self.write(" else ") self.visit(node.orelse) def visit_Starred(self, node): - self.write('*') + self.write("*") self.visit(node.value) def visit_Repr(self, node): # XXX: python 2.6 only - self.write('`') + self.write("`") self.visit(node.value) - self.write('`') + self.write("`") # Helper Nodes def visit_alias(self, node): self.write(node.name) if node.asname is not None: - self.write(' as ' + node.asname) + self.write(" as " + node.asname) def visit_comprehension(self, node): - self.write(' for ') + self.write(" for ") self.visit(node.target) - self.write(' in ') + self.write(" in ") self.visit(node.iter) if node.ifs: for if_ in node.ifs: - self.write(' if ') + self.write(" if ") self.visit(if_) def visit_excepthandler(self, node): self.newline() - self.write('except') + self.write("except") if node.type is not None: - self.write(' ') + self.write(" ") self.visit(node.type) if node.name is not None: - self.write(' as ') + self.write(" as ") self.visit(node.name) - self.write(':') + self.write(":") self.body(node.body) diff --git a/mako/ast.py b/mako/ast.py index 8d2d150..2081d5d 100644 --- a/mako/ast.py +++ b/mako/ast.py @@ -7,9 +7,12 @@ """utilities for analyzing expressions and blocks of Python code, as well as generating Python from AST nodes""" -from mako import exceptions, pyparser, compat import re +from mako import compat +from mako import exceptions +from mako import pyparser + class PythonCode(object): @@ -72,36 +75,39 @@ class PythonFragment(PythonCode): """extends PythonCode to provide identifier lookups in partial control statements - e.g. + e.g.:: + for x in 5: elif y==9: except (MyException, e): - etc. + """ def __init__(self, code, **exception_kwargs): - m = re.match(r'^(\w+)(?:\s+(.*?))?:\s*(#|$)', code.strip(), re.S) + 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)] + code = code[: m.start(3)] (keyword, expr) = m.group(1, 2) - if keyword in ['for', 'if', 'while']: + if keyword in ["for", "if", "while"]: code = code + "pass" - elif keyword == 'try': + elif keyword == "try": code = code + "pass\nexcept:pass" - elif keyword == 'elif' or keyword == 'else': + elif keyword == "elif" or keyword == "else": code = "if False:pass\n" + code + "pass" - elif keyword == 'except': + elif keyword == "except": code = "try:pass\n" + code + "pass" - elif keyword == 'with': + elif keyword == "with": 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) @@ -115,14 +121,17 @@ class FunctionDecl(object): f = pyparser.ParseFunc(self, **exception_kwargs) f.visit(expr) - if not hasattr(self, 'funcname'): + if not hasattr(self, "funcname"): raise exceptions.CompileException( "Code '%s' is not a function declaration" % code, - **exception_kwargs) + **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 @@ -157,8 +166,10 @@ class FunctionDecl(object): # `def foo(*, a=1, b, c=3)` namedecls.append(name) else: - namedecls.append("%s=%s" % ( - name, pyparser.ExpressionGenerator(default).value())) + namedecls.append( + "%s=%s" + % (name, pyparser.ExpressionGenerator(default).value()) + ) else: namedecls.append(name) @@ -171,8 +182,10 @@ class FunctionDecl(object): namedecls.append(name) else: default = defaults.pop(0) - namedecls.append("%s=%s" % ( - name, pyparser.ExpressionGenerator(default).value())) + namedecls.append( + "%s=%s" + % (name, pyparser.ExpressionGenerator(default).value()) + ) namedecls.reverse() return namedecls @@ -187,5 +200,6 @@ 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) + super(FunctionArgs, self).__init__( + "def ANON(%s):pass" % code, **kwargs + ) diff --git a/mako/cache.py b/mako/cache.py index 1af17dd..57821d7 100644 --- a/mako/cache.py +++ b/mako/cache.py @@ -4,7 +4,8 @@ # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -from mako import compat, util +from mako import compat +from mako import util _cache_plugins = util.PluginLoader("mako.cache") @@ -90,9 +91,8 @@ class Cache(object): return creation_function() return self.impl.get_or_create( - key, - creation_function, - **self._get_cache_kw(kw, context)) + key, creation_function, **self._get_cache_kw(kw, context) + ) def set(self, key, value, **kw): r"""Place a value in the cache. @@ -141,7 +141,7 @@ class Cache(object): template. """ - self.invalidate('render_body', __M_defname='render_body') + self.invalidate("render_body", __M_defname="render_body") def invalidate_def(self, name): """Invalidate the cached content of a particular ``<%def>`` within this @@ -149,7 +149,7 @@ class Cache(object): """ - self.invalidate('render_%s' % name, __M_defname='render_%s' % name) + self.invalidate("render_%s" % name, __M_defname="render_%s" % name) def invalidate_closure(self, name): """Invalidate a nested ``<%def>`` within this template. @@ -165,7 +165,7 @@ class Cache(object): self.invalidate(name, __M_defname=name) def _get_cache_kw(self, kw, context): - defname = kw.pop('__M_defname', None) + defname = kw.pop("__M_defname", None) if not defname: tmpl_kw = self.template.cache_args.copy() tmpl_kw.update(kw) @@ -177,7 +177,7 @@ class Cache(object): self._def_regions[defname] = tmpl_kw if context and self.impl.pass_context: tmpl_kw = tmpl_kw.copy() - tmpl_kw.setdefault('context', context) + tmpl_kw.setdefault("context", context) return tmpl_kw diff --git a/mako/cmd.py b/mako/cmd.py index ff738c4..e51f021 100755 --- a/mako/cmd.py +++ b/mako/cmd.py @@ -4,11 +4,13 @@ # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php from argparse import ArgumentParser -from os.path import isfile, dirname +from os.path import dirname +from os.path import isfile import sys -from mako.template import Template -from mako.lookup import TemplateLookup + from mako import exceptions +from mako.lookup import TemplateLookup +from mako.template import Template def varsplit(var): @@ -26,29 +28,39 @@ def cmdline(argv=None): parser = ArgumentParser() parser.add_argument( - "--var", default=[], action="append", - help="variable (can be used multiple times, use name=value)") + "--var", + default=[], + action="append", + help="variable (can be used multiple times, use name=value)", + ) parser.add_argument( - "--template-dir", default=[], action="append", + "--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.") + "parent directory of the file provided.", + ) parser.add_argument( - "--output-encoding", default=None, - help="force output encoding") - parser.add_argument('input', nargs='?', default='-') + "--output-encoding", default=None, help="force output encoding" + ) + parser.add_argument("input", nargs="?", default="-") options = parser.parse_args(argv) output_encoding = options.output_encoding - if options.input == '-': + if options.input == "-": lookup_dirs = options.template_dir or ["."] lookup = TemplateLookup(lookup_dirs) try: - template = Template(sys.stdin.read(), lookup=lookup, output_encoding=output_encoding) + template = Template( + sys.stdin.read(), + lookup=lookup, + output_encoding=output_encoding, + ) except: _exit() else: @@ -58,7 +70,11 @@ def cmdline(argv=None): lookup_dirs = options.template_dir or [dirname(filename)] lookup = TemplateLookup(lookup_dirs) try: - template = Template(filename=filename, lookup=lookup, output_encoding=output_encoding) + template = Template( + filename=filename, + lookup=lookup, + output_encoding=output_encoding, + ) except: _exit() diff --git a/mako/codegen.py b/mako/codegen.py index d4ecbe8..d7e48f9 100644 --- a/mako/codegen.py +++ b/mako/codegen.py @@ -7,11 +7,16 @@ """provides functionality for rendering a parsetree constructing into module source code.""" -import time import re -from mako.pygen import PythonPrinter -from mako import util, ast, parsetree, filters, exceptions +import time + +from mako import ast from mako import compat +from mako import exceptions +from mako import filters +from mako import parsetree +from mako import util +from mako.pygen import PythonPrinter MAGIC_NUMBER = 10 @@ -20,22 +25,24 @@ MAGIC_NUMBER = 10 # template and are not accessed via the # context itself 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()): +RESERVED_NAMES = set(["context", "loop"]).union(TOPLEVEL_DECLARED) + + +def compile( # noqa + 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""" @@ -49,38 +56,43 @@ def compile(node, 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) + _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, + ) 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): + 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, + ): self.uri = uri self.filename = filename self.default_filters = default_filters @@ -113,12 +125,12 @@ class _GenerateRenderMethod(object): name = "render_%s" % node.funcname args = node.get_argument_expressions() filtered = len(node.filter_args.args) > 0 - buffered = eval(node.attributes.get('buffered', 'False')) - cached = eval(node.attributes.get('cached', 'False')) + buffered = eval(node.attributes.get("buffered", "False")) + cached = eval(node.attributes.get("cached", "False")) defs = None pagetag = None if node.is_block and not node.is_anonymous: - args += ['**pageargs'] + args += ["**pageargs"] else: defs = self.write_toplevel() pagetag = self.compiler.pagetag @@ -126,25 +138,23 @@ class _GenerateRenderMethod(object): if pagetag is not None: args = pagetag.body_decl.get_argument_expressions() if not pagetag.body_decl.kwargs: - args += ['**pageargs'] - cached = eval(pagetag.attributes.get('cached', 'False')) + 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'] + args = ["**pageargs"] cached = False buffered = filtered = False if args is None: - args = ['context'] + args = ["context"] else: - args = [a for a in ['context'] + args] + 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: @@ -154,8 +164,9 @@ class _GenerateRenderMethod(object): self.write_metadata_struct() def write_metadata_struct(self): - self.printer.source_map[self.printer.lineno] = \ - max(self.printer.source_map) + self.printer.source_map[self.printer.lineno] = max( + self.printer.source_map + ) struct = { "filename": self.compiler.filename, "uri": self.compiler.uri, @@ -164,10 +175,9 @@ class _GenerateRenderMethod(object): } self.printer.writelines( '"""', - '__M_BEGIN_METADATA', + "__M_BEGIN_METADATA", compat.json.dumps(struct), - '__M_END_METADATA\n' - '"""' + "__M_END_METADATA\n" '"""', ) @property @@ -186,7 +196,6 @@ class _GenerateRenderMethod(object): self.compiler.pagetag = None class FindTopLevel(object): - def visitInheritTag(s, node): inherit.append(node) @@ -214,14 +223,19 @@ class _GenerateRenderMethod(object): module_identifiers.declared = module_ident # module-level names, python code - if self.compiler.generate_magic_comment and \ - self.compiler.source_encoding: - self.printer.writeline("# -*- coding:%s -*-" % - self.compiler.source_encoding) + if ( + self.compiler.generate_magic_comment + and self.compiler.source_encoding + ): + self.printer.writeline( + "# -*- coding:%s -*-" % self.compiler.source_encoding + ) if self.compiler.future_imports: - self.printer.writeline("from __future__ import %s" % - (", ".join(self.compiler.future_imports),)) + self.printer.writeline( + "from __future__ import %s" + % (", ".join(self.compiler.future_imports),) + ) self.printer.writeline("from mako import runtime, filters, cache") self.printer.writeline("UNDEFINED = runtime.UNDEFINED") self.printer.writeline("STOP_RENDERING = runtime.STOP_RENDERING") @@ -231,36 +245,41 @@ class _GenerateRenderMethod(object): 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 = '' + buf = "" for imp in self.compiler.imports: buf += imp + "\n" self.printer.writeline(imp) impcode = ast.PythonCode( buf, - source='', lineno=0, + source="", + lineno=0, pos=0, - filename='template defined imports') + filename="template defined imports", + ) else: impcode = None main_identifiers = module_identifiers.branch(self.node) - module_identifiers.topleveldefs = \ - module_identifiers.topleveldefs.\ - union(main_identifiers.topleveldefs) + mit = module_identifiers.topleveldefs + module_identifiers.topleveldefs = mit.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()] - ) + self.printer.writeline( + "_exports = %r" + % [n.name for n in main_identifiers.topleveldefs.values()] + ) self.printer.write_blanks(2) if len(module_code): @@ -274,8 +293,9 @@ class _GenerateRenderMethod(object): return list(main_identifiers.topleveldefs.values()) - def write_render_callable(self, node, name, args, buffered, filtered, - cached): + def write_render_callable( + self, node, name, args, buffered, filtered, cached + ): """write a top-level render callable. this could be the main render() method or that of a top-level def.""" @@ -284,32 +304,38 @@ class _GenerateRenderMethod(object): 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)), + "def %s(%s):" % (name, ",".join(args)), # push new frame, assign current frame to __M_caller "__M_caller = context.caller_stack._push_frame()", - "try:" + "try:", ) if buffered or filtered or cached: self.printer.writeline("context._push_buffer()") self.identifier_stack.append( - 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') + 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 - self.identifiers.argument_declared - ])) + self.printer.writeline( + "__M_locals = __M_dict_builtin(%s)" + % ",".join( + [ + "%s=%s" % (x, x) + for x in self.identifiers.argument_declared + ] + ) + ) self.write_variable_declares(self.identifiers, toplevel=True) @@ -321,9 +347,8 @@ class _GenerateRenderMethod(object): 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 @@ -338,9 +363,9 @@ class _GenerateRenderMethod(object): 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 + "return runtime._inherit_from(context, %s, _template_uri)" + % (node.parsed_attributes["file"]), + None, ) def write_namespaces(self, namespaces): @@ -352,12 +377,13 @@ class _GenerateRenderMethod(object): "except KeyError:", "_mako_generate_namespaces(context)", "return context.namespaces[(__name__, name)]", - None, None + None, + None, ) self.printer.writeline("def _mako_generate_namespaces(context):") for node in namespaces.values(): - if 'import' in node.attributes: + if "import" in node.attributes: self.compiler.has_ns_imports = True self.printer.start_source(node.lineno) if len(node.nodes): @@ -367,7 +393,6 @@ class _GenerateRenderMethod(object): self.in_def = True class NSDefVisitor(object): - def visitDefTag(s, node): s.visitDefOrBase(node) @@ -383,56 +408,54 @@ class _GenerateRenderMethod(object): ) self.write_inline_def(node, identifiers, nested=False) export.append(node.funcname) + vis = NSDefVisitor() for n in node.nodes: n.accept_visitor(vis) - self.printer.writeline("return [%s]" % (','.join(export))) + self.printer.writeline("return [%s]" % (",".join(export))) self.printer.writeline(None) self.in_def = False callable_name = "make_namespace()" else: callable_name = "None" - if 'file' in node.parsed_attributes: + 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)" % - ( + " calling_uri=_template_uri)" + % ( node.name, - node.parsed_attributes.get('file', 'None'), + node.parsed_attributes.get("file", "None"), callable_name, ) ) - elif 'module' in node.parsed_attributes: + 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)" % - ( + " module=%s)" + % ( node.name, callable_name, - node.parsed_attributes.get( - 'module', 'None') + 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, - ) + " callables=%s, calling_uri=_template_uri)" + % (node.name, callable_name) ) - if eval(node.attributes.get('inheritable', "False")): + if eval(node.attributes.get("inheritable", "False")): self.printer.writeline("context['self'].%s = ns" % (node.name)) self.printer.writeline( - "context.namespaces[(__name__, %s)] = ns" % repr(node.name)) + "context.namespaces[(__name__, %s)] = ns" % repr(node.name) + ) self.printer.write_blanks(1) if not len(namespaces): self.printer.writeline("pass") @@ -468,7 +491,8 @@ class _GenerateRenderMethod(object): # 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 @@ -492,23 +516,22 @@ class _GenerateRenderMethod(object): if limit is not None: to_write = to_write.intersection(limit) - if toplevel and getattr(self.compiler, 'has_ns_imports', False): + if toplevel and getattr(self.compiler, "has_ns_imports", False): self.printer.writeline("_import_ns = {}") self.compiler.has_imports = True for ident, ns in self.compiler.namespaces.items(): - if 'import' in ns.attributes: + if "import" in ns.attributes: self.printer.writeline( "_mako_get_namespace(context, %r)." - "_populate(_import_ns, %r)" % - ( + "_populate(_import_ns, %r)" + % ( ident, - re.split(r'\s*,\s*', ns.attributes['import']) - )) + re.split(r"\s*,\s*", ns.attributes["import"]), + ) + ) if has_loop: - self.printer.writeline( - 'loop = __M_loop = runtime.LoopStack()' - ) + self.printer.writeline("loop = __M_loop = runtime.LoopStack()") for ident in to_write: if ident in comp_idents: @@ -526,37 +549,36 @@ class _GenerateRenderMethod(object): 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 getattr(self.compiler, "has_ns_imports", False): if self.compiler.strict_undefined: self.printer.writelines( - "%s = _import_ns.get(%r, UNDEFINED)" % - (ident, ident), + "%s = _import_ns.get(%r, UNDEFINED)" + % (ident, ident), "if %s is UNDEFINED:" % ident, "try:", "%s = context[%r]" % (ident, ident), "except KeyError:", - "raise NameError(\"'%s' is not defined\")" % - ident, - None, None + "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)) + "(%r, context.get(%r, UNDEFINED))" + % (ident, ident, ident) + ) else: if self.compiler.strict_undefined: self.printer.writelines( "try:", "%s = context[%r]" % (ident, ident), "except KeyError:", - "raise NameError(\"'%s' is not defined\")" % - ident, - None + "raise NameError(\"'%s' is not defined\")" % ident, + None, ) else: self.printer.writeline( @@ -572,14 +594,16 @@ class _GenerateRenderMethod(object): 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): - nameargs.insert(0, 'context._locals(__M_locals)') + 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') + 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): @@ -590,21 +614,21 @@ class _GenerateRenderMethod(object): 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')) + buffered = eval(node.attributes.get("buffered", "False")) + cached = eval(node.attributes.get("cached", "False")) self.printer.writelines( # push new frame, assign current frame to __M_caller "__M_caller = context.caller_stack._push_frame()", - "try:" + "try:", ) if buffered or filtered or cached: - self.printer.writelines( - "context._push_buffer()", - ) + self.printer.writelines("context._push_buffer()") identifiers = identifiers.branch(node, nested=nested) @@ -618,12 +642,19 @@ class _GenerateRenderMethod(object): self.write_def_finish(node, buffered, filtered, cached) self.printer.writeline(None) if cached: - self.write_cache_decorator(node, node.funcname, - namedecls, False, identifiers, - inline=True, toplevel=False) + self.write_cache_decorator( + node, + node.funcname, + namedecls, + False, + identifiers, + inline=True, + toplevel=False, + ) - def write_def_finish(self, node, buffered, filtered, cached, - callstack=True): + def write_def_finish( + self, node, buffered, filtered, cached, callstack=True + ): """write the end section of a rendering function, either outermost or inline. @@ -636,9 +667,7 @@ class _GenerateRenderMethod(object): self.printer.writeline("return ''") if callstack: self.printer.writelines( - "finally:", - "context.caller_stack._pop_frame()", - None + "finally:", "context.caller_stack._pop_frame()", None ) if buffered or filtered or cached: @@ -648,13 +677,12 @@ class _GenerateRenderMethod(object): # implemenation might be using a context with no # extra buffers self.printer.writelines( - "finally:", - "__M_buf = context._pop_buffer()" + "finally:", "__M_buf = context._pop_buffer()" ) else: self.printer.writelines( "finally:", - "__M_buf, __M_writer = context._pop_buffer_and_writer()" + "__M_buf, __M_writer = context._pop_buffer_and_writer()", ) if callstack: @@ -662,89 +690,100 @@ class _GenerateRenderMethod(object): s = "__M_buf.getvalue()" if filtered: - s = self.create_filter_callable(node.filter_args.args, s, - False) + s = self.create_filter_callable( + node.filter_args.args, s, False + ) self.printer.writeline(None) if buffered and not cached: - s = self.create_filter_callable(self.compiler.buffer_filters, - s, False) + s = self.create_filter_callable( + self.compiler.buffer_filters, s, False + ) if buffered or cached: self.printer.writeline("return %s" % s) else: - self.printer.writelines( - "__M_writer(%s)" % s, - "return ''" - ) - - def write_cache_decorator(self, node_or_pagetag, name, - args, buffered, identifiers, - inline=False, toplevel=False): + self.printer.writelines("__M_writer(%s)" % s, "return ''") + + def write_cache_decorator( + self, + node_or_pagetag, + name, + args, + buffered, + identifiers, + inline=False, + toplevel=False, + ): """write a post-function decorator to replace a rendering callable with a cached version of itself.""" self.printer.writeline("__M_%s = %s" % (name, name)) - cachekey = node_or_pagetag.parsed_attributes.get('cache_key', - repr(name)) + cachekey = node_or_pagetag.parsed_attributes.get( + "cache_key", repr(name) + ) cache_args = {} if self.compiler.pagetag is not None: cache_args.update( - ( - pa[6:], - self.compiler.pagetag.parsed_attributes[pa] - ) + (pa[6:], self.compiler.pagetag.parsed_attributes[pa]) for pa in self.compiler.pagetag.parsed_attributes - if pa.startswith('cache_') and pa != 'cache_key' + if pa.startswith("cache_") and pa != "cache_key" ) cache_args.update( - ( - pa[6:], - node_or_pagetag.parsed_attributes[pa] - ) for pa in node_or_pagetag.parsed_attributes - if pa.startswith('cache_') and pa != 'cache_key' + (pa[6:], node_or_pagetag.parsed_attributes[pa]) + for pa in node_or_pagetag.parsed_attributes + if pa.startswith("cache_") and pa != "cache_key" ) - if 'timeout' in cache_args: - cache_args['timeout'] = int(eval(cache_args['timeout'])) + if "timeout" in cache_args: + cache_args["timeout"] = int(eval(cache_args["timeout"])) - self.printer.writeline("def %s(%s):" % (name, ','.join(args))) + self.printer.writeline("def %s(%s):" % (name, ",".join(args))) # 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() + 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 + 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, ) + ) # apply buffer_filters - s = self.create_filter_callable(self.compiler.buffer_filters, s, - False) + 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()]), + "%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 + None, ) def create_filter_callable(self, args, target, is_expression): @@ -753,14 +792,14 @@ class _GenerateRenderMethod(object): 'default' filter aliases as needed.""" def locate_encode(name): - if re.match(r'decode\..+', name): + if re.match(r"decode\..+", name): return "filters." + name elif self.compiler.disable_unicode: return filters.NON_UNICODE_ESCAPES.get(name, name) else: return filters.DEFAULT_ESCAPES.get(name, name) - if 'n' not in args: + if "n" not in args: if is_expression: if self.compiler.pagetag: args = self.compiler.pagetag.filter_args.args + args @@ -768,9 +807,9 @@ class _GenerateRenderMethod(object): args = self.compiler.default_filters + args for e in args: # if filter given as a function, get just the identifier portion - if e == 'n': + if e == "n": continue - m = re.match(r'(.+?)(\(.*\))', e) + m = re.match(r"(.+?)(\(.*\))", e) if m: ident, fargs = m.group(1, 2) f = locate_encode(ident) @@ -783,15 +822,18 @@ class _GenerateRenderMethod(object): def visitExpression(self, node): self.printer.start_source(node.lineno) - if len(node.escapes) or \ - ( - self.compiler.pagetag is not None and - len(self.compiler.pagetag.filter_args.args) - ) or \ - len(self.compiler.default_filters): - - s = self.create_filter_callable(node.escapes_code.args, - "%s" % node.text, True) + if ( + len(node.escapes) + or ( + self.compiler.pagetag is not None + and len(self.compiler.pagetag.filter_args.args) + ) + or len(self.compiler.default_filters) + ): + + s = self.create_filter_callable( + node.escapes_code.args, "%s" % node.text, True + ) self.printer.writeline("__M_writer(%s)" % s) else: self.printer.writeline("__M_writer(%s)" % node.text) @@ -800,12 +842,12 @@ class _GenerateRenderMethod(object): if node.isend: self.printer.writeline(None) if node.has_loop_context: - self.printer.writeline('finally:') + self.printer.writeline("finally:") self.printer.writeline("loop = __M_loop._exit()") self.printer.writeline(None) else: self.printer.start_source(node.lineno) - if self.compiler.enable_loop and node.keyword == 'for': + if self.compiler.enable_loop and node.keyword == "for": text = mangle_mako_loop(node, self.printer) else: text = node.text @@ -817,12 +859,16 @@ class _GenerateRenderMethod(object): # and end control lines, and # 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 - compat.all((node.is_ternary(c.keyword) or c.isend) - for c in children - if isinstance(c, parsetree.ControlLine))): + compat.all( + isinstance(c, (parsetree.Comment, 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) + ) + ): self.printer.writeline("pass") def visitText(self, node): @@ -833,8 +879,7 @@ class _GenerateRenderMethod(object): filtered = len(node.filter_args.args) > 0 if filtered: self.printer.writelines( - "__M_writer = context._push_writer()", - "try:", + "__M_writer = context._push_writer()", "try:" ) for n in node.nodes: n.accept_visitor(self) @@ -842,12 +887,11 @@ class _GenerateRenderMethod(object): self.printer.writelines( "finally:", "__M_buf, __M_writer = context._pop_buffer_and_writer()", - "__M_writer(%s)" % - self.create_filter_callable( - node.filter_args.args, - "__M_buf.getvalue()", - False), - None + "__M_writer(%s)" + % self.create_filter_callable( + node.filter_args.args, "__M_buf.getvalue()", False + ), + None, ) def visitCode(self, node): @@ -861,24 +905,28 @@ class _GenerateRenderMethod(object): # which is used for def calls within the same template, # to simulate "enclosing scope" self.printer.writeline( - '__M_locals_builtin_stored = __M_locals_builtin()') + "__M_locals_builtin_stored = __M_locals_builtin()" + ) self.printer.writeline( - '__M_locals.update(__M_dict_builtin([(__M_key,' - ' __M_locals_builtin_stored[__M_key]) for __M_key in' - ' [%s] if __M_key in __M_locals_builtin_stored]))' % - ','.join([repr(x) for x in node.declared_identifiers()])) + "__M_locals.update(__M_dict_builtin([(__M_key," + " __M_locals_builtin_stored[__M_key]) for __M_key in" + " [%s] if __M_key in __M_locals_builtin_stored]))" + % ",".join([repr(x) for x in node.declared_identifiers()]) + ) def visitIncludeTag(self, node): self.printer.start_source(node.lineno) - args = node.attributes.get('args') + 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 @@ -891,13 +939,14 @@ class _GenerateRenderMethod(object): self.printer.writeline("%s()" % node.funcname) else: nameargs = node.get_argument_expressions(as_call=True) - nameargs += ['**pageargs'] + nameargs += ["**pageargs"] self.printer.writeline( "if 'parent' not in context._data or " - "not hasattr(context._data['parent'], '%s'):" - % node.funcname) + "not hasattr(context._data['parent'], '%s'):" % node.funcname + ) self.printer.writeline( - "context['self'].%s(%s)" % (node.funcname, ",".join(nameargs))) + "context['self'].%s(%s)" % (node.funcname, ",".join(nameargs)) + ) self.printer.writeline("\n") def visitCallNamespaceTag(self, node): @@ -908,19 +957,18 @@ class _GenerateRenderMethod(object): def visitCallTag(self, node): self.printer.writeline("def ccall(caller):") - export = ['body'] + export = ["body"] callable_identifiers = self.identifiers.branch(node, nested=True) body_identifiers = callable_identifiers.branch(node, nested=False) # we want the 'caller' passed to ccall to be used # for the body() function, but for other non-body() # <%def>s within <%call> we want the current caller # off the call stack (if any) - body_identifiers.add_declared('caller') + body_identifiers.add_declared("caller") self.identifier_stack.append(body_identifiers) class DefVisitor(object): - def visitDefTag(s, node): s.visitDefOrBase(node) @@ -942,16 +990,13 @@ class _GenerateRenderMethod(object): self.identifier_stack.pop() bodyargs = node.body_decl.get_argument_expressions() - self.printer.writeline("def body(%s):" % ','.join(bodyargs)) + self.printer.writeline("def body(%s):" % ",".join(bodyargs)) # TODO: figure out best way to specify # buffering/nonbuffering (at call time would be better) buffered = False if buffered: - self.printer.writelines( - "context._push_buffer()", - "try:" - ) + self.printer.writelines("context._push_buffer()", "try:") self.write_variable_declares(body_identifiers) self.identifier_stack.append(body_identifiers) @@ -960,25 +1005,22 @@ class _GenerateRenderMethod(object): self.identifier_stack.pop() self.write_def_finish(node, buffered, False, False, callstack=False) - self.printer.writelines( - None, - "return [%s]" % (','.join(export)), - None - ) + self.printer.writelines(None, "return [%s]" % (",".join(export)), None) self.printer.writelines( # push on caller for nested call "context.caller_stack.nextcaller = " "runtime.Namespace('caller', context, " "callables=ccall(__M_caller))", - "try:") + "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", - None + None, ) @@ -996,10 +1038,12 @@ class _Identifiers(object): else: # 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) + self.declared = ( + set(parent.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 @@ -1043,11 +1087,13 @@ class _Identifiers(object): 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)) + "Reserved words declared in template: %s" + % ", ".join(illegal_names) + ) def branch(self, node, **kwargs): """create a new Identifiers for a new Node, with @@ -1060,24 +1106,28 @@ class _Identifiers(object): return set(self.topleveldefs.union(self.closuredefs).values()) def __repr__(self): - return "Identifiers(declared=%r, locally_declared=%r, "\ - "undeclared=%r, topleveldefs=%r, closuredefs=%r, "\ - "argumentdeclared=%r)" %\ - ( + 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) + self.argument_declared, + ) + ) def check_declared(self, node): """update the state of this Identifiers with the undeclared and declared identifiers of the given node.""" for ident in node.undeclared_identifiers(): - if ident != 'context' and\ - ident not in self.declared.union(self.locally_declared): + if ident != "context" and ident not in self.declared.union( + self.locally_declared + ): self.undeclared.add(ident) for ident in node.declared_identifiers(): self.locally_declared.add(ident) @@ -1097,7 +1147,8 @@ class _Identifiers(object): 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 @@ -1110,13 +1161,16 @@ class _Identifiers(object): def _check_name_exists(self, collection, node): 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): + if ( + existing is not None + and 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) + "exists in this template." % node.funcname, + **node.exception_kwargs + ) def visitDefTag(self, node): if node.is_root() and not node.is_anonymous: @@ -1125,8 +1179,9 @@ class _Identifiers(object): self._check_name_exists(self.closuredefs, node) for ident in node.undeclared_identifiers(): - if ident != 'context' and \ - ident not in self.declared.union(self.locally_declared): + if ident != "context" and ident not in self.declared.union( + self.locally_declared + ): self.undeclared.add(ident) # visit defs only one level deep @@ -1143,16 +1198,22 @@ class _Identifiers(object): 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) - elif isinstance(self.node, - (parsetree.CallTag, parsetree.CallNamespaceTag)): + % (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) + % (node.name,), + **node.exception_kwargs + ) for ident in node.undeclared_identifiers(): - if ident != 'context' and \ - ident not in self.declared.union(self.locally_declared): + if ident != "context" and ident not in self.declared.union( + self.locally_declared + ): self.undeclared.add(ident) if not node.is_anonymous: @@ -1167,8 +1228,9 @@ class _Identifiers(object): def visitTextTag(self, node): for ident in node.undeclared_identifiers(): - if ident != 'context' and \ - ident not in self.declared.union(self.locally_declared): + if ident != "context" and ident not in self.declared.union( + self.locally_declared + ): self.undeclared.add(ident) def visitIncludeTag(self, node): @@ -1185,9 +1247,9 @@ class _Identifiers(object): def visitCallTag(self, node): if node is self.node: for ident in node.undeclared_identifiers(): - if ident != 'context' and \ - ident not in self.declared.union( - self.locally_declared): + if ident != "context" and ident not in self.declared.union( + self.locally_declared + ): self.undeclared.add(ident) for ident in node.declared_identifiers(): self.argument_declared.add(ident) @@ -1195,15 +1257,15 @@ class _Identifiers(object): n.accept_visitor(self) else: for ident in node.undeclared_identifiers(): - if ident != 'context' and \ - ident not in self.declared.union( - self.locally_declared): + if ident != "context" and ident not in self.declared.union( + 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+(.*):" ) @@ -1218,11 +1280,11 @@ def mangle_mako_loop(node, printer): match = _FOR_LOOP.match(node.text) if match: printer.writelines( - 'loop = __M_loop._enter(%s)' % match.group(2), - 'try:' + "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) + text = "for %s in loop:" % match.group(1) else: raise SyntaxError("Couldn't apply loop context: %s" % node.text) else: @@ -1239,7 +1301,7 @@ class LoopVariable(object): self.detected = False def _loop_reference_detected(self, node): - if 'loop' in node.undeclared_identifiers(): + if "loop" in node.undeclared_identifiers(): self.detected = True else: for n in node.get_children(): diff --git a/mako/compat.py b/mako/compat.py index 312bbd8..5f9d9ac 100644 --- a/mako/compat.py +++ b/mako/compat.py @@ -1,3 +1,4 @@ +import json # noqa import sys import time @@ -5,9 +6,9 @@ py3k = sys.version_info >= (3, 0) py33 = sys.version_info >= (3, 3) py2k = sys.version_info < (3,) py27 = sys.version_info >= (2, 7) -jython = sys.platform.startswith('java') -win32 = sys.platform.startswith('win') -pypy = hasattr(sys, 'pypy_version_info') +jython = sys.platform.startswith("java") +win32 = sys.platform.startswith("win") +pypy = hasattr(sys, "pypy_version_info") if py3k: # create a "getargspec" from getfullargspec(), which is not deprecated @@ -17,15 +18,16 @@ if py3k: # with that for now. import collections + ArgSpec = collections.namedtuple( - "ArgSpec", - ["args", "varargs", "keywords", "defaults"]) + "ArgSpec", ["args", "varargs", "keywords", "defaults"] + ) from inspect import getfullargspec as inspect_getfullargspec def inspect_getargspec(func): - return ArgSpec( - *inspect_getfullargspec(func)[0:4] - ) + return ArgSpec(*inspect_getfullargspec(func)[0:4]) + + else: from inspect import getargspec as inspect_getargspec # noqa @@ -35,7 +37,8 @@ if py3k: import builtins as compat_builtins from urllib.parse import quote_plus, unquote_plus from html.entities import codepoint2name, name2codepoint - string_types = str, + + string_types = (str,) binary_type = bytes text_type = str @@ -50,8 +53,10 @@ if py3k: def octal(lit): return eval("0o" + lit) + else: import __builtin__ as compat_builtins # noqa + try: from cStringIO import StringIO except: @@ -61,7 +66,8 @@ else: from urllib import quote_plus, unquote_plus # noqa from htmlentitydefs import codepoint2name, name2codepoint # noqa - string_types = basestring, # noqa + + string_types = (basestring,) # noqa binary_type = str text_type = unicode # noqa @@ -80,11 +86,13 @@ if py33: 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') + fp = open(path, "rb") try: return imp.load_source(module_id, path, fp) finally: @@ -92,28 +100,36 @@ else: if py3k: + def reraise(tp, value, tb=None, cause=None): if cause is not None: value.__cause__ = cause if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value + + else: - exec("def reraise(tp, value, tb=None, cause=None):\n" - " raise tp, value, tb\n") + exec( + "def reraise(tp, value, tb=None, cause=None):\n" + " raise tp, value, tb\n" + ) def exception_as(): return sys.exc_info()[1] + try: import threading + if py3k: import _thread as thread else: import thread except ImportError: import dummy_threading as threading # noqa + if py3k: import _dummy_thread as thread else: @@ -127,21 +143,23 @@ else: try: from functools import partial except: + def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func(*(args + fargs), **newkeywords) + return newfunc -all = all -import json # noqa +all = all # noqa def exception_name(exc): return exc.__class__.__name__ + try: from inspect import CO_VARKEYWORDS, CO_VARARGS @@ -167,17 +185,23 @@ try: return args, varargs, varkw, fn.__defaults__ else: return args, varargs, varkw, fn.func_defaults + + except ImportError: import inspect def inspect_func_args(fn): return inspect.getargspec(fn) + if py3k: - def callable(fn): - return hasattr(fn, '__call__') + # TODO: this has been restored in py3k + def callable(fn): # noqa + return hasattr(fn, "__call__") + + else: - callable = callable + callable = callable # noqa ################################################ @@ -186,6 +210,8 @@ else: def with_metaclass(meta, base=object): """Create a base class with a metaclass.""" return meta("%sBase" % meta.__name__, (base,), {}) + + ################################################ @@ -194,7 +220,7 @@ def arg_stringname(func_arg): In Python3.4 a function's args are of _ast.arg type not _ast.name """ - if hasattr(func_arg, 'arg'): + if hasattr(func_arg, "arg"): return func_arg.arg else: return str(func_arg) diff --git a/mako/exceptions.py b/mako/exceptions.py index e2d78bd..7720356 100644 --- a/mako/exceptions.py +++ b/mako/exceptions.py @@ -6,9 +6,11 @@ """exception classes""" -import traceback import sys -from mako import util, compat +import traceback + +from mako import compat +from mako import util class MakoException(Exception): @@ -27,11 +29,10 @@ def _format_filepos(lineno, pos, filename): class CompileException(MakoException): - def __init__(self, message, source, lineno, pos, filename): MakoException.__init__( - self, - message + _format_filepos(lineno, pos, filename)) + self, message + _format_filepos(lineno, pos, filename) + ) self.lineno = lineno self.pos = pos self.filename = filename @@ -39,11 +40,10 @@ class CompileException(MakoException): class SyntaxException(MakoException): - def __init__(self, message, source, lineno, pos, filename): MakoException.__init__( - self, - message + _format_filepos(lineno, pos, filename)) + self, message + _format_filepos(lineno, pos, filename) + ) self.lineno = lineno self.pos = pos self.filename = filename @@ -115,7 +115,7 @@ class RichTraceback(object): # str(Exception(u'\xe6')) work in Python < 2.6 self.message = self.error.args[0] if not isinstance(self.message, compat.text_type): - self.message = compat.text_type(self.message, 'ascii', 'replace') + self.message = compat.text_type(self.message, "ascii", "replace") def _get_reformatted_records(self, records): for rec in records: @@ -151,12 +151,13 @@ class RichTraceback(object): source, and code line from that line number of the template.""" import mako.template + mods = {} rawrecords = traceback.extract_tb(trcback) new_trcback = [] for filename, lineno, function, line in rawrecords: if not line: - line = '' + line = "" try: (line_map, template_lines) = mods[filename] except KeyError: @@ -169,7 +170,7 @@ class RichTraceback(object): # A normal .py file (not a Template) if not compat.py3k: try: - fp = open(filename, 'rb') + fp = open(filename, "rb") encoding = util.parse_encoding(fp) fp.close() except IOError: @@ -177,20 +178,32 @@ class RichTraceback(object): if encoding: line = line.decode(encoding) else: - line = line.decode('ascii', 'replace') - new_trcback.append((filename, lineno, function, line, - None, None, None, None)) + line = line.decode("ascii", "replace") + new_trcback.append( + ( + filename, + lineno, + function, + line, + None, + None, + None, + None, + ) + ) continue template_ln = 1 - source_map = mako.template.ModuleInfo.\ - get_module_source_metadata( - module_source, full_line_map=True) - line_map = source_map['full_line_map'] + mtm = mako.template.ModuleInfo + source_map = mtm.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] @@ -199,9 +212,18 @@ class RichTraceback(object): template_line = template_lines[template_ln - 1] else: template_line = None - new_trcback.append((filename, lineno, function, - line, template_filename, template_ln, - template_line, template_source)) + new_trcback.append( + ( + filename, + lineno, + function, + line, + template_filename, + template_ln, + template_line, + template_source, + ) + ) if not self.source: for l in range(len(new_trcback) - 1, 0, -1): if new_trcback[l][5]: @@ -212,17 +234,17 @@ class RichTraceback(object): if new_trcback: try: # A normal .py file (not a Template) - fp = open(new_trcback[-1][0], 'rb') + fp = open(new_trcback[-1][0], "rb") encoding = util.parse_encoding(fp) if compat.py3k and not encoding: - encoding = 'utf-8' + encoding = "utf-8" fp.seek(0) self.source = fp.read() fp.close() if encoding: self.source = self.source.decode(encoding) except IOError: - self.source = '' + self.source = "" self.lineno = new_trcback[-1][1] return new_trcback @@ -235,7 +257,9 @@ def text_error_template(lookup=None): """ import mako.template - return mako.template.Template(r""" + + return mako.template.Template( + r""" <%page args="error=None, traceback=None"/> <%! from mako.exceptions import RichTraceback @@ -249,7 +273,8 @@ Traceback (most recent call last): ${line | trim} % endfor ${tback.errorname}: ${tback.message} -""") +""" + ) def _install_pygments(): @@ -261,9 +286,10 @@ def _install_pygments(): 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): + def syntax_highlight(filename="", language=None): return html_escape @@ -272,6 +298,8 @@ def _install_highlighting(): _install_pygments() except ImportError: _install_fallback() + + _install_highlighting() @@ -289,7 +317,9 @@ def html_error_template(): """ import mako.template - return mako.template.Template(r""" + + return mako.template.Template( + r""" <%! from mako.exceptions import RichTraceback, syntax_highlight,\ pygments_html_formatter @@ -392,5 +422,7 @@ def html_error_template(): </body> </html> % endif -""", output_encoding=sys.getdefaultencoding(), - encoding_errors='htmlentityreplace') +""", + output_encoding=sys.getdefaultencoding(), + encoding_errors="htmlentityreplace", + ) diff --git a/mako/ext/autohandler.py b/mako/ext/autohandler.py index 9d1c911..f262b13 100644 --- a/mako/ext/autohandler.py +++ b/mako/ext/autohandler.py @@ -8,29 +8,29 @@ requires that the TemplateLookup class is used with templates. -usage: +usage:: -<%! - from mako.ext.autohandler import autohandler -%> -<%inherit file="${autohandler(template, context)}"/> + <%! + from mako.ext.autohandler import autohandler + %> + <%inherit file="${autohandler(template, context)}"/> -or with custom autohandler filename: +or with custom autohandler filename:: -<%! - from mako.ext.autohandler import autohandler -%> -<%inherit file="${autohandler(template, context, name='somefilename')}"/> + <%! + from mako.ext.autohandler import autohandler + %> + <%inherit file="${autohandler(template, context, name='somefilename')}"/> """ -import posixpath import os +import posixpath import re -def autohandler(template, context, name='autohandler'): +def autohandler(template, context, name="autohandler"): lookup = context.lookup _template_uri = template.module._template_uri if not lookup.filesystem_checks: @@ -39,13 +39,14 @@ def autohandler(template, context, name='autohandler'): except KeyError: pass - tokens = re.findall(r'([^/]+)', posixpath.dirname(_template_uri)) + [name] + tokens = re.findall(r"([^/]+)", posixpath.dirname(_template_uri)) + [name] while len(tokens): - path = '/' + '/'.join(tokens) + path = "/" + "/".join(tokens) 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: @@ -54,15 +55,16 @@ def autohandler(template, context, name='autohandler'): 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): + if os.path.exists(d + "/" + psub): return True else: return False diff --git a/mako/ext/babelplugin.py b/mako/ext/babelplugin.py index 0b5e84f..e7e93f5 100644 --- a/mako/ext/babelplugin.py +++ b/mako/ext/babelplugin.py @@ -6,18 +6,19 @@ """gettext message extraction via Babel: http://babel.edgewall.org/""" from babel.messages.extract import extract_python + from mako.ext.extract import MessageExtractor 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__() @@ -25,12 +26,19 @@ class BabelMakoExtractor(MessageExtractor): return self.process_file(fileobj) def process_python(self, code, code_lineno, translator_strings): - comment_tags = self.config['comment-tags'] - for lineno, funcname, messages, python_translator_comments \ - in extract_python(code, - self.keywords, comment_tags, self.options): - yield (code_lineno + (lineno - 1), funcname, messages, - translator_strings + python_translator_comments) + comment_tags = self.config["comment-tags"] + for ( + lineno, + funcname, + messages, + python_translator_comments, + ) in extract_python(code, self.keywords, comment_tags, self.options): + yield ( + code_lineno + (lineno - 1), + funcname, + messages, + translator_strings + python_translator_comments, + ) def extract(fileobj, keywords, comment_tags, options): diff --git a/mako/ext/beaker_cache.py b/mako/ext/beaker_cache.py index c7c260d..ebca8a9 100644 --- a/mako/ext/beaker_cache.py +++ b/mako/ext/beaker_cache.py @@ -1,7 +1,6 @@ """Provide a :class:`.CacheImpl` for the Beaker caching system.""" from mako import exceptions - from mako.cache import CacheImpl try: @@ -27,36 +26,37 @@ class BeakerCacheImpl(CacheImpl): def __init__(self, cache): if not has_beaker: raise exceptions.RuntimeException( - "Can't initialize Beaker plugin; Beaker is not installed.") + "Can't initialize Beaker plugin; Beaker is not installed." + ) global _beaker_cache if _beaker_cache is None: - if 'manager' in cache.template.cache_args: - _beaker_cache = cache.template.cache_args['manager'] + if "manager" in cache.template.cache_args: + _beaker_cache = cache.template.cache_args["manager"] else: _beaker_cache = beaker_cache.CacheManager() super(BeakerCacheImpl, self).__init__(cache) def _get_cache(self, **kw): - expiretime = kw.pop('timeout', None) - if 'dir' in kw: - kw['data_dir'] = kw.pop('dir') + expiretime = kw.pop("timeout", None) + if "dir" in kw: + kw["data_dir"] = kw.pop("dir") elif self.cache.template.module_directory: - kw['data_dir'] = self.cache.template.module_directory + kw["data_dir"] = self.cache.template.module_directory - if 'manager' in kw: - kw.pop('manager') + if "manager" in kw: + kw.pop("manager") - if kw.get('type') == 'memcached': - kw['type'] = 'ext:memcached' + if kw.get("type") == "memcached": + kw["type"] = "ext:memcached" - if 'region' in kw: - region = kw.pop('region') + if "region" in kw: + region = kw.pop("region") cache = _beaker_cache.get_cache_region(self.cache.id, region, **kw) else: cache = _beaker_cache.get_cache(self.cache.id, **kw) - cache_args = {'starttime': self.cache.starttime} + cache_args = {"starttime": self.cache.starttime} if expiretime: - cache_args['expiretime'] = expiretime + cache_args["expiretime"] = expiretime return cache, cache_args def get_or_create(self, key, creation_function, **kw): diff --git a/mako/ext/extract.py b/mako/ext/extract.py index d777ea8..766129b 100644 --- a/mako/ext/extract.py +++ b/mako/ext/extract.py @@ -1,30 +1,33 @@ import re + from mako import compat from mako import lexer from mako import parsetree class MessageExtractor(object): - def process_file(self, fileobj): template_node = lexer.Lexer( - fileobj.read(), - input_encoding=self.config['encoding']).parse() + fileobj.read(), input_encoding=self.config["encoding"] + ).parse() for extracted in self.extract_nodes(template_node.get_children()): yield extracted def extract_nodes(self, nodes): translator_comments = [] in_translator_comments = False - input_encoding = self.config['encoding'] or 'ascii' + input_encoding = self.config["encoding"] or "ascii" comment_tags = list( - filter(None, re.split(r'\s+', self.config['comment-tags']))) + filter(None, re.split(r"\s+", self.config["comment-tags"])) + ) for node in nodes: child_nodes = None - if in_translator_comments and \ - isinstance(node, parsetree.Text) and \ - not node.content.strip(): + if ( + in_translator_comments + and isinstance(node, parsetree.Text) + and not node.content.strip() + ): # Ignore whitespace within translator comments continue @@ -32,13 +35,15 @@ class MessageExtractor(object): value = node.text.strip() if in_translator_comments: translator_comments.extend( - self._split_comment(node.lineno, value)) + self._split_comment(node.lineno, value) + ) continue for comment_tag in comment_tags: if value.startswith(comment_tag): in_translator_comments = True translator_comments.extend( - self._split_comment(node.lineno, value)) + self._split_comment(node.lineno, value) + ) continue if isinstance(node, parsetree.DefTag): @@ -69,15 +74,18 @@ class MessageExtractor(object): continue # Comments don't apply unless they immediately precede the message - if translator_comments and \ - translator_comments[-1][0] < node.lineno - 1: + if ( + translator_comments + and translator_comments[-1][0] < node.lineno - 1 + ): translator_comments = [] translator_strings = [ - comment[1] for comment in translator_comments] + comment[1] for comment in translator_comments + ] if isinstance(code, compat.text_type): - code = code.encode(input_encoding, 'backslashreplace') + code = code.encode(input_encoding, "backslashreplace") used_translator_comments = False # We add extra newline to work around a pybabel bug @@ -85,10 +93,11 @@ class MessageExtractor(object): # input string of the input is non-ascii) # Also, because we added it, we have to subtract one from # node.lineno - code = compat.byte_buffer(compat.b('\n') + code) + code = compat.byte_buffer(compat.b("\n") + code) for message in self.process_python( - code, node.lineno - 1, translator_strings): + code, node.lineno - 1, translator_strings + ): yield message used_translator_comments = True @@ -104,5 +113,7 @@ class MessageExtractor(object): def _split_comment(lineno, comment): """Return the multiline comment at lineno split into a list of comment line numbers and the accompanying comment line""" - return [(lineno + index, line) for index, line in - enumerate(comment.splitlines())] + return [ + (lineno + index, line) + for index, line in enumerate(comment.splitlines()) + ] diff --git a/mako/ext/linguaplugin.py b/mako/ext/linguaplugin.py index 46b0d6a..dda3422 100644 --- a/mako/ext/linguaplugin.py +++ b/mako/ext/linguaplugin.py @@ -1,43 +1,51 @@ import io + from lingua.extractors import Extractor -from lingua.extractors import Message from lingua.extractors import get_extractor -from mako.ext.extract import MessageExtractor +from lingua.extractors import Message + from mako import compat +from mako.ext.extract import MessageExtractor class LinguaMakoExtractor(Extractor, MessageExtractor): - '''Mako templates''' - extensions = ['.mako'] - default_config = { - 'encoding': 'utf-8', - 'comment-tags': '', - } + """Mako templates""" + + extensions = [".mako"] + default_config = {"encoding": "utf-8", "comment-tags": ""} def __call__(self, filename, options, fileobj=None): self.options = options self.filename = filename - self.python_extractor = get_extractor('x.py') + self.python_extractor = get_extractor("x.py") if fileobj is None: - fileobj = open(filename, 'rb') + fileobj = open(filename, "rb") return self.process_file(fileobj) def process_python(self, code, code_lineno, translator_strings): source = code.getvalue().strip() - if source.endswith(compat.b(':')): - if source in (compat.b('try:'), compat.b('else:')) or source.startswith(compat.b('except')): - source = compat.b('') # Ignore try/except and else - elif source.startswith(compat.b('elif')): - source = source[2:] # Replace "elif" with "if" - source += compat.b('pass') + if source.endswith(compat.b(":")): + if source in ( + compat.b("try:"), + compat.b("else:"), + ) or source.startswith(compat.b("except")): + source = compat.b("") # Ignore try/except and else + elif source.startswith(compat.b("elif")): + source = source[2:] # Replace "elif" with "if" + source += compat.b("pass") code = io.BytesIO(source) for msg in self.python_extractor( - self.filename, self.options, code, code_lineno -1): + self.filename, self.options, code, code_lineno - 1 + ): if translator_strings: - msg = Message(msg.msgctxt, msg.msgid, msg.msgid_plural, - msg.flags, - compat.u(' ').join( - translator_strings + [msg.comment]), - msg.tcomment, msg.location) + msg = Message( + msg.msgctxt, + msg.msgid, + msg.msgid_plural, + msg.flags, + compat.u(" ").join(translator_strings + [msg.comment]), + msg.tcomment, + msg.location, + ) yield msg diff --git a/mako/ext/preprocessors.py b/mako/ext/preprocessors.py index 9b700d1..524b87f 100644 --- a/mako/ext/preprocessors.py +++ b/mako/ext/preprocessors.py @@ -17,4 +17,4 @@ def convert_comments(text): from mako.ext.preprocessors import convert_comments t = Template(..., preprocessor=convert_comments)""" - return re.sub(r'(?<=\n)\s*#[^#]', "##", text) + return re.sub(r"(?<=\n)\s*#[^#]", "##", text) diff --git a/mako/ext/pygmentplugin.py b/mako/ext/pygmentplugin.py index 4057caa..809e696 100644 --- a/mako/ext/pygmentplugin.py +++ b/mako/ext/pygmentplugin.py @@ -4,42 +4,70 @@ # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -from pygments.lexers.web import \ - HtmlLexer, XmlLexer, JavascriptLexer, CssLexer -from pygments.lexers.agile import PythonLexer, Python3Lexer -from pygments.lexer import DelegatingLexer, RegexLexer, bygroups, \ - include, using -from pygments.token import \ - Text, Comment, Operator, Keyword, Name, String, Other -from pygments.formatters.html import HtmlFormatter from pygments import highlight +from pygments.formatters.html import HtmlFormatter +from pygments.lexer import bygroups +from pygments.lexer import DelegatingLexer +from pygments.lexer import include +from pygments.lexer import RegexLexer +from pygments.lexer import using +from pygments.lexers.agile import Python3Lexer +from pygments.lexers.agile import PythonLexer +from pygments.lexers.web import CssLexer +from pygments.lexers.web import HtmlLexer +from pygments.lexers.web import JavascriptLexer +from pygments.lexers.web import XmlLexer +from pygments.token import Comment +from pygments.token import Keyword +from pygments.token import Name +from pygments.token import Operator +from pygments.token import Other +from pygments.token import String +from pygments.token import Text + from mako import compat class MakoLexer(RegexLexer): - name = 'Mako' - aliases = ['mako'] - filenames = ['*.mao'] + name = "Mako" + aliases = ["mako"] + filenames = ["*.mao"] tokens = { - 'root': [ - (r'(\s*)(\%)(\s*end(?:\w+))(\n|\Z)', - bygroups(Text, Comment.Preproc, Keyword, Other)), - (r'(\s*)(\%(?!%))([^\n]*)(\n|\Z)', - bygroups(Text, Comment.Preproc, using(PythonLexer), Other)), - (r'(\s*)(##[^\n]*)(\n|\Z)', - bygroups(Text, Comment.Preproc, Other)), - (r'''(?s)<%doc>.*?</%doc>''', Comment.Preproc), - (r'(<%)([\w\.\:]+)', - bygroups(Comment.Preproc, Name.Builtin), 'tag'), - (r'(</%)([\w\.\:]+)(>)', - bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc)), - (r'<%(?=([\w\.\:]+))', Comment.Preproc, 'ondeftags'), - (r'(<%(?:!?))(.*?)(%>)(?s)', - bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)), - (r'(\$\{)(.*?)(\})', - bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc)), - (r'''(?sx) + "root": [ + ( + r"(\s*)(\%)(\s*end(?:\w+))(\n|\Z)", + bygroups(Text, Comment.Preproc, Keyword, Other), + ), + ( + r"(\s*)(\%(?!%))([^\n]*)(\n|\Z)", + bygroups(Text, Comment.Preproc, using(PythonLexer), Other), + ), + ( + r"(\s*)(##[^\n]*)(\n|\Z)", + bygroups(Text, Comment.Preproc, Other), + ), + (r"""(?s)<%doc>.*?</%doc>""", Comment.Preproc), + ( + r"(<%)([\w\.\:]+)", + bygroups(Comment.Preproc, Name.Builtin), + "tag", + ), + ( + r"(</%)([\w\.\:]+)(>)", + bygroups(Comment.Preproc, Name.Builtin, Comment.Preproc), + ), + (r"<%(?=([\w\.\:]+))", Comment.Preproc, "ondeftags"), + ( + r"(<%(?:!?))(.*?)(%>)(?s)", + bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc), + ), + ( + r"(\$\{)(.*?)(\})", + bygroups(Comment.Preproc, using(PythonLexer), Comment.Preproc), + ), + ( + r"""(?sx) (.+?) # anything, followed by: (?: (?<=\n)(?=%(?!%)|\#\#) | # an eval or comment line @@ -52,76 +80,78 @@ class MakoLexer(RegexLexer): (\\\n) | # an escaped newline \Z # end of string ) - ''', bygroups(Other, Operator)), - (r'\s+', Text), + """, + bygroups(Other, Operator), + ), + (r"\s+", Text), ], - 'ondeftags': [ - (r'<%', Comment.Preproc), - (r'(?<=<%)(include|inherit|namespace|page)', Name.Builtin), - include('tag'), + "ondeftags": [ + (r"<%", Comment.Preproc), + (r"(?<=<%)(include|inherit|namespace|page)", Name.Builtin), + include("tag"), ], - 'tag': [ - (r'((?:\w+)\s*=)\s*(".*?")', - bygroups(Name.Attribute, String)), - (r'/?\s*>', Comment.Preproc, '#pop'), - (r'\s+', Text), + "tag": [ + (r'((?:\w+)\s*=)\s*(".*?")', bygroups(Name.Attribute, String)), + (r"/?\s*>", Comment.Preproc, "#pop"), + (r"\s+", Text), ], - 'attr': [ - ('".*?"', String, '#pop'), - ("'.*?'", String, '#pop'), - (r'[^\s>]+', String, '#pop'), + "attr": [ + ('".*?"', String, "#pop"), + ("'.*?'", String, "#pop"), + (r"[^\s>]+", String, "#pop"), ], } class MakoHtmlLexer(DelegatingLexer): - name = 'HTML+Mako' - aliases = ['html+mako'] + name = "HTML+Mako" + aliases = ["html+mako"] def __init__(self, **options): - super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer, - **options) + super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer, **options) class MakoXmlLexer(DelegatingLexer): - name = 'XML+Mako' - aliases = ['xml+mako'] + name = "XML+Mako" + aliases = ["xml+mako"] def __init__(self, **options): - super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer, - **options) + super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer, **options) class MakoJavascriptLexer(DelegatingLexer): - name = 'JavaScript+Mako' - aliases = ['js+mako', 'javascript+mako'] + name = "JavaScript+Mako" + aliases = ["js+mako", "javascript+mako"] def __init__(self, **options): - super(MakoJavascriptLexer, self).__init__(JavascriptLexer, - MakoLexer, **options) + super(MakoJavascriptLexer, self).__init__( + JavascriptLexer, MakoLexer, **options + ) class MakoCssLexer(DelegatingLexer): - name = 'CSS+Mako' - aliases = ['css+mako'] + name = "CSS+Mako" + aliases = ["css+mako"] def __init__(self, **options): - super(MakoCssLexer, self).__init__(CssLexer, MakoLexer, - **options) + super(MakoCssLexer, self).__init__(CssLexer, MakoLexer, **options) -pygments_html_formatter = HtmlFormatter(cssclass='syntax-highlighted', - linenos=True) +pygments_html_formatter = HtmlFormatter( + cssclass="syntax-highlighted", linenos=True +) -def syntax_highlight(filename='', language=None): +def syntax_highlight(filename="", language=None): mako_lexer = MakoLexer() if compat.py3k: python_lexer = Python3Lexer() else: python_lexer = PythonLexer() - if filename.startswith('memory:') or language == 'mako': - return lambda string: highlight(string, mako_lexer, - pygments_html_formatter) - return lambda string: highlight(string, python_lexer, - pygments_html_formatter) + if filename.startswith("memory:") or language == "mako": + return lambda string: highlight( + string, mako_lexer, 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 eaa2d78..ee1147d 100644 --- a/mako/ext/turbogears.py +++ b/mako/ext/turbogears.py @@ -13,7 +13,7 @@ class TGPlugin(object): """TurboGears compatible Template Plugin.""" - def __init__(self, extra_vars_func=None, options=None, extension='mak'): + def __init__(self, extra_vars_func=None, options=None, extension="mak"): self.extra_vars_func = extra_vars_func self.extension = extension if not options: @@ -22,9 +22,9 @@ class TGPlugin(object): # Pull the options out and initialize the lookup lookup_options = {} for k, v in options.items(): - if k.startswith('mako.'): + if k.startswith("mako."): lookup_options[k[5:]] = v - elif k in ['directories', 'filesystem_checks', 'module_directory']: + elif k in ["directories", "filesystem_checks", "module_directory"]: lookup_options[k] = v self.lookup = TemplateLookup(**lookup_options) @@ -40,14 +40,17 @@ class TGPlugin(object): if template_string is not None: return Template(template_string, **self.tmpl_options) # Translate TG dot notation to normal / template path - if '/' not in templatename: - templatename = '/' + templatename.replace('.', '/') + '.' +\ - self.extension + if "/" not in templatename: + templatename = ( + "/" + templatename.replace(".", "/") + "." + self.extension + ) # Lookup template return self.lookup.get_template(templatename) - def render(self, info, format="html", fragment=False, template=None): + def render( + self, info, format="html", fragment=False, template=None # noqa + ): if isinstance(template, compat.string_types): template = self.load_template(template) diff --git a/mako/filters.py b/mako/filters.py index c082690..56d1d73 100644 --- a/mako/filters.py +++ b/mako/filters.py @@ -5,20 +5,21 @@ # the MIT License: http://www.opensource.org/licenses/mit-license.php -import re import codecs - -from mako.compat import quote_plus, unquote_plus, codepoint2name, \ - name2codepoint +import re from mako import compat +from mako.compat import codepoint2name +from mako.compat import name2codepoint +from mako.compat import quote_plus +from mako.compat import unquote_plus xml_escapes = { - '&': '&', - '>': '>', - '<': '<', - '"': '"', # also " in html-only - "'": ''' # also ' in html-only + "&": "&", + ">": ">", + "<": "<", + '"': """, # also " in html-only + "'": "'", # also ' in html-only } # XXX: " is valid in HTML and XML @@ -37,6 +38,7 @@ def legacy_html_escape(s): try: import markupsafe + html_escape = markupsafe.escape except ImportError: html_escape = legacy_html_escape @@ -69,7 +71,6 @@ def trim(string): class Decode(object): - def __getattr__(self, key): def decode(x): if isinstance(x, compat.text_type): @@ -78,24 +79,31 @@ class Decode(object): return decode(str(x)) else: return compat.text_type(x, encoding=key) + return decode + + decode = Decode() -_ASCII_re = re.compile(r'\A[\x00-\x7f]*\Z') +_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()]) + self.codepoint2entity = dict( + [ + (c, compat.text_type("&%s;" % n)) + for c, n in codepoint2name.items() + ] + ) self.name2codepoint = name2codepoint def escape_entities(self, text): @@ -110,7 +118,7 @@ class XMLEntityEscaper(object): try: return self.codepoint2entity[codepoint] except (KeyError, IndexError): - return '&#x%X;' % codepoint + return "&#x%X;" % codepoint __escapable = re.compile(r'["&<>]|[^\x00-\x7f]') @@ -123,19 +131,22 @@ class XMLEntityEscaper(object): The return value is guaranteed to be ASCII. """ - return self.__escapable.sub(self.__escape, compat.text_type(text) - ).encode('ascii') + return self.__escapable.sub( + self.__escape, compat.text_type(text) + ).encode("ascii") # XXX: This regexp will not match all valid XML entity names__. # (It punts on details involving involving CombiningChars and Extenders.) # # .. __: http://www.w3.org/TR/2000/REC-xml-20001006#NT-EntityRef - __characterrefs = re.compile(r'''& (?: + __characterrefs = re.compile( + r"""& (?: \#(\d+) | \#x([\da-f]+) | ( (?!\d) [:\w] [-.:\w]+ ) - ) ;''', - re.X | re.UNICODE) + ) ;""", + re.X | re.UNICODE, + ) def __unescape(self, m): dval, hval, name = m.groups() @@ -144,7 +155,7 @@ class XMLEntityEscaper(object): elif hval: codepoint = int(hval, 16) else: - codepoint = self.name2codepoint.get(name, 0xfffd) + codepoint = self.name2codepoint.get(name, 0xFFFD) # U+FFFD = "REPLACEMENT CHARACTER" if codepoint < 128: return chr(codepoint) @@ -168,42 +179,41 @@ html_entities_unescape = _html_entities_escaper.unescape def htmlentityreplace_errors(ex): """An encoding error handler. - This python `codecs`_ error handler replaces unencodable + This python codecs error handler replaces unencodable characters with HTML entities, or, if no HTML entity exists for - the character, XML character references. + the character, XML character references:: - >>> u'The cost was \u20ac12.'.encode('latin1', 'htmlentityreplace') - 'The cost was €12.' + >>> u'The cost was \u20ac12.'.encode('latin1', 'htmlentityreplace') + 'The cost was €12.' """ if isinstance(ex, UnicodeEncodeError): # Handle encoding errors - bad_text = ex.object[ex.start:ex.end] + bad_text = ex.object[ex.start : ex.end] text = _html_entities_escaper.escape(bad_text) return (compat.text_type(text), ex.end) raise ex -codecs.register_error('htmlentityreplace', htmlentityreplace_errors) + +codecs.register_error("htmlentityreplace", htmlentityreplace_errors) # TODO: options to make this dynamic per-compilation will be added in a later # release DEFAULT_ESCAPES = { - 'x': 'filters.xml_escape', - 'h': 'filters.html_escape', - 'u': 'filters.url_escape', - 'trim': 'filters.trim', - 'entity': 'filters.html_entities_escape', - 'unicode': 'unicode', - 'decode': 'decode', - 'str': 'str', - 'n': 'n' + "x": "filters.xml_escape", + "h": "filters.html_escape", + "u": "filters.url_escape", + "trim": "filters.trim", + "entity": "filters.html_entities_escape", + "unicode": "unicode", + "decode": "decode", + "str": "str", + "n": "n", } if compat.py3k: - DEFAULT_ESCAPES.update({ - 'unicode': 'str' - }) + DEFAULT_ESCAPES.update({"unicode": "str"}) NON_UNICODE_ESCAPES = DEFAULT_ESCAPES.copy() -NON_UNICODE_ESCAPES['h'] = 'filters.legacy_html_escape' -NON_UNICODE_ESCAPES['u'] = 'filters.legacy_url_escape' +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 cf4187f..e11a949 100644 --- a/mako/lexer.py +++ b/mako/lexer.py @@ -6,19 +6,26 @@ """provides the Lexer class for parsing template strings into parse trees.""" -import re import codecs -from mako import parsetree, exceptions, compat +import re + +from mako import compat +from mako import exceptions +from mako import parsetree from mako.pygen import adjust_whitespace _regexp_cache = {} class Lexer(object): - - def __init__(self, text, filename=None, - disable_unicode=False, - input_encoding=None, preprocessor=None): + def __init__( + self, + text, + filename=None, + disable_unicode=False, + input_encoding=None, + preprocessor=None, + ): self.text = text self.filename = filename self.template = parsetree.TemplateNode(self.filename) @@ -34,22 +41,24 @@ class Lexer(object): 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 = [] - elif not hasattr(preprocessor, '__iter__'): + elif not hasattr(preprocessor, "__iter__"): self.preprocessor = [preprocessor] else: self.preprocessor = preprocessor @property def exception_kwargs(self): - return {'source': self.text, - 'lineno': self.matched_lineno, - 'pos': self.matched_charpos, - 'filename': self.filename} + return { + "source": self.text, + "lineno": self.matched_lineno, + "pos": self.matched_charpos, + "filename": self.filename, + } def match(self, regexp, flags=None): """compile the given regexp, cache the reg, and call match_reg().""" @@ -83,9 +92,9 @@ class Lexer(object): else: self.match_position = end self.matched_lineno = self.lineno - lines = re.findall(r"\n", self.text[mp:self.match_position]) + lines = re.findall(r"\n", self.text[mp : self.match_position]) cp = mp - 1 - while (cp >= 0 and cp < self.textlength and self.text[cp] != '\n'): + while cp >= 0 and cp < self.textlength and self.text[cp] != "\n": cp -= 1 self.matched_charpos = mp - cp self.lineno += len(lines) @@ -97,46 +106,49 @@ class Lexer(object): def parse_until_text(self, watch_nesting, *text): startpos = self.match_position - text_re = r'|'.join(text) + text_re = r"|".join(text) brace_level = 0 paren_level = 0 bracket_level = 0 while True: - match = self.match(r'#.*\n') + match = self.match(r"#.*\n") if match: continue - match = self.match(r'(\"\"\"|\'\'\'|\"|\')[^\\]*?(\\.[^\\]*?)*\1', - re.S) + match = self.match( + r"(\"\"\"|\'\'\'|\"|\')[^\\]*?(\\.[^\\]*?)*\1", re.S + ) if match: continue - match = self.match(r'(%s)' % text_re) - if match and not (watch_nesting - and (brace_level > 0 or paren_level > 0 - or bracket_level > 0)): - return \ - self.text[startpos: - self.match_position - len(match.group(1))],\ - match.group(1) + match = self.match(r"(%s)" % text_re) + if match and not ( + watch_nesting + and (brace_level > 0 or paren_level > 0 or bracket_level > 0) + ): + return ( + self.text[ + startpos : self.match_position - len(match.group(1)) + ], + match.group(1), + ) elif not match: match = self.match(r"(.*?)(?=\"|\'|#|%s)" % text_re, re.S) if match: - brace_level += match.group(1).count('{') - brace_level -= match.group(1).count('}') - paren_level += match.group(1).count('(') - paren_level -= match.group(1).count(')') - bracket_level += match.group(1).count('[') - bracket_level -= match.group(1).count(']') + brace_level += match.group(1).count("{") + brace_level -= match.group(1).count("}") + paren_level += match.group(1).count("(") + paren_level -= match.group(1).count(")") + bracket_level += match.group(1).count("[") + bracket_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) - kwargs.setdefault('lineno', self.matched_lineno) - kwargs.setdefault('pos', self.matched_charpos) - kwargs['filename'] = self.filename + kwargs.setdefault("source", self.text) + kwargs.setdefault("lineno", self.matched_lineno) + kwargs.setdefault("pos", self.matched_charpos) + kwargs["filename"] = self.filename node = nodecls(*args, **kwargs) if len(self.tag): self.tag[-1].nodes.append(node) @@ -149,8 +161,10 @@ class Lexer(object): if self.control_line: control_frame = self.control_line[-1] control_frame.nodes.append(node) - if not (isinstance(node, parsetree.ControlLine) and - control_frame.is_ternary(node.keyword)): + if not ( + isinstance(node, parsetree.ControlLine) + and control_frame.is_ternary(node.keyword) + ): if self.ternary_stack and self.ternary_stack[-1]: self.ternary_stack[-1][-1].nodes.append(node) if isinstance(node, parsetree.Tag): @@ -164,17 +178,20 @@ class Lexer(object): elif node.is_primary: self.control_line.append(node) self.ternary_stack.append([]) - elif self.control_line and \ - self.control_line[-1].is_ternary(node.keyword): + elif self.control_line and self.control_line[-1].is_ternary( + node.keyword + ): self.ternary_stack[-1].append(node) - elif self.control_line and \ - not self.control_line[-1].is_ternary(node.keyword): + 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') + _coding_re = re.compile(r"#.*coding[:=]\s*([-\w.]+).*\r?\n") def decode_raw_stream(self, text, decode_raw, known_encoding, filename): """given string/unicode or bytes/string, determine encoding @@ -184,44 +201,48 @@ class Lexer(object): """ if isinstance(text, compat.text_type): m = self._coding_re.match(text) - encoding = m and m.group(1) or known_encoding or 'ascii' + encoding = m and m.group(1) or known_encoding or "ascii" return encoding, text if text.startswith(codecs.BOM_UTF8): - text = text[len(codecs.BOM_UTF8):] - parsed_encoding = 'utf-8' - m = self._coding_re.match(text.decode('utf-8', 'ignore')) - if m is not None and m.group(1) != 'utf-8': + text = text[len(codecs.BOM_UTF8) :] + parsed_encoding = "utf-8" + 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) + text.decode("utf-8", "ignore"), + 0, + 0, + filename, + ) else: - m = self._coding_re.match(text.decode('utf-8', 'ignore')) + m = self._coding_re.match(text.decode("utf-8", "ignore")) if m: parsed_encoding = m.group(1) else: - parsed_encoding = known_encoding or 'ascii' + parsed_encoding = known_encoding or "ascii" if decode_raw: try: 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.text, not self.disable_unicode, self.encoding, self.filename + ) for preproc in self.preprocessor: self.text = preproc(self.text) @@ -232,7 +253,7 @@ class Lexer(object): self.textlength = len(self.text) - while (True): + while True: if self.match_position > self.textlength: break @@ -258,20 +279,24 @@ class Lexer(object): raise exceptions.CompileException("assertion failed") if len(self.tag): - raise exceptions.SyntaxException("Unclosed tag: <%%%s>" % - self.tag[-1].keyword, - **self.exception_kwargs) + raise exceptions.SyntaxException( + "Unclosed tag: <%%%s>" % self.tag[-1].keyword, + **self.exception_kwargs + ) if len(self.control_line): raise exceptions.SyntaxException( - "Unterminated control keyword: '%s'" % - self.control_line[-1].keyword, + "Unterminated control keyword: '%s'" + % self.control_line[-1].keyword, self.text, self.control_line[-1].lineno, - self.control_line[-1].pos, self.filename) + self.control_line[-1].pos, + self.filename, + ) return self.template def match_tag_start(self): - match = self.match(r''' + match = self.match( + r""" \<% # opening tag ([\w\.\:]+) # keyword @@ -283,9 +308,9 @@ class Lexer(object): (/)?> # closing - ''', - - re.I | re.S | re.X) + """, + re.I | re.S | re.X, + ) if match: keyword, attr, isend = match.groups() @@ -293,22 +318,23 @@ class Lexer(object): 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') + text = text.replace("\r\n", "\n") attributes[key] = text self.append_node(parsetree.Tag, keyword, attributes) if isend: self.tag.pop() else: - if keyword == 'text': - match = self.match(r'(.*?)(?=\</%text>)', re.S) + if keyword == "text": + 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 @@ -316,25 +342,27 @@ class Lexer(object): return False def match_tag_end(self): - match = self.match(r'\</%[\t ]*(.+?)[\t ]*>') + match = self.match(r"\</%[\t ]*(.+?)[\t ]*>") 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: return False def match_end(self): - match = self.match(r'\Z', re.S) + match = self.match(r"\Z", re.S) if match: string = match.group() if string: @@ -345,7 +373,8 @@ class Lexer(object): return False def match_text(self): - match = self.match(r""" + match = self.match( + r""" (.*?) # anything, followed by: ( (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based @@ -360,7 +389,9 @@ class Lexer(object): (\\\r?\n) # an escaped newline - throw away | \Z # end of string - )""", re.X | re.S) + )""", + re.X | re.S, + ) if match: text = match.group(1) @@ -374,14 +405,17 @@ class Lexer(object): match = self.match(r"<%(!)?") if match: line, pos = self.matched_lineno, self.matched_charpos - text, end = self.parse_until_text(False, r'%>') + text, end = self.parse_until_text(False, r"%>") # the trailing newline helps # compiler.parse() not complain about indentation text = adjust_whitespace(text) + "\n" self.append_node( parsetree.Code, text, - match.group(1) == '!', lineno=line, pos=pos) + match.group(1) == "!", + lineno=line, + pos=pos, + ) return True else: return False @@ -390,16 +424,19 @@ class Lexer(object): match = self.match(r"\${") if match: line, pos = self.matched_lineno, self.matched_charpos - text, end = self.parse_until_text(True, r'\|', r'}') - if end == '|': - escapes, end = self.parse_until_text(True, r'}') + text, end = self.parse_until_text(True, r"\|", r"}") + if end == "|": + escapes, end = self.parse_until_text(True, r"}") else: escapes = "" - text = text.replace('\r\n', '\n') + text = text.replace("\r\n", "\n") self.append_node( parsetree.Expression, - text, escapes.strip(), - lineno=line, pos=pos) + text, + escapes.strip(), + lineno=line, + pos=pos, + ) return True else: return False @@ -407,31 +444,35 @@ class Lexer(object): def match_control_line(self): match = self.match( r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)" - r"(?:\r?\n|\Z)", re.M) + r"(?:\r?\n|\Z)", + re.M, + ) if match: operator = match.group(1) text = match.group(2) - if operator == '%': - m2 = re.match(r'(end)?(\w+)\s*(.*)', text) + if operator == "%": + 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) + 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) diff --git a/mako/lookup.py b/mako/lookup.py index 0d3f304..a3010d5 100644 --- a/mako/lookup.py +++ b/mako/lookup.py @@ -5,10 +5,12 @@ # the MIT License: http://www.opensource.org/licenses/mit-license.php import os -import stat import posixpath import re -from mako import exceptions, util +import stat + +from mako import exceptions +from mako import util from mako.template import Template try: @@ -151,41 +153,41 @@ class TemplateLookup(TemplateCollection): """ - 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', - - 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, - include_error_handler=None): - - self.directories = [posixpath.normpath(d) for d in - util.to_list(directories, ()) - ] + 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", + 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, + include_error_handler=None, + ): + + self.directories = [ + posixpath.normpath(d) for d in util.to_list(directories, ()) + ] self.module_directory = module_directory self.modulename_callable = modulename_callable self.filesystem_checks = filesystem_checks @@ -195,34 +197,34 @@ class TemplateLookup(TemplateCollection): cache_args = {} # transfer deprecated cache_* args if cache_dir: - cache_args.setdefault('dir', cache_dir) + cache_args.setdefault("dir", cache_dir) if cache_url: - cache_args.setdefault('url', cache_url) + cache_args.setdefault("url", cache_url) if cache_type: - cache_args.setdefault('type', cache_type) + cache_args.setdefault("type", cache_type) self.template_args = { - 'format_exceptions': format_exceptions, - 'error_handler': error_handler, - 'include_error_handler': include_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, + "include_error_handler": include_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: @@ -248,17 +250,18 @@ class TemplateLookup(TemplateCollection): else: return self._collection[uri] except KeyError: - u = re.sub(r'^\/+', '', uri) - for dir in self.directories: + u = re.sub(r"^\/+", "", uri) + for dir_ in self.directories: # make sure the path seperators are posix - os.altsep is empty # on POSIX and cannot be used. - dir = dir.replace(os.path.sep, posixpath.sep) - srcfile = posixpath.normpath(posixpath.join(dir, u)) + dir_ = dir_.replace(os.path.sep, posixpath.sep) + srcfile = posixpath.normpath(posixpath.join(dir_, u)) if os.path.isfile(srcfile): 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.""" @@ -267,12 +270,13 @@ class TemplateLookup(TemplateCollection): if key in self._uri_cache: return self._uri_cache[key] - if uri[0] != '/': + 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 + v = self._uri_cache[key] = "/" + uri else: v = self._uri_cache[key] = uri return v @@ -295,9 +299,9 @@ class TemplateLookup(TemplateCollection): """ filename = posixpath.normpath(filename) - for dir in self.directories: - if filename[0:len(dir)] == dir: - return filename[len(dir):] + for dir_ in self.directories: + if filename[0 : len(dir_)] == dir_: + return filename[len(dir_) :] else: return None @@ -320,7 +324,8 @@ class TemplateLookup(TemplateCollection): filename=posixpath.normpath(filename), lookup=self, module_filename=module_filename, - **self.template_args) + **self.template_args + ) return template except: # if compilation fails etc, ensure @@ -337,8 +342,7 @@ class TemplateLookup(TemplateCollection): try: template_stat = os.stat(template.filename) - if template.module._modified_time < \ - template_stat[stat.ST_MTIME]: + if template.module._modified_time < template_stat[stat.ST_MTIME]: self._collection.pop(uri, None) return self._load(template.filename, uri) else: @@ -346,7 +350,8 @@ class TemplateLookup(TemplateCollection): 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 @@ -355,10 +360,8 @@ class TemplateLookup(TemplateCollection): """ 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 diff --git a/mako/parsetree.py b/mako/parsetree.py index e129916..7f06667 100644 --- a/mako/parsetree.py +++ b/mako/parsetree.py @@ -6,9 +6,14 @@ """defines the parse tree components for Mako templates.""" -from mako import exceptions, ast, util, filters, compat import re +from mako import ast +from mako import compat +from mako import exceptions +from mako import filters +from mako import util + class Node(object): @@ -22,8 +27,12 @@ class Node(object): @property def exception_kwargs(self): - return {'source': self.source, 'lineno': self.lineno, - 'pos': self.pos, 'filename': self.filename} + return { + "source": self.source, + "lineno": self.lineno, + "pos": self.pos, + "filename": self.filename, + } def get_children(self): return [] @@ -42,7 +51,7 @@ class TemplateNode(Node): """a 'container' node that stores the overall collection of nodes.""" def __init__(self, filename): - super(TemplateNode, self).__init__('', 0, 0, filename) + super(TemplateNode, self).__init__("", 0, 0, filename) self.nodes = [] self.page_attributes = {} @@ -52,7 +61,8 @@ class TemplateNode(Node): def __repr__(self): return "TemplateNode(%s, %r)" % ( util.sorted_dict_repr(self.page_attributes), - self.nodes) + self.nodes, + ) class ControlLine(Node): @@ -74,7 +84,7 @@ class ControlLine(Node): self.text = text self.keyword = keyword self.isend = isend - self.is_primary = keyword in ['for', 'if', 'while', 'try', 'with'] + self.is_primary = keyword in ["for", "if", "while", "try", "with"] self.nodes = [] if self.isend: self._declared_identifiers = [] @@ -98,9 +108,9 @@ class ControlLine(Node): 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): @@ -108,7 +118,7 @@ class ControlLine(Node): self.keyword, self.text, self.isend, - (self.lineno, self.pos) + (self.lineno, self.pos), ) @@ -158,7 +168,7 @@ class Code(Node): return "Code(%r, %r, %r)" % ( self.text, self.ismodule, - (self.lineno, self.pos) + (self.lineno, self.pos), ) @@ -208,7 +218,7 @@ class Expression(Node): return "Expression(%r, %r, %r)" % ( self.text, self.escapes_code.args, - (self.lineno, self.pos) + (self.lineno, self.pos), ) @@ -219,45 +229,55 @@ class _TagMeta(type): _classmap = {} - def __init__(cls, clsname, bases, dict): - if getattr(cls, '__keyword__', None) is not None: + def __init__(cls, clsname, bases, dict_): + if getattr(cls, "__keyword__", None) is not None: cls._classmap[cls.__keyword__] = cls - super(_TagMeta, cls).__init__(clsname, bases, dict) + super(_TagMeta, cls).__init__(clsname, bases, dict_) def __call__(cls, keyword, attributes, **kwargs): if ":" in keyword: - ns, defname = keyword.split(':') - return type.__call__(CallNamespaceTag, ns, defname, - attributes, **kwargs) + ns, defname = keyword.split(":") + return type.__call__( + CallNamespaceTag, ns, defname, attributes, **kwargs + ) try: cls = _TagMeta._classmap[keyword] except KeyError: raise exceptions.CompileException( "No such tag: '%s'" % keyword, - source=kwargs['source'], - lineno=kwargs['lineno'], - pos=kwargs['pos'], - filename=kwargs['filename'] + source=kwargs["source"], + lineno=kwargs["lineno"], + pos=kwargs["pos"], + filename=kwargs["filename"], ) return type.__call__(cls, keyword, attributes, **kwargs) class Tag(compat.with_metaclass(_TagMeta, Node)): - """abstract base class for tags. - <%sometag/> + e.g.:: + + <%sometag/> - <%someothertag> - stuff - </%someothertag> + <%someothertag> + stuff + </%someothertag> """ + __keyword__ = None - def __init__(self, keyword, attributes, expressions, - nonexpressions, required, **kwargs): + def __init__( + self, + keyword, + attributes, + expressions, + nonexpressions, + required, + **kwargs + ): r"""construct a new Tag instance. this constructor not called directly, and is only called @@ -284,9 +304,10 @@ class Tag(compat.with_metaclass(_TagMeta, Node)): missing = [r for r in required if r not in self.parsed_attributes] if len(missing): raise exceptions.CompileException( - "Missing attribute(s): %s" % - ",".join([repr(m) for m in missing]), - **self.exception_kwargs) + "Missing attribute(s): %s" + % ",".join([repr(m) for m in missing]), + **self.exception_kwargs + ) self.parent = None self.nodes = [] @@ -302,36 +323,40 @@ class Tag(compat.with_metaclass(_TagMeta, Node)): for key in self.attributes: if key in expressions: expr = [] - for x in re.compile(r'(\${.+?})', - re.S).split(self.attributes[key]): - m = re.compile(r'^\${(.+?)}$', re.S).match(x) + for x in re.compile(r"(\${.+?})", re.S).split( + self.attributes[key] + ): + m = re.compile(r"^\${(.+?)}$", re.S).match(x) if m: - code = ast.PythonCode(m.group(1).rstrip(), - **self.exception_kwargs) + code = ast.PythonCode( + m.group(1).rstrip(), **self.exception_kwargs + ) # we aren't discarding "declared_identifiers" here, # which we do so that list comprehension-declared # variables aren't counted. As yet can't find a # condition that requires it here. - undeclared_identifiers = \ - undeclared_identifiers.union( - code.undeclared_identifiers) - expr.append('(%s)' % m.group(1)) + undeclared_identifiers = undeclared_identifiers.union( + code.undeclared_identifiers + ) + expr.append("(%s)" % m.group(1)) else: if x: expr.append(repr(x)) - self.parsed_attributes[key] = " + ".join(expr) or repr('') + self.parsed_attributes[key] = " + ".join(expr) or repr("") elif key in nonexpressions: - if re.search(r'\${.+?}', self.attributes[key]): + 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) + **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): @@ -341,56 +366,64 @@ class Tag(compat.with_metaclass(_TagMeta, Node)): return self.expression_undeclared_identifiers 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 - ) + return "%s(%r, %s, %r, %r)" % ( + self.__class__.__name__, + self.keyword, + util.sorted_dict_repr(self.attributes), + (self.lineno, self.pos), + self.nodes, + ) class IncludeTag(Tag): - __keyword__ = 'include' + __keyword__ = "include" def __init__(self, keyword, attributes, **kwargs): super(IncludeTag, self).__init__( keyword, attributes, - ('file', 'import', 'args'), - (), ('file',), **kwargs) + ("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) - return identifiers.union(super(IncludeTag, self). - undeclared_identifiers()) + identifiers = self.page_args.undeclared_identifiers.difference( + set(["__DUMMY"]) + ).difference(self.page_args.declared_identifiers) + return identifiers.union( + super(IncludeTag, self).undeclared_identifiers() + ) class NamespaceTag(Tag): - __keyword__ = 'namespace' + __keyword__ = "namespace" def __init__(self, keyword, attributes, **kwargs): super(NamespaceTag, self).__init__( - keyword, attributes, - ('file',), - ('name', 'inheritable', - 'import', 'module'), - (), **kwargs) - - self.name = attributes.get('name', '__anon_%s' % hex(abs(id(self)))) - if 'name' not in attributes and 'import' not in attributes: + keyword, + attributes, + ("file",), + ("name", "inheritable", "import", "module"), + (), + **kwargs + ) + + self.name = attributes.get("name", "__anon_%s" % hex(abs(id(self)))) + if "name" not in attributes and "import" not in attributes: raise exceptions.CompileException( "'name' and/or 'import' attributes are required " "for <%namespace>", - **self.exception_kwargs) - if 'file' in attributes and 'module' in attributes: + **self.exception_kwargs + ) + if "file" in attributes and "module" in attributes: raise exceptions.CompileException( "<%namespace> may only have one of 'file' or 'module'", **self.exception_kwargs @@ -401,51 +434,51 @@ class NamespaceTag(Tag): class TextTag(Tag): - __keyword__ = 'text' + __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 - ) + return self.filter_args.undeclared_identifiers.difference( + filters.DEFAULT_ESCAPES.keys() + ).union(self.expression_undeclared_identifiers) class DefTag(Tag): - __keyword__ = 'def' + __keyword__ = "def" def __init__(self, keyword, attributes, **kwargs): - expressions = ['buffered', 'cached'] + [ - c for c in attributes if c.startswith('cache_')] + expressions = ["buffered", "cached"] + [ + c for c in attributes if c.startswith("cache_") + ] super(DefTag, self).__init__( keyword, attributes, expressions, - ('name', 'filter', 'decorator'), - ('name',), - **kwargs) - name = attributes['name'] - if re.match(r'^[\w_]+$', name): + ("name", "filter", "decorator"), + ("name",), + **kwargs + ) + name = attributes["name"] + if re.match(r"^[\w_]+$", name): raise exceptions.CompileException( - "Missing parenthesis in %def", - **self.exception_kwargs) - self.function_decl = ast.FunctionDecl("def " + name + ":pass", - **self.exception_kwargs) + "Missing parenthesis in %def", **self.exception_kwargs + ) + self.function_decl = ast.FunctionDecl( + "def " + name + ":pass", **self.exception_kwargs + ) self.name = self.function_decl.funcname - self.decorator = attributes.get('decorator', '') + self.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 @@ -463,51 +496,58 @@ class DefTag(Tag): def undeclared_identifiers(self): res = [] for c in self.function_decl.defaults: - res += list(ast.PythonCode(c, **self.exception_kwargs). - undeclared_identifiers) - return set(res).union( - self.filter_args. - undeclared_identifiers. - difference(filters.DEFAULT_ESCAPES.keys()) - ).union( - self.expression_undeclared_identifiers - ).difference( - self.function_decl.allargnames + res += list( + ast.PythonCode( + c, **self.exception_kwargs + ).undeclared_identifiers + ) + return ( + set(res) + .union( + 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' + __keyword__ = "block" def __init__(self, keyword, attributes, **kwargs): - expressions = ['buffered', 'cached', 'args'] + [ - c for c in attributes if c.startswith('cache_')] + expressions = ["buffered", "cached", "args"] + [ + c for c in attributes if c.startswith("cache_") + ] super(BlockTag, self).__init__( keyword, attributes, expressions, - ('name', 'filter', 'decorator'), + ("name", "filter", "decorator"), (), - **kwargs) - name = attributes.get('name') - if name and not re.match(r'^[\w_]+$', name): + **kwargs + ) + name = attributes.get("name") + if name and not re.match(r"^[\w_]+$", name): raise exceptions.CompileException( "%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 ) - self.body_decl = ast.FunctionArgs(attributes.get('args', ''), - **self.exception_kwargs) + if not name and attributes.get("args", None): + raise exceptions.CompileException( + "Only named %blocks may specify args", **self.exception_kwargs + ) + self.body_decl = ast.FunctionArgs( + attributes.get("args", ""), **self.exception_kwargs + ) self.name = name - self.decorator = attributes.get('decorator', '') + 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 @@ -517,7 +557,7 @@ class BlockTag(Tag): @property def funcname(self): - return self.name or "__M_anon_%d" % (self.lineno, ) + return self.name or "__M_anon_%d" % (self.lineno,) def get_argument_expressions(self, **kw): return self.body_decl.get_argument_expressions(**kw) @@ -526,91 +566,100 @@ class BlockTag(Tag): return self.body_decl.allargnames def undeclared_identifiers(self): - return (self.filter_args. - undeclared_identifiers. - difference(filters.DEFAULT_ESCAPES.keys()) - ).union(self.expression_undeclared_identifiers) + return ( + self.filter_args.undeclared_identifiers.difference( + filters.DEFAULT_ESCAPES.keys() + ) + ).union(self.expression_undeclared_identifiers) class CallTag(Tag): - __keyword__ = 'call' + __keyword__ = "call" def __init__(self, keyword, attributes, **kwargs): - super(CallTag, self).__init__(keyword, attributes, - ('args'), ('expr',), ('expr',), **kwargs) - self.expression = attributes['expr'] + super(CallTag, self).__init__( + keyword, attributes, ("args"), ("expr",), ("expr",), **kwargs + ) + self.expression = attributes["expr"] self.code = ast.PythonCode(self.expression, **self.exception_kwargs) - self.body_decl = ast.FunctionArgs(attributes.get('args', ''), - **self.exception_kwargs) + self.body_decl = ast.FunctionArgs( + attributes.get("args", ""), **self.exception_kwargs + ) def declared_identifiers(self): return self.code.declared_identifiers.union(self.body_decl.allargnames) def undeclared_identifiers(self): - return self.code.undeclared_identifiers.\ - difference(self.code.declared_identifiers) + return self.code.undeclared_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', ), + tuple(attributes.keys()) + ("args",), (), (), - **kwargs) + **kwargs + ) self.expression = "%s.%s(%s)" % ( namespace, defname, - ",".join(["%s=%s" % (k, v) for k, v in - self.parsed_attributes.items() - if k != 'args']) + ",".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) + return self.code.undeclared_identifiers.difference( + self.code.declared_identifiers + ) class InheritTag(Tag): - __keyword__ = 'inherit' + __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' + __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) - self.body_decl = ast.FunctionArgs(attributes.get('args', ''), - **self.exception_kwargs) + keyword, attributes, expressions, (), (), **kwargs + ) + self.body_decl = ast.FunctionArgs( + attributes.get("args", ""), **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 8514e02..70665f6 100644 --- a/mako/pygen.py +++ b/mako/pygen.py @@ -7,11 +7,11 @@ """utilities for generating and formatting literal Python code.""" import re + from mako import exceptions class PythonPrinter(object): - def __init__(self, stream): # indentation counter self.indent = 0 @@ -60,7 +60,7 @@ class PythonPrinter(object): The indentation of the total block of lines will be adjusted to that of the current indent level.""" self.in_indent_lines = False - for l in re.split(r'\r?\n', block): + for l in re.split(r"\r?\n", block): self.line_buffer.append(l) self._update_lineno(1) @@ -83,21 +83,18 @@ class PythonPrinter(object): self.in_indent_lines = True if ( - line is None or - re.match(r"^\s*#", line) or - re.match(r"^\s*$", line) + line is None + or re.match(r"^\s*#", line) + or re.match(r"^\s*$", line) ): hastext = False else: hastext = True - is_comment = line and len(line) and line[0] == '#' + is_comment = line and len(line) and line[0] == "#" # see if this line should decrease the indentation level - if ( - not is_comment and - (not hastext or self._is_unindentor(line)) - ): + if not is_comment and (not hastext or self._is_unindentor(line)): if self.indent > 0: self.indent -= 1 @@ -106,7 +103,8 @@ class PythonPrinter(object): # 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: @@ -136,8 +134,9 @@ class PythonPrinter(object): # its not a "compound" keyword. but lets also # test for valid Python keywords that might be indenting us, # else assume its a non-indenting line - m2 = re.match(r"^\s*(def|class|else|elif|except|finally)", - line) + m2 = re.match( + r"^\s*(def|class|else|elif|except|finally)", line + ) if m2: self.indent += 1 self.indent_detail.append(indentor) @@ -189,14 +188,15 @@ class PythonPrinter(object): # return False - def _indent_line(self, line, stripspace=''): + def _indent_line(self, line, stripspace=""): """indent the given line according to the current indent level. stripspace is a string of space that will be truncated from the start of the line before indenting.""" - return re.sub(r"^%s" % stripspace, self.indentstring - * self.indent, line) + return re.sub( + r"^%s" % stripspace, self.indentstring * self.indent, line + ) def _reset_multi_line_flags(self): """reset the flags which would indicate we are in a backslashed @@ -214,7 +214,7 @@ class PythonPrinter(object): # a literal multiline string with unfortunately placed # whitespace - current_state = (self.backslashed or self.triplequoted) + current_state = self.backslashed or self.triplequoted if re.search(r"\\$", line): self.backslashed = True @@ -251,7 +251,7 @@ def adjust_whitespace(text): (backslashed, triplequoted) = (0, 1) def in_multi_line(line): - start_state = (state[backslashed] or state[triplequoted]) + start_state = state[backslashed] or state[triplequoted] if re.search(r"\\$", line): state[backslashed] = True @@ -261,7 +261,7 @@ def adjust_whitespace(text): def match(reg, t): m = re.match(reg, t) if m: - return m, t[len(m.group(0)):] + return m, t[len(m.group(0)) :] else: return None, t @@ -273,7 +273,7 @@ def adjust_whitespace(text): else: m, line = match(r".*?(?=%s|$)" % state[triplequoted], line) else: - m, line = match(r'#', line) + m, line = match(r"#", line) if m: return start_state @@ -286,13 +286,13 @@ def adjust_whitespace(text): return start_state - def _indent_line(line, stripspace=''): - return re.sub(r"^%s" % stripspace, '', line) + def _indent_line(line, stripspace=""): + return re.sub(r"^%s" % stripspace, "", line) lines = [] stripspace = None - for line in re.split(r'\r?\n', text): + for line in re.split(r"\r?\n", text): if in_multi_line(line): lines.append(line) else: diff --git a/mako/pyparser.py b/mako/pyparser.py index 15d0da6..c171897 100644 --- a/mako/pyparser.py +++ b/mako/pyparser.py @@ -10,46 +10,52 @@ Parsing to AST is done via _ast on Python > 2.5, otherwise the compiler module is used. """ -from mako import exceptions, util, compat -from mako.compat import arg_stringname import operator +import _ast + +from mako import _ast_util +from mako import compat +from mako import exceptions +from mako import util +from mako.compat import arg_stringname + if compat.py3k: # words that cannot be assigned to (notably # smaller than the total keys in __builtins__) - reserved = set(['True', 'False', 'None', 'print']) + reserved = set(["True", "False", "None", "print"]) # the "id" attribute on a function node - arg_id = operator.attrgetter('arg') + arg_id = operator.attrgetter("arg") else: # words that cannot be assigned to (notably # smaller than the total keys in __builtins__) - reserved = set(['True', 'False', 'None']) + reserved = set(["True", "False", "None"]) # the "id" attribute on a function node - arg_id = operator.attrgetter('id') + arg_id = operator.attrgetter("id") -import _ast util.restore__ast(_ast) -from mako import _ast_util -def parse(code, mode='exec', **exception_kwargs): +def parse(code, mode="exec", **exception_kwargs): """Parse an expression into AST""" try: - return _ast_util.parse(code, '<unknown>', mode) + return _ast_util.parse(code, "<unknown>", mode) except Exception: raise exceptions.SyntaxException( - "(%s) %s (%r)" % ( + "(%s) %s (%r)" + % ( compat.exception_as().__class__.__name__, compat.exception_as(), - code[0:50] - ), **exception_kwargs) + code[0:50], + ), + **exception_kwargs + ) class FindIdentifiers(_ast_util.NodeVisitor): - def __init__(self, listener, **exception_kwargs): self.in_function = False self.in_assign_targets = False @@ -119,9 +125,9 @@ class FindIdentifiers(_ast_util.NodeVisitor): self.in_function = True local_ident_stack = self.local_ident_stack - self.local_ident_stack = local_ident_stack.union([ - arg_id(arg) for arg in self._expand_tuples(node.args.args) - ]) + self.local_ident_stack = local_ident_stack.union( + [arg_id(arg) for arg in self._expand_tuples(node.args.args)] + ) if islambda: self.visit(node.body) else: @@ -146,9 +152,11 @@ class FindIdentifiers(_ast_util.NodeVisitor): # this is eqiuvalent to visit_AssName in # compiler self._add_declared(node.id) - elif node.id not in reserved and node.id \ - not in self.listener.declared_identifiers and node.id \ - not in self.local_ident_stack: + elif ( + node.id not in reserved + and node.id not in self.listener.declared_identifiers + and node.id not in self.local_ident_stack + ): self.listener.undeclared_identifiers.add(node.id) def visit_Import(self, node): @@ -156,24 +164,25 @@ class FindIdentifiers(_ast_util.NodeVisitor): if name.asname is not None: self._add_declared(name.asname) else: - self._add_declared(name.name.split('.')[0]) + self._add_declared(name.name.split(".")[0]) def visit_ImportFrom(self, node): for name in node.names: if name.asname is not None: self._add_declared(name.asname) else: - if name.name == '*': + if name.name == "*": raise exceptions.CompileException( "'import *' is not supported, since all identifier " "names must be explicitly declared. Please use the " "form 'from <modulename> import <name1>, <name2>, " - "...' instead.", **self.exception_kwargs) + "...' instead.", + **self.exception_kwargs + ) self._add_declared(name.name) class FindTuple(_ast_util.NodeVisitor): - def __init__(self, listener, code_factory, **exception_kwargs): self.listener = listener self.exception_kwargs = exception_kwargs @@ -184,16 +193,17 @@ class FindTuple(_ast_util.NodeVisitor): p = self.code_factory(n, **self.exception_kwargs) self.listener.codeargs.append(p) self.listener.args.append(ExpressionGenerator(n).value()) - self.listener.declared_identifiers = \ - self.listener.declared_identifiers.union( - p.declared_identifiers) - self.listener.undeclared_identifiers = \ - self.listener.undeclared_identifiers.union( - p.undeclared_identifiers) + ldi = self.listener.declared_identifiers + self.listener.declared_identifiers = ldi.union( + p.declared_identifiers + ) + lui = self.listener.undeclared_identifiers + self.listener.undeclared_identifiers = lui.union( + p.undeclared_identifiers + ) class ParseFunc(_ast_util.NodeVisitor): - def __init__(self, listener, **exception_kwargs): self.listener = listener self.exception_kwargs = exception_kwargs @@ -224,10 +234,9 @@ class ParseFunc(_ast_util.NodeVisitor): class ExpressionGenerator(object): - def __init__(self, astnode): - self.generator = _ast_util.SourceGenerator(' ' * 4) + self.generator = _ast_util.SourceGenerator(" " * 4) self.generator.visit(astnode) def value(self): - return ''.join(self.generator.result) + return "".join(self.generator.result) diff --git a/mako/runtime.py b/mako/runtime.py index 769541c..8c4f78c 100644 --- a/mako/runtime.py +++ b/mako/runtime.py @@ -7,10 +7,13 @@ """provides runtime services for templates, including Context, Namespace, and various helper functions.""" -from mako import exceptions, util, compat -from mako.compat import compat_builtins import sys +from mako import compat +from mako import exceptions +from mako import util +from mako.compat import compat_builtins + class Context(object): @@ -34,18 +37,19 @@ class Context(object): # "capture" function which proxies to the # generic "capture" function - self._data['capture'] = compat.partial(capture, self) + self._data["capture"] = compat.partial(capture, self) # "caller" stack used by def calls with content - self.caller_stack = self._data['caller'] = CallerStack() + self.caller_stack = self._data["caller"] = CallerStack() def _set_with_template(self, t): self._with_template = t illegal_names = t.reserved_names.intersection(self._data) if illegal_names: raise exceptions.NameConflictError( - "Reserved words passed to render(): %s" % - ", ".join(illegal_names)) + "Reserved words passed to render(): %s" + % ", ".join(illegal_names) + ) @property def lookup(self): @@ -177,14 +181,13 @@ class Context(object): c = self._copy() x = c._data - x.pop('self', None) - x.pop('parent', None) - x.pop('next', None) + x.pop("self", None) + x.pop("parent", None) + x.pop("next", None) return c class CallerStack(list): - def __init__(self): self.nextcaller = None @@ -231,6 +234,7 @@ class Undefined(object): def __bool__(self): return False + UNDEFINED = Undefined() STOP_RENDERING = "" @@ -342,7 +346,6 @@ class LoopContext(object): class _NSAttr(object): - def __init__(self, parent): self.__parent = parent @@ -373,9 +376,15 @@ class Namespace(object): """ - def __init__(self, name, context, - callables=None, inherits=None, - populate_self=True, calling_uri=None): + def __init__( + self, + name, + context, + callables=None, + inherits=None, + populate_self=True, + calling_uri=None, + ): self.name = name self.context = context self.inherits = inherits @@ -473,9 +482,12 @@ class Namespace(object): if key in self.context.namespaces: return self.context.namespaces[key] else: - ns = TemplateNamespace(uri, self.context._copy(), - templateuri=uri, - calling_uri=self._templateuri) + ns = TemplateNamespace( + uri, + self.context._copy(), + templateuri=uri, + calling_uri=self._templateuri, + ) self.context.namespaces[key] = ns return ns @@ -518,7 +530,7 @@ class Namespace(object): def _populate(self, d, l): for ident in l: - if ident == '*': + if ident == "*": for (k, v) in self._get_star(): d[k] = v else: @@ -536,8 +548,8 @@ class Namespace(object): val = getattr(self.inherits, key) else: raise AttributeError( - "Namespace '%s' has no member '%s'" % - (self.name, key)) + "Namespace '%s' has no member '%s'" % (self.name, key) + ) setattr(self, key, val) return val @@ -546,9 +558,17 @@ class TemplateNamespace(Namespace): """A :class:`.Namespace` specific to a :class:`.Template` instance.""" - def __init__(self, name, context, template=None, templateuri=None, - callables=None, inherits=None, - populate_self=True, calling_uri=None): + def __init__( + self, + name, + context, + template=None, + templateuri=None, + callables=None, + inherits=None, + populate_self=True, + calling_uri=None, + ): self.name = name self.context = context self.inherits = inherits @@ -556,8 +576,7 @@ class TemplateNamespace(Namespace): self.callables = dict([(c.__name__, c) for c in callables]) if templateuri is not None: - self.template = _lookup_template(context, templateuri, - calling_uri) + self.template = _lookup_template(context, templateuri, calling_uri) self._templateuri = self.template.module._template_uri elif template is not None: self.template = template @@ -566,9 +585,9 @@ class TemplateNamespace(Namespace): raise TypeError("'template' argument is required.") if populate_self: - lclcallable, lclcontext = \ - _populate_self_namespace(context, self.template, - self_ns=self) + lclcallable, lclcontext = _populate_self_namespace( + context, self.template, self_ns=self + ) @property def module(self): @@ -607,6 +626,7 @@ class TemplateNamespace(Namespace): def get(key): callable_ = self.template._get_def_callable(key) return compat.partial(callable_, self.context) + for k in self.template.module._exports: yield (k, get(k)) @@ -621,8 +641,8 @@ class TemplateNamespace(Namespace): 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 @@ -631,9 +651,16 @@ class ModuleNamespace(Namespace): """A :class:`.Namespace` specific to a Python module instance.""" - def __init__(self, name, context, module, - callables=None, inherits=None, - populate_self=True, calling_uri=None): + def __init__( + self, + name, + context, + module, + callables=None, + inherits=None, + populate_self=True, + calling_uri=None, + ): self.name = name self.context = context self.inherits = inherits @@ -641,7 +668,7 @@ class ModuleNamespace(Namespace): self.callables = dict([(c.__name__, c) for c in callables]) mod = __import__(module) - for token in module.split('.')[1:]: + for token in module.split(".")[1:]: mod = getattr(mod, token) self.module = mod @@ -657,7 +684,7 @@ class ModuleNamespace(Namespace): for key in self.callables: yield (key, self.callables[key]) for key in dir(self.module): - if key[0] != '_': + if key[0] != "_": callable_ = getattr(self.module, key) if compat.callable(callable_): yield key, compat.partial(callable_, self.context) @@ -672,8 +699,8 @@ class ModuleNamespace(Namespace): 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 @@ -692,6 +719,7 @@ def supports_caller(func): return func(context, *args, **kwargs) finally: context.caller_stack._pop_frame() + return wrap_stackframe @@ -721,13 +749,16 @@ def _decorate_toplevel(fn): def go(context, *args, **kw): def y(*args, **kw): return render_fn(context, *args, **kw) + try: y.__name__ = render_fn.__name__[7:] except TypeError: # < Python 2.4 pass return fn(y)(context, *args, **kw) + return go + return decorate_render @@ -737,7 +768,9 @@ def _decorate_inline(context, fn): def go(*args, **kw): return dec(context, *args, **kw) + return go + return decorate_render @@ -747,8 +780,8 @@ def _include_file(context, uri, calling_uri, **kwargs): template = _lookup_template(context, uri, calling_uri) (callable_, ctx) = _populate_self_namespace( - context._clean_inheritance_tokens(), - template) + context._clean_inheritance_tokens(), template + ) kwargs = _kwargs_for_include(callable_, context._data, **kwargs) if template.include_error_handler: try: @@ -769,23 +802,25 @@ def _inherit_from(context, uri, calling_uri): if uri is None: return None template = _lookup_template(context, uri, calling_uri) - self_ns = context['self'] + self_ns = context["self"] ih = self_ns while ih.inherits is not None: ih = ih.inherits - lclcontext = context._locals({'next': ih}) - ih.inherits = TemplateNamespace("self:%s" % template.uri, - lclcontext, - template=template, - populate_self=False) - context._data['parent'] = lclcontext._data['local'] = ih.inherits - callable_ = getattr(template.module, '_mako_inherit', None) + lclcontext = context._locals({"next": ih}) + ih.inherits = TemplateNamespace( + "self:%s" % template.uri, + lclcontext, + template=template, + populate_self=False, + ) + context._data["parent"] = lclcontext._data["local"] = ih.inherits + callable_ = getattr(template.module, "_mako_inherit", None) if callable_ is not None: ret = callable_(template, lclcontext) if ret: return ret - gen_ns = getattr(template.module, '_mako_generate_namespaces', None) + gen_ns = getattr(template.module, "_mako_generate_namespaces", None) if gen_ns is not None: gen_ns(context) return (template.callable_, lclcontext) @@ -795,8 +830,9 @@ 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) @@ -806,11 +842,14 @@ def _lookup_template(context, uri, relativeto): def _populate_self_namespace(context, template, self_ns=None): if self_ns is None: - self_ns = TemplateNamespace('self:%s' % template.uri, - context, template=template, - populate_self=False) - context._data['self'] = context._data['local'] = self_ns - if hasattr(template.module, '_mako_inherit'): + self_ns = TemplateNamespace( + "self:%s" % template.uri, + context, + template=template, + populate_self=False, + ) + context._data["self"] = context._data["local"] = self_ns + if hasattr(template.module, "_mako_inherit"): ret = template.module._mako_inherit(template, context) if ret: return ret @@ -829,13 +868,19 @@ def _render(template, callable_, args, data, as_unicode=False): buf = util.FastEncodingBuffer( as_unicode=as_unicode, encoding=template.output_encoding, - errors=template.encoding_errors) + errors=template.encoding_errors, + ) context = Context(buf, **data) context._outputting_as_unicode = as_unicode context._set_with_template(template) - _render_context(template, callable_, context, *args, - **_kwargs_for_callable(callable_, data)) + _render_context( + template, + callable_, + context, + *args, + **_kwargs_for_callable(callable_, data) + ) return context._pop_buffer().getvalue() @@ -849,7 +894,7 @@ def _kwargs_for_callable(callable_, data): namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None] kwargs = {} for arg in namedargs: - if arg != 'context' and arg in data and arg not in kwargs: + if arg != "context" and arg in data and arg not in kwargs: kwargs[arg] = data[arg] return kwargs @@ -858,13 +903,14 @@ 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] for arg in namedargs: - if arg != 'context' and arg in data and arg not in kwargs: + if arg != "context" and arg in data and arg not in kwargs: kwargs[arg] = data[arg] return kwargs def _render_context(tmpl, callable_, context, *args, **kwargs): import mako.template as template + # create polymorphic 'self' namespace for this # template with possibly updated context if not isinstance(tmpl, template.DefTemplate): @@ -886,8 +932,9 @@ def _exec_template(callable_, context, args=None, kwargs=None): be interpreted here. """ template = context._with_template - if template is not None and \ - (template.format_exceptions or template.error_handler): + if template is not None and ( + template.format_exceptions or template.error_handler + ): try: callable_(context, *args, **kwargs) except Exception: @@ -908,11 +955,15 @@ def _render_error(template, context, error): error_template = exceptions.html_error_template() if context._outputting_as_unicode: context._buffer_stack[:] = [ - util.FastEncodingBuffer(as_unicode=True)] + util.FastEncodingBuffer(as_unicode=True) + ] else: - context._buffer_stack[:] = [util.FastEncodingBuffer( - error_template.output_encoding, - error_template.encoding_errors)] + context._buffer_stack[:] = [ + util.FastEncodingBuffer( + error_template.output_encoding, + error_template.encoding_errors, + ) + ] context._set_with_template(error_template) error_template.render_context(context, error=error) diff --git a/mako/template.py b/mako/template.py index 329632c..89d2105 100644 --- a/mako/template.py +++ b/mako/template.py @@ -7,8 +7,6 @@ """Provides the Template class, a facade for parsing, generating and executing template strings, as well as template runtime operations.""" -from mako.lexer import Lexer -from mako import runtime, util, exceptions, codegen, cache, compat import os import re import shutil @@ -18,6 +16,14 @@ import tempfile import types import weakref +from mako import cache +from mako import codegen +from mako import compat +from mako import exceptions +from mako import runtime +from mako import util +from mako.lexer import Lexer + class Template(object): @@ -230,41 +236,43 @@ class Template(object): 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, - include_error_handler=None): + 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, + include_error_handler=None, + ): if uri: - self.module_id = re.sub(r'\W', "_", uri) + self.module_id = re.sub(r"\W", "_", uri) self.uri = uri elif filename: - self.module_id = re.sub(r'\W', "_", filename) + self.module_id = re.sub(r"\W", "_", filename) drive, path = os.path.splitdrive(filename) path = os.path.normpath(path).replace(os.path.sep, "/") self.uri = path @@ -278,9 +286,10 @@ class Template(object): u_norm = os.path.normpath(u_norm) if u_norm.startswith(".."): raise exceptions.TemplateLookupException( - "Template uri \"%s\" is invalid - " + 'Template uri "%s" is invalid - ' "it cannot be relative outside " - "of the root path." % self.uri) + "of the root path." % self.uri + ) self.input_encoding = input_encoding self.output_encoding = output_encoding @@ -293,17 +302,18 @@ class Template(object): 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.") + "None when disable_unicode is used." + ) if default_filters is None: if compat.py3k or self.disable_unicode: - self.default_filters = ['str'] + self.default_filters = ["str"] else: - self.default_filters = ['unicode'] + self.default_filters = ["unicode"] else: self.default_filters = default_filters self.buffer_filters = buffer_filters @@ -329,8 +339,7 @@ class Template(object): elif module_directory is not None: path = os.path.abspath( os.path.join( - os.path.normpath(module_directory), - u_norm + ".py" + os.path.normpath(module_directory), u_norm + ".py" ) ) else: @@ -338,7 +347,8 @@ class Template(object): 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 @@ -351,8 +361,12 @@ class Template(object): self.module_directory = module_directory self._setup_cache_args( - cache_impl, cache_enabled, cache_args, - cache_type, cache_dir, cache_url + cache_impl, + cache_enabled, + cache_args, + cache_type, + cache_dir, + cache_url, ) @util.memoized_property @@ -360,11 +374,17 @@ class Template(object): if self.enable_loop: return codegen.RESERVED_NAMES else: - return codegen.RESERVED_NAMES.difference(['loop']) - - def _setup_cache_args(self, - cache_impl, cache_enabled, cache_args, - cache_type, cache_dir, cache_url): + return codegen.RESERVED_NAMES.difference(["loop"]) + + def _setup_cache_args( + self, + 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: @@ -374,35 +394,31 @@ class Template(object): # transfer deprecated cache_* args if cache_type: - self.cache_args['type'] = cache_type + self.cache_args["type"] = cache_type if cache_dir: - self.cache_args['dir'] = cache_dir + self.cache_args["dir"] = cache_dir if cache_url: - self.cache_args['url'] = cache_url + self.cache_args["url"] = cache_url def _compile_from_file(self, path, filename): if path is not None: 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: + if ( + not os.path.exists(path) + or 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) @@ -410,10 +426,7 @@ class Template(object): # template filename and no module directory, compile code # in memory data = util.read_file(filename) - code, module = _compile_text( - self, - data, - filename) + code, module = _compile_text(self, data, filename) self._source = None self._code = code ModuleInfo(module, None, self, filename, code, None) @@ -437,15 +450,15 @@ class Template(object): @property def cache_dir(self): - return self.cache_args['dir'] + return self.cache_args["dir"] @property def cache_url(self): - return self.cache_args['url'] + return self.cache_args["url"] @property def cache_type(self): - return self.cache_args['type'] + return self.cache_args["type"] def render(self, *args, **data): """Render the output of this template as a string. @@ -464,11 +477,9 @@ class Template(object): def render_unicode(self, *args, **data): """Render the output of this template as a unicode object.""" - return runtime._render(self, - self.callable_, - args, - data, - as_unicode=True) + return runtime._render( + self, self.callable_, args, data, as_unicode=True + ) def render_context(self, context, *args, **kwargs): """Render this :class:`.Template` with the given context. @@ -476,13 +487,9 @@ class Template(object): The data is written to the context's buffer. """ - if getattr(context, '_with_template', None) is None: + if getattr(context, "_with_template", None) is None: context._set_with_template(self) - runtime._render_context(self, - self.callable_, - context, - *args, - **kwargs) + runtime._render_context(self, self.callable_, context, *args, **kwargs) def has_def(self, name): return hasattr(self.module, "render_%s" % name) @@ -498,7 +505,7 @@ class Template(object): .. versionadded:: 1.0.4 """ - return [i[7:] for i in dir(self.module) if i[:7] == 'render_'] + return [i[7:] for i in dir(self.module) if i[:7] == "render_"] def _get_def_callable(self, name): return getattr(self.module, "render_%s" % name) @@ -526,28 +533,30 @@ class ModuleTemplate(Template): """ - 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, - include_error_handler=None, - ): - self.module_id = re.sub(r'\W', "_", module._template_uri) + 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, + include_error_handler=None, + ): + self.module_id = re.sub(r"\W", "_", module._template_uri) self.uri = module._template_uri self.input_encoding = module._source_encoding self.output_encoding = output_encoding @@ -558,21 +567,24 @@ class ModuleTemplate(Template): 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.") + "None when disable_unicode is used." + ) self.module = module self.filename = template_filename - ModuleInfo(module, - module_filename, - self, - template_filename, - module_source, - template_source) + ModuleInfo( + module, + module_filename, + self, + template_filename, + module_source, + template_source, + ) self.callable_ = self.module.render_body self.format_exceptions = format_exceptions @@ -580,8 +592,12 @@ class ModuleTemplate(Template): self.include_error_handler = include_error_handler self.lookup = lookup self._setup_cache_args( - cache_impl, cache_enabled, cache_args, - cache_type, cache_dir, cache_url + cache_impl, + cache_enabled, + cache_args, + cache_type, + cache_dir, + cache_url, ) @@ -614,15 +630,18 @@ class ModuleInfo(object): source code based on a module's identifier. """ + _modules = weakref.WeakValueDictionary() - def __init__(self, - module, - module_filename, - template, - template_filename, - module_source, - template_source): + def __init__( + self, + module, + module_filename, + template, + template_filename, + module_source, + template_source, + ): self.module = module self.module_filename = module_filename self.template_filename = template_filename @@ -635,15 +654,15 @@ class ModuleInfo(object): @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'] + f_line_map = source_map["full_line_map"] = [] + line_map = source_map["line_map"] curr_templ_line = 1 for mod_line in range(1, max(line_map)): @@ -662,10 +681,12 @@ class ModuleInfo(object): @property def source(self): if self.template_source is not None: - if self.module._source_encoding and \ - not isinstance(self.template_source, compat.text_type): + 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: @@ -677,38 +698,46 @@ class ModuleInfo(object): 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) + lexer = template.lexer_cls( + text, + 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) + 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, + ) 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) + source, lexer = _compile( + template, + text, + filename, + generate_magic_comment=template.disable_unicode, + ) cid = identifier if not compat.py3k and isinstance(cid, compat.text_type): cid = cid.encode() module = types.ModuleType(cid) - code = compile(source, cid, 'exec') + code = compile(source, cid, "exec") # this exec() works for 2.4->3.3. exec(code, module.__dict__, module.__dict__) @@ -716,11 +745,12 @@ def _compile_text(template, text, filename): def _compile_module_file(template, text, filename, outputpath, module_writer): - source, lexer = _compile(template, text, filename, - generate_magic_comment=True) + source, lexer = _compile( + template, text, filename, generate_magic_comment=True + ) if isinstance(source, compat.text_type): - source = source.encode(lexer.encoding or 'ascii') + source = source.encode(lexer.encoding or "ascii") if module_writer: module_writer(source, outputpath) @@ -737,9 +767,9 @@ def _compile_module_file(template, text, filename, outputpath, module_writer): def _get_module_info_from_callable(callable_): if compat.py3k: - return _get_module_info(callable_.__globals__['__name__']) + return _get_module_info(callable_.__globals__["__name__"]) else: - return _get_module_info(callable_.func_globals['__name__']) + return _get_module_info(callable_.func_globals["__name__"]) def _get_module_info(filename): diff --git a/mako/util.py b/mako/util.py index 2f089ff..cee911b 100644 --- a/mako/util.py +++ b/mako/util.py @@ -4,12 +4,13 @@ # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -import re -import collections import codecs +import collections +import operator import os +import re + from mako import compat -import operator def update_wrapper(decorated, fn): @@ -19,7 +20,6 @@ def update_wrapper(decorated, fn): class PluginLoader(object): - def __init__(self, group): self.group = group self.impls = {} @@ -29,16 +29,16 @@ class PluginLoader(object): return self.impls[name]() else: import pkg_resources - for impl in pkg_resources.iter_entry_points( - self.group, - name): + + for impl in pkg_resources.iter_entry_points(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,18 +46,19 @@ class PluginLoader(object): for token in modulepath.split(".")[1:]: mod = getattr(mod, token) return getattr(mod, objname) + self.impls[name] = load -def verify_directory(dir): +def verify_directory(dir_): """create and/or verify a filesystem directory.""" tries = 0 - while not os.path.exists(dir): + while not os.path.exists(dir_): try: tries += 1 - os.makedirs(dir, compat.octal("0775")) + os.makedirs(dir_, compat.octal("0775")) except: if tries > 5: raise @@ -109,11 +110,15 @@ class memoized_instancemethod(object): def oneshot(*args, **kw): result = self.fget(obj, *args, **kw) - memo = lambda *a, **kw: result + + def memo(*a, **kw): + return result + memo.__name__ = self.__name__ memo.__doc__ = self.__doc__ obj.__dict__[self.__name__] = memo return result + oneshot.__name__ = self.__name__ oneshot.__doc__ = self.__doc__ return oneshot @@ -137,13 +142,13 @@ class FastEncodingBuffer(object): """a very rudimentary buffer that is faster than StringIO, but doesn't crash on unicode data like cStringIO.""" - def __init__(self, encoding=None, errors='strict', as_unicode=False): + def __init__(self, encoding=None, errors="strict", as_unicode=False): self.data = collections.deque() self.encoding = encoding if as_unicode: - self.delim = compat.u('') + self.delim = compat.u("") else: - self.delim = '' + self.delim = "" self.as_unicode = as_unicode self.errors = errors self.write = self.data.append @@ -154,8 +159,9 @@ class FastEncodingBuffer(object): def getvalue(self): if self.encoding: - return self.delim.join(self.data).encode(self.encoding, - self.errors) + return self.delim.join(self.data).encode( + self.encoding, self.errors + ) else: return self.delim.join(self.data) @@ -171,7 +177,6 @@ class LRUCache(dict): """ class _Item(object): - def __init__(self, key, value): self.key = key self.value = value @@ -180,7 +185,7 @@ class LRUCache(dict): def __repr__(self): return repr(self.value) - def __init__(self, capacity, threshold=.5): + def __init__(self, capacity, threshold=0.5): self.capacity = capacity self.threshold = threshold @@ -210,9 +215,12 @@ class LRUCache(dict): def _manage_size(self): while len(self) > self.capacity + self.capacity * self.threshold: - bytime = sorted(dict.values(self), - key=operator.attrgetter('timestamp'), reverse=True) - for item in bytime[self.capacity:]: + bytime = sorted( + dict.values(self), + key=operator.attrgetter("timestamp"), + reverse=True, + ) + for item in bytime[self.capacity :]: try: del self[item.key] except KeyError: @@ -220,10 +228,11 @@ class LRUCache(dict): # broke in on us. loop around and try again break + # Regexp to match python magic encoding line _PYTHON_MAGIC_COMMENT_re = re.compile( - r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)', - re.VERBOSE) + r"[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)", re.VERBOSE +) def parse_encoding(fp): @@ -242,13 +251,14 @@ def parse_encoding(fp): line1 = fp.readline() has_bom = line1.startswith(codecs.BOM_UTF8) if has_bom: - line1 = line1[len(codecs.BOM_UTF8):] + line1 = line1[len(codecs.BOM_UTF8) :] - m = _PYTHON_MAGIC_COMMENT_re.match(line1.decode('ascii', 'ignore')) + m = _PYTHON_MAGIC_COMMENT_re.match(line1.decode("ascii", "ignore")) if not m: try: import parser - parser.suite(line1.decode('ascii', 'ignore')) + + parser.suite(line1.decode("ascii", "ignore")) except (ImportError, SyntaxError): # Either it's a real syntax error, in which case the source # is not valid python source, or line2 is a continuation of @@ -258,14 +268,16 @@ def parse_encoding(fp): 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") - return 'utf_8' + " byte-order-mark and a magic encoding comment" + ) + return "utf_8" elif m: return m.group(1) else: @@ -289,10 +301,11 @@ def restore__ast(_ast): """Attempt to restore the required classes to the _ast module if it appears to be missing them """ - if hasattr(_ast, 'AST'): + if hasattr(_ast, "AST"): return _ast.PyCF_ONLY_AST = 2 << 9 - m = compile("""\ + m = compile( + """\ def foo(): pass class Bar(object): pass if False: pass @@ -305,13 +318,17 @@ baz = 'mako' baz and 'foo' or 'bar' (mako is baz == baz) is not baz != mako mako > baz < mako >= baz <= mako -mako in baz not in mako""", '<unknown>', 'exec', _ast.PyCF_ONLY_AST) +mako in baz not in mako""", + "<unknown>", + "exec", + _ast.PyCF_ONLY_AST, + ) _ast.Module = type(m) for cls in _ast.Module.__mro__: - if cls.__name__ == 'mod': + if cls.__name__ == "mod": _ast.mod = cls - elif cls.__name__ == 'AST': + elif cls.__name__ == "AST": _ast.AST = cls _ast.FunctionDef = type(m.body[0]) @@ -361,7 +378,7 @@ mako in baz not in mako""", '<unknown>', 'exec', _ast.PyCF_ONLY_AST) _ast.NotIn = type(m.body[12].value.ops[1]) -def read_file(path, mode='rb'): +def read_file(path, mode="rb"): fp = open(path, mode) try: data = fp.read() @@ -11,3 +11,17 @@ python_files=test/*test_*.py [upload] sign = 1 identity = C4DAFEE1 + +[flake8] +enable-extensions = G +# E203 is due to https://github.com/PyCQA/pycodestyle/issues/373 +ignore = + A003, + D, + E203,E305,E711,E712,E721,E722,E741, + N801,N802,N806, + RST304,RST303,RST299,RST399, + W503,W504 +exclude = .venv,.git,.tox,dist,docs/*,*egg,build +import-order-style = google +application-import-names = mako,test @@ -1,14 +1,20 @@ -from setuptools import setup, find_packages -from setuptools.command.test import test as TestCommand import os import re import sys -v = open(os.path.join(os.path.dirname(__file__), 'mako', '__init__.py')) -VERSION = re.compile(r".*__version__ = '(.*?)'", re.S).match(v.read()).group(1) +from setuptools import find_packages +from setuptools import setup +from setuptools.command.test import test as TestCommand + +v = open(os.path.join(os.path.dirname(__file__), "mako", "__init__.py")) +VERSION = ( + re.compile(r".*__version__ = [\"'](.*?)[\"']", re.S) + .match(v.read()) + .group(1) +) v.close() -readme = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read() +readme = open(os.path.join(os.path.dirname(__file__), "README.rst")).read() if sys.version_info < (2, 6): raise Exception("Mako requires Python 2.6 or higher.") @@ -20,16 +26,16 @@ markupsafe_installs = ( install_requires = [] if markupsafe_installs: - install_requires.append('MarkupSafe>=0.9.2') + install_requires.append("MarkupSafe>=0.9.2") try: - import argparse + import argparse # noqa except ImportError: - install_requires.append('argparse') + install_requires.append("argparse") class PyTest(TestCommand): - user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")] + user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] def initialize_options(self): TestCommand.initialize_options(self) @@ -43,39 +49,41 @@ class PyTest(TestCommand): def run_tests(self): # import here, cause outside the eggs aren't loaded import pytest + errno = pytest.main(self.pytest_args) sys.exit(errno) -setup(name='Mako', - version=VERSION, - description="A super-fast templating language that borrows the \ +setup( + name="Mako", + version=VERSION, + description="A super-fast templating language that borrows the \ best ideas from the existing templating languages.", - long_description=readme, - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'License :: OSI Approved :: MIT License', - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - ], - keywords='templates', - author='Mike Bayer', - author_email='mike@zzzcomputing.com', - url='https://www.makotemplates.org/', - license='MIT', - packages=find_packages('.', exclude=['examples*', 'test*']), - tests_require=['pytest', 'mock'], - cmdclass={'test': PyTest}, - zip_safe=False, - python_requires='>=2.6', - install_requires=install_requires, - extras_require={}, - entry_points=""" + long_description=readme, + classifiers=[ + "Development Status :: 5 - Production/Stable", + "License :: OSI Approved :: MIT License", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + ], + keywords="templates", + author="Mike Bayer", + author_email="mike@zzzcomputing.com", + url="https://www.makotemplates.org/", + license="MIT", + packages=find_packages(".", exclude=["examples*", "test*"]), + tests_require=["pytest", "mock"], + cmdclass={"test": PyTest}, + zip_safe=False, + python_requires=">=2.6", + install_requires=install_requires, + extras_require={}, + entry_points=""" [python.templating.engines] mako = mako.ext.turbogears:TGPlugin @@ -94,5 +102,5 @@ setup(name='Mako', [console_scripts] mako-render = mako.cmd:cmdline - """ + """, ) diff --git a/test/__init__.py b/test/__init__.py index 186ec04..b91e709 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,11 +1,15 @@ -from mako.template import Template -import unittest +import contextlib import os -from mako.compat import py3k, py33 +import re +import unittest + from mako import compat +from mako.cache import CacheImpl +from mako.cache import register_plugin +from mako.compat import py33 +from mako.compat import py3k +from mako.template import Template from mako.util import update_wrapper -import re -from mako.cache import CacheImpl, register_plugin try: # unitttest has a SkipTest also but pytest doesn't @@ -14,17 +18,16 @@ try: except ImportError: from _pytest.runner import Skipped as SkipTest -import contextlib +template_base = os.path.join(os.path.dirname(__file__), "templates") +module_base = os.path.join(template_base, "modules") -template_base = os.path.join(os.path.dirname(__file__), 'templates') -module_base = os.path.join(template_base, 'modules') class TemplateTest(unittest.TestCase): - def _file_template(self, filename, **kw): filepath = self._file_path(filename) - return Template(uri=filename, filename=filepath, - module_directory=module_base, **kw) + return Template( + uri=filename, filename=filepath, module_directory=module_base, **kw + ) def _file_path(self, filename): name, ext = os.path.splitext(filename) @@ -36,20 +39,50 @@ class TemplateTest(unittest.TestCase): return os.path.join(template_base, filename) - def _do_file_test(self, filename, expected, filters=None, - unicode_=True, template_args=None, **kw): + def _do_file_test( + self, + filename, + expected, + filters=None, + unicode_=True, + template_args=None, + **kw + ): t1 = self._file_template(filename, **kw) - self._do_test(t1, expected, filters=filters, - unicode_=unicode_, template_args=template_args) - - def _do_memory_test(self, source, expected, filters=None, - unicode_=True, template_args=None, **kw): + self._do_test( + t1, + expected, + filters=filters, + unicode_=unicode_, + template_args=template_args, + ) + + def _do_memory_test( + self, + source, + expected, + filters=None, + unicode_=True, + template_args=None, + **kw + ): t1 = Template(text=source, **kw) - self._do_test(t1, expected, filters=filters, - unicode_=unicode_, template_args=template_args) - - def _do_test(self, template, expected, filters=None, template_args=None, - unicode_=True): + self._do_test( + t1, + expected, + filters=filters, + unicode_=unicode_, + template_args=template_args, + ) + + def _do_test( + self, + template, + expected, + filters=None, + template_args=None, + unicode_=True, + ): if template_args is None: template_args = {} if unicode_: @@ -61,18 +94,23 @@ class TemplateTest(unittest.TestCase): output = filters(output) eq_(output, expected) + def eq_(a, b, msg=None): """Assert a == b, with repr messaging on failure.""" assert a == b, msg or "%r != %r" % (a, b) + def teardown(): import shutil + shutil.rmtree(module_base, True) + if py33: - from unittest import mock + from unittest import mock # noqa else: - import mock + import mock # noqa + @contextlib.contextmanager def raises(except_cls, message=None): @@ -81,9 +119,10 @@ def raises(except_cls, message=None): success = False except except_cls as e: if message: - assert re.search(message, compat.text_type(e), re.UNICODE), \ - "%r !~ %s" % (message, e) - print(compat.text_type(e).encode('utf-8')) + assert re.search( + message, compat.text_type(e), re.UNICODE + ), "%r !~ %s" % (message, e) + print(compat.text_type(e).encode("utf-8")) success = True # assert outside the block so it works for AssertionError too ! @@ -94,50 +133,64 @@ def assert_raises(except_cls, callable_, *args, **kw): with raises(except_cls): return callable_(*args, **kw) + def assert_raises_message(except_cls, msg, callable_, *args, **kwargs): with raises(except_cls, msg): return callable_(*args, **kwargs) + def skip_if(predicate, reason=None): """Skip a test if predicate is true.""" reason = reason or predicate.__name__ def decorate(fn): fn_name = fn.__name__ + def maybe(*args, **kw): if predicate(): - msg = "'%s' skipped: %s" % ( - fn_name, reason) + msg = "'%s' skipped: %s" % (fn_name, reason) raise SkipTest(msg) else: return fn(*args, **kw) + return update_wrapper(maybe, fn) + return decorate + def requires_python_3(fn): return skip_if(lambda: not py3k, "Requires Python 3.xx")(fn) + def requires_python_2(fn): return skip_if(lambda: py3k, "Requires Python 2.xx")(fn) + def requires_pygments_14(fn): try: import pygments + version = pygments.__version__ except: version = "0" - return skip_if(lambda: version < "1.4", "Requires pygments 1.4 or greater")(fn) + return skip_if( + lambda: version < "1.4", "Requires pygments 1.4 or greater" + )(fn) + def requires_no_pygments_exceptions(fn): def go(*arg, **kw): from mako import exceptions + exceptions._install_fallback() try: return fn(*arg, **kw) finally: exceptions._install_highlighting() + return update_wrapper(go, fn) + class PlainCacheImpl(CacheImpl): """Simple memory cache impl so that tests which use caching can run without beaker. """ @@ -162,4 +215,5 @@ class PlainCacheImpl(CacheImpl): def invalidate(self, key, **kw): del self.data[key] + register_plugin("plain", __name__, "PlainCacheImpl") diff --git a/test/ext/test_babelplugin.py b/test/ext/test_babelplugin.py index 3658c50..5f25a6a 100644 --- a/test/ext/test_babelplugin.py +++ b/test/ext/test_babelplugin.py @@ -1,93 +1,120 @@ import io import os import unittest -from .. import TemplateTest, template_base, skip_if + from mako import compat +from .. import skip_if +from .. import template_base +from .. import TemplateTest try: import babel.messages.extract as babel from mako.ext.babelplugin import extract - + except ImportError: babel = None def skip(): return skip_if( - lambda: not babel, - 'babel not installed: skipping babelplugin test') + lambda: not babel, "babel not installed: skipping babelplugin test" + ) class Test_extract(unittest.TestCase): @skip() def test_parse_python_expression(self): - input = io.BytesIO(compat.b('<p>${_("Message")}</p>')) - messages = list(extract(input, ['_'], [], {})) - self.assertEqual(messages, [(1, '_', compat.u('Message'), [])]) + input_ = io.BytesIO(compat.b('<p>${_("Message")}</p>')) + messages = list(extract(input_, ["_"], [], {})) + self.assertEqual(messages, [(1, "_", compat.u("Message"), [])]) @skip() def test_python_gettext_call(self): - input = io.BytesIO(compat.b('<p>${_("Message")}</p>')) - messages = list(extract(input, ['_'], [], {})) - self.assertEqual(messages, [(1, '_', compat.u('Message'), [])]) + input_ = io.BytesIO(compat.b('<p>${_("Message")}</p>')) + messages = list(extract(input_, ["_"], [], {})) + self.assertEqual(messages, [(1, "_", compat.u("Message"), [])]) @skip() def test_translator_comment(self): - input = io.BytesIO(compat.b(''' + input_ = io.BytesIO( + compat.b( + """ <p> ## TRANSLATORS: This is a comment. ${_("Message")} - </p>''')) - messages = list(extract(input, ['_'], ['TRANSLATORS:'], {})) + </p>""" + ) + ) + messages = list(extract(input_, ["_"], ["TRANSLATORS:"], {})) self.assertEqual( messages, - [(4, '_', compat.u('Message'), - [compat.u('TRANSLATORS: This is a comment.')])]) + [ + ( + 4, + "_", + compat.u("Message"), + [compat.u("TRANSLATORS: This is a comment.")], + ) + ], + ) class ExtractMakoTestCase(TemplateTest): @skip() def test_extract(self): - mako_tmpl = open(os.path.join(template_base, 'gettext.mako')) - messages = list(extract(mako_tmpl, {'_': None, 'gettext': None, - 'ungettext': (1, 2)}, - ['TRANSLATOR:'], {})) - expected = \ - [(1, '_', 'Page arg 1', []), - (1, '_', 'Page arg 2', []), - (10, 'gettext', 'Begin', []), - (14, '_', 'Hi there!', ['TRANSLATOR: Hi there!']), - (19, '_', 'Hello', []), - (22, '_', 'Welcome', []), - (25, '_', 'Yo', []), - (36, '_', 'The', ['TRANSLATOR: Ensure so and', 'so, thanks']), - (36, 'ungettext', ('bunny', 'bunnies', None), []), - (41, '_', 'Goodbye', ['TRANSLATOR: Good bye']), - (44, '_', 'Babel', []), - (45, 'ungettext', ('hella', 'hellas', None), []), - (62, '_', 'The', ['TRANSLATOR: Ensure so and', 'so, thanks']), - (62, 'ungettext', ('bunny', 'bunnies', None), []), - (68, '_', 'Goodbye, really!', ['TRANSLATOR: HTML comment']), - (71, '_', 'P.S. byebye', []), - (77, '_', 'Top', []), - (83, '_', 'foo', []), - (83, '_', 'hoho', []), - (85, '_', 'bar', []), - (92, '_', 'Inside a p tag', ['TRANSLATOR: <p> tag is ok?']), - (95, '_', 'Later in a p tag', ['TRANSLATOR: also this']), - (99, '_', 'No action at a distance.', []), - ] + mako_tmpl = open(os.path.join(template_base, "gettext.mako")) + messages = list( + extract( + mako_tmpl, + {"_": None, "gettext": None, "ungettext": (1, 2)}, + ["TRANSLATOR:"], + {}, + ) + ) + expected = [ + (1, "_", "Page arg 1", []), + (1, "_", "Page arg 2", []), + (10, "gettext", "Begin", []), + (14, "_", "Hi there!", ["TRANSLATOR: Hi there!"]), + (19, "_", "Hello", []), + (22, "_", "Welcome", []), + (25, "_", "Yo", []), + (36, "_", "The", ["TRANSLATOR: Ensure so and", "so, thanks"]), + (36, "ungettext", ("bunny", "bunnies", None), []), + (41, "_", "Goodbye", ["TRANSLATOR: Good bye"]), + (44, "_", "Babel", []), + (45, "ungettext", ("hella", "hellas", None), []), + (62, "_", "The", ["TRANSLATOR: Ensure so and", "so, thanks"]), + (62, "ungettext", ("bunny", "bunnies", None), []), + (68, "_", "Goodbye, really!", ["TRANSLATOR: HTML comment"]), + (71, "_", "P.S. byebye", []), + (77, "_", "Top", []), + (83, "_", "foo", []), + (83, "_", "hoho", []), + (85, "_", "bar", []), + (92, "_", "Inside a p tag", ["TRANSLATOR: <p> tag is ok?"]), + (95, "_", "Later in a p tag", ["TRANSLATOR: also this"]), + (99, "_", "No action at a distance.", []), + ] self.assertEqual(expected, messages) @skip() def test_extract_utf8(self): - mako_tmpl = open(os.path.join(template_base, 'gettext_utf8.mako'), 'rb') - message = next(extract(mako_tmpl, set(['_', None]), [], {'encoding': 'utf-8'})) - assert message == (1, '_', u'K\xf6ln', []) + mako_tmpl = open( + os.path.join(template_base, "gettext_utf8.mako"), "rb" + ) + message = next( + extract(mako_tmpl, set(["_", None]), [], {"encoding": "utf-8"}) + ) + assert message == (1, "_", u"K\xf6ln", []) @skip() def test_extract_cp1251(self): - mako_tmpl = open(os.path.join(template_base, 'gettext_cp1251.mako'), 'rb') - message = next(extract(mako_tmpl, set(['_', None]), [], {'encoding': 'cp1251'})) + mako_tmpl = open( + os.path.join(template_base, "gettext_cp1251.mako"), "rb" + ) + message = next( + extract(mako_tmpl, set(["_", None]), [], {"encoding": "cp1251"}) + ) # "test" in Rusian. File encoding is cp1251 (aka "windows-1251") - assert message == (1, '_', u'\u0442\u0435\u0441\u0442', []) + assert message == (1, "_", u"\u0442\u0435\u0441\u0442", []) diff --git a/test/ext/test_linguaplugin.py b/test/ext/test_linguaplugin.py index 9c46271..a563969 100644 --- a/test/ext/test_linguaplugin.py +++ b/test/ext/test_linguaplugin.py @@ -1,5 +1,8 @@ import os -from .. import TemplateTest, template_base, skip_if + +from .. import skip_if +from .. import template_base +from .. import TemplateTest try: import lingua @@ -18,40 +21,44 @@ class MockOptions: def skip(): return skip_if( - lambda: not lingua, 'lingua not installed: skipping linguaplugin test') + lambda: not lingua, "lingua not installed: skipping linguaplugin test" + ) class ExtractMakoTestCase(TemplateTest): @skip() def test_extract(self): register_extractors() - plugin = LinguaMakoExtractor({'comment-tags': 'TRANSLATOR'}) + plugin = LinguaMakoExtractor({"comment-tags": "TRANSLATOR"}) messages = list( - plugin(os.path.join(template_base, 'gettext.mako'), MockOptions())) + plugin(os.path.join(template_base, "gettext.mako"), MockOptions()) + ) msgids = [(m.msgid, m.msgid_plural) for m in messages] self.assertEqual( msgids, [ - ('Page arg 1', None), - ('Page arg 2', None), - ('Begin', None), - ('Hi there!', None), - ('Hello', None), - ('Welcome', None), - ('Yo', None), - ('The', None), - ('bunny', 'bunnies'), - ('Goodbye', None), - ('Babel', None), - ('hella', 'hellas'), - ('The', None), - ('bunny', 'bunnies'), - ('Goodbye, really!', None), - ('P.S. byebye', None), - ('Top', None), - (u'foo', None), - ('hoho', None), - (u'bar', None), - ('Inside a p tag', None), - ('Later in a p tag', None), - ('No action at a distance.', None)]) + ("Page arg 1", None), + ("Page arg 2", None), + ("Begin", None), + ("Hi there!", None), + ("Hello", None), + ("Welcome", None), + ("Yo", None), + ("The", None), + ("bunny", "bunnies"), + ("Goodbye", None), + ("Babel", None), + ("hella", "hellas"), + ("The", None), + ("bunny", "bunnies"), + ("Goodbye, really!", None), + ("P.S. byebye", None), + ("Top", None), + (u"foo", None), + ("hoho", None), + (u"bar", None), + ("Inside a p tag", None), + ("Later in a p tag", None), + ("No action at a distance.", None), + ], + ) diff --git a/test/foo/mod_no_encoding.py b/test/foo/mod_no_encoding.py index 2ba6746..004cc44 100644 --- a/test/foo/mod_no_encoding.py +++ b/test/foo/mod_no_encoding.py @@ -1,8 +1,7 @@ - from mako.lookup import TemplateLookup -from mako.exceptions import MakoException, html_error_template template_lookup = TemplateLookup() -def run(): - tpl = template_lookup.get_template('not_found.html') + +def run(): + tpl = template_lookup.get_template("not_found.html") diff --git a/test/foo/test_ns.py b/test/foo/test_ns.py index 282447a..f67e22e 100644 --- a/test/foo/test_ns.py +++ b/test/foo/test_ns.py @@ -1,10 +1,11 @@ def foo1(context): context.write("this is foo1.") - return '' + return "" + def foo2(context, x): context.write("this is foo2, x is " + x) - return '' + return "" -foo3 = "I'm not a callable"
\ No newline at end of file +foo3 = "I'm not a callable" diff --git a/test/sample_module_namespace.py b/test/sample_module_namespace.py index 7a2425d..886e8dd 100644 --- a/test/sample_module_namespace.py +++ b/test/sample_module_namespace.py @@ -1,7 +1,8 @@ def foo1(context): context.write("this is foo1.") - return '' - + return "" + + def foo2(context, x): context.write("this is foo2, x is " + x) - return ''
\ No newline at end of file + return "" diff --git a/test/test_ast.py b/test/test_ast.py index 24ba0c3..ce6c082 100644 --- a/test/test_ast.py +++ b/test/test_ast.py @@ -1,16 +1,17 @@ import unittest -from mako import ast, exceptions, pyparser, util, compat -from test import eq_, requires_python_2, requires_python_3 +from mako import ast +from mako import compat +from mako import exceptions +from mako import pyparser +from test import eq_ +from test import requires_python_2 +from test import requires_python_3 -exception_kwargs = { - 'source': '', - 'lineno': 0, - 'pos': 0, - 'filename': ''} +exception_kwargs = {"source": "", "lineno": 0, "pos": 0, "filename": ""} -class AstParseTest(unittest.TestCase): +class AstParseTest(unittest.TestCase): def test_locate_identifiers(self): """test the location of identifiers in a python code string""" code = """ @@ -29,16 +30,17 @@ for lar in (1,2,3): parsed = ast.PythonCode(code, **exception_kwargs) eq_( parsed.declared_identifiers, - set(['a', 'b', 'c', 'g', 'h', 'i', 'u', - 'k', 'j', 'gh', 'lar', 'x']) + set( + ["a", "b", "c", "g", "h", "i", "u", "k", "j", "gh", "lar", "x"] + ), ) eq_( parsed.undeclared_identifiers, - set(['x', 'q', 'foo', 'gah', 'blah']) + set(["x", "q", "foo", "gah", "blah"]), ) parsed = ast.PythonCode("x + 5 * (y-z)", **exception_kwargs) - assert parsed.undeclared_identifiers == set(['x', 'y', 'z']) + assert parsed.undeclared_identifiers == set(["x", "y", "z"]) assert parsed.declared_identifiers == set() def test_locate_identifiers_2(self): @@ -52,10 +54,10 @@ for x in data: result.append(x+7) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['get_data'])) + eq_(parsed.undeclared_identifiers, set(["get_data"])) eq_( parsed.declared_identifiers, - set(['result', 'data', 'x', 'hoho', 'foobar', 'foo', 'yaya']) + set(["result", "data", "x", "hoho", "foobar", "foo", "yaya"]), ) def test_locate_identifiers_3(self): @@ -69,10 +71,7 @@ for y in range(1, y): (q for q in range (1, q)) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_( - parsed.undeclared_identifiers, - set(['x', 'y', 'z', 'q', 'range']) - ) + eq_(parsed.undeclared_identifiers, set(["x", "y", "z", "q", "range"])) def test_locate_identifiers_4(self): code = """ @@ -82,8 +81,8 @@ def mydef(mydefarg): print("mda is", mydefarg) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['y'])) - eq_(parsed.declared_identifiers, set(['mydef', 'x'])) + eq_(parsed.undeclared_identifiers, set(["y"])) + eq_(parsed.declared_identifiers, set(["mydef", "x"])) def test_locate_identifiers_5(self): code = """ @@ -93,7 +92,7 @@ except: print(y) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['x', 'y'])) + eq_(parsed.undeclared_identifiers, set(["x", "y"])) def test_locate_identifiers_6(self): code = """ @@ -101,7 +100,7 @@ def foo(): return bar() """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['bar'])) + eq_(parsed.undeclared_identifiers, set(["bar"])) code = """ def lala(x, y): @@ -109,8 +108,8 @@ def lala(x, y): print(x) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['z', 'x'])) - eq_(parsed.declared_identifiers, set(['lala'])) + eq_(parsed.undeclared_identifiers, set(["z", "x"])) + eq_(parsed.declared_identifiers, set(["lala"])) code = """ def lala(x, y): @@ -120,15 +119,15 @@ def lala(x, y): print(z) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['z'])) - eq_(parsed.declared_identifiers, set(['lala'])) + eq_(parsed.undeclared_identifiers, set(["z"])) + eq_(parsed.declared_identifiers, set(["lala"])) def test_locate_identifiers_7(self): code = """ import foo.bar """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['foo'])) + eq_(parsed.declared_identifiers, set(["foo"])) eq_(parsed.undeclared_identifiers, set()) def test_locate_identifiers_8(self): @@ -139,7 +138,7 @@ class Hi(object): x = 5 """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['Hi'])) + eq_(parsed.declared_identifiers, set(["Hi"])) eq_(parsed.undeclared_identifiers, set()) def test_locate_identifiers_9(self): @@ -147,15 +146,15 @@ class Hi(object): ",".join([t for t in ("a", "b", "c")]) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['t'])) - eq_(parsed.undeclared_identifiers, set(['t'])) + eq_(parsed.declared_identifiers, set(["t"])) + eq_(parsed.undeclared_identifiers, set(["t"])) code = """ [(val, name) for val, name in x] """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['val', 'name'])) - eq_(parsed.undeclared_identifiers, set(['val', 'name', 'x'])) + eq_(parsed.declared_identifiers, set(["val", "name"])) + eq_(parsed.undeclared_identifiers, set(["val", "name", "x"])) def test_locate_identifiers_10(self): code = """ @@ -171,10 +170,9 @@ def x(q): return q + 5 """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['x'])) + eq_(parsed.declared_identifiers, set(["x"])) eq_(parsed.undeclared_identifiers, set()) - def test_locate_identifiers_12(self): code = """ def foo(): @@ -183,7 +181,7 @@ def foo(): t = s """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['foo'])) + eq_(parsed.declared_identifiers, set(["foo"])) eq_(parsed.undeclared_identifiers, set()) def test_locate_identifiers_13(self): @@ -194,7 +192,7 @@ def foo(): Bat """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['foo'])) + eq_(parsed.declared_identifiers, set(["foo"])) eq_(parsed.undeclared_identifiers, set()) def test_locate_identifiers_14(self): @@ -207,8 +205,8 @@ def foo(): print(Bat) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['foo'])) - eq_(parsed.undeclared_identifiers, set(['Bat'])) + eq_(parsed.declared_identifiers, set(["foo"])) + eq_(parsed.undeclared_identifiers, set(["Bat"])) @requires_python_2 def test_locate_identifiers_15(self): @@ -219,7 +217,7 @@ def t1((x,y)): t2 = lambda (x,y):(x+5, y+4) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.declared_identifiers, set(['t1', 't2'])) + eq_(parsed.declared_identifiers, set(["t1", "t2"])) eq_(parsed.undeclared_identifiers, set()) def test_locate_identifiers_16(self): @@ -230,7 +228,7 @@ except Exception as e: print(y) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['x', 'y', 'Exception'])) + eq_(parsed.undeclared_identifiers, set(["x", "y", "Exception"])) def test_locate_identifiers_17(self): code = """ @@ -240,38 +238,47 @@ except (Foo, Bar) as e: print(y) """ parsed = ast.PythonCode(code, **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['x', 'y', 'Foo', 'Bar'])) + eq_(parsed.undeclared_identifiers, set(["x", "y", "Foo", "Bar"])) def test_no_global_imports(self): code = """ from foo import * import x as bar """ - self.assertRaises(exceptions.CompileException, - ast.PythonCode, code, **exception_kwargs) + self.assertRaises( + exceptions.CompileException, + ast.PythonCode, + code, + **exception_kwargs + ) def test_python_fragment(self): parsed = ast.PythonFragment("for x in foo:", **exception_kwargs) - eq_(parsed.declared_identifiers, set(['x'])) - eq_(parsed.undeclared_identifiers, set(['foo'])) + eq_(parsed.declared_identifiers, set(["x"])) + eq_(parsed.undeclared_identifiers, set(["foo"])) parsed = ast.PythonFragment("try:", **exception_kwargs) if compat.py3k: parsed = ast.PythonFragment( - "except MyException as e:", **exception_kwargs) + "except MyException as e:", **exception_kwargs + ) else: parsed = ast.PythonFragment( - "except MyException, e:", **exception_kwargs) - eq_(parsed.declared_identifiers, set(['e'])) - eq_(parsed.undeclared_identifiers, set(['MyException'])) + "except MyException, e:", **exception_kwargs + ) + eq_(parsed.declared_identifiers, set(["e"])) + eq_(parsed.undeclared_identifiers, set(["MyException"])) def test_argument_list(self): - parsed = ast.ArgumentList("3, 5, 'hi', x+5, " - "context.get('lala')", **exception_kwargs) - eq_(parsed.undeclared_identifiers, set(['x', 'context'])) - eq_([x for x in parsed.args], - ["3", "5", "'hi'", "(x + 5)", "context.get('lala')"]) + parsed = ast.ArgumentList( + "3, 5, 'hi', x+5, " "context.get('lala')", **exception_kwargs + ) + eq_(parsed.undeclared_identifiers, set(["x", "context"])) + eq_( + [x for x in parsed.args], + ["3", "5", "'hi'", "(x + 5)", "context.get('lala')"], + ) parsed = ast.ArgumentList("h", **exception_kwargs) eq_(parsed.args, ["h"]) @@ -280,32 +287,26 @@ import x as bar """test getting the arguments from a function""" code = "def foo(a, b, c=None, d='hi', e=x, f=y+7):pass" parsed = ast.FunctionDecl(code, **exception_kwargs) - eq_(parsed.funcname, 'foo') - eq_(parsed.argnames, - ['a', 'b', 'c', 'd', 'e', 'f']) - eq_(parsed.kwargnames, - []) + eq_(parsed.funcname, "foo") + eq_(parsed.argnames, ["a", "b", "c", "d", "e", "f"]) + eq_(parsed.kwargnames, []) def test_function_decl_2(self): """test getting the arguments from a function""" code = "def foo(a, b, c=None, *args, **kwargs):pass" parsed = ast.FunctionDecl(code, **exception_kwargs) - eq_(parsed.funcname, 'foo') - eq_(parsed.argnames, - ['a', 'b', 'c', 'args']) - eq_(parsed.kwargnames, - ['kwargs']) + eq_(parsed.funcname, "foo") + eq_(parsed.argnames, ["a", "b", "c", "args"]) + eq_(parsed.kwargnames, ["kwargs"]) @requires_python_3 def test_function_decl_3(self): """test getting the arguments from a fancy py3k function""" code = "def foo(a, b, *c, d, e, **f):pass" parsed = ast.FunctionDecl(code, **exception_kwargs) - eq_(parsed.funcname, 'foo') - eq_(parsed.argnames, - ['a', 'b', 'c']) - eq_(parsed.kwargnames, - ['d', 'e', 'f']) + eq_(parsed.funcname, "foo") + eq_(parsed.argnames, ["a", "b", "c"]) + eq_(parsed.kwargnames, ["d", "e", "f"]) def test_expr_generate(self): """test the round trip of expressions to AST back to python source""" @@ -313,7 +314,7 @@ import x as bar y = 2 class F(object): - def bar(self, a,b): + def bar(self, a, b): return a + b def lala(arg): @@ -327,48 +328,47 @@ import x as bar eq_(eval(code, local_dict), eval(newcode, local_dict)) a = ["one", "two", "three"] - hoho = {'somevalue': "asdf"} + hoho = {"somevalue": "asdf"} g = [1, 2, 3, 4, 5] local_dict = dict(a=a, hoho=hoho, g=g) - code = "a[2] + hoho['somevalue'] + "\ - "repr(g[3:5]) + repr(g[3:]) + repr(g[:5])" + code = ( + "a[2] + hoho['somevalue'] + " + "repr(g[3:5]) + repr(g[3:]) + repr(g[:5])" + ) astnode = pyparser.parse(code) newcode = pyparser.ExpressionGenerator(astnode).value() eq_(eval(code, local_dict), eval(newcode, local_dict)) - local_dict = {'f': lambda: 9, 'x': 7} + local_dict = {"f": lambda: 9, "x": 7} code = "x+f()" astnode = pyparser.parse(code) newcode = pyparser.ExpressionGenerator(astnode).value() eq_(eval(code, local_dict), eval(newcode, local_dict)) - for code in ["repr({'x':7,'y':18})", - "repr([])", - "repr({})", - "repr([{3:[]}])", - "repr({'x':37*2 + len([6,7,8])})", - "repr([1, 2, {}, {'x':'7'}])", - "repr({'x':-1})", "repr(((1,2,3), (4,5,6)))", - "repr(1 and 2 and 3 and 4)", - "repr(True and False or 55)", - "repr(lambda x, y: (x + y))", - "repr(lambda *arg, **kw: arg, kw)", - "repr(1 & 2 | 3)", - "repr(3//5)", - "repr(3^5)", - "repr([q.endswith('e') for q in " - "['one', 'two', 'three']])", - "repr([x for x in (5,6,7) if x == 6])", - "repr(not False)"]: + for code in [ + "repr({'x':7,'y':18})", + "repr([])", + "repr({})", + "repr([{3:[]}])", + "repr({'x':37*2 + len([6,7,8])})", + "repr([1, 2, {}, {'x':'7'}])", + "repr({'x':-1})", + "repr(((1,2,3), (4,5,6)))", + "repr(1 and 2 and 3 and 4)", + "repr(True and False or 55)", + "repr(lambda x, y: (x + y))", + "repr(lambda *arg, **kw: arg, kw)", + "repr(1 & 2 | 3)", + "repr(3//5)", + "repr(3^5)", + "repr([q.endswith('e') for q in " "['one', 'two', 'three']])", + "repr([x for x in (5,6,7) if x == 6])", + "repr(not False)", + ]: local_dict = {} astnode = pyparser.parse(code) newcode = pyparser.ExpressionGenerator(astnode).value() if "lambda" in code: eq_(code, newcode) else: - eq_(eval(code, local_dict), - eval(newcode, local_dict) - ) - - - + eq_(eval(code, local_dict), eval(newcode, local_dict)) diff --git a/test/test_block.py b/test/test_block.py index da3de15..0cbe347 100644 --- a/test/test_block.py +++ b/test/test_block.py @@ -1,9 +1,9 @@ -from mako.template import Template -from mako.lookup import TemplateLookup from mako import exceptions -from test import TemplateTest, assert_raises, assert_raises_message -from test.util import flatten_result, result_lines - +from mako.lookup import TemplateLookup +from mako.template import Template +from test import assert_raises_message +from test import TemplateTest +from test.util import result_lines class BlockTest(TemplateTest): @@ -11,17 +11,19 @@ class BlockTest(TemplateTest): assert_raises_message( exceptions.CompileException, "Can't put anonymous blocks inside <%namespace>", - Template, """ + Template, + """ <%namespace name="foo"> <%block> block </%block> </%namespace> - """ + """, ) def test_anonymous_block_in_call(self): - template = Template(""" + template = Template( + """ <%self:foo x="5"> <%block> @@ -33,18 +35,18 @@ class BlockTest(TemplateTest): foo: ${caller.body()} </%def> - """) + """ + ) self._do_test( - template, - ["foo:", "this is the block x"], - filters=result_lines + template, ["foo:", "this is the block x"], filters=result_lines ) def test_named_block_in_call(self): assert_raises_message( exceptions.CompileException, "Named block 'y' not allowed inside of <%call> tag", - Template,""" + Template, + """ <%self:foo x="5"> <%block name="y"> @@ -57,7 +59,8 @@ class BlockTest(TemplateTest): ${caller.body()} ${caller.y()} </%def> - """) + """, + ) def test_name_collision_blocks_toplevel(self): assert_raises_message( @@ -74,7 +77,7 @@ class BlockTest(TemplateTest): <%block name="x"> block </%block> - """ + """, ) def test_name_collision_blocks_nested_block(self): @@ -94,7 +97,7 @@ class BlockTest(TemplateTest): block </%block> </%block> - """ + """, ) def test_name_collision_blocks_nested_def(self): @@ -114,7 +117,7 @@ class BlockTest(TemplateTest): block </%block> </%def> - """ + """, ) def test_name_collision_block_def_toplevel(self): @@ -132,7 +135,7 @@ class BlockTest(TemplateTest): <%def name="x()"> block </%def> - """ + """, ) def test_name_collision_def_block_toplevel(self): @@ -151,31 +154,37 @@ class BlockTest(TemplateTest): block </%block> - """ + """, ) def test_named_block_renders(self): - template = Template(""" + template = Template( + """ above <%block name="header"> the header </%block> below - """) - self._do_test(template, ["above", "the header", "below"], - filters=result_lines) + """ + ) + self._do_test( + template, ["above", "the header", "below"], filters=result_lines + ) def test_inherited_block_no_render(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="base"/> <%block name="header"> index header </%block> - """ + """, ) - l.put_string("base",""" + l.put_string( + "base", + """ above <%block name="header"> the header @@ -183,10 +192,13 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "index header", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "index header", "below"], + filters=result_lines, + ) def test_no_named_in_def(self): assert_raises_message( @@ -198,11 +210,13 @@ class BlockTest(TemplateTest): <%block name="y"> </%block> </%def> - """) + """, + ) def test_inherited_block_nested_both(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="base"/> <%block name="title"> @@ -213,9 +227,11 @@ class BlockTest(TemplateTest): index header ${parent.header()} </%block> - """ + """, ) - l.put_string("base",""" + l.put_string( + "base", + """ above <%block name="header"> base header @@ -226,23 +242,29 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "index header", "base header", "index title", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "index header", "base header", "index title", "below"], + filters=result_lines, + ) def test_inherited_block_nested_inner_only(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="base"/> <%block name="title"> index title </%block> - """ + """, ) - l.put_string("base",""" + l.put_string( + "base", + """ above <%block name="header"> base header @@ -253,22 +275,28 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "base header", "index title", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "base header", "index title", "below"], + filters=result_lines, + ) def test_noninherited_block_no_render(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="base"/> <%block name="some_thing"> some thing </%block> - """ + """, ) - l.put_string("base",""" + l.put_string( + "base", + """ above <%block name="header"> the header @@ -276,14 +304,18 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "the header", "some thing", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "the header", "some thing", "below"], + filters=result_lines, + ) def test_no_conflict_nested_one(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="base"/> <%block> @@ -291,9 +323,11 @@ class BlockTest(TemplateTest): inner header </%block> </%block> - """ + """, ) - l.put_string("base",""" + l.put_string( + "base", + """ above <%block name="header"> the header @@ -301,10 +335,13 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "inner header", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "inner header", "below"], + filters=result_lines, + ) def test_nested_dupe_names_raise(self): assert_raises_message( @@ -318,12 +355,13 @@ class BlockTest(TemplateTest): inner header </%block> </%block> - """ + """, ) def test_two_levels_one(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="middle"/> <%block name="header"> @@ -332,16 +370,21 @@ class BlockTest(TemplateTest): <%block> index anon </%block> - """ + """, ) - l.put_string("middle", """ + l.put_string( + "middle", + """ <%inherit file="base"/> <%block> middle anon </%block> ${next.body()} - """) - l.put_string("base",""" + """, + ) + l.put_string( + "base", + """ above <%block name="header"> the header @@ -349,23 +392,27 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "index header", "middle anon", - "index anon", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "index header", "middle anon", "index anon", "below"], + filters=result_lines, + ) def test_filter(self): - template = Template(""" + template = Template( + """ <%block filter="h"> <html> </%block> - """) - self._do_test(template, ['<html>'], - filters=result_lines) + """ + ) + self._do_test(template, ["<html>"], filters=result_lines) def test_anon_in_named(self): - template = Template(""" + template = Template( + """ <%block name="x"> outer above <%block> @@ -373,11 +420,13 @@ class BlockTest(TemplateTest): </%block> outer below </%block> - """) + """ + ) self._test_block_in_block(template) def test_named_in_anon(self): - template = Template(""" + template = Template( + """ <%block> outer above <%block name="x"> @@ -385,11 +434,13 @@ class BlockTest(TemplateTest): </%block> outer below </%block> - """) + """ + ) self._test_block_in_block(template) def test_anon_in_anon(self): - template = Template(""" + template = Template( + """ <%block> outer above <%block> @@ -397,11 +448,13 @@ class BlockTest(TemplateTest): </%block> outer below </%block> - """) + """ + ) self._test_block_in_block(template) def test_named_in_named(self): - template = Template(""" + template = Template( + """ <%block name="x"> outer above <%block name="y"> @@ -409,28 +462,30 @@ class BlockTest(TemplateTest): </%block> outer below </%block> - """) + """ + ) self._test_block_in_block(template) def _test_block_in_block(self, template): - self._do_test(template, + self._do_test( + template, ["outer above", "inner", "outer below"], - filters=result_lines + filters=result_lines, ) def test_iteration(self): - t = Template(""" + t = Template( + """ % for i in (1, 2, 3): <%block>${i}</%block> % endfor - """) - self._do_test(t, - ["1", "2", "3"], - filters=result_lines + """ ) + self._do_test(t, ["1", "2", "3"], filters=result_lines) def test_conditional(self): - t = Template(""" + t = Template( + """ % if True: <%block>true</%block> % endif @@ -438,23 +493,24 @@ class BlockTest(TemplateTest): % if False: <%block>false</%block> % endif - """) - self._do_test(t, - ["true"], - filters=result_lines + """ ) + self._do_test(t, ["true"], filters=result_lines) def test_block_overridden_by_def(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="base"/> <%def name="header()"> inner header </%def> - """ + """, ) - l.put_string("base",""" + l.put_string( + "base", + """ above <%block name="header"> the header @@ -462,22 +518,28 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "inner header", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "inner header", "below"], + filters=result_lines, + ) def test_def_overridden_by_block(self): l = TemplateLookup() - l.put_string("index", + l.put_string( + "index", """ <%inherit file="base"/> <%block name="header"> inner header </%block> - """ + """, ) - l.put_string("base",""" + l.put_string( + "base", + """ above ${self.header()} <%def name="header()"> @@ -486,84 +548,101 @@ class BlockTest(TemplateTest): ${next.body()} below - """) - self._do_test(l.get_template("index"), - ["above", "inner header", "below"], - filters=result_lines) + """, + ) + self._do_test( + l.get_template("index"), + ["above", "inner header", "below"], + filters=result_lines, + ) def test_block_args(self): l = TemplateLookup() - l.put_string("caller", """ + l.put_string( + "caller", + """ <%include file="callee" args="val1='3', val2='4'"/> - """) - l.put_string("callee", """ + """, + ) + l.put_string( + "callee", + """ <%page args="val1, val2"/> <%block name="foob" args="val1, val2"> foob, ${val1}, ${val2} </%block> - """) + """, + ) self._do_test( - l.get_template("caller"), - ['foob, 3, 4'], - filters=result_lines + l.get_template("caller"), ["foob, 3, 4"], filters=result_lines ) def test_block_variables_contextual(self): - t = Template(""" + t = Template( + """ <%block name="foob" > foob, ${val1}, ${val2} </%block> - """) + """ + ) self._do_test( t, - ['foob, 3, 4'], - template_args={'val1':3, 'val2':4}, - filters=result_lines + ["foob, 3, 4"], + template_args={"val1": 3, "val2": 4}, + filters=result_lines, ) def test_block_args_contextual(self): - t = Template(""" + t = Template( + """ <%page args="val1"/> <%block name="foob" args="val1"> foob, ${val1}, ${val2} </%block> - """) + """ + ) self._do_test( t, - ['foob, 3, 4'], - template_args={'val1':3, 'val2':4}, - filters=result_lines + ["foob, 3, 4"], + template_args={"val1": 3, "val2": 4}, + filters=result_lines, ) def test_block_pageargs_contextual(self): - t = Template(""" + t = Template( + """ <%block name="foob"> foob, ${pageargs['val1']}, ${pageargs['val2']} </%block> - """) + """ + ) self._do_test( t, - ['foob, 3, 4'], - template_args={'val1':3, 'val2':4}, - filters=result_lines + ["foob, 3, 4"], + template_args={"val1": 3, "val2": 4}, + filters=result_lines, ) def test_block_pageargs(self): l = TemplateLookup() - l.put_string("caller", """ + l.put_string( + "caller", + """ <%include file="callee" args="val1='3', val2='4'"/> - """) - l.put_string("callee", """ + """, + ) + l.put_string( + "callee", + """ <%block name="foob"> foob, ${pageargs['val1']}, ${pageargs['val2']} </%block> - """) + """, + ) self._do_test( - l.get_template("caller"), - ['foob, 3, 4'], - filters=result_lines - )
\ No newline at end of file + l.get_template("caller"), ["foob, 3, 4"], filters=result_lines + ) diff --git a/test/test_cache.py b/test/test_cache.py index 990a088..7fe9350 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -1,19 +1,21 @@ -from mako.template import Template -from mako.lookup import TemplateLookup -from mako import lookup import time -from test.util import result_lines -from test import TemplateTest, module_base -from test import eq_, SkipTest -from mako.compat import py27 +from mako import lookup +from mako.cache import CacheImpl +from mako.cache import register_plugin +from mako.compat import py27 from mako.ext import beaker_cache +from mako.lookup import TemplateLookup +from mako.template import Template +from test import eq_ +from test import module_base +from test import SkipTest +from test import TemplateTest +from test.util import result_lines if beaker_cache.has_beaker: import beaker -from mako.cache import register_plugin, CacheImpl - class SimpleBackend(object): def __init__(self): @@ -43,23 +45,22 @@ class MockCacheImpl(CacheImpl): self.cache = cache def set_backend(self, cache, backend): - if backend == 'simple': + if backend == "simple": self.realcacheimpl = SimpleBackend() else: self.realcacheimpl = cache._load_impl(backend) def _setup_kwargs(self, kw): self.kwargs = kw.copy() - self.kwargs.pop('regions', None) - self.kwargs.pop('manager', None) - if self.kwargs.get('region') != 'myregion': - self.kwargs.pop('region', None) + self.kwargs.pop("regions", None) + self.kwargs.pop("manager", None) + if self.kwargs.get("region") != "myregion": + self.kwargs.pop("region", None) def get_or_create(self, key, creation_function, **kw): self.key = key self._setup_kwargs(kw) - return self.realcacheimpl.\ - get_or_create(key, creation_function, **kw) + return self.realcacheimpl.get_or_create(key, creation_function, **kw) def put(self, key, value, **kw): self.key = key @@ -82,16 +83,17 @@ register_plugin("mock", __name__, "MockCacheImpl") class CacheTest(TemplateTest): - real_backend = 'simple' + real_backend = "simple" def _install_mock_cache(self, template, implname=None): - template.cache_impl = 'mock' + template.cache_impl = "mock" impl = template.cache.impl impl.set_backend(template.cache, implname or self.real_backend) return impl def test_def(self): - t = Template(""" + t = Template( + """ <%! callcount = [0] %> @@ -106,18 +108,20 @@ class CacheTest(TemplateTest): ${foo()} ${foo()} callcount: ${callcount} -""") +""" + ) m = self._install_mock_cache(t) assert result_lines(t.render()) == [ - 'this is foo', - 'this is foo', - 'this is foo', - 'callcount: [1]', + "this is foo", + "this is foo", + "this is foo", + "callcount: [1]", ] assert m.kwargs == {} def test_cache_enable(self): - t = Template(""" + t = Template( + """ <%! callcount = [0] %> @@ -127,13 +131,16 @@ class CacheTest(TemplateTest): ${foo()} ${foo()} callcount: ${callcount} - """, cache_enabled=False) + """, + cache_enabled=False, + ) self._install_mock_cache(t) eq_(t.render().strip(), "callcount: [2]") def test_nested_def(self): - t = Template(""" + t = Template( + """ <%! callcount = [0] %> @@ -151,18 +158,20 @@ class CacheTest(TemplateTest): ${foo()} ${foo()} callcount: ${callcount} -""") +""" + ) m = self._install_mock_cache(t) assert result_lines(t.render()) == [ - 'this is foo', - 'this is foo', - 'this is foo', - 'callcount: [1]', + "this is foo", + "this is foo", + "this is foo", + "callcount: [1]", ] assert m.kwargs == {} def test_page(self): - t = Template(""" + t = Template( + """ <%! callcount = [0] %> @@ -172,85 +181,89 @@ class CacheTest(TemplateTest): callcount[0] += 1 %> callcount: ${callcount} -""") +""" + ) m = self._install_mock_cache(t) t.render() t.render() - assert result_lines(t.render()) == [ - "this is foo", - "callcount: [1]" - ] + assert result_lines(t.render()) == ["this is foo", "callcount: [1]"] assert m.kwargs == {} def test_dynamic_key_with_context(self): - t = Template(""" + t = Template( + """ <%block name="foo" cached="True" cache_key="${mykey}"> some block </%block> - """) + """ + ) m = self._install_mock_cache(t) t.render(mykey="thekey") t.render(mykey="thekey") - eq_( - result_lines(t.render(mykey="thekey")), - ["some block"] - ) + eq_(result_lines(t.render(mykey="thekey")), ["some block"]) eq_(m.key, "thekey") - t = Template(""" + t = Template( + """ <%def name="foo()" cached="True" cache_key="${mykey}"> some def </%def> ${foo()} - """) + """ + ) m = self._install_mock_cache(t) t.render(mykey="thekey") t.render(mykey="thekey") - eq_( - result_lines(t.render(mykey="thekey")), - ["some def"] - ) + eq_(result_lines(t.render(mykey="thekey")), ["some def"]) eq_(m.key, "thekey") def test_dynamic_key_with_funcargs(self): - t = Template(""" + t = Template( + """ <%def name="foo(num=5)" cached="True" cache_key="foo_${str(num)}"> hi </%def> ${foo()} - """) + """ + ) m = self._install_mock_cache(t) t.render() t.render() - assert result_lines(t.render()) == ['hi'] + assert result_lines(t.render()) == ["hi"] assert m.key == "foo_5" - t = Template(""" + t = Template( + """ <%def name="foo(*args, **kwargs)" cached="True" cache_key="foo_${kwargs['bar']}"> hi </%def> ${foo(1, 2, bar='lala')} - """) + """ + ) m = self._install_mock_cache(t) t.render() - assert result_lines(t.render()) == ['hi'] + assert result_lines(t.render()) == ["hi"] assert m.key == "foo_lala" - t = Template(''' + t = Template( + """ <%page args="bar='hi'" cache_key="foo_${bar}" cached="True"/> hi - ''') + """ + ) m = self._install_mock_cache(t) t.render() - assert result_lines(t.render()) == ['hi'] + assert result_lines(t.render()) == ["hi"] assert m.key == "foo_hi" def test_dynamic_key_with_imports(self): lookup = TemplateLookup() - lookup.put_string("foo.html", """ + lookup.put_string( + "foo.html", + """ <%! callcount = [0] %> @@ -261,21 +274,24 @@ class CacheTest(TemplateTest): callcount[0] += 1 %> callcount: ${callcount} -""") +""", + ) lookup.put_string("ns.html", """""") t = lookup.get_template("foo.html") m = self._install_mock_cache(t) - t.render(foo='somekey') - t.render(foo='somekey') - assert result_lines(t.render(foo='somekey')) == [ + t.render(foo="somekey") + t.render(foo="somekey") + assert result_lines(t.render(foo="somekey")) == [ "this is foo", - "callcount: [1]" + "callcount: [1]", ] assert m.kwargs == {} def test_fileargs_implicit(self): l = lookup.TemplateLookup(module_directory=module_base) - l.put_string("test", """ + l.put_string( + "test", + """ <%! callcount = [0] %> @@ -290,19 +306,21 @@ class CacheTest(TemplateTest): ${foo()} ${foo()} callcount: ${callcount} - """) - - m = self._install_mock_cache(l.get_template('test')) - assert result_lines(l.get_template('test').render()) == [ - 'this is foo', - 'this is foo', - 'this is foo', - 'callcount: [1]', + """, + ) + + m = self._install_mock_cache(l.get_template("test")) + assert result_lines(l.get_template("test").render()) == [ + "this is foo", + "this is foo", + "this is foo", + "callcount: [1]", ] - eq_(m.kwargs, {'type': 'dbm'}) + eq_(m.kwargs, {"type": "dbm"}) def test_fileargs_deftag(self): - t = Template(""" + t = Template( + """ <%%! callcount = [0] %%> @@ -317,18 +335,21 @@ class CacheTest(TemplateTest): ${foo()} ${foo()} callcount: ${callcount} -""" % module_base) +""" + % module_base + ) m = self._install_mock_cache(t) assert result_lines(t.render()) == [ - 'this is foo', - 'this is foo', - 'this is foo', - 'callcount: [1]', + "this is foo", + "this is foo", + "this is foo", + "callcount: [1]", ] - assert m.kwargs == {'type': 'file', 'dir': module_base} + assert m.kwargs == {"type": "file", "dir": module_base} def test_fileargs_pagetag(self): - t = Template(""" + t = Template( + """ <%%page cache_dir='%s' cache_type='dbm'/> <%%! callcount = [0] @@ -344,41 +365,51 @@ class CacheTest(TemplateTest): ${foo()} ${foo()} callcount: ${callcount} -""" % module_base) +""" + % module_base + ) m = self._install_mock_cache(t) assert result_lines(t.render()) == [ - 'this is foo', - 'this is foo', - 'this is foo', - 'callcount: [1]', + "this is foo", + "this is foo", + "this is foo", + "callcount: [1]", ] - eq_(m.kwargs, {'dir': module_base, 'type': 'dbm'}) + eq_(m.kwargs, {"dir": module_base, "type": "dbm"}) def test_args_complete(self): - t = Template(""" + t = Template( + """ <%%def name="foo()" cached="True" cache_timeout="30" cache_dir="%s" cache_type="file" cache_key='somekey'> this is foo </%%def> ${foo()} -""" % module_base) +""" + % module_base + ) m = self._install_mock_cache(t) t.render() - eq_(m.kwargs, {'dir': module_base, 'type': 'file', 'timeout': 30}) + eq_(m.kwargs, {"dir": module_base, "type": "file", "timeout": 30}) - t2 = Template(""" + t2 = Template( + """ <%%page cached="True" cache_timeout="30" cache_dir="%s" cache_type="file" cache_key='somekey'/> hi - """ % module_base) + """ + % module_base + ) m = self._install_mock_cache(t2) t2.render() - eq_(m.kwargs, {'dir': module_base, 'type': 'file', 'timeout': 30}) + eq_(m.kwargs, {"dir": module_base, "type": "file", "timeout": 30}) def test_fileargs_lookup(self): - l = lookup.TemplateLookup(cache_dir=module_base, cache_type='file') - l.put_string("test", """ + l = lookup.TemplateLookup(cache_dir=module_base, cache_type="file") + l.put_string( + "test", + """ <%! callcount = [0] %> @@ -393,20 +424,22 @@ class CacheTest(TemplateTest): ${foo()} ${foo()} callcount: ${callcount} - """) + """, + ) - t = l.get_template('test') + t = l.get_template("test") m = self._install_mock_cache(t) - assert result_lines(l.get_template('test').render()) == [ - 'this is foo', - 'this is foo', - 'this is foo', - 'callcount: [1]', + assert result_lines(l.get_template("test").render()) == [ + "this is foo", + "this is foo", + "this is foo", + "callcount: [1]", ] - eq_(m.kwargs, {'dir': module_base, 'type': 'file'}) + eq_(m.kwargs, {"dir": module_base, "type": "file"}) def test_buffered(self): - t = Template(""" + t = Template( + """ <%! def a(text): return "this is a " + text.strip() @@ -416,11 +449,13 @@ class CacheTest(TemplateTest): <%def name="foo()" cached="True" buffered="True"> this is a test </%def> - """, buffer_filters=["a"]) + """, + buffer_filters=["a"], + ) self._install_mock_cache(t) eq_( result_lines(t.render()), - ["this is a this is a test", "this is a this is a test"] + ["this is a this is a test", "this is a this is a test"], ) def test_load_from_expired(self): @@ -428,12 +463,14 @@ class CacheTest(TemplateTest): originating template has completed rendering. """ - t = Template(""" + t = Template( + """ ${foo()} <%def name="foo()" cached="True" cache_timeout="1"> foo </%def> - """) + """ + ) self._install_mock_cache(t) x1 = t.render() @@ -442,7 +479,8 @@ class CacheTest(TemplateTest): assert x1.strip() == x2.strip() == "foo" def test_namespace_access(self): - t = Template(""" + t = Template( + """ <%def name="foo(x)" cached="True"> foo: ${x} </%def> @@ -454,19 +492,20 @@ class CacheTest(TemplateTest): foo(3) foo(4) %> - """) - self._install_mock_cache(t) - eq_( - result_lines(t.render()), - ['foo: 1', 'foo: 1', 'foo: 3', 'foo: 3'] + """ ) + self._install_mock_cache(t) + eq_(result_lines(t.render()), ["foo: 1", "foo: 1", "foo: 3", "foo: 3"]) def test_lookup(self): - l = TemplateLookup(cache_impl='mock') - l.put_string("x", """ + l = TemplateLookup(cache_impl="mock") + l.put_string( + "x", + """ <%page cached="True" /> ${y} - """) + """, + ) t = l.get_template("x") self._install_mock_cache(t) assert result_lines(t.render(y=5)) == ["5"] @@ -474,7 +513,8 @@ class CacheTest(TemplateTest): assert isinstance(t.cache.impl, MockCacheImpl) def test_invalidate(self): - t = Template(""" + t = Template( + """ <%%def name="foo()" cached="True"> foo: ${x} </%%def> @@ -483,20 +523,25 @@ class CacheTest(TemplateTest): bar: ${x} </%%def> ${foo()} ${bar()} - """ % module_base) + """ + % module_base + ) self._install_mock_cache(t) assert result_lines(t.render(x=1)) == ["foo: 1", "bar: 1"] assert result_lines(t.render(x=2)) == ["foo: 1", "bar: 1"] - t.cache.invalidate_def('foo') + t.cache.invalidate_def("foo") assert result_lines(t.render(x=3)) == ["foo: 3", "bar: 1"] - t.cache.invalidate_def('bar') + t.cache.invalidate_def("bar") assert result_lines(t.render(x=4)) == ["foo: 3", "bar: 4"] - t = Template(""" + t = Template( + """ <%%page cached="True" cache_type="dbm" cache_dir="%s"/> page: ${x} - """ % module_base) + """ + % module_base + ) self._install_mock_cache(t) assert result_lines(t.render(x=1)) == ["page: 1"] assert result_lines(t.render(x=2)) == ["page: 1"] @@ -505,66 +550,67 @@ class CacheTest(TemplateTest): assert result_lines(t.render(x=4)) == ["page: 3"] def test_custom_args_def(self): - t = Template(""" + t = Template( + """ <%def name="foo()" cached="True" cache_region="myregion" cache_timeout="50" cache_foo="foob"> </%def> ${foo()} - """) - m = self._install_mock_cache(t, 'simple') + """ + ) + m = self._install_mock_cache(t, "simple") t.render() - eq_( - m.kwargs, - {'region': 'myregion', - 'timeout': 50, 'foo': 'foob'}) + eq_(m.kwargs, {"region": "myregion", "timeout": 50, "foo": "foob"}) def test_custom_args_block(self): - t = Template(""" + t = Template( + """ <%block name="foo" cached="True" cache_region="myregion" cache_timeout="50" cache_foo="foob"> </%block> - """) + """ + ) m = self._install_mock_cache(t, "simple") t.render() - eq_( - m.kwargs, - {'region': 'myregion', - 'timeout': 50, 'foo': 'foob'}) + eq_(m.kwargs, {"region": "myregion", "timeout": 50, "foo": "foob"}) def test_custom_args_page(self): - t = Template(""" + t = Template( + """ <%page cached="True" cache_region="myregion" cache_timeout="50" cache_foo="foob"/> - """) + """ + ) m = self._install_mock_cache(t, "simple") t.render() - eq_( - m.kwargs, - {'region': 'myregion', - 'timeout': 50, 'foo': 'foob'}) + eq_(m.kwargs, {"region": "myregion", "timeout": 50, "foo": "foob"}) def test_pass_context(self): - t = Template(""" + t = Template( + """ <%page cached="True"/> - """) + """ + ) m = self._install_mock_cache(t) t.render() - assert 'context' not in m.kwargs + assert "context" not in m.kwargs m.pass_context = True t.render(x="bar") - assert 'context' in m.kwargs - assert m.kwargs['context'].get('x') == 'bar' + assert "context" in m.kwargs + assert m.kwargs["context"].get("x") == "bar" class RealBackendTest(object): def test_cache_uses_current_context(self): - t = Template(""" + t = Template( + """ ${foo()} <%def name="foo()" cached="True" cache_timeout="1"> foo: ${x} </%def> - """) + """ + ) self._install_mock_cache(t) x1 = t.render(x=1) @@ -585,7 +631,8 @@ class RealBackendTest(object): <%block name="lala"> none ${x} </%block> - """) + """ + ) self._install_mock_cache(t) r1 = result_lines(t.render(x=5)) @@ -598,7 +645,7 @@ class RealBackendTest(object): class BeakerCacheTest(RealBackendTest, CacheTest): - real_backend = 'beaker' + real_backend = "beaker" def setUp(self): if not beaker_cache.has_beaker: @@ -607,28 +654,23 @@ class BeakerCacheTest(RealBackendTest, CacheTest): raise SkipTest("newer beakers not working w/ py26") def _install_mock_cache(self, template, implname=None): - template.cache_args['manager'] = self._regions() + template.cache_args["manager"] = self._regions() impl = super(BeakerCacheTest, self)._install_mock_cache( - template, implname) + template, implname + ) return impl def _regions(self): return beaker.cache.CacheManager( cache_regions={ - 'short': { - 'expire': 1, - 'type': 'memory' - }, - 'long': { - 'expire': 60, - 'type': 'memory' - } + "short": {"expire": 1, "type": "memory"}, + "long": {"expire": 60, "type": "memory"}, } ) class DogpileCacheTest(RealBackendTest, CacheTest): - real_backend = 'dogpile.cache' + real_backend = "dogpile.cache" def setUp(self): try: @@ -637,10 +679,11 @@ class DogpileCacheTest(RealBackendTest, CacheTest): raise SkipTest("dogpile.cache is required to run these tests") def _install_mock_cache(self, template, implname=None): - template.cache_args['regions'] = self._regions() - template.cache_args.setdefault('region', 'short') + template.cache_args["regions"] = self._regions() + template.cache_args.setdefault("region", "short") impl = super(DogpileCacheTest, self)._install_mock_cache( - template, implname) + template, implname + ) return impl def _regions(self): @@ -648,17 +691,14 @@ class DogpileCacheTest(RealBackendTest, CacheTest): my_regions = { "short": make_region().configure( - "dogpile.cache.memory", - expiration_time=1 + "dogpile.cache.memory", expiration_time=1 ), "long": make_region().configure( - "dogpile.cache.memory", - expiration_time=60 + "dogpile.cache.memory", expiration_time=60 ), "myregion": make_region().configure( - "dogpile.cache.memory", - expiration_time=60 - ) + "dogpile.cache.memory", expiration_time=60 + ), } return my_regions diff --git a/test/test_call.py b/test/test_call.py index 5071222..36d15dc 100644 --- a/test/test_call.py +++ b/test/test_call.py @@ -1,11 +1,14 @@ from mako.template import Template -from mako import util -from test.util import result_lines, flatten_result -from test import TemplateTest, eq_ +from test import eq_ +from test import TemplateTest +from test.util import flatten_result +from test.util import result_lines + class CallTest(TemplateTest): def test_call(self): - t = Template(""" + t = Template( + """ <%def name="foo()"> hi im foo ${caller.body(y=5)} </%def> @@ -13,12 +16,16 @@ class CallTest(TemplateTest): <%call expr="foo()" args="y, **kwargs"> this is the body, y is ${y} </%call> -""") - assert result_lines(t.render()) == ['hi im foo', 'this is the body, y is 5'] - +""" + ) + assert result_lines(t.render()) == [ + "hi im foo", + "this is the body, y is 5", + ] def test_compound_call(self): - t = Template(""" + t = Template( + """ <%def name="bar()"> this is bar @@ -41,16 +48,26 @@ class CallTest(TemplateTest): </%call> ${bar()} -""") - assert result_lines(t.render()) == ['foo calling comp1:', 'this is comp1, 5', 'foo calling body:', 'this is the body,', 'this is comp1, 6', 'this is bar'] +""" + ) + assert result_lines(t.render()) == [ + "foo calling comp1:", + "this is comp1, 5", + "foo calling body:", + "this is the body,", + "this is comp1, 6", + "this is bar", + ] def test_new_syntax(self): - """test foo:bar syntax, including multiline args and expression eval.""" + """test foo:bar syntax, including multiline args and expression + eval.""" # note the trailing whitespace in the bottom ${} expr, need to strip # that off < python 2.7 - t = Template(""" + t = Template( + """ <%def name="foo(x, y, q, z)"> ${x} ${y} @@ -70,15 +87,17 @@ class CallTest(TemplateTest): ] }"/> - """) + """ + ) eq_( result_lines(t.render()), - ['this is x', 'some y', 'this', 'is', 'q', '1->2,3->4,5->6'] + ["this is x", "some y", "this", "is", "q", "1->2,3->4,5->6"], ) def test_ccall_caller(self): - t = Template(""" + t = Template( + """ <%def name="outer_func()"> OUTER BEGIN <%call expr="caller.inner_func()"> @@ -95,8 +114,9 @@ class CallTest(TemplateTest): </%def> </%call> - """) - #print t.code + """ + ) + # print t.code assert result_lines(t.render()) == [ "OUTER BEGIN", "INNER BEGIN", @@ -106,7 +126,8 @@ class CallTest(TemplateTest): ] def test_stack_pop(self): - t = Template(""" + t = Template( + """ <%def name="links()" buffered="True"> Some links </%def> @@ -122,19 +143,22 @@ class CallTest(TemplateTest): Some title </%call> - """) + """ + ) assert result_lines(t.render()) == [ - "<h1>", - "Some title", - "</h1>", - "Some links" + "<h1>", + "Some title", + "</h1>", + "Some links", ] def test_conditional_call(self): - """test that 'caller' is non-None only if the immediate <%def> was called via <%call>""" + """test that 'caller' is non-None only if the immediate <%def> was + called via <%call>""" - t = Template(""" + t = Template( + """ <%def name="a()"> % if caller: ${ caller.body() } \\ @@ -162,17 +186,14 @@ class CallTest(TemplateTest): CALL </%call> - """) - assert result_lines(t.render()) == [ - "CALL", - "AAA", - "BBB", - "CCC" - ] + """ + ) + assert result_lines(t.render()) == ["CALL", "AAA", "BBB", "CCC"] def test_chained_call(self): """test %calls that are chained through their targets""" - t = Template(""" + t = Template( + """ <%def name="a()"> this is a. <%call expr="b()"> @@ -189,19 +210,21 @@ class CallTest(TemplateTest): heres the main templ call </%call> -""") +""" + ) assert result_lines(t.render()) == [ - 'this is a.', - 'this is b. heres my body:', + "this is a.", + "this is b. heres my body:", "this is a's ccall. heres my body:", - 'heres the main templ call', + "heres the main templ call", "whats in the body's caller's body ?", - 'heres the main templ call' + "heres the main templ call", ] def test_nested_call(self): """test %calls that are nested inside each other""" - t = Template(""" + t = Template( + """ <%def name="foo()"> ${caller.body(x=10)} </%def> @@ -218,16 +241,18 @@ class CallTest(TemplateTest): this is bar body: ${x} </%call> </%call> -""") +""" + ) assert result_lines(t.render(x=5)) == [ "x is 5", "this is foo body: 10", "bar:", - "this is bar body: 10" + "this is bar body: 10", ] def test_nested_call_2(self): - t = Template(""" + t = Template( + """ x is ${x} <%def name="foo()"> ${caller.foosub(x=10)} @@ -250,16 +275,18 @@ class CallTest(TemplateTest): </%def> </%call> -""") +""" + ) assert result_lines(t.render(x=5)) == [ "x is 5", "this is foo body: 10", "bar:", - "this is bar body: 10" + "this is bar body: 10", ] def test_nested_call_3(self): - template = Template('''\ + template = Template( + """\ <%def name="A()"> ${caller.body()} </%def> @@ -276,7 +303,8 @@ class CallTest(TemplateTest): </%call> </%call> - ''') + """ + ) assert flatten_result(template.render()) == "foo" def test_nested_call_4(self): @@ -292,7 +320,9 @@ class CallTest(TemplateTest): </%def> """ - template = Template(base + """ + template = Template( + base + + """ <%def name="C()"> C_def <%self:B> @@ -307,14 +337,17 @@ class CallTest(TemplateTest): <%self:C> C_body </%self:C> - """) + """ + ) eq_( flatten_result(template.render()), - "C_def B_def A_def A_body B_body C_body" + "C_def B_def A_def A_body B_body C_body", ) - template = Template(base + """ + template = Template( + base + + """ <%def name="C()"> C_def <%self:B> @@ -329,15 +362,17 @@ class CallTest(TemplateTest): <%self:C> C_body </%self:C> - """) + """ + ) eq_( flatten_result(template.render()), - "C_def B_def B_body C_body A_def A_body" + "C_def B_def B_body C_body A_def A_body", ) def test_chained_call_in_nested(self): - t = Template(""" + t = Template( + """ <%def name="embedded()"> <%def name="a()"> this is a. @@ -347,7 +382,8 @@ class CallTest(TemplateTest): </%def> <%def name="b()"> this is b. heres my body: ${caller.body()} - whats in the body's caller's body ? ${context.caller_stack[-2].body()} + whats in the body's caller's body ? """ + """${context.caller_stack[-2].body()} </%def> <%call expr="a()"> @@ -355,20 +391,22 @@ class CallTest(TemplateTest): </%call> </%def> ${embedded()} -""") - #print t.code - #print result_lines(t.render()) +""" + ) + # print t.code + # print result_lines(t.render()) assert result_lines(t.render()) == [ - 'this is a.', - 'this is b. heres my body:', + "this is a.", + "this is b. heres my body:", "this is a's ccall. heres my body:", - 'heres the main templ call', + "heres the main templ call", "whats in the body's caller's body ?", - 'heres the main templ call' + "heres the main templ call", ] def test_call_in_nested(self): - t = Template(""" + t = Template( + """ <%def name="a()"> this is a ${b()} <%def name="b()"> @@ -382,22 +420,31 @@ class CallTest(TemplateTest): </%def> </%def> ${a()} -""") - assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call"] +""" + ) + assert result_lines(t.render()) == [ + "this is a", + "this is b", + "this is c:", + "this is the body in b's call", + ] def test_composed_def(self): - t = Template(""" + t = Template( + """ <%def name="f()"><f>${caller.body()}</f></%def> <%def name="g()"><g>${caller.body()}</g></%def> <%def name="fg()"> <%self:f><%self:g>${caller.body()}</%self:g></%self:f> </%def> <%self:fg>fgbody</%self:fg> - """) - assert result_lines(t.render()) == ['<f><g>fgbody</g></f>'] + """ + ) + assert result_lines(t.render()) == ["<f><g>fgbody</g></f>"] def test_regular_defs(self): - t = Template(""" + t = Template( + """ <%! @runtime.supports_caller def a(context): @@ -430,7 +477,8 @@ class CallTest(TemplateTest): </%call> - """) + """ + ) assert result_lines(t.render()) == [ "test 1", "this is a", @@ -449,11 +497,12 @@ class CallTest(TemplateTest): "our body:", "this is the nested body", "this is aa is done", - "this is aa is done" + "this is aa is done", ] def test_call_in_nested_2(self): - t = Template(""" + t = Template( + """ <%def name="a()"> <%def name="d()"> not this d @@ -477,14 +526,24 @@ class CallTest(TemplateTest): </%def> </%def> ${a()} -""") - assert result_lines(t.render()) == ['this is a', 'this is b', 'this is c:', "this is the body in b's call", 'the embedded "d" is:', 'this is d'] +""" + ) + assert result_lines(t.render()) == [ + "this is a", + "this is b", + "this is c:", + "this is the body in b's call", + 'the embedded "d" is:', + "this is d", + ] + class SelfCacheTest(TemplateTest): """this test uses a now non-public API.""" def test_basic(self): - t = Template(""" + t = Template( + """ <%! cached = None %> @@ -505,10 +564,10 @@ class SelfCacheTest(TemplateTest): ${foo()} ${foo()} -""") +""" + ) assert result_lines(t.render()) == [ "this is foo", "cached:", - "this is foo" + "this is foo", ] - diff --git a/test/test_cmd.py b/test/test_cmd.py index a2adbf9..ac0db25 100644 --- a/test/test_cmd.py +++ b/test/test_cmd.py @@ -1,8 +1,15 @@ from __future__ import with_statement + from contextlib import contextmanager -from test import TemplateTest, eq_, raises, template_base, mock import os + from mako.cmd import cmdline +from test import eq_ +from test import mock +from test import raises +from test import template_base +from test import TemplateTest + class CmdTest(TemplateTest): @contextmanager @@ -12,27 +19,31 @@ class CmdTest(TemplateTest): def test_stdin_success(self): with self._capture_output_fixture() as stdout: - with mock.patch("sys.stdin", mock.Mock( - read=mock.Mock(return_value="hello world ${x}"))): + with mock.patch( + "sys.stdin", + mock.Mock(read=mock.Mock(return_value="hello world ${x}")), + ): cmdline(["--var", "x=5", "-"]) eq_(stdout.write.mock_calls[0][1][0], "hello world 5") def test_stdin_syntax_err(self): - with mock.patch("sys.stdin", mock.Mock( - read=mock.Mock(return_value="${x"))): + with mock.patch( + "sys.stdin", mock.Mock(read=mock.Mock(return_value="${x")) + ): with self._capture_output_fixture("stderr") as stderr: with raises(SystemExit): cmdline(["--var", "x=5", "-"]) - assert "SyntaxException: Expected" in \ - stderr.write.mock_calls[0][1][0] + assert ( + "SyntaxException: Expected" in stderr.write.mock_calls[0][1][0] + ) assert "Traceback" in stderr.write.mock_calls[0][1][0] - def test_stdin_rt_err(self): - with mock.patch("sys.stdin", mock.Mock( - read=mock.Mock(return_value="${q}"))): + with mock.patch( + "sys.stdin", mock.Mock(read=mock.Mock(return_value="${q}")) + ): with self._capture_output_fixture("stderr") as stderr: with raises(SystemExit): cmdline(["--var", "x=5", "-"]) @@ -42,16 +53,22 @@ class CmdTest(TemplateTest): def test_file_success(self): with self._capture_output_fixture() as stdout: - cmdline(["--var", "x=5", - os.path.join(template_base, "cmd_good.mako")]) + cmdline( + ["--var", "x=5", os.path.join(template_base, "cmd_good.mako")] + ) eq_(stdout.write.mock_calls[0][1][0], "hello world 5") def test_file_syntax_err(self): with self._capture_output_fixture("stderr") as stderr: with raises(SystemExit): - cmdline(["--var", "x=5", - os.path.join(template_base, "cmd_syntax.mako")]) + cmdline( + [ + "--var", + "x=5", + os.path.join(template_base, "cmd_syntax.mako"), + ] + ) assert "SyntaxException: Expected" in stderr.write.mock_calls[0][1][0] assert "Traceback" in stderr.write.mock_calls[0][1][0] @@ -59,14 +76,17 @@ class CmdTest(TemplateTest): def test_file_rt_err(self): with self._capture_output_fixture("stderr") as stderr: with raises(SystemExit): - cmdline(["--var", "x=5", - os.path.join(template_base, "cmd_runtime.mako")]) + cmdline( + [ + "--var", + "x=5", + os.path.join(template_base, "cmd_runtime.mako"), + ] + ) assert "NameError: Undefined" in stderr.write.mock_calls[0][1][0] assert "Traceback" in stderr.write.mock_calls[0][1][0] - def test_file_notfound(self): with raises(SystemExit, "error: can't find fake.lalala"): cmdline(["--var", "x=5", "fake.lalala"]) - diff --git a/test/test_decorators.py b/test/test_decorators.py index a3fa8f5..195a636 100644 --- a/test/test_decorators.py +++ b/test/test_decorators.py @@ -1,15 +1,18 @@ -from mako.template import Template -from mako import lookup import unittest -from test.util import flatten_result, result_lines + +from mako.template import Template +from test.util import flatten_result + class DecoratorTest(unittest.TestCase): def test_toplevel(self): - template = Template(""" + template = Template( + """ <%! def bar(fn): def decorate(context, *args, **kw): - return "BAR" + runtime.capture(context, fn, *args, **kw) + "BAR" + return "BAR" + runtime.capture""" + """(context, fn, *args, **kw) + "BAR" return decorate %> @@ -18,12 +21,14 @@ class DecoratorTest(unittest.TestCase): </%def> ${foo(1, x=5)} - """) + """ + ) assert flatten_result(template.render()) == "BAR this is foo 1 5 BAR" def test_toplevel_contextual(self): - template = Template(""" + template = Template( + """ <%! def bar(fn): def decorate(context): @@ -39,15 +44,19 @@ class DecoratorTest(unittest.TestCase): </%def> ${foo()} - """) + """ + ) assert flatten_result(template.render()) == "BAR this is foo BAR" - assert flatten_result(template.get_def('foo').render()) == "BAR this is foo BAR" - + assert ( + flatten_result(template.get_def("foo").render()) + == "BAR this is foo BAR" + ) def test_nested(self): - template = Template(""" + template = Template( + """ <%! def bat(fn): def decorate(context): @@ -64,16 +73,19 @@ class DecoratorTest(unittest.TestCase): </%def> ${foo()} - """) + """ + ) assert flatten_result(template.render()) == "BAT this is bar BAT" def test_toplevel_decorated_name(self): - template = Template(""" + template = Template( + """ <%! def bar(fn): def decorate(context, *args, **kw): - return "function " + fn.__name__ + " " + runtime.capture(context, fn, *args, **kw) + return "function " + fn.__name__ + """ + """" " + runtime.capture(context, fn, *args, **kw) return decorate %> @@ -82,16 +94,21 @@ class DecoratorTest(unittest.TestCase): </%def> ${foo(1, x=5)} - """) + """ + ) - assert flatten_result(template.render()) == "function foo this is foo 1 5" + assert ( + flatten_result(template.render()) == "function foo this is foo 1 5" + ) def test_nested_decorated_name(self): - template = Template(""" + template = Template( + """ <%! def bat(fn): def decorate(context): - return "function " + fn.__name__ + " " + runtime.capture(context, fn) + return "function " + fn.__name__ + " " + """ + """runtime.capture(context, fn) return decorate %> @@ -104,7 +121,7 @@ class DecoratorTest(unittest.TestCase): </%def> ${foo()} - """) + """ + ) assert flatten_result(template.render()) == "function bar this is bar" - diff --git a/test/test_def.py b/test/test_def.py index 19142c8..99b929d 100644 --- a/test/test_def.py +++ b/test/test_def.py @@ -1,13 +1,18 @@ -from mako.template import Template +from mako import compat from mako import lookup +from mako.template import Template +from test import assert_raises +from test import eq_ +from test import requires_python_3 from test import TemplateTest -from test.util import flatten_result, result_lines -from test import eq_, assert_raises, requires_python_3 -from mako import compat +from test.util import flatten_result +from test.util import result_lines + class DefTest(TemplateTest): def test_def_noargs(self): - template = Template(""" + template = Template( + """ ${mycomp()} @@ -15,52 +20,55 @@ class DefTest(TemplateTest): hello mycomp ${variable} </%def> - """) - eq_( - template.render(variable='hi').strip(), - """hello mycomp hi""" + """ ) + eq_(template.render(variable="hi").strip(), """hello mycomp hi""") def test_def_blankargs(self): - template = Template(""" + template = Template( + """ <%def name="mycomp()"> hello mycomp ${variable} </%def> - ${mycomp()}""") - eq_( - template.render(variable='hi').strip(), - "hello mycomp hi" + ${mycomp()}""" ) + eq_(template.render(variable="hi").strip(), "hello mycomp hi") def test_def_args(self): - template = Template(""" + template = Template( + """ <%def name="mycomp(a, b)"> hello mycomp ${variable}, ${a}, ${b} </%def> - ${mycomp(5, 6)}""") + ${mycomp(5, 6)}""" + ) eq_( - template.render(variable='hi', a=5, b=6).strip(), - """hello mycomp hi, 5, 6""" + template.render(variable="hi", a=5, b=6).strip(), + """hello mycomp hi, 5, 6""", ) @requires_python_3 def test_def_py3k_args(self): - template = Template(""" + template = Template( + """ <%def name="kwonly(one, two, *three, four, five=5, **six)"> - look at all these args: ${one} ${two} ${three[0]} ${four} ${five} ${six['seven']} + look at all these args: ${one} ${two} ${three[0]} """ + """${four} ${five} ${six['seven']} </%def> - ${kwonly('one', 'two', 'three', four='four', seven='seven')}""") + ${kwonly('one', 'two', 'three', four='four', seven='seven')}""" + ) eq_( template.render(one=1, two=2, three=(3,), six=6).strip(), - """look at all these args: one two three four 5 seven""" + """look at all these args: one two three four 5 seven""", ) def test_inter_def(self): """test defs calling each other""" - template = Template(""" + template = Template( + """ ${b()} <%def name="a()">\ @@ -75,7 +83,8 @@ class DefTest(TemplateTest): <%def name="c()"> im c </%def> -""") +""" + ) # check that "a" is declared in "b", but not in "c" if compat.py3k: assert "a" not in template.module.render_c.__code__.co_varnames @@ -85,15 +94,13 @@ class DefTest(TemplateTest): assert "a" in template.module.render_b.func_code.co_varnames # then test output - eq_( - flatten_result(template.render()), - "im b and heres a: im a" - ) + eq_(flatten_result(template.render()), "im b and heres a: im a") def test_toplevel(self): """test calling a def from the top level""" - template = Template(""" + template = Template( + """ this is the body @@ -105,28 +112,37 @@ class DefTest(TemplateTest): this is b, ${x} ${y} </%def> - """) + """ + ) - self._do_test(template.get_def("a"), - "this is a", - filters=flatten_result) - self._do_test(template.get_def("b"), - "this is b, 10 15", - template_args={'x': 10, 'y': 15}, - filters=flatten_result) - self._do_test(template.get_def("body"), - "this is the body", - filters=flatten_result) + self._do_test( + template.get_def("a"), "this is a", filters=flatten_result + ) + self._do_test( + template.get_def("b"), + "this is b, 10 15", + template_args={"x": 10, "y": 15}, + filters=flatten_result, + ) + self._do_test( + template.get_def("body"), + "this is the body", + filters=flatten_result, + ) # test that args outside of the dict can be used - self._do_test(template.get_def("a"), "this is a", - filters=flatten_result, - template_args={'q': 5, 'zq': 'test'}) + self._do_test( + template.get_def("a"), + "this is a", + filters=flatten_result, + template_args={"q": 5, "zq": "test"}, + ) def test_def_operations(self): """test get/list/has def""" - template = Template(""" + template = Template( + """ this is the body @@ -138,14 +154,12 @@ class DefTest(TemplateTest): this is b, ${x} ${y} </%def> - """) + """ + ) assert template.get_def("a") assert template.get_def("b") - assert_raises(AttributeError, - template.get_def, - ("c") - ) + assert_raises(AttributeError, template.get_def, ("c")) assert template.has_def("a") assert template.has_def("b") @@ -163,7 +177,8 @@ class ScopeTest(TemplateTest): scope always takes precedence over contextual scope.""" def test_scope_one(self): - self._do_memory_test(""" + self._do_memory_test( + """ <%def name="a()"> this is a, and y is ${y} </%def> @@ -179,11 +194,12 @@ class ScopeTest(TemplateTest): """, "this is a, and y is None this is a, and y is 7", filters=flatten_result, - template_args={'y': None} + template_args={"y": None}, ) def test_scope_two(self): - t = Template(""" + t = Template( + """ y is ${y} <% @@ -191,7 +207,8 @@ class ScopeTest(TemplateTest): %> y is ${y} -""") +""" + ) try: t.render(y=None) assert False @@ -201,7 +218,8 @@ class ScopeTest(TemplateTest): def test_scope_four(self): """test that variables are pulled from 'enclosing' scope before context.""" - t = Template(""" + t = Template( + """ <% x = 5 %> @@ -218,17 +236,19 @@ class ScopeTest(TemplateTest): </%def> ${b()} -""") +""" + ) eq_( flatten_result(t.render()), - "this is b. x is 9. calling a. this is a. x is 5." + "this is b. x is 9. calling a. this is a. x is 5.", ) def test_scope_five(self): """test that variables are pulled from 'enclosing' scope before context.""" # same as test four, but adds a scope around it. - t = Template(""" + t = Template( + """ <%def name="enclosing()"> <% x = 5 @@ -248,16 +268,18 @@ class ScopeTest(TemplateTest): ${b()} </%def> ${enclosing()} -""") +""" + ) eq_( flatten_result(t.render()), - "this is b. x is 9. calling a. this is a. x is 5." + "this is b. x is 9. calling a. this is a. x is 5.", ) def test_scope_six(self): """test that the initial context counts as 'enclosing' scope, for plain defs""" - t = Template(""" + t = Template( + """ <%def name="a()"> a: x is ${x} @@ -271,16 +293,15 @@ class ScopeTest(TemplateTest): </%def> ${b()} - """) - eq_( - flatten_result(t.render(x=5)), - "b. x is 10. a: x is 5" + """ ) + eq_(flatten_result(t.render(x=5)), "b. x is 10. a: x is 5") def test_scope_seven(self): """test that the initial context counts as 'enclosing' scope, for nested defs""" - t = Template(""" + t = Template( + """ <%def name="enclosing()"> <%def name="a()"> a: x is ${x} @@ -296,16 +317,15 @@ class ScopeTest(TemplateTest): ${b()} </%def> ${enclosing()} - """) - eq_( - flatten_result(t.render(x=5)), - "b. x is 10. a: x is 5" + """ ) + eq_(flatten_result(t.render(x=5)), "b. x is 10. a: x is 5") def test_scope_eight(self): """test that the initial context counts as 'enclosing' scope, for nested defs""" - t = Template(""" + t = Template( + """ <%def name="enclosing()"> <%def name="a()"> a: x is ${x} @@ -322,35 +342,40 @@ class ScopeTest(TemplateTest): ${b()} </%def> ${enclosing()} - """) - eq_( - flatten_result(t.render(x=5)), - "b. x is 10. a: x is 5" + """ ) + eq_(flatten_result(t.render(x=5)), "b. x is 10. a: x is 5") def test_scope_nine(self): """test that 'enclosing scope' doesnt get exported to other templates""" l = lookup.TemplateLookup() - l.put_string('main', """ + l.put_string( + "main", + """ <% x = 5 %> this is main. <%include file="secondary"/> -""") +""", + ) - l.put_string('secondary', """ + l.put_string( + "secondary", + """ this is secondary. x is ${x} -""") +""", + ) eq_( - flatten_result(l.get_template('main').render(x=2)), - "this is main. this is secondary. x is 2" + flatten_result(l.get_template("main").render(x=2)), + "this is main. this is secondary. x is 2", ) def test_scope_ten(self): - t = Template(""" + t = Template( + """ <%def name="a()"> <%def name="b()"> <% @@ -378,14 +403,16 @@ class ScopeTest(TemplateTest): %> main/a: ${a()} main/y: ${y} - """) + """ + ) eq_( flatten_result(t.render()), - "main/a: a/y: 10 a/b: b/c: c/y: 10 b/y: 19 main/y: 7" + "main/a: a/y: 10 a/b: b/c: c/y: 10 b/y: 19 main/y: 7", ) def test_scope_eleven(self): - t = Template(""" + t = Template( + """ x is ${x} <%def name="a(x)"> this is a, ${b()} @@ -395,17 +422,16 @@ class ScopeTest(TemplateTest): </%def> ${a(x=5)} -""") +""" + ) eq_( result_lines(t.render(x=10)), - [ - "x is 10", - "this is a,", - "this is b, x is 5" - ]) + ["x is 10", "this is a,", "this is b, x is 5"], + ) def test_unbound_scope(self): - t = Template(""" + t = Template( + """ <% y = 10 %> @@ -418,14 +444,13 @@ class ScopeTest(TemplateTest): y is ${y} </%def> ${a()} -""") - assert_raises( - UnboundLocalError, - t.render - ) +""" + ) + assert_raises(UnboundLocalError, t.render) def test_unbound_scope_two(self): - t = Template(""" + t = Template( + """ <%def name="enclosing()"> <% y = 10 @@ -441,7 +466,8 @@ class ScopeTest(TemplateTest): ${a()} </%def> ${enclosing()} -""") +""" + ) try: print(t.render()) assert False @@ -452,13 +478,18 @@ class ScopeTest(TemplateTest): """test that arguments passed to the body() function are accessible by top-level defs""" l = lookup.TemplateLookup() - l.put_string("base", """ + l.put_string( + "base", + """ ${next.body(x=12)} - """) + """, + ) - l.put_string("main", """ + l.put_string( + "main", + """ <%inherit file="base"/> <%page args="x"/> this is main. x is ${x} @@ -468,28 +499,28 @@ class ScopeTest(TemplateTest): <%def name="a(**args)"> this is a, x is ${x} </%def> - """) + """, + ) # test via inheritance eq_( result_lines(l.get_template("main").render()), - [ - "this is main. x is 12", - "this is a, x is 12" - ]) + ["this is main. x is 12", "this is a, x is 12"], + ) - l.put_string("another", """ + l.put_string( + "another", + """ <%namespace name="ns" file="main"/> ${ns.body(x=15)} - """) + """, + ) # test via namespace eq_( result_lines(l.get_template("another").render()), - [ - "this is main. x is 15", - "this is a, x is 15" - ]) + ["this is main. x is 15", "this is a, x is 15"], + ) def test_inline_expression_from_arg_one(self): """test that cache_key=${foo} gets its value from @@ -499,20 +530,20 @@ class ScopeTest(TemplateTest): this is #191. """ - t = Template(""" + t = Template( + """ <%def name="layout(foo)" cached="True" cache_key="${foo}"> foo: ${foo} </%def> ${layout(3)} - """, strict_undefined=True, - cache_impl="plain") - - eq_( - result_lines(t.render()), - ["foo: 3"] + """, + strict_undefined=True, + cache_impl="plain", ) + eq_(result_lines(t.render()), ["foo: 3"]) + def test_interpret_expression_from_arg_two(self): """test that cache_key=${foo} gets its value from the 'foo' argument regardless of it being passed @@ -522,26 +553,25 @@ class ScopeTest(TemplateTest): to existing behavior before and after #191. """ - t = Template(""" + t = Template( + """ <%def name="layout(foo)" cached="True" cache_key="${foo}"> foo: ${value} </%def> ${layout(3)} - """, cache_impl="plain") - - eq_( - result_lines(t.render(foo='foo', value=1)), - ["foo: 1"] - ) - eq_( - result_lines(t.render(foo='bar', value=2)), - ["foo: 1"] + """, + cache_impl="plain", ) + eq_(result_lines(t.render(foo="foo", value=1)), ["foo: 1"]) + eq_(result_lines(t.render(foo="bar", value=2)), ["foo: 1"]) + + class NestedDefTest(TemplateTest): def test_nested_def(self): - t = Template(""" + t = Template( + """ ${hi()} @@ -557,14 +587,16 @@ class NestedDefTest(TemplateTest): this is bar </%def> </%def> -""") +""" + ) eq_( flatten_result(t.render()), - "hey, im hi. and heres this is foo , this is bar" + "hey, im hi. and heres this is foo , this is bar", ) def test_nested_2(self): - t = Template(""" + t = Template( + """ x is ${x} <%def name="a()"> this is a, x is ${x} @@ -574,15 +606,17 @@ class NestedDefTest(TemplateTest): </%def> </%def> ${a()} -""") +""" + ) eq_( flatten_result(t.render(x=10)), - "x is 10 this is a, x is 10 this is b: 10" + "x is 10 this is a, x is 10 this is b: 10", ) def test_nested_with_args(self): - t = Template(""" + t = Template( + """ ${a()} <%def name="a()"> <%def name="b(x, y=2)"> @@ -590,14 +624,13 @@ class NestedDefTest(TemplateTest): </%def> a ${b(5)} </%def> -""") - eq_( - flatten_result(t.render()), - "a b x is 5 y is 2" +""" ) + eq_(flatten_result(t.render()), "a b x is 5 y is 2") def test_nested_def_2(self): - template = Template(""" + template = Template( + """ ${a()} <%def name="a()"> <%def name="b()"> @@ -608,14 +641,13 @@ class NestedDefTest(TemplateTest): </%def> ${b()} </%def> -""") - eq_( - flatten_result(template.render()), - "comp c" +""" ) + eq_(flatten_result(template.render()), "comp c") def test_nested_nested_def(self): - t = Template(""" + t = Template( + """ ${a()} <%def name="a()"> @@ -648,16 +680,18 @@ class NestedDefTest(TemplateTest): ${b1()} ${b2()} ${b3()} </%def> -""") +""" + ) eq_( flatten_result(t.render(x=5, y=None)), "a a_b1 a_b2 a_b2_c1 a_b3 a_b3_c1 " "heres x: 5 y is 7 a_b3_c2 y is " - "None c1 is a_b3_c1 heres x: 5 y is 7" + "None c1 is a_b3_c1 heres x: 5 y is 7", ) def test_nested_nested_def_2(self): - t = Template(""" + t = Template( + """ <%def name="a()"> this is a ${b()} <%def name="b()"> @@ -670,14 +704,13 @@ class NestedDefTest(TemplateTest): </%def> </%def> ${a()} -""") - eq_( - flatten_result(t.render()), - "this is a this is b this is c" +""" ) + eq_(flatten_result(t.render()), "this is a this is b this is c") def test_outer_scope(self): - t = Template(""" + t = Template( + """ <%def name="a()"> a: x is ${x} </%def> @@ -696,36 +729,34 @@ class NestedDefTest(TemplateTest): ${b()} x is ${x} -""") - eq_( - flatten_result(t.render(x=5)), - "b. c. x is 10. a: x is 5 x is 5" +""" ) + eq_(flatten_result(t.render(x=5)), "b. c. x is 10. a: x is 5 x is 5") + class ExceptionTest(TemplateTest): def test_raise(self): - template = Template(""" + template = Template( + """ <% raise Exception("this is a test") %> - """, format_exceptions=False) - assert_raises( - Exception, - template.render - ) + """, + format_exceptions=False, + ) + assert_raises(Exception, template.render) def test_handler(self): def handle(context, error): context.write("error message is " + str(error)) return True - template = Template(""" + template = Template( + """ <% raise Exception("this is a test") %> - """, error_handler=handle) - eq_( - template.render().strip(), - "error message is this is a test" + """, + error_handler=handle, ) - + eq_(template.render().strip(), "error message is this is a test") diff --git a/test/test_exceptions.py b/test/test_exceptions.py index 242577f..c680591 100644 --- a/test/test_exceptions.py +++ b/test/test_exceptions.py @@ -1,13 +1,16 @@ # -*- coding: utf-8 -*- import sys -from mako import exceptions, compat -from mako.template import Template -from mako.lookup import TemplateLookup +from mako import compat +from mako import exceptions from mako.compat import u -from test.util import result_lines +from mako.lookup import TemplateLookup +from mako.template import Template +from test import requires_no_pygments_exceptions +from test import requires_pygments_14 from test import TemplateTest -from test import requires_pygments_14, requires_no_pygments_exceptions +from test.util import result_lines + class ExceptionsTest(TemplateTest): def test_html_error_template(self): @@ -21,24 +24,28 @@ class ExceptionsTest(TemplateTest): assert False except exceptions.CompileException: html_error = exceptions.html_error_template().render_unicode() - assert ("CompileException: Fragment 'i = 0' is not " - "a partial control statement at line: 2 char: 1") in html_error - assert '<style>' in html_error + assert ( + "CompileException: Fragment 'i = 0' is not " + "a partial control statement at line: 2 char: 1" + ) in html_error + assert "<style>" in html_error html_error_stripped = html_error.strip() - assert html_error_stripped.startswith('<html>') - assert html_error_stripped.endswith('</html>') + assert html_error_stripped.startswith("<html>") + assert html_error_stripped.endswith("</html>") - not_full = exceptions.html_error_template().\ - render_unicode(full=False) - assert '<html>' not in not_full - assert '<style>' in not_full + not_full = exceptions.html_error_template().render_unicode( + full=False + ) + assert "<html>" not in not_full + assert "<style>" in not_full - no_css = exceptions.html_error_template().\ - render_unicode(css=False) - assert '<style>' not in no_css + no_css = exceptions.html_error_template().render_unicode(css=False) + assert "<style>" not in no_css else: - assert False, ("This function should trigger a CompileException, " - "but didn't") + assert False, ( + "This function should trigger a CompileException, " + "but didn't" + ) def test_text_error_template(self): code = """ @@ -50,9 +57,11 @@ class ExceptionsTest(TemplateTest): assert False except exceptions.CompileException: text_error = exceptions.text_error_template().render_unicode() - assert 'Traceback (most recent call last):' in text_error - assert ("CompileException: Fragment 'i = 0' is not a partial " - "control statement") in text_error + assert "Traceback (most recent call last):" in text_error + assert ( + "CompileException: Fragment 'i = 0' is not a partial " + "control statement" + ) in text_error @requires_pygments_14 def test_utf8_html_error_template_pygments(self): @@ -77,28 +86,40 @@ ${u'привет'} except exceptions.CompileException: html_error = exceptions.html_error_template().render() if compat.py3k: - assert ("CompileException: Fragment 'if 2 == 2: /an " - "error' is not a partial control statement " - "at line: 2 char: 1").encode(sys.getdefaultencoding(), 'htmlentityreplace') in \ - html_error - else: - assert ("CompileException: Fragment 'if 2 == 2: /an " + assert ( + ( + "CompileException: Fragment 'if 2 == 2: /an " "error' is not a partial control statement " - "at line: 2 char: 1") in \ - html_error + "at line: 2 char: 1" + ).encode(sys.getdefaultencoding(), "htmlentityreplace") + in html_error + ) + else: + assert ( + "CompileException: Fragment 'if 2 == 2: /an " + "error' is not a partial control statement " + "at line: 2 char: 1" + ) in html_error if compat.py3k: - assert "".encode(sys.getdefaultencoding(), - 'htmlentityreplace') in html_error + assert ( + "".encode(sys.getdefaultencoding(), "htmlentityreplace") + in html_error + ) else: - assert '''\ - 'привет'\ - ''</span><span class="cp">}</span>'.encode( - sys.getdefaultencoding(), - 'htmlentityreplace') in html_error + assert ( + "'" + "привет" + ''</span><span class="cp">}</span>'.encode( + sys.getdefaultencoding(), "htmlentityreplace" + ) + in html_error + ) else: - assert False, ("This function should trigger a CompileException, " - "but didn't") + assert False, ( + "This function should trigger a CompileException, " + "but didn't" + ) @requires_no_pygments_exceptions def test_utf8_html_error_template_no_pygments(self): @@ -123,87 +144,117 @@ ${u'привет'} except exceptions.CompileException: html_error = exceptions.html_error_template().render() if compat.py3k: - assert ("CompileException: Fragment 'if 2 == 2: /an " - "error' is not a partial control statement " - "at line: 2 char: 1").encode(sys.getdefaultencoding(), - 'htmlentityreplace') in \ - html_error - else: - assert ("CompileException: Fragment 'if 2 == 2: /an " + assert ( + ( + "CompileException: Fragment 'if 2 == 2: /an " "error' is not a partial control statement " - "at line: 2 char: 1") in \ - html_error + "at line: 2 char: 1" + ).encode(sys.getdefaultencoding(), "htmlentityreplace") + in html_error + ) + else: + assert ( + "CompileException: Fragment 'if 2 == 2: /an " + "error' is not a partial control statement " + "at line: 2 char: 1" + ) in html_error if compat.py3k: - assert "${'привет'}".encode(sys.getdefaultencoding(), - 'htmlentityreplace') in html_error + assert ( + "${'привет'}".encode( + sys.getdefaultencoding(), "htmlentityreplace" + ) + in html_error + ) else: - assert u("${u'привет'}").encode(sys.getdefaultencoding(), - 'htmlentityreplace') in html_error + assert ( + u("${u'привет'}").encode( + sys.getdefaultencoding(), "htmlentityreplace" + ) + in html_error + ) else: - assert False, ("This function should trigger a CompileException, " - "but didn't") + assert False, ( + "This function should trigger a CompileException, " + "but didn't" + ) def test_format_closures(self): try: - exec("def foo():"\ - " raise RuntimeError('test')", locals()) - foo() + exec("def foo():" " raise RuntimeError('test')", locals()) + foo() # noqa except: html_error = exceptions.html_error_template().render() assert "RuntimeError: test" in str(html_error) def test_py_utf8_html_error_template(self): try: - foo = u('日本') - raise RuntimeError('test') + foo = u("日本") # noqa + raise RuntimeError("test") except: html_error = exceptions.html_error_template().render() if compat.py3k: - assert 'RuntimeError: test' in html_error.decode('utf-8') - assert "foo = u('日本')" in html_error.decode('utf-8') + assert "RuntimeError: test" in html_error.decode("utf-8") + assert "foo = u("日本")" in html_error.decode("utf-8") else: - assert 'RuntimeError: test' in html_error - assert "foo = u('日本')" in html_error + assert "RuntimeError: test" in html_error + assert "foo = u("日本")" in html_error def test_py_unicode_error_html_error_template(self): try: - raise RuntimeError(u('日本')) + raise RuntimeError(u("日本")) except: html_error = exceptions.html_error_template().render() - assert u("RuntimeError: 日本").encode('ascii', 'ignore') in html_error + assert ( + u("RuntimeError: 日本").encode("ascii", "ignore") in html_error + ) @requires_pygments_14 def test_format_exceptions_pygments(self): l = TemplateLookup(format_exceptions=True) - l.put_string("foo.html", """ + l.put_string( + "foo.html", + """ <%inherit file="base.html"/> ${foobar} - """) + """, + ) - l.put_string("base.html", """ + l.put_string( + "base.html", + """ ${self.body()} - """) + """, + ) - assert '<div class="sourceline"><table class="syntax-highlightedtable">' in \ - l.get_template("foo.html").render_unicode() + assert ( + '<div class="sourceline"><table class="syntax-highlightedtable">' + in l.get_template("foo.html").render_unicode() + ) @requires_no_pygments_exceptions def test_format_exceptions_no_pygments(self): l = TemplateLookup(format_exceptions=True) - l.put_string("foo.html", """ + l.put_string( + "foo.html", + """ <%inherit file="base.html"/> ${foobar} - """) + """, + ) - l.put_string("base.html", """ + l.put_string( + "base.html", + """ ${self.body()} - """) + """, + ) - assert '<div class="sourceline">${foobar}</div>' in \ - result_lines(l.get_template("foo.html").render_unicode()) + assert '<div class="sourceline">${foobar}</div>' in result_lines( + l.get_template("foo.html").render_unicode() + ) @requires_pygments_14 def test_utf8_format_exceptions_pygments(self): @@ -212,17 +263,24 @@ ${foobar} l = TemplateLookup(format_exceptions=True) if compat.py3k: - l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}""") + l.put_string( + "foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}""" + ) else: - l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""") + l.put_string( + "foo.html", + """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""", + ) if compat.py3k: - assert ''привет'</span>' in \ - l.get_template("foo.html").render().decode('utf-8') + assert "'привет'</span>" in l.get_template( + "foo.html" + ).render().decode("utf-8") else: - assert ''прив'\ - 'ет'</span>' in \ - l.get_template("foo.html").render().decode('utf-8') + assert ( + "'прив" + "ет'</span>" + ) in l.get_template("foo.html").render().decode("utf-8") @requires_no_pygments_exceptions def test_utf8_format_exceptions_no_pygments(self): @@ -231,44 +289,59 @@ ${foobar} l = TemplateLookup(format_exceptions=True) if compat.py3k: - l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}""") + l.put_string( + "foo.html", """# -*- coding: utf-8 -*-\n${'привет' + foobar}""" + ) else: - l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""") + l.put_string( + "foo.html", + """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""", + ) if compat.py3k: - assert '<div class="sourceline">${'привет' + foobar}</div>'\ - in result_lines(l.get_template("foo.html").render().decode('utf-8')) + assert ( + '<div class="sourceline">${'привет' + foobar}</div>' + in result_lines( + l.get_template("foo.html").render().decode("utf-8") + ) + ) else: - assert '${u'приве'\ - 'т' + foobar}' in \ - result_lines(l.get_template("foo.html").render().decode('utf-8')) + assert ( + "${u'приве" + "т' + foobar}" + in result_lines( + l.get_template("foo.html").render().decode("utf-8") + ) + ) def test_mod_no_encoding(self): mod = __import__("test.foo.mod_no_encoding").foo.mod_no_encoding try: - mod.run() + mod.run() except: t, v, tback = sys.exc_info() - html_error = exceptions.html_error_template().\ - render_unicode(error=v, traceback=tback) + exceptions.html_error_template().render_unicode( + error=v, traceback=tback + ) def test_custom_tback(self): try: raise RuntimeError("error 1") - foo('bar') + foo("bar") # noqa except: t, v, tback = sys.exc_info() try: raise RuntimeError("error 2") except: - html_error = exceptions.html_error_template().\ - render_unicode(error=v, traceback=tback) + html_error = exceptions.html_error_template().render_unicode( + error=v, traceback=tback + ) # obfuscate the text so that this text # isn't in the 'wrong' exception - assert "".join(reversed(");93#&rab;93#&(oof")) in html_error + assert "".join(reversed(");touq&rab;touq&(oof")) in html_error def test_tback_no_trace_from_py_file(self): try: @@ -282,9 +355,13 @@ ${foobar} sys.exc_clear() # and don't even send what we have. - html_error = exceptions.html_error_template().\ - render_unicode(error=v, traceback=None) - assert "local variable 'y' referenced before assignment" in html_error + html_error = exceptions.html_error_template().render_unicode( + error=v, traceback=None + ) + assert ( + "local variable 'y' referenced before assignment" + in html_error + ) def test_tback_trace_from_py_file(self): t = self._file_template("runtimeerr.html") @@ -292,7 +369,9 @@ ${foobar} t.render() assert False except: - html_error = exceptions.html_error_template().\ - render_unicode() + html_error = exceptions.html_error_template().render_unicode() - assert "local variable 'y' referenced before assignment" in html_error + assert ( + "local variable 'y' referenced before assignment" + in html_error + ) diff --git a/test/test_filters.py b/test/test_filters.py index 64f36f6..598cb45 100644 --- a/test/test_filters.py +++ b/test/test_filters.py @@ -1,228 +1,302 @@ # -*- coding: utf-8 -*- -from mako.template import Template import unittest -from test import TemplateTest, eq_, requires_python_2 -from test.util import result_lines, flatten_result -from mako.compat import u + from mako import compat +from mako.compat import u +from mako.template import Template +from test import eq_ +from test import requires_python_2 +from test import TemplateTest +from test.util import flatten_result +from test.util import result_lines + class FilterTest(TemplateTest): def test_basic(self): - t = Template(""" + t = Template( + """ ${x | myfilter} -""") - assert flatten_result(t.render(x="this is x", myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)) == "MYFILTER->this is x<-MYFILTER" +""" + ) + assert ( + flatten_result( + t.render( + x="this is x", + myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t, + ) + ) + == "MYFILTER->this is x<-MYFILTER" + ) def test_expr(self): """test filters that are themselves expressions""" - t = Template(""" + t = Template( + """ ${x | myfilter(y)} -""") +""" + ) + def myfilter(y): return lambda x: "MYFILTER->%s<-%s" % (x, y) - assert flatten_result(t.render(x="this is x", myfilter=myfilter, y="this is y")) == "MYFILTER->this is x<-this is y" + + assert ( + flatten_result( + t.render(x="this is x", myfilter=myfilter, y="this is y") + ) + == "MYFILTER->this is x<-this is y" + ) def test_convert_str(self): - """test that string conversion happens in expressions before sending to filters""" - t = Template(""" + """test that string conversion happens in expressions before + sending to filters""" + t = Template( + """ ${x | trim} - """) + """ + ) assert flatten_result(t.render(x=5)) == "5" def test_quoting(self): - t = Template(""" + t = Template( + """ foo ${bar | h} - """) + """ + ) eq_( flatten_result(t.render(bar="<'some bar'>")), - "foo <'some bar'>" + "foo <'some bar'>", ) def test_url_escaping(self): - t = Template(""" + t = Template( + """ http://example.com/?bar=${bar | u}&v=1 - """) + """ + ) eq_( flatten_result(t.render(bar=u"酒吧bar")), - "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1" + "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1", ) def test_entity(self): t = Template("foo ${bar | entity}") eq_( flatten_result(t.render(bar="<'some bar'>")), - "foo <'some bar'>" + "foo <'some bar'>", ) @requires_python_2 def test_quoting_non_unicode(self): - t = Template(""" + t = Template( + """ foo ${bar | h} - """, disable_unicode=True, - output_encoding=None) + """, + disable_unicode=True, + output_encoding=None, + ) eq_( flatten_result(t.render(bar="<'привет'>")), - "foo <'привет'>" + "foo <'привет'>", ) @requires_python_2 def test_url_escaping_non_unicode(self): - t = Template(""" + t = Template( + """ http://example.com/?bar=${bar | u}&v=1 - """, disable_unicode=True, - output_encoding=None) + """, + disable_unicode=True, + output_encoding=None, + ) eq_( flatten_result(t.render(bar="酒吧bar")), - "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1" + "http://example.com/?bar=%E9%85%92%E5%90%A7bar&v=1", ) - def test_def(self): - t = Template(""" + t = Template( + """ <%def name="foo()" filter="myfilter"> this is foo </%def> ${foo()} -""") +""" + ) eq_( - flatten_result(t.render(x="this is x", - myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t)), - "MYFILTER-> this is foo <-MYFILTER" + flatten_result( + t.render( + x="this is x", + myfilter=lambda t: "MYFILTER->%s<-MYFILTER" % t, + ) + ), + "MYFILTER-> this is foo <-MYFILTER", ) def test_import(self): - t = Template(""" + t = Template( + """ <%! from mako import filters %>\ - trim this string: ${" some string to trim " | filters.trim} continue\ - """) + trim this string: """ + """${" some string to trim " | filters.trim} continue\ + """ + ) - assert t.render().strip()=="trim this string: some string to trim continue" + assert ( + t.render().strip() + == "trim this string: some string to trim continue" + ) def test_import_2(self): - t = Template(""" - trim this string: ${" some string to trim " | filters.trim} continue\ - """, imports=["from mako import filters"]) - #print t.code - assert t.render().strip()=="trim this string: some string to trim continue" + t = Template( + """ + trim this string: """ + """${" some string to trim " | filters.trim} continue\ + """, + imports=["from mako import filters"], + ) + # print t.code + assert ( + t.render().strip() + == "trim this string: some string to trim continue" + ) def test_encode_filter(self): - t = Template("""# coding: utf-8 + t = Template( + """# coding: utf-8 some stuff.... ${x} - """, default_filters=['decode.utf8']) + """, + default_filters=["decode.utf8"], + ) eq_( t.render_unicode(x=u("voix m’a réveillé")).strip(), - u("some stuff.... voix m’a réveillé") + u("some stuff.... voix m’a réveillé"), ) def test_encode_filter_non_str(self): - t = Template("""# coding: utf-8 + t = Template( + """# coding: utf-8 some stuff.... ${x} - """, default_filters=['decode.utf8']) - eq_( - t.render_unicode(x=3).strip(), - u("some stuff.... 3") + """, + default_filters=["decode.utf8"], ) + eq_(t.render_unicode(x=3).strip(), u("some stuff.... 3")) @requires_python_2 def test_encode_filter_non_str_we_return_bytes(self): class Foo(object): def __str__(self): return compat.b("å") - t = Template("""# coding: utf-8 + + t = Template( + """# coding: utf-8 some stuff.... ${x} - """, default_filters=['decode.utf8']) - eq_( - t.render_unicode(x=Foo()).strip(), - u("some stuff.... å") + """, + default_filters=["decode.utf8"], ) + eq_(t.render_unicode(x=Foo()).strip(), u("some stuff.... å")) def test_custom_default(self): - t = Template(""" + t = Template( + """ <%! def myfilter(x): return "->" + x + "<-" %> hi ${'there'} - """, default_filters=['myfilter']) - assert t.render().strip()=="hi ->there<-" + """, + default_filters=["myfilter"], + ) + assert t.render().strip() == "hi ->there<-" def test_global(self): - t = Template(""" + t = Template( + """ <%page expression_filter="h"/> ${"<tag>this is html</tag>"} - """) - assert t.render().strip() == "<tag>this is html</tag>" + """ + ) + assert t.render().strip() == "<tag>this is html</tag>" def test_block_via_context(self): - t = Template(""" + t = Template( + """ <%block name="foo" filter="myfilter"> some text </%block> - """) + """ + ) + def myfilter(text): return "MYTEXT" + text - eq_( - result_lines(t.render(myfilter=myfilter)), - ["MYTEXT", "some text"] - ) + + eq_(result_lines(t.render(myfilter=myfilter)), ["MYTEXT", "some text"]) def test_def_via_context(self): - t = Template(""" + t = Template( + """ <%def name="foo()" filter="myfilter"> some text </%def> ${foo()} - """) + """ + ) + def myfilter(text): return "MYTEXT" + text - eq_( - result_lines(t.render(myfilter=myfilter)), - ["MYTEXT", "some text"] - ) + + eq_(result_lines(t.render(myfilter=myfilter)), ["MYTEXT", "some text"]) def test_text_via_context(self): - t = Template(""" + t = Template( + """ <%text filter="myfilter"> some text </%text> - """) + """ + ) + def myfilter(text): return "MYTEXT" + text - eq_( - result_lines(t.render(myfilter=myfilter)), - ["MYTEXT", "some text"] - ) + eq_(result_lines(t.render(myfilter=myfilter)), ["MYTEXT", "some text"]) def test_nflag(self): - t = Template(""" + t = Template( + """ ${"<tag>this is html</tag>" | n} - """, default_filters=['h', 'unicode']) - assert t.render().strip() == "<tag>this is html</tag>" + """, + default_filters=["h", "unicode"], + ) + assert t.render().strip() == "<tag>this is html</tag>" - t = Template(""" + t = Template( + """ <%page expression_filter="h"/> ${"<tag>this is html</tag>" | n} - """) - assert t.render().strip() == "<tag>this is html</tag>" + """ + ) + assert t.render().strip() == "<tag>this is html</tag>" - t = Template(""" + t = Template( + """ <%page expression_filter="h"/> ${"<tag>this is html</tag>" | n, h} - """) - assert t.render().strip() == "<tag>this is html</tag>" + """ + ) + assert t.render().strip() == "<tag>this is html</tag>" def test_non_expression(self): - t = Template(""" + t = Template( + """ <%! def a(text): return "this is a" @@ -234,10 +308,13 @@ class FilterTest(TemplateTest): <%def name="foo()" buffered="True"> this is text </%def> - """, buffer_filters=['a']) + """, + buffer_filters=["a"], + ) assert t.render().strip() == "this is a" - t = Template(""" + t = Template( + """ <%! def a(text): return "this is a" @@ -250,10 +327,14 @@ class FilterTest(TemplateTest): <%def name="foo()" buffered="True"> this is text </%def> - """, buffer_filters=['a'], default_filters=['b']) + """, + buffer_filters=["a"], + default_filters=["b"], + ) assert flatten_result(t.render()) == "this is b this is b" - t = Template(""" + t = Template( + """ <%! class Foo(object): foo = True @@ -273,10 +354,14 @@ class FilterTest(TemplateTest): <%def name="foo()" buffered="True"> this is text </%def> - """, buffer_filters=['a'], default_filters=['b']) + """, + buffer_filters=["a"], + default_filters=["b"], + ) assert flatten_result(t.render()) == "this is b this is a" - t = Template(""" + t = Template( + """ <%! def a(text): return "this is a" @@ -292,51 +377,67 @@ class FilterTest(TemplateTest): <%def name="bar()" filter="b" buffered="True"> this is text </%def> - """, buffer_filters=['a']) + """, + buffer_filters=["a"], + ) assert flatten_result(t.render()) == "this is b this is a" - def test_builtins(self): - t = Template(""" + t = Template( + """ ${"this is <text>" | h} -""") +""" + ) assert flatten_result(t.render()) == "this is <text>" - t = Template(""" + t = Template( + """ http://foo.com/arg1=${"hi! this is a string." | u} -""") - assert flatten_result(t.render()) == "http://foo.com/arg1=hi%21+this+is+a+string." +""" + ) + assert ( + flatten_result(t.render()) + == "http://foo.com/arg1=hi%21+this+is+a+string." + ) + class BufferTest(unittest.TestCase): def test_buffered_def(self): - t = Template(""" + t = Template( + """ <%def name="foo()" buffered="True"> this is foo </%def> ${"hi->" + foo() + "<-hi"} -""") +""" + ) assert flatten_result(t.render()) == "hi-> this is foo <-hi" def test_unbuffered_def(self): - t = Template(""" + t = Template( + """ <%def name="foo()" buffered="False"> this is foo </%def> ${"hi->" + foo() + "<-hi"} -""") +""" + ) assert flatten_result(t.render()) == "this is foo hi-><-hi" def test_capture(self): - t = Template(""" + t = Template( + """ <%def name="foo()" buffered="False"> this is foo </%def> ${"hi->" + capture(foo) + "<-hi"} -""") +""" + ) assert flatten_result(t.render()) == "hi-> this is foo <-hi" def test_capture_exception(self): - template = Template(""" + template = Template( + """ <%def name="a()"> this is a <% @@ -347,7 +448,8 @@ class BufferTest(unittest.TestCase): c = capture(a) %> a->${c}<-a - """) + """ + ) try: template.render() assert False @@ -355,7 +457,8 @@ class BufferTest(unittest.TestCase): assert True def test_buffered_exception(self): - template = Template(""" + template = Template( + """ <%def name="a()" buffered="True"> <% raise TypeError("hi") @@ -364,7 +467,8 @@ class BufferTest(unittest.TestCase): ${a()} -""") +""" + ) try: print(template.render()) assert False @@ -372,7 +476,8 @@ class BufferTest(unittest.TestCase): assert True def test_capture_ccall(self): - t = Template(""" + t = Template( + """ <%def name="foo()"> <% x = capture(caller.body) @@ -383,8 +488,8 @@ class BufferTest(unittest.TestCase): <%call expr="foo()"> ccall body </%call> -""") +""" + ) - #print t.render() + # print t.render() assert flatten_result(t.render()) == "this is foo. body: ccall body" - diff --git a/test/test_inheritance.py b/test/test_inheritance.py index 08a46b3..e8ed74e 100644 --- a/test/test_inheritance.py +++ b/test/test_inheritance.py @@ -1,12 +1,17 @@ -from mako import lookup, compat import unittest + +from mako import compat +from mako import lookup from test.util import result_lines + class InheritanceTest(unittest.TestCase): def test_basic(self): collection = lookup.TemplateLookup() - collection.put_string('main', """ + collection.put_string( + "main", + """ <%inherit file="base"/> <%def name="header()"> @@ -14,9 +19,12 @@ class InheritanceTest(unittest.TestCase): </%def> this is the content. -""") +""", + ) - collection.put_string('base', """ + collection.put_string( + "base", + """ This is base. header: ${self.header()} @@ -28,31 +36,38 @@ footer: ${self.footer()} <%def name="footer()"> this is the footer. header again ${next.header()} </%def> -""") - - assert result_lines(collection.get_template('main').render()) == [ - 'This is base.', - 'header:', - 'main header.', - 'body:', - 'this is the content.', - 'footer:', - 'this is the footer. header again', - 'main header.' +""", + ) + + assert result_lines(collection.get_template("main").render()) == [ + "This is base.", + "header:", + "main header.", + "body:", + "this is the content.", + "footer:", + "this is the footer. header again", + "main header.", ] def test_multilevel_nesting(self): collection = lookup.TemplateLookup() - collection.put_string('main', """ + collection.put_string( + "main", + """ <%inherit file="layout"/> <%def name="d()">main_d</%def> main_body ${parent.d()} full stack from the top: - ${self.name} ${parent.name} ${parent.context['parent'].name} ${parent.context['parent'].context['parent'].name} -""") - - collection.put_string('layout', """ + ${self.name} ${parent.name} ${parent.context['parent'].name} """ + """${parent.context['parent'].context['parent'].name} +""", + ) + + collection.put_string( + "layout", + """ <%inherit file="general"/> <%def name="d()">layout_d</%def> layout_body @@ -60,95 +75,122 @@ parent name: ${parent.name} ${parent.d()} ${parent.context['parent'].d()} ${next.body()} -""") +""", + ) - collection.put_string('general', """ + collection.put_string( + "general", + """ <%inherit file="base"/> <%def name="d()">general_d</%def> general_body ${next.d()} ${next.context['next'].d()} ${next.body()} -""") - collection.put_string('base', """ +""", + ) + collection.put_string( + "base", + """ base_body full stack from the base: - ${self.name} ${self.context['parent'].name} ${self.context['parent'].context['parent'].name} ${self.context['parent'].context['parent'].context['parent'].name} + ${self.name} ${self.context['parent'].name} """ + """${self.context['parent'].context['parent'].name} """ + """${self.context['parent'].context['parent'].context['parent'].name} ${next.body()} <%def name="d()">base_d</%def> -""") - - assert result_lines(collection.get_template('main').render()) == [ - 'base_body', - 'full stack from the base:', - 'self:main self:layout self:general self:base', - 'general_body', - 'layout_d', - 'main_d', - 'layout_body', - 'parent name: self:general', - 'general_d', - 'base_d', - 'main_body layout_d', - 'full stack from the top:', - 'self:main self:layout self:general self:base' +""", + ) + + assert result_lines(collection.get_template("main").render()) == [ + "base_body", + "full stack from the base:", + "self:main self:layout self:general self:base", + "general_body", + "layout_d", + "main_d", + "layout_body", + "parent name: self:general", + "general_d", + "base_d", + "main_body layout_d", + "full stack from the top:", + "self:main self:layout self:general self:base", ] def test_includes(self): - """test that an included template also has its full hierarchy invoked.""" + """test that an included template also has its full hierarchy + invoked.""" collection = lookup.TemplateLookup() - collection.put_string("base", """ + collection.put_string( + "base", + """ <%def name="a()">base_a</%def> This is the base. ${next.body()} End base. -""") +""", + ) - collection.put_string("index",""" + collection.put_string( + "index", + """ <%inherit file="base"/> this is index. a is: ${self.a()} <%include file="secondary"/> -""") +""", + ) - collection.put_string("secondary",""" + collection.put_string( + "secondary", + """ <%inherit file="base"/> this is secondary. a is: ${self.a()} -""") +""", + ) assert result_lines(collection.get_template("index").render()) == [ - 'This is the base.', - 'this is index.', - 'a is: base_a', - 'This is the base.', - 'this is secondary.', - 'a is: base_a', - 'End base.', - 'End base.' - ] + "This is the base.", + "this is index.", + "a is: base_a", + "This is the base.", + "this is secondary.", + "a is: base_a", + "End base.", + "End base.", + ] def test_namespaces(self): - """test that templates used via <%namespace> have access to an inheriting 'self', and that - the full 'self' is also exported.""" + """test that templates used via <%namespace> have access to an + inheriting 'self', and that the full 'self' is also exported.""" collection = lookup.TemplateLookup() - collection.put_string("base", """ + collection.put_string( + "base", + """ <%def name="a()">base_a</%def> <%def name="b()">base_b</%def> This is the base. ${next.body()} -""") +""", + ) - collection.put_string("layout", """ + collection.put_string( + "layout", + """ <%inherit file="base"/> <%def name="a()">layout_a</%def> This is the layout.. ${next.body()} -""") +""", + ) - collection.put_string("index",""" + collection.put_string( + "index", + """ <%inherit file="base"/> <%namespace name="sc" file="secondary"/> this is index. @@ -157,32 +199,41 @@ ${next.body()} sc.b is: ${sc.b()} sc.c is: ${sc.c()} sc.body is: ${sc.body()} -""") +""", + ) - collection.put_string("secondary",""" + collection.put_string( + "secondary", + """ <%inherit file="layout"/> - <%def name="c()">secondary_c. a is ${self.a()} b is ${self.b()} d is ${self.d()}</%def> + <%def name="c()">secondary_c. a is ${self.a()} b is ${self.b()} """ + """d is ${self.d()}</%def> <%def name="d()">secondary_d.</%def> this is secondary. a is: ${self.a()} c is: ${self.c()} -""") - - assert result_lines(collection.get_template('index').render()) == ['This is the base.', - 'this is index.', - 'a is: base_a', - 'sc.a is: layout_a', - 'sc.b is: base_b', - 'sc.c is: secondary_c. a is layout_a b is base_b d is secondary_d.', - 'sc.body is:', - 'this is secondary.', - 'a is: layout_a', - 'c is: secondary_c. a is layout_a b is base_b d is secondary_d.' - ] +""", + ) + + assert result_lines(collection.get_template("index").render()) == [ + "This is the base.", + "this is index.", + "a is: base_a", + "sc.a is: layout_a", + "sc.b is: base_b", + "sc.c is: secondary_c. a is layout_a b is base_b d is " + "secondary_d.", + "sc.body is:", + "this is secondary.", + "a is: layout_a", + "c is: secondary_c. a is layout_a b is base_b d is secondary_d.", + ] def test_pageargs(self): collection = lookup.TemplateLookup() - collection.put_string("base", """ + collection.put_string( + "base", + """ this is the base. <% @@ -195,29 +246,39 @@ ${next.body()} </%def> ${foo()} - """) - collection.put_string("index", """ + """, + ) + collection.put_string( + "index", + """ <%inherit file="base"/> <%page args="x, y, z=7"/> print ${x}, ${y}, ${z} - """) + """, + ) if compat.py3k: - assert result_lines(collection.get_template('index').render_unicode(x=5,y=10)) == [ + assert result_lines( + collection.get_template("index").render_unicode(x=5, y=10) + ) == [ "this is the base.", "pageargs: (type: <class 'dict'>) [('x', 5), ('y', 10)]", - "print 5, 10, 7" + "print 5, 10, 7", ] else: - assert result_lines(collection.get_template('index').render_unicode(x=5,y=10)) == [ + assert result_lines( + collection.get_template("index").render_unicode(x=5, y=10) + ) == [ "this is the base.", "pageargs: (type: <type 'dict'>) [('x', 5), ('y', 10)]", - "print 5, 10, 7" + "print 5, 10, 7", ] def test_pageargs_2(self): collection = lookup.TemplateLookup() - collection.put_string("base", """ + collection.put_string( + "base", + """ this is the base. ${next.body(**context.kwargs)} @@ -232,61 +293,84 @@ ${next.body()} ${foo(x=12, y=15, z=8)} ${bar(x=19, y=17)} - """) - collection.put_string("index", """ + """, + ) + collection.put_string( + "index", + """ <%inherit file="base"/> <%page args="x, y, z=7"/> pageargs: ${x}, ${y}, ${z} - """) - assert result_lines(collection.get_template('index').render(x=5,y=10)) == [ + """, + ) + assert result_lines( + collection.get_template("index").render(x=5, y=10) + ) == [ "this is the base.", "pageargs: 5, 10, 7", "pageargs: 12, 15, 8", - "pageargs: 5, 10, 16" + "pageargs: 5, 10, 16", ] def test_pageargs_err(self): collection = lookup.TemplateLookup() - collection.put_string("base", """ + collection.put_string( + "base", + """ this is the base. ${next.body()} - """) - collection.put_string("index", """ + """, + ) + collection.put_string( + "index", + """ <%inherit file="base"/> <%page args="x, y, z=7"/> print ${x}, ${y}, ${z} - """) + """, + ) try: - print(collection.get_template('index').render(x=5,y=10)) + print(collection.get_template("index").render(x=5, y=10)) assert False except TypeError: assert True def test_toplevel(self): collection = lookup.TemplateLookup() - collection.put_string("base", """ + collection.put_string( + "base", + """ this is the base. ${next.body()} - """) - collection.put_string("index", """ + """, + ) + collection.put_string( + "index", + """ <%inherit file="base"/> this is the body - """) - assert result_lines(collection.get_template('index').render()) == [ + """, + ) + assert result_lines(collection.get_template("index").render()) == [ "this is the base.", - "this is the body" - ] - assert result_lines(collection.get_template('index').get_def("body").render()) == [ - "this is the body" + "this is the body", ] + assert result_lines( + collection.get_template("index").get_def("body").render() + ) == ["this is the body"] def test_dynamic(self): collection = lookup.TemplateLookup() - collection.put_string("base", """ + collection.put_string( + "base", + """ this is the base. ${next.body()} - """) - collection.put_string("index", """ + """, + ) + collection.put_string( + "index", + """ <%! def dyn(context): if context.get('base', None) is not None: @@ -296,18 +380,20 @@ ${next.body()} %> <%inherit file="${dyn(context)}"/> this is index. - """) - assert result_lines(collection.get_template('index').render()) == [ - 'this is index.' - ] - assert result_lines(collection.get_template('index').render(base=True)) == [ - 'this is the base.', - 'this is index.' + """, + ) + assert result_lines(collection.get_template("index").render()) == [ + "this is index." ] + assert result_lines( + collection.get_template("index").render(base=True) + ) == ["this is the base.", "this is index."] def test_in_call(self): collection = lookup.TemplateLookup() - collection.put_string("/layout.html",""" + collection.put_string( + "/layout.html", + """ Super layout! <%call expr="self.grid()"> ${next.body()} @@ -319,10 +405,12 @@ ${next.body()} ${caller.body()} End Parent </%def> - """) - + """, + ) - collection.put_string("/subdir/layout.html", """ + collection.put_string( + "/subdir/layout.html", + """ ${next.body()} <%def name="grid()"> Subdir grid @@ -330,20 +418,23 @@ ${next.body()} End subdir </%def> <%inherit file="/layout.html"/> - """) + """, + ) - collection.put_string("/subdir/renderedtemplate.html",""" + collection.put_string( + "/subdir/renderedtemplate.html", + """ Holy smokes! <%inherit file="/subdir/layout.html"/> - """) + """, + ) - #print collection.get_template("/layout.html").code - #print collection.get_template("/subdir/renderedtemplate.html").render() - assert result_lines(collection.get_template("/subdir/renderedtemplate.html").render()) == [ + assert result_lines( + collection.get_template("/subdir/renderedtemplate.html").render() + ) == [ "Super layout!", "Subdir grid", "Holy smokes!", "End subdir", - "Oh yea!" + "Oh yea!", ] - diff --git a/test/test_lexer.py b/test/test_lexer.py index 06ebb05..9807961 100644 --- a/test/test_lexer.py +++ b/test/test_lexer.py @@ -1,37 +1,64 @@ +import re + +from mako import compat +from mako import exceptions +from mako import parsetree +from mako import util from mako.lexer import Lexer -from mako import exceptions, util, compat -from test.util import flatten_result from mako.template import Template -import re -from test import TemplateTest, eq_, assert_raises_message +from test import assert_raises_message +from test import eq_ +from test import TemplateTest +from test.util import flatten_result # create fake parsetree classes which are constructed # exactly as the repr() of a real parsetree object. # this allows us to use a Python construct as the source # of a comparable repr(), which is also hit by the 2to3 tool. + def repr_arg(x): if isinstance(x, dict): return util.sorted_dict_repr(x) else: return repr(x) + def _as_unicode(arg): if isinstance(arg, compat.string_types): return compat.text_type(arg) elif isinstance(arg, dict): - return dict( - (_as_unicode(k), _as_unicode(v)) - for k, v in arg.items() - ) + return dict((_as_unicode(k), _as_unicode(v)) for k, v in arg.items()) else: return arg -from mako import parsetree + +Node = None +TemplateNode = None +ControlLine = None +Text = None +Code = None +Comment = None +Expression = None +_TagMeta = None +Tag = None +IncludeTag = None +NamespaceTag = None +TextTag = None +DefTag = None +BlockTag = None +CallTag = None +CallNamespaceTag = None +InheritTag = None +PageTag = None + +# go through all the elements in parsetree and build out +# mocks of them for cls in list(parsetree.__dict__.values()): - if isinstance(cls, type) and \ - issubclass(cls, parsetree.Node): + if isinstance(cls, type) and issubclass(cls, parsetree.Node): clsname = cls.__name__ - exec((""" + exec( + ( + """ class %s(object): def __init__(self, *args): self.args = [_as_unicode(arg) for arg in args] @@ -40,13 +67,17 @@ class %s(object): self.__class__.__name__, ", ".join(repr_arg(x) for x in self.args) ) -""" % clsname), locals()) +""" + % clsname + ), + locals(), + ) # NOTE: most assertion expressions were generated, then formatted # by PyTidy, hence the dense formatting. -class LexerTest(TemplateTest): +class LexerTest(TemplateTest): def _compare(self, node, expected): eq_(repr(node), repr(expected)) @@ -60,13 +91,27 @@ class LexerTest(TemplateTest): and some more text. """ node = Lexer(template).parse() - self._compare(node, TemplateNode({}, - [Text('''\n<b>Hello world</b>\n ''', (1, - 1)), DefTag('def', {'name': 'foo()'}, (3, 9), - [Text('''\n this is a def.\n ''', - (3, 28))]), - Text('''\n\n and some more text.\n''', - (5, 16))])) + self._compare( + node, + TemplateNode( + {}, + [ + Text("""\n<b>Hello world</b>\n """, (1, 1)), + DefTag( + "def", + {"name": "foo()"}, + (3, 9), + [ + Text( + "\n this is a def.\n ", + (3, 28), + ) + ], + ), + Text("""\n\n and some more text.\n""", (5, 16)), + ], + ), + ) def test_unclosed_tag(self): template = """ @@ -75,17 +120,16 @@ class LexerTest(TemplateTest): other text """ try: - nodes = Lexer(template).parse() + Lexer(template).parse() assert False except exceptions.SyntaxException: eq_( str(compat.exception_as()), - "Unclosed tag: <%def> at line: 5 char: 9" + "Unclosed tag: <%def> at line: 5 char: 9", ) def test_onlyclosed_tag(self): - template = \ - """ + template = """ <%def name="foo()"> foo </%def> @@ -94,20 +138,16 @@ class LexerTest(TemplateTest): hi. """ - self.assertRaises(exceptions.SyntaxException, - Lexer(template).parse) + self.assertRaises(exceptions.SyntaxException, Lexer(template).parse) def test_noexpr_allowed(self): - template = \ - """ + template = """ <%namespace name="${foo}"/> """ - self.assertRaises(exceptions.CompileException, - Lexer(template).parse) + self.assertRaises(exceptions.CompileException, Lexer(template).parse) def test_unmatched_tag(self): - template = \ - """ + template = """ <%namespace name="bar"> <%def name="foo()"> foo @@ -117,29 +157,24 @@ class LexerTest(TemplateTest): hi. """ - self.assertRaises(exceptions.SyntaxException, - Lexer(template).parse) + self.assertRaises(exceptions.SyntaxException, Lexer(template).parse) def test_nonexistent_tag(self): template = """ <%lala x="5"/> """ - self.assertRaises(exceptions.CompileException, - Lexer(template).parse) + self.assertRaises(exceptions.CompileException, Lexer(template).parse) def test_wrongcase_tag(self): - template = \ - """ + template = """ <%DEF name="foo()"> </%def> """ - self.assertRaises(exceptions.CompileException, - Lexer(template).parse) + self.assertRaises(exceptions.CompileException, Lexer(template).parse) def test_percent_escape(self): - template = \ - """ + template = """ %% some whatever. @@ -148,22 +183,28 @@ class LexerTest(TemplateTest): % endif """ node = Lexer(template).parse() - self._compare(node, TemplateNode({}, [Text('''\n\n''', - (1, 1)), Text('''% some whatever.\n\n''', (3, 2)), - Text(' %% more some whatever\n', (5, 2)), - ControlLine('if', 'if foo:', False, (6, 1)), - ControlLine('if', 'endif', True, (7, 1)), - Text(' ', (8, 1))])) + self._compare( + node, + TemplateNode( + {}, + [ + Text("""\n\n""", (1, 1)), + Text("""% some whatever.\n\n""", (3, 2)), + Text(" %% more some whatever\n", (5, 2)), + ControlLine("if", "if foo:", False, (6, 1)), + ControlLine("if", "endif", True, (7, 1)), + Text(" ", (8, 1)), + ], + ), + ) def test_old_multiline_comment(self): template = """#*""" node = Lexer(template).parse() - self._compare(node, TemplateNode({}, [Text('''#*''', (1, 1))])) - + self._compare(node, TemplateNode({}, [Text("""#*""", (1, 1))])) def test_text_tag(self): - template = \ - """ + template = """ ## comment % if foo: hi @@ -185,105 +226,176 @@ class LexerTest(TemplateTest): % endif """ node = Lexer(template).parse() - self._compare(node, - TemplateNode({}, [Text('\n', (1, 1)), - Comment('comment', (2, 1)), - ControlLine('if', 'if foo:', False, (3, 1)), - Text(' hi\n', (4, 1)), - ControlLine('if', 'endif', True, (5, 1)), - Text(' ', (6, 1)), - TextTag('text', {}, (6, 9), - [Text('\n # more code\n\n ' - ' % more code\n <%illegal compionent>/></>\n' - ' <%def name="laal()">def</%def>\n\n\n ', - (6, 16))]), Text('\n\n ', (14, 17)), - DefTag('def', {'name': 'foo()'}, (16, 9), - [Text('this is foo', (16, 28))]), Text('\n\n', (16, 46)), - ControlLine('if', 'if bar:', False, (18, 1)), - Text(' code\n', (19, 1)), - ControlLine('if', 'endif', True, (20, 1)), - Text(' ', (21, 1))]) + self._compare( + node, + TemplateNode( + {}, + [ + Text("\n", (1, 1)), + Comment("comment", (2, 1)), + ControlLine("if", "if foo:", False, (3, 1)), + Text(" hi\n", (4, 1)), + ControlLine("if", "endif", True, (5, 1)), + Text(" ", (6, 1)), + TextTag( + "text", + {}, + (6, 9), + [ + Text( + "\n # more code\n\n " + " % more code\n " + "<%illegal compionent>/></>\n" + ' <%def name="laal()">def</%def>' + '\n\n\n ', + (6, 16), + ) + ], + ), + Text("\n\n ", (14, 17)), + DefTag( + "def", + {"name": "foo()"}, + (16, 9), + [Text("this is foo", (16, 28))], + ), + Text("\n\n", (16, 46)), + ControlLine("if", "if bar:", False, (18, 1)), + Text(" code\n", (19, 1)), + ControlLine("if", "endif", True, (20, 1)), + Text(" ", (21, 1)), + ], + ), ) def test_def_syntax(self): - template = \ - """ + template = """ <%def lala> hi </%def> """ - self.assertRaises(exceptions.CompileException, - Lexer(template).parse) + self.assertRaises(exceptions.CompileException, Lexer(template).parse) def test_def_syntax_2(self): - template = \ - """ + template = """ <%def name="lala"> hi </%def> """ - self.assertRaises(exceptions.CompileException, - Lexer(template).parse) + self.assertRaises(exceptions.CompileException, Lexer(template).parse) def test_whitespace_equals(self): - template = \ - """ + template = """ <%def name = "adef()" > adef </%def> """ node = Lexer(template).parse() - self._compare(node, TemplateNode({}, [Text('\n ', - (1, 1)), DefTag('def', {'name': 'adef()'}, (2, - 13), - [Text('''\n adef\n ''', - (2, 36))]), Text('\n ', (4, 20))])) + self._compare( + node, + TemplateNode( + {}, + [ + Text("\n ", (1, 1)), + DefTag( + "def", + {"name": "adef()"}, + (2, 13), + [ + Text( + """\n adef\n """, + (2, 36), + ) + ], + ), + Text("\n ", (4, 20)), + ], + ), + ) def test_ns_tag_closed(self): - template = \ - """ + template = """ <%self:go x="1" y="2" z="${'hi' + ' ' + 'there'}"/> """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text(''' - - ''', (1, 1)), - CallNamespaceTag('self:go', {'x': '1', 'y' - : '2', 'z': "${'hi' + ' ' + 'there'}"}, (3, - 13), []), Text('\n ', (3, 64))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text( + """ + + """, + (1, 1), + ), + CallNamespaceTag( + "self:go", + {"x": "1", "y": "2", "z": "${'hi' + ' ' + 'there'}"}, + (3, 13), + [], + ), + Text("\n ", (3, 64)), + ], + ), + ) def test_ns_tag_empty(self): - template = \ - """ + template = """ <%form:option value=""></%form:option> """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [Text('\n ', - (1, 1)), CallNamespaceTag('form:option', - {'value': ''}, (2, 13), []), Text('\n ' - , (2, 51))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n ", (1, 1)), + CallNamespaceTag( + "form:option", {"value": ""}, (2, 13), [] + ), + Text("\n ", (2, 51)), + ], + ), + ) def test_ns_tag_open(self): - template = \ - """ + template = """ <%self:go x="1" y="${process()}"> this is the body </%self:go> """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text(''' - - ''', (1, 1)), - CallNamespaceTag('self:go', {'x': '1', 'y' - : '${process()}'}, (3, 13), - [Text(''' + self._compare( + nodes, + TemplateNode( + {}, + [ + Text( + """ + + """, + (1, 1), + ), + CallNamespaceTag( + "self:go", + {"x": "1", "y": "${process()}"}, + (3, 13), + [ + Text( + """ this is the body - ''', - (3, 46))]), Text('\n ', (5, 24))])) + """, + (3, 46), + ) + ], + ), + Text("\n ", (5, 24)), + ], + ), + ) def test_expr_in_attribute(self): """test some slightly trickier expressions. @@ -291,39 +403,64 @@ class LexerTest(TemplateTest): you can still trip up the expression parsing, though, unless we integrated really deeply somehow with AST.""" - template = \ - """ + template = """ <%call expr="foo>bar and 'lala' or 'hoho'"/> <%call expr='foo<bar and hoho>lala and "x" + "y"'/> """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [Text('\n ', - (1, 1)), CallTag('call', {'expr' - : "foo>bar and 'lala' or 'hoho'"}, (2, 13), []), - Text('\n ', (2, 57)), CallTag('call' - , {'expr': 'foo<bar and hoho>lala and "x" + "y"' - }, (3, 13), []), Text('\n ', (3, 64))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n ", (1, 1)), + CallTag( + "call", + {"expr": "foo>bar and 'lala' or 'hoho'"}, + (2, 13), + [], + ), + Text("\n ", (2, 57)), + CallTag( + "call", + {"expr": 'foo<bar and hoho>lala and "x" + "y"'}, + (3, 13), + [], + ), + Text("\n ", (3, 64)), + ], + ), + ) def test_pagetag(self): - template = \ - """ + template = """ <%page cached="True", args="a, b"/> some template """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [Text('\n ', - (1, 1)), PageTag('page', {'args': 'a, b', - 'cached': 'True'}, (2, 13), []), - Text(''' + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n ", (1, 1)), + PageTag( + "page", {"args": "a, b", "cached": "True"}, (2, 13), [] + ), + Text( + """ some template - ''', - (2, 48))])) + """, + (2, 48), + ), + ], + ), + ) def test_nesting(self): - template = \ - """ + template = """ <%namespace name="ns"> <%def name="lala(hi, there)"> @@ -333,25 +470,55 @@ class LexerTest(TemplateTest): """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text(''' - - ''', (1, 1)), - NamespaceTag('namespace', {'name': 'ns'}, (3, - 9), [Text('\n ', (3, 31)), - DefTag('def', {'name': 'lala(hi, there)'}, (4, - 13), [Text('\n ', (4, 42)), - CallTag('call', {'expr': 'something()'}, (5, - 17), []), Text('\n ', (5, 44))]), - Text('\n ', (6, 20))]), - Text(''' - - ''', (7, 22))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text( + """ + + """, + (1, 1), + ), + NamespaceTag( + "namespace", + {"name": "ns"}, + (3, 9), + [ + Text("\n ", (3, 31)), + DefTag( + "def", + {"name": "lala(hi, there)"}, + (4, 13), + [ + Text("\n ", (4, 42)), + CallTag( + "call", + {"expr": "something()"}, + (5, 17), + [], + ), + Text("\n ", (5, 44)), + ], + ), + Text("\n ", (6, 20)), + ], + ), + Text( + """ + + """, + (7, 22), + ), + ], + ), + ) if compat.py3k: + def test_code(self): - template = \ -"""text + template = """text <% print("hi") for x in range(1,5): @@ -363,22 +530,29 @@ more text %> """ nodes = Lexer(template).parse() - self._compare(nodes, - TemplateNode({}, [ - Text('text\n ', (1, 1)), - Code('\nprint("hi")\nfor x in range(1,5):\n ' - 'print(x)\n \n', False, (2, 5)), - Text('\nmore text\n ', (6, 7)), - Code('\nimport foo\n \n', True, (8, 5)), - Text('\n', (10, 7))]) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("text\n ", (1, 1)), + Code( + '\nprint("hi")\nfor x in range(1,5):\n ' + "print(x)\n \n", + False, + (2, 5), + ), + Text("\nmore text\n ", (6, 7)), + Code("\nimport foo\n \n", True, (8, 5)), + Text("\n", (10, 7)), + ], + ), ) - else: def test_code(self): - template = \ -"""text + template = """text <% print "hi" for x in range(1,5): @@ -390,19 +564,27 @@ more text %> """ nodes = Lexer(template).parse() - self._compare(nodes, - TemplateNode({}, [ - Text('text\n ', (1, 1)), - Code('\nprint "hi"\nfor x in range(1,5):\n ' - 'print x\n \n', False, (2, 5)), - Text('\nmore text\n ', (6, 7)), - Code('\nimport foo\n \n', True, (8, 5)), - Text('\n', (10, 7))]) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("text\n ", (1, 1)), + Code( + '\nprint "hi"\nfor x in range(1,5):\n ' + "print x\n \n", + False, + (2, 5), + ), + Text("\nmore text\n ", (6, 7)), + Code("\nimport foo\n \n", True, (8, 5)), + Text("\n", (10, 7)), + ], + ), ) def test_code_and_tags(self): - template = \ - """ + template = """ <%namespace name="foo"> <%def name="x()"> this is x @@ -422,24 +604,60 @@ more text result: <%call expr="foo.x(result)"/> """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [Text('\n', (1, 1)), - NamespaceTag('namespace', {'name': 'foo'}, (2, - 1), [Text('\n ', (2, 24)), DefTag('def', - {'name': 'x()'}, (3, 5), - [Text('''\n this is x\n ''', (3, 22))]), - Text('\n ', (5, 12)), DefTag('def', {'name' - : 'y()'}, (6, 5), - [Text('''\n this is y\n ''', (6, 22))]), - Text('\n', (8, 12))]), Text('''\n\n''', (9, 14)), - Code('''\nresult = []\ndata = get_data()\n''' - '''for x in data:\n result.append(x+7)\n\n''', - False, (11, 1)), Text('''\n\n result: ''', (16, - 3)), CallTag('call', {'expr': 'foo.x(result)' - }, (18, 13), []), Text('\n', (18, 42))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n", (1, 1)), + NamespaceTag( + "namespace", + {"name": "foo"}, + (2, 1), + [ + Text("\n ", (2, 24)), + DefTag( + "def", + {"name": "x()"}, + (3, 5), + [ + Text( + """\n this is x\n """, + (3, 22), + ) + ], + ), + Text("\n ", (5, 12)), + DefTag( + "def", + {"name": "y()"}, + (6, 5), + [ + Text( + """\n this is y\n """, + (6, 22), + ) + ], + ), + Text("\n", (8, 12)), + ], + ), + Text("""\n\n""", (9, 14)), + Code( + """\nresult = []\ndata = get_data()\n""" + """for x in data:\n result.append(x+7)\n\n""", + False, + (11, 1), + ), + Text("""\n\n result: """, (16, 3)), + CallTag("call", {"expr": "foo.x(result)"}, (18, 13), []), + Text("\n", (18, 42)), + ], + ), + ) def test_expression(self): - template = \ - """ + template = """ this is some ${text} and this is ${textwith | escapes, moreescapes} <%def name="hi()"> give me ${foo()} and ${bar()} @@ -447,20 +665,36 @@ more text ${hi()} """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text('\n this is some ', (1, 1)), - Expression('text', [], (2, 22)), - Text(' and this is ', (2, 29)), - Expression('textwith ', ['escapes', 'moreescapes' - ], (2, 42)), Text('\n ', (2, 76)), - DefTag('def', {'name': 'hi()'}, (3, 9), - [Text('\n give me ', (3, 27)), - Expression('foo()', [], (4, 21)), Text(' and ', - (4, 29)), Expression('bar()', [], (4, 34)), - Text('\n ', (4, 42))]), Text('\n ' - , (5, 16)), Expression('hi()', [], (6, 9)), - Text('\n', (6, 16))])) - + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n this is some ", (1, 1)), + Expression("text", [], (2, 22)), + Text(" and this is ", (2, 29)), + Expression( + "textwith ", ["escapes", "moreescapes"], (2, 42) + ), + Text("\n ", (2, 76)), + DefTag( + "def", + {"name": "hi()"}, + (3, 9), + [ + Text("\n give me ", (3, 27)), + Expression("foo()", [], (4, 21)), + Text(" and ", (4, 29)), + Expression("bar()", [], (4, 34)), + Text("\n ", (4, 42)), + ], + ), + Text("\n ", (5, 16)), + Expression("hi()", [], (6, 9)), + Text("\n", (6, 16)), + ], + ), + ) def test_tricky_expression(self): template = """ @@ -470,11 +704,14 @@ more text nodes = Lexer(template).parse() self._compare( nodes, - TemplateNode({}, [ - Text('\n\n ', (1, 1)), - Expression('x and "|" or "hi"', [], (3, 13)), - Text('\n ', (3, 33)) - ]) + TemplateNode( + {}, + [ + Text("\n\n ", (1, 1)), + Expression('x and "|" or "hi"', [], (3, 13)), + Text("\n ", (3, 33)), + ], + ), ) template = r""" @@ -485,47 +722,68 @@ more text nodes = Lexer(template).parse() self._compare( nodes, - TemplateNode({}, [ - Text('\n\n ', (1, 1)), - Expression("hello + '''heres '{|}' text | | }''' ", - ['escape1'], (3, 13)), - Text('\n ', (3, 62)), - Expression(r"""'Tricky string: ' + '\\\"\\\'|\\'""", - [], (4, 13)), - Text('\n ', (4, 49)) - ]) + TemplateNode( + {}, + [ + Text("\n\n ", (1, 1)), + Expression( + "hello + '''heres '{|}' text | | }''' ", + ["escape1"], + (3, 13), + ), + Text("\n ", (3, 62)), + Expression( + r"""'Tricky string: ' + '\\\"\\\'|\\'""", [], (4, 13) + ), + Text("\n ", (4, 49)), + ], + ), ) def test_tricky_code(self): if compat.py3k: template = """<% print('hi %>') %>""" nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Code("print('hi %>') \n", False, (1, 1))])) + self._compare( + nodes, + TemplateNode({}, [Code("print('hi %>') \n", False, (1, 1))]), + ) else: template = """<% print 'hi %>' %>""" nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Code("print 'hi %>' \n", False, (1, 1))])) + self._compare( + nodes, + TemplateNode({}, [Code("print 'hi %>' \n", False, (1, 1))]), + ) def test_tricky_code_2(self): - template = \ - """<% + template = """<% # someone's comment %> """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Code(""" + self._compare( + nodes, + TemplateNode( + {}, + [ + Code( + """ # someone's comment """, - False, (1, 1)), Text('\n ', (3, 3))])) + False, + (1, 1), + ), + Text("\n ", (3, 3)), + ], + ), + ) if compat.py3k: + def test_tricky_code_3(self): - template = \ - """<% + template = """<% print('hi') # this is a comment # another comment @@ -536,8 +794,13 @@ more text # someone else's comment %> '''and now some text '''""" nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Code(""" + self._compare( + nodes, + TemplateNode( + {}, + [ + Code( + """ print('hi') # this is a comment # another comment @@ -548,13 +811,18 @@ print(''' # someone else's comment """, - False, (1, 1)), - Text(" '''and now some text '''", (10, - 3))])) + False, + (1, 1), + ), + Text(" '''and now some text '''", (10, 3)), + ], + ), + ) + else: + def test_tricky_code_3(self): - template = \ - """<% + template = """<% print 'hi' # this is a comment # another comment @@ -565,44 +833,65 @@ print(''' # someone else's comment %> '''and now some text '''""" nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Code("""\nprint 'hi'\n# this is a comment\n""" - """# another comment\nx = 7 """ - """# someone's '''comment\nprint '''\n """ - """there\n '''\n# someone else's """ - """comment\n\n""", - False, (1, 1)), - Text(" '''and now some text '''", (10, 3))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Code( + """\nprint 'hi'\n# this is a comment\n""" + """# another comment\nx = 7 """ + """# someone's '''comment\nprint '''\n """ + """there\n '''\n# someone else's """ + """comment\n\n""", + False, + (1, 1), + ), + Text(" '''and now some text '''", (10, 3)), + ], + ), + ) def test_tricky_code_4(self): - template = \ - """<% foo = "\\"\\\\" %>""" + template = """<% foo = "\\"\\\\" %>""" nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Code("""foo = "\\"\\\\" \n""", - False, (1, 1))])) + self._compare( + nodes, + TemplateNode({}, [Code("""foo = "\\"\\\\" \n""", False, (1, 1))]), + ) def test_tricky_code_5(self): - template = \ - """before ${ {'key': 'value'} } after""" + template = """before ${ {'key': 'value'} } after""" nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text('before ', (1, 1)), - Expression(" {'key': 'value'} ", [], (1, 8)), - Text(' after', (1, 29))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("before ", (1, 1)), + Expression(" {'key': 'value'} ", [], (1, 8)), + Text(" after", (1, 29)), + ], + ), + ) def test_tricky_code_6(self): - template = \ - """before ${ (0x5302 | 0x0400) } after""" + template = """before ${ (0x5302 | 0x0400) } after""" nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text('before ', (1, 1)), - Expression(" (0x5302 | 0x0400) ", [], (1, 8)), - Text(' after', (1, 30))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("before ", (1, 1)), + Expression(" (0x5302 | 0x0400) ", [], (1, 8)), + Text(" after", (1, 30)), + ], + ), + ) def test_control_lines(self): - template = \ - """ + template = """ text text la la % if foo(): mroe text la la blah blah @@ -616,34 +905,51 @@ text text la la """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text('''\ntext text la la\n''', (1, 1)), - ControlLine('if', 'if foo():', False, (3, 1)), - Text(' mroe text la la blah blah\n', (4, 1)), - ControlLine('if', 'endif', True, (5, 1)), - Text('''\n and osme more stuff\n''', (6, - 1)), ControlLine('for', 'for l in range(1,5):', - False, (8, 1)), Text(' tex tesl asdl l is ', - (9, 1)), Expression('l', [], (9, 24)), - Text(' kfmas d\n', (9, 28)), ControlLine('for', - 'endfor', True, (10, 1)), - Text(''' tetx text\n\n''', (11, 1))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("""\ntext text la la\n""", (1, 1)), + ControlLine("if", "if foo():", False, (3, 1)), + Text(" mroe text la la blah blah\n", (4, 1)), + ControlLine("if", "endif", True, (5, 1)), + Text("""\n and osme more stuff\n""", (6, 1)), + ControlLine("for", "for l in range(1,5):", False, (8, 1)), + Text(" tex tesl asdl l is ", (9, 1)), + Expression("l", [], (9, 24)), + Text(" kfmas d\n", (9, 28)), + ControlLine("for", "endfor", True, (10, 1)), + Text(""" tetx text\n\n""", (11, 1)), + ], + ), + ) def test_control_lines_2(self): - template = \ -"""% for file in requestattr['toc'].filenames: + template = """% for file in requestattr['toc'].filenames: x % endfor """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [ControlLine('for', - "for file in requestattr['toc'].filenames:", - False, (1, 1)), Text(' x\n', (2, 1)), - ControlLine('for', 'endfor', True, (3, 1))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + ControlLine( + "for", + "for file in requestattr['toc'].filenames:", + False, + (1, 1), + ), + Text(" x\n", (2, 1)), + ControlLine("for", "endfor", True, (3, 1)), + ], + ), + ) def test_long_control_lines(self): - template = \ - """ + template = """ % for file in \\ requestattr['toc'].filenames: x @@ -652,15 +958,22 @@ text text la la nodes = Lexer(template).parse() self._compare( nodes, - TemplateNode({}, [ - Text('\n', (1, 1)), - ControlLine('for', "for file in \\\n " - "requestattr['toc'].filenames:", - False, (2, 1)), - Text(' x\n', (4, 1)), - ControlLine('for', 'endfor', True, (5, 1)), - Text(' ', (6, 1)) - ]) + TemplateNode( + {}, + [ + Text("\n", (1, 1)), + ControlLine( + "for", + "for file in \\\n " + "requestattr['toc'].filenames:", + False, + (2, 1), + ), + Text(" x\n", (4, 1)), + ControlLine("for", "endfor", True, (5, 1)), + Text(" ", (6, 1)), + ], + ), ) def test_unmatched_control(self): @@ -673,7 +986,7 @@ text text la la assert_raises_message( exceptions.SyntaxException, "Keyword 'endif' doesn't match keyword 'for' at line: 5 char: 1", - Lexer(template).parse + Lexer(template).parse, ) def test_unmatched_control_2(self): @@ -687,7 +1000,7 @@ text text la la assert_raises_message( exceptions.SyntaxException, "Unterminated control keyword: 'if' at line: 3 char: 1", - Lexer(template).parse + Lexer(template).parse, ) def test_unmatched_control_3(self): @@ -701,12 +1014,11 @@ text text la la assert_raises_message( exceptions.SyntaxException, "Keyword 'endlala' doesn't match keyword 'for' at line: 5 char: 1", - Lexer(template).parse + Lexer(template).parse, ) def test_ternary_control(self): - template = \ - """ + template = """ % if x: hi % elif y+7==10: @@ -718,20 +1030,27 @@ text text la la % endif """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [Text('\n', (1, 1)), - ControlLine('if', 'if x:', False, (2, 1)), - Text(' hi\n', (3, 1)), - ControlLine('elif', 'elif y+7==10:', False, (4, - 1)), Text(' there\n', (5, 1)), - ControlLine('elif', 'elif lala:', False, (6, - 1)), Text(' lala\n', (7, 1)), - ControlLine('else', 'else:', False, (8, 1)), - Text(' hi\n', (9, 1)), - ControlLine('if', 'endif', True, (10, 1))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n", (1, 1)), + ControlLine("if", "if x:", False, (2, 1)), + Text(" hi\n", (3, 1)), + ControlLine("elif", "elif y+7==10:", False, (4, 1)), + Text(" there\n", (5, 1)), + ControlLine("elif", "elif lala:", False, (6, 1)), + Text(" lala\n", (7, 1)), + ControlLine("else", "else:", False, (8, 1)), + Text(" hi\n", (9, 1)), + ControlLine("if", "endif", True, (10, 1)), + ], + ), + ) def test_integration(self): - template = \ - """<%namespace name="foo" file="somefile.html"/> + template = """<%namespace name="foo" file="somefile.html"/> ## inherit from foobar.html <%inherit file="foobar.html"/> @@ -753,31 +1072,51 @@ text text la la </table> """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [NamespaceTag('namespace' - , {'file': 'somefile.html', 'name': 'foo'}, - (1, 1), []), Text('\n', (1, 46)), - Comment('inherit from foobar.html', (2, 1)), - InheritTag('inherit', {'file': 'foobar.html'}, - (3, 1), []), Text('''\n\n''', (3, 31)), - DefTag('def', {'name': 'header()'}, (5, 1), - [Text('''\n <div>header</div>\n''', (5, - 23))]), Text('\n', (7, 8)), DefTag('def', - {'name': 'footer()'}, (8, 1), - [Text('''\n <div> footer</div>\n''', (8, - 23))]), Text('''\n\n<table>\n''', (10, 8)), - ControlLine('for', 'for j in data():', False, - (13, 1)), Text(' <tr>\n', (14, 1)), - ControlLine('for', 'for x in j:', False, (15, - 1)), Text(' <td>Hello ', (16, 1)), - Expression('x', ['h'], (16, 23)), Text('</td>\n' - , (16, 30)), ControlLine('for', 'endfor', True, - (17, 1)), Text(' </tr>\n', (18, 1)), - ControlLine('for', 'endfor', True, (19, 1)), - Text('</table>\n', (20, 1))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + NamespaceTag( + "namespace", + {"file": "somefile.html", "name": "foo"}, + (1, 1), + [], + ), + Text("\n", (1, 46)), + Comment("inherit from foobar.html", (2, 1)), + InheritTag("inherit", {"file": "foobar.html"}, (3, 1), []), + Text("""\n\n""", (3, 31)), + DefTag( + "def", + {"name": "header()"}, + (5, 1), + [Text("""\n <div>header</div>\n""", (5, 23))], + ), + Text("\n", (7, 8)), + DefTag( + "def", + {"name": "footer()"}, + (8, 1), + [Text("""\n <div> footer</div>\n""", (8, 23))], + ), + Text("""\n\n<table>\n""", (10, 8)), + ControlLine("for", "for j in data():", False, (13, 1)), + Text(" <tr>\n", (14, 1)), + ControlLine("for", "for x in j:", False, (15, 1)), + Text(" <td>Hello ", (16, 1)), + Expression("x", ["h"], (16, 23)), + Text("</td>\n", (16, 30)), + ControlLine("for", "endfor", True, (17, 1)), + Text(" </tr>\n", (18, 1)), + ControlLine("for", "endfor", True, (19, 1)), + Text("</table>\n", (20, 1)), + ], + ), + ) def test_comment_after_statement(self): - template = \ - """ + template = """ % if x: #comment hi % else: #next @@ -785,44 +1124,66 @@ text text la la % endif #end """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, [Text('\n', (1, 1)), - ControlLine('if', 'if x: #comment', False, (2, - 1)), Text(' hi\n', (3, 1)), - ControlLine('else', 'else: #next', False, (4, - 1)), Text(' hi\n', (5, 1)), - ControlLine('if', 'endif #end', True, (6, 1))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n", (1, 1)), + ControlLine("if", "if x: #comment", False, (2, 1)), + Text(" hi\n", (3, 1)), + ControlLine("else", "else: #next", False, (4, 1)), + Text(" hi\n", (5, 1)), + ControlLine("if", "endif #end", True, (6, 1)), + ], + ), + ) def test_crlf(self): template = util.read_file(self._file_path("crlf.html")) nodes = Lexer(template).parse() self._compare( nodes, - TemplateNode({}, [ - Text('<html>\r\n\r\n', (1, 1)), - PageTag('page', { - 'args': "a=['foo',\n 'bar']" - }, (3, 1), []), - Text('\r\n\r\nlike the name says.\r\n\r\n', (4, 26)), - ControlLine('for', 'for x in [1,2,3]:', False, (8, 1)), - Text(' ', (9, 1)), - Expression('x', [], (9, 9)), - ControlLine('for', 'endfor', True, (10, 1)), - Text('\r\n', (11, 1)), - Expression("trumpeter == 'Miles' and " - "trumpeter or \\\n 'Dizzy'", - [], (12, 1)), - Text('\r\n\r\n', (13, 15)), - DefTag('def', {'name': 'hi()'}, (15, 1), [ - Text('\r\n hi!\r\n', (15, 19))]), - Text('\r\n\r\n</html>\r\n', (17, 8)) - ]) - ) - assert flatten_result(Template(template).render()) \ + TemplateNode( + {}, + [ + Text("<html>\r\n\r\n", (1, 1)), + PageTag( + "page", + {"args": "a=['foo',\n 'bar']"}, + (3, 1), + [], + ), + Text("\r\n\r\nlike the name says.\r\n\r\n", (4, 26)), + ControlLine("for", "for x in [1,2,3]:", False, (8, 1)), + Text(" ", (9, 1)), + Expression("x", [], (9, 9)), + ControlLine("for", "endfor", True, (10, 1)), + Text("\r\n", (11, 1)), + Expression( + "trumpeter == 'Miles' and " + "trumpeter or \\\n 'Dizzy'", + [], + (12, 1), + ), + Text("\r\n\r\n", (13, 15)), + DefTag( + "def", + {"name": "hi()"}, + (15, 1), + [Text("\r\n hi!\r\n", (15, 19))], + ), + Text("\r\n\r\n</html>\r\n", (17, 8)), + ], + ), + ) + assert ( + flatten_result(Template(template).render()) == """<html> like the name says. 1 2 3 Dizzy </html>""" + ) def test_comments(self): - template = \ - """ + template = """ <style> #someselector # other non comment stuff @@ -842,22 +1203,34 @@ comment hi """ nodes = Lexer(template).parse() - self._compare(nodes, TemplateNode({}, - [Text('''\n<style>\n #someselector\n # ''' - '''other non comment stuff\n</style>\n''', - (1, 1)), Comment('a comment', (6, 1)), - Text('''\n# also not a comment\n\n''', (7, 1)), - Comment('this is a comment', (10, 1)), - Text('''\nthis is ## not a comment\n\n''', (11, - 1)), Comment(''' multiline\ncomment\n''', (14, - 1)), Text(''' + self._compare( + nodes, + TemplateNode( + {}, + [ + Text( + """\n<style>\n #someselector\n # """ + """other non comment stuff\n</style>\n""", + (1, 1), + ), + Comment("a comment", (6, 1)), + Text("""\n# also not a comment\n\n""", (7, 1)), + Comment("this is a comment", (10, 1)), + Text("""\nthis is ## not a comment\n\n""", (11, 1)), + Comment(""" multiline\ncomment\n""", (14, 1)), + Text( + """ hi -''', (16, 8))])) +""", + (16, 8), + ), + ], + ), + ) def test_docs(self): - template = \ - """ + template = """ <%doc> this is a comment </%doc> @@ -868,30 +1241,53 @@ hi </%def> """ nodes = Lexer(template).parse() - self._compare(nodes, - TemplateNode({}, [Text('\n ', (1, - 1)), - Comment('''\n this is a comment\n ''', - (2, 9)), Text('\n ', (4, 16)), - DefTag('def', {'name': 'foo()'}, (5, 9), - [Text('\n ', (5, 28)), - Comment('''\n this is the foo func\n''' - ''' ''', - (6, 13)), Text('\n ', (8, 20))]), - Text('\n ', (9, 16))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("\n ", (1, 1)), + Comment( + """\n this is a comment\n """, (2, 9) + ), + Text("\n ", (4, 16)), + DefTag( + "def", + {"name": "foo()"}, + (5, 9), + [ + Text("\n ", (5, 28)), + Comment( + """\n this is the foo func\n""" + """ """, + (6, 13), + ), + Text("\n ", (8, 20)), + ], + ), + Text("\n ", (9, 16)), + ], + ), + ) def test_preprocess(self): - def preproc(text): - return re.sub(r'(?<=\n)\s*#[^#]', '##', text) + return re.sub(r"(?<=\n)\s*#[^#]", "##", text) - template = \ - """ + template = """ hi # old style comment # another comment """ nodes = Lexer(template, preprocessor=preproc).parse() - self._compare(nodes, TemplateNode({}, [Text('''\n hi\n''', - (1, 1)), Comment('old style comment', (3, 1)), - Comment('another comment', (4, 1))])) + self._compare( + nodes, + TemplateNode( + {}, + [ + Text("""\n hi\n""", (1, 1)), + Comment("old style comment", (3, 1)), + Comment("another comment", (4, 1)), + ], + ), + ) diff --git a/test/test_lookup.py b/test/test_lookup.py index 43234d2..0dacfbb 100644 --- a/test/test_lookup.py +++ b/test/test_lookup.py @@ -1,46 +1,50 @@ +import os +import unittest + +from mako import compat +from mako import exceptions +from mako import lookup +from mako import runtime from mako.template import Template -from mako import lookup, exceptions, runtime from mako.util import FastEncodingBuffer -from mako import compat -from test.util import flatten_result, result_lines +from test import assert_raises_message from test import eq_ -import unittest -import os - -from test import TemplateTest, template_base, module_base, assert_raises_message +from test import template_base +from test.util import result_lines tl = lookup.TemplateLookup(directories=[template_base]) + + class LookupTest(unittest.TestCase): def test_basic(self): - t = tl.get_template('index.html') - assert result_lines(t.render()) == [ - "this is index" - ] + t = tl.get_template("index.html") + assert result_lines(t.render()) == ["this is index"] + def test_subdir(self): - t = tl.get_template('/subdir/index.html') + t = tl.get_template("/subdir/index.html") assert result_lines(t.render()) == [ "this is sub index", - "this is include 2" - + "this is include 2", ] - assert tl.get_template('/subdir/index.html').module_id \ - == '_subdir_index_html' + assert ( + tl.get_template("/subdir/index.html").module_id + == "_subdir_index_html" + ) def test_updir(self): - t = tl.get_template('/subdir/foo/../bar/../index.html') + t = tl.get_template("/subdir/foo/../bar/../index.html") assert result_lines(t.render()) == [ "this is sub index", - "this is include 2" - + "this is include 2", ] def test_directory_lookup(self): """test that hitting an existent directory still raises LookupError.""" - self.assertRaises(exceptions.TopLevelLookupException, - tl.get_template, "/subdir" + self.assertRaises( + exceptions.TopLevelLookupException, tl.get_template, "/subdir" ) def test_no_lookup(self): @@ -51,23 +55,26 @@ class LookupTest(unittest.TestCase): except exceptions.TemplateLookupException: eq_( str(compat.exception_as()), - "Template 'memory:%s' has no TemplateLookup associated" % \ - hex(id(t)) - ) + "Template 'memory:%s' has no TemplateLookup associated" + % hex(id(t)), + ) def test_uri_adjust(self): - tl = lookup.TemplateLookup(directories=['/foo/bar']) - assert tl.filename_to_uri('/foo/bar/etc/lala/index.html') == \ - '/etc/lala/index.html' + tl = lookup.TemplateLookup(directories=["/foo/bar"]) + assert ( + tl.filename_to_uri("/foo/bar/etc/lala/index.html") + == "/etc/lala/index.html" + ) - tl = lookup.TemplateLookup(directories=['./foo/bar']) - assert tl.filename_to_uri('./foo/bar/etc/index.html') == \ - '/etc/index.html' + tl = lookup.TemplateLookup(directories=["./foo/bar"]) + assert ( + tl.filename_to_uri("./foo/bar/etc/index.html") == "/etc/index.html" + ) def test_uri_cache(self): """test that the _uri_cache dictionary is available""" - tl._uri_cache[('foo', 'bar')] = '/some/path' - assert tl._uri_cache[('foo', 'bar')] == '/some/path' + tl._uri_cache[("foo", "bar")] = "/some/path" + assert tl._uri_cache[("foo", "bar")] == "/some/path" def test_check_not_found(self): tl = lookup.TemplateLookup() @@ -75,34 +82,41 @@ class LookupTest(unittest.TestCase): f = tl.get_template("foo") assert f.uri in tl._collection f.filename = "nonexistent" - self.assertRaises(exceptions.TemplateLookupException, - tl.get_template, "foo" + self.assertRaises( + exceptions.TemplateLookupException, tl.get_template, "foo" ) assert f.uri not in tl._collection def test_dont_accept_relative_outside_of_root(self): """test the mechanics of an include where the include goes outside of the path""" - tl = lookup.TemplateLookup(directories=[os.path.join(template_base, "subdir")]) + tl = lookup.TemplateLookup( + directories=[os.path.join(template_base, "subdir")] + ) index = tl.get_template("index.html") ctx = runtime.Context(FastEncodingBuffer()) - ctx._with_template=index + ctx._with_template = index assert_raises_message( exceptions.TemplateLookupException, - "Template uri \"../index.html\" is invalid - it " + 'Template uri "../index.html" is invalid - it ' "cannot be relative outside of the root path", - runtime._lookup_template, ctx, "../index.html", index.uri + runtime._lookup_template, + ctx, + "../index.html", + index.uri, ) assert_raises_message( exceptions.TemplateLookupException, - "Template uri \"../othersubdir/foo.html\" is invalid - it " + 'Template uri "../othersubdir/foo.html" is invalid - it ' "cannot be relative outside of the root path", - runtime._lookup_template, ctx, "../othersubdir/foo.html", index.uri + runtime._lookup_template, + ctx, + "../othersubdir/foo.html", + index.uri, ) # this is OK since the .. cancels out - t = runtime._lookup_template(ctx, "foo/../index.html", index.uri) - + runtime._lookup_template(ctx, "foo/../index.html", index.uri) diff --git a/test/test_loop.py b/test/test_loop.py index bdfbaea..8104e49 100644 --- a/test/test_loop.py +++ b/test/test_loop.py @@ -1,136 +1,162 @@ import re import unittest -from mako.template import Template -from mako.lookup import TemplateLookup -from mako.codegen import ( - _FOR_LOOP, mangle_mako_loop, LoopVariable - ) -from mako.runtime import LoopStack, LoopContext from mako import exceptions +from mako.codegen import _FOR_LOOP +from mako.lookup import TemplateLookup +from mako.runtime import LoopContext +from mako.runtime import LoopStack +from mako.template import Template from test import assert_raises_message -from test import TemplateTest, eq_ -from test.util import flatten_result, result_lines +from test import TemplateTest +from test.util import flatten_result -class TestLoop(unittest.TestCase): +class TestLoop(unittest.TestCase): def test__FOR_LOOP(self): for statement, target_list, expression_list in ( - ('for x in y:', 'x', 'y'), - ('for x, y in z:', 'x, y', 'z'), - ('for (x,y) in z:', '(x,y)', 'z'), - ('for ( x, y, z) in a:', '( x, y, z)', 'a'), - ('for x in [1, 2, 3]:', 'x', '[1, 2, 3]'), - ('for x in "spam":', 'x', '"spam"'), - ('for k,v in dict(a=1,b=2).items():', 'k,v', - 'dict(a=1,b=2).items()'), - ('for x in [y+1 for y in [1, 2, 3]]:', 'x', - '[y+1 for y in [1, 2, 3]]') - ): + ("for x in y:", "x", "y"), + ("for x, y in z:", "x, y", "z"), + ("for (x,y) in z:", "(x,y)", "z"), + ("for ( x, y, z) in a:", "( x, y, z)", "a"), + ("for x in [1, 2, 3]:", "x", "[1, 2, 3]"), + ('for x in "spam":', "x", '"spam"'), + ( + "for k,v in dict(a=1,b=2).items():", + "k,v", + "dict(a=1,b=2).items()", + ), + ( + "for x in [y+1 for y in [1, 2, 3]]:", + "x", + "[y+1 for y in [1, 2, 3]]", + ), + ): match = _FOR_LOOP.match(statement) assert match and match.groups() == (target_list, expression_list) def test_no_loop(self): - template = Template("""% for x in 'spam': + template = Template( + """% for x in 'spam': ${x} -% endfor""") +% endfor""" + ) code = template.code - assert not re.match(r"loop = __M_loop._enter\(:", code), "No need to "\ - "generate a loop context if the loop variable wasn't accessed" + assert not re.match(r"loop = __M_loop._enter\(:", code), ( + "No need to " + "generate a loop context if the loop variable wasn't accessed" + ) print(template.render()) def test_loop_demo(self): - template = Template("""x|index|reverse_index|first|last|cycle|even|odd + template = Template( + """x|index|reverse_index|first|last|cycle|even|odd % for x in 'ham': -${x}|${loop.index}|${loop.reverse_index}|${loop.first}|${loop.last}|${loop.cycle('even', 'odd')}|${loop.even}|${loop.odd} -% endfor""") +${x}|${loop.index}|${loop.reverse_index}|${loop.first}|""" + """${loop.last}|${loop.cycle('even', 'odd')}|""" + """${loop.even}|${loop.odd} +% endfor""" + ) expected = [ - "x|index|reverse_index|first|last|cycle|even|odd", - "h|0|2|True|False|even|True|False", - "a|1|1|False|False|odd|False|True", - "m|2|0|False|True|even|True|False" - ] + "x|index|reverse_index|first|last|cycle|even|odd", + "h|0|2|True|False|even|True|False", + "a|1|1|False|False|odd|False|True", + "m|2|0|False|True|even|True|False", + ] code = template.code - assert "loop = __M_loop._enter(" in code, "Generated a loop context since "\ - "the loop variable was accessed" + assert "loop = __M_loop._enter(" in code, ( + "Generated a loop context since " "the loop variable was accessed" + ) rendered = template.render() print(rendered) for line in expected: - assert line in rendered, "Loop variables give information about "\ - "the progress of the loop" + assert line in rendered, ( + "Loop variables give information about " + "the progress of the loop" + ) def test_nested_loops(self): - template = Template("""% for x in 'ab': + template = Template( + """% for x in 'ab': ${x} ${loop.index} <- start in outer loop % for y in [0, 1]: ${y} ${loop.index} <- go to inner loop % endfor ${x} ${loop.index} <- back to outer loop -% endfor""") - code = template.code +% endfor""" + ) rendered = template.render() expected = [ - "a 0 <- start in outer loop", - "0 0 <- go to inner loop", - "1 1 <- go to inner loop", - "a 0 <- back to outer loop", - "b 1 <- start in outer loop", - "0 0 <- go to inner loop", - "1 1 <- go to inner loop", - "b 1 <- back to outer loop", - ] + "a 0 <- start in outer loop", + "0 0 <- go to inner loop", + "1 1 <- go to inner loop", + "a 0 <- back to outer loop", + "b 1 <- start in outer loop", + "0 0 <- go to inner loop", + "1 1 <- go to inner loop", + "b 1 <- back to outer loop", + ] for line in expected: - assert line in rendered, "The LoopStack allows you to take "\ - "advantage of the loop variable even in embedded loops" + assert line in rendered, ( + "The LoopStack allows you to take " + "advantage of the loop variable even in embedded loops" + ) def test_parent_loops(self): - template = Template("""% for x in 'ab': + template = Template( + """% for x in 'ab': ${x} ${loop.index} <- outer loop % for y in [0, 1]: ${y} ${loop.index} <- inner loop ${x} ${loop.parent.index} <- parent loop % endfor ${x} ${loop.index} <- outer loop -% endfor""") +% endfor""" + ) code = template.code rendered = template.render() expected = [ - "a 0 <- outer loop", - "a 0 <- parent loop", - "b 1 <- outer loop", - "b 1 <- parent loop" - ] + "a 0 <- outer loop", + "a 0 <- parent loop", + "b 1 <- outer loop", + "b 1 <- parent loop", + ] for line in expected: print(code) - assert line in rendered, "The parent attribute of a loop gives "\ - "you the previous loop context in the stack" + assert line in rendered, ( + "The parent attribute of a loop gives " + "you the previous loop context in the stack" + ) def test_out_of_context_access(self): template = Template("""${loop.index}""") assert_raises_message( exceptions.RuntimeException, "No loop context is established", - template.render + template.render, ) -class TestLoopStack(unittest.TestCase): +class TestLoopStack(unittest.TestCase): def setUp(self): self.stack = LoopStack() - self.bottom = 'spam' + self.bottom = "spam" self.stack.stack = [self.bottom] def test_enter(self): - iterable = 'ham' + iterable = "ham" s = self.stack._enter(iterable) - assert s is self.stack.stack[-1], "Calling the stack with an iterable returns "\ - "the stack" - assert iterable == self.stack.stack[-1]._iterable, "and pushes the "\ - "iterable on the top of the stack" + assert s is self.stack.stack[-1], ( + "Calling the stack with an iterable returns " "the stack" + ) + assert iterable == self.stack.stack[-1]._iterable, ( + "and pushes the " "iterable on the top of the stack" + ) def test__top(self): - assert self.bottom == self.stack._top, "_top returns the last item "\ - "on the stack" + assert self.bottom == self.stack._top, ( + "_top returns the last item " "on the stack" + ) def test__pop(self): assert len(self.stack.stack) == 1 @@ -140,13 +166,13 @@ class TestLoopStack(unittest.TestCase): def test__push(self): assert len(self.stack.stack) == 1 - iterable = 'ham' + iterable = "ham" self.stack._push(iterable) assert len(self.stack.stack) == 2 assert iterable is self.stack._top._iterable def test_exit(self): - iterable = 'ham' + iterable = "ham" self.stack._enter(iterable) before = len(self.stack.stack) self.stack._exit() @@ -155,28 +181,30 @@ class TestLoopStack(unittest.TestCase): class TestLoopContext(unittest.TestCase): - def setUp(self): self.iterable = [1, 2, 3] self.ctx = LoopContext(self.iterable) def test___len__(self): - assert len(self.iterable) == len(self.ctx), "The LoopContext is the "\ - "same length as the iterable" + assert len(self.iterable) == len(self.ctx), ( + "The LoopContext is the " "same length as the iterable" + ) def test_index(self): expected = tuple(range(len(self.iterable))) actual = tuple(self.ctx.index for i in self.ctx) - assert expected == actual, "The index is consistent with the current "\ - "iteration count" + assert expected == actual, ( + "The index is consistent with the current " "iteration count" + ) def test_reverse_index(self): length = len(self.iterable) - expected = tuple([length-i-1 for i in range(length)]) + expected = tuple([length - i - 1 for i in range(length)]) actual = tuple(self.ctx.reverse_index for i in self.ctx) print(expected, actual) - assert expected == actual, "The reverse_index is the number of "\ - "iterations until the end" + assert expected == actual, ( + "The reverse_index is the number of " "iterations until the end" + ) def test_first(self): expected = (True, False, False) @@ -199,91 +227,95 @@ class TestLoopContext(unittest.TestCase): assert expected == actual, "odd is true on odd iterations" def test_cycle(self): - expected = ('a', 'b', 'a') - actual = tuple(self.ctx.cycle('a', 'b') for i in self.ctx) + expected = ("a", "b", "a") + actual = tuple(self.ctx.cycle("a", "b") for i in self.ctx) assert expected == actual, "cycle endlessly cycles through the values" + class TestLoopFlags(TemplateTest): def test_loop_disabled_template(self): self._do_memory_test( - """ + """ the loop: ${loop} """, - "the loop: hi", - template_args=dict(loop='hi'), - filters=flatten_result, - enable_loop=False + "the loop: hi", + template_args=dict(loop="hi"), + filters=flatten_result, + enable_loop=False, ) def test_loop_disabled_lookup(self): l = TemplateLookup(enable_loop=False) - l.put_string("x", - """ + l.put_string( + "x", + """ the loop: ${loop} - """ + """, ) self._do_test( l.get_template("x"), "the loop: hi", - template_args=dict(loop='hi'), + template_args=dict(loop="hi"), filters=flatten_result, ) def test_loop_disabled_override_template(self): self._do_memory_test( - """ + """ <%page enable_loop="True" /> % for i in (1, 2, 3): ${i} ${loop.index} % endfor """, - "1 0 2 1 3 2", - template_args=dict(loop='hi'), - filters=flatten_result, - enable_loop=False + "1 0 2 1 3 2", + template_args=dict(loop="hi"), + filters=flatten_result, + enable_loop=False, ) def test_loop_disabled_override_lookup(self): l = TemplateLookup(enable_loop=False) - l.put_string("x", - """ + l.put_string( + "x", + """ <%page enable_loop="True" /> % for i in (1, 2, 3): ${i} ${loop.index} % endfor - """ + """, ) self._do_test( l.get_template("x"), "1 0 2 1 3 2", - template_args=dict(loop='hi'), + template_args=dict(loop="hi"), filters=flatten_result, ) def test_loop_enabled_override_template(self): self._do_memory_test( - """ + """ <%page enable_loop="True" /> % for i in (1, 2, 3): ${i} ${loop.index} % endfor """, - "1 0 2 1 3 2", - template_args=dict(), - filters=flatten_result, + "1 0 2 1 3 2", + template_args=dict(), + filters=flatten_result, ) def test_loop_enabled_override_lookup(self): l = TemplateLookup() - l.put_string("x", - """ + l.put_string( + "x", + """ <%page enable_loop="True" /> % for i in (1, 2, 3): ${i} ${loop.index} % endfor - """ + """, ) self._do_test( @@ -292,4 +324,3 @@ class TestLoopFlags(TemplateTest): template_args=dict(), filters=flatten_result, ) - diff --git a/test/test_lru.py b/test/test_lru.py index 6152799..7281537 100644 --- a/test/test_lru.py +++ b/test/test_lru.py @@ -1,34 +1,30 @@ -from mako.util import LRUCache -import string import unittest -import time -import random -from mako.compat import thread +from mako.util import LRUCache + class item: - def __init__(self, id): - self.id = id + def __init__(self, id_): + self.id = id_ def __str__(self): return "item id %d" % self.id -class LRUTest(unittest.TestCase): - +class LRUTest(unittest.TestCase): def testlru(self): - l = LRUCache(10, threshold=.2) + l = LRUCache(10, threshold=0.2) - for id in range(1,20): - l[id] = item(id) + for id_ in range(1, 20): + l[id_] = item(id_) # first couple of items should be gone assert 1 not in l assert 2 not in l # next batch over the threshold of 10 should be present - for id in range(11,20): - assert id in l + for id_ in range(11, 20): + assert id_ in l l[12] l[15] @@ -41,74 +37,5 @@ class LRUTest(unittest.TestCase): assert 11 not in l assert 13 not in l - for id in (25, 24, 23, 14, 12, 19, 18, 17, 16, 15): - assert id in l - - def _disabled_test_threaded(self): - size = 100 - threshold = .5 - all_elems = 2000 - hot_zone = list(range(30,40)) - cache = LRUCache(size, threshold) - - # element to store - class Element(object): - def __init__(self, id): - self.id = id - self.regets = 0 - - # return an element. we will favor ids in the relatively small - # "hot zone" 25% of the time. - def get_elem(): - if random.randint(1,4) == 1: - return hot_zone[random.randint(0, len(hot_zone) - 1)] - else: - return random.randint(1, all_elems) - - total = [0] - # request thread. - def request_elem(): - while True: - total[0] += 1 - id = get_elem() - try: - elem = cache[id] - elem.regets += 1 - except KeyError: - e = Element(id) - cache[id] = e - - time.sleep(random.random() / 1000) - - for x in range(0,20): - _thread.start_new_thread(request_elem, ()) - - # assert size doesn't grow unbounded, doesnt shrink well below size - for x in range(0,5): - time.sleep(1) - print("size:", len(cache)) - assert len(cache) < size + size * threshold * 2 - assert len(cache) > size - (size * .1) - - # computs the average number of times a range of elements were "reused", - # i.e. without being removed from the cache. - def average_regets_in_range(start, end): - elem = [e for e in list(cache.values()) if e.id >= start and e.id <= end] - if len(elem) == 0: - return 0 - avg = sum([e.regets for e in elem]) / len(elem) - return avg - - hotzone_avg = average_regets_in_range(30, 40) - control_avg = average_regets_in_range(450,760) - total_avg = average_regets_in_range(0, 2000) - - # hotzone should be way above the others - print("total fetches", total[0], "hotzone", \ - hotzone_avg, "control", \ - control_avg, "total", total_avg) - - assert hotzone_avg > total_avg * 5 > control_avg * 5 - - - + for id_ in (25, 24, 23, 14, 12, 19, 18, 17, 16, 15): + assert id_ in l diff --git a/test/test_namespace.py b/test/test_namespace.py index 90964b5..8d223d5 100644 --- a/test/test_namespace.py +++ b/test/test_namespace.py @@ -1,7 +1,10 @@ -from mako.template import Template from mako import lookup -from test.util import flatten_result, result_lines -from test import TemplateTest, eq_ +from mako.template import Template +from test import eq_ +from test import TemplateTest +from test.util import flatten_result +from test.util import result_lines + class NamespaceTest(TemplateTest): def test_inline_crossreference(self): @@ -21,7 +24,7 @@ class NamespaceTest(TemplateTest): ${x.b()} """, "this is x a this is x b, and heres this is x a", - filters=flatten_result + filters=flatten_result, ) def test_inline_assignment(self): @@ -40,7 +43,7 @@ class NamespaceTest(TemplateTest): """, "this is x: 5", - filters=flatten_result + filters=flatten_result, ) def test_inline_arguments(self): @@ -59,7 +62,7 @@ class NamespaceTest(TemplateTest): """, "result: 50", - filters=flatten_result + filters=flatten_result, ) def test_inline_not_duped(self): @@ -78,38 +81,49 @@ class NamespaceTest(TemplateTest): """, "", - filters=flatten_result + filters=flatten_result, ) def test_dynamic(self): collection = lookup.TemplateLookup() - collection.put_string('a', """ + collection.put_string( + "a", + """ <%namespace name="b" file="${context['b_def']}"/> a. b: ${b.body()} -""") +""", + ) - collection.put_string('b', """ + collection.put_string( + "b", + """ b. -""") +""", + ) eq_( - flatten_result(collection.get_template('a').render(b_def='b')), - "a. b: b." + flatten_result(collection.get_template("a").render(b_def="b")), + "a. b: b.", ) def test_template(self): collection = lookup.TemplateLookup() - collection.put_string('main.html', """ + collection.put_string( + "main.html", + """ <%namespace name="comp" file="defs.html"/> this is main. ${comp.def1("hi")} ${comp.def2("there")} -""") +""", + ) - collection.put_string('defs.html', """ + collection.put_string( + "defs.html", + """ <%def name="def1(s)"> def1: ${s} </%def> @@ -117,70 +131,103 @@ class NamespaceTest(TemplateTest): <%def name="def2(x)"> def2: ${x} </%def> -""") +""", + ) - assert flatten_result(collection.get_template('main.html').render()) == "this is main. def1: hi def2: there" + assert ( + flatten_result(collection.get_template("main.html").render()) + == "this is main. def1: hi def2: there" + ) def test_module(self): collection = lookup.TemplateLookup() - collection.put_string('main.html', """ + collection.put_string( + "main.html", + """ <%namespace name="comp" module="test.sample_module_namespace"/> this is main. ${comp.foo1()} ${comp.foo2("hi")} -""") +""", + ) - assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi" + assert ( + flatten_result(collection.get_template("main.html").render()) + == "this is main. this is foo1. this is foo2, x is hi" + ) def test_module_2(self): collection = lookup.TemplateLookup() - collection.put_string('main.html', """ + collection.put_string( + "main.html", + """ <%namespace name="comp" module="test.foo.test_ns"/> this is main. ${comp.foo1()} ${comp.foo2("hi")} -""") +""", + ) - assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi" + assert ( + flatten_result(collection.get_template("main.html").render()) + == "this is main. this is foo1. this is foo2, x is hi" + ) def test_module_imports(self): collection = lookup.TemplateLookup() - collection.put_string('main.html', """ + collection.put_string( + "main.html", + """ <%namespace import="*" module="test.foo.test_ns"/> this is main. ${foo1()} ${foo2("hi")} -""") +""", + ) - assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi" + assert ( + flatten_result(collection.get_template("main.html").render()) + == "this is main. this is foo1. this is foo2, x is hi" + ) def test_module_imports_2(self): collection = lookup.TemplateLookup() - collection.put_string('main.html', """ + collection.put_string( + "main.html", + """ <%namespace import="foo1, foo2" module="test.foo.test_ns"/> this is main. ${foo1()} ${foo2("hi")} -""") +""", + ) - assert flatten_result(collection.get_template('main.html').render()) == "this is main. this is foo1. this is foo2, x is hi" + assert ( + flatten_result(collection.get_template("main.html").render()) + == "this is main. this is foo1. this is foo2, x is hi" + ) def test_context(self): """test that namespace callables get access to the current context""" collection = lookup.TemplateLookup() - collection.put_string('main.html', """ + collection.put_string( + "main.html", + """ <%namespace name="comp" file="defs.html"/> this is main. ${comp.def1()} ${comp.def2("there")} -""") +""", + ) - collection.put_string('defs.html', """ + collection.put_string( + "defs.html", + """ <%def name="def1()"> def1: x is ${x} </%def> @@ -188,14 +235,22 @@ class NamespaceTest(TemplateTest): <%def name="def2(x)"> def2: x is ${x} </%def> -""") +""", + ) - assert flatten_result(collection.get_template('main.html').render(x="context x")) == "this is main. def1: x is context x def2: x is there" + assert ( + flatten_result( + collection.get_template("main.html").render(x="context x") + ) + == "this is main. def1: x is context x def2: x is there" + ) def test_overload(self): collection = lookup.TemplateLookup() - collection.put_string('main.html', """ + collection.put_string( + "main.html", + """ <%namespace name="comp" file="defs.html"> <%def name="def1(x, y)"> overridden def1 ${x}, ${y} @@ -204,9 +259,12 @@ class NamespaceTest(TemplateTest): this is main. ${comp.def1("hi", "there")} ${comp.def2("there")} - """) + """, + ) - collection.put_string('defs.html', """ + collection.put_string( + "defs.html", + """ <%def name="def1(s)"> def1: ${s} </%def> @@ -214,13 +272,19 @@ class NamespaceTest(TemplateTest): <%def name="def2(x)"> def2: ${x} </%def> - """) + """, + ) - assert flatten_result(collection.get_template('main.html').render()) == "this is main. overridden def1 hi, there def2: there" + assert ( + flatten_result(collection.get_template("main.html").render()) + == "this is main. overridden def1 hi, there def2: there" + ) def test_getattr(self): collection = lookup.TemplateLookup() - collection.put_string("main.html", """ + collection.put_string( + "main.html", + """ <%namespace name="foo" file="ns.html"/> <% if hasattr(foo, 'lala'): @@ -228,72 +292,93 @@ class NamespaceTest(TemplateTest): if not hasattr(foo, 'hoho'): context.write('foo has no hoho.') %> - """) - collection.put_string("ns.html", """ + """, + ) + collection.put_string( + "ns.html", + """ <%def name="lala()">this is lala.</%def> - """) - assert flatten_result(collection.get_template("main.html").render()) == "this is lala.foo has no hoho." + """, + ) + assert ( + flatten_result(collection.get_template("main.html").render()) + == "this is lala.foo has no hoho." + ) def test_in_def(self): collection = lookup.TemplateLookup() - collection.put_string("main.html", """ + collection.put_string( + "main.html", + """ <%namespace name="foo" file="ns.html"/> this is main. ${bar()} <%def name="bar()"> this is bar, foo is ${foo.bar()} </%def> - """) + """, + ) - collection.put_string("ns.html", """ + collection.put_string( + "ns.html", + """ <%def name="bar()"> this is ns.html->bar </%def> - """) + """, + ) assert result_lines(collection.get_template("main.html").render()) == [ "this is main.", - "this is bar, foo is" , - "this is ns.html->bar" + "this is bar, foo is", + "this is ns.html->bar", ] - def test_in_remote_def(self): collection = lookup.TemplateLookup() - collection.put_string("main.html", """ + collection.put_string( + "main.html", + """ <%namespace name="foo" file="ns.html"/> this is main. ${bar()} <%def name="bar()"> this is bar, foo is ${foo.bar()} </%def> - """) + """, + ) - collection.put_string("ns.html", """ + collection.put_string( + "ns.html", + """ <%def name="bar()"> this is ns.html->bar </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%namespace name="main" file="main.html"/> this is index ${main.bar()} - """) + """, + ) - assert result_lines(collection.get_template("index.html").render()) == [ - "this is index", - "this is bar, foo is" , - "this is ns.html->bar" - ] + assert result_lines( + collection.get_template("index.html").render() + ) == ["this is index", "this is bar, foo is", "this is ns.html->bar"] def test_dont_pollute_self(self): # test that get_namespace() doesn't modify the original context # incompatibly collection = lookup.TemplateLookup() - collection.put_string("base.html", """ + collection.put_string( + "base.html", + """ <%def name="foo()"> <% @@ -313,16 +398,20 @@ class NamespaceTest(TemplateTest): </%def> - """) + """, + ) - collection.put_string("page.html", """ + collection.put_string( + "page.html", + """ <%inherit file="base.html"/> ${self.foo()} hello world - """) + """, + ) collection.put_string("foo.html", """<%inherit file="base.html"/>""") assert result_lines(collection.get_template("page.html").render()) == [ @@ -332,38 +421,49 @@ class NamespaceTest(TemplateTest): "hello world", "name: self:page.html", "name via bar:", - "self:page.html" + "self:page.html", ] def test_inheritance(self): - """test namespace initialization in a base inherited template that doesnt otherwise access the namespace""" + """test namespace initialization in a base inherited template that + doesnt otherwise access the namespace""" collection = lookup.TemplateLookup() - collection.put_string("base.html", """ + collection.put_string( + "base.html", + """ <%namespace name="foo" file="ns.html" inheritable="True"/> ${next.body()} -""") - collection.put_string("ns.html", """ +""", + ) + collection.put_string( + "ns.html", + """ <%def name="bar()"> this is ns.html->bar </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%inherit file="base.html"/> this is index ${self.foo.bar()} - """) + """, + ) - assert result_lines(collection.get_template("index.html").render()) == [ - "this is index", - "this is ns.html->bar" - ] + assert result_lines( + collection.get_template("index.html").render() + ) == ["this is index", "this is ns.html->bar"] def test_inheritance_two(self): collection = lookup.TemplateLookup() - collection.put_string("base.html", """ + collection.put_string( + "base.html", + """ <%def name="foo()"> base.foo </%def> @@ -371,8 +471,11 @@ class NamespaceTest(TemplateTest): <%def name="bat()"> base.bat </%def> -""") - collection.put_string("lib.html", """ +""", + ) + collection.put_string( + "lib.html", + """ <%inherit file="base.html"/> <%def name="bar()"> lib.bar @@ -386,19 +489,27 @@ class NamespaceTest(TemplateTest): lib.foo </%def> - """) + """, + ) - collection.put_string("front.html", """ + collection.put_string( + "front.html", + """ <%namespace name="lib" file="lib.html"/> ${lib.bar()} - """) + """, + ) - assert result_lines(collection.get_template("front.html").render()) == ['lib.bar', 'base.foo', 'lib.foo', 'base.bat', 'base.bat'] + assert result_lines( + collection.get_template("front.html").render() + ) == ["lib.bar", "base.foo", "lib.foo", "base.bat", "base.bat"] def test_attr(self): l = lookup.TemplateLookup() - l.put_string("foo.html", """ + l.put_string( + "foo.html", + """ <%! foofoo = "foo foo" onlyfoo = "only foo" @@ -414,9 +525,12 @@ class NamespaceTest(TemplateTest): ${self.attr.onlyfoo} ${self.attr.lala} ${self.attr.foolala} - """) + """, + ) - l.put_string("base.html", """ + l.put_string( + "base.html", + """ <%! basefoo = "base foo 1" foofoo = "base foo 2" @@ -433,7 +547,8 @@ class NamespaceTest(TemplateTest): ${self.attr.foolala} body ${self.body()} - """) + """, + ) assert result_lines(l.get_template("foo.html").render()) == [ "base foo 1", @@ -452,33 +567,43 @@ class NamespaceTest(TemplateTest): def test_attr_raise(self): l = lookup.TemplateLookup() - l.put_string("foo.html", """ + l.put_string( + "foo.html", + """ <%def name="foo()"> </%def> - """) + """, + ) - l.put_string("bar.html", """ + l.put_string( + "bar.html", + """ <%namespace name="foo" file="foo.html"/> ${foo.notfoo()} - """) + """, + ) self.assertRaises(AttributeError, l.get_template("bar.html").render) def test_custom_tag_1(self): - template = Template(""" + template = Template( + """ <%def name="foo(x, y)"> foo: ${x} ${y} </%def> <%self:foo x="5" y="${7+8}"/> - """) - assert result_lines(template.render()) == ['foo: 5 15'] + """ + ) + assert result_lines(template.render()) == ["foo: 5 15"] def test_custom_tag_2(self): collection = lookup.TemplateLookup() - collection.put_string("base.html", """ + collection.put_string( + "base.html", + """ <%def name="foo(x, y)"> foo: ${x} ${y} </%def> @@ -490,9 +615,12 @@ class NamespaceTest(TemplateTest): <%def name="bar(x)"> ${caller.body(z=x)} </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%namespace name="myns" file="base.html"/> <%myns:foo x="${'some x'}" y="some y"/> @@ -501,45 +629,57 @@ class NamespaceTest(TemplateTest): record: ${z} </%myns:bar> - """) + """, + ) - assert result_lines(collection.get_template("index.html").render()) == [ - 'foo: some x some y', - 'record: the bat! 10' - ] + assert result_lines( + collection.get_template("index.html").render() + ) == ["foo: some x some y", "record: the bat! 10"] def test_custom_tag_3(self): collection = lookup.TemplateLookup() - collection.put_string("base.html", """ + collection.put_string( + "base.html", + """ <%namespace name="foo" file="ns.html" inheritable="True"/> ${next.body()} - """) - collection.put_string("ns.html", """ + """, + ) + collection.put_string( + "ns.html", + """ <%def name="bar()"> this is ns.html->bar caller body: ${caller.body()} </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%inherit file="base.html"/> this is index <%self.foo:bar> call body </%self.foo:bar> - """) + """, + ) - assert result_lines(collection.get_template("index.html").render()) == [ + assert result_lines( + collection.get_template("index.html").render() + ) == [ "this is index", "this is ns.html->bar", "caller body:", - "call body" + "call body", ] def test_custom_tag_case_sensitive(self): - t = Template(""" + t = Template( + """ <%def name="renderPanel()"> panel ${caller.body()} </%def> @@ -551,67 +691,86 @@ class NamespaceTest(TemplateTest): </%def> <%self:renderTablePanel/> - """) - assert result_lines(t.render()) == ['panel', 'hi'] - + """ + ) + assert result_lines(t.render()) == ["panel", "hi"] def test_expr_grouping(self): - """test that parenthesis are placed around string-embedded expressions.""" + """test that parenthesis are placed around string-embedded + expressions.""" - template = Template(""" + template = Template( + """ <%def name="bar(x, y)"> ${x} ${y} </%def> <%self:bar x=" ${foo} " y="x${g and '1' or '2'}y"/> - """, input_encoding='utf-8') + """, + input_encoding="utf-8", + ) # the concat has to come out as "x + (g and '1' or '2') + y" - assert result_lines(template.render(foo='this is foo', g=False)) == [ + assert result_lines(template.render(foo="this is foo", g=False)) == [ "this is foo", - "x2y" + "x2y", ] - def test_ccall(self): collection = lookup.TemplateLookup() - collection.put_string("base.html", """ + collection.put_string( + "base.html", + """ <%namespace name="foo" file="ns.html" inheritable="True"/> ${next.body()} - """) - collection.put_string("ns.html", """ + """, + ) + collection.put_string( + "ns.html", + """ <%def name="bar()"> this is ns.html->bar caller body: ${caller.body()} </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%inherit file="base.html"/> this is index <%call expr="self.foo.bar()"> call body </%call> - """) + """, + ) - assert result_lines(collection.get_template("index.html").render()) == [ + assert result_lines( + collection.get_template("index.html").render() + ) == [ "this is index", "this is ns.html->bar", "caller body:", - "call body" + "call body", ] def test_ccall_2(self): collection = lookup.TemplateLookup() - collection.put_string("base.html", """ + collection.put_string( + "base.html", + """ <%namespace name="foo" file="ns1.html" inheritable="True"/> ${next.body()} - """) - collection.put_string("ns1.html", """ + """, + ) + collection.put_string( + "ns1.html", + """ <%namespace name="foo2" file="ns2.html"/> <%def name="bar()"> <%call expr="foo2.ns2_bar()"> @@ -619,36 +778,47 @@ class NamespaceTest(TemplateTest): caller body: ${caller.body()} </%call> </%def> - """) + """, + ) - collection.put_string("ns2.html", """ + collection.put_string( + "ns2.html", + """ <%def name="ns2_bar()"> this is ns2.html->bar caller body: ${caller.body()} </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%inherit file="base.html"/> this is index <%call expr="self.foo.bar()"> call body </%call> - """) + """, + ) - assert result_lines(collection.get_template("index.html").render()) == [ + assert result_lines( + collection.get_template("index.html").render() + ) == [ "this is index", "this is ns2.html->bar", "caller body:", "this is ns1.html->bar", "caller body:", - "call body" + "call body", ] def test_import(self): collection = lookup.TemplateLookup() - collection.put_string("functions.html",""" + collection.put_string( + "functions.html", + """ <%def name="foo()"> this is foo </%def> @@ -660,17 +830,23 @@ class NamespaceTest(TemplateTest): <%def name="lala()"> this is lala </%def> - """) + """, + ) - collection.put_string("func2.html", """ + collection.put_string( + "func2.html", + """ <%def name="a()"> this is a </%def> <%def name="b()"> this is b </%def> - """) - collection.put_string("index.html", """ + """, + ) + collection.put_string( + "index.html", + """ <%namespace file="functions.html" import="*"/> <%namespace file="func2.html" import="a, b"/> ${foo()} @@ -679,26 +855,36 @@ class NamespaceTest(TemplateTest): ${a()} ${b()} ${x} - """) + """, + ) - assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [ + assert result_lines( + collection.get_template("index.html").render( + bar="this is bar", x="this is x" + ) + ) == [ "this is foo", "this is bar", "this is lala", "this is a", "this is b", - "this is x" + "this is x", ] def test_import_calledfromdef(self): l = lookup.TemplateLookup() - l.put_string("a", """ + l.put_string( + "a", + """ <%def name="table()"> im table </%def> - """) + """, + ) - l.put_string("b",""" + l.put_string( + "b", + """ <%namespace file="a" import="table"/> <% @@ -708,14 +894,17 @@ class NamespaceTest(TemplateTest): %> ${table2()} - """) + """, + ) t = l.get_template("b") assert flatten_result(t.render()) == "im table" def test_closure_import(self): collection = lookup.TemplateLookup() - collection.put_string("functions.html",""" + collection.put_string( + "functions.html", + """ <%def name="foo()"> this is foo </%def> @@ -723,9 +912,12 @@ class NamespaceTest(TemplateTest): <%def name="bar()"> this is bar </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%namespace file="functions.html" import="*"/> <%def name="cl1()"> ${foo()} @@ -737,14 +929,17 @@ class NamespaceTest(TemplateTest): ${cl1()} ${cl2()} - """) - assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [ - "this is foo", - "this is bar", - ] + """, + ) + assert result_lines( + collection.get_template("index.html").render( + bar="this is bar", x="this is x" + ) + ) == ["this is foo", "this is bar"] def test_import_local(self): - t = Template(""" + t = Template( + """ <%namespace import="*"> <%def name="foo()"> this is foo @@ -753,12 +948,15 @@ class NamespaceTest(TemplateTest): ${foo()} - """) + """ + ) assert flatten_result(t.render()) == "this is foo" def test_ccall_import(self): collection = lookup.TemplateLookup() - collection.put_string("functions.html",""" + collection.put_string( + "functions.html", + """ <%def name="foo()"> this is foo </%def> @@ -768,9 +966,12 @@ class NamespaceTest(TemplateTest): ${caller.body()} ${caller.lala()} </%def> - """) + """, + ) - collection.put_string("index.html", """ + collection.put_string( + "index.html", + """ <%namespace name="func" file="functions.html" import="*"/> <%call expr="bar()"> this is index embedded @@ -779,14 +980,17 @@ class NamespaceTest(TemplateTest): this is lala ${foo()} </%def> </%call> - """) - #print collection.get_template("index.html").code - #print collection.get_template("functions.html").code - assert result_lines(collection.get_template("index.html").render()) == [ + """, + ) + # print collection.get_template("index.html").code + # print collection.get_template("functions.html").code + assert result_lines( + collection.get_template("index.html").render() + ) == [ "this is bar.", "this is index embedded", "foo is", "this is foo", "this is lala", - "this is foo" + "this is foo", ] diff --git a/test/test_pygen.py b/test/test_pygen.py index 7671bd9..daa76de 100644 --- a/test/test_pygen.py +++ b/test/test_pygen.py @@ -1,7 +1,8 @@ import unittest -from mako.pygen import PythonPrinter, adjust_whitespace from mako.compat import StringIO +from mako.pygen import adjust_whitespace +from mako.pygen import PythonPrinter from test import eq_ @@ -14,12 +15,15 @@ class GeneratePythonTest(unittest.TestCase): printer.writeline("print x") printer.writeline(None) printer.writeline("print y") - assert stream.getvalue() == \ -"""import lala + assert ( + stream.getvalue() + == """import lala for x in foo: print x print y """ + ) + def test_generate_adjusted(self): block = """ x = 5 +6 @@ -31,18 +35,20 @@ print y printer = PythonPrinter(stream) printer.write_indented_block(block) printer.close() - #print stream.getvalue() - assert stream.getvalue() == \ -""" + # print stream.getvalue() + assert ( + stream.getvalue() + == """ x = 5 +6 if x > 7: for y in range(1,5): print "<td>%s</td>" % y """ + ) + def test_generate_combo(self): - block = \ -""" + block = """ x = 5 +6 if x > 7: for y in range(1,5): @@ -60,9 +66,10 @@ if x > 7: printer.writeline(None) printer.writeline("print y") printer.close() - #print "->" + stream.getvalue().replace(' ', '#') + "<-" - eq_(stream.getvalue(), -"""import lala + # print "->" + stream.getvalue().replace(' ', '#') + "<-" + eq_( + stream.getvalue(), + """import lala for x in foo: print x @@ -75,10 +82,11 @@ for x in foo: foo(lala) print y -""") +""", + ) + def test_multi_line(self): - block = \ -""" + block = """ if test: print ''' this is a block of stuff. this is more stuff in the block. @@ -90,9 +98,10 @@ and more block. printer = PythonPrinter(stream) printer.write_indented_block(block) printer.close() - #print stream.getvalue() - assert stream.getvalue() == \ -""" + # print stream.getvalue() + assert ( + stream.getvalue() + == """ if test: print ''' this is a block of stuff. this is more stuff in the block. @@ -101,6 +110,7 @@ and more block. do_more_stuff(g) """ + ) def test_false_unindentor(self): stream = StringIO() @@ -113,23 +123,23 @@ and more block. None, "finally:", "dosomething", - None + None, ]: printer.writeline(line) - assert stream.getvalue() == \ -"""try: + assert ( + stream.getvalue() + == """try: elsemyvar = 12 if True: print 'hi' finally: dosomething -""" , stream.getvalue() - +""" + ), stream.getvalue() def test_backslash_line(self): - block = \ -""" + block = """ # comment if test: if (lala + hoho) + \\ @@ -141,8 +151,9 @@ finally: printer = PythonPrinter(stream) printer.write_indented_block(block) printer.close() - assert stream.getvalue() == \ -""" + assert ( + stream.getvalue() + == """ # comment if test: if (lala + hoho) + \\ @@ -151,6 +162,8 @@ if test: print "more indent" """ + ) + class WhitespaceTest(unittest.TestCase): def test_basic(self): @@ -159,12 +172,14 @@ class WhitespaceTest(unittest.TestCase): print x print "hi" """ - assert adjust_whitespace(text) == \ -""" + assert ( + adjust_whitespace(text) + == """ for x in range(0,15): print x print "hi" """ + ) def test_blank_lines(self): text = """ @@ -174,14 +189,16 @@ print "hi" print g """ - assert adjust_whitespace(text) == \ -""" + assert ( + adjust_whitespace(text) + == """ print "hi" # a comment # more comments print g """ + ) def test_open_quotes_with_pound(self): text = ''' @@ -189,15 +206,17 @@ print g # and this is text # and this is too """ ''' - assert adjust_whitespace(text) == \ -''' + assert ( + adjust_whitespace(text) + == ''' print """ this is text # and this is text # and this is too """ ''' + ) def test_quote_with_comments(self): - text= """ + text = """ print 'hi' # this is a comment # another comment @@ -208,8 +227,9 @@ print """ this is text # someone else's comment """ - assert adjust_whitespace(text) == \ -""" + assert ( + adjust_whitespace(text) + == """ print 'hi' # this is a comment # another comment @@ -219,7 +239,7 @@ print ''' ''' # someone else's comment """ - + ) def test_quotes_with_pound(self): text = ''' @@ -228,13 +248,15 @@ print ''' elif False: "bar" ''' - assert adjust_whitespace(text) == \ -''' + assert ( + adjust_whitespace(text) + == ''' if True: """#""" elif False: "bar" ''' + ) def test_quotes(self): text = """ @@ -244,11 +266,13 @@ asdkfjnads kfajns ''' if x: print y """ - assert adjust_whitespace(text) == \ -""" + assert ( + adjust_whitespace(text) + == """ print ''' aslkjfnas kjdfn askdjfnaskfd fkasnf dknf sadkfjn asdkfjna sdakjn asdkfjnads kfajns ''' if x: print y """ + ) diff --git a/test/test_runtime.py b/test/test_runtime.py index 80b97ce..d87d264 100644 --- a/test/test_runtime.py +++ b/test/test_runtime.py @@ -1,21 +1,21 @@ """Assorted runtime unit tests """ -from mako import runtime import unittest + +from mako import runtime from test import eq_ + class ContextTest(unittest.TestCase): def test_locals_kwargs(self): - c = runtime.Context(None, foo='bar') - eq_(c.kwargs, {'foo': 'bar'}) + c = runtime.Context(None, foo="bar") + eq_(c.kwargs, {"foo": "bar"}) - d = c._locals({'zig': 'zag'}) + d = c._locals({"zig": "zag"}) # kwargs is the original args sent to the Context, # it's intentionally kept separate from _data - eq_(c.kwargs, {'foo': 'bar'}) - eq_(d.kwargs, {'foo': 'bar'}) - - eq_(d._data['zig'], 'zag') - + eq_(c.kwargs, {"foo": "bar"}) + eq_(d.kwargs, {"foo": "bar"}) + eq_(d._data["zig"], "zag") diff --git a/test/test_template.py b/test/test_template.py index 1f2d0c1..89e5a61 100644 --- a/test/test_template.py +++ b/test/test_template.py @@ -1,17 +1,28 @@ # -*- coding: utf-8 -*- -from mako.template import Template, ModuleTemplate, ModuleInfo -from mako.lookup import TemplateLookup -from mako.ext.preprocessors import convert_comments -from mako import exceptions, runtime +import os +import unittest + from mako import compat +from mako import exceptions +from mako import runtime from mako import util -import os -from test.util import flatten_result, result_lines from mako.compat import u -from test import TemplateTest, eq_, template_base, module_base, \ - assert_raises, assert_raises_message, requires_python_2 -import unittest +from mako.ext.preprocessors import convert_comments +from mako.lookup import TemplateLookup +from mako.template import ModuleInfo +from mako.template import ModuleTemplate +from mako.template import Template +from test import assert_raises +from test import assert_raises_message +from test import eq_ +from test import module_base +from test import requires_python_2 +from test import template_base +from test import TemplateTest +from test.util import flatten_result +from test.util import result_lines + class ctx(object): def __init__(self, a, b): @@ -23,14 +34,17 @@ class ctx(object): def __exit__(self, *arg): pass + class EncodingTest(TemplateTest): def test_escapes_html_tags(self): from mako.exceptions import html_error_template - x = Template(""" + x = Template( + """ X: <% raise Exception('<span style="color:red">Foobar</span>') %> - """) + """ + ) try: x.render() @@ -38,254 +52,390 @@ class EncodingTest(TemplateTest): # <h3>Exception: <span style="color:red">Foobar</span></h3> markup = html_error_template().render(full=False, css=False) if compat.py3k: - assert '<span style="color:red">Foobar</span></h3>'\ - .encode('ascii') not in markup - assert '<span style="color:red"'\ - '>Foobar</span>'\ - .encode('ascii') in markup + assert ( + '<span style="color:red">Foobar</span></h3>'.encode( + "ascii" + ) + not in markup + ) + assert ( + "<span style="color:red"" + ">Foobar</span>".encode("ascii") in markup + ) else: - assert '<span style="color:red">Foobar</span></h3>' \ - not in markup - assert '<span style="color:red"'\ - '>Foobar</span>' in markup + assert ( + '<span style="color:red">Foobar</span></h3>' not in markup + ) + assert ( + "<span style="color:red"" + ">Foobar</span>" in markup + ) def test_unicode(self): self._do_memory_test( - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), ) def test_encoding_doesnt_conflict(self): self._do_memory_test( - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - output_encoding='utf-8' + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + output_encoding="utf-8", ) def test_unicode_arg(self): - val = u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + val = u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ) self._do_memory_test( "${val}", - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - template_args={'val':val} + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + template_args={"val": val}, ) def test_unicode_file(self): self._do_file_test( "unicode.html", - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), ) def test_unicode_file_code(self): self._do_file_test( - 'unicode_code.html', + "unicode_code.html", u("""hi, drôle de petite voix m’a réveillé."""), - filters=flatten_result + filters=flatten_result, ) def test_unicode_file_lookup(self): lookup = TemplateLookup( - directories=[template_base], - output_encoding='utf-8', - default_filters=['decode.utf8']) + directories=[template_base], + output_encoding="utf-8", + default_filters=["decode.utf8"], + ) if compat.py3k: - template = lookup.get_template('/chs_unicode_py3k.html') + template = lookup.get_template("/chs_unicode_py3k.html") else: - template = lookup.get_template('/chs_unicode.html') + template = lookup.get_template("/chs_unicode.html") eq_( - flatten_result(template.render_unicode(name='毛泽东')), - u('毛泽东 是 新中国的主席<br/> Welcome 你 to 北京.') + flatten_result(template.render_unicode(name="毛泽东")), + u("毛泽东 是 新中国的主席<br/> Welcome 你 to 北京."), ) def test_unicode_bom(self): self._do_file_test( - 'bom.html', - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + "bom.html", + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), ) self._do_file_test( - 'bommagic.html', - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + "bommagic.html", + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), ) self.assertRaises( exceptions.CompileException, - Template, filename=self._file_path('badbom.html'), - module_directory=module_base + Template, + filename=self._file_path("badbom.html"), + module_directory=module_base, ) def test_unicode_memory(self): - val = u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + val = u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ) self._do_memory_test( - ("## -*- coding: utf-8 -*-\n" + val).encode('utf-8'), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), ) def test_unicode_text(self): - val = u("""<%text>Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »</%text>""") + val = u( + "<%text>Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »</%text>" + ) self._do_memory_test( - ("## -*- coding: utf-8 -*-\n" + val).encode('utf-8'), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""") + ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), ) def test_unicode_text_ccall(self): - val = u(""" + val = u( + """ <%def name="foo()"> ${capture(caller.body)} </%def> <%call expr="foo()"> - <%text>Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »</%text> - </%call>""") + <%text>Alors vous imaginez ma surprise, au lever du jour, +quand une drôle de petite voix m’a réveillé. Elle disait: +« S’il vous plaît… dessine-moi un mouton! »</%text> + </%call>""" + ) self._do_memory_test( - ("## -*- coding: utf-8 -*-\n" + val).encode('utf-8'), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - filters=flatten_result + ("## -*- coding: utf-8 -*-\n" + val).encode("utf-8"), + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + filters=flatten_result, ) def test_unicode_literal_in_expr(self): if compat.py3k: self._do_memory_test( - u("""## -*- coding: utf-8 -*- - ${"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"} - """).encode('utf-8'), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - filters = lambda s:s.strip() + u( + "## -*- coding: utf-8 -*-\n" + '${"Alors vous imaginez ma surprise, au lever du jour, ' + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: " + '« S’il vous plaît… dessine-moi un mouton! »"}\n' + ).encode("utf-8"), + u( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + filters=lambda s: s.strip(), ) else: self._do_memory_test( - u("""## -*- coding: utf-8 -*- - ${u"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"} - """).encode('utf-8'), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - filters = lambda s:s.strip() + u( + "## -*- coding: utf-8 -*-\n" + '${u"Alors vous imaginez ma surprise, au lever du jour, ' + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un " + 'mouton! »"}' + ).encode("utf-8"), + u( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + filters=lambda s: s.strip(), ) def test_unicode_literal_in_expr_file(self): self._do_file_test( - 'unicode_expr.html', - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - lambda t:t.strip() + "unicode_expr.html", + u( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + lambda t: t.strip(), ) def test_unicode_literal_in_code(self): if compat.py3k: self._do_memory_test( - u("""## -*- coding: utf-8 -*- + u( + """## -*- coding: utf-8 -*- <% - context.write("Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »") + context.write("Alors vous imaginez ma surprise, au """ + """lever du jour, quand une drôle de petite voix m’a """ + """réveillé. Elle disait: """ + """« S’il vous plaît… dessine-moi un mouton! »") %> - """).encode('utf-8'), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - filters=lambda s:s.strip() + """ + ).encode("utf-8"), + u( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + filters=lambda s: s.strip(), ) else: self._do_memory_test( - u("""## -*- coding: utf-8 -*- + u( + """## -*- coding: utf-8 -*- <% - context.write(u"Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »") + context.write(u"Alors vous imaginez ma surprise, """ + """au lever du jour, quand une drôle de petite voix """ + """m’a réveillé. Elle disait: « S’il vous plaît… """ + """dessine-moi un mouton! »") %> - """).encode('utf-8'), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - filters=lambda s:s.strip() + """ + ).encode("utf-8"), + u( + "Alors vous imaginez ma surprise, au lever du jour, " + "quand une drôle de petite voix m’a réveillé. " + "Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + ), + filters=lambda s: s.strip(), ) def test_unicode_literal_in_controlline(self): if compat.py3k: self._do_memory_test( - u("""## -*- coding: utf-8 -*- + u( + """## -*- coding: utf-8 -*- <% x = "drôle de petite voix m’a réveillé." %> % if x=="drôle de petite voix m’a réveillé.": hi, ${x} % endif - """).encode('utf-8'), + """ + ).encode("utf-8"), u("""hi, drôle de petite voix m’a réveillé."""), - filters=lambda s:s.strip(), + filters=lambda s: s.strip(), ) else: self._do_memory_test( - u("""## -*- coding: utf-8 -*- + u( + """## -*- coding: utf-8 -*- <% x = u"drôle de petite voix m’a réveillé." %> % if x==u"drôle de petite voix m’a réveillé.": hi, ${x} % endif - """).encode('utf-8'), + """ + ).encode("utf-8"), u("""hi, drôle de petite voix m’a réveillé."""), - filters=lambda s:s.strip(), + filters=lambda s: s.strip(), ) def test_unicode_literal_in_tag(self): self._do_file_test( "unicode_arguments.html", [ - u('x is: drôle de petite voix m’a réveillé'), - u('x is: drôle de petite voix m’a réveillé'), - u('x is: drôle de petite voix m’a réveillé'), - u('x is: drôle de petite voix m’a réveillé'), + u("x is: drôle de petite voix m’a réveillé"), + u("x is: drôle de petite voix m’a réveillé"), + u("x is: drôle de petite voix m’a réveillé"), + u("x is: drôle de petite voix m’a réveillé"), ], - filters=result_lines + filters=result_lines, ) self._do_memory_test( util.read_file(self._file_path("unicode_arguments.html")), [ - u('x is: drôle de petite voix m’a réveillé'), - u('x is: drôle de petite voix m’a réveillé'), - u('x is: drôle de petite voix m’a réveillé'), - u('x is: drôle de petite voix m’a réveillé'), + u("x is: drôle de petite voix m’a réveillé"), + u("x is: drôle de petite voix m’a réveillé"), + u("x is: drôle de petite voix m’a réveillé"), + u("x is: drôle de petite voix m’a réveillé"), ], - filters=result_lines + filters=result_lines, ) def test_unicode_literal_in_def(self): if compat.py3k: self._do_memory_test( - u("""## -*- coding: utf-8 -*- + u( + """## -*- coding: utf-8 -*- <%def name="bello(foo, bar)"> Foo: ${ foo } Bar: ${ bar } </%def> - <%call expr="bello(foo='árvíztűrő tükörfúrógép', bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> - </%call>""").encode('utf-8'), - u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""), - filters=flatten_result + <%call expr="bello(foo='árvíztűrő tükörfúrógép', """ + """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> + </%call>""" + ).encode("utf-8"), + u( + """Foo: árvíztűrő tükörfúrógép """ + """Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" + ), + filters=flatten_result, ) self._do_memory_test( - u("""## -*- coding: utf-8 -*- - <%def name="hello(foo='árvíztűrő tükörfúrógép', bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> - Foo: ${ foo } - Bar: ${ bar } - </%def> - ${ hello() }""").encode('utf-8'), - u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""), - filters=flatten_result + u( + "## -*- coding: utf-8 -*-\n" + """<%def name="hello(foo='árvíztűrő tükörfúrógép', """ + """bar='ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')">\n""" + "Foo: ${ foo }\n" + "Bar: ${ bar }\n" + "</%def>\n" + "${ hello() }" + ).encode("utf-8"), + u( + """Foo: árvíztűrő tükörfúrógép Bar: """ + """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" + ), + filters=flatten_result, ) else: self._do_memory_test( - u("""## -*- coding: utf-8 -*- + u( + """## -*- coding: utf-8 -*- <%def name="bello(foo, bar)"> Foo: ${ foo } Bar: ${ bar } </%def> - <%call expr="bello(foo=u'árvíztűrő tükörfúrógép', bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> - </%call>""").encode('utf-8'), - u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""), - filters=flatten_result + <%call expr="bello(foo=u'árvíztűrő tükörfúrógép', """ + """bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> + </%call>""" + ).encode("utf-8"), + u( + """Foo: árvíztűrő tükörfúrógép Bar: """ + """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" + ), + filters=flatten_result, ) self._do_memory_test( - u("""## -*- coding: utf-8 -*- - <%def name="hello(foo=u'árvíztűrő tükörfúrógép', bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> + u( + """## -*- coding: utf-8 -*- + <%def name="hello(foo=u'árvíztűrő tükörfúrógép', """ + """bar=u'ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP')"> Foo: ${ foo } Bar: ${ bar } </%def> - ${ hello() }""").encode('utf-8'), - u("""Foo: árvíztűrő tükörfúrógép Bar: ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP"""), - filters=flatten_result + ${ hello() }""" + ).encode("utf-8"), + u( + """Foo: árvíztűrő tükörfúrógép Bar: """ + """ÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP""" + ), + filters=flatten_result, ) def test_input_encoding(self): @@ -296,32 +446,32 @@ class EncodingTest(TemplateTest): self._do_memory_test( u("hello ${f('śląsk')}"), u("hello śląsk"), - input_encoding='utf-8', - template_args={'f': lambda x:x} + input_encoding="utf-8", + template_args={"f": lambda x: x}, ) self._do_memory_test( u("## -*- coding: utf-8 -*-\nhello ${f('śląsk')}"), u("hello śląsk"), - template_args={'f': lambda x:x} + template_args={"f": lambda x: x}, ) else: self._do_memory_test( u("hello ${f(u'śląsk')}"), u("hello śląsk"), - input_encoding='utf-8', - template_args={'f': lambda x:x} + input_encoding="utf-8", + template_args={"f": lambda x: x}, ) self._do_memory_test( u("## -*- coding: utf-8 -*-\nhello ${f(u'śląsk')}"), u("hello śląsk"), - template_args={'f': lambda x:x} + template_args={"f": lambda x: x}, ) def test_raw_strings(self): - """test that raw strings go straight thru with default_filters turned off, - bytestring_passthrough enabled. + """test that raw strings go straight thru with default_filters + turned off, bytestring_passthrough enabled. """ @@ -329,75 +479,101 @@ class EncodingTest(TemplateTest): u("## -*- coding: utf-8 -*-\nhello ${x}"), "hello śląsk", default_filters=[], - template_args={'x':'śląsk'}, + template_args={"x": "śląsk"}, unicode_=False, bytestring_passthrough=True, - output_encoding=None #'ascii' + output_encoding=None, # 'ascii' ) # now, the way you *should* be doing it.... self._do_memory_test( u("## -*- coding: utf-8 -*-\nhello ${x}"), u("hello śląsk"), - template_args={'x':u('śląsk')} + template_args={"x": u("śląsk")}, ) def test_encoding(self): self._do_memory_test( - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""), - u("""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petite voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »""").encode('utf-8'), - output_encoding='utf-8', - unicode_=False + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ), + u( + "Alors vous imaginez ma surprise, au lever du jour, quand " + "une drôle de petite voix m’a réveillé. Elle disait: " + "« S’il vous plaît… dessine-moi un mouton! »" + ).encode("utf-8"), + output_encoding="utf-8", + unicode_=False, ) def test_encoding_errors(self): self._do_memory_test( - u("""KGB (transliteration of "КГБ") is the Russian-language abbreviation for Committee for State Security, (Russian: Комит́ет Госуд́арственной Безоп́асности (help·info); Komitet Gosudarstvennoy Bezopasnosti)"""), - u("""KGB (transliteration of "КГБ") is the Russian-language abbreviation for Committee for State Security, (Russian: Комит́ет Госуд́арственной Безоп́асности (help·info); Komitet Gosudarstvennoy Bezopasnosti)""").encode('iso-8859-1', 'replace'), - output_encoding='iso-8859-1', encoding_errors='replace', - unicode_=False + u( + """KGB (transliteration of "КГБ") is the Russian-language """ + """abbreviation for Committee for State Security, """ + """(Russian: Комит́ет Госуд́арственной Безоп́асности """ + """(help·info); Komitet Gosudarstvennoy Bezopasnosti)""" + ), + u( + """KGB (transliteration of "КГБ") is the Russian-language """ + """abbreviation for Committee for State Security, """ + """(Russian: Комит́ет Госуд́арственной Безоп́асности """ + """(help·info); Komitet Gosudarstvennoy Bezopasnosti)""" + ).encode("iso-8859-1", "replace"), + output_encoding="iso-8859-1", + encoding_errors="replace", + unicode_=False, ) def test_read_unicode(self): - lookup = TemplateLookup(directories=[template_base], - filesystem_checks=True, output_encoding='utf-8') + lookup = TemplateLookup( + directories=[template_base], + filesystem_checks=True, + output_encoding="utf-8", + ) if compat.py3k: - template = lookup.get_template('/read_unicode_py3k.html') + template = lookup.get_template("/read_unicode_py3k.html") else: - template = lookup.get_template('/read_unicode.html') + template = lookup.get_template("/read_unicode.html") # TODO: I've no idea what encoding this file is, Python 3.1.2 # won't read the file even with open(...encoding='utf-8') unless # errors is specified. or if there's some quirk in 3.1.2 # since I'm pretty sure this test worked with py3k when I wrote it. - data = template.render(path=self._file_path('internationalization.html')) + template.render( + path=self._file_path("internationalization.html") + ) @requires_python_2 def test_bytestring_passthru(self): self._do_file_test( - 'chs_utf8.html', - '毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.', + "chs_utf8.html", + "毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.", default_filters=[], disable_unicode=True, output_encoding=None, - template_args={'name':'毛泽东'}, + template_args={"name": "毛泽东"}, filters=flatten_result, - unicode_=False + unicode_=False, ) self._do_file_test( - 'chs_utf8.html', - '毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.', + "chs_utf8.html", + "毛泽东 是 新中国的主席<br/> Welcome 你 to 北京. Welcome 你 to 北京.", disable_unicode=True, output_encoding=None, - template_args={'name':'毛泽东'}, + template_args={"name": "毛泽东"}, filters=flatten_result, - unicode_=False + unicode_=False, ) - template = self._file_template('chs_utf8.html', - output_encoding=None, - disable_unicode=True) - self.assertRaises(UnicodeDecodeError, template.render_unicode, name='毛泽东') + template = self._file_template( + "chs_utf8.html", output_encoding=None, disable_unicode=True + ) + self.assertRaises( + UnicodeDecodeError, template.render_unicode, name="毛泽东" + ) template = Template( "${'Alors vous imaginez ma surprise, au lever" @@ -405,400 +581,531 @@ class EncodingTest(TemplateTest): "réveillé. Elle disait: « S’il vous plaît… " "dessine-moi un mouton! »'}", output_encoding=None, - disable_unicode=True, input_encoding='utf-8') - assert template.render() == "Alors vous imaginez ma surprise, "\ - "au lever du jour, quand une drôle de petite "\ - "voix m’a réveillé. Elle disait: « S’il vous "\ - "plaît… dessine-moi un mouton! »" + disable_unicode=True, + input_encoding="utf-8", + ) + assert ( + template.render() == "Alors vous imaginez ma surprise, " + "au lever du jour, quand une drôle de petite " + "voix m’a réveillé. Elle disait: « S’il vous " + "plaît… dessine-moi un mouton! »" + ) template = Template( - "${'Alors vous imaginez ma surprise, au " - "lever du jour, quand une drôle de petite " - "voix m’a réveillé. Elle disait: « S’il " - "vous plaît… dessine-moi un mouton! »'}", - input_encoding='utf8', output_encoding='utf8', - disable_unicode=False, default_filters=[]) - # raises because expression contains an encoded bytestring which cannot be decoded + "${'Alors vous imaginez ma surprise, au " + "lever du jour, quand une drôle de petite " + "voix m’a réveillé. Elle disait: « S’il " + "vous plaît… dessine-moi un mouton! »'}", + input_encoding="utf8", + output_encoding="utf8", + disable_unicode=False, + default_filters=[], + ) + # raises because expression contains an encoded bytestring which cannot + # be decoded self.assertRaises(UnicodeDecodeError, template.render) class PageArgsTest(TemplateTest): def test_basic(self): - template = Template(""" + template = Template( + """ <%page args="x, y, z=7"/> this is page, ${x}, ${y}, ${z} -""") +""" + ) - assert flatten_result(template.render(x=5, y=10)) == "this is page, 5, 10, 7" - assert flatten_result(template.render(x=5, y=10, z=32)) == "this is page, 5, 10, 32" + assert ( + flatten_result(template.render(x=5, y=10)) + == "this is page, 5, 10, 7" + ) + assert ( + flatten_result(template.render(x=5, y=10, z=32)) + == "this is page, 5, 10, 32" + ) assert_raises(TypeError, template.render, y=10) def test_inherits(self): lookup = TemplateLookup() - lookup.put_string("base.tmpl", - """ + lookup.put_string( + "base.tmpl", + """ <%page args="bar" /> ${bar} ${pageargs['foo']} ${self.body(**pageargs)} - """ + """, ) - lookup.put_string("index.tmpl", """ + lookup.put_string( + "index.tmpl", + """ <%inherit file="base.tmpl" /> <%page args="variable" /> ${variable} - """) + """, + ) self._do_test( lookup.get_template("index.tmpl"), "bar foo var", filters=flatten_result, - template_args={'variable':'var', 'bar':'bar', 'foo':'foo'} - + template_args={"variable": "var", "bar": "bar", "foo": "foo"}, ) def test_includes(self): lookup = TemplateLookup() - lookup.put_string("incl1.tmpl", - """ + lookup.put_string( + "incl1.tmpl", + """ <%page args="bar" /> ${bar} ${pageargs['foo']} - """ + """, ) - lookup.put_string("incl2.tmpl", - """ + lookup.put_string( + "incl2.tmpl", + """ ${pageargs} - """ + """, ) - lookup.put_string("index.tmpl", """ + lookup.put_string( + "index.tmpl", + """ <%include file="incl1.tmpl" args="**pageargs"/> <%page args="variable" /> ${variable} <%include file="incl2.tmpl" /> - """) + """, + ) self._do_test( lookup.get_template("index.tmpl"), "bar foo var {}", filters=flatten_result, - template_args={'variable':'var', 'bar':'bar', 'foo':'foo'} - + template_args={"variable": "var", "bar": "bar", "foo": "foo"}, ) def test_context_small(self): ctx = runtime.Context([].append, x=5, y=4) - eq_(sorted(ctx.keys()), ['caller', 'capture', 'x', 'y']) + eq_(sorted(ctx.keys()), ["caller", "capture", "x", "y"]) def test_with_context(self): - template = Template(""" + template = Template( + """ <%page args="x, y, z=7"/> this is page, ${x}, ${y}, ${z}, ${w} -""") - #print template.code - assert flatten_result(template.render(x=5, y=10, w=17)) == "this is page, 5, 10, 7, 17" +""" + ) + # print template.code + assert ( + flatten_result(template.render(x=5, y=10, w=17)) + == "this is page, 5, 10, 7, 17" + ) def test_overrides_builtins(self): - template = Template(""" + template = Template( + """ <%page args="id"/> this is page, id is ${id} - """) + """ + ) - assert flatten_result(template.render(id="im the id")) == "this is page, id is im the id" + assert ( + flatten_result(template.render(id="im the id")) + == "this is page, id is im the id" + ) def test_canuse_builtin_names(self): - template = Template(""" + template = Template( + """ exception: ${Exception} id: ${id} - """) - assert flatten_result(template.render(id='some id', Exception='some exception')) == "exception: some exception id: some id" + """ + ) + assert ( + flatten_result( + template.render(id="some id", Exception="some exception") + ) + == "exception: some exception id: some id" + ) def test_builtin_names_dont_clobber_defaults_in_includes(self): lookup = TemplateLookup() - lookup.put_string("test.mako", - """ + lookup.put_string( + "test.mako", + """ <%include file="test1.mako"/> - """) + """, + ) - lookup.put_string("test1.mako", """ + lookup.put_string( + "test1.mako", + """ <%page args="id='foo'"/> ${id} - """) + """, + ) for template in ("test.mako", "test1.mako"): - assert flatten_result(lookup.get_template(template).render()) == "foo" - assert flatten_result(lookup.get_template(template).render(id=5)) == "5" - assert flatten_result(lookup.get_template(template).render(id=id)) == "<built-in function id>" + assert ( + flatten_result(lookup.get_template(template).render()) == "foo" + ) + assert ( + flatten_result(lookup.get_template(template).render(id=5)) + == "5" + ) + assert ( + flatten_result(lookup.get_template(template).render(id=id)) + == "<built-in function id>" + ) def test_dict_locals(self): - template = Template(""" + template = Template( + """ <% dict = "this is dict" locals = "this is locals" %> dict: ${dict} locals: ${locals} - """) - assert flatten_result(template.render()) == "dict: this is dict locals: this is locals" + """ + ) + assert ( + flatten_result(template.render()) + == "dict: this is dict locals: this is locals" + ) + class IncludeTest(TemplateTest): def test_basic(self): lookup = TemplateLookup() - lookup.put_string("a", """ + lookup.put_string( + "a", + """ this is a <%include file="b" args="a=3,b=4,c=5"/> - """) - lookup.put_string("b", """ + """, + ) + lookup.put_string( + "b", + """ <%page args="a,b,c"/> this is b. ${a}, ${b}, ${c} - """) - assert flatten_result(lookup.get_template("a").render()) == "this is a this is b. 3, 4, 5" + """, + ) + assert ( + flatten_result(lookup.get_template("a").render()) + == "this is a this is b. 3, 4, 5" + ) def test_localargs(self): lookup = TemplateLookup() - lookup.put_string("a", """ + lookup.put_string( + "a", + """ this is a <%include file="b" args="a=a,b=b,c=5"/> - """) - lookup.put_string("b", """ + """, + ) + lookup.put_string( + "b", + """ <%page args="a,b,c"/> this is b. ${a}, ${b}, ${c} - """) - assert flatten_result(lookup.get_template("a").render(a=7,b=8)) == "this is a this is b. 7, 8, 5" + """, + ) + assert ( + flatten_result(lookup.get_template("a").render(a=7, b=8)) + == "this is a this is b. 7, 8, 5" + ) def test_viakwargs(self): lookup = TemplateLookup() - lookup.put_string("a", """ + lookup.put_string( + "a", + """ this is a <%include file="b" args="c=5, **context.kwargs"/> - """) - lookup.put_string("b", """ + """, + ) + lookup.put_string( + "b", + """ <%page args="a,b,c"/> this is b. ${a}, ${b}, ${c} - """) - #print lookup.get_template("a").code - assert flatten_result(lookup.get_template("a").render(a=7,b=8)) == "this is a this is b. 7, 8, 5" + """, + ) + # print lookup.get_template("a").code + assert ( + flatten_result(lookup.get_template("a").render(a=7, b=8)) + == "this is a this is b. 7, 8, 5" + ) def test_include_withargs(self): lookup = TemplateLookup() - lookup.put_string("a", """ + lookup.put_string( + "a", + """ this is a <%include file="${i}" args="c=5, **context.kwargs"/> - """) - lookup.put_string("b", """ + """, + ) + lookup.put_string( + "b", + """ <%page args="a,b,c"/> this is b. ${a}, ${b}, ${c} - """) - assert flatten_result(lookup.get_template("a").render(a=7,b=8,i='b')) == "this is a this is b. 7, 8, 5" + """, + ) + assert ( + flatten_result(lookup.get_template("a").render(a=7, b=8, i="b")) + == "this is a this is b. 7, 8, 5" + ) def test_within_ccall(self): lookup = TemplateLookup() lookup.put_string("a", """this is a""") - lookup.put_string("b", """ + lookup.put_string( + "b", + """ <%def name="bar()"> bar: ${caller.body()} <%include file="a"/> </%def> - """) - lookup.put_string("c", """ + """, + ) + lookup.put_string( + "c", + """ <%namespace name="b" file="b"/> <%b:bar> calling bar </%b:bar> - """) - assert flatten_result(lookup.get_template("c").render()) == "bar: calling bar this is a" + """, + ) + assert ( + flatten_result(lookup.get_template("c").render()) + == "bar: calling bar this is a" + ) def test_include_error_handler(self): def handle(context, error): - context.write('include error') + context.write("include error") return True lookup = TemplateLookup(include_error_handler=handle) - lookup.put_string("a", """ + lookup.put_string( + "a", + """ this is a. <%include file="b"/> - """) - lookup.put_string("b", """ + """, + ) + lookup.put_string( + "b", + """ this is b ${1/0} end. - """) - assert flatten_result(lookup.get_template("a").render()) == "this is a. this is b include error" + """, + ) + assert ( + flatten_result(lookup.get_template("a").render()) + == "this is a. this is b include error" + ) + class UndefinedVarsTest(TemplateTest): def test_undefined(self): - t = Template(""" + t = Template( + """ % if x is UNDEFINED: undefined % else: x: ${x} % endif - """) + """ + ) assert result_lines(t.render(x=12)) == ["x: 12"] assert result_lines(t.render(y=12)) == ["undefined"] def test_strict(self): - t = Template(""" + t = Template( + """ % if x is UNDEFINED: undefined % else: x: ${x} % endif - """, strict_undefined=True) + """, + strict_undefined=True, + ) - assert result_lines(t.render(x=12)) == ['x: 12'] + assert result_lines(t.render(x=12)) == ["x: 12"] - assert_raises( - NameError, - t.render, y=12 - ) + assert_raises(NameError, t.render, y=12) l = TemplateLookup(strict_undefined=True) l.put_string("a", "some template") - l.put_string("b", """ + l.put_string( + "b", + """ <%namespace name='a' file='a' import='*'/> % if x is UNDEFINED: undefined % else: x: ${x} % endif - """) + """, + ) - assert result_lines(t.render(x=12)) == ['x: 12'] + assert result_lines(t.render(x=12)) == ["x: 12"] - assert_raises( - NameError, - t.render, y=12 - ) + assert_raises(NameError, t.render, y=12) def test_expression_declared(self): - t = Template(""" + t = Template( + """ ${",".join([t for t in ("a", "b", "c")])} - """, strict_undefined=True) + """, + strict_undefined=True, + ) - eq_(result_lines(t.render()), ['a,b,c']) + eq_(result_lines(t.render()), ["a,b,c"]) - t = Template(""" + t = Template( + """ <%self:foo value="${[(val, n) for val, n in [(1, 2)]]}"/> <%def name="foo(value)"> ${value} </%def> - """, strict_undefined=True) + """, + strict_undefined=True, + ) - eq_(result_lines(t.render()), ['[(1, 2)]']) + eq_(result_lines(t.render()), ["[(1, 2)]"]) - t = Template(""" + t = Template( + """ <%call expr="foo(value=[(val, n) for val, n in [(1, 2)]])" /> <%def name="foo(value)"> ${value} </%def> - """, strict_undefined=True) + """, + strict_undefined=True, + ) - eq_(result_lines(t.render()), ['[(1, 2)]']) + eq_(result_lines(t.render()), ["[(1, 2)]"]) l = TemplateLookup(strict_undefined=True) l.put_string("i", "hi, ${pageargs['y']}") - l.put_string("t", """ + l.put_string( + "t", + """ <%include file="i" args="y=[x for x in range(3)]" /> - """) - eq_( - result_lines(l.get_template("t").render()), ['hi, [0, 1, 2]'] + """, ) + eq_(result_lines(l.get_template("t").render()), ["hi, [0, 1, 2]"]) - l.put_string('q', """ - <%namespace name="i" file="${(str([x for x in range(3)][2]) + 'i')[-1]}" /> + l.put_string( + "q", + """ + <%namespace name="i" file="${(str([x for x in range(3)][2]) + """ + """'i')[-1]}" /> ${i.body(y='x')} - """) - eq_( - result_lines(l.get_template("q").render()), ['hi, x'] + """, ) + eq_(result_lines(l.get_template("q").render()), ["hi, x"]) - t = Template(""" + t = Template( + """ <% y = lambda q: str(q) %> ${y('hi')} - """, strict_undefined=True) - eq_( - result_lines(t.render()), ["hi"] + """, + strict_undefined=True, ) + eq_(result_lines(t.render()), ["hi"]) def test_list_comprehensions_plus_undeclared_nonstrict(self): # traditional behavior. variable inside a list comprehension # is treated as an "undefined", so is pulled from the context. - t = Template(""" + t = Template( + """ t is: ${t} ${",".join([t for t in ("a", "b", "c")])} - """) - - eq_( - result_lines(t.render(t="T")), - ['t is: T', 'a,b,c'] + """ ) + eq_(result_lines(t.render(t="T")), ["t is: T", "a,b,c"]) + def test_traditional_assignment_plus_undeclared(self): - t = Template(""" + t = Template( + """ t is: ${t} <% t = 12 %> - """) - assert_raises( - UnboundLocalError, - t.render, t="T" + """ ) + assert_raises(UnboundLocalError, t.render, t="T") def test_list_comprehensions_plus_undeclared_strict(self): # with strict, a list comprehension now behaves # like the undeclared case above. - t = Template(""" + t = Template( + """ t is: ${t} ${",".join([t for t in ("a", "b", "c")])} - """, strict_undefined=True) - - eq_( - result_lines(t.render(t="T")), - ['t is: T', 'a,b,c'] + """, + strict_undefined=True, ) + eq_(result_lines(t.render(t="T")), ["t is: T", "a,b,c"]) + + class StopRenderingTest(TemplateTest): def test_return_in_template(self): - t = Template(""" + t = Template( + """ Line one <% return STOP_RENDERING %> Line Three - """, strict_undefined=True) - - eq_( - result_lines(t.render()), - ['Line one'] + """, + strict_undefined=True, ) + eq_(result_lines(t.render()), ["Line one"]) + + class ReservedNameTest(TemplateTest): def test_names_on_context(self): - for name in ('context', 'loop', 'UNDEFINED', 'STOP_RENDERING'): + for name in ("context", "loop", "UNDEFINED", "STOP_RENDERING"): assert_raises_message( exceptions.NameConflictError, r"Reserved words passed to render\(\): %s" % name, - Template("x").render, **{name:'foo'} + Template("x").render, + **{name: "foo"} ) def test_names_in_template(self): - for name in ('context', 'loop', 'UNDEFINED', 'STOP_RENDERING'): + for name in ("context", "loop", "UNDEFINED", "STOP_RENDERING"): assert_raises_message( exceptions.NameConflictError, r"Reserved words declared in template: %s" % name, - Template, "<%% %s = 5 %%>" % name + Template, + "<%% %s = 5 %%>" % name, ) def test_exclude_loop_context(self): @@ -806,19 +1113,19 @@ class ReservedNameTest(TemplateTest): "loop is ${loop}", "loop is 5", template_args=dict(loop=5), - enable_loop=False + enable_loop=False, ) def test_exclude_loop_template(self): self._do_memory_test( - "<% loop = 12 %>loop is ${loop}", - "loop is 12", - enable_loop=False + "<% loop = 12 %>loop is ${loop}", "loop is 12", enable_loop=False ) + class ControlTest(TemplateTest): def test_control(self): - t = Template(""" + t = Template( + """ ## this is a template. % for x in y: % if 'test' in x: @@ -827,12 +1134,17 @@ class ControlTest(TemplateTest): no x does not have test %endif %endfor -""") - assert result_lines(t.render(y=[{'test':'one'}, {'foo':'bar'}, {'foo':'bar', 'test':'two'}])) == [ - "yes x has test", - "no x does not have test", - "yes x has test" - ] +""" + ) + assert result_lines( + t.render( + y=[ + {"test": "one"}, + {"foo": "bar"}, + {"foo": "bar", "test": "two"}, + ] + ) + ) == ["yes x has test", "no x does not have test", "yes x has test"] def test_blank_control_1(self): self._do_memory_test( @@ -841,7 +1153,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_blank_control_2(self): @@ -852,7 +1164,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_blank_control_3(self): @@ -863,7 +1175,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_blank_control_4(self): @@ -875,7 +1187,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_blank_control_5(self): @@ -885,7 +1197,7 @@ class ControlTest(TemplateTest): % endfor """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_blank_control_6(self): @@ -895,7 +1207,7 @@ class ControlTest(TemplateTest): % endwhile """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_blank_control_7(self): @@ -906,7 +1218,7 @@ class ControlTest(TemplateTest): % endtry """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_blank_control_8(self): @@ -917,7 +1229,7 @@ class ControlTest(TemplateTest): """, "", filters=lambda s: s.strip(), - template_args={"ctx": ctx} + template_args={"ctx": ctx}, ) def test_commented_blank_control_1(self): @@ -928,7 +1240,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_commented_blank_control_2(self): @@ -941,7 +1253,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_commented_blank_control_3(self): @@ -954,7 +1266,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_commented_blank_control_4(self): @@ -969,7 +1281,7 @@ class ControlTest(TemplateTest): % endif """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_commented_blank_control_5(self): @@ -980,7 +1292,7 @@ class ControlTest(TemplateTest): % endfor """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_commented_blank_control_6(self): @@ -991,7 +1303,7 @@ class ControlTest(TemplateTest): % endwhile """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_commented_blank_control_7(self): @@ -1004,7 +1316,7 @@ class ControlTest(TemplateTest): % endtry """, "", - filters=lambda s:s.strip() + filters=lambda s: s.strip(), ) def test_commented_blank_control_8(self): @@ -1016,19 +1328,22 @@ class ControlTest(TemplateTest): """, "", filters=lambda s: s.strip(), - template_args={"ctx": ctx} + template_args={"ctx": ctx}, ) def test_multiline_control(self): - t = Template(""" + t = Template( + """ % for x in \\ [y for y in [1,2,3]]: ${x} % endfor -""") - #print t.code +""" + ) + # print t.code assert flatten_result(t.render()) == "1 2 3" + class GlobalsTest(TemplateTest): def test_globals(self): self._do_memory_test( @@ -1039,33 +1354,39 @@ class GlobalsTest(TemplateTest): y is ${y} """, "y is hi", - filters=lambda t:t.strip() + filters=lambda t: t.strip(), ) -class RichTracebackTest(TemplateTest): +class RichTracebackTest(TemplateTest): def _do_test_traceback(self, utf8, memory, syntax): if memory: if syntax: - source = u('## coding: utf-8\n<% print "m’a réveillé. '\ - 'Elle disait: « S’il vous plaît… dessine-moi un mouton! » %>') + source = u( + '## coding: utf-8\n<% print "m’a réveillé. ' + "Elle disait: « S’il vous plaît… dessine-moi " + "un mouton! » %>" + ) else: - source = u('## coding: utf-8\n<% print u"m’a réveillé. '\ - 'Elle disait: « S’il vous plaît… dessine-moi un mouton! »" + str(5/0) %>') + source = u( + '## coding: utf-8\n<% print u"m’a réveillé. ' + "Elle disait: « S’il vous plaît… dessine-moi un " + 'mouton! »" + str(5/0) %>' + ) if utf8: - source = source.encode('utf-8') + source = source.encode("utf-8") else: source = source - templateargs = {'text': source} + templateargs = {"text": source} else: if syntax: - filename = 'unicode_syntax_error.html' + filename = "unicode_syntax_error.html" else: - filename = 'unicode_runtime_error.html' - source = util.read_file(self._file_path(filename), 'rb') + filename = "unicode_runtime_error.html" + source = util.read_file(self._file_path(filename), "rb") if not utf8: - source = source.decode('utf-8') - templateargs = {'filename': self._file_path(filename)} + source = source.decode("utf-8") + templateargs = {"filename": self._file_path(filename)} try: template = Template(**templateargs) if not syntax: @@ -1074,101 +1395,119 @@ class RichTracebackTest(TemplateTest): except Exception: tback = exceptions.RichTraceback() if utf8: - assert tback.source == source.decode('utf-8') + assert tback.source == source.decode("utf-8") else: assert tback.source == source + for utf8 in (True, False): for memory in (True, False): for syntax in (True, False): + def _do_test(self): self._do_test_traceback(utf8, memory, syntax) - name = 'test_%s_%s_%s' % (utf8 and 'utf8' or 'unicode', - memory and 'memory' or 'file', - syntax and 'syntax' or 'runtime') + + name = "test_%s_%s_%s" % ( + utf8 and "utf8" or "unicode", + memory and "memory" or "file", + syntax and "syntax" or "runtime", + ) _do_test.__name__ = name setattr(RichTracebackTest, name, _do_test) del _do_test + class ModuleDirTest(TemplateTest): def tearDown(self): import shutil + shutil.rmtree(module_base, True) def test_basic(self): t = self._file_template("modtest.html") - t2 = self._file_template('subdir/modtest.html') + t2 = self._file_template("subdir/modtest.html") - eq_( - t.module.__file__, - os.path.join(module_base, 'modtest.html.py') - ) + eq_(t.module.__file__, os.path.join(module_base, "modtest.html.py")) eq_( t2.module.__file__, - os.path.join(module_base, 'subdir', 'modtest.html.py') + os.path.join(module_base, "subdir", "modtest.html.py"), ) def test_callable(self): def get_modname(filename, uri): return os.path.join( - module_base, - os.path.dirname(uri)[1:], - 'foo', - os.path.basename(filename) + ".py") + module_base, + os.path.dirname(uri)[1:], + "foo", + os.path.basename(filename) + ".py", + ) lookup = TemplateLookup(template_base, modulename_callable=get_modname) - t = lookup.get_template('/modtest.html') - t2 = lookup.get_template('/subdir/modtest.html') + t = lookup.get_template("/modtest.html") + t2 = lookup.get_template("/subdir/modtest.html") eq_( t.module.__file__, - os.path.join(module_base, 'foo', 'modtest.html.py') + os.path.join(module_base, "foo", "modtest.html.py"), ) eq_( t2.module.__file__, - os.path.join(module_base, 'subdir', 'foo', 'modtest.html.py') + os.path.join(module_base, "subdir", "foo", "modtest.html.py"), ) def test_custom_writer(self): canary = [] + def write_module(source, outputpath): - f = open(outputpath, 'wb') + f = open(outputpath, "wb") canary.append(outputpath) f.write(source) f.close() - lookup = TemplateLookup(template_base, module_writer=write_module, - module_directory=module_base) - t = lookup.get_template('/modtest.html') - t2 = lookup.get_template('/subdir/modtest.html') + + lookup = TemplateLookup( + template_base, + module_writer=write_module, + module_directory=module_base, + ) + lookup.get_template("/modtest.html") + lookup.get_template("/subdir/modtest.html") eq_( canary, - [os.path.join(module_base, "modtest.html.py"), - os.path.join(module_base, "subdir", "modtest.html.py")] + [ + os.path.join(module_base, "modtest.html.py"), + os.path.join(module_base, "subdir", "modtest.html.py"), + ], ) + class FilenameToURITest(TemplateTest): def test_windows_paths(self): - """test that windows filenames are handled appropriately by Template.""" + """test that windows filenames are handled appropriately by + Template.""" current_path = os.path import ntpath + os.path = ntpath try: + class NoCompileTemplate(Template): def _compile_from_file(self, path, filename): self.path = path return Template("foo bar").module t1 = NoCompileTemplate( - filename="c:\\foo\\template.html", - module_directory="c:\\modules\\") + filename="c:\\foo\\template.html", + module_directory="c:\\modules\\", + ) eq_(t1.uri, "/foo/template.html") eq_(t1.path, "c:\\modules\\foo\\template.html.py") t1 = NoCompileTemplate( - filename="c:\\path\\to\\templates\\template.html", - uri = "/bar/template.html", - module_directory="c:\\modules\\") + filename="c:\\path\\to\\templates\\template.html", + uri="/bar/template.html", + module_directory="c:\\modules\\", + ) eq_(t1.uri, "/bar/template.html") eq_(t1.path, "c:\\modules\\bar\\template.html.py") @@ -1181,24 +1520,31 @@ class FilenameToURITest(TemplateTest): current_path = os.path import posixpath + os.path = posixpath try: + class NoCompileTemplate(Template): def _compile_from_file(self, path, filename): self.path = path return Template("foo bar").module t1 = NoCompileTemplate( - filename="/var/www/htdocs/includes/template.html", - module_directory="/var/lib/modules") + filename="/var/www/htdocs/includes/template.html", + module_directory="/var/lib/modules", + ) eq_(t1.uri, "/var/www/htdocs/includes/template.html") - eq_(t1.path, "/var/lib/modules/var/www/htdocs/includes/template.html.py") + eq_( + t1.path, + "/var/lib/modules/var/www/htdocs/includes/template.html.py", + ) t1 = NoCompileTemplate( - filename="/var/www/htdocs/includes/template.html", - uri = "/bar/template.html", - module_directory="/var/lib/modules") + filename="/var/www/htdocs/includes/template.html", + uri="/bar/template.html", + module_directory="/var/lib/modules", + ) eq_(t1.uri, "/bar/template.html") eq_(t1.path, "/var/lib/modules/bar/template.html.py") @@ -1209,16 +1555,20 @@ class FilenameToURITest(TemplateTest): def test_dont_accept_relative_outside_of_root(self): assert_raises_message( exceptions.TemplateLookupException, - "Template uri \"../../foo.html\" is invalid - it " + 'Template uri "../../foo.html" is invalid - it ' "cannot be relative outside of the root path", - Template, "test", uri="../../foo.html", + Template, + "test", + uri="../../foo.html", ) assert_raises_message( exceptions.TemplateLookupException, - "Template uri \"/../../foo.html\" is invalid - it " + 'Template uri "/../../foo.html" is invalid - it ' "cannot be relative outside of the root path", - Template, "test", uri="/../../foo.html", + Template, + "test", + uri="/../../foo.html", ) # normalizes in the root is OK @@ -1230,24 +1580,35 @@ class ModuleTemplateTest(TemplateTest): def test_module_roundtrip(self): lookup = TemplateLookup() - template = Template(""" + template = Template( + """ <%inherit file="base.html"/> % for x in range(5): ${x} % endfor -""", lookup=lookup) +""", + lookup=lookup, + ) - base = Template(""" + base = Template( + """ This is base. ${self.body()} -""", lookup=lookup) +""", + lookup=lookup, + ) lookup.put_template("base.html", base) lookup.put_template("template.html", template) assert result_lines(template.render()) == [ - "This is base.", "0", "1", "2", "3", "4" + "This is base.", + "0", + "1", + "2", + "3", + "4", ] lookup = TemplateLookup() @@ -1258,12 +1619,19 @@ class ModuleTemplateTest(TemplateTest): lookup.put_template("template.html", template) assert result_lines(template.render()) == [ - "This is base.", "0", "1", "2", "3", "4" + "This is base.", + "0", + "1", + "2", + "3", + "4", ] + class TestTemplateAPI(unittest.TestCase): def test_metadata(self): - t = Template(""" + t = Template( + """ Text Text % if bar: @@ -1272,24 +1640,69 @@ Text <%include file='bar'/> -""", uri="/some/template") +""", + uri="/some/template", + ) eq_( ModuleInfo.get_module_source_metadata(t.code, full_line_map=True), { - 'full_line_map': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 4, 5, 5, 5, 7, - 8, 8, 8, 8, 8, 8, 8], - 'source_encoding': 'ascii', - 'filename': None, - 'line_map': {35: 29, 15: 0, 22: 1, 23: 4, 24: 5, 25: 5, - 26: 5, 27: 7, 28: 8, 29: 8}, - 'uri': '/some/template' - } - + "full_line_map": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 4, + 5, + 5, + 5, + 7, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + ], + "source_encoding": "ascii", + "filename": None, + "line_map": { + 35: 29, + 15: 0, + 22: 1, + 23: 4, + 24: 5, + 25: 5, + 26: 5, + 27: 7, + 28: 8, + 29: 8, + }, + "uri": "/some/template", + }, ) def test_metadata_two(self): - t = Template(""" + t = Template( + """ Text Text % if bar: @@ -1301,26 +1714,89 @@ Text </%block> -""", uri="/some/template") +""", + uri="/some/template", + ) eq_( ModuleInfo.get_module_source_metadata(t.code, full_line_map=True), { - 'full_line_map': [ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 5, 5, 5, 7, 7, - 7, 7, 7, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8], - 'source_encoding': 'ascii', - 'filename': None, - 'line_map': {34: 10, 40: 8, 46: 8, 15: 0, 52: 46, - 24: 1, 25: 4, 26: 5, 27: 5, 28: 5, 29: 7}, - 'uri': '/some/template'} + "full_line_map": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 4, + 5, + 5, + 5, + 7, + 7, + 7, + 7, + 7, + 10, + 10, + 10, + 10, + 10, + 10, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 8, + ], + "source_encoding": "ascii", + "filename": None, + "line_map": { + 34: 10, + 40: 8, + 46: 8, + 15: 0, + 52: 46, + 24: 1, + 25: 4, + 26: 5, + 27: 5, + 28: 5, + 29: 7, + }, + "uri": "/some/template", + }, ) class PreprocessTest(TemplateTest): def test_old_comments(self): - t = Template(""" + t = Template( + """ im a template # old style comment # more old style comment @@ -1328,32 +1804,43 @@ class PreprocessTest(TemplateTest): ## new style comment - # not a comment - ## not a comment -""", preprocessor=convert_comments) +""", + preprocessor=convert_comments, + ) + + assert ( + flatten_result(t.render()) + == "im a template - # not a comment - ## not a comment" + ) - assert flatten_result(t.render()) == "im a template - # not a comment - ## not a comment" class LexerTest(TemplateTest): def _fixture(self): from mako.parsetree import TemplateNode, Text + class MyLexer(object): - encoding = 'ascii' + encoding = "ascii" + def __init__(self, *arg, **kw): pass def parse(self): t = TemplateNode("foo") t.nodes.append( - Text("hello world", source="foo", lineno=0, - pos=0, filename=None) + Text( + "hello world", + source="foo", + lineno=0, + pos=0, + filename=None, + ) ) return t + return MyLexer def _test_custom_lexer(self, template): - eq_( - result_lines(template.render()), - ["hello world"] - ) + eq_(result_lines(template.render()), ["hello world"]) def test_via_template(self): t = Template("foo", lexer_cls=self._fixture()) @@ -1365,8 +1852,8 @@ class LexerTest(TemplateTest): t = tl.get_template("foo") self._test_custom_lexer(t) -class FuturesTest(TemplateTest): +class FuturesTest(TemplateTest): def test_future_import(self): t = Template("${ x / y }", future_imports=["division"]) assert result_lines(t.render(x=12, y=5)) == ["2.4"] diff --git a/test/test_tgplugin.py b/test/test_tgplugin.py index 3f548c4..df95d00 100644 --- a/test/test_tgplugin.py +++ b/test/test_tgplugin.py @@ -1,49 +1,52 @@ +from mako import compat from mako.ext.turbogears import TGPlugin +from test import template_base +from test import TemplateTest from test.util import result_lines -from test import TemplateTest, template_base -from mako import compat -tl = TGPlugin(options=dict(directories=[template_base]), extension='html') +tl = TGPlugin(options=dict(directories=[template_base]), extension="html") + class TestTGPlugin(TemplateTest): def test_basic(self): - t = tl.load_template('/index.html') - assert result_lines(t.render()) == [ - "this is index" - ] + t = tl.load_template("/index.html") + assert result_lines(t.render()) == ["this is index"] + def test_subdir(self): - t = tl.load_template('/subdir/index.html') + t = tl.load_template("/subdir/index.html") assert result_lines(t.render()) == [ "this is sub index", - "this is include 2" - + "this is include 2", ] - assert tl.load_template('/subdir/index.html').module_id == '_subdir_index_html' + assert ( + tl.load_template("/subdir/index.html").module_id + == "_subdir_index_html" + ) def test_basic_dot(self): - t = tl.load_template('index') - assert result_lines(t.render()) == [ - "this is index" - ] + t = tl.load_template("index") + assert result_lines(t.render()) == ["this is index"] + def test_subdir_dot(self): - t = tl.load_template('subdir.index') + t = tl.load_template("subdir.index") assert result_lines(t.render()) == [ "this is sub index", - "this is include 2" - + "this is include 2", ] - assert tl.load_template('subdir.index').module_id == '_subdir_index_html' + assert ( + tl.load_template("subdir.index").module_id == "_subdir_index_html" + ) def test_string(self): - t = tl.load_template('foo', "hello world") + t = tl.load_template("foo", "hello world") assert t.render() == "hello world" def test_render(self): - assert result_lines(tl.render({}, template='/index.html')) == [ - "this is index" - ] - assert result_lines(tl.render({}, template=compat.u('/index.html'))) == [ + assert result_lines(tl.render({}, template="/index.html")) == [ "this is index" ] + assert result_lines( + tl.render({}, template=compat.u("/index.html")) + ) == ["this is index"] diff --git a/test/test_util.py b/test/test_util.py index c8034a1..f3f3edb 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -2,9 +2,15 @@ import os import unittest -from mako import util, exceptions, compat -from test import eq_, skip_if, assert_raises_message + +from mako import compat +from mako import exceptions +from mako import util from mako.compat import u +from test import assert_raises_message +from test import eq_ +from test import skip_if + class UtilTest(unittest.TestCase): def test_fast_buffer_write(self): @@ -24,22 +30,22 @@ class UtilTest(unittest.TestCase): def test_fast_buffer_encoded(self): s = u("drôl m’a rée « S’il") - buf = util.FastEncodingBuffer(encoding='utf-8') + buf = util.FastEncodingBuffer(encoding="utf-8") buf.write(s[0:10]) buf.write(s[10:]) - q = buf.getvalue() - eq_(buf.getvalue(), s.encode('utf-8')) + eq_(buf.getvalue(), s.encode("utf-8")) def test_read_file(self): - fn = os.path.join(os.path.dirname(__file__), 'test_util.py') - data = util.read_file(fn, 'rb') - assert 'test_util' in str(data) # str() for py3k + fn = os.path.join(os.path.dirname(__file__), "test_util.py") + data = util.read_file(fn, "rb") + assert "test_util" in str(data) # str() for py3k @skip_if(lambda: compat.pypy, "Pypy does this differently") def test_load_module(self): - fn = os.path.join(os.path.dirname(__file__), 'test_util.py') - module = compat.load_module('mako.template', fn) + fn = os.path.join(os.path.dirname(__file__), "test_util.py") + module = compat.load_module("mako.template", fn) import mako.template + self.assertEqual(module, mako.template) def test_load_plugin_failure(self): @@ -47,5 +53,6 @@ class UtilTest(unittest.TestCase): assert_raises_message( exceptions.RuntimeException, "Can't load plugin fakegroup fake", - loader.load, "fake" + loader.load, + "fake", ) diff --git a/test/util.py b/test/util.py index 605269f..29225e2 100644 --- a/test/util.py +++ b/test/util.py @@ -1,7 +1,13 @@ import re + def flatten_result(result): - return re.sub(r'[\s\r\n]+', ' ', result).strip() + return re.sub(r"[\s\r\n]+", " ", result).strip() + def result_lines(result): - return [x.strip() for x in re.split(r'\r?\n', re.sub(r' +', ' ', result)) if x.strip() != '']
\ No newline at end of file + return [ + x.strip() + for x in re.split(r"\r?\n", re.sub(r" +", " ", result)) + if x.strip() != "" + ] @@ -22,9 +22,15 @@ setenv= commands=py.test {env:COVERAGE:} {posargs} -[flake8] - -show-source = True -ignore = E711,E712,E721,D,N -# F841,F811,F401 -exclude=.venv,.git,.tox,dist,doc,*egg,build +# thanks to https://julien.danjou.info/the-best-flake8-extensions/ +[testenv:pep8] +basepython = python3.7 +deps= + flake8 + flake8-import-order + flake8-builtins + flake8-docstrings + flake8-rst-docstrings + # used by flake8-rst-docstrings + pygments +commands = flake8 ./mako/ ./test/ setup.py --exclude test/templates,test/foo |