WRAP(...)
中,保留注释和其他所有内容:example = """
def foo(): # Test
'''My func'''
log("hello world") # Print
"""
import ast, asttokens
atok = asttokens.ASTTokens(example, parse=True)
call = next(n for n in ast.walk(atok.tree) if isinstance(n, ast.Call))
start, end = atok.get_text_range(call)
print(atok.text[:start] + ('WRAP(%s)' % atok.text[start:end]) + atok.text[end:])
def foo(): # Test
'''My func'''
WRAP(log("hello world")) # Print
一个程序转换系统是一种工具,可以解析源代码文本,构建ASTs,并允许您使用源到源转换来修改它们(“如果您看到这个模式,请将其替换为该模式”)。这样的工具非常适合对现有源代码进行突变,这些代码仅是“如果您看到此模式,请替换为模式变体”。
当然,您需要一个能够解析您感兴趣的语言并仍然进行模式导向转换的程序转换引擎。我们的DMS软件重构工具包可以做到这一点,并处理Python和其他各种语言。
查看此SO答案,其中有一个Python的DMS解析AST捕获注释的示例。DMS可以更改AST并重新生成有效文本,包括注释。您可以要求它使用自己的格式约定(您可以更改这些)对AST进行漂亮打印,或者进行“忠实打印”,该打印使用原始行和列信息以最大程度地保留原始布局(在插入新代码的位置上不可避免地会有一些布局变化)。
要使用DMS为Python实现“突变”规则,可以编写以下内容:
rule mutate_addition(s:sum, p:product):sum->sum =
" \s + \p " -> " \s - \p"
if mutate_this_place(s);
这个规则以语法正确的方式将“+”替换为“-”; 它操作于AST,因此不会触及看起来正确的字符串或注释。 "mutate_this_place"上的额外条件是让您控制此操作发生的频率; 您不希望突变程序中的每个位置。
显然,您需要更多类似于此的规则,以检测各种代码结构,并用突变版本替换它们。 DMS很高兴应用一组规则。 突变后的AST然后被漂亮地打印出来。
我曾经使用baron来完成这个任务,但现在已经转换到parso,因为它与现代python兼容。它非常好用。
我也需要这个来进行变异测试。使用parso制作一个变异测试器非常简单,请查看我的代码https://github.com/boxed/mutmut
我已经编写了几个实用程序来完成这种操作,而在每种情况下,我选择的工具都是libcst
。Instagram创建了这个库来操作他们的Python代码库,例如插入类型注释。尽管它没有使用AST,而是CST,但结构非常相似,而且易于使用。