如何在不导入模块的情况下检查模块的属性

时间:2017-02-13 01:46:44

标签: python

我正在尝试为Python 3(toga)的UI库编写静态文档生成器。

在项目中有子目录:

  • iOS
    • setup.py
    • toga_iOS
      • __init__.py
      • app.py
  • mac
    • setup.py
    • toga_mac
      • __init__.py
      • app.py

我想遍历目录并获取__all__模块中toga_x属性的值。我遇到的问题是每个模块都设计为安装在该平台上,例如Windows需要一个安装在Windows上的Python软件包,Mac上的Mac等等。

如果我使用importlib或__import__它会失败,因为在每个__init__.py文件中它将导入特定于平台的软件包,例如。

PLATFORM_LIST = {
    'android': 'Android',
    'cocoa': 'Mac OS cocoa',
    'gtk': 'GTK +'
}

for module, label in PLATFORM_LIST.items():
    print(module)
    sys.path.append(os.path.join('../src',
                                 module))
    module = importlib.import_module('toga_'+module)
    sys.modules[module] = module
    _all = getattr(module, '__all__')

因“ImportError:没有名为'android'的模块”而失败。

有很多选项,ast,pylint,compile,inspectlib。哪个是获得__all__的价值而不必安装所有相关模块的最佳方法?

1 个答案:

答案 0 :(得分:2)

您可以使用ast在python源文件中查找静态分配节点:

import ast


def get_declaration_from_source(text, name="__all__"):
    """gets a single declaration from python source code"""
    tree = ast.parse(text)
    #walk through each statement (more or less) in the module
    for node in tree.body:
        #if assigning to a single target (a = b=  5 is multiple)
        if isinstance(node, ast.Assign) and len(node.targets)==1:
            target = node.targets[0]
            #if assigning to the name we are looking for
            if isinstance(target, ast.Name) and target.id == name:
                #use literal_eval to get the actual value, can raise ValueError if not a literal value.
                return ast.literal_eval(node.value)
    raise NameError("name %r was not found"%(name,))

可以使用random源文件作为示例:

import random
with open(random.__file__, "r") as f:
    names = get_declaration_from_source(f.read())

>>> names
['Random', 'seed', 'random', 'uniform', 'randint', 'choice', 'sample', 'randrange', 'shuffle', 'normalvariate', 'lognormvariate', 'expovariate', 'vonmisesvariate', 'gammavariate', 'triangular', 'gauss', 'betavariate', 'paretovariate', 'weibullvariate', 'getstate', 'setstate', 'getrandbits', 'choices', 'SystemRandom']

请注意,如果源代码存在语法错误(可能在编译时可能引发其他错误),则ast.parse可能会引发SyntaxError,而ast.literal_eval会引发ValueError如果值不是python文字,你所评论的不应该是一个问题,欢呼。