def test_basic_hook(self): # define the hook def threebecomestwo(ast, enc, filename): class ChangeConstVisitor: def visitConst(self, node): if node.value == 3: node.value = 2 def defaultvisit(self, node): for child in node.getChildNodes(): child.accept(self) def __getattr__(self, attrname): if attrname.startswith('visit'): return self.defaultvisit raise AttributeError(attrname) ast.accept(ChangeConstVisitor()) return ast # install the hook import parser parser.install_compiler_hook(threebecomestwo) d = {} exec "a = 3" in d assert d['a'] == 2 # well, yes ...
def test_removal_of_broken_hooks(self): def hook(ast, enc, filename): 1/0 import parser parser.install_compiler_hook(hook) raises(ZeroDivisionError, "eval('1')") assert eval("1") == 1 def hook2(ast, enc, filename): return 1 parser.install_compiler_hook(hook2) raises(TypeError, "eval('2')") assert eval("2") == 2
def test_ast_parser(self): # define the hook def change_globals(ast, enc, filename): class ChangeGlobalsVisitor: def visitConst(self, node): pass def defaultvisit(self, node): for child in node.getChildNodes(): child.accept(self) def __getattr__(self, attrname): if attrname.startswith('visit'): return self.defaultvisit raise AttributeError(attrname) ast.accept(ChangeConstVisitor()) return ast # install the hook import parser parser.install_compiler_hook(change_globals)
def test_constant_fold_add(self): import parser class Folder(object): def defaultvisit(self, node): return node def __getattr__(self, attrname): if attrname.startswith('visit'): return self.defaultvisit raise AttributeError(attrname) def visitAdd(self, node): left = node.left right = node.right if isinstance(left, parser.ASTConst) and \ isinstance(right, parser.ASTConst): if type(left.value) == type(right.value): return parser.ASTConst(left.value + right.value) return node def hook(ast, enc, filename): return ast.mutate(Folder()) parser.install_compiler_hook(hook) code = compile("1+2", "", "eval") parser.install_compiler_hook(None) import dis, sys, StringIO s = StringIO.StringIO() so = sys.stdout sys.stdout = s try: dis.dis(code) finally: sys.stdout = so output = s.getvalue() assert 'BINARY_ADD' not in output
def test_constant_fold_add(self): import parser class Folder: def defaultvisit(self, node): return node def __getattr__(self, attrname): if attrname.startswith("visit"): return self.defaultvisit raise AttributeError(attrname) def visitAdd(self, node): left = node.left right = node.right if isinstance(left, parser.ASTConst) and isinstance(right, parser.ASTConst): if type(left.value) == type(right.value): return parser.ASTConst(left.value + right.value) return node def hook(ast, enc, filename): return ast.mutate(Folder()) parser.install_compiler_hook(hook) code = compile("1+2", "", "eval") parser.install_compiler_hook(None) import dis, sys, StringIO s = StringIO.StringIO() so = sys.stdout sys.stdout = s try: dis.dis(code) finally: sys.stdout = so output = s.getvalue() assert "BINARY_ADD" not in output
def __init__(self): self.advices = [] self.joinpoints = {} self._id = 1 parser.install_compiler_hook(self.weave)
import parser class ConstMutator(parser.ASTMutator): def visitConst(self, node): if node.value == 3: node.value = 2 return node def threebecomestwo(ast, enc, filename): ast.mutate(ConstMutator()) return ast # install the hook parser.install_compiler_hook(threebecomestwo) print eval('3*2')
def get_statements(source): module = source2ast(source) return module.node.nodes class Tracer(ASTMutator): def visitAssName(self, assname): assign = assname while not isinstance(assign, ASTAssign): assign = assign.parent stmt = assign.parent varname = assname.name before_stmts = get_statements(BEFORE_LOG_SOURCE % ((varname,) * 5)) after_stmts = get_statements(AFTER_LOG_SOURCE % (varname, varname)) stmt.insert_before(assign, before_stmts) stmt.insert_after(assign, after_stmts) return assname def _trace(ast, enc, filename): return ast.accept(Tracer()) install_compiler_hook(_trace) code = """ a = 3 b = 2 a = 1 """ exec code