def exact_src_imp(tree, src, indexes, line_lengths): all_child_pos = sorted(indexer.collect(tree)) start_index = linear_index(line_lengths(), *all_child_pos[0]) last_child_index = linear_index(line_lengths(), *all_child_pos[-1]) first_successor_index = indexes()[min( indexes().index(last_child_index) + 1, len(indexes()) - 1)] for end_index in range(last_child_index, first_successor_index + 1): prelim = src[start_index:end_index] prelim = _transforms.get(type(tree), "%s") % prelim if isinstance(tree, stmt): prelim = prelim.replace("\n" + " " * tree.col_offset, "\n") if isinstance(tree, list): prelim = prelim.replace("\n" + " " * tree[0].col_offset, "\n") try: if isinstance(tree, expr): x = "(" + prelim + ")" else: x = prelim import ast parsed = ast.parse(x) if unparse(parsed).strip() == unparse(tree).strip(): return prelim except SyntaxError as e: pass raise ExactSrcException()
def exact_src_imp(tree, src, indexes, line_lengths): all_child_pos = sorted(indexer.collect(tree)) start_index = linear_index(line_lengths(), *all_child_pos[0]) last_child_index = linear_index(line_lengths(), *all_child_pos[-1]) first_successor_index = indexes()[min(indexes().index(last_child_index)+1, len(indexes())-1)] for end_index in range(last_child_index, first_successor_index+1): prelim = src[start_index:end_index] prelim = _transforms.get(type(tree), "%s") % prelim if isinstance(tree, stmt): prelim = prelim.replace("\n" + " " * tree.col_offset, "\n") if isinstance(tree, list): prelim = prelim.replace("\n" + " " * tree[0].col_offset, "\n") try: if isinstance(tree, expr): x = "(" + prelim + ")" else: x = prelim import ast parsed = ast.parse(x) if unparse(parsed).strip() == unparse(tree).strip(): return prelim except SyntaxError as e: pass raise ExactSrcException()
def my_macro2(tree, **kw): assert unparse(tree).strip() == "\n".join([ "@middle", "@inner", "def run():", " x = 10", " x = (x + 1)", " x = (x + 1)", " x = (x + 1)", " x = (x + 1)", " return x" ]), unparse(tree) return tree
def my_macro(tree, **kw): assert unparse(tree).strip() == "\n".join([ "@inner", "def run():", " x = 10", " x = (x + 1)", " return x" ]), unparse(tree) b = tree.body tree.body = [b[0], b[1], b[1], b[1], b[1], b[2]] return tree
def testBuildOpsList(self): """ Proper jump tables get built for multiple try/except blocks. """ input = ast.parse(sampleAst1).body output = buildOperationsDAG(input) self.assertEqual( [[unparse(line[0]).strip()] + list(line[1:]) for line in output], [ ["resolve(r, BytesObject(contents))", None, None, None, None], ["ruv.magic_fsClose(vat, f)", output[0], None, None, None], ["smash(r, StrObject((u'libuv error: %s' % err)))", None, None, None, None], ["ruv.magic_fsClose(vat, f)", output[2], None, None, None], ["readLoop(f, buf)", output[1], output[3], "contents", "err"], ['smash(r, StrObject((u"Couldn\'t open file fount: %s" % err)))', None, None, None, None], ['ruv.magic_fsOpen(vat, path, os.O_RDONLY, 0)', output[4], output[5], "f", "err"], ['0', output[6], None, 'f', None] ]) input = ast.parse(sampleAst2).body output = buildOperationsDAG(input) self.assertEqual( [[unparse(line[0]).strip()] + list(line[1:]) for line in output], [ ["ioC()", None, None, None, None], ["ioB()", output[0], None, None, None], ["ioA()", output[1], None, None, None], ["io9()", output[1], None, None, None], ["io8()", output[2], output[3], None, "err3"], ["io7()", output[4], output[3], None, "err3"], ["io6()", output[5], None, None, None], ["io5()", output[0], None, None, None], ["io4()", output[0], output[7], None, "err2"], ["io3()", output[8], None, None, None], ["io2()", output[6], output[9], "y", "err1"], ["io1()", output[10], output[9], "x", "err1"], ["1", output[11], None, "x", None] ]) input = ast.parse(sampleAst3).body output = buildOperationsDAG(input) self.assertEqual( [[unparse(line[0]).strip()] + list(line[1:]) for line in output], [ ["io6()", None, None, None, None], ["io5()", output[0], None, None, None], ["io4()", output[0], output[1], None, "err2"], ["io3()", output[0], output[1], None, "err2"], ["io2()", output[2], output[3], "y", "err1"], ["io1()", output[4], output[3], "x", "err1"], ["io0()", output[5], output[1], None, "err2"] ])
def my_macro(tree, **kw): assert unparse(tree).strip() == "\n".join([ "@inner", "def run():", " x = 10", " x = (x + 1)", " return x"]), unparse(tree) b = tree.body tree.body = [b[0], b[1], b[1], b[1], b[1], b[2]] tree.decorator_list = [hq[added_decorator]] + tree.decorator_list return tree
def my_macro2(tree, **kw): assert unparse(tree).strip() == "\n".join([ "@middle", "@added_decorator", "@inner", "def run():", " x = 10", " x = (x + 1)", " x = (x + 1)", " x = (x + 1)", " x = (x + 1)", " return x"]), unparse(tree) return tree
def dbg_expr(tree): ln = q[u[tree.lineno]] if hasattr(tree, "lineno") else q[None] filename = hq[callsite_filename()] return q[dbgprint_expr(u[unparse(tree)], ast_literal[tree], filename=ast_literal[filename], lineno=ast_literal[ln])]
def export_transformed(self, code, tree, module_name, file_name): new_path = os.path.join(self.root, self.directory, os.path.relpath(file_name, self.root)) with open(new_path, "w") as f: f.write(unparse(tree))
def export_transformed(self, tree, module_name, file_name): new_path = os.path.join( self.root, self.directory, os.path.relpath(file_name, self.root) ) with open(new_path, "w") as f: f.write(unparse(tree))
def transform(tree, **kw): if type(tree) is Call and type(tree.func) is Name and tree.func.id == pname: names = [q[u[unparse(node)]] for node in tree.args] # x --> "x"; (1 + 2) --> "(1 + 2)"; ... names = Tuple(elts=names, lineno=tree.lineno, col_offset=tree.col_offset) values = Tuple(elts=tree.args, lineno=tree.lineno, col_offset=tree.col_offset) tree.args = [names, values] # can't use inspect.stack in the printer itself because we want the line number *before macro expansion*. tree.keywords += [keyword(arg="filename", value=q[__file__]), keyword(arg="lineno", value=(q[u[tree.lineno]] if hasattr(tree, "lineno") else q[None]))] tree.func = q[ast_literal[p]] return tree
def _test_block_signals_or_raises(block_body, args, syntaxname, asserter): if not block_body: return [] # pragma: no cover, cannot happen through the public API. first_stmt = block_body[0] # Note we want the line number *before macro expansion*, so we capture it now. ln = q[u[first_stmt.lineno]] if hasattr(first_stmt, "lineno") else q[None] filename = hq[callsite_filename()] # with test_raises(exctype, message): # TODO: Python 3.8+: ast.Constant, no ast.Str if len(args) == 2 and type(args[1]) is Str: exctype, message = args # with test_raises(exctype): elif len(args) == 1: exctype = args[0] message = q[None] else: assert False, 'Expected `with {stx}(exctype):` or `with {stx}(exctype, message):`'.format( stx=syntaxname) # Before we edit the tree, get the source code in its pre-transformation # state, so we can include that into the test failure message. sourcecode = unparse(block_body) gen_sym = dyn.gen_sym testblock_function_name = gen_sym("test_block") #def unpythonic_assert_raises(exctype, sourcecode, thunk, *, filename, lineno, message=None): thetest = q[(ast_literal[asserter])(ast_literal[exctype], u[sourcecode], name[testblock_function_name], filename=ast_literal[filename], lineno=ast_literal[ln], message=ast_literal[message])] with q as newbody: def _insert_funcname_here_( ): # no env needed, since `the[]` is not meaningful here. ... ast_literal[thetest] thefunc = newbody[0] thefunc.name = testblock_function_name thefunc.body = block_body return newbody
def test_expr(tree): # Note we want the line number *before macro expansion*, so we capture it now. ln = q[u[tree.lineno]] if hasattr(tree, "lineno") else q[None] filename = hq[callsite_filename()] asserter = hq[unpythonic_assert] # test[expr, message] (like assert expr, message) # TODO: Python 3.8+: ast.Constant, no ast.Str if type(tree) is Tuple and len( tree.elts) == 2 and type(tree.elts[1]) is Str: tree, message = tree.elts # test[expr] (like assert expr) else: message = q[None] # Before we edit the tree, get the source code in its pre-transformation # state, so we can include that into the test failure message. sourcecode = unparse(tree) gen_sym = dyn.gen_sym envname = gen_sym("e") # for injecting the captured value # Handle the `the[...]` mark, if any. tree, the_exprs = _transform_important_subexpr.recurse_collect( tree, envname=envname) if len(the_exprs) > 1: assert False, "test[]: At most one `the[...]` may appear in expr" # pragma: no cover if len(the_exprs) == 0 and type( tree) is Compare: # inject the implicit the[] on the LHS tree.left = _inject_value_recorder(envname, tree.left) # We delay the execution of the test expr using a lambda, so # `unpythonic_assert` can get control first before the expr runs. # # Also, we need the lambda for passing in the value capture environment # for the `the[]` mark, anyway. func_tree = q[lambda _: ast_literal[ tree]] # create the function that takes in the env func_tree.args.args[0] = arg( arg=envname) # inject the gensymmed parameter name return q[(ast_literal[asserter])(u[sourcecode], ast_literal[func_tree], filename=ast_literal[filename], lineno=ast_literal[ln], message=ast_literal[message])]
def _test_expr_signals_or_raises(tree, syntaxname, asserter): ln = q[u[tree.lineno]] if hasattr(tree, "lineno") else q[None] filename = hq[callsite_filename()] # test_signals[exctype, expr, message] # TODO: Python 3.8+: ast.Constant, no ast.Str if type(tree) is Tuple and len( tree.elts) == 3 and type(tree.elts[2]) is Str: exctype, tree, message = tree.elts # test_signals[exctype, expr] elif type(tree) is Tuple and len(tree.elts) == 2: exctype, tree = tree.elts message = q[None] else: assert False, "Expected one of {stx}[exctype, expr], {stx}[exctype, expr, message]".format( stx=syntaxname) return q[(ast_literal[asserter])(ast_literal[exctype], u[unparse(tree)], lambda: ast_literal[tree], filename=ast_literal[filename], lineno=ast_literal[ln], message=ast_literal[message])]
def indexer(tree, collect, **kw): try: unparse(tree) collect((tree.lineno, tree.col_offset)) except Exception, e: pass
def printcode(tree, expand_macros, **kw): expanded_tree = expand_macros(tree) print(unparse(expanded_tree)) return expanded_tree
def test_block(block_body, args): if not block_body: return [] # pragma: no cover, cannot happen through the public API. first_stmt = block_body[0] # Note we want the line number *before macro expansion*, so we capture it now. ln = q[u[first_stmt.lineno]] if hasattr(first_stmt, "lineno") else q[None] filename = hq[callsite_filename()] asserter = hq[unpythonic_assert] # with test(message): # TODO: Python 3.8+: ast.Constant, no ast.Str if len(args) == 1 and type(args[0]) is Str: message = args[0] # with test: elif len(args) == 0: message = q[None] else: assert False, 'Expected `with test:` or `with test(message):`' # Before we edit the tree, get the source code in its pre-transformation # state, so we can include that into the test failure message. sourcecode = unparse(block_body) gen_sym = dyn.gen_sym envname = gen_sym("e") # for injecting the captured value testblock_function_name = gen_sym("test_block") # Handle the `the[...]` mark, if any. block_body, the_exprs = _transform_important_subexpr.recurse_collect( block_body, envname=envname) if len(the_exprs) > 1: assert False, "test[]: At most one `the[...]` may appear in a `with test` block" # pragma: no cover thetest = q[(ast_literal[asserter])(u[sourcecode], name[testblock_function_name], filename=ast_literal[filename], lineno=ast_literal[ln], message=ast_literal[message])] with q as newbody: def _insert_funcname_here_(_insert_envname_here_): ... ast_literal[thetest] thefunc = newbody[0] thefunc.name = testblock_function_name thefunc.args.args[0] = arg( arg=envname) # inject the gensymmed parameter name # Handle the return statement. # # We just check if there is at least one; if so, we don't need to do # anything; the returned value is what the test should return to the # asserter. for stmt in block_body: if type(stmt) is Return: retval = stmt.value if len(the_exprs) == 0 and type(retval) is Compare: # inject the implicit the[] on the LHS retval.left = _inject_value_recorder(envname, retval.left) else: # When there is no return statement at the top level of the `with test` block, # we inject a `return True` to satisfy the test when the function returns normally. with q as thereturn: return True block_body.append(thereturn) thefunc.body = block_body return newbody
def preprocess(tree, **kw): #print(tree) if tree.name in container['config']: tree = transform.recurse(tree, ctx=tree.name) #, init_ctx=tree.name print(unparse(tree)) return tree
def testOpsToCallbacks(self): """ Op lists are converted to callback lists properly. """ def flattenOps(ops): return [[unparse(line.base).strip(), line.successName, line.successExpr and unparse(line.successExpr).strip(), line.successCB, line.failName, line.failExpr and unparse(line.failExpr).strip(), line.failCB] for line in ops] input = ast.parse(sampleAst1).body initialState, output = opsToCallbacks(buildOperationsDAG(input)) self.assertEqual(initialState.keys(), ['f']) self.assertEqual([unparse(v) for v in initialState.values()], ['0']) self.assertEqual( flattenOps(output), [['ruv.magic_fsOpen.callbackType', "f", "readLoop(f, buf)", output[1], "err", 'smash(r, StrObject((u"Couldn\'t open file fount: %s" % err)))', None], ['readLoop.callbackType', "contents", "ruv.magic_fsClose(vat, f)", output[3], "err", "ruv.magic_fsClose(vat, f)", output[2]], ['ruv.magic_fsClose.callbackType', None, "smash(r, StrObject((u'libuv error: %s' % err)))", None, None, None, None], ['ruv.magic_fsClose.callbackType', None, "resolve(r, BytesObject(contents))", None, None, None, None]]) input = ast.parse(sampleAst2).body initialState, output = opsToCallbacks(buildOperationsDAG(input)) self.assertEqual(initialState.keys(), ['x']) self.assertEqual([unparse(v) for v in initialState.values()], ['1']) self.assertEqual( flattenOps(output), [['io1.callbackType', 'x', 'io2()', output[1], 'err1', 'io3()', output[2]], ['io2.callbackType', 'y', 'io6()', output[5], 'err1', 'io3()', output[2]], ['io3.callbackType', None, 'io4()', output[3], None, None, None], ['io4.callbackType', None, 'ioC()', None, 'err2', 'io5()', output[4]], ['io5.callbackType', None, 'ioC()', None, None, None, None], ['io6.callbackType', None, 'io7()', output[6], None, None, None], ['io7.callbackType', None, 'io8()', output[7], 'err3', 'io9()', output[8]], ['io8.callbackType', None, 'ioA()', output[9], 'err3', 'io9()', output[8]], ['io9.callbackType', None, 'ioB()', output[10], None, None, None], ['ioA.callbackType', None, 'ioB()', output[10], None, None, None], ['ioB.callbackType', None, 'ioC()', None, None, None, None]]) input = ast.parse(sampleAst3).body initialState, output = opsToCallbacks(buildOperationsDAG(input)) self.assertEqual(initialState, {}) self.assertEqual( flattenOps(output), [['io0.callbackType', None, 'io1()', output[1], 'err2', 'io5()', output[5]], ['io1.callbackType', 'x', 'io2()', output[2], 'err1', 'io3()', output[3]], ['io2.callbackType', 'y', 'io4()', output[4], 'err1', 'io3()', output[3]], ['io3.callbackType', None, 'io6()', None, 'err2', 'io5()', output[5]], ['io4.callbackType', None, 'io6()', None, 'err2', 'io5()', output[5]], ['io5.callbackType', None, 'io6()', None, None, None, None]])
def flattenOps(ops): return [[unparse(line.base).strip(), line.successName, line.successExpr and unparse(line.successExpr).strip(), line.successCB, line.failName, line.failExpr and unparse(line.failExpr).strip(), line.failCB] for line in ops]