def wrap_code(code: str, args: str = '') -> ast.Module: """Compiles Python code into an async function or generator. Automatically adds return if the function body is a single evaluation. Also adds inline import expression support. """ if sys.version_info >= (3, 7): user_code = import_expression.parse(code, mode='exec') injected = '' else: injected = code mod = import_expression.parse(CORO_CODE.format( args, textwrap.indent(injected, ' ' * 8)), mode='exec') definition = mod.body[-1] # async def ...: assert isinstance(definition, ast.AsyncFunctionDef) try_block = definition.body[-1] # try: assert isinstance(try_block, ast.Try) if sys.version_info >= (3, 7): try_block.body.extend(user_code.body) else: preclude_offset = CORO_CODE.split('pass')[0].count('\n') + 1 ast.increment_lineno( mod, -preclude_offset) # bring line numbers back in sync with repl ast.fix_missing_locations(mod) is_asyncgen = any( isinstance(node, ast.Yield) for node in ast.walk(try_block)) last_expr = try_block.body[-1] # if the last part isn't an expression, ignore it if not isinstance(last_expr, ast.Expr): return mod # if the last expression is not a yield if not isinstance(last_expr.value, ast.Yield): # copy the expression into a return/yield if is_asyncgen: # copy the value of the expression into a yield yield_stmt = ast.Yield(last_expr.value) ast.copy_location(yield_stmt, last_expr) # place the yield into its own expression yield_expr = ast.Expr(yield_stmt) ast.copy_location(yield_expr, last_expr) # place the yield where the original expression was try_block.body[-1] = yield_expr else: # copy the expression into a return return_stmt = ast.Return(last_expr.value) ast.copy_location(return_stmt, last_expr) # place the return where the original expression was try_block.body[-1] = return_stmt return mod
def test_operators(self): boolop0 = ast.BoolOp() boolop1 = ast.BoolOp(ast.And(), [ ast.Name('True', ast.Load()), ast.Name('False', ast.Load()), ast.Name('a',ast.Load())]) boolop2 = ast.BoolOp(ast.And(), [ ast.Name('True', ast.Load()), ast.Name('False', ast.Load()), ast.Name('a',ast.Load())], 0, 0) binop0 = ast.BinOp() binop1 = ast.BinOp(ast.Str('xy'), ast.Mult(), ast.Num(3)) binop2 = ast.BinOp(ast.Str('xy'), ast.Mult(), ast.Num(3), 0, 0) unaryop0 = ast.UnaryOp() unaryop1 = ast.UnaryOp(ast.Not(), ast.Name('True',ast.Load())) unaryop2 = ast.UnaryOp(ast.Not(), ast.Name('True',ast.Load()), 0, 0) lambda0 = ast.Lambda() lambda1 = ast.Lambda(ast.arguments([ast.Name('x', ast.Param())], None, None, []), ast.Name('x', ast.Load())) ifexp0 = ast.IfExp() ifexp1 = ast.IfExp(ast.Name('True',ast.Load()), ast.Num(1), ast.Num(0)) ifexp2 = ast.IfExp(ast.Name('True',ast.Load()), ast.Num(1), ast.Num(0), 0, 0) dict0 = ast.Dict() dict1 = ast.Dict([ast.Num(1), ast.Num(2)], [ast.Str('a'), ast.Str('b')]) dict2 = ast.Dict([ast.Num(1), ast.Num(2)], [ast.Str('a'), ast.Str('b')], 0, 0) set0 = ast.Set() set1 = ast.Set([ast.Num(1), ast.Num(2)]) set2 = ast.Set([ast.Num(1), ast.Num(2)], 0, 0) lc0 = ast.ListComp() lc1 = ast.ListComp( ast.Name('x',ast.Load()), [ast.comprehension(ast.Name('x', ast.Store()), ast.Tuple([ast.Num(1), ast.Num(2)], ast.Load()), [])]) lc2 = ast.ListComp( ast.Name('x',ast.Load()), [ast.comprehension(ast.Name('x', ast.Store()), ast.Tuple([ast.Num(1), ast.Num(2)], ast.Load()), [])], 0, 0) setcomp0 = ast.SetComp() setcomp1 = ast.SetComp(ast.Name('x', ast.Load()), [ast.comprehension(ast.Name('x', ast.Store()), ast.Str('abracadabra'), [ast.Compare(ast.Name('x', ast.Load()), [ast.NotIn()], [ast.Str('abc')])])]) comprehension0 = ast.comprehension() comprehension1 = ast.comprehension(ast.Name('x', ast.Store()), ast.Tuple([ast.Num(1), ast.Num(2)], ast.Load()), []) # "{i : chr(65+i) for i in (1,2)}") dictcomp0 = ast.DictComp() dictcomp1 = ast.DictComp(ast.Name('i', ast.Load()), ast.Call(ast.Name('chr', ast.Load()), [ast.BinOp(ast.Num(65), ast.Add(), ast.Name('i', ast.Load()))], [], None, None), [ast.comprehension(ast.Name('i', ast.Store()), ast.Tuple([ast.Num(1), ast.Num(n=2)], ast.Load()), [])]) dictcomp2 = ast.DictComp(ast.Name('i', ast.Load()), ast.Call(ast.Name('chr', ast.Load()), [ast.BinOp(ast.Num(65), ast.Add(), ast.Name('i', ast.Load()))], [], None, None), [ast.comprehension(ast.Name('i', ast.Store()), ast.Tuple([ast.Num(1), ast.Num(n=2)], ast.Load()), [])],0,0) # (x for x in (1,2)) genexp0 = ast.GeneratorExp() genexp1 = ast.GeneratorExp(ast.Name('x', ast.Load()), [ast.comprehension(ast.Name('x', ast.Store()), ast.Tuple([ast.Num(1), ast.Num(2)], ast.Load()), [])]) genexp2 = ast.GeneratorExp(ast.Name('x', ast.Load()), [ast.comprehension(ast.Name('x', ast.Store()), ast.Tuple([ast.Num(1), ast.Num(2)], ast.Load()), [])],0,0) # yield 2 yield0 = ast.Yield() yield1 = ast.Yield(ast.Num(2)) yield2 = ast.Yield(ast.Num(2),0,0) yield20 = ast.Yield(lineno=0, col_offset=0) # a>0 compare0 = ast.Compare() compare1 = ast.Compare(ast.Name('a', ast.Load()), [ast.Gt()], [ast.Num(0)]) compare2 = ast.Compare(ast.Name('a', ast.Load()), [ast.Gt()], [ast.Num(0)],0,0) # chr(65) call0 = ast.Call() call1 = ast.Call(ast.Name('chr', ast.Load()), [ast.Num(65)], [], None, None) call2 = ast.Call(ast.Name('chr', ast.Load()), [ast.Num(65)], [], None, None, 0, 0) call20 = ast.Call(ast.Name('f', ast.Load()), [ast.Num(0)], []) call21 = ast.Call(ast.Name('f', ast.Load()), [ast.Num(0)], [], lineno=0, col_offset=0) # 0 num0 = ast.Num() num1 = ast.Num(0) num2 = ast.Num(0,0,0) # "foo" str0 = ast.Str() str1 = ast.Str("foo") str2 = ast.Str("foo",0,0) # TODO: come back repr0 = ast.Repr() repr1 = ast.Repr(ast.Num(0)) repr2 = ast.Repr(ast.Num(0),0,0) # foo.bar attr0 = ast.Attribute() attr1 = ast.Attribute(ast.Name('foo', ast.Load()), 'bar', ast.Load()) attr2 = ast.Attribute(ast.Name('foo', ast.Load()), 'bar', ast.Load(), 0,0) # a[1:2] subscript0 = ast.Subscript() subscript1 = ast.Subscript(ast.Name('a', ast.Load()), ast.Slice(ast.Num(1), ast.Num(2)), ast.Load()) subscript2 = ast.Subscript(ast.Name('a', ast.Load()), ast.ExtSlice([ast.Num(1), ast.Num(2)]), ast.Load(), 0, 0) # name name0 = ast.Name() name1 = ast.Name("name", ast.Load()) name2 = ast.Name("name", ast.Load(),0,0) # [1,2] list0 = ast.List() list1 = ast.List([ast.Num(1), ast.Num(2)], ast.Load()) list2 = ast.List([ast.Num(1), ast.Num(2)], ast.Load(),0,0) # (1,2) tuple0 = ast.Tuple() tuple1 = ast.Tuple([ast.Num(1), ast.Num(2)], ast.Load()) tuple2 = ast.Tuple([ast.Num(1), ast.Num(2)], ast.Load(), 0, 0)
def visit_Return(self, node): self.generic_visit(node) return ast.Expr(ast.Yield(node.value)) if self.active[-1] else node
def visitYield(self, n, *args): return ast.Yield(self.dispatch(n.value, *args) if n.value else None)
def test_optional_arg(self): node = python_ast.Yield() setattr(node, "value", None) assert python_ast.dump(node) == \ python_ast.dump(to_python_ast(to_ast(node, lambda x: [x])))
def test_yield(self): self.expr(ast.Yield(ast.Name("x", ast.Store())), "must have Load") self.expr(ast.YieldFrom(ast.Name("x", ast.Store())), "must have Load")
def 新节点( 类型, 主体=None, 忽略类型=None, 值=None, 左=None, 运算符=None, 右=None, 标识=None, 上下文=None, 函数=None, 参数=None, 关键词=None, 变量=None, 条件=None, 否则=None, 前项=None, 后项=None, 标注=None, 名称=None, 返回=None, 各基准类=None, 片段=None): if 类型 == 语法.模块: 节点 = ast.Module(body=主体, type_ignores=忽略类型) elif 类型 == 语法.表达式: 节点 = ast.Expr(value=值) elif 类型 == 语法.数: 节点 = ast.Num(n=值) elif 类型 == 语法.二元表达式: # 通过类名方式简化if语句 运算符名 = 运算符.__class__.__name__ if 运算符名 in ('And', 'Or'): 节点 = ast.BoolOp(op=运算符, values=[前项, 后项]) elif 运算符名 in ('Add', 'Sub', 'Mult', 'Pow', 'Mod', 'LShift', 'RShift', 'BitAnd', 'BitOr'): 节点 = ast.BinOp(left=左, op=运算符, right=右) else: # DONE: 为何比较符和后项在数组中? # https://docs.python.org/zh-cn/3/library/ast.html#ast.Compare 函数定义的参数在数组中 节点 = ast.Compare(前项, [运算符], [后项]) elif 类型 == 语法.名称: 节点 = ast.Name(id=标识, ctx=上下文) elif 类型 == 语法.调用: 节点 = ast.Call(func=函数, args=参数, keywords=关键词) elif 类型 == 语法.赋值: 节点 = ast.Assign([变量], 值) elif 类型 == 语法.增量赋值: 节点 = ast.AugAssign(变量, 运算符, 值) elif 类型 == 语法.类型赋值: 节点 = ast.AnnAssign( target=变量, annotation=标注, value=值, simple=1, ) elif 类型 == 语法.条件声明: 节点 = ast.If(test=条件, body=主体, orelse=否则) elif 类型 == 语法.每当声明: 节点 = ast.While(test=条件, body=主体, orelse=[]) elif 类型 == 语法.终止声明: 节点 = ast.Break() elif 类型 == 语法.跳过声明: 节点 = ast.Continue() elif 类型 == 语法.操作数: 节点 = ast.arg(arg=参数) elif 类型 == 语法.lambda形参 or 类型 == 语法.形参: 节点 = ast.arg(arg=参数, annotation=标注) elif 类型 == 语法.形参列表: 节点 = ast.arguments(args=参数, kwonlyargs=[], kw_defaults=[], defaults=[], vararg=None, kwarg=None) elif 类型 == 语法.函数: 节点 = ast.FunctionDef( name=名称, args=参数, body=主体, decorator_list=[] ) if 返回: 节点.returns = 返回 elif 类型 == 语法.生成表达式: 节点 = ast.Yield(value=值) elif 类型 == 语法.返回声明: 节点 = ast.Return(value=值) elif 类型 == 语法.引用声明: 节点 = ast.Import(names=名称) elif 类型 == 语法.lambda表达式: 节点 = ast.Lambda(args=参数, body=主体) elif 类型 == 语法.类型定义: 节点 = ast.ClassDef( name=名称, bases=各基准类, keywords=[], body=主体, decorator_list=[] ) elif 类型 == 语法.字符串: 节点 = ast.Str(值) elif 类型 == 语法.外部声明: 节点 = ast.Global(names=名称) elif 类型 == 语法.一元表达式: 节点 = ast.UnaryOp(op=运算符, operand=值) if 片段: 节点.lineno = 语法树.取行号(片段) 节点.col_offset = 语法树.取列号(片段) return 节点
def p_yield_expr3(self, p): ''' yield_expr : YIELD FROM testlist ''' value = ast_for_testlist(p[2]) p[0] = ast.Yield(value=value, lineno=p.lineno(1))
def p_yield_expr2(self, p): ''' yield_expr : YIELD testlist_star_expr ''' value = ast_for_testlist(p[2]) p[0] = ast.Yield(value=value, lineno=p.lineno(1))
def visit_Call(self, node): return ast.Yield(value=node)
def Yield(draw, expression) -> ast.Yield: return ast.Yield(draw(expression))
def visit_Yield(self, node: Yield, *args, **kwargs) -> C.Yield: value = self.visit(node.value, *args, **kwargs) return C.Yield(value=value, )
def generate_yield(max_depth=None): return ast.Expr(ast.Yield(generate_expression(max_depth=max_depth - 1)))
def yield_(value): return ast.Yield(value=value)
def _yield(self, node): return ast.Expr(ast.Yield(node))
def p_yield_stmt(p): """expression : YIELD expression""" p[0] = ast.Yield(p[2])
def make_yield(): """Yield(expr? value)""" return ast.Yield(value=make_expression())
def test_empty_init(self): # Jython 2.5.0 did not allow empty constructors for many ast node types # but CPython ast nodes do allow this. For the moment, I don't see a # reason to allow construction of the super types (like ast.AST and # ast.stmt) as well as the op types that are implemented as enums in # Jython (like boolop), but I've left them in but commented out for # now. We may need them in the future since CPython allows this, but # it may fall under implementation detail. #ast.AST() ast.Add() ast.And() ast.Assert() ast.Assign() ast.Attribute() ast.AugAssign() ast.AugLoad() ast.AugStore() ast.BinOp() ast.BitAnd() ast.BitOr() ast.BitXor() ast.BoolOp() ast.Break() ast.Call() ast.ClassDef() ast.Compare() ast.Continue() ast.Del() ast.Delete() ast.Dict() ast.Div() ast.Ellipsis() ast.Eq() ast.Exec() ast.Expr() ast.Expression() ast.ExtSlice() ast.FloorDiv() ast.For() ast.FunctionDef() ast.GeneratorExp() ast.Global() ast.Gt() ast.GtE() ast.If() ast.IfExp() ast.Import() ast.ImportFrom() ast.In() ast.Index() ast.Interactive() ast.Invert() ast.Is() ast.IsNot() ast.LShift() ast.Lambda() ast.List() ast.ListComp() ast.Load() ast.Lt() ast.LtE() ast.Mod() ast.Module() ast.Mult() ast.Name() ast.Not() ast.NotEq() ast.NotIn() ast.Num() ast.Or() ast.Param() ast.Pass() ast.Pow() ast.Print() ast.RShift() ast.Raise() ast.Repr() ast.Return() ast.Slice() ast.Store() ast.Str() ast.Sub() ast.Subscript() ast.Suite() ast.TryExcept() ast.TryFinally() ast.Tuple() ast.UAdd() ast.USub() ast.UnaryOp() ast.While() ast.With() ast.Yield() ast.alias() ast.arguments() #ast.boolop() #ast.cmpop() ast.comprehension() #ast.excepthandler() #ast.expr() #ast.expr_context() ast.keyword()
def ast_yield_true(): return ast.Yield(value=ast.Name(id='True', ctx=ast.Load))
def _check_for_duplicate_yields(self, node: ast.Yield, current_statement: ast.stmt) -> None: if not isinstance(node.value, ast.Tuple) or len(node.value.elts) < 2: return duplicate_indices = {} # index to first index seen = {} # ast.dump result to index for i, member in enumerate(node.value.elts): # identical AST nodes don't compare equally, so just stringify them for comparison code = ast.dump(member) if code in seen: duplicate_indices[i] = seen[code] else: seen[code] = i if not duplicate_indices: return new_members = [ elt for i, elt in enumerate(node.value.elts) if i not in duplicate_indices ] if len(new_members) == 1: new_value = new_members[0] else: new_value = ast.Tuple(elts=new_members) new_yield_node = ast.Yield(value=new_value) if isinstance(current_statement, ast.Expr) and current_statement.value is node: new_nodes = [ast.Expr(value=new_yield_node)] elif (isinstance(current_statement, ast.Assign) and current_statement.value is node): if (len(current_statement.targets) != 1 or not isinstance(current_statement.targets[0], ast.Tuple) or len(current_statement.targets[0].elts) != len( node.value.elts)): new_nodes = None else: new_targets = [] # these are for cases where we do something like # a, b = yield f.asynq(), f.asynq() # we turn this into # a = yield f.asynq() # b = a extra_nodes = [] assignment_targets = current_statement.targets[0].elts for i, target in enumerate(assignment_targets): if i not in duplicate_indices: new_targets.append(target) elif not (isinstance(target, ast.Name) and target.id == "_"): extra_nodes.append( ast.Assign( targets=[target], value=assignment_targets[duplicate_indices[i]], )) if len(new_targets) == 1: new_target = new_targets[0] else: new_target = ast.Tuple(elts=new_targets) new_assign = ast.Assign(targets=[new_target], value=new_yield_node) new_nodes = [new_assign] + extra_nodes else: new_nodes = None if new_nodes is not None: lines_to_delete = self._lines_of_node(node) indent = self._indentation_of_node(current_statement) new_code = "".join( decompile(node, starting_indentation=indent) for node in new_nodes) new_lines = [line + "\n" for line in new_code.splitlines()] replacement = Replacement(lines_to_delete, new_lines) else: replacement = None self.visitor.show_error(node, error_code=ErrorCode.duplicate_yield, replacement=replacement)