def assert_ast_like(self, f, target): from lambdex.utils.ast import ( ast_from_source, pformat, pprint, recursively_set_attr, ) ast_f = f.__ast__ recursively_set_attr(ast_f, "type_comment", None) ast_target = ast_from_source(target, "def") ast_target.name = ast_f.name try: assert_ast_like(ast_f, ast_target) except AssertionError as cause: msg = "\n".join( [ "", "===> Compiled:", pformat(ast_f), "===> Target:", pformat(ast_target), ] ) raise AssertionError(msg) from cause
def assert_ast_like(self, f, target): from lambdex.utils.ast import ast_from_source, pformat, pprint, recursively_set_attr ast_f = f.__ast__ recursively_set_attr(ast_f, 'type_comment', None) ast_target = ast_from_source(target, 'async def') ast_target.name = ast_f.name try: assert_ast_like(ast_f, ast_target) except AssertionError as cause: msg = '\n'.join(['', '===> Compiled:', pformat(ast_f), '===> Target:', pformat(ast_target)]) raise AssertionError(msg) from cause
def assert_ast_like(self, f, target): ast_f = f.__ast__ recursively_set_attr(ast_f, "type_comment", None) if is_coroutine_ast(ast_f): keyword = "async def" else: keyword = "def" ast_target = ast_from_source(target, keyword) ast_target.name = ast_f.name try: assert_ast_like(ast_f, ast_target) except AssertionError as cause: msg = "\n".join([ "", "===> Compiled:", pformat(ast_f), "===> Target:", pformat(ast_target), ]) raise AssertionError(msg) from cause
def _compile( ast_node: ast.AST, filename: str, freevars: typing.Sequence[str], globals: typing.Optional[dict] = None, ) -> typing.Tuple[types.CodeType, ast.AST, typing.Sequence[int]]: """ An internal function that do the compilation. """ if globals is None: globals = {} context = Context( compile_node, globals, filename, ) lambdex_node = compile_node( ast_node, ctx=context, flag=ContextFlag.outermost_lambdex, ) # A name in `lambdex_node` should be compiled as nonlocal instead of # global (default) if it appears in `freevars`. # # This is done by wrapping `lambdex_node` in another FunctionDef, and # let names in `freevars` become local variables in the wrapper. wrapper_name = context.select_name_and_use("wrapper") if freevars: wrapper_body = [ ast.Assign( targets=[ ast.Name(id=name, ctx=ast.Store()) for name in freevars ], value=None_node, ), lambdex_node, ] else: wrapper_body = [lambdex_node] wrapper_node = ast.FunctionDef( name=wrapper_name, args=empty_arguments, body=wrapper_body, decorator_list=[], returns=None, ) module_node = ast.Module( body=[wrapper_node], type_ignores=[], ) module_node = ast.fix_missing_locations(module_node) if __DEBUG__: try: module_code = compile(module_node, filename, "exec") except Exception as e: raise SyntaxError(pformat(module_node)) from e else: module_code = compile(module_node, filename, "exec") # unwrap the outer FunctionDef. # since no other definition in the module, it should be co_consts[0] wrapper_code = module_code.co_consts[0] # the desired code object should be in `module_code.co_consts` # we use `.co_name` to identify for obj in wrapper_code.co_consts: if inspect.iscode(obj) and obj.co_name == lambdex_node.name: lambdex_code = obj break # Append code object name to its co_freevars, so that lambdex # can always access itself via its name `anonymous_...` callee_name = lambdex_code.co_name try: callee_index = lambdex_code.co_freevars.index(callee_name) except ValueError: callee_index = len(lambdex_code.co_freevars) lambdex_code = compat.code_replace( lambdex_code, co_freevars=(*lambdex_code.co_freevars, callee_name), ) freevars_mapping = _resolve_freevars_mapping(freevars, lambdex_code.co_freevars) lambdex_code = _rename_code_object(lambdex_code, context) return lambdex_code, lambdex_node, freevars_mapping