列出给定完整路径的模块中的所有函数

时间:2016-08-31 00:55:37

标签: python

我试图列出每个遇到的模块中的所有函数来强制编写测试用例。但是,我遇到的问题只是将文件的完整路径作为字符串而不是导入它。当我使用inspect.getmembers(fullpath, inspect.isfunction)时,它返回一个空数组。有没有办法实现这个目标?到目前为止,这是我的代码:

import glob
import os
import inspect

def count_tests(moduletestdict):
    for key,value in moduletestdict.items():
        print("Key: {}".format(key))
        print(inspect.getmembers(key, inspect.isfunction))

def find_functions(base_dir):
    """moduletestdict has key value pairs where the key is the module
    to be tested and the value is the testing module"""
    moduletestdict = {}
    for roots, dirs, files in os.walk(base_dir):
        for f in files:
            if (".py" in f) and (".pyc" not in f) and ("test_" not in f) and (f != "__init__.py"):
                if "test_{}".format(f) in files:
                    moduletestdict["{}/{}".format(roots,f)] = "{}/{}".format(roots, "test_{}".format(f))
                else:   
                    moduletestdict["{}/{}".format(roots,f)] = "NOTEST"
    return moduletestdict

if __name__ == "__main__":
    base_dir = "/Users/MyName/Documents/Work/MyWork/local-dev/sns"
    moduletestdict = find_functions(base_dir)
    count_tests(moduletestdict)

1 个答案:

答案 0 :(得分:0)

你确实需要以某种方式导入模块,但“推荐”的方式有点棘手,因为随着新版本的Python不断变化,请参阅this answer

这是一个基于gorilla library的测试运行器的示例,它与Python 2和Python 3兼容:

import inspect
import os
import sys


def module_iterator(directory, package_dotted_path):
    paths = os.listdir(directory)
    for path in paths:
        full_path = os.path.join(directory, path)
        basename, tail = os.path.splitext(path)
        if basename == '__init__':
            dotted_path = package_dotted_path
        elif package_dotted_path:
            dotted_path = "%s.%s" % (package_dotted_path, basename)
        else:
            dotted_path = basename

        if os.path.isfile(full_path):
            if tail != '.py':
                continue

            __import__(dotted_path)
            module = sys.modules[dotted_path]
            yield module
        elif os.path.isdir(full_path):
            if not os.path.isfile(os.path.join(full_path, '__init__.py')):
                continue

            __import__(dotted_path)
            package = sys.modules[dotted_path]
            yield package
            for module in module_iterator(full_path, dotted_path):
                yield module

def main():
    directory_path = '/path/to/your/package'
    package_name = 'package'
    sys.path.insert(0, directory_path)
    modules = module_iterator(directory_path, package_name)
    for module in modules:
        functions = inspect.getmembers(module, inspect.isfunction)
        print("functions for module '{0}': {1}".format(
            module.__name__, functions)
        )

if __name__ == "__main__":
    main()

这里/path/to/your/package将是包的存储库,即包含自述文件,文档等的目录,就像Python包的情况一样,而package_name将是存储库中包含根__init__.py文件的目录名。

实际上,函数module_iterator也接受其参数package_dotted_path的模块,例如'package.subpackage.module',但之后只会检索此特定模块中的函数。如果传递了一个包,那么将检查所有递归嵌套的模块。