我正在尝试为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__
的价值而不必安装所有相关模块的最佳方法?
答案 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文字,你所评论的不应该是一个问题,欢呼。