当对Python脚本进行表面更改(例如,更改代码样式/格式/空格)时,能够检查是否(意外地)对代码进行了任何逻辑更改是很有用的。 / p>
对于C / C ++,我生成汇编程序并将其与区分开来(不是100%使用特定于平台ifdef's
的傻瓜证明,但仍然有用)。虽然我可以对pyc
文件进行二进制差异化处理,但这对于查看确切更改的内容并非如此有用。
有没有一种方便的方法来获取可以检查更改的AST的人类可读文本输出?
这当然可能会引发一些误报(例如,将str % bar
替换为str.format(bar)
),但我仍然有兴趣知道是否存在一些方便的方法。
背景信息
因为建议只是运行测试。
以下是我提出这个问题的原因。
此代码没有测试,并且它不太可能具有100%的测试覆盖率,因为它恰好是构建系统实用程序脚本。理论上,我们可以花时间添加测试套件,并找到使测试能够在不同平台上运行的方法(猴子补丁sys.platform
或在VM中所有支持的平台上运行持续集成...)但我们可以&目前正在努力花费这种努力。
此外,您可能希望自己清理测试代码!
答案 0 :(得分:2)
解析AST以检查逻辑差异是一个好主意。 Python使its AST非常容易使用。
import ast
original_ast = ast.parse("""
import sys
for a in range(0,10):
print(a)
sys.exit(0)""")
altered_ast = ast.parse("""
import sys
for a in range(0,10):
print(a + 1)
sys.exit(0)""")
ast.dump(original_ast) == ast.dump(altered_ast)
如果你想看到差异,那么Python有另一个built in diff library。
答案 1 :(得分:1)
正如@ erik-e所指出的那样,你可以简单地使用ast.dump
,但这会将所有内容放在一行中,这是ast.dump
的修改版本,在一个从stdin中读取并打印的脚本中淘汰了。
例如:
py_to_ast < my_script.py > my_ast.txt
除了换行符和缩进之外,输出与ast.dump
相同。
您可以从以下位置下载脚本: https://gitlab.com/ideasman42/dotfiles/blob/master/bin/py_to_ast.py
此脚本的Example output贯穿其自身
#!/usr/bin/env python3
import ast
def dump(node, annotate_fields=True, include_attributes=False):
"""
ast.dump from Python3.4 modified for pretty printing.
"""
from ast import AST, iter_fields
def _format(node, level):
level_next = level + 1
indent = level * ' '
indent_next = level_next * ' '
if isinstance(node, AST):
fields = [(a, _format(b, level_next)) for a, b in iter_fields(node)]
rv = '\n' + indent + '%s(%s' % (node.__class__.__name__, (',\n' + indent_next).join(
('%s=%s' % field for field in fields)
if annotate_fields else
(b for a, b in fields)
))
if include_attributes and node._attributes:
rv += fields and ', ' or ' '
rv += (',\n' + indent_next).join('%s=%s' % (a, _format(getattr(node, a), level_next))
for a in node._attributes)
return rv + ')'
elif isinstance(node, list):
return '[%s]' % (',\n' + indent_next).join(_format(x, level_next) for x in node)
return repr(node)
if not isinstance(node, AST):
raise TypeError('expected AST, got %r' % node.__class__.__name__)
return _format(node, 0)
import sys
def main():
data = sys.stdin.read()
tree = ast.parse(data)
print(dump(tree))
if __name__ == "__main__":
main()
答案 2 :(得分:0)
你可以很容易地创建自己的树,如果上面的相等运算符已经超载以进行比较,我建议阅读它,你还没有必须手动比较它们。
了解here
答案 3 :(得分:-1)
我们的SmartDifferencer将源代码解析为AST,并计算AST的差异。这会忽略字符串中的空格格式,注释,数字基数,转义序列。 SmartDifference适用于Python以及其他语言。
如果唯一的变化是空白差异,则AST差异为空。在这种情况下,程序在语义上是相同的。
任何实际差异都以对代码结构的合理编辑的形式报告,例如:删除,插入,移动,复制,替换标识符。