搜索导入位置

时间:2013-02-06 15:37:46

标签: python

我正在尝试编写一个Python脚本/函数来帮助确定导入的位置 来自的东西。我希望这个功能专门用于PyQt4,但它可以 对Python标准库进行扩展和有用。

要实现这一点,我需要动态搜索模块,共享对象, 对于给定的搜索词,可能有更多类型的东西。

我想传递一个模块/ class / etc.作为字符串,动态导入然后 搜索它。

该函数的接口将是这样的:

search(object_to_search, search_term)

示例:

search('datetime', 'today') -> 'datetime.datetime.today'

search('PyQt4', 'NonModal') -> 'PyQt4.QtCore.Qt.NonModal'

search('PyQt4', 'QIcon') -> 'PyQt4.QtGui.QIcon'

我认为这也可以支持像'*'这样的通配符来搜索所有 sys.path然而,这超出了我对此的看法 时间。

这种类型的脚本对PyQt4特别有用。有很多的 'enum-like'之类的内容,例如上面的NonModal,并找到要导入的位置 或引用它们可能很麻烦。

因为PyQt4信息,我倾向于使用C ++ Qt文档 将示例翻译成Python通常很容易。 C ++ Qt 文档更全面。找到示例代码也更容易 对于Qt来说。然而,其中一些'enum-like'的导入位置 PyQt4中很难找到属性而无需手动搜索文档或 猜测。目标是自动执行此过程,并让脚本告诉您 我正在寻找的东西的位置。

我尝试过几种不同的实现方式,包括搜索 使用dir()模块递归inspect的对象,以及hacky 共享对象的导入/发现版本。以下是我的各种 实现,其中非实际工作正常。

这类事情甚至可能吗?如果是这样,最好的方法是什么? 另外,我试图通过省略来减少搜索的内容 内置的东西,功能等,但我不相信这是必要的 甚至是正确的。

尝试解决方案:

def search_obj_inspect(obj, search_term):
    """Search given object for 'search_term' with 'inspect' module"""

    import inspect

    def searchable_type(obj):
        is_class = inspect.isclass(obj)
        root_type_or_obj = is_class and obj not in [object, type]
        abstract_class = is_class and inspect.isabstract(obj)
        method_or_func = inspect.ismethod(obj) or inspect.isfunction(obj)
        try:
            hidden_attribute = obj.__name__.startswith('__')
        except AttributeError:
            hidden_attribute = False

        searchable = True

        # Avoid infinite recursion when looking through 'object' and 'type' b/c
        # they are members of each other
        if True in [abstract_class, root_type_or_obj, hidden_attribute,
                    method_or_func, inspect.isbuiltin(obj)]:
            searchable = False

        return searchable


    # FIXME: Search obj itself for search term? obj.__name__ == search_term?
    for n, v in inspect.getmembers(obj,
                                   predicate=lambda x: searchable_type(x)):
        if search_term in n:
            try:
                return v.__name__
            except AttributeError:
                return str(v)

    return None


def search_obj_dir(obj, search_term):
    """Search given object and all it's python submodules for attr"""

    import re
    import types
    SEARCHABLE_TYPES = (types.ModuleType, types.ClassType, types.InstanceType,
                        types.DictProxyType)

    for item in dir(obj):
        if item.startswith('__'):
            continue

        if re.search(search_term, item):
            return obj.__dict__[item].__module__
        else:
            try:
                submod = obj.__dict__[item]
            except (KeyError, AttributeError):
                # Nothing left to recursively search
                continue

            if not isinstance(submod, SEARCHABLE_TYPES):
                continue

            #mod = search_obj_dir(submod, search_term)
            #if mod:
                #return '.'.join([mod, submod.__name__])

    return None


def search_so(module, attr):
    """Search given modules shared objects for attr"""

    import os
    import re

    try:
        path = module.__path__[0]
    except (AttributeError, IndexError):
        return False

    for root, dirs, files in os.walk(path):
        for filename in files:
            if filename.endswith('.so'):
                py_module_name = filename.split('.')[0]
                so_module = __import__(module.__name__, globals(), locals(),
                                        [py_module_name])

                if re.search(attr, py_module_name):
                    return ''.join([module.__name__, '.', py_module_name])
                try:
                    found = search_obj_dir(
                                    so_module.__dict__[py_module_name], attr)
                except KeyError:
                    # This isn't a top-level so, might be a subpackage
                    # FIXME: Could recursively search SO as well, but imports
                    #        might get weird
                    continue

                if found:
                    return found

1 个答案:

答案 0 :(得分:0)

感谢@JonClements提示查看pydoc模块。我发现了一种通过pkgutilinspect模块组合实现我想要的方法。

'''是使用pkgutil.iter_modules遍历包中的所有模块(如PyQt4),然后可以使用inspect.getmembers搜索所有非包对象。一般的想法如下:

for pkg in given_pkg:
    for module_or_class in pkg:
        for attribute in module_or_class:

您可以看到完整的解决方案here