分析python项目导入

2024-04-25 20:01:38 发布

您现在位置:Python中文网/ 问答频道 /正文

一般来说,我想了解我的项目中的代码在一个大框架中实际使用的是什么代码。在

首先我想知道什么是所有的导入(可能是静态分析),然后如果可能的话,这些导入中有哪些是实际使用的。在

对于第一个问题,我当然可以使用regexp,但是我想找到一个更干净的方法。 但是我不知道如何使用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)

但尝试输入“随机”我得到 来自未来进口部 重要错误:没有名为未来的模块

我想这意味着我遗漏了一些东西。。 我没有找到任何使用imp进行导入内省的简单示例,有什么提示吗?在


Tags: 方法代码nameselfobjectdefloadfind
3条回答

我不知道我是否应该再问一个问题,我会试着跟在这里。在

所以现在我想做一些更花哨的事情,写一个上下文管理器,它在场景后面做一些肮脏的工作来测试我的代码以进行分析。在

下面的代码给了我一个非常奇怪的错误,我真的无法理解:

 File "study_imports.py", line 59, in <module>
   exec(code)
 File "study_imports.py", line 55, in <module>
   cl = CollectImports()
 File "study_imports.py", line 15, in __init__
   self.loaded = set()
RuntimeError: maximum recursion depth exceeded while calling a Python object

import os
import sys

class CollectImports(object):
    """
    Import hook, adds each import request to the loaded set and dumps
    them to file
    """

    def __init__(self):
        self.loaded = set()

    def __str__(self):
        return str(self.loaded)

    def dump_to_file(self, fname):
        """Dump the loaded set to file
        """
        dumped_str = '\n'.join(x for x in self.loaded)
        open(fname, 'w').write(dumped_str)

    def find_module(self, module_name, package=None):
        self.loaded.add(module_name)


class CollectorContext(object):
    """Example of context manager to collect and dump on exit
   XXX: not working at the moment
    """

    def __init__(self, collector, argv, output_file):
        self.collector = collector
        self.argv = argv
        self.output_file = output_file

    def __enter__(self):
        self.argv = self.argv[1:]
        sys.meta_path.append(self.collector)

    def __exit__(self, type, value, traceback):
        # TODO: should assert that the variables are None, otherwise
        # we are quitting with some exceptions
        self.collector.dump_to_file(self.output_file)
        sys.meta_path.remove(self.collector)



if __name__ == '__main__':
    # main()
    progname = sys.argv[0]
    cl = CollectImports()

    with CollectorContext(cl, sys.argv, 'imports.log'):
        code = compile(open(progname).read(), progname, 'exec')
        exec(code)

我很高兴地说,列出进口商品实际上很简单。在

我需要一个Importer协议的最小实现(由pep302定义),如果find_模块返回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的动态特性。事实上,使用的模块集可能依赖于运行时变量(即某些模块只能在某些运行时条件下导入和使用)。在

可能不是最好的方法,但是如果您的代码有相当好的测试覆盖率,您可以使用覆盖率.py输出以检查在测试执行期间加载了哪些模块。在

相关问题 更多 >

    热门问题