def test_return_value_is_filled_dict_by_keyword(): # when method return dict(a='b') try: assert ReturnedExpression( _ast.Return( value=_ast.Call( func=_ast.Name(id='dict', ctx=_ast.Load()), args=[], keywords=[_ast.keyword(arg='a', value=_ast.Str(s='b'))], ), lineno=1, ), ).value_not_none() is True except (AttributeError): assert ReturnedExpression( _ast.Return( value=_ast.Call( func=_ast.Name(id='dict', ctx=_ast.Load()), args=[], keywords=[ _ast.keyword(arg='a', value=_ast.JoinedStr(values=['a', 'b'])) ], ), lineno=1, ), ).value_not_none() is True
def _replace_with_block_context(with_node, block_type): with_node.items[0].context_expr = _ast.Call( func=_ast.Attribute(value=_ast.Name(id='self', ctx=_ast.Load()), attr='_feature_block_context', ctx=_ast.Load()), args=[_ast.Str(s=block_type)], keywords=[])
def visit_Expr(self, expression_node): value = expression_node.value if not isinstance(value, _ast.BinOp) or not isinstance( value.op, _ast.Mult) or not isinstance(value.right, _ast.Call): return expression_node number_of_invocations = value.left if MockAssertionTransformer._value_is_a_wildcard( number_of_invocations): number_of_invocations = _ast.Num(n=-1) target_mock = value.right.func.value target_method = _ast.Str(s=value.right.func.attr) list_of_arguments = [ MockAssertionTransformer._transform_arg_if_wildcard(x) for x in value.right.args ] spread_list_of_arguments = _ast.Starred(value=_ast.List( elts=list_of_arguments, ctx=_ast.Load()), ctx=_ast.Load()) expression_node.value = _ast.Call( func=_ast.Attribute(value=_ast.Name(id='self', ctx=_ast.Load()), attr='_assert_mock', ctx=_ast.Load()), args=[ number_of_invocations, target_mock, target_method, spread_list_of_arguments ], keywords=[]) return expression_node
def new_class(self, items): identifier = items[0] if len(items) > 1: args = items[1] else: args = [] return _ast.Call(func=_ast.Name(id=identifier), args=args, keywords=[])
def visit_Expr(self, expression_node): value = expression_node.value if not isinstance(value, _ast.Compare): if isinstance(value, _ast.BinOp): if hasattr(value, 'op') and not isinstance(value.op, _ast.MatMult): return expression_node else: return expression_node left_value = value.left # TODO: Support multiple comparators (1 < 2 < 3). This may be tricky because one expression of multiple if hasattr(value, 'op'): comparison_operation = value.op right_value = value.right else: comparison_operation = value.ops[0] right_value = value.comparators[0] comparison_operation_type = type(comparison_operation) internal_comparison_type = self.comparator_methods[ comparison_operation_type] expression_node.value = _ast.Call( func=_ast.Attribute(value=_ast.Name(id='self', ctx=_ast.Load()), attr='_compare', ctx=_ast.Load()), args=[ left_value, right_value, _ast.Str(s=internal_comparison_type.name) ], keywords=[]) return expression_node
def make_call(i, bytecode): op = bytecode[i][2] def get_call_arg_length(op, arg): na = arg & 0xff # num args nk = (arg >> 8) & 0xff # num keywords return na, nk, na + 2 * nk + CALL_EXTRA_ARG_OFFSET[op] has_var, has_kw = 0, 0 if op in (CALL_FUNCTION_VAR, CALL_FUNCTION_VAR_KW): has_var = 1 if op in (CALL_FUNCTION_KW, CALL_FUNCTION_VAR_KW): has_kw = 1 op, arg = bytecode[i][2], bytecode[i][3] num_args, num_keywords, offset = get_call_arg_length(op, arg) func, args, keywords, starargs, kwargs = None, None, None, None, None if has_kw > 0: i, kwargs = Statement.make_expr(i - 1, bytecode) if has_var > 0: i, starargs = Statement.make_expr(i - 1, bytecode) # Handle keywords if num_keywords > 0: keywords = [] while num_keywords > 0: i, kw_value = Statement.make_expr(i - 1, bytecode) i, kw_name = Statement.make_expr(i - 1, bytecode) keywords.insert(0, _ast.keyword(kw_name, kw_value)) num_keywords -= 1 finger = i - 1 if num_args > 0: n = num_args - 1 args = [None] * num_args for k in range(num_args): cur_stack = 0 loc_bytecode = [] is_first = True while True: op, arg = bytecode[finger][2], bytecode[finger][3] pop, push = get_stack_effect(op, arg) cur_stack -= (pop - push) if not is_first else pop is_first = False loc_bytecode.insert(0, bytecode[finger]) if cur_stack == 0: break finger -= 1 _, args[n] = Statement.make_expr(len(loc_bytecode) - 1, loc_bytecode) n -= 1 finger -= 1 _, func = Statement.make_expr(finger, bytecode) call = _ast.Call(func, args, keywords, starargs, kwargs) logger.debug("\n%s", dump(call)) return finger, call
def test_return_value_is_empty_frozenset_by_keyword(): # when method return frozenset() assert ReturnedExpression( _ast.Return( value=_ast.Call( func=_ast.Name(id='frozenset', ctx=_ast.Load()), args=[], keywords=[], ), lineno=1, ), ).value_not_none() is False
def visit_Call(self, expression_node): if isinstance(expression_node, _ast.Call): if hasattr(expression_node.func, 'id') and expression_node.func.id == 'thrown': expected_exception = expression_node.args[0] expression_node = _ast.Call(func=_ast.Attribute( value=_ast.Name(id='self', ctx=_ast.Load()), attr='_exception_thrown', ctx=_ast.Load()), args=[expected_exception], keywords=[]) return expression_node
def visit_Expr(self, expression_node): expression_value = expression_node.value if type(expression_value) is _ast.Compare: comparison_method = 'assertEquals' expression_node.value = _ast.Call( func=_ast.Attribute(value=_ast.Name(id='self', ctx=_ast.Load()), attr=comparison_method, ctx=_ast.Load()), args=[expression_value.left, expression_value.comparators[0]], keywords=[]) return expression_node
def test_return_value_is_filled_frozenset_by_keyword(): # when method return frozenset('1') try: assert ReturnedExpression( _ast.Return( value=_ast.Call( func=_ast.Name(id='frozenset', ctx=_ast.Load()), args=[_ast.Str(s='1')], keywords=[], ), lineno=1, ), ).value_not_none() is True except (AttributeError): assert ReturnedExpression( _ast.Return( value=_ast.Call( func=_ast.Name(id='frozenset', ctx=_ast.Load()), args=[_ast.JoinedStr(values=['1'])], keywords=[], ), lineno=1, ), ).value_not_none() is True
def test_return_value_is_func(): assert ReturnedExpression( _ast.Return( value=_ast.Call( func=_ast.Attribute( value=_ast.Name(id='Function', ctx=_ast.Load()), attr='staticm', ctx=_ast.Load(), ), args=[], keywords=[], ), lineno=1, ), ).value_not_none() is True
def Call(caller, args=(), keys=(), values=(), starargs=None, kwargs=None): """Creates an _ast.Call node. Args: caller: Either a node of the appropriate type (_ast.Str, _ast.Name, or _ast.Attribute), or a dot-separated string. args: A list of args. keys: A list of keys, must be the same length as values. values: A list of values, correspond to keys. starargs: A node with a star in front of it. Passing a string will be interpreted as a VarReference. kwargs: A node with two stars in front of it. Passing a string will be interpreted as a VarReference. Raises: ValueError: If len(keys) != len(values) or caller is not the right type. Returns: An _ast.Call object. """ if len(keys) != len(values): raise ValueError('len(keys)={} != len(values)={}'.format( len(keys), len(values))) if isinstance(caller, str): caller = VarReference(*caller.split('.')) if not isinstance(caller, (_ast.Str, _ast.Name, _ast.Attribute)): raise ValueError('caller must be a: \n' '1. string\n' '2. _ast.Str node\n' '3. _ast.Name node\n' '4. _ast.Attr node\n' 'not {}'.format(caller)) keywords = [ _ast.keyword(arg=key, value=val) for key, val in zip(keys, values) ] args = [_WrapWithName(arg, ctx_type=CtxEnum.LOAD) for arg in args] if isinstance(starargs, str): starargs = VarReference(*starargs.split('.')) if isinstance(kwargs, str): kwargs = VarReference(*kwargs.split('.')) return _ast.Call(func=caller, args=args, keywords=keywords, starargs=starargs, kwargs=kwargs)
def visit_Call( self, node ): # TODO: specially handle self.visit( node.func ) if attr # currently not visiting at all! args = [self.visit(x) for x in node.args] keywords = [self.visit(x) for x in node.keywords] if node.starargs: starargs = [self.visit(x) for x in node.starargs] else: starargs = None if node.kwargs: kwargs = [self.visit(x) for x in node.kwargs] else: kwargs = None return _ast.Call(func=node.func, args=args, keyword=keywords, starargs=starargs, kwargs=kwargs)
def CALL_FUNCTION(self, instr): nkwargs = instr.oparg >> 8 nargs = (~(nkwargs << 8)) & instr.oparg args = [] keywords = [] for _ in range(nkwargs): expr = self.ast_stack.pop() name = self.ast_stack.pop() keyword = _ast.keyword(arg=name.s, value=expr, lineno=instr.lineno) keywords.insert(0, keyword) for _ in range(nargs): arg = self.ast_stack.pop() args.insert(0, arg) if len(args) == 1 and isinstance(args[0], (_ast.FunctionDef, _ast.ClassDef)): function = args[0] if function.decorator_list is None: function.decorator_list = [] node = self.ast_stack.pop() function.decorator_list.insert(0, node) self.ast_stack.append(function) return node = self.ast_stack.pop() callfunc = _ast.Call( func=node, args=args, keywords=keywords, starargs=None, kwargs=None, lineno=instr.lineno, col_offset=0, ) self.ast_stack.append(callfunc)
def test_bug_null_in_objspace_type(self): import ast code = ast.Expression( lineno=1, col_offset=1, body=ast.ListComp( lineno=1, col_offset=1, elt=ast.Call(lineno=1, col_offset=1, func=ast.Name(lineno=1, col_offset=1, id='str', ctx=ast.Load(lineno=1, col_offset=1)), args=[ ast.Name(lineno=1, col_offset=1, id='x', ctx=ast.Load(lineno=1, col_offset=1)) ], keywords=[]), generators=[ ast.comprehension( lineno=1, col_offset=1, target=ast.Name(lineno=1, col_offset=1, id='x', ctx=ast.Store(lineno=1, col_offset=1)), iter=ast.List( lineno=1, col_offset=1, elts=[ast.Num(lineno=1, col_offset=1, n=23)], ctx=ast.Load( lineno=1, col_offset=1, )), ifs=[]) ])) compile(code, '<template>', 'eval')
def visit_Assign(self, node): """Rewrite the Assign visitor function to deal with list comprehensions and function calls. """ # if the value is a list comprehension, the we need to handle # it specially if isinstance(node.value, (_ast.ListComp, _ast.GeneratorExp, _ast.Lambda)): node.value = self.extract(node.value, cthreshold=1) iden = self.visit(node.value) if isinstance(node.value, _ast.GeneratorExp): val = _ast.Call(func=_ast.Name(id=iden, ctx=_ast.Load()), args=[], keywords=[], starargs=None, kwargs=None) else: val = _ast.Name(id=iden, ctx=_ast.Load()) node = ast.Assign(value=val, targets=node.targets) elif isinstance(node.value, _ast.Dict) or \ isinstance(node.value, _ast.List) or \ isinstance(node.value, _ast.Tuple): node.value = self.extract(node.value, threshold=0) else: # do Call/ListComp extraction on the node's value node.value = self.extract(node.value, cthreshold=0) self.newline(node) for idx, target in enumerate(node.targets): if idx: self.write(' = ') self.visit(target) self.write(' = ') self.visit(node.value)
def _cfa(body, state, on_gen): assert isinstance(on_gen, list) for c in on_gen: assert callable(c) cfg = state.cfg def make_connect(cur_bid): assert isinstance(cur_bid, int) def inner(new_bid): assert isinstance(new_bid, int) state.connect([cur_bid], [new_bid]) return inner def push_block(block): block_id = len(cfg.blocks) assert block_id not in cfg.blocks cfg.blocks[block_id] = block for c in on_gen: c(block_id) return block_id cur_block = [] for b in body: if REDUCE_FORS_TO_WHILES and isinstance(b, _ast.For): if isinstance(b.iter, _ast.Call) and isinstance( b.iter.func, _ast.Name) and b.iter.func.id in ("range", "xrange"): if not b.iter.keywords and not b.iter.starargs and not b.iter.kwargs: end_var = "__wfend_%d_%d_" % (b.lineno, b.col_offset) iter_var = "__wfiter_%d_%d_" % (b.lineno, b.col_offset) if len(b.iter.args) in (1, 2): if len(b.iter.args) == 1: start = _ast.Num(0) end = b.iter.args[0] elif len(b.iter.args) == 2: start = b.iter.args[0] end = b.iter.args[1] else: start = b.iter.args[0] end = b.iter.args[1] cur_block.append( _ast.Assign([ _ast.Name( iter_var, _ast.Store(), not_real=True) ], start, lineno=b.lineno, col_offset=b.col_offset, not_real=True)) cur_block.append( _ast.Assign([ _ast.Name(end_var, _ast.Store(), not_real=True) ], end, lineno=b.lineno, col_offset=b.col_offset, not_real=True)) body = [ _ast.Assign([b.target], _ast.Name(iter_var, _ast.Load(), not_real=True), lineno=b.lineno, col_offset=b.col_offset, not_real=True), _ast.Assign([ _ast.Name( iter_var, _ast.Store(), not_real=True) ], _ast.BinOp( _ast.Name(iter_var, _ast.Load(), not_real=True), _ast.Add(), _ast.Num(1)), lineno=b.lineno, col_offset=b.col_offset, not_real=True) ] + b.body b = _ast.While(_ast.Compare( _ast.Name(iter_var, _ast.Load(), not_real=True), [_ast.Lt()], [_ast.Name(end_var, _ast.Load(), not_real=True)], lineno=b.lineno, col_offset=b.col_offset, not_real=True), body, b.orelse, not_real=True) if isinstance(b, ( _ast.Assign, _ast.AugAssign, _ast.ClassDef, _ast.Delete, _ast.Exec, _ast.Expr, _ast.FunctionDef, _ast.Global, _ast.Import, _ast.ImportFrom, _ast.Print, _ast.Pass, )): cur_block.append(b) elif isinstance(b, _ast.Assert): cur_block.append(b) if isinstance(b.test, _ast.Call) and isinstance( b.test.func, _ast.Name ) and b.test.func.id == "isinstance" and isinstance( b.test.args[0], _ast.Name) and isinstance( b.test.args[1], _ast.Name): varname = b.test.args[0].id cast = _ast.Call(_ast.Name( "__cast__", _ast.Load(), not_real=True, **pos(b)), [ _ast.Name( varname, _ast.Store(), not_real=True, **pos(b)), b.test.args[1] ], [], None, None, not_real=True, **pos(b)) assign = _ast.Assign([ _ast.Name(varname, _ast.Store(), not_real=True, **pos(b)) ], cast, not_real=True, lineno=b.lineno, col_offset=b.col_offset) cur_block.append(assign) elif isinstance(b, (_ast.Break, _ast.Continue)): f = state.add_break if isinstance( b, _ast.Break) else state.add_continue if cur_block: j = Jump() cur_block.append(j) block_id = push_block(cur_block) f(j.set_dest) f(make_connect(block_id)) else: for c in on_gen: f(c) return [] elif isinstance(b, _ast.If): br = Branch(b.test, lineno=b.lineno) cur_block.append(br) next_block = push_block(cur_block) on_gen = None # make sure this doesn't get used cur_block = [] gen_true = [br.set_true, make_connect(next_block)] gen_false = [br.set_false, make_connect(next_block)] if ENFORCE_NO_MULTIMULTI: on_gen = gen_true j1 = Jump() gen_true = [make_connect(push_block([j1])), j1.set_dest] on_gen = gen_false j2 = Jump() gen_false = [make_connect(push_block([j2])), j2.set_dest] on_gen = None assert b.body body = b.body if isinstance(b.test, _ast.Call) and isinstance( b.test.func, _ast.Name ) and b.test.func.id == "isinstance" and isinstance( b.test.args[0], _ast.Name) and isinstance( b.test.args[1], _ast.Name): varname = b.test.args[0].id cast = _ast.Call(_ast.Name( "__cast__", _ast.Load(), not_real=True, **pos(b)), [ _ast.Name( varname, _ast.Store(), not_real=True, **pos(b)), b.test.args[1] ], [], None, None, not_real=True, **pos(b)) assign = _ast.Assign([ _ast.Name(varname, _ast.Store(), not_real=True, **pos(b)) ], cast, not_real=True, lineno=b.lineno, col_offset=b.col_offset) body = [assign] + body if ADD_IF_ASSERTS: body = [_ast.Assert(b.test, None, not_real=True, **pos(b)) ] + body ending_gen = _cfa(body, state, gen_true) if b.orelse: ending_gen += _cfa(b.orelse, state, gen_false) else: ending_gen += gen_false on_gen = ending_gen if not on_gen and PRUNE_UNREACHABLE_BLOCKS: return [] elif isinstance(b, _ast.TryExcept): j = Jump() cur_block.append(j) next_block = push_block(cur_block) on_gen = [j.set_dest, make_connect(next_block)] cur_block = [] on_gen = _cfa(b.body, state, on_gen) # Set this to evaluate a string to try to defeat simple flow analysis br = Branch(_ast.Str("nonzero")) next_block = push_block([br]) on_except = [br.set_false, make_connect(next_block)] on_fine = [br.set_true, make_connect(next_block)] assert len(b.handlers) >= 1 # for handler in b.handlers: # on_except = _cfa(b.handlers[0].body, state, on_except) if b.orelse: on_fine = _cfa(b.orelse, state, on_fine) if ENFORCE_NO_MULTIMULTI: j = Jump() on_gen = on_fine next_block = push_block([j]) on_fine = [j.set_dest, make_connect(next_block)] j = Jump() on_gen = on_except next_block = push_block([j]) on_except = [j.set_dest, make_connect(next_block)] on_gen = on_fine + on_except cur_block = [] elif isinstance(b, _ast.TryFinally): j = Jump() cur_block.append(j) next_block = push_block(cur_block) on_gen = [j.set_dest, make_connect(next_block)] cur_block = [] on_gen = _cfa(b.body, state, on_gen) on_gen = _cfa(b.finalbody, state, on_gen) elif isinstance(b, _ast.While): # This could also be architected as having no extra block and having two jump statements, but I don't like that if cur_block: j = Jump() cur_block.append(j) on_gen = [make_connect(push_block(cur_block)), j.set_dest] cur_block = [] always_true = False always_false = False if isinstance(b.test, _ast.Name): if b.test.id == "True": always_true = True elif b.test.id == "False": always_false = True elif isinstance(b.test, _ast.Num): if b.test.n: always_true = True else: always_false = True if always_true: br = Jump() on_true = br.set_dest elif always_false: br = Jump() on_false = br.set_dest else: br = Branch(b.test) on_true = br.set_true on_false = br.set_false init_id = push_block([br]) on_gen = None assert cur_block == [] # just checking if not always_false: gen_true = [on_true, make_connect(init_id)] if not always_true: gen_false = [on_false, make_connect(init_id)] if ENFORCE_NO_MULTIMULTI: if not always_false: on_gen = gen_true j1 = Jump() gen_true = [make_connect(push_block([j1])), j1.set_dest] if not always_true: on_gen = gen_false j2 = Jump() gen_false = [make_connect(push_block([j2])), j2.set_dest] on_gen = None ending_gen = [] if not always_false: state.push_loop() assert b.body loop_ending_gen = _cfa(b.body, state, gen_true) loop_ending_gen += state.get_continues() for c in loop_ending_gen: c(init_id) ending_gen = state.get_breaks() state.pop_loop() if not always_true: if b.orelse: ending_gen += _cfa(b.orelse, state, gen_false) else: ending_gen += gen_false on_gen = ending_gen if not on_gen and PRUNE_UNREACHABLE_BLOCKS: return [] elif isinstance(b, _ast.For): iter_func = _ast.Attribute(b.iter, "__iter__", _ast.Load(), not_real=True, lineno=b.lineno, col_offset=b.col_offset) iter_call = _ast.Call(iter_func, [], [], None, None, not_real=True, lineno=b.lineno, col_offset=b.col_offset) # iter_var = _make_temp_name() iter_var = "__foriter_%d_%d_" % (b.lineno, b.col_offset) iter_assign = _ast.Assign( [_ast.Name(iter_var, _ast.Store(), not_real=True, **pos(b))], iter_call, not_real=True, lineno=b.lineno, col_offset=b.col_offset) cur_block.append(iter_assign) j = Jump() cur_block.append(j) on_gen = [make_connect(push_block(cur_block)), j.set_dest] cur_block = [] br = Branch( HasNext( _ast.Name(iter_var, _ast.Load(), not_real=True, **pos(b)), **pos(b)), **pos(b)) init_id = push_block([br]) on_gen = None assert cur_block == [] # just checking gen_true = [br.set_true, make_connect(init_id)] gen_false = [br.set_false, make_connect(init_id)] if ENFORCE_NO_MULTIMULTI: on_gen = gen_true j1 = Jump() gen_true = [make_connect(push_block([j1])), j1.set_dest] on_gen = gen_false j2 = Jump() gen_false = [make_connect(push_block([j2])), j2.set_dest] on_gen = None ending_gen = [] state.push_loop() next_func = _ast.Attribute(_ast.Name(iter_var, _ast.Load(), not_real=True, **pos(b)), "next", _ast.Load(), not_real=True, lineno=b.lineno, col_offset=b.col_offset) next = _ast.Call(next_func, [], [], None, None, not_real=True, lineno=b.lineno, col_offset=b.col_offset) next_assign = _ast.Assign([b.target], next, not_real=True, lineno=b.lineno, col_offset=b.col_offset) next_iter_gen = _cfa([next_assign] + b.body, state, gen_true) next_iter_gen += state.get_continues() for c in next_iter_gen: c(init_id) loop_done_gen = list(state.get_breaks()) state.pop_loop() if b.orelse: # if b.orelse and loop_ending_blocks: loop_done_gen += _cfa(b.orelse, state, gen_false) else: loop_done_gen += gen_false on_gen = loop_done_gen if not on_gen and PRUNE_UNREACHABLE_BLOCKS: return [] elif isinstance(b, (_ast.Return, _ast.Raise)): cur_block.append(b) block_id = push_block(cur_block) state.returns.append(make_connect(block_id)) return [] elif isinstance(b, _ast.With): # XXX totally ignores the functionality of with statements # Have to save the context manager because the expression might not be valid later mgr_name = "__mgr_%s_%s_" % (b.lineno, b.col_offset) save_mgr = _ast.Assign([ _ast.Name(mgr_name, _ast.Store(), lineno=b.lineno, col_offset=b.col_offset, not_real=True) ], b.context_expr, lineno=b.lineno, col_offset=b.col_offset, not_real=True) enter_func = _ast.Attribute(_ast.Name(mgr_name, _ast.Load(), lineno=b.lineno, col_offset=b.col_offset, not_real=True), "__enter__", _ast.Load(), lineno=b.lineno, col_offset=b.col_offset, not_real=True) bind = _ast.Call(enter_func, [], [], None, None, lineno=b.lineno, col_offset="__enter__()", not_real=True) if b.optional_vars: assert isinstance(b.optional_vars, _ast.AST) init = _ast.Assign([b.optional_vars], bind, lineno=b.lineno, col_offset=b.col_offset, not_real=True) else: init = _ast.Expr(bind, lineno=b.lineno, col_offset=b.col_offset, not_real=True) exit_func = _ast.Attribute(_ast.Name(mgr_name, _ast.Load(), lineno=b.lineno, col_offset=b.col_offset, not_real=True), "__exit__", _ast.Load(), lineno=b.lineno, col_offset=b.col_offset, not_real=True) if SIMPLE_WITH_EXIT: exit_call = _ast.Call(exit_func, [], [], None, None, lineno=b.lineno, col_offset=b.col_offset, not_real=True) else: none_ = _ast.Name("None", _ast.Load(), lineno=b.lineno, col_offset=b.col_offset, not_real=True) exit_call = _ast.Call(exit_func, [none_, none_, none_], [], None, None, lineno=b.lineno, col_offset=b.col_offset, not_real=True) exit = _ast.Expr(exit_call, lineno=b.lineno, col_offset="__exit__()", not_real=True) cur_block.extend([save_mgr, init]) j = Jump() cur_block.append(j) next_block = push_block(cur_block) on_gen = [j.set_dest, make_connect(next_block)] cur_block = [] body = b.body + [exit] next_gen = _cfa(body, state, on_gen) on_gen = next_gen else: raise Exception(b) if cur_block: j = Jump() cur_block.append(j) next = push_block(cur_block) return [j.set_dest, make_connect(next)] return on_gen return on_gen
def call_expr(func: _ast.expr, args: List[_ast.expr], keywords: List[_ast.expr] = None) -> _ast.Call: if keywords is None: keywords = list() return _ast.Call(func=func, args=args, keywords=keywords)