def simplify_list_comp( comp: t.Union[ast.ListComp, ast.GeneratorExp, ast.SetComp, ast.DictComp], new_stmts: t.List[ast.stmt], init: ast.expr, appender_attr: str, ) -> ast.Name: rewriter = NameRewriter() for gen in comp.generators: rewriter.visit(gen.target) res_load, res_store = gensym() res_stmts: t.List[ast.stmt] = [] if isinstance(comp, ast.DictComp): rewriter.visit(comp.key) rewriter.visit(comp.value) key = SimplifyExpr(res_stmts).visit(comp.key) value = SimplifyExpr(res_stmts).visit(comp.value) res_stmts.append( ast.Assign(targets=[ ast.Subscript(value=c.deepcopy(res_load), slice=ast.Index(value=key), ctx=ast.Store()) ], value=value)) else: rewriter.visit(comp.elt) comp.elt = SimplifyExpr(res_stmts).visit(comp.elt) res_stmts.append( ast.Expr(value=ast.Call( func=ast.Attribute(value=c.deepcopy(res_load), attr=appender_attr, ctx=ast.Load()), args=[comp.elt], keywords=[], ))) for gen in reversed(comp.generators): new_loop: t.Union[ast.For, ast.AsyncFor] if hasattr(gen, 'is_async') and gen.is_async: # type: ignore new_loop = ast.AsyncFor(target=gen.target, orelse=[]) else: new_loop = ast.For(target=gen.target, orelse=[]) body: t.List[ast.stmt] = [] new_loop.iter = SimplifyExpr(body).visit(gen.iter) for cond in reversed(gen.ifs): res_stmts = [ast.If(test=cond, body=res_stmts, orelse=[])] new_loop.body = res_stmts body.append(new_loop) res_stmts = body new_stmts.append(ast.Assign( targets=[res_store], value=init, )) new_stmts.extend(res_stmts) return res_load
def p_async_for_stmt(self, p): ''' async_for_stmt : ASYNC for_stmt ''' async_for = ast.AsyncFor() for_node = p[2] for attr in tuple(for_node._fields) + ('lineno', 'col_offset'): setattr(async_for, attr, getattr(for_node, attr)) p[0] = async_for
def visit_AsyncFor(self, node): new_node = ast.AsyncFor( self._visit(node.target), self._visit(node.iter), self._visit(node.body), self._visit(node.orelse), None, # type_comment ) return ast.copy_location(new_node, node)
def visit_AsyncFor(self, node): new_body = self.if_exists(node.body, self.visit_list) new_orelse = self.if_exists(node.orelse, self.visit_list) new_target = self.visit(node.target) new_iter = self.visit(node.iter) return_list = self.new_stmts + [ ast.copy_location( ast.AsyncFor(new_target, new_iter, new_body, new_orelse), node) ] self.new_stmts.clear() return return_list
def visit_AsyncFor(self, node: AsyncFor, *args, **kwargs) -> C.AsyncFor: target = self.visit(node.target, *args, **kwargs) iter = self.visit(node.iter, *args, **kwargs) body = self.visit(node.body, *args, **kwargs) orelse = self.visit(node.orelse, *args, **kwargs) type_comment = self.visit(node.type_comment, *args, **kwargs) return C.AsyncFor( target=target, iter=iter, body=body, orelse=orelse, type_comment=type_comment, )
def explode_list_comp( comp: t.Union[ast.ListComp, ast.GeneratorExp, ast.SetComp], new_stmts: t.List[ast.stmt], init: ast.expr, appender_attr: str, ) -> ast.expr: res_load, res_store = gensym() res_stmts: t.List[ast.stmt] = [ ast.Expr( value=ast.Call( func=ast.Attribute( value=c.deepcopy(res_load), attr=appender_attr, ctx=ast.Load() ), args=[comp.elt] ) ) ] for gen in reversed(comp.generators): new_loop: t.Union[ast.For, ast.AsyncFor] if gen.is_async: new_loop = ast.AsyncFor(target=gen.target) else: new_loop = ast.For(target=gen.target) body: t.List[ast.stmt] = [] new_loop.iter = explode_expr(gen.iter, body) for cond in reversed(gen.ifs): res_stmts = [ast.If(cond, res_stmts)] new_loop.body = res_stmts body.append(new_loop) res_stmts = body new_stmts.append(ast.Assign( targets=[res_store], value=init, )) new_stmts.extend(res_stmts) return res_load
import pytest from astvalidate.validators.contextual import ContextualASTValidator @pytest.mark.parametrize( "node, message", [ (ast.Return(), "inside of a function"), ( ast.AsyncFunctionDef(body=[ast.Yield(), ast.Return(1)]), "can't be part of async gen", ), (ast.Continue(), "inside of a loop"), (ast.Break(), "inside of a loop"), (ast.AsyncFor(), "inside of a coroutine"), ( ast.Try(handlers=[ ast.ExceptHandler(type=None), ast.ExceptHandler(type=1), ]), "must be placed last", ), ( ast.Module([1, 2, ast.ImportFrom("__future__")]), "must occur at the top", ), ( ast.Module( [ast.ImportFrom("__future__", names=[ast.alias(name="lol")])]), "'lol' is not defined",
def AsyncFor(draw, statements) -> ast.AsyncFor: target = draw(Name(ast.Store)) iter = draw(expression()) body = draw(lists(statements, min_size=1, max_size=3)) orelse = draw(lists(statements, min_size=1, max_size=3)) return ast.AsyncFor(target, iter, body, orelse)
def _translate_all_expression_to_a_module( generator_exp: ast.GeneratorExp, generated_function_name: str, name_to_value: Mapping[str, Any]) -> ast.Module: """ Generate the AST of the module to trace an all quantifier on an generator expression. :param generator_exp: generator expression to be translated :param generated_function_name: UUID of the tracing function to be used in the code :param name_to_value: mapping of all resolved values to the variable names (passed as arguments to the function so that the generation can access them) :return: translation to a module """ assert generated_function_name not in name_to_value assert not hasattr(builtins, generated_function_name) # Collect all the names involved in the generation relevant_names = _collect_stored_names( generator.target for generator in generator_exp.generators) assert generated_function_name not in relevant_names # Work backwards, from the most-inner block outwards result_id = 'icontract_tracing_all_result_{}'.format(uuid.uuid4().hex) result_assignment = ast.Assign( targets=[ast.Name(id=result_id, ctx=ast.Store())], value=generator_exp.elt) exceptional_return = ast.Return( ast.Tuple(elts=[ ast.Name(id=result_id, ctx=ast.Load()), ast.Tuple(elts=[ ast.Tuple(elts=[ ast.Constant(value=relevant_name, kind=None), ast.Name(id=relevant_name, ctx=ast.Load()) ], ctx=ast.Load()) for relevant_name in relevant_names ], ctx=ast.Load()) ], ctx=ast.Load())) # While happy return shall not be executed, we add it here for robustness in case # future refactorings forget to check for that edge case. happy_return = ast.Return( ast.Tuple(elts=[ ast.Name(id=result_id, ctx=ast.Load()), ast.Constant(value=None, kind=None) ], ctx=ast.Load())) critical_if: If = ast.If(test=ast.Name(id=result_id, ctx=ast.Load()), body=[ast.Pass()], orelse=[exceptional_return]) # Previous inner block to be added as body to the next outer block block = None # type: Optional[List[ast.stmt]] for i, comprehension in enumerate(reversed(generator_exp.generators)): if i == 0: # This is the inner-most comprehension. block = [result_assignment, critical_if] assert block is not None for condition in reversed(comprehension.ifs): block = [ast.If(test=condition, body=block, orelse=[])] if not comprehension.is_async: block = [ ast.For(target=comprehension.target, iter=comprehension.iter, body=block, orelse=[]) ] else: block = [ ast.AsyncFor(target=comprehension.target, iter=comprehension.iter, body=block, orelse=[]) ] assert block is not None block.append(happy_return) # Now we are ready to generate the function. is_async = any(comprehension.is_async for comprehension in generator_exp.generators) args = [ ast.arg(arg=name, annotation=None) for name in sorted(name_to_value.keys()) ] if sys.version_info < (3, 5): raise NotImplementedError( "Python versions below 3.5 not supported, got: {}".format( sys.version_info)) if not is_async: if sys.version_info < (3, 8): func_def_node = ast.FunctionDef( name=generated_function_name, args=ast.arguments(args=args, kwonlyargs=[], kw_defaults=[], defaults=[], vararg=None, kwarg=None), decorator_list=[], body=block ) # type: Union[ast.FunctionDef, ast.AsyncFunctionDef] module_node = ast.Module(body=[func_def_node]) else: func_def_node = ast.FunctionDef(name=generated_function_name, args=ast.arguments(args=args, posonlyargs=[], kwonlyargs=[], kw_defaults=[], defaults=[], vararg=None, kwarg=None), decorator_list=[], body=block) module_node = ast.Module(body=[func_def_node], type_ignores=[]) else: if sys.version_info < (3, 8): async_func_def_node = ast.AsyncFunctionDef( name=generated_function_name, args=ast.arguments(args=args, kwonlyargs=[], kw_defaults=[], defaults=[], vararg=None, kwarg=None), decorator_list=[], body=block) module_node = ast.Module(body=[async_func_def_node]) else: async_func_def_node = ast.AsyncFunctionDef( name=generated_function_name, args=ast.arguments(args=args, posonlyargs=[], kwonlyargs=[], kw_defaults=[], defaults=[], vararg=None, kwarg=None), decorator_list=[], body=block) module_node = ast.Module(body=[async_func_def_node], type_ignores=[]) ast.fix_missing_locations(module_node) return module_node
def generate_async_for(max_depth=None): target = generate_variable_or_tuple() iter = generate_expression(max_depth=max_depth) body = generate_block(max_depth=max_depth) orelse = random.choice([generate_block(max_depth=max_depth), []]) return ast.AsyncFor(target, iter, body, orelse)