Mar*_*eld 7 python backwards-compatibility
在我目前的工作环境中,我们会生成大量内部使用的Python包(如果不是100则为10s).每个包都有一些依赖关系,通常是内部和外部包的混合,并且这些依赖关系中的一些是共享的.
当我们接近依赖地狱时,更新依赖关系变成一个耗时的过程.虽然我们关心新版本可能引入的功能更改,但重要的是(如果不是更多)重要的是API更改会破坏代码.
尽管针对较新版本的依赖项运行单元/集成测试有助于我们捕获一些问题,但我们的覆盖范围并不足以达到100%才能使其成为一个强大的策略.发行说明和更改日志有助于识别高级别的主要更改,但这些更改很少存在于内部开发的工具中,或者详细了解新版本对(公共)API的影响.
我正在寻找其他方法来自动化这个过程.
我希望能够自动比较Python包的两个版本并报告它们之间的API差异.特别是这将包括向后不兼容的更改,例如删除函数/方法/类/模块,向函数/方法/类添加位置参数以及更改函数/方法返回的项数.作为开发人员,基于此生成的报告,我应该对此版本更改将引入的代码级别含义有更深入的了解,因此需要时间来集成它.
在其他地方,我们使用C++ abi-compliance-checker,并且正在查看Java api-compliance-checker以帮助完成此过程.是否有适用于Python的类似工具?我发现了大量的lint/analysis/refactor工具,但没有提供这种功能.据我所知,Python的动态类型将无法提供全面的报告.
如果这样的工具不存在,那么它们是否可以帮助实现解决方案?例如,我当前的方法是使用ast.NodeVisitor遍历包并构建一个树,其中每个节点代表一个模块/类/方法/函数,然后将该树与同一个包的另一个版本的树进行比较.
编辑:自发布问题以来,我发现pysdiff涵盖了我的一些要求,但有兴趣看到其他选择.
编辑:还发现Upstream-Tracker就是我想最终得到的那种信息的一个很好的例子.
使用AST模块解析文件怎么样?
import ast
with file("test.py") as f:
python_src = f.read()
node = ast.parse(python_src) # Note: doesn't compile the src
print ast.dump(node)
Run Code Online (Sandbox Code Playgroud)
ast节点上有walk方法(描述http://docs.python.org/2/library/ast.html)
astdump可能有效(可在pypi上获得)
这个过时的漂亮打印机 http://code.activestate.com/recipes/533146-ast-pretty-printer/
文档工具Sphinx还会提取您要查找的信息.也许看看吧.
所以走AST并用你想要的信息构建一棵树.一旦你有了一棵树,你就可以腌制它并稍后进行差异化,或者将树转换为文本文件中的文本表示,你可以使用difftools或一些外部差异程序进行差异.
ast有parse()和compile()方法.唯一的问题是我不完全确定解析后有多少信息可供使用(因为你不想编译()).
也许您可以从使用该inspect模块开始
import inspect
import types
def genFunctions(module):
moduleDict = module.__dict__
for name in dir(module):
if name.startswith('_'):
continue
element = moduleDict[name]
if isinstance(element, types.FunctionType):
argSpec = inspect.getargspec(element)
argList = argSpec.args
print "{}.{}({})".format(module.__name__, name, ", ".join(argList))
Run Code Online (Sandbox Code Playgroud)
这将为您提供“公共”(不以下划线开头)函数及其参数列表的列表。您可以添加更多内容来打印 kwargs、类等。
一旦你在你关心的所有包/模块上运行它,无论是旧版本还是新版本,你都会有两个像这样的列表:
myPackage.myModule.myFunction1(foo, bar)
myPackage.myModule.myFunction2(baz)
Run Code Online (Sandbox Code Playgroud)
然后,您可以对它们进行排序和比较,或者在 Python 中编写一些更智能的工具来实际比较所有名称,例如允许其他可选参数但拒绝新的强制参数。