分析Python项目的导入依赖
总的来说,我想了解我的项目中使用的大框架到底用到了哪些代码。
首先,我想知道所有的导入(可能通过静态分析来实现),然后如果可以的话,想知道这些导入中哪些实际上是被用到的。
对于第一个问题,我当然可以用正则表达式来解决,但我想找到一种更干净的方法。不过,我不太清楚如何使用ast/inspect/parser来实现。
至于第二个问题,我应该能自动找出哪些导入实际上没有被使用,但我该怎么做呢?
编辑:关于第二个问题,或许最好的办法是用一个简单的导入钩子,它可以记录所有被导入的内容,然后再调用默认的导入机制。
所以我尝试了类似这样的代码:
class MyLoader(object):
"""
Loader object
"""
def __init__(self):
self.loaded = set()
def find_module(self, module_name, package=None):
print("requesting %s" % module_name)
self.loaded.add(module_name)
return self
def load_module(self, fullname):
fp, pathname, stuff = imp.find_module(fullname)
imp.load_module(fullname, fp, pathname, stuff)
但是在尝试导入“random”时,我得到了
from future import division
ImportError: No module named future
我觉得这意味着我缺少了一些东西……我还没有找到任何简单的例子来使用imp进行导入检查,有什么提示吗?
2 个回答
我很高兴地说,列出导入的内容其实非常简单。
我需要一个最基本的导入协议实现(这个协议是PEP 302定义的),如果find_module返回None,它就会自动尝试下一个。
这个简单的脚本实际上可以显示传入程序的导入情况:
import sys
class ImportInspector(object):
def find_module(self, module, path):
print("importing module %s" % module)
if __name__ == '__main__':
progname = sys.argv[0]
# shift by one position
sys.argv = sys.argv[1:]
sys.meta_path.append(ImportInspector())
code = compile(open(progname, 'rb').read(), progname, 'exec')
exec(code)
有了这个,我们可以在此基础上实现各种技巧。比如,我们可以用一个集合来跟踪所有的导入,并在程序退出时把它们都存储起来。
我觉得我们甚至可以得到导入的层级关系,并生成一个类似于gprof2dot的图,但只是基于对导入的分析。
这个分析的问题在于Python的动态特性。实际上,使用的模块可能会依赖于运行时的变量(也就是说,有些模块可能只在特定的运行条件下被导入和使用)。
这可能不是最好的方法,但如果你的代码有相当不错的测试覆盖率,你可以使用coverage.py的输出结果来检查在测试执行过程中加载了哪些模块。