diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-02-05 00:15:54 +0000 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-02-05 00:15:54 +0000 |
commit | 1575e1e4e117cf127ddeade810c3dccafe1f218b (patch) | |
tree | 4b66991b170127051dd3c250f1a0c03943477832 /lib/mako | |
parent | 86411ebded5f62970eaa2b119a215a71212cb492 (diff) | |
download | external_python_mako-1575e1e4e117cf127ddeade810c3dccafe1f218b.tar.gz external_python_mako-1575e1e4e117cf127ddeade810c3dccafe1f218b.tar.bz2 external_python_mako-1575e1e4e117cf127ddeade810c3dccafe1f218b.zip |
move lib/mako to mako
Diffstat (limited to 'lib/mako')
-rw-r--r-- | lib/mako/__init__.py | 9 | ||||
-rw-r--r-- | lib/mako/_ast_util.py | 834 | ||||
-rw-r--r-- | lib/mako/ast.py | 125 | ||||
-rw-r--r-- | lib/mako/cache.py | 55 | ||||
-rw-r--r-- | lib/mako/codegen.py | 765 | ||||
-rw-r--r-- | lib/mako/exceptions.py | 283 | ||||
-rw-r--r-- | lib/mako/ext/__init__.py | 0 | ||||
-rw-r--r-- | lib/mako/ext/autohandler.py | 57 | ||||
-rw-r--r-- | lib/mako/ext/babelplugin.py | 123 | ||||
-rw-r--r-- | lib/mako/ext/preprocessors.py | 20 | ||||
-rw-r--r-- | lib/mako/ext/pygmentplugin.py | 101 | ||||
-rw-r--r-- | lib/mako/ext/turbogears.py | 50 | ||||
-rw-r--r-- | lib/mako/filters.py | 170 | ||||
-rw-r--r-- | lib/mako/lexer.py | 328 | ||||
-rw-r--r-- | lib/mako/lookup.py | 202 | ||||
-rw-r--r-- | lib/mako/parsetree.py | 422 | ||||
-rw-r--r-- | lib/mako/pygen.py | 267 | ||||
-rw-r--r-- | lib/mako/pyparser.py | 371 | ||||
-rw-r--r-- | lib/mako/runtime.py | 419 | ||||
-rw-r--r-- | lib/mako/template.py | 392 | ||||
-rw-r--r-- | lib/mako/util.py | 274 |
21 files changed, 0 insertions, 5267 deletions
diff --git a/lib/mako/__init__.py b/lib/mako/__init__.py deleted file mode 100644 index 6a30418..0000000 --- a/lib/mako/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# __init__.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - - -__version__ = '0.2.5' - diff --git a/lib/mako/_ast_util.py b/lib/mako/_ast_util.py deleted file mode 100644 index 6ff4ab9..0000000 --- a/lib/mako/_ast_util.py +++ /dev/null @@ -1,834 +0,0 @@ -# -*- coding: utf-8 -*- -""" - ast - ~~~ - - The `ast` module helps Python applications to process trees of the Python - abstract syntax grammar. The abstract syntax itself might change with - each Python release; this module helps to find out programmatically what - the current grammar looks like and allows modifications of it. - - An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as - a flag to the `compile()` builtin function or by using the `parse()` - function from this module. The result will be a tree of objects whose - classes all inherit from `ast.AST`. - - A modified abstract syntax tree can be compiled into a Python code object - using the built-in `compile()` function. - - Additionally various helper functions are provided that make working with - the trees simpler. The main intention of the helper functions and this - module in general is to provide an easy to use interface for libraries - that work tightly with the python syntax (template engines for example). - - - :copyright: Copyright 2008 by Armin Ronacher. - :license: Python License. -""" -from _ast import * - - -BOOLOP_SYMBOLS = { - And: 'and', - Or: 'or' -} - -BINOP_SYMBOLS = { - 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' -} - -UNARYOP_SYMBOLS = { - Invert: '~', - Not: 'not', - UAdd: '+', - USub: '-' -} - -ALL_SYMBOLS = {} -ALL_SYMBOLS.update(BOOLOP_SYMBOLS) -ALL_SYMBOLS.update(BINOP_SYMBOLS) -ALL_SYMBOLS.update(CMPOP_SYMBOLS) -ALL_SYMBOLS.update(UNARYOP_SYMBOLS) - - -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): - """ - This function can convert a node tree back into python sourcecode. This - is useful for debugging purposes, especially if you're dealing with custom - asts not generated by python itself. - - It could be that the sourcecode is evaluable when the AST itself is not - compilable / evaluable. The reason for this is that the AST contains some - more data than regular sourcecode does, which is dropped during - conversion. - - Each level of indentation is replaced with `indent_with`. Per default this - parameter is equal to four spaces as suggested by PEP 8, but it might be - adjusted to match the application's styleguide. - """ - generator = SourceGenerator(indent_with) - generator.visit(node) - return ''.join(generator.result) - - -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))) - elif isinstance(node, list): - 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__) - return _format(node) - - -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): - setattr(new_node, attr, getattr(old_node, attr)) - return new_node - - -def fix_missing_locations(node): - """ - Some nodes require a line number and the column offset. Without that - information the compiler will abort the compilation. Because it can be - a dull task to add appropriate line numbers and column offsets when - adding new nodes this function can help. It copies the line number and - column offset of the parent node to the child nodes without this - information. - - 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'): - node.lineno = lineno - else: - lineno = node.lineno - 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 - - -def increment_lineno(node, n=1): - """ - Increment the line numbers of all nodes by `n` if they have line number - attributes. This is useful to "move code" to a different location in a - file. - """ - for node in zip((node,), walk(node)): - 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: - return - for field in node._fields: - try: - yield field, getattr(node, field) - except AttributeError: - pass - - -def get_fields(node): - """Like `iter_fiels` but returns a dict.""" - return dict(iter_fields(node)) - - -def iter_child_nodes(node): - """Iterate over all child nodes or a node.""" - for name, field in iter_fields(node): - if isinstance(field, AST): - yield field - elif isinstance(field, list): - for item in field: - if isinstance(item, AST): - yield item - - -def get_child_nodes(node): - """Like `iter_child_nodes` but returns a list.""" - return list(iter_child_nodes(node)) - - -def get_compile_mode(node): - """ - Get the mode for `compile` of a given node. If the node is not a `mod` - 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') - - -def get_docstring(node): - """ - Return the docstring for the given node or `None` if no docstring can be - found. If the node provided does not accept docstrings a `TypeError` - will be raised. - """ - if not isinstance(node, (FunctionDef, ClassDef, Module)): - raise TypeError("%r can't have docstrings" % node.__class__.__name__) - if node.body and isinstance(node.body[0], Str): - return node.body[0].s - - -def walk(node): - """ - Iterate over all nodes. This is useful if you only want to modify nodes in - 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() - todo.extend(iter_child_nodes(node)) - yield node - - -class NodeVisitor(object): - """ - Walks the abstract syntax tree and call visitor functions for every node - found. The visitor functions may return values which will be forwarded - by the `visit` method. - - Per default the visitor functions for the nodes are ``'visit_'`` + - class name of the node. So a `TryFinally` node visit function would - be `visit_TryFinally`. This behavior can be changed by overriding - the `get_visitor` function. If no visitor function exists for a node - (return value `None`) the `generic_visit` visitor is used instead. - - Don't use the `NodeVisitor` if you want to apply changes to nodes during - traversing. For this a special visitor exists (`NodeTransformer`) that - allows modifications. - """ - - def get_visitor(self, node): - """ - Return the visitor function for this node or `None` if no visitor - exists for this node. In that case the generic visit function is - used instead. - """ - method = 'visit_' + node.__class__.__name__ - return getattr(self, method, None) - - def visit(self, node): - """Visit a node.""" - f = self.get_visitor(node) - if f is not None: - return f(node) - return self.generic_visit(node) - - def generic_visit(self, node): - """Called if no explicit visitor function exists for a node.""" - for field, value in iter_fields(node): - if isinstance(value, list): - for item in value: - if isinstance(item, AST): - self.visit(item) - elif isinstance(value, AST): - self.visit(value) - - -class NodeTransformer(NodeVisitor): - """ - Walks the abstract syntax tree and allows modifications of nodes. - - The `NodeTransformer` will walk the AST and use the return value of the - visitor functions to replace or remove the old node. If the return - value of the visitor function is `None` the node will be removed - from the previous location otherwise it's replaced with the return - value. The return value may be the original node in which case no - replacement takes place. - - Here an example transformer that rewrites all `foo` to `data['foo']`:: - - class RewriteName(NodeTransformer): - - def visit_Name(self, node): - return copy_location(Subscript( - value=Name(id='data', ctx=Load()), - slice=Index(value=Str(s=node.id)), - ctx=node.ctx - ), node) - - Keep in mind that if the node you're operating on has child nodes - you must either transform the child nodes yourself or call the generic - visit function for the node first. - - Nodes that were part of a collection of statements (that applies to - all statement nodes) may also return a list of nodes rather than just - a single node. - - Usually you use the transformer like this:: - - node = YourTransformer().visit(node) - """ - - def generic_visit(self, node): - for field, old_value in iter_fields(node): - old_value = getattr(node, field, None) - if isinstance(old_value, list): - new_values = [] - for value in old_value: - if isinstance(value, AST): - value = self.visit(value) - if value is None: - continue - elif not isinstance(value, AST): - new_values.extend(value) - continue - new_values.append(value) - old_value[:] = new_values - elif isinstance(old_value, AST): - new_node = self.visit(old_value) - if new_node is None: - delattr(node, field) - else: - setattr(node, field, new_node) - return node - - -class SourceGenerator(NodeVisitor): - """ - This visitor is able to transform a well formed syntax tree into python - sourcecode. For more details have a look at the docstring of the - `node_to_source` function. - """ - - def __init__(self, indent_with): - self.result = [] - self.indent_with = indent_with - self.indentation = 0 - self.new_lines = 0 - - def write(self, x): - if self.new_lines: - if self.result: - self.result.append('\n' * self.new_lines) - self.result.append(self.indent_with * self.indentation) - self.new_lines = 0 - self.result.append(x) - - def newline(self, n=1): - self.new_lines = max(self.new_lines, n) - - def body(self, statements): - self.new_line = True - self.indentation += 1 - for stmt in statements: - self.visit(stmt) - self.indentation -= 1 - - def body_or_else(self, node): - self.body(node.body) - if node.orelse: - self.newline() - self.write('else:') - self.body(node.orelse) - - def signature(self, node): - want_comma = [] - def write_comma(): - if want_comma: - self.write(', ') - else: - want_comma.append(True) - - padding = [None] * (len(node.args) - len(node.defaults)) - for arg, default in zip(node.args, padding + node.defaults): - write_comma() - self.visit(arg) - if default is not None: - self.write('=') - self.visit(default) - if node.vararg is not None: - write_comma() - self.write('*' + node.vararg) - if node.kwarg is not None: - write_comma() - self.write('**' + node.kwarg) - - def decorators(self, node): - for decorator in node.decorator_list: - self.newline() - self.write('@') - self.visit(decorator) - - # Statements - - def visit_Assign(self, node): - self.newline() - for idx, target in enumerate(node.targets): - if idx: - self.write(', ') - self.visit(target) - 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.visit(node.value) - - def visit_ImportFrom(self, node): - self.newline() - self.write('from %s%s import ' % ('.' * node.level, node.module)) - for idx, item in enumerate(node.names): - if idx: - self.write(', ') - self.write(item) - - def visit_Import(self, node): - self.newline() - for item in node.names: - self.write('import ') - self.visit(item) - - def visit_Expr(self, node): - self.newline() - self.generic_visit(node) - - def visit_FunctionDef(self, node): - self.newline(n=2) - self.decorators(node) - self.newline() - self.write('def %s(' % node.name) - self.signature(node.args) - self.write('):') - self.body(node.body) - - def visit_ClassDef(self, node): - have_args = [] - def paren_or_comma(): - if have_args: - self.write(', ') - else: - have_args.append(True) - self.write('(') - - self.newline(n=3) - self.decorators(node) - self.newline() - 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'): - for keyword in node.keywords: - paren_or_comma() - self.write(keyword.arg + '=') - self.visit(keyword.value) - if node.starargs is not None: - paren_or_comma() - self.write('*') - self.visit(node.starargs) - if node.kwargs is not None: - paren_or_comma() - self.write('**') - self.visit(node.kwargs) - self.write(have_args and '):' or ':') - self.body(node.body) - - def visit_If(self, node): - self.newline() - self.write('if ') - self.visit(node.test) - 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.visit(node.test) - self.write(':') - self.body(node.body) - else: - self.newline() - self.write('else:') - self.body(else_) - break - - def visit_For(self, node): - self.newline() - self.write('for ') - self.visit(node.target) - self.write(' in ') - self.visit(node.iter) - self.write(':') - self.body_or_else(node) - - def visit_While(self, node): - self.newline() - self.write('while ') - self.visit(node.test) - self.write(':') - self.body_or_else(node) - - def visit_With(self, node): - self.newline() - self.write('with ') - self.visit(node.context_expr) - if node.optional_vars is not None: - self.write(' as ') - self.visit(node.optional_vars) - self.write(':') - self.body(node.body) - - def visit_Pass(self, node): - self.newline() - self.write('pass') - - def visit_Print(self, node): - # XXX: python 2.6 only - self.newline() - self.write('print ') - want_comma = False - if node.dest is not None: - self.write(' >> ') - self.visit(node.dest) - want_comma = True - for value in node.values: - if want_comma: - self.write(', ') - self.visit(value) - want_comma = True - if not node.nl: - self.write(',') - - def visit_Delete(self, node): - self.newline() - self.write('del ') - for idx, target in enumerate(node): - if idx: - self.write(', ') - self.visit(target) - - def visit_TryExcept(self, node): - self.newline() - 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.body(node.body) - self.newline() - self.write('finally:') - self.body(node.finalbody) - - def visit_Global(self, node): - self.newline() - self.write('global ' + ', '.join(node.names)) - - def visit_Nonlocal(self, node): - self.newline() - self.write('nonlocal ' + ', '.join(node.names)) - - def visit_Return(self, node): - self.newline() - self.write('return ') - self.visit(node.value) - - def visit_Break(self, node): - self.newline() - self.write('break') - - def visit_Continue(self, node): - self.newline() - 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.visit(node.exc) - if node.cause is not None: - self.write(' from ') - self.visit(node.cause) - elif hasattr(node, 'type') and node.type is not None: - self.visit(node.type) - if node.inst is not None: - self.write(', ') - self.visit(node.inst) - if node.tback is not None: - self.write(', ') - self.visit(node.tback) - - # Expressions - - def visit_Attribute(self, node): - self.visit(node.value) - self.write('.' + node.attr) - - def visit_Call(self, node): - want_comma = [] - def write_comma(): - if want_comma: - self.write(', ') - else: - want_comma.append(True) - - self.visit(node.func) - self.write('(') - for arg in node.args: - write_comma() - self.visit(arg) - for keyword in node.keywords: - write_comma() - self.write(keyword.arg + '=') - self.visit(keyword.value) - if node.starargs is not None: - write_comma() - self.write('*') - self.visit(node.starargs) - if node.kwargs is not None: - write_comma() - self.write('**') - self.visit(node.kwargs) - self.write(')') - - def visit_Name(self, node): - self.write(node.id) - - def visit_Str(self, node): - self.write(repr(node.s)) - - def visit_Bytes(self, node): - self.write(repr(node.s)) - - def visit_Num(self, node): - self.write(repr(node.n)) - - def visit_Tuple(self, node): - self.write('(') - idx = -1 - for idx, item in enumerate(node.elts): - if idx: - self.write(', ') - self.visit(item) - 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.visit(item) - self.write(right) - return visit - - visit_List = sequence_visit('[', ']') - visit_Set = sequence_visit('{', '}') - del sequence_visit - - def visit_Dict(self, node): - self.write('{') - for idx, (key, value) in enumerate(zip(node.keys, node.values)): - if idx: - self.write(', ') - self.visit(key) - self.write(': ') - self.visit(value) - self.write('}') - - def visit_BinOp(self, node): - self.write('(') - self.visit(node.left) - self.write(' %s ' % BINOP_SYMBOLS[type(node.op)]) - self.visit(node.right) - self.write(')') - - def visit_BoolOp(self, node): - self.write('(') - for idx, value in enumerate(node.values): - if idx: - self.write(' %s ' % BOOLOP_SYMBOLS[type(node.op)]) - self.visit(value) - self.write(')') - - def visit_Compare(self, node): - self.write('(') - self.visit(node.left) - for op, right in zip(node.ops, node.comparators): - self.write(' %s ' % CMPOP_SYMBOLS[type(op)]) - self.visit(right) - self.write(')') - - def visit_UnaryOp(self, node): - self.write('(') - op = UNARYOP_SYMBOLS[type(node.op)] - self.write(op) - if op == 'not': - self.write(' ') - self.visit(node.operand) - self.write(')') - - def visit_Subscript(self, node): - self.visit(node.value) - self.write('[') - self.visit(node.slice) - self.write(']') - - def visit_Slice(self, node): - if node.lower is not None: - self.visit(node.lower) - 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.visit(node.step) - - def visit_ExtSlice(self, node): - for idx, item in node.dims: - if idx: - self.write(', ') - self.visit(item) - - def visit_Yield(self, node): - self.write('yield ') - self.visit(node.value) - - def visit_Lambda(self, node): - self.write('lambda ') - self.signature(node.args) - self.write(': ') - self.visit(node.body) - - def visit_Ellipsis(self, node): - self.write('Ellipsis') - - def generator_visit(left, right): - def visit(self, node): - self.write(left) - self.visit(node.elt) - 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('{', '}') - del generator_visit - - def visit_DictComp(self, node): - self.write('{') - self.visit(node.key) - self.write(': ') - self.visit(node.value) - for comprehension in node.generators: - self.visit(comprehension) - self.write('}') - - def visit_IfExp(self, node): - self.visit(node.body) - self.write(' if ') - self.visit(node.test) - self.write(' else ') - self.visit(node.orelse) - - def visit_Starred(self, node): - self.write('*') - self.visit(node.value) - - def visit_Repr(self, node): - # XXX: python 2.6 only - self.write('`') - self.visit(node.value) - self.write('`') - - # Helper Nodes - - def visit_alias(self, node): - self.write(node.name) - if node.asname is not None: - self.write(' as ' + node.asname) - - def visit_comprehension(self, node): - self.write(' for ') - self.visit(node.target) - self.write(' in ') - self.visit(node.iter) - if node.ifs: - for if_ in node.ifs: - self.write(' if ') - self.visit(if_) - - def visit_excepthandler(self, node): - self.newline() - self.write('except') - if node.type is not None: - self.write(' ') - self.visit(node.type) - if node.name is not None: - self.write(' as ') - self.visit(node.name) - self.write(':') - self.body(node.body) diff --git a/lib/mako/ast.py b/lib/mako/ast.py deleted file mode 100644 index 3b9f3ed..0000000 --- a/lib/mako/ast.py +++ /dev/null @@ -1,125 +0,0 @@ -# ast.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""utilities for analyzing expressions and blocks of Python code, as well as generating Python from AST nodes""" - -from mako import exceptions, pyparser, util -import re - -class PythonCode(object): - """represents information about a string containing Python code""" - def __init__(self, code, **exception_kwargs): - self.code = code - - # represents all identifiers which are assigned to at some point in the code - self.declared_identifiers = util.Set() - - # represents all identifiers which are referenced before their assignment, if any - self.undeclared_identifiers = util.Set() - - # note that an identifier can be in both the undeclared and declared lists. - - # using AST to parse instead of using code.co_varnames, code.co_names has several advantages: - # - we can locate an identifier as "undeclared" even if its declared later in the same block of code - # - AST is less likely to break with version changes (for example, the behavior of co_names changed a little bit - # in python version 2.5) - if isinstance(code, basestring): - expr = pyparser.parse(code.lstrip(), "exec", **exception_kwargs) - else: - expr = code - - f = pyparser.FindIdentifiers(self, **exception_kwargs) - f.visit(expr) - -class ArgumentList(object): - """parses a fragment of code as a comma-separated list of expressions""" - def __init__(self, code, **exception_kwargs): - self.codeargs = [] - self.args = [] - self.declared_identifiers = util.Set() - self.undeclared_identifiers = util.Set() - if isinstance(code, basestring): - if re.match(r"\S", code) and not re.match(r",\s*$", code): - # if theres text and no trailing comma, insure its parsed - # as a tuple by adding a trailing comma - code += "," - expr = pyparser.parse(code, "exec", **exception_kwargs) - else: - expr = code - - f = pyparser.FindTuple(self, PythonCode, **exception_kwargs) - f.visit(expr) - -class PythonFragment(PythonCode): - """extends PythonCode to provide identifier lookups in partial control statements - - 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) - if not m: - raise exceptions.CompileException("Fragment '%s' is not a partial control statement" % code, **exception_kwargs) - if m.group(3): - code = code[:m.start(3)] - (keyword, expr) = m.group(1,2) - if keyword in ['for','if', 'while']: - code = code + "pass" - elif keyword == 'try': - code = code + "pass\nexcept:pass" - elif keyword == 'elif' or keyword == 'else': - code = "if False:pass\n" + code + "pass" - elif keyword == 'except': - code = "try:pass\n" + code + "pass" - else: - raise exceptions.CompileException("Unsupported control keyword: '%s'" % keyword, **exception_kwargs) - super(PythonFragment, self).__init__(code, **exception_kwargs) - - -class FunctionDecl(object): - """function declaration""" - def __init__(self, code, allow_kwargs=True, **exception_kwargs): - self.code = code - expr = pyparser.parse(code, "exec", **exception_kwargs) - - f = pyparser.ParseFunc(self, **exception_kwargs) - f.visit(expr) - if not hasattr(self, 'funcname'): - raise exceptions.CompileException("Code '%s' is not a function declaration" % code, **exception_kwargs) - if not allow_kwargs and self.kwargs: - raise exceptions.CompileException("'**%s' keyword argument not allowed here" % self.argnames[-1], **exception_kwargs) - - def get_argument_expressions(self, include_defaults=True): - """return the argument declarations of this FunctionDecl as a printable list.""" - namedecls = [] - defaults = [d for d in self.defaults] - kwargs = self.kwargs - varargs = self.varargs - argnames = [f for f in self.argnames] - argnames.reverse() - for arg in argnames: - default = None - if kwargs: - arg = "**" + arg - kwargs = False - elif varargs: - arg = "*" + arg - varargs = False - else: - default = len(defaults) and defaults.pop() or None - if include_defaults and default: - namedecls.insert(0, "%s=%s" % (arg, pyparser.ExpressionGenerator(default).value())) - else: - namedecls.insert(0, arg) - return namedecls - -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) diff --git a/lib/mako/cache.py b/lib/mako/cache.py deleted file mode 100644 index 43f7317..0000000 --- a/lib/mako/cache.py +++ /dev/null @@ -1,55 +0,0 @@ -from mako import exceptions - -try: - from beaker import cache - cache = cache.CacheManager() -except ImportError: - cache = None - -class Cache(object): - def __init__(self, id, starttime): - self.id = id - self.starttime = starttime - self.def_regions = {} - - def put(self, key, value, **kwargs): - defname = kwargs.pop('defname', None) - expiretime = kwargs.pop('expiretime', None) - createfunc = kwargs.pop('createfunc', None) - - self._get_cache(defname, **kwargs).put_value(key, starttime=self.starttime, expiretime=expiretime) - - def get(self, key, **kwargs): - defname = kwargs.pop('defname', None) - expiretime = kwargs.pop('expiretime', None) - createfunc = kwargs.pop('createfunc', None) - - return self._get_cache(defname, **kwargs).get_value(key, starttime=self.starttime, expiretime=expiretime, createfunc=createfunc) - - def invalidate(self, key, **kwargs): - defname = kwargs.pop('defname', None) - expiretime = kwargs.pop('expiretime', None) - createfunc = kwargs.pop('createfunc', None) - - self._get_cache(defname, **kwargs).remove_value(key, starttime=self.starttime, expiretime=expiretime) - - def invalidate_body(self): - self.invalidate('render_body', defname='render_body') - - def invalidate_def(self, name): - self.invalidate('render_%s' % name, defname='render_%s' % name) - - def invalidate_closure(self, name): - self.invalidate(name, defname=name) - - def _get_cache(self, defname, type=None, **kw): - if not cache: - raise exceptions.RuntimeException("the Beaker package is required to use cache functionality.") - if type == 'memcached': - type = 'ext:memcached' - if not type: - (type, kw) = self.def_regions.get(defname, ('memory', {})) - else: - self.def_regions[defname] = (type, kw) - return cache.get_cache(self.id, type=type, **kw) -
\ No newline at end of file diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py deleted file mode 100644 index b3074f0..0000000 --- a/lib/mako/codegen.py +++ /dev/null @@ -1,765 +0,0 @@ -# codegen.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""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 - -MAGIC_NUMBER = 5 - -def compile(node, - uri, - filename=None, - default_filters=None, - buffer_filters=None, - imports=None, - source_encoding=None, - generate_unicode=True): - - """Generate module source code given a parsetree node, - uri, and optional source filename""" - - buf = util.FastEncodingBuffer(unicode=generate_unicode) - - printer = PythonPrinter(buf) - _GenerateRenderMethod(printer, - _CompileContext(uri, - filename, - default_filters, - buffer_filters, - imports, - source_encoding, - generate_unicode), - node) - return buf.getvalue() - -class _CompileContext(object): - def __init__(self, - uri, - filename, - default_filters, - buffer_filters, - imports, - source_encoding, - generate_unicode): - self.uri = uri - self.filename = filename - self.default_filters = default_filters - self.buffer_filters = buffer_filters - self.imports = imports - self.source_encoding = source_encoding - self.generate_unicode = generate_unicode - -class _GenerateRenderMethod(object): - """A template visitor object which generates the - full module source for a template. - - """ - def __init__(self, printer, compiler, node): - self.printer = printer - self.last_source_line = -1 - self.compiler = compiler - self.node = node - self.identifier_stack = [None] - - self.in_def = isinstance(node, parsetree.DefTag) - - if self.in_def: - name = "render_" + node.name - args = node.function_decl.get_argument_expressions() - filtered = len(node.filter_args.args) > 0 - buffered = eval(node.attributes.get('buffered', 'False')) - cached = eval(node.attributes.get('cached', 'False')) - defs = None - pagetag = None - else: - defs = self.write_toplevel() - pagetag = self.compiler.pagetag - name = "render_body" - 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')) - else: - args = ['**pageargs'] - cached = False - buffered = filtered = False - if args is None: - args = ['context'] - else: - args = [a for a in ['context'] + args] - - self.write_render_callable( - pagetag or node, - name, args, - buffered, filtered, cached) - - if defs is not None: - for node in defs: - _GenerateRenderMethod(printer, compiler, node) - - @property - def identifiers(self): - return self.identifier_stack[-1] - - def write_toplevel(self): - """Traverse a template structure for module-level directives and - generate the start of module-level code. - - """ - inherit = [] - namespaces = {} - module_code = [] - encoding =[None] - - self.compiler.pagetag = None - - class FindTopLevel(object): - def visitInheritTag(s, node): - inherit.append(node) - def visitNamespaceTag(s, node): - namespaces[node.name] = node - def visitPageTag(s, node): - self.compiler.pagetag = node - def visitCode(s, node): - if node.ismodule: - module_code.append(node) - - f = FindTopLevel() - for n in self.node.nodes: - n.accept_visitor(f) - - self.compiler.namespaces = namespaces - - module_ident = util.Set() - for n in module_code: - module_ident = module_ident.union(n.declared_identifiers()) - - module_identifiers = _Identifiers() - module_identifiers.declared = module_ident - - # module-level names, python code - if not self.compiler.generate_unicode and \ - self.compiler.source_encoding: - self.printer.writeline("# -*- encoding:%s -*-" % - self.compiler.source_encoding) - - self.printer.writeline("from mako import runtime, filters, cache") - self.printer.writeline("UNDEFINED = runtime.UNDEFINED") - self.printer.writeline("__M_dict_builtin = dict") - self.printer.writeline("__M_locals_builtin = locals") - self.printer.writeline("_magic_number = %r" % MAGIC_NUMBER) - self.printer.writeline("_modified_time = %r" % time.time()) - self.printer.writeline( - "_template_filename=%r" % self.compiler.filename) - self.printer.writeline("_template_uri=%r" % self.compiler.uri) - self.printer.writeline( - "_template_cache=cache.Cache(__name__, _modified_time)") - self.printer.writeline( - "_source_encoding=%r" % self.compiler.source_encoding) - if self.compiler.imports: - buf = '' - for imp in self.compiler.imports: - buf += imp + "\n" - self.printer.writeline(imp) - impcode = ast.PythonCode( - buf, - source='', lineno=0, - pos=0, - filename='template defined imports') - else: - impcode = None - - main_identifiers = module_identifiers.branch(self.node) - module_identifiers.topleveldefs = \ - module_identifiers.topleveldefs.\ - union(main_identifiers.topleveldefs) - module_identifiers.declared.add("UNDEFINED") - 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.write("\n\n") - - if len(module_code): - self.write_module_code(module_code) - - if len(inherit): - self.write_namespaces(namespaces) - self.write_inherit(inherit[-1]) - elif len(namespaces): - self.write_namespaces(namespaces) - - return main_identifiers.topleveldefs.values() - -##### continue [ticket:98] below #### - - 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.""" - - if self.in_def: - decorator = node.decorator - if decorator: - self.printer.writeline("@runtime._decorate_toplevel(%s)" % decorator) - - self.printer.writelines( - "def %s(%s):" % (name, ','.join(args)), - "context.caller_stack._push_frame()", - "try:" - ) - if buffered or filtered or cached: - self.printer.writeline("context._push_buffer()") - - self.identifier_stack.append(self.compiler.identifiers.branch(self.node)) - if not self.in_def 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): - 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) - - for n in self.node.nodes: - n.accept_visitor(self) - - self.write_def_finish(self.node, buffered, filtered, cached) - self.printer.writeline(None) - self.printer.write("\n\n") - if cached: - self.write_cache_decorator(node, name, args, buffered, self.identifiers, toplevel=True) - - def write_module_code(self, module_code): - """write module-level template code, i.e. that which is enclosed in <%! %> tags - in the template.""" - for n in module_code: - self.write_source_comment(n) - self.printer.write_indented_block(n.text) - - def write_inherit(self, node): - """write the module-level inheritance-determination callable.""" - 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 - ) - - def write_namespaces(self, namespaces): - """write the module-level namespace-generating callable.""" - self.printer.writelines( - "def _mako_get_namespace(context, name):", - "try:", - "return context.namespaces[(__name__, name)]", - "except KeyError:", - "_mako_generate_namespaces(context)", - "return context.namespaces[(__name__, name)]", - None,None - ) - self.printer.writeline("def _mako_generate_namespaces(context):") - for node in namespaces.values(): - if node.attributes.has_key('import'): - self.compiler.has_ns_imports = True - self.write_source_comment(node) - if len(node.nodes): - self.printer.writeline("def make_namespace():") - export = [] - identifiers = self.compiler.identifiers.branch(node) - class NSDefVisitor(object): - def visitDefTag(s, node): - self.write_inline_def(node, identifiers, nested=False) - export.append(node.name) - vis = NSDefVisitor() - for n in node.nodes: - n.accept_visitor(vis) - self.printer.writeline("return [%s]" % (','.join(export))) - self.printer.writeline(None) - callable_name = "make_namespace()" - else: - callable_name = "None" - self.printer.writeline("ns = runtime.Namespace(%s, context._clean_inheritance_tokens(), templateuri=%s, callables=%s, calling_uri=_template_uri, module=%s)" % (repr(node.name), node.parsed_attributes.get('file', 'None'), callable_name, node.parsed_attributes.get('module', 'None'))) - 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)) - self.printer.write("\n") - if not len(namespaces): - self.printer.writeline("pass") - self.printer.writeline(None) - - def write_variable_declares(self, identifiers, toplevel=False, limit=None): - """write variable declarations at the top of a function. - - the variable declarations are in the form of callable definitions for defs and/or - name lookup within the function's context argument. the names declared are based on the - names that are referenced in the function body, which don't otherwise have any explicit - assignment operation. names that are assigned within the body are assumed to be - locally-scoped variables and are not separately declared. - - for def callable definitions, if the def is a top-level callable then a - 'stub' callable is generated which wraps the current Context into a closure. if the def - is not top-level, it is fully rendered as a local closure.""" - - # collection of all defs available to us in this scope - comp_idents = dict([(c.name, c) for c in identifiers.defs]) - to_write = util.Set() - - # write "context.get()" for all variables we are going to need that arent in the namespace yet - to_write = to_write.union(identifiers.undeclared) - - # write closure functions for closures that we define right here - to_write = to_write.union(util.Set([c.name for c in identifiers.closuredefs.values()])) - - # remove identifiers that are declared in the argument signature of the callable - to_write = to_write.difference(identifiers.argument_declared) - - # remove identifiers that we are going to assign to. in this way we mimic Python's behavior, - # i.e. assignment to a variable within a block means that variable is now a "locally declared" var, - # which cannot be referenced beforehand. - to_write = to_write.difference(identifiers.locally_declared) - - # if a limiting set was sent, constraint to those items in that list - # (this is used for the caching decorator) - if limit is not None: - to_write = to_write.intersection(limit) - - 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.iteritems(): - if ns.attributes.has_key('import'): - self.printer.writeline("_mako_get_namespace(context, %s)._populate(_import_ns, %s)" % (repr(ident), repr(re.split(r'\s*,\s*', ns.attributes['import'])))) - - for ident in to_write: - if ident in comp_idents: - comp = comp_idents[ident] - if comp.is_root(): - self.write_def_decl(comp, identifiers) - else: - self.write_inline_def(comp, identifiers, nested=True) - elif ident in self.compiler.namespaces: - self.printer.writeline("%s = _mako_get_namespace(context, %s)" % (ident, repr(ident))) - else: - if getattr(self.compiler, 'has_ns_imports', False): - self.printer.writeline("%s = _import_ns.get(%s, context.get(%s, UNDEFINED))" % (ident, repr(ident), repr(ident))) - else: - self.printer.writeline("%s = context.get(%s, UNDEFINED)" % (ident, repr(ident))) - - self.printer.writeline("__M_writer = context.writer()") - - def write_source_comment(self, node): - """write a source comment containing the line number of the corresponding template line.""" - if self.last_source_line != node.lineno: - self.printer.writeline("# SOURCE LINE %d" % node.lineno) - self.last_source_line = node.lineno - - def write_def_decl(self, node, identifiers): - """write a locally-available callable referencing a top-level def""" - funcname = node.function_decl.funcname - namedecls = node.function_decl.get_argument_expressions() - nameargs = node.function_decl.get_argument_expressions(include_defaults=False) - 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)') - else: - nameargs.insert(0, 'context') - self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls))) - self.printer.writeline("return render_%s(%s)" % (funcname, ",".join(nameargs))) - self.printer.writeline(None) - - def write_inline_def(self, node, identifiers, nested): - """write a locally-available def callable inside an enclosing def.""" - namedecls = node.function_decl.get_argument_expressions() - - decorator = node.decorator - if decorator: - self.printer.writeline("@runtime._decorate_inline(context, %s)" % decorator) - self.printer.writeline("def %s(%s):" % (node.name, ",".join(namedecls))) - filtered = len(node.filter_args.args) > 0 - buffered = eval(node.attributes.get('buffered', 'False')) - cached = eval(node.attributes.get('cached', 'False')) - self.printer.writelines( - "context.caller_stack._push_frame()", - "try:" - ) - if buffered or filtered or cached: - self.printer.writelines( - "context._push_buffer()", - ) - - identifiers = identifiers.branch(node, nested=nested) - - self.write_variable_declares(identifiers) - - self.identifier_stack.append(identifiers) - for n in node.nodes: - n.accept_visitor(self) - self.identifier_stack.pop() - - self.write_def_finish(node, buffered, filtered, cached) - self.printer.writeline(None) - if cached: - self.write_cache_decorator(node, node.name, namedecls, False, identifiers, inline=True, toplevel=False) - - def write_def_finish(self, node, buffered, filtered, cached, callstack=True): - """write the end section of a rendering function, either outermost or inline. - - this takes into account if the rendering function was filtered, buffered, etc. - and closes the corresponding try: block if any, and writes code to retrieve captured content, - apply filters, send proper return value.""" - if not buffered and not cached and not filtered: - self.printer.writeline("return ''") - if callstack: - self.printer.writelines( - "finally:", - "context.caller_stack._pop_frame()", - None - ) - - if buffered or filtered or cached: - if buffered or cached: - # in a caching scenario, don't try to get a writer - # from the context after popping; assume the caching - # implemenation might be using a context with no - # extra buffers - self.printer.writelines( - "finally:", - "__M_buf = context._pop_buffer()" - ) - else: - self.printer.writelines( - "finally:", - "__M_buf, __M_writer = context._pop_buffer_and_writer()" - ) - - if callstack: - self.printer.writeline("context.caller_stack._pop_frame()") - - s = "__M_buf.getvalue()" - if filtered: - 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) - 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): - """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)) - cacheargs = {} - for arg in (('cache_type', 'type'), ('cache_dir', 'data_dir'), ('cache_timeout', 'expiretime'), ('cache_url', 'url')): - val = node_or_pagetag.parsed_attributes.get(arg[0], None) - if val is not None: - if arg[1] == 'expiretime': - cacheargs[arg[1]] = int(eval(val)) - else: - cacheargs[arg[1]] = val - else: - if self.compiler.pagetag is not None: - val = self.compiler.pagetag.parsed_attributes.get(arg[0], None) - if val is not None: - if arg[1] == 'expiretime': - cacheargs[arg[1]] == int(eval(val)) - else: - cacheargs[arg[1]] = val - - self.printer.writeline("def %s(%s):" % (name, ','.join(args))) - - # form "arg1, arg2, arg3=arg3, arg4=arg4", etc. - pass_args = [ '=' in a and "%s=%s" % ((a.split('=')[0],)*2) or a for a in args] - - self.write_variable_declares(identifiers, toplevel=toplevel, limit=node_or_pagetag.undeclared_identifiers()) - if buffered: - s = "context.get('local').get_cached(%s, defname=%r, %screatefunc=lambda:__M_%s(%s))" % (cachekey, name, ''.join(["%s=%s, " % (k,v) for k, v in cacheargs.iteritems()]), name, ','.join(pass_args)) - # apply buffer_filters - s = self.create_filter_callable(self.compiler.buffer_filters, s, False) - self.printer.writelines("return " + s,None) - else: - self.printer.writelines( - "__M_writer(context.get('local').get_cached(%s, defname=%r, %screatefunc=lambda:__M_%s(%s)))" % (cachekey, name, ''.join(["%s=%s, " % (k,v) for k, v in cacheargs.iteritems()]), name, ','.join(pass_args)), - "return ''", - None - ) - - def create_filter_callable(self, args, target, is_expression): - """write a filter-applying expression based on the filters present in the given - filter names, adjusting for the global 'default' filter aliases as needed.""" - def locate_encode(name): - if re.match(r'decode\..+', name): - return "filters." + name - else: - return filters.DEFAULT_ESCAPES.get(name, name) - - if 'n' not in args: - if is_expression: - if self.compiler.pagetag: - args = self.compiler.pagetag.filter_args.args + args - if self.compiler.default_filters: - args = self.compiler.default_filters + args - for e in args: - # if filter given as a function, get just the identifier portion - if e == 'n': - continue - m = re.match(r'(.+?)(\(.*\))', e) - if m: - (ident, fargs) = m.group(1,2) - f = locate_encode(ident) - e = f + fargs - else: - x = e - e = locate_encode(e) - assert e is not None - target = "%s(%s)" % (e, target) - return target - - def visitExpression(self, node): - self.write_source_comment(node) - 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) - - def visitControlLine(self, node): - if node.isend: - self.printer.writeline(None) - else: - self.write_source_comment(node) - self.printer.writeline(node.text) - def visitText(self, node): - self.write_source_comment(node) - self.printer.writeline("__M_writer(%s)" % repr(node.content)) - def visitTextTag(self, node): - filtered = len(node.filter_args.args) > 0 - if filtered: - self.printer.writelines( - "__M_writer = context._push_writer()", - "try:", - ) - for n in node.nodes: - n.accept_visitor(self) - if filtered: - 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 - ) - - def visitCode(self, node): - if not node.ismodule: - self.write_source_comment(node) - self.printer.write_indented_block(node.text) - - if not self.in_def and len(self.identifiers.locally_assigned) > 0: - # if we are the "template" def, fudge locally declared/modified variables into the "__M_locals" dictionary, - # which is used for def calls within the same template, to simulate "enclosing scope" - self.printer.writeline('__M_locals.update(__M_dict_builtin([(__M_key, __M_locals_builtin()[__M_key]) for __M_key in [%s] if __M_key in __M_locals_builtin()]))' % ','.join([repr(x) for x in node.declared_identifiers()])) - - def visitIncludeTag(self, node): - self.write_source_comment(node) - args = node.attributes.get('args') - if args: - self.printer.writeline("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'])) - - def visitNamespaceTag(self, node): - pass - - def visitDefTag(self, node): - pass - - def visitCallNamespaceTag(self, node): - # TODO: we can put namespace-specific checks here, such - # as ensure the given namespace will be imported, - # pre-import the namespace, etc. - self.visitCallTag(node) - - def visitCallTag(self, node): - self.printer.writeline("def ccall(caller):") - 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') - - self.identifier_stack.append(body_identifiers) - class DefVisitor(object): - def visitDefTag(s, node): - self.write_inline_def(node, callable_identifiers, nested=False) - export.append(node.name) - # remove defs that are within the <%call> from the "closuredefs" defined - # in the body, so they dont render twice - if node.name in body_identifiers.closuredefs: - del body_identifiers.closuredefs[node.name] - - vis = DefVisitor() - for n in node.nodes: - n.accept_visitor(vis) - self.identifier_stack.pop() - - bodyargs = node.body_decl.get_argument_expressions() - 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.write_variable_declares(body_identifiers) - self.identifier_stack.append(body_identifiers) - - for n in node.nodes: - n.accept_visitor(self) - 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( - # get local reference to current caller, if any - "caller = context.caller_stack._get_caller()", - # push on caller for nested call - "context.caller_stack.nextcaller = runtime.Namespace('caller', context, callables=ccall(caller))", - "try:") - self.write_source_comment(node) - self.printer.writelines( - "__M_writer(%s)" % self.create_filter_callable([], node.expression, True), - "finally:", - "context.caller_stack.nextcaller = None", - None - ) - -class _Identifiers(object): - """tracks the status of identifier names as template code is rendered.""" - def __init__(self, node=None, parent=None, nested=False): - if parent is not None: - # things that have already been declared in an enclosing namespace (i.e. names we can just use) - self.declared = util.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 had as undeclared will have been declared by that parent, - # and therefore we have them in our scope. - if nested: - self.declared = self.declared.union(parent.undeclared) - - # top level defs that are available - self.topleveldefs = util.SetLikeDict(**parent.topleveldefs) - else: - self.declared = util.Set() - self.topleveldefs = util.SetLikeDict() - - # things within this level that are referenced before they are declared (e.g. assigned to) - self.undeclared = util.Set() - - # things that are declared locally. some of these things could be in the "undeclared" - # list as well if they are referenced before declared - self.locally_declared = util.Set() - - # assignments made in explicit python blocks. these will be propigated to - # the context of local def calls. - self.locally_assigned = util.Set() - - # things that are declared in the argument signature of the def callable - self.argument_declared = util.Set() - - # closure defs that are defined in this level - self.closuredefs = util.SetLikeDict() - - self.node = node - - if node is not None: - node.accept_visitor(self) - - def branch(self, node, **kwargs): - """create a new Identifiers for a new Node, with this Identifiers as the parent.""" - return _Identifiers(node, self, **kwargs) - - defs = property(lambda self:util.Set(self.topleveldefs.union(self.closuredefs).values())) - - def __repr__(self): - return "Identifiers(declared=%s, locally_declared=%s, undeclared=%s, topleveldefs=%s, closuredefs=%s, argumenetdeclared=%s)" % (repr(list(self.declared)), repr(list(self.locally_declared)), repr(list(self.undeclared)), repr([c.name for c in self.topleveldefs.values()]), repr([c.name for c in self.closuredefs.values()]), repr(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): - self.undeclared.add(ident) - for ident in node.declared_identifiers(): - self.locally_declared.add(ident) - - def add_declared(self, ident): - self.declared.add(ident) - if ident in self.undeclared: - self.undeclared.remove(ident) - - def visitExpression(self, node): - self.check_declared(node) - def visitControlLine(self, node): - self.check_declared(node) - def visitCode(self, node): - if not node.ismodule: - self.check_declared(node) - self.locally_assigned = self.locally_assigned.union(node.declared_identifiers()) - def visitDefTag(self, node): - if node.is_root(): - self.topleveldefs[node.name] = node - elif node is not self.node: - self.closuredefs[node.name] = node - for ident in node.undeclared_identifiers(): - if ident != 'context' and ident not in self.declared.union(self.locally_declared): - self.undeclared.add(ident) - # visit defs only one level deep - if node is self.node: - for ident in node.declared_identifiers(): - self.argument_declared.add(ident) - for n in node.nodes: - n.accept_visitor(self) - def visitIncludeTag(self, node): - self.check_declared(node) - def visitPageTag(self, node): - for ident in node.declared_identifiers(): - self.argument_declared.add(ident) - self.check_declared(node) - - def visitCallNamespaceTag(self, node): - self.visitCallTag(node) - - 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): - self.undeclared.add(ident) - for ident in node.declared_identifiers(): - self.argument_declared.add(ident) - for n in node.nodes: - n.accept_visitor(self) - else: - for ident in node.undeclared_identifiers(): - if ident != 'context' and ident not in self.declared.union(self.locally_declared): - self.undeclared.add(ident) - diff --git a/lib/mako/exceptions.py b/lib/mako/exceptions.py deleted file mode 100644 index dcd6a64..0000000 --- a/lib/mako/exceptions.py +++ /dev/null @@ -1,283 +0,0 @@ -# exceptions.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""exception classes""" - -import traceback, sys, re -from mako import util - -class MakoException(Exception): - pass - -class RuntimeException(MakoException): - pass - -def _format_filepos(lineno, pos, filename): - if filename is None: - return " at line: %d char: %d" % (lineno, pos) - else: - return " in file '%s' at line: %d char: %d" % (filename, lineno, pos) -class CompileException(MakoException): - def __init__(self, message, source, lineno, pos, filename): - MakoException.__init__(self, message + _format_filepos(lineno, pos, filename)) - self.lineno =lineno - self.pos = pos - self.filename = filename - self.source = source - -class SyntaxException(MakoException): - def __init__(self, message, source, lineno, pos, filename): - MakoException.__init__(self, message + _format_filepos(lineno, pos, filename)) - self.lineno =lineno - self.pos = pos - self.filename = filename - self.source = source - -class TemplateLookupException(MakoException): - pass - -class TopLevelLookupException(TemplateLookupException): - pass - -class RichTraceback(object): - """pulls the current exception from the sys traceback and extracts Mako-specific - template information. - - Usage: - - RichTraceback() - - Properties: - - error - the exception instance. - message - the exception error message as unicode - source - source code of the file where the error occured. if the error occured within a compiled template, - this is the template source. - lineno - line number where the error occured. if the error occured within a compiled template, the line number - is adjusted to that of the template source - records - a list of 8-tuples containing the original python traceback elements, plus the - filename, line number, source line, and full template source for the traceline mapped back to its originating source - template, if any for that traceline (else the fields are None). - reverse_records - the list of records in reverse - traceback - a list of 4-tuples, in the same format as a regular python traceback, with template-corresponding - traceback records replacing the originals - reverse_traceback - the traceback list in reverse - - """ - def __init__(self, traceback=None): - (self.source, self.lineno) = ("", 0) - (t, self.error, self.records) = self._init(traceback) - if self.error is None: - self.error = t - if isinstance(self.error, CompileException) or isinstance(self.error, SyntaxException): - import mako.template - self.source = self.error.source - self.lineno = self.error.lineno - self._has_source = True - self.reverse_records = [r for r in self.records] - self.reverse_records.reverse() - self.init_message() - - def init_message(self): - """Find a unicode representation of self.error""" - try: - self.message = unicode(self.error) - except UnicodeError: - try: - self.message = str(self.error) - except UnicodeEncodeError: - # Fallback to args as neither unicode nor - # str(Exception(u'\xe6')) work in Python < 2.6 - self.message = self.error.args[0] - if not isinstance(self.message, unicode): - self.message = unicode(self.message, 'ascii', 'replace') - - def _get_reformatted_records(self, records): - for rec in records: - if rec[6] is not None: - yield (rec[4], rec[5], rec[2], rec[6]) - else: - yield tuple(rec[0:4]) - traceback = property(lambda self:self._get_reformatted_records(self.records), doc=""" - return a list of 4-tuple traceback records (i.e. normal python format) - with template-corresponding lines remapped to the originating template - """) - reverse_traceback = property(lambda self:self._get_reformatted_records(self.reverse_records), doc=""" - return the same data as traceback, except in reverse order - """) - def _init(self, trcback): - """format a traceback from sys.exc_info() into 7-item tuples, containing - the regular four traceback tuple items, plus the original template - filename, the line number adjusted relative to the template source, and - code line from that line number of the template.""" - import mako.template - mods = {} - if not trcback: - (type, value, trcback) = sys.exc_info() - rawrecords = traceback.extract_tb(trcback) - new_trcback = [] - for filename, lineno, function, line in rawrecords: - try: - (line_map, template_lines) = mods[filename] - except KeyError: - try: - info = mako.template._get_module_info(filename) - module_source = info.code - template_source = info.source - template_filename = info.template_filename or filename - except KeyError: - # A normal .py file (not a Template) - try: - fp = open(filename) - encoding = util.parse_encoding(fp) - fp.close() - except IOError: - encoding = None - if encoding: - line = line.decode(encoding) - else: - line = line.decode('ascii', 'replace') - new_trcback.append((filename, lineno, function, line, None, None, None, None)) - continue - - template_ln = module_ln = 1 - line_map = {} - for line in module_source.split("\n"): - match = re.match(r'\s*# SOURCE LINE (\d+)', line) - if match: - template_ln = int(match.group(1)) - else: - template_ln += 1 - module_ln += 1 - line_map[module_ln] = template_ln - template_lines = [line for line in template_source.split("\n")] - mods[filename] = (line_map, template_lines) - - template_ln = line_map[lineno] - if template_ln <= len(template_lines): - 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)) - if not self.source: - for l in range(len(new_trcback)-1, 0, -1): - if new_trcback[l][5]: - self.source = new_trcback[l][7] - self.lineno = new_trcback[l][5] - break - else: - try: - # A normal .py file (not a Template) - fp = open(new_trcback[-1][0]) - encoding = util.parse_encoding(fp) - fp.seek(0) - self.source = fp.read() - fp.close() - if encoding: - self.source = self.source.decode(encoding) - except IOError: - self.source = '' - self.lineno = new_trcback[-1][1] - return (type, value, new_trcback) - - -def text_error_template(lookup=None): - """provides a template that renders a stack trace in a similar format to the Python interpreter, - substituting source template filenames, line numbers and code for that of the originating - source template, as applicable.""" - import mako.template - return mako.template.Template(r""" -<%page args="traceback=None"/> -<%! - from mako.exceptions import RichTraceback -%>\ -<% - tback = RichTraceback(traceback=traceback) -%>\ -Traceback (most recent call last): -% for (filename, lineno, function, line) in tback.traceback: - File "${filename}", line ${lineno}, in ${function or '?'} - ${line | unicode.strip} -% endfor -${str(tback.error.__class__.__name__)}: ${tback.message} -""") - -def html_error_template(): - """provides a template that renders a stack trace in an HTML format, providing an excerpt of - code as well as substituting source template filenames, line numbers and code - for that of the originating source template, as applicable. - - the template's default encoding_errors value is 'htmlentityreplace'. the template has - two options: - - with the full option disabled, only a section of an HTML document is returned. - with the css option disabled, the default stylesheet won't be included.""" - import mako.template - return mako.template.Template(r""" -<%! - from mako.exceptions import RichTraceback -%> -<%page args="full=True, css=True, traceback=None"/> -% if full: -<html> -<head> - <title>Mako Runtime Error</title> -% endif -% if css: - <style> - body { font-family:verdana; margin:10px 30px 10px 30px;} - .stacktrace { margin:5px 5px 5px 5px; } - .highlight { padding:0px 10px 0px 10px; background-color:#9F9FDF; } - .nonhighlight { padding:0px; background-color:#DFDFDF; } - .sample { padding:10px; margin:10px 10px 10px 10px; font-family:monospace; } - .sampleline { padding:0px 10px 0px 10px; } - .sourceline { margin:5px 5px 10px 5px; font-family:monospace;} - .location { font-size:80%; } - </style> -% endif -% if full: -</head> -<body> -% endif - -<h2>Error !</h2> -<% - tback = RichTraceback(traceback=traceback) - src = tback.source - line = tback.lineno - if src: - lines = src.split('\n') - else: - lines = None -%> -<h3>${str(tback.error.__class__.__name__)}: ${tback.message}</h3> - -% if lines: - <div class="sample"> - <div class="nonhighlight"> -% for index in range(max(0, line-4),min(len(lines), line+5)): - % if index + 1 == line: -<div class="highlight">${index + 1} ${lines[index] | h}</div> - % else: -<div class="sampleline">${index + 1} ${lines[index] | h}</div> - % endif -% endfor - </div> - </div> -% endif - -<div class="stacktrace"> -% for (filename, lineno, function, line) in tback.reverse_traceback: - <div class="location">${filename}, line ${lineno}:</div> - <div class="sourceline">${line | h}</div> -% endfor -</div> - -% if full: -</body> -</html> -% endif -""", output_encoding=sys.getdefaultencoding(), encoding_errors='htmlentityreplace') diff --git a/lib/mako/ext/__init__.py b/lib/mako/ext/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/lib/mako/ext/__init__.py +++ /dev/null diff --git a/lib/mako/ext/autohandler.py b/lib/mako/ext/autohandler.py deleted file mode 100644 index 3025f8e..0000000 --- a/lib/mako/ext/autohandler.py +++ /dev/null @@ -1,57 +0,0 @@ -"""adds autohandler functionality to Mako templates. - -requires that the TemplateLookup class is used with templates. - -usage: - -<%! - from mako.ext.autohandler import autohandler -%> -<%inherit file="${autohandler(template, context)}"/> - - -or with custom autohandler filename: - -<%! - from mako.ext.autohandler import autohandler -%> -<%inherit file="${autohandler(template, context, name='somefilename')}"/> - -""" - -import posixpath, os, re - -def autohandler(template, context, name='autohandler'): - lookup = context.lookup - _template_uri = template.module._template_uri - if not lookup.filesystem_checks: - try: - return lookup._uri_cache[(autohandler, _template_uri, name)] - except KeyError: - pass - - tokens = re.findall(r'([^/]+)', posixpath.dirname(_template_uri)) + [name] - while len(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) - else: - return path - if len(tokens) == 1: - break - tokens[-2:] = [name] - - if not lookup.filesystem_checks: - return lookup._uri_cache.setdefault((autohandler, _template_uri, name), None) - else: - return None - -def _file_exists(lookup, path): - psub = re.sub(r'^/', '',path) - for d in lookup.directories: - if os.path.exists(d + '/' + psub): - return True - else: - return False - diff --git a/lib/mako/ext/babelplugin.py b/lib/mako/ext/babelplugin.py deleted file mode 100644 index 9f08c5e..0000000 --- a/lib/mako/ext/babelplugin.py +++ /dev/null @@ -1,123 +0,0 @@ -"""gettext message extraction via Babel: http://babel.edgewall.org/""" -from StringIO import StringIO - -from babel.messages.extract import extract_python - -from mako import lexer, parsetree - -def extract(fileobj, keywords, comment_tags, options): - """Extract messages from Mako templates. - - :param fileobj: the file-like object the messages should be extracted from - :param keywords: a list of keywords (i.e. function names) that should be - recognized as translation functions - :param comment_tags: a list of translator tags to search for and include - in the results - :param options: a dictionary of additional options (optional) - :return: an iterator over ``(lineno, funcname, message, comments)`` tuples - :rtype: ``iterator`` - """ - encoding = options.get('input_encoding', options.get('encoding', None)) - - template_node = lexer.Lexer(fileobj.read(), - input_encoding=encoding).parse() - for extracted in extract_nodes(template_node.get_children(), - keywords, comment_tags, options): - yield extracted - -def extract_nodes(nodes, keywords, comment_tags, options): - """Extract messages from Mako's lexer node objects - - :param nodes: an iterable of Mako parsetree.Node objects to extract from - :param keywords: a list of keywords (i.e. function names) that should be - recognized as translation functions - :param comment_tags: a list of translator tags to search for and include - in the results - :param options: a dictionary of additional options (optional) - :return: an iterator over ``(lineno, funcname, message, comments)`` tuples - :rtype: ``iterator`` - """ - translator_comments = [] - in_translator_comments = False - - for node in nodes: - child_nodes = None - if in_translator_comments and isinstance(node, parsetree.Text) and \ - not node.content.strip(): - # Ignore whitespace within translator comments - continue - - if isinstance(node, parsetree.Comment): - value = node.text.strip() - if in_translator_comments: - translator_comments.extend(_split_comment(node.lineno, value)) - continue - for comment_tag in comment_tags: - if value.startswith(comment_tag): - in_translator_comments = True - translator_comments.extend(_split_comment(node.lineno, - value)) - continue - - if isinstance(node, parsetree.DefTag): - code = node.function_decl.code - child_nodes = node.nodes - elif isinstance(node, parsetree.CallTag): - code = node.code.code - child_nodes = node.nodes - elif isinstance(node, parsetree.PageTag): - code = node.body_decl.code - elif isinstance(node, parsetree.CallNamespaceTag): - attribs = ', '.join(['%s=%s' % (key, val) - for key, val in node.attributes.iteritems()]) - code = '{%s}' % attribs - child_nodes = node.nodes - elif isinstance(node, parsetree.ControlLine): - if node.isend: - translator_comments = [] - in_translator_comments = False - continue - code = node.text - elif isinstance(node, parsetree.Code): - # <% and <%! blocks would provide their own translator comments - translator_comments = [] - in_translator_comments = False - - code = node.code.code - elif isinstance(node, parsetree.Expression): - code = node.code.code - else: - translator_comments = [] - in_translator_comments = False - continue - - # Comments don't apply unless they immediately preceed the message - if translator_comments and \ - translator_comments[-1][0] < node.lineno - 1: - translator_comments = [] - else: - translator_comments = \ - [comment[1] for comment in translator_comments] - - if isinstance(code, unicode): - code = code.encode('ascii', 'backslashreplace') - code = StringIO(code) - for lineno, funcname, messages, python_translator_comments \ - in extract_python(code, keywords, comment_tags, options): - yield (node.lineno + (lineno - 1), funcname, messages, - translator_comments + python_translator_comments) - - translator_comments = [] - in_translator_comments = False - - if child_nodes: - for extracted in extract_nodes(child_nodes, keywords, comment_tags, - options): - yield extracted - - -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())] diff --git a/lib/mako/ext/preprocessors.py b/lib/mako/ext/preprocessors.py deleted file mode 100644 index 601ac0d..0000000 --- a/lib/mako/ext/preprocessors.py +++ /dev/null @@ -1,20 +0,0 @@ -"""preprocessing functions, used with the 'preprocessor' argument on Template, TemplateLookup""" - -import re - -def convert_comments(text): - """preprocess old style comments. - - example: - - from mako.ext.preprocessors import convert_comments - t = Template(..., preprocessor=preprocess_comments)""" - return re.sub(r'(?<=\n)\s*#[^#]', "##", text) - -# TODO -def create_tag(callable): - """given a callable, extract the *args and **kwargs, and produce a preprocessor - that will parse for <%<funcname> <args>> and convert to an appropriate <%call> statement. - - this allows any custom tag to be created which looks like a pure Mako-style tag.""" - raise NotImplementedError("Future functionality....")
\ No newline at end of file diff --git a/lib/mako/ext/pygmentplugin.py b/lib/mako/ext/pygmentplugin.py deleted file mode 100644 index 09ffe12..0000000 --- a/lib/mako/ext/pygmentplugin.py +++ /dev/null @@ -1,101 +0,0 @@ -import re -try: - set -except NameError: - from sets import Set as set - -from pygments.lexers.web import \ - HtmlLexer, XmlLexer, JavascriptLexer, CssLexer -from pygments.lexers.agile import PythonLexer -from pygments.lexer import Lexer, DelegatingLexer, RegexLexer, bygroups, \ - include, using, this -from pygments.token import Error, Punctuation, \ - Text, Comment, Operator, Keyword, Name, String, Number, Other, Literal -from pygments.util import html_doctype_matches, looks_like_xml - -class MakoLexer(RegexLexer): - 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) - (.+?) # anything, followed by: - (?: - (?<=\n)(?=%|\#\#) | # an eval or comment line - (?=\#\*) | # multiline comment - (?=</?%) | # a python block - # call start or end - (?=\$\{) | # a substitution - (?<=\n)(?=\s*%) | - # - don't consume - (\\\n) | # an escaped newline - \Z # end of string - ) - ''', bygroups(Other, Operator)), - (r'\s+', Text), - ], - '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), - ], - 'attr': [ - ('".*?"', String, '#pop'), - ("'.*?'", String, '#pop'), - (r'[^\s>]+', String, '#pop'), - ], - } - - -class MakoHtmlLexer(DelegatingLexer): - name = 'HTML+Mako' - aliases = ['html+mako'] - - def __init__(self, **options): - super(MakoHtmlLexer, self).__init__(HtmlLexer, MakoLexer, - **options) - -class MakoXmlLexer(DelegatingLexer): - name = 'XML+Mako' - aliases = ['xml+mako'] - - def __init__(self, **options): - super(MakoXmlLexer, self).__init__(XmlLexer, MakoLexer, - **options) - -class MakoJavascriptLexer(DelegatingLexer): - name = 'JavaScript+Mako' - aliases = ['js+mako', 'javascript+mako'] - - def __init__(self, **options): - super(MakoJavascriptLexer, self).__init__(JavascriptLexer, - MakoLexer, **options) - -class MakoCssLexer(DelegatingLexer): - name = 'CSS+Mako' - aliases = ['css+mako'] - - def __init__(self, **options): - super(MakoCssLexer, self).__init__(CssLexer, MakoLexer, - **options) diff --git a/lib/mako/ext/turbogears.py b/lib/mako/ext/turbogears.py deleted file mode 100644 index f82f907..0000000 --- a/lib/mako/ext/turbogears.py +++ /dev/null @@ -1,50 +0,0 @@ -import re, inspect -from mako.lookup import TemplateLookup -from mako.template import Template - -class TGPlugin(object): - """TurboGears compatible Template Plugin.""" - - def __init__(self, extra_vars_func=None, options=None, extension='mak'): - self.extra_vars_func = extra_vars_func - self.extension = extension - if not options: - options = {} - - # Pull the options out and initialize the lookup - lookup_options = {} - for k, v in options.iteritems(): - if k.startswith('mako.'): - lookup_options[k[5:]] = v - elif k in ['directories', 'filesystem_checks', 'module_directory']: - lookup_options[k] = v - self.lookup = TemplateLookup(**lookup_options) - - self.tmpl_options = {} - # transfer lookup args to template args, based on those available - # in getargspec - for kw in inspect.getargspec(Template.__init__)[0]: - if kw in lookup_options: - self.tmpl_options[kw] = lookup_options[kw] - - def load_template(self, templatename, template_string=None): - """Loads a template from a file or a string""" - 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 - - # Lookup template - return self.lookup.get_template(templatename) - - def render(self, info, format="html", fragment=False, template=None): - if isinstance(template, basestring): - template = self.load_template(template) - - # Load extra vars func if provided - if self.extra_vars_func: - info.update(self.extra_vars_func()) - - return template.render(**info) - diff --git a/lib/mako/filters.py b/lib/mako/filters.py deleted file mode 100644 index 9a5b21d..0000000 --- a/lib/mako/filters.py +++ /dev/null @@ -1,170 +0,0 @@ -# filters.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Geoffrey T. Dairiki <dairiki@dairiki.org> and Michael Bayer <mike_mp@zzzcomputing.com> -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - - -import re, cgi, urllib, htmlentitydefs, codecs -from StringIO import StringIO - -xml_escapes = { - '&' : '&', - '>' : '>', - '<' : '<', - '"' : '"', # also " in html-only - "'" : ''' # also ' in html-only -} -# XXX: " is valid in HTML and XML -# ' is not valid HTML, but is valid XML - -def html_escape(string): - return cgi.escape(string, True) - -def xml_escape(string): - return re.sub(r'([&<"\'>])', lambda m: xml_escapes[m.group()], string) - -def url_escape(string): - # convert into a list of octets - string = string.encode("utf8") - return urllib.quote_plus(string) - -def url_unescape(string): - text = urllib.unquote_plus(string) - if not is_ascii_str(text): - text = text.decode("utf8") - return text - -def trim(string): - return string.strip() - - -class Decode(object): - def __getattr__(self, key): - def decode(x): - if isinstance(x, unicode): - return x - elif not isinstance(x, str): - return unicode(str(x), encoding=key) - else: - return unicode(x, encoding=key) - return decode -decode = Decode() - - -_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, u'&%s;' % n) - for c,n in codepoint2name.iteritems()]) - self.name2codepoint = name2codepoint - - def escape_entities(self, text): - """Replace characters with their character entity references. - - Only characters corresponding to a named entity are replaced. - """ - return unicode(text).translate(self.codepoint2entity) - - def __escape(self, m): - codepoint = ord(m.group()) - try: - return self.codepoint2entity[codepoint] - except (KeyError, IndexError): - return '&#x%X;' % codepoint - - - __escapable = re.compile(r'["&<>]|[^\x00-\x7f]') - - def escape(self, text): - """Replace characters with their character references. - - Replace characters by their named entity references. - Non-ASCII characters, if they do not have a named entity reference, - are replaced by numerical character references. - - The return value is guaranteed to be ASCII. - """ - return self.__escapable.sub(self.__escape, unicode(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'''& (?: - \#(\d+) - | \#x([\da-f]+) - | ( (?!\d) [:\w] [-.:\w]+ ) - ) ;''', - re.X | re.UNICODE) - - def __unescape(self, m): - dval, hval, name = m.groups() - if dval: - codepoint = int(dval) - elif hval: - codepoint = int(hval, 16) - else: - codepoint = self.name2codepoint.get(name, 0xfffd) - # U+FFFD = "REPLACEMENT CHARACTER" - if codepoint < 128: - return chr(codepoint) - return unichr(codepoint) - - def unescape(self, text): - """Unescape character references. - - All character references (both entity references and numerical - character references) are unescaped. - """ - return self.__characterrefs.sub(self.__unescape, text) - - -_html_entities_escaper = XMLEntityEscaper(htmlentitydefs.codepoint2name, - htmlentitydefs.name2codepoint) - -html_entities_escape = _html_entities_escaper.escape_entities -html_entities_unescape = _html_entities_escaper.unescape - - -def htmlentityreplace_errors(ex): - """An encoding error handler. - - This python `codecs`_ error handler replaces unencodable - characters with HTML entities, or, if no HTML entity exists for - the character, XML character references. - - >>> 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] - text = _html_entities_escaper.escape(bad_text) - return (unicode(text), ex.end) - raise ex - -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' -} - - diff --git a/lib/mako/lexer.py b/lib/mako/lexer.py deleted file mode 100644 index 52a4b6d..0000000 --- a/lib/mako/lexer.py +++ /dev/null @@ -1,328 +0,0 @@ -# lexer.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""provides the Lexer class for parsing template strings into parse trees.""" - -import re, codecs -from mako import parsetree, exceptions -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): - self.text = text - self.filename = filename - self.template = parsetree.TemplateNode(self.filename) - self.matched_lineno = 1 - self.matched_charpos = 0 - self.lineno = 1 - self.match_position = 0 - self.tag = [] - self.control_line = [] - self.disable_unicode = disable_unicode - self.encoding = input_encoding - if preprocessor is None: - self.preprocessor = [] - elif not hasattr(preprocessor, '__iter__'): - self.preprocessor = [preprocessor] - else: - self.preprocessor = preprocessor - - exception_kwargs = property(lambda self:{'source':self.text, 'lineno':self.matched_lineno, 'pos':self.matched_charpos, 'filename':self.filename}) - - def match(self, regexp, flags=None): - """match the given regular expression string and flags to the current text position. - - if a match occurs, update the current text and line position.""" - mp = self.match_position - try: - reg = _regexp_cache[(regexp, flags)] - except KeyError: - if flags: - reg = re.compile(regexp, flags) - else: - reg = re.compile(regexp) - _regexp_cache[(regexp, flags)] = reg - - match = reg.match(self.text, self.match_position) - if match: - (start, end) = match.span() - if end == start: - self.match_position = end + 1 - else: - self.match_position = end - self.matched_lineno = self.lineno - 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'): - cp -=1 - self.matched_charpos = mp - cp - self.lineno += len(lines) - #print "MATCHED:", match.group(0), "LINE START:", self.matched_lineno, "LINE END:", self.lineno - #print "MATCH:", regexp, "\n", self.text[mp : mp + 15], (match and "TRUE" or "FALSE") - return match - - def parse_until_text(self, *text): - startpos = self.match_position - while True: - match = self.match(r'#.*\n') - if match: - continue - match = self.match(r'(\"\"\"|\'\'\'|\"|\')') - if match: - m = self.match(r'.*?%s' % match.group(1), re.S) - if not m: - raise exceptions.SyntaxException("Unmatched '%s'" % match.group(1), **self.exception_kwargs) - else: - match = self.match(r'(%s)' % r'|'.join(text)) - if match: - return (self.text[startpos:self.match_position-len(match.group(1))], match.group(1)) - else: - match = self.match(r".*?(?=\"|\'|#|%s)" % r'|'.join(text), re.S) - if not match: - raise exceptions.SyntaxException("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 - node = nodecls(*args, **kwargs) - if len(self.tag): - self.tag[-1].nodes.append(node) - else: - self.template.nodes.append(node) - if isinstance(node, parsetree.Tag): - if len(self.tag): - node.parent = self.tag[-1] - self.tag.append(node) - elif isinstance(node, parsetree.ControlLine): - if node.isend: - self.control_line.pop() - elif node.is_primary: - self.control_line.append(node) - elif len(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) - - def escape_code(self, text): - if not self.disable_unicode and self.encoding: - return text.encode('ascii', 'backslashreplace') - else: - return text - - def parse(self): - for preproc in self.preprocessor: - self.text = preproc(self.text) - if not isinstance(self.text, unicode) and self.text.startswith(codecs.BOM_UTF8): - self.text = self.text[len(codecs.BOM_UTF8):] - parsed_encoding = 'utf-8' - me = self.match_encoding() - if me is not None and me != 'utf-8': - raise exceptions.CompileException("Found utf-8 BOM in file, with conflicting magic encoding comment of '%s'" % me, self.text.decode('utf-8', 'ignore'), 0, 0, self.filename) - else: - parsed_encoding = self.match_encoding() - if parsed_encoding: - self.encoding = parsed_encoding - if not self.disable_unicode and not isinstance(self.text, unicode): - if self.encoding: - try: - self.text = self.text.decode(self.encoding) - except UnicodeDecodeError, e: - raise exceptions.CompileException("Unicode decode operation of encoding '%s' failed" % self.encoding, self.text.decode('utf-8', 'ignore'), 0, 0, self.filename) - else: - try: - self.text = self.text.decode() - except UnicodeDecodeError, e: - raise exceptions.CompileException("Could not read template using encoding of 'ascii'. Did you forget a magic encoding comment?", self.text.decode('utf-8', 'ignore'), 0, 0, self.filename) - - self.textlength = len(self.text) - - while (True): - if self.match_position > self.textlength: - break - - if self.match_end(): - break - if self.match_expression(): - continue - if self.match_control_line(): - continue - if self.match_comment(): - continue - if self.match_tag_start(): - continue - if self.match_tag_end(): - continue - if self.match_python_block(): - continue - if self.match_text(): - continue - - if self.match_position > self.textlength: - break - raise exceptions.CompileException("assertion failed") - - if len(self.tag): - 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, self.text, self.control_line[-1].lineno, self.control_line[-1].pos, self.filename) - return self.template - - def match_encoding(self): - match = self.match(r'#.*coding[:=]\s*([-\w.]+).*\r?\n') - if match: - return match.group(1) - else: - return None - - def match_tag_start(self): - match = self.match(r''' - \<% # opening tag - - ([\w\.\:]+) # keyword - - ((?:\s+\w+|\s*=\s*|".*?"|'.*?')*) # attrname, = sign, string expression - - \s* # more whitespace - - (/)?> # closing - - ''', - - re.I | re.S | re.X) - - if match: - (keyword, attr, isend) = (match.group(1), match.group(2), match.group(3)) - self.keyword = keyword - attributes = {} - if attr: - for att in re.findall(r"\s*(\w+)\s*=\s*(?:'([^']*)'|\"([^\"]*)\")", attr): - (key, val1, val2) = att - text = val1 or val2 - text = text.replace('\r\n', '\n') - attributes[key] = self.escape_code(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 not match: - raise exceptions.SyntaxException("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 - else: - return False - - def match_tag_end(self): - 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) - 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) - self.tag.pop() - return True - else: - return False - - def match_end(self): - match = self.match(r'\Z', re.S) - if match: - string = match.group() - if string: - return string - else: - return True - else: - return False - - def match_text(self): - match = self.match(r""" - (.*?) # anything, followed by: - ( - (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based comment preceded by a consumed \n and whitespace - | - (?=\${) # an expression - | - (?=\#\*) # multiline comment - | - (?=</?[%&]) # a substitution or block or call start or end - # - don't consume - | - (\\\r?\n) # an escaped newline - throw away - | - \Z # end of string - )""", re.X | re.S) - - if match: - text = match.group(1) - self.append_node(parsetree.Text, text) - return True - else: - return False - - def match_python_block(self): - match = self.match(r"<%(!)?") - if match: - (line, pos) = (self.matched_lineno, self.matched_charpos) - (text, end) = self.parse_until_text(r'%>') - text = adjust_whitespace(text) + "\n" # the trailing newline helps compiler.parse() not complain about indentation - self.append_node(parsetree.Code, self.escape_code(text), match.group(1)=='!', lineno=line, pos=pos) - return True - else: - return False - - def match_expression(self): - match = self.match(r"\${") - if match: - (line, pos) = (self.matched_lineno, self.matched_charpos) - (text, end) = self.parse_until_text(r'\|', r'}') - if end == '|': - (escapes, end) = self.parse_until_text(r'}') - else: - escapes = "" - text = text.replace('\r\n', '\n') - self.append_node(parsetree.Expression, self.escape_code(text), escapes.strip(), lineno=line, pos=pos) - return True - else: - return False - - def match_control_line(self): - match = self.match(r"(?<=^)[\t ]*(%|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)(?:\r?\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 not m2: - raise exceptions.SyntaxException("Invalid control line: '%s'" % text, **self.exception_kwargs) - (isend, keyword) = m2.group(1, 2) - isend = (isend is not None) - - if isend: - if not len(self.control_line): - raise exceptions.SyntaxException("No starting keyword '%s' for '%s'" % (keyword, text), **self.exception_kwargs) - 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) - self.append_node(parsetree.ControlLine, keyword, isend, self.escape_code(text)) - else: - self.append_node(parsetree.Comment, text) - return True - else: - return False - - def match_comment(self): - """matches the multiline version of a comment""" - match = self.match(r"<%doc>(.*?)</%doc>", re.S) - if match: - self.append_node(parsetree.Comment, match.group(1)) - return True - else: - return False - diff --git a/lib/mako/lookup.py b/lib/mako/lookup.py deleted file mode 100644 index 0398c5e..0000000 --- a/lib/mako/lookup.py +++ /dev/null @@ -1,202 +0,0 @@ -# lookup.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer -# mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -import os, stat, posixpath, re -from mako import exceptions, util -from mako.template import Template - -try: - import threading -except: - import dummy_threading as threading - -class TemplateCollection(object): - def has_template(self, uri): - try: - self.get_template(uri) - return True - except exceptions.TemplateLookupException: - return False - - def get_template(self, uri, relativeto=None): - raise NotImplementedError() - - def filename_to_uri(self, uri, filename): - """Convert the given filename to a uri relative to - this TemplateCollection.""" - - return uri - - def adjust_uri(self, uri, filename): - """Adjust the given uri based on the calling filename. - - When this method is called from the runtime, the 'filename' parameter - is taken directly to the 'filename' attribute of the calling template. - Therefore a custom TemplateCollection subclass can place any string - identifier desired in the "filename" parameter of the Template objects - it constructs and have them come back here. - - """ - return uri - -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, - output_encoding=None, - encoding_errors='strict', - cache_type=None, - cache_dir=None, cache_url=None, - cache_enabled=True, - modulename_callable=None, - default_filters=None, - buffer_filters=(), - imports=None, - input_encoding=None, - preprocessor=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 - self.collection_size = collection_size - - self.template_args = { - 'format_exceptions':format_exceptions, - 'error_handler':error_handler, - 'disable_unicode':disable_unicode, - 'output_encoding':output_encoding, - 'encoding_errors':encoding_errors, - 'input_encoding':input_encoding, - 'module_directory':module_directory, - 'cache_type':cache_type, - 'cache_dir':cache_dir or module_directory, - 'cache_url':cache_url, - 'cache_enabled':cache_enabled, - 'default_filters':default_filters, - 'buffer_filters':buffer_filters, - 'imports':imports, - 'preprocessor':preprocessor} - - if collection_size == -1: - self._collection = {} - self._uri_cache = {} - else: - self._collection = util.LRUCache(collection_size) - self._uri_cache = util.LRUCache(collection_size) - self._mutex = threading.Lock() - - def get_template(self, uri): - try: - if self.filesystem_checks: - return self._check(uri, self._collection[uri]) - else: - return self._collection[uri] - except KeyError: - u = re.sub(r'^\/+', '', uri) - for dir in self.directories: - srcfile = posixpath.normpath(posixpath.join(dir, u)) - if os.path.exists(srcfile): - return self._load(srcfile, uri) - else: - raise exceptions.TopLevelLookupException( - "Cant locate template for uri %r" % uri) - - def adjust_uri(self, uri, relativeto): - """adjust the given uri based on the calling filename.""" - - if uri[0] != '/': - if relativeto is not None: - return posixpath.join(posixpath.dirname(relativeto), uri) - else: - return '/' + uri - else: - return uri - - - def filename_to_uri(self, filename): - try: - return self._uri_cache[filename] - except KeyError: - value = self._relativeize(filename) - self._uri_cache[filename] = value - return value - - def _relativeize(self, filename): - """Return the portion of a filename that is 'relative' - to the directories in this lookup. - - """ - - filename = posixpath.normpath(filename) - for dir in self.directories: - if filename[0:len(dir)] == dir: - return filename[len(dir):] - else: - return None - - def _load(self, filename, uri): - self._mutex.acquire() - try: - try: - # try returning from collection one - # more time in case concurrent thread already loaded - return self._collection[uri] - except KeyError: - pass - try: - if self.modulename_callable is not None: - module_filename = self.modulename_callable(filename, uri) - else: - module_filename = None - self._collection[uri] = template = Template( - uri=uri, - filename=posixpath.normpath(filename), - lookup=self, - module_filename=module_filename, - **self.template_args) - return template - except: - # if compilation fails etc, ensure - # template is removed from collection, - # re-raise - self._collection.pop(uri, None) - raise - finally: - self._mutex.release() - - def _check(self, uri, template): - if template.filename is None: - return template - if not os.path.exists(template.filename): - self._collection.pop(uri, None) - raise exceptions.TemplateLookupException( - "Cant locate template for uri %r" % uri) - elif template.module._modified_time < \ - os.stat(template.filename)[stat.ST_MTIME]: - self._collection.pop(uri, None) - return self._load(template.filename, uri) - else: - return template - - def put_string(self, uri, text): - self._collection[uri] = Template( - text, - lookup=self, - uri=uri, - **self.template_args) - - def put_template(self, uri, template): - self._collection[uri] = template - diff --git a/lib/mako/parsetree.py b/lib/mako/parsetree.py deleted file mode 100644 index 347c31a..0000000 --- a/lib/mako/parsetree.py +++ /dev/null @@ -1,422 +0,0 @@ -# parsetree.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""defines the parse tree components for Mako templates.""" - -from mako import exceptions, ast, util, filters -import re - -class Node(object): - """base class for a Node in the parse tree.""" - def __init__(self, source, lineno, pos, filename): - self.source = source - self.lineno = lineno - self.pos = pos - self.filename = filename - - def exception_kwargs(self): - return {'source':self.source, 'lineno':self.lineno, 'pos':self.pos, 'filename':self.filename} - exception_kwargs = property(exception_kwargs) - - def get_children(self): - return [] - - def accept_visitor(self, visitor): - def traverse(node): - for n in node.get_children(): - n.accept_visitor(visitor) - method = getattr(visitor, "visit" + self.__class__.__name__, traverse) - method(self) - -class TemplateNode(Node): - """a 'container' node that stores the overall collection of nodes.""" - - def __init__(self, filename): - super(TemplateNode, self).__init__('', 0, 0, filename) - self.nodes = [] - self.page_attributes = {} - - def get_children(self): - return self.nodes - - def __repr__(self): - return "TemplateNode(%s, %r)" % (util.sorted_dict_repr(self.page_attributes), self.nodes) - -class ControlLine(Node): - """defines a control line, a line-oriented python line or end tag. - - e.g.:: - - % if foo: - (markup) - % endif - - """ - - def __init__(self, keyword, isend, text, **kwargs): - super(ControlLine, self).__init__(**kwargs) - self.text = text - self.keyword = keyword - self.isend = isend - self.is_primary = keyword in ['for','if', 'while', 'try'] - if self.isend: - self._declared_identifiers = [] - self._undeclared_identifiers = [] - else: - code = ast.PythonFragment(text, **self.exception_kwargs) - self._declared_identifiers = code.declared_identifiers - self._undeclared_identifiers = code.undeclared_identifiers - - def declared_identifiers(self): - return self._declared_identifiers - - def undeclared_identifiers(self): - return self._undeclared_identifiers - - def is_ternary(self, keyword): - """return true if the given keyword is a ternary keyword for this ControlLine""" - - return keyword in { - 'if':util.Set(['else', 'elif']), - 'try':util.Set(['except', 'finally']), - 'for':util.Set(['else']) - }.get(self.keyword, []) - - def __repr__(self): - return "ControlLine(%r, %r, %r, %r)" % ( - self.keyword, - self.text, - self.isend, - (self.lineno, self.pos) - ) - -class Text(Node): - """defines plain text in the template.""" - - def __init__(self, content, **kwargs): - super(Text, self).__init__(**kwargs) - self.content = content - - def __repr__(self): - return "Text(%r, %r)" % (self.content, (self.lineno, self.pos)) - -class Code(Node): - """defines a Python code block, either inline or module level. - - e.g.:: - - inline: - <% - x = 12 - %> - - module level: - <%! - import logger - %> - - """ - - def __init__(self, text, ismodule, **kwargs): - super(Code, self).__init__(**kwargs) - self.text = text - self.ismodule = ismodule - self.code = ast.PythonCode(text, **self.exception_kwargs) - - def declared_identifiers(self): - return self.code.declared_identifiers - - def undeclared_identifiers(self): - return self.code.undeclared_identifiers - - def __repr__(self): - return "Code(%r, %r, %r)" % ( - self.text, - self.ismodule, - (self.lineno, self.pos) - ) - -class Comment(Node): - """defines a comment line. - - # this is a comment - - """ - - def __init__(self, text, **kwargs): - super(Comment, self).__init__(**kwargs) - self.text = text - - def __repr__(self): - return "Comment(%r, %r)" % (self.text, (self.lineno, self.pos)) - -class Expression(Node): - """defines an inline expression. - - ${x+y} - - """ - - def __init__(self, text, escapes, **kwargs): - super(Expression, self).__init__(**kwargs) - self.text = text - self.escapes = escapes - self.escapes_code = ast.ArgumentList(escapes, **self.exception_kwargs) - self.code = ast.PythonCode(text, **self.exception_kwargs) - - def declared_identifiers(self): - return [] - - def undeclared_identifiers(self): - # TODO: make the "filter" shortcut list configurable at parse/gen time - return self.code.undeclared_identifiers.union( - self.escapes_code.undeclared_identifiers.difference( - util.Set(filters.DEFAULT_ESCAPES.keys()) - ) - ) - - def __repr__(self): - return "Expression(%r, %r, %r)" % ( - self.text, - self.escapes_code.args, - (self.lineno, self.pos) - ) - -class _TagMeta(type): - """metaclass to allow Tag to produce a subclass according to its keyword""" - - _classmap = {} - - def __init__(cls, clsname, bases, dict): - if cls.__keyword__ is not None: - cls._classmap[cls.__keyword__] = cls - 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) - - 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'] - ) - return type.__call__(cls, keyword, attributes, **kwargs) - -class Tag(Node): - """abstract base class for tags. - - <%sometag/> - - <%someothertag> - stuff - </%someothertag> - - """ - - __metaclass__ = _TagMeta - __keyword__ = None - - def __init__(self, keyword, attributes, expressions, nonexpressions, required, **kwargs): - """construct a new Tag instance. - - this constructor not called directly, and is only called by subclasses. - - keyword - the tag keyword - - attributes - raw dictionary of attribute key/value pairs - - expressions - a util.Set of identifiers that are legal attributes, which can also contain embedded expressions - - nonexpressions - a util.Set of identifiers that are legal attributes, which cannot contain embedded expressions - - **kwargs - other arguments passed to the Node superclass (lineno, pos) - - """ - super(Tag, self).__init__(**kwargs) - self.keyword = keyword - self.attributes = attributes - self._parse_attributes(expressions, nonexpressions) - 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) - self.parent = None - self.nodes = [] - - def is_root(self): - return self.parent is None - - def get_children(self): - return self.nodes - - def _parse_attributes(self, expressions, nonexpressions): - undeclared_identifiers = util.Set() - self.parsed_attributes = {} - for key in self.attributes: - if key in expressions: - expr = [] - for x in re.split(r'(\${.+?})', self.attributes[key]): - m = re.match(r'^\${(.+?)}$', x) - if m: - code = ast.PythonCode(m.group(1), **self.exception_kwargs) - 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('') - elif key in nonexpressions: - if re.search(r'${.+?}', self.attributes[key]): - raise exceptions.CompileException( - "Attibute '%s' in tag '%s' does not allow embedded expressions" % (key, self.keyword), - **self.exception_kwargs) - self.parsed_attributes[key] = repr(self.attributes[key]) - else: - raise exceptions.CompileException("Invalid attribute for tag '%s': '%s'" %(self.keyword, key), **self.exception_kwargs) - self.expression_undeclared_identifiers = undeclared_identifiers - - def declared_identifiers(self): - return [] - - def undeclared_identifiers(self): - 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), - [repr(x) for x in self.nodes] - ) - -class IncludeTag(Tag): - __keyword__ = 'include' - - def __init__(self, keyword, attributes, **kwargs): - super(IncludeTag, self).__init__(keyword, attributes, ('file', 'import', 'args'), (), ('file',), **kwargs) - self.page_args = ast.PythonCode("__DUMMY(%s)" % attributes.get('args', ''), **self.exception_kwargs) - - def declared_identifiers(self): - return [] - - def undeclared_identifiers(self): - identifiers = self.page_args.undeclared_identifiers.difference(util.Set(["__DUMMY"])) - return identifiers.union(super(IncludeTag, self).undeclared_identifiers()) - -class NamespaceTag(Tag): - __keyword__ = 'namespace' - - def __init__(self, keyword, attributes, **kwargs): - super(NamespaceTag, self).__init__(keyword, attributes, (), ('name','inheritable','file','import','module'), (), **kwargs) - self.name = attributes.get('name', '__anon_%s' % hex(abs(id(self)))) - if not 'name' in attributes and not 'import' in attributes: - raise exceptions.CompileException("'name' and/or 'import' attributes are required for <%namespace>", **self.exception_kwargs) - - def declared_identifiers(self): - return [] - -class TextTag(Tag): - __keyword__ = 'text' - - def __init__(self, keyword, attributes, **kwargs): - super(TextTag, self).__init__(keyword, attributes, (), ('filter'), (), **kwargs) - self.filter_args = ast.ArgumentList(attributes.get('filter', ''), **self.exception_kwargs) - -class DefTag(Tag): - __keyword__ = 'def' - - def __init__(self, keyword, attributes, **kwargs): - super(DefTag, self).__init__( - keyword, - attributes, - ('buffered', 'cached', 'cache_key', 'cache_timeout', 'cache_type', 'cache_dir', 'cache_url'), - ('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) - self.name = self.function_decl.funcname - self.decorator = attributes.get('decorator', '') - self.filter_args = ast.ArgumentList(attributes.get('filter', ''), **self.exception_kwargs) - - def declared_identifiers(self): - return self.function_decl.argnames - - def undeclared_identifiers(self): - res = [] - for c in self.function_decl.defaults: - res += list(ast.PythonCode(c, **self.exception_kwargs).undeclared_identifiers) - return res + list(self.filter_args.undeclared_identifiers.difference(util.Set(filters.DEFAULT_ESCAPES.keys()))) - -class CallTag(Tag): - __keyword__ = 'call' - - def __init__(self, keyword, attributes, **kwargs): - 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) - - def declared_identifiers(self): - return self.code.declared_identifiers.union(self.body_decl.argnames) - - def undeclared_identifiers(self): - return self.code.undeclared_identifiers - -class CallNamespaceTag(Tag): - - def __init__(self, namespace, defname, attributes, **kwargs): - super(CallNamespaceTag, self).__init__( - namespace + ":" + defname, - attributes, - tuple(attributes.keys()) + ('args', ), - (), - (), - **kwargs) - self.expression = "%s.%s(%s)" % (namespace, defname, ",".join(["%s=%s" % (k, v) for k, v in self.parsed_attributes.iteritems() if k != 'args'])) - self.code = ast.PythonCode(self.expression, **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.argnames) - - def undeclared_identifiers(self): - return self.code.undeclared_identifiers - -class InheritTag(Tag): - __keyword__ = 'inherit' - - def __init__(self, keyword, attributes, **kwargs): - super(InheritTag, self).__init__(keyword, attributes, ('file',), (), ('file',), **kwargs) - -class PageTag(Tag): - __keyword__ = 'page' - - def __init__(self, keyword, attributes, **kwargs): - super(PageTag, self).__init__( - keyword, - attributes, - ('cached', 'cache_key', 'cache_timeout', 'cache_type', 'cache_dir', 'cache_url', 'args', 'expression_filter'), - (), - (), - **kwargs) - self.body_decl = ast.FunctionArgs(attributes.get('args', ''), **self.exception_kwargs) - self.filter_args = ast.ArgumentList(attributes.get('expression_filter', ''), **self.exception_kwargs) - - def declared_identifiers(self): - return self.body_decl.argnames - - diff --git a/lib/mako/pygen.py b/lib/mako/pygen.py deleted file mode 100644 index 914443b..0000000 --- a/lib/mako/pygen.py +++ /dev/null @@ -1,267 +0,0 @@ -# pygen.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""utilities for generating and formatting literal Python code.""" - -import re, string -from StringIO import StringIO - -class PythonPrinter(object): - def __init__(self, stream): - # indentation counter - self.indent = 0 - - # a stack storing information about why we incremented - # the indentation counter, to help us determine if we - # should decrement it - self.indent_detail = [] - - # the string of whitespace multiplied by the indent - # counter to produce a line - self.indentstring = " " - - # the stream we are writing to - self.stream = stream - - # a list of lines that represents a buffered "block" of code, - # which can be later printed relative to an indent level - self.line_buffer = [] - - self.in_indent_lines = False - - self._reset_multi_line_flags() - - def write(self, text): - self.stream.write(text) - - def write_indented_block(self, block): - """print a line or lines of python which already contain indentation. - - 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): - self.line_buffer.append(l) - - def writelines(self, *lines): - """print a series of lines of python.""" - for line in lines: - self.writeline(line) - - def writeline(self, line): - """print a line of python, indenting it according to the current indent level. - - this also adjusts the indentation counter according to the content of the line.""" - - if not self.in_indent_lines: - self._flush_adjusted_lines() - self.in_indent_lines = True - - decreased_indent = False - - if (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] == '#' - - # see if this line should decrease the indentation level - if (not decreased_indent and - not is_comment and - (not hastext or self._is_unindentor(line)) - ): - - if self.indent > 0: - self.indent -=1 - # if the indent_detail stack is empty, the user - # probably put extra closures - the resulting - # module wont compile. - if len(self.indent_detail) == 0: - raise "Too many whitespace closures" - self.indent_detail.pop() - - if line is None: - return - - # write the line - self.stream.write(self._indent_line(line) + "\n") - - # see if this line should increase the indentation level. - # note that a line can both decrase (before printing) and - # then increase (after printing) the indentation level. - - if re.search(r":[ \t]*(?:#.*)?$", line): - # increment indentation count, and also - # keep track of what the keyword was that indented us, - # if it is a python compound statement keyword - # where we might have to look for an "unindent" keyword - match = re.match(r"^\s*(if|try|elif|while|for)", line) - if match: - # its a "compound" keyword, so we will check for "unindentors" - indentor = match.group(1) - self.indent +=1 - self.indent_detail.append(indentor) - else: - indentor = None - # 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) - if m2: - self.indent += 1 - self.indent_detail.append(indentor) - - def close(self): - """close this printer, flushing any remaining lines.""" - self._flush_adjusted_lines() - - def _is_unindentor(self, line): - """return true if the given line is an 'unindentor', relative to the last 'indent' event received.""" - - # no indentation detail has been pushed on; return False - if len(self.indent_detail) == 0: - return False - - indentor = self.indent_detail[-1] - - # the last indent keyword we grabbed is not a - # compound statement keyword; return False - if indentor is None: - return False - - # if the current line doesnt have one of the "unindentor" keywords, - # return False - match = re.match(r"^\s*(else|elif|except|finally).*\:", line) - if not match: - return False - - # whitespace matches up, we have a compound indentor, - # and this line has an unindentor, this - # is probably good enough - return True - - # should we decide that its not good enough, heres - # more stuff to check. - #keyword = match.group(1) - - # match the original indent keyword - #for crit in [ - # (r'if|elif', r'else|elif'), - # (r'try', r'except|finally|else'), - # (r'while|for', r'else'), - #]: - # if re.match(crit[0], indentor) and re.match(crit[1], keyword): return True - - #return False - - 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) - - def _reset_multi_line_flags(self): - """reset the flags which would indicate we are in a backslashed or triple-quoted section.""" - (self.backslashed, self.triplequoted) = (False, False) - - def _in_multi_line(self, line): - """return true if the given line is part of a multi-line block, via backslash or triple-quote.""" - # we are only looking for explicitly joined lines here, - # not implicit ones (i.e. brackets, braces etc.). this is just - # to guard against the possibility of modifying the space inside - # of a literal multiline string with unfortunately placed whitespace - - current_state = (self.backslashed or self.triplequoted) - - if re.search(r"\\$", line): - self.backslashed = True - else: - self.backslashed = False - - triples = len(re.findall(r"\"\"\"|\'\'\'", line)) - if triples == 1 or triples % 2 != 0: - self.triplequoted = not self.triplequoted - - return current_state - - def _flush_adjusted_lines(self): - stripspace = None - self._reset_multi_line_flags() - - for entry in self.line_buffer: - if self._in_multi_line(entry): - self.stream.write(entry + "\n") - else: - entry = string.expandtabs(entry) - if stripspace is None and re.search(r"^[ \t]*[^# \t]", entry): - stripspace = re.match(r"^([ \t]*)", entry).group(1) - self.stream.write(self._indent_line(entry, stripspace) + "\n") - - self.line_buffer = [] - self._reset_multi_line_flags() - - -def adjust_whitespace(text): - """remove the left-whitespace margin of a block of Python code.""" - state = [False, False] - (backslashed, triplequoted) = (0, 1) - - def in_multi_line(line): - start_state = (state[backslashed] or state[triplequoted]) - - if re.search(r"\\$", line): - state[backslashed] = True - else: - state[backslashed] = False - - def match(reg, t): - m = re.match(reg, t) - if m: - return m, t[len(m.group(0)):] - else: - return None, t - - while line: - if state[triplequoted]: - m, line = match(r"%s" % state[triplequoted], line) - if m: - state[triplequoted] = False - else: - m, line = match(r".*?(?=%s|$)" % state[triplequoted], line) - else: - m, line = match(r'#', line) - if m: - return start_state - - m, line = match(r"\"\"\"|\'\'\'", line) - if m: - state[triplequoted] = m.group(0) - continue - - m, line = match(r".*?(?=\"\"\"|\'\'\'|#|$)", line) - - return start_state - - def _indent_line(line, stripspace = ''): - return re.sub(r"^%s" % stripspace, '', line) - - lines = [] - stripspace = None - - for line in re.split(r'\r?\n', text): - if in_multi_line(line): - lines.append(line) - else: - line = string.expandtabs(line) - if stripspace is None and re.search(r"^[ \t]*[^# \t]", line): - stripspace = re.match(r"^([ \t]*)", line).group(1) - lines.append(_indent_line(line, stripspace)) - return "\n".join(lines) diff --git a/lib/mako/pyparser.py b/lib/mako/pyparser.py deleted file mode 100644 index c79692c..0000000 --- a/lib/mako/pyparser.py +++ /dev/null @@ -1,371 +0,0 @@ -# ast.py -# Copyright (C) Mako developers -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""Handles parsing of Python code. - -Parsing to AST is done via _ast on Python > 2.5, otherwise the compiler -module is used. -""" - -from StringIO import StringIO -from mako import exceptions, util - -# words that cannot be assigned to (notably smaller than the total keys in __builtins__) -reserved = util.Set(['True', 'False', 'None']) - -try: - import _ast - util.restore__ast(_ast) - import _ast_util -except ImportError: - _ast = None - from compiler import parse as compiler_parse - from compiler import visitor - - -def parse(code, mode='exec', **exception_kwargs): - """Parse an expression into AST""" - try: - if _ast: - return _ast_util.parse(code, '<unknown>', mode) - else: - return compiler_parse(code, mode) - except Exception, e: - raise exceptions.SyntaxException("(%s) %s (%s)" % (e.__class__.__name__, str(e), repr(code[0:50])), **exception_kwargs) - - -if _ast: - class FindIdentifiers(_ast_util.NodeVisitor): - def __init__(self, listener, **exception_kwargs): - self.in_function = False - self.in_assign_targets = False - self.local_ident_stack = {} - self.listener = listener - self.exception_kwargs = exception_kwargs - def _add_declared(self, name): - if not self.in_function: - self.listener.declared_identifiers.add(name) - def visit_ClassDef(self, node): - self._add_declared(node.name) - def visit_Assign(self, node): - # flip around the visiting of Assign so the expression gets evaluated first, - # in the case of a clause like "x=x+5" (x is undeclared) - self.visit(node.value) - in_a = self.in_assign_targets - self.in_assign_targets = True - for n in node.targets: - self.visit(n) - self.in_assign_targets = in_a - def visit_FunctionDef(self, node): - self._add_declared(node.name) - # push function state onto stack. dont log any - # more identifiers as "declared" until outside of the function, - # but keep logging identifiers as "undeclared". - # track argument names in each function header so they arent counted as "undeclared" - saved = {} - inf = self.in_function - self.in_function = True - for arg in node.args.args: - if arg.id in self.local_ident_stack: - saved[arg.id] = True - else: - self.local_ident_stack[arg.id] = True - for n in node.body: - self.visit(n) - self.in_function = inf - for arg in node.args.args: - if arg.id not in saved: - del self.local_ident_stack[arg.id] - def visit_For(self, node): - # flip around visit - self.visit(node.iter) - self.visit(node.target) - for statement in node.body: - self.visit(statement) - for statement in node.orelse: - self.visit(statement) - def visit_Name(self, node): - if isinstance(node.ctx, _ast.Store): - self._add_declared(node.id) - if 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): - for name in node.names: - if name.asname is not None: - self._add_declared(name.asname) - else: - 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 == '*': - 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) - 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 - self.code_factory = code_factory - def visit_Tuple(self, node): - for n in node.elts: - 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) - - class ParseFunc(_ast_util.NodeVisitor): - def __init__(self, listener, **exception_kwargs): - self.listener = listener - self.exception_kwargs = exception_kwargs - def visit_FunctionDef(self, node): - self.listener.funcname = node.name - argnames = [arg.id for arg in node.args.args] - if node.args.vararg: - argnames.append(node.args.vararg) - if node.args.kwarg: - argnames.append(node.args.kwarg) - self.listener.argnames = argnames - self.listener.defaults = node.args.defaults # ast - self.listener.varargs = node.args.vararg - self.listener.kwargs = node.args.kwarg - - class ExpressionGenerator(object): - def __init__(self, astnode): - self.generator = _ast_util.SourceGenerator(' ' * 4) - self.generator.visit(astnode) - def value(self): - return ''.join(self.generator.result) -else: - class FindIdentifiers(object): - def __init__(self, listener, **exception_kwargs): - self.in_function = False - self.local_ident_stack = {} - self.listener = listener - self.exception_kwargs = exception_kwargs - def _add_declared(self, name): - if not self.in_function: - self.listener.declared_identifiers.add(name) - def visitClass(self, node, *args): - self._add_declared(node.name) - def visitAssName(self, node, *args): - self._add_declared(node.name) - def visitAssign(self, node, *args): - # flip around the visiting of Assign so the expression gets evaluated first, - # in the case of a clause like "x=x+5" (x is undeclared) - self.visit(node.expr, *args) - for n in node.nodes: - self.visit(n, *args) - def visitFunction(self,node, *args): - self._add_declared(node.name) - # push function state onto stack. dont log any - # more identifiers as "declared" until outside of the function, - # but keep logging identifiers as "undeclared". - # track argument names in each function header so they arent counted as "undeclared" - saved = {} - inf = self.in_function - self.in_function = True - for arg in node.argnames: - if arg in self.local_ident_stack: - saved[arg] = True - else: - self.local_ident_stack[arg] = True - for n in node.getChildNodes(): - self.visit(n, *args) - self.in_function = inf - for arg in node.argnames: - if arg not in saved: - del self.local_ident_stack[arg] - def visitFor(self, node, *args): - # flip around visit - self.visit(node.list, *args) - self.visit(node.assign, *args) - self.visit(node.body, *args) - def visitName(self, node, *args): - if node.name not in reserved and node.name not in self.listener.declared_identifiers and node.name not in self.local_ident_stack: - self.listener.undeclared_identifiers.add(node.name) - def visitImport(self, node, *args): - for (mod, alias) in node.names: - if alias is not None: - self._add_declared(alias) - else: - self._add_declared(mod.split('.')[0]) - def visitFrom(self, node, *args): - for (mod, alias) in node.names: - if alias is not None: - self._add_declared(alias) - else: - if mod == '*': - 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) - self._add_declared(mod) - def visit(self, expr): - visitor.walk(expr, self) #, walker=walker()) - - class FindTuple(object): - def __init__(self, listener, code_factory, **exception_kwargs): - self.listener = listener - self.exception_kwargs = exception_kwargs - self.code_factory = code_factory - def visitTuple(self, node, *args): - for n in node.nodes: - 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) - def visit(self, expr): - visitor.walk(expr, self) #, walker=walker()) - - class ParseFunc(object): - def __init__(self, listener, **exception_kwargs): - self.listener = listener - self.exception_kwargs = exception_kwargs - def visitFunction(self, node, *args): - self.listener.funcname = node.name - self.listener.argnames = node.argnames - self.listener.defaults = node.defaults - self.listener.varargs = node.varargs - self.listener.kwargs = node.kwargs - def visit(self, expr): - visitor.walk(expr, self) - - class ExpressionGenerator(object): - """given an AST node, generates an equivalent literal Python expression.""" - def __init__(self, astnode): - self.buf = StringIO() - visitor.walk(astnode, self) #, walker=walker()) - def value(self): - return self.buf.getvalue() - def operator(self, op, node, *args): - self.buf.write("(") - self.visit(node.left, *args) - self.buf.write(" %s " % op) - self.visit(node.right, *args) - self.buf.write(")") - def booleanop(self, op, node, *args): - self.visit(node.nodes[0]) - for n in node.nodes[1:]: - self.buf.write(" " + op + " ") - self.visit(n, *args) - def visitConst(self, node, *args): - self.buf.write(repr(node.value)) - def visitAssName(self, node, *args): - # TODO: figure out OP_ASSIGN, other OP_s - self.buf.write(node.name) - def visitName(self, node, *args): - self.buf.write(node.name) - def visitMul(self, node, *args): - self.operator("*", node, *args) - def visitAnd(self, node, *args): - self.booleanop("and", node, *args) - def visitOr(self, node, *args): - self.booleanop("or", node, *args) - def visitBitand(self, node, *args): - self.booleanop("&", node, *args) - def visitBitor(self, node, *args): - self.booleanop("|", node, *args) - def visitBitxor(self, node, *args): - self.booleanop("^", node, *args) - def visitAdd(self, node, *args): - self.operator("+", node, *args) - def visitGetattr(self, node, *args): - self.visit(node.expr, *args) - self.buf.write(".%s" % node.attrname) - def visitSub(self, node, *args): - self.operator("-", node, *args) - def visitNot(self, node, *args): - self.buf.write("not ") - self.visit(node.expr) - def visitDiv(self, node, *args): - self.operator("/", node, *args) - def visitFloorDiv(self, node, *args): - self.operator("//", node, *args) - def visitSubscript(self, node, *args): - self.visit(node.expr) - self.buf.write("[") - [self.visit(x) for x in node.subs] - self.buf.write("]") - def visitUnarySub(self, node, *args): - self.buf.write("-") - self.visit(node.expr) - def visitUnaryAdd(self, node, *args): - self.buf.write("-") - self.visit(node.expr) - def visitSlice(self, node, *args): - self.visit(node.expr) - self.buf.write("[") - if node.lower is not None: - self.visit(node.lower) - self.buf.write(":") - if node.upper is not None: - self.visit(node.upper) - self.buf.write("]") - def visitDict(self, node): - self.buf.write("{") - c = node.getChildren() - for i in range(0, len(c), 2): - self.visit(c[i]) - self.buf.write(": ") - self.visit(c[i+1]) - if i<len(c) -2: - self.buf.write(", ") - self.buf.write("}") - def visitTuple(self, node): - self.buf.write("(") - c = node.getChildren() - for i in range(0, len(c)): - self.visit(c[i]) - if i<len(c) - 1: - self.buf.write(", ") - self.buf.write(")") - def visitList(self, node): - self.buf.write("[") - c = node.getChildren() - for i in range(0, len(c)): - self.visit(c[i]) - if i<len(c) - 1: - self.buf.write(", ") - self.buf.write("]") - def visitListComp(self, node): - self.buf.write("[") - self.visit(node.expr) - self.buf.write(" ") - for n in node.quals: - self.visit(n) - self.buf.write("]") - def visitListCompFor(self, node): - self.buf.write(" for ") - self.visit(node.assign) - self.buf.write(" in ") - self.visit(node.list) - for n in node.ifs: - self.visit(n) - def visitListCompIf(self, node): - self.buf.write(" if ") - self.visit(node.test) - def visitCompare(self, node): - self.visit(node.expr) - for tup in node.ops: - self.buf.write(tup[0]) - self.visit(tup[1]) - def visitCallFunc(self, node, *args): - self.visit(node.node) - self.buf.write("(") - if len(node.args): - self.visit(node.args[0]) - for a in node.args[1:]: - self.buf.write(", ") - self.visit(a) - self.buf.write(")") - - class walker(visitor.ASTVisitor): - def dispatch(self, node, *args): - print "Node:", str(node) - #print "dir:", dir(node) - return visitor.ASTVisitor.dispatch(self, node, *args) diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py deleted file mode 100644 index a475b71..0000000 --- a/lib/mako/runtime.py +++ /dev/null @@ -1,419 +0,0 @@ -# runtime.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""provides runtime services for templates, including Context, Namespace, and various helper functions.""" - -from mako import exceptions, util -import __builtin__, inspect, sys - -class Context(object): - """provides runtime namespace, output buffer, and various callstacks for templates.""" - def __init__(self, buffer, **data): - self._buffer_stack = [buffer] - self._orig = data # original data, minus the builtins - self._data = __builtin__.__dict__.copy() # the context data which includes builtins - self._data.update(data) - self._kwargs = data.copy() - self._with_template = None - self.namespaces = {} - - # "capture" function which proxies to the generic "capture" function - self._data['capture'] = lambda x, *args, **kwargs: capture(self, x, *args, **kwargs) - - # "caller" stack used by def calls with content - self.caller_stack = self._data['caller'] = CallerStack() - - lookup = property(lambda self:self._with_template.lookup) - kwargs = property(lambda self:self._kwargs.copy()) - - def push_caller(self, caller): - self.caller_stack.append(caller) - - def pop_caller(self): - del self.caller_stack[-1] - - def keys(self): - return self._data.keys() - - def __getitem__(self, key): - return self._data[key] - - def _push_writer(self): - """push a capturing buffer onto this Context and return the new Writer function.""" - - buf = util.FastEncodingBuffer() - self._buffer_stack.append(buf) - return buf.write - - def _pop_buffer_and_writer(self): - """pop the most recent capturing buffer from this Context - and return the current writer after the pop. - - """ - - buf = self._buffer_stack.pop() - return buf, self._buffer_stack[-1].write - - def _push_buffer(self): - """push a capturing buffer onto this Context.""" - - self._push_writer() - - def _pop_buffer(self): - """pop the most recent capturing buffer from this Context.""" - - return self._buffer_stack.pop() - - def get(self, key, default=None): - return self._data.get(key, default) - - def write(self, string): - """write a string to this Context's underlying output buffer.""" - - self._buffer_stack[-1].write(string) - - def writer(self): - """return the current writer function""" - - return self._buffer_stack[-1].write - - def _copy(self): - c = Context.__new__(Context) - c._buffer_stack = self._buffer_stack - c._data = self._data.copy() - c._orig = self._orig - c._kwargs = self._kwargs - c._with_template = self._with_template - c.namespaces = self.namespaces - c.caller_stack = self.caller_stack - return c - def locals_(self, d): - """create a new Context with a copy of this Context's current state, updated with the given dictionary.""" - if len(d) == 0: - return self - c = self._copy() - c._data.update(d) - return c - def _clean_inheritance_tokens(self): - """create a new copy of this Context with tokens related to inheritance state removed.""" - c = self._copy() - x = c._data - x.pop('self', None) - x.pop('parent', None) - x.pop('next', None) - return c - -class CallerStack(list): - def __init__(self): - self.nextcaller = None - def __nonzero__(self): - return self._get_caller() and True or False - def _get_caller(self): - return self[-1] - def __getattr__(self, key): - return getattr(self._get_caller(), key) - def _push_frame(self): - self.append(self.nextcaller or None) - self.nextcaller = None - def _pop_frame(self): - self.nextcaller = self.pop() - - -class Undefined(object): - """represents an undefined value in a template.""" - def __str__(self): - raise NameError("Undefined") - def __nonzero__(self): - return False - -UNDEFINED = Undefined() - -class _NSAttr(object): - def __init__(self, parent): - self.__parent = parent - def __getattr__(self, key): - ns = self.__parent - while ns: - if hasattr(ns.module, key): - return getattr(ns.module, key) - else: - ns = ns.inherits - raise AttributeError(key) - -class Namespace(object): - """provides access to collections of rendering methods, which can be local, from other templates, or from imported modules""" - def __init__(self, name, context, module=None, template=None, templateuri=None, callables=None, inherits=None, populate_self=True, calling_uri=None): - self.name = name - if module is not None: - mod = __import__(module) - for token in module.split('.')[1:]: - mod = getattr(mod, token) - self._module = mod - else: - self._module = None - if templateuri is not None: - self.template = _lookup_template(context, templateuri, calling_uri) - self._templateuri = self.template.module._template_uri - else: - self.template = template - if self.template is not None: - self._templateuri = self.template.module._template_uri - self.context = context - self.inherits = inherits - if callables is not None: - self.callables = dict([(c.func_name, c) for c in callables]) - else: - self.callables = None - if populate_self and self.template is not None: - (lclcallable, lclcontext) = _populate_self_namespace(context, self.template, self_ns=self) - - module = property(lambda s:s._module or s.template.module) - filename = property(lambda s:s._module and s._module.__file__ or s.template.filename) - uri = property(lambda s:s.template.uri) - - def attr(self): - if not hasattr(self, '_attr'): - self._attr = _NSAttr(self) - return self._attr - attr = property(attr) - - def get_namespace(self, uri): - """return a namespace corresponding to the given template uri. - - if a relative uri, it is adjusted to that of the template of this namespace""" - key = (self, uri) - if self.context.namespaces.has_key(key): - return self.context.namespaces[key] - else: - ns = Namespace(uri, self.context._copy(), templateuri=uri, calling_uri=self._templateuri) - self.context.namespaces[key] = ns - return ns - - def get_template(self, uri): - return _lookup_template(self.context, uri, self._templateuri) - - def get_cached(self, key, **kwargs): - if self.template: - if not self.template.cache_enabled: - createfunc = kwargs.get('createfunc', None) - if createfunc: - return createfunc() - else: - return None - - if self.template.cache_dir: - kwargs.setdefault('data_dir', self.template.cache_dir) - if self.template.cache_type: - kwargs.setdefault('type', self.template.cache_type) - if self.template.cache_url: - kwargs.setdefault('url', self.template.cache_url) - return self.cache.get(key, **kwargs) - - def cache(self): - return self.template.cache - cache = property(cache) - - def include_file(self, uri, **kwargs): - """include a file at the given uri""" - _include_file(self.context, uri, self._templateuri, **kwargs) - - def _populate(self, d, l): - for ident in l: - if ident == '*': - for (k, v) in self._get_star(): - d[k] = v - else: - d[ident] = getattr(self, ident) - - def _get_star(self): - if self.callables: - for key in self.callables: - yield (key, self.callables[key]) - if self.template: - def get(key): - callable_ = self.template._get_def_callable(key) - return lambda *args, **kwargs:callable_(self.context, *args, **kwargs) - for k in self.template.module._exports: - yield (k, get(k)) - if self._module: - def get(key): - callable_ = getattr(self._module, key) - return lambda *args, **kwargs:callable_(self.context, *args, **kwargs) - for k in dir(self._module): - if k[0] != '_': - yield (k, get(k)) - - def __getattr__(self, key): - if self.callables and key in self.callables: - return self.callables[key] - - if self.template and self.template.has_def(key): - callable_ = self.template._get_def_callable(key) - return lambda *args, **kwargs:callable_(self.context, *args, **kwargs) - - if self._module and hasattr(self._module, key): - callable_ = getattr(self._module, key) - return lambda *args, **kwargs:callable_(self.context, *args, **kwargs) - - if self.inherits is not None: - return getattr(self.inherits, key) - raise AttributeError("Namespace '%s' has no member '%s'" % (self.name, key)) - -def supports_caller(func): - """apply a caller_stack compatibility decorator to a plain Python function.""" - def wrap_stackframe(context, *args, **kwargs): - context.caller_stack._push_frame() - try: - return func(context, *args, **kwargs) - finally: - context.caller_stack._pop_frame() - return wrap_stackframe - -def capture(context, callable_, *args, **kwargs): - """execute the given template def, capturing the output into a buffer.""" - if not callable(callable_): - raise exceptions.RuntimeException("capture() function expects a callable as its argument (i.e. capture(func, *args, **kwargs))") - context._push_buffer() - try: - callable_(*args, **kwargs) - finally: - buf = context._pop_buffer() - return buf.getvalue() - -def _decorate_toplevel(fn): - def decorate_render(render_fn): - def go(context, *args, **kw): - def y(*args, **kw): - return render_fn(context, *args, **kw) - try: - y.__name__ = render_fn.__name__[7:] - except TypeError: - # < Python 2.4 - pass - return fn(y)(context, *args, **kw) - return go - return decorate_render - -def _decorate_inline(context, fn): - def decorate_render(render_fn): - dec = fn(render_fn) - def go(*args, **kw): - return dec(context, *args, **kw) - return go - return decorate_render - -def _include_file(context, uri, calling_uri, **kwargs): - """locate the template from the given uri and include it in the current output.""" - template = _lookup_template(context, uri, calling_uri) - (callable_, ctx) = _populate_self_namespace(context._clean_inheritance_tokens(), template) - callable_(ctx, **_kwargs_for_callable(callable_, context._orig, **kwargs)) - -def _inherit_from(context, uri, calling_uri): - """called by the _inherit method in template modules to set up the inheritance chain at the start - of a template's execution.""" - if uri is None: - return None - template = _lookup_template(context, uri, calling_uri) - self_ns = context['self'] - ih = self_ns - while ih.inherits is not None: - ih = ih.inherits - lclcontext = context.locals_({'next':ih}) - ih.inherits = Namespace("self:%s" % template.uri, lclcontext, template = template, populate_self=False) - context._data['parent'] = lclcontext._data['local'] = ih.inherits - callable_ = getattr(template.module, '_mako_inherit', None) - if callable_ is not None: - ret = callable_(template, lclcontext) - if ret: - return ret - - gen_ns = getattr(template.module, '_mako_generate_namespaces', None) - if gen_ns is not None: - gen_ns(context) - return (template.callable_, lclcontext) - -def _lookup_template(context, uri, relativeto): - lookup = context._with_template.lookup - if lookup is None: - raise exceptions.TemplateLookupException("Template '%s' has no TemplateLookup associated" % context._with_template.uri) - uri = lookup.adjust_uri(uri, relativeto) - try: - return lookup.get_template(uri) - except exceptions.TopLevelLookupException, e: - raise exceptions.TemplateLookupException(str(e)) - -def _populate_self_namespace(context, template, self_ns=None): - if self_ns is None: - self_ns = Namespace('self:%s' % template.uri, context, template=template, populate_self=False) - context._data['self'] = context._data['local'] = self_ns - if hasattr(template.module, '_mako_inherit'): - ret = template.module._mako_inherit(template, context) - if ret: - return ret - return (template.callable_, context) - -def _render(template, callable_, args, data, as_unicode=False): - """create a Context and return the string output of the given template and template callable.""" - - if as_unicode: - buf = util.FastEncodingBuffer(unicode=True) - elif template.output_encoding: - buf = util.FastEncodingBuffer(unicode=as_unicode, encoding=template.output_encoding, errors=template.encoding_errors) - else: - buf = util.StringIO() - context = Context(buf, **data) - context._with_template = template - _render_context(template, callable_, context, *args, **_kwargs_for_callable(callable_, data)) - return context._pop_buffer().getvalue() - -def _kwargs_for_callable(callable_, data, **kwargs): - argspec = inspect.getargspec(callable_) - namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None] - for arg in namedargs: - if arg != 'context' and arg in data and arg not in kwargs: - kwargs[arg] = data[arg] - return kwargs - -def _render_context(tmpl, callable_, context, *args, **kwargs): - import mako.template as template - # create polymorphic 'self' namespace for this template with possibly updated context - if not isinstance(tmpl, template.DefTemplate): - # if main render method, call from the base of the inheritance stack - (inherit, lclcontext) = _populate_self_namespace(context, tmpl) - _exec_template(inherit, lclcontext, args=args, kwargs=kwargs) - else: - # otherwise, call the actual rendering method specified - (inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent) - _exec_template(callable_, context, args=args, kwargs=kwargs) - -def _exec_template(callable_, context, args=None, kwargs=None): - """execute a rendering callable given the callable, a Context, and optional explicit arguments - - the contextual Template will be located if it exists, and the error handling options specified - on that Template will be interpreted here. - """ - template = context._with_template - if template is not None and (template.format_exceptions or template.error_handler): - error = None - try: - callable_(context, *args, **kwargs) - except Exception, e: - error = e - except: - e = sys.exc_info()[0] - error = e - if error: - if template.error_handler: - result = template.error_handler(context, error) - if not result: - raise error - else: - error_template = exceptions.html_error_template() - context._buffer_stack[:] = [util.FastEncodingBuffer(error_template.output_encoding, error_template.encoding_errors)] - context._with_template = error_template - error_template.render_context(context, error=error) - else: - callable_(context, *args, **kwargs) diff --git a/lib/mako/template.py b/lib/mako/template.py deleted file mode 100644 index 4bf01e0..0000000 --- a/lib/mako/template.py +++ /dev/null @@ -1,392 +0,0 @@ -# template.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer -# mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -"""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 -import imp, os, re, shutil, stat, sys, tempfile, time, types, weakref - - -class Template(object): - """a compiled template""" - 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_type=None, - cache_dir=None, - cache_url=None, - module_filename=None, - input_encoding=None, - disable_unicode=False, - default_filters=None, - buffer_filters=(), - imports=None, - preprocessor=None, - cache_enabled=True): - """Construct a new Template instance using either literal template - text, or a previously loaded template module - - :param text: textual template source, or None if a module is to be - provided - - :param uri: the uri of this template, or some identifying string. - defaults to the full filename given, or "memory:(hex id of this - Template)" if no filename - - :param filename: filename of the source template, if any - - :param format_exceptions: catch exceptions and format them into an - error display template - """ - - if uri: - self.module_id = re.sub(r'\W', "_", uri) - self.uri = uri - elif filename: - self.module_id = re.sub(r'\W', "_", filename) - self.uri = filename - else: - self.module_id = "memory:" + hex(id(self)) - self.uri = self.module_id - - self.input_encoding = input_encoding - self.output_encoding = output_encoding - self.encoding_errors = encoding_errors - self.disable_unicode = disable_unicode - if default_filters is None: - if self.disable_unicode: - self.default_filters = ['str'] - else: - self.default_filters = ['unicode'] - else: - self.default_filters = default_filters - self.buffer_filters = buffer_filters - - self.imports = imports - self.preprocessor = preprocessor - - # if plain text, compile code in memory only - if text is not None: - (code, module) = _compile_text(self, text, filename) - self._code = code - self._source = text - ModuleInfo(module, None, self, filename, code, text) - elif filename is not None: - # if template filename and a module directory, load - # a filesystem-based module file, generating if needed - if module_filename is not None: - path = module_filename - elif module_directory is not None: - u = self.uri - if u[0] == '/': - u = u[1:] - path = os.path.abspath( - os.path.join( - module_directory.replace('/', os.path.sep), - u + ".py" - ) - ) - else: - path = None - 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: - _compile_module_file( - self, - file(filename).read(), - filename, - path) - module = imp.load_source(self.module_id, path, file(path)) - del sys.modules[self.module_id] - if module._magic_number != codegen.MAGIC_NUMBER: - _compile_module_file( - self, - file(filename).read(), - filename, - path) - module = imp.load_source(self.module_id, path, file(path)) - del sys.modules[self.module_id] - ModuleInfo(module, path, self, filename, None, None) - else: - # template filename and no module directory, compile code - # in memory - (code, module) = _compile_text( - self, - file(filename).read(), - filename) - self._source = None - self._code = code - ModuleInfo(module, None, self, filename, code, None) - else: - raise exceptions.RuntimeException( - "Template requires text or filename") - - self.module = module - self.filename = filename - self.callable_ = self.module.render_body - self.format_exceptions = format_exceptions - self.error_handler = error_handler - self.lookup = lookup - self.cache_type = cache_type - self.cache_dir = cache_dir - self.cache_url = cache_url - self.cache_enabled = cache_enabled - - @property - def source(self): - """return the template source code for this Template.""" - - return _get_module_info_from_callable(self.callable_).source - - @property - def code(self): - """return the module source code for this Template""" - - return _get_module_info_from_callable(self.callable_).code - - @property - def cache(self): - return self.module._template_cache - - def render(self, *args, **data): - """Render the output of this template as a string. - - if the template specifies an output encoding, the string will be - encoded accordingly, else the output is raw (raw output uses cStringIO - and can't handle multibyte characters). a Context object is created - corresponding to the given data. Arguments that are explictly declared - by this template's internal rendering method are also pulled from the - given \*args, \**data members. - - """ - return runtime._render(self, self.callable_, args, data) - - 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) - - def render_context(self, context, *args, **kwargs): - """Render this Template with the given context. - - the data is written to the context's buffer. - - """ - if getattr(context, '_with_template', None) is None: - context._with_template = self - runtime._render_context(self, - self.callable_, - context, - *args, - **kwargs) - - def has_def(self, name): - return hasattr(self.module, "render_%s" % name) - - def get_def(self, name): - """Return a def of this template as a DefTemplate.""" - - return DefTemplate(self, getattr(self.module, "render_%s" % name)) - - def _get_def_callable(self, name): - return getattr(self.module, "render_%s" % name) - - @property - def last_modified(self): - return self.module._modified_time - last_modified = property(last_modified) - -class ModuleTemplate(Template): - """A Template which is constructed given an existing Python module. - - e.g.:: - - t = Template("this is a template") - f = file("mymodule.py", "w") - f.write(t.code) - f.close() - - import mymodule - - t = ModuleTemplate(mymodule) - print t.render() - - """ - - 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, - format_exceptions=False, - error_handler=None, - lookup=None, - cache_type=None, - cache_dir=None, - cache_url=None, - cache_enabled=True - ): - 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 - self.encoding_errors = encoding_errors - self.disable_unicode = disable_unicode - self.module = module - self.filename = template_filename - ModuleInfo(module, - module_filename, - self, - template_filename, - module_source, - template_source) - - self.callable_ = self.module.render_body - self.format_exceptions = format_exceptions - self.error_handler = error_handler - self.lookup = lookup - self.cache_type = cache_type - self.cache_dir = cache_dir - self.cache_url = cache_url - self.cache_enabled = cache_enabled - -class DefTemplate(Template): - """a Template which represents a callable def in a parent template.""" - - def __init__(self, parent, callable_): - self.parent = parent - self.callable_ = callable_ - self.output_encoding = parent.output_encoding - self.module = parent.module - self.encoding_errors = parent.encoding_errors - self.format_exceptions = parent.format_exceptions - self.error_handler = parent.error_handler - self.lookup = parent.lookup - - def get_def(self, name): - return self.parent.get_def(name) - -class ModuleInfo(object): - """Stores information about a module currently loaded into memory, - provides reverse lookups of template source, module source code based on - a module's identifier. - - """ - _modules = weakref.WeakValueDictionary() - - 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 - self.module_source = module_source - self.template_source = template_source - self._modules[module.__name__] = template._mmarker = self - if module_filename: - self._modules[module_filename] = self - - @property - def code(self): - if self.module_source is not None: - return self.module_source - else: - return file(self.module_filename).read() - - @property - def source(self): - if self.template_source is not None: - if self.module._source_encoding and \ - not isinstance(self.template_source, unicode): - return self.template_source.decode( - self.module._source_encoding) - else: - return self.template_source - else: - if self.module._source_encoding: - return file(self.template_filename).read().\ - decode(self.module._source_encoding) - else: - return file(self.template_filename).read() - -def _compile_text(template, text, filename): - identifier = template.module_id - lexer = Lexer(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, - source_encoding=lexer.encoding, - generate_unicode=not template.disable_unicode) - - cid = identifier - if isinstance(cid, unicode): - cid = cid.encode() - module = types.ModuleType(cid) - code = compile(source, cid, 'exec') - exec code in module.__dict__, module.__dict__ - return (source, module) - -def _compile_module_file(template, text, filename, outputpath): - identifier = template.module_id - lexer = Lexer(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, - source_encoding=lexer.encoding, - generate_unicode=not template.disable_unicode) - (dest, name) = tempfile.mkstemp() - os.write(dest, source) - os.close(dest) - shutil.move(name, outputpath) - -def _get_module_info_from_callable(callable_): - return _get_module_info(callable_.func_globals['__name__']) - -def _get_module_info(filename): - return ModuleInfo._modules[filename] - diff --git a/lib/mako/util.py b/lib/mako/util.py deleted file mode 100644 index 1f9f3d4..0000000 --- a/lib/mako/util.py +++ /dev/null @@ -1,274 +0,0 @@ -# util.py -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com -# -# This module is part of Mako and is released under -# the MIT License: http://www.opensource.org/licenses/mit-license.php - -import sys -try: - Set = set -except: - import sets - Set = sets.Set - -try: - from cStringIO import StringIO -except: - from StringIO import StringIO - -import codecs, re, weakref, os, time - -try: - import threading - import thread -except ImportError: - import dummy_threading as threading - import dummy_thread as thread - -if sys.platform.startswith('win') or sys.platform.startswith('java'): - time_func = time.clock -else: - time_func = time.time - -def verify_directory(dir): - """create and/or verify a filesystem directory.""" - - tries = 0 - - while not os.path.exists(dir): - try: - tries += 1 - os.makedirs(dir, 0775) - except: - if tries > 5: - raise - -def to_list(x, default=None): - if x is None: - return default - if not isinstance(x, (list, tuple)): - return [x] - else: - return x - -class SetLikeDict(dict): - """a dictionary that has some setlike methods on it""" - def union(self, other): - """produce a 'union' of this dict and another (at the key level). - - values in the second dict take precedence over that of the first""" - x = SetLikeDict(**self) - x.update(other) - return x - -class FastEncodingBuffer(object): - """a very rudimentary buffer that is faster than StringIO, but doesnt crash on unicode data like cStringIO.""" - - def __init__(self, encoding=None, errors='strict', unicode=False): - self.data = [] - self.encoding = encoding - if unicode: - self.delim = u'' - else: - self.delim = '' - self.unicode = unicode - self.errors = errors - self.write = self.data.append - - def getvalue(self): - if self.encoding: - return self.delim.join(self.data).encode(self.encoding, self.errors) - else: - return self.delim.join(self.data) - -class LRUCache(dict): - """A dictionary-like object that stores a limited number of items, discarding - lesser used items periodically. - - this is a rewrite of LRUCache from Myghty to use a periodic timestamp-based - paradigm so that synchronization is not really needed. the size management - is inexact. - """ - - class _Item(object): - def __init__(self, key, value): - self.key = key - self.value = value - self.timestamp = time_func() - def __repr__(self): - return repr(self.value) - - def __init__(self, capacity, threshold=.5): - self.capacity = capacity - self.threshold = threshold - - def __getitem__(self, key): - item = dict.__getitem__(self, key) - item.timestamp = time_func() - return item.value - - def values(self): - return [i.value for i in dict.values(self)] - - def setdefault(self, key, value): - if key in self: - return self[key] - else: - self[key] = value - return value - - def __setitem__(self, key, value): - item = dict.get(self, key) - if item is None: - item = self._Item(key, value) - dict.__setitem__(self, key, item) - else: - item.value = value - self._manage_size() - - def _manage_size(self): - while len(self) > self.capacity + self.capacity * self.threshold: - bytime = dict.values(self) - bytime.sort(lambda a, b: cmp(b.timestamp, a.timestamp)) - for item in bytime[self.capacity:]: - try: - del self[item.key] - except KeyError: - # if we couldnt find a key, most likely some other thread 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) - -def parse_encoding(fp): - """Deduce the encoding of a source file from magic comment. - - It does this in the same way as the `Python interpreter`__ - - .. __: http://docs.python.org/ref/encodings.html - - The ``fp`` argument should be a seekable file object. - """ - pos = fp.tell() - fp.seek(0) - try: - line1 = fp.readline() - has_bom = line1.startswith(codecs.BOM_UTF8) - if has_bom: - line1 = line1[len(codecs.BOM_UTF8):] - - m = _PYTHON_MAGIC_COMMENT_re.match(line1) - if not m: - try: - import parser - parser.suite(line1) - 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 - # line1, in which case we don't want to scan line2 for a magic - # comment. - pass - else: - line2 = fp.readline() - m = _PYTHON_MAGIC_COMMENT_re.match(line2) - - 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' - elif m: - return m.group(1) - else: - return None - finally: - fp.seek(pos) - -def sorted_dict_repr(d): - """repr() a dictionary with the keys in order. - - Used by the lexer unit test to compare parse trees based on strings. - - """ - keys = d.keys() - keys.sort() - return "{" + ", ".join(["%r: %r" % (k, d[k]) for k in keys]) + "}" - -def restore__ast(_ast): - """Attempt to restore the required classes to the _ast module if it - appears to be missing them - """ - if hasattr(_ast, 'AST'): - return - _ast.PyCF_ONLY_AST = 2 << 9 - m = compile("""\ -def foo(): pass -class Bar(object): pass -if False: pass -baz = 'mako' -1 + 2 - 3 * 4 / 5 -6 // 7 % 8 << 9 >> 10 -11 & 12 ^ 13 | 14 -15 and 16 or 17 --baz + (not +18) - ~17 -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) - _ast.Module = type(m) - - for cls in _ast.Module.__mro__: - if cls.__name__ == 'mod': - _ast.mod = cls - elif cls.__name__ == 'AST': - _ast.AST = cls - - _ast.FunctionDef = type(m.body[0]) - _ast.ClassDef = type(m.body[1]) - _ast.If = type(m.body[2]) - - _ast.Name = type(m.body[3].targets[0]) - _ast.Store = type(m.body[3].targets[0].ctx) - _ast.Str = type(m.body[3].value) - - _ast.Sub = type(m.body[4].value.op) - _ast.Add = type(m.body[4].value.left.op) - _ast.Div = type(m.body[4].value.right.op) - _ast.Mult = type(m.body[4].value.right.left.op) - - _ast.RShift = type(m.body[5].value.op) - _ast.LShift = type(m.body[5].value.left.op) - _ast.Mod = type(m.body[5].value.left.left.op) - _ast.FloorDiv = type(m.body[5].value.left.left.left.op) - - _ast.BitOr = type(m.body[6].value.op) - _ast.BitXor = type(m.body[6].value.left.op) - _ast.BitAnd = type(m.body[6].value.left.left.op) - - _ast.Or = type(m.body[7].value.op) - _ast.And = type(m.body[7].value.values[0].op) - - _ast.Invert = type(m.body[8].value.right.op) - _ast.Not = type(m.body[8].value.left.right.op) - _ast.UAdd = type(m.body[8].value.left.right.operand.op) - _ast.USub = type(m.body[8].value.left.left.op) - - _ast.Or = type(m.body[9].value.op) - _ast.And = type(m.body[9].value.values[0].op) - - _ast.IsNot = type(m.body[10].value.ops[0]) - _ast.NotEq = type(m.body[10].value.ops[1]) - _ast.Is = type(m.body[10].value.left.ops[0]) - _ast.Eq = type(m.body[10].value.left.ops[1]) - - _ast.Gt = type(m.body[11].value.ops[0]) - _ast.Lt = type(m.body[11].value.ops[1]) - _ast.GtE = type(m.body[11].value.ops[2]) - _ast.LtE = type(m.body[11].value.ops[3]) - - _ast.In = type(m.body[12].value.ops[0]) - _ast.NotIn = type(m.body[12].value.ops[1]) |