如何阅读__version__ 使用模块查找器找到的模块?



我正在使用ModuleFinder来获取Python程序中导入的所有模块的列表。我的一些模块中有__version__号。如何读取__version__变量?

这是我的测试代码。它不起作用:

__version__ = "1.1.1"
from modulefinder import ModuleFinder
finder = ModuleFinder()
finder.run_script(__file__)
for name,mod in sorted(finder.modules.items()):
try:
ver = mod.__version__
except AttributeError as e:
ver = '--'
print(name, ver, mod.__file__)

输出如下所示:

$ python3 demo.py|head
__future__ -- /Users/simsong/anaconda3/lib/python3.6/__future__.py
__main__ -- demo.py
_ast -- None
_bisect -- /Users/simsong/anaconda3/lib/python3.6/lib-dynload/_bisect.cpython-36m-darwin.so
_blake2 -- /Users/simsong/anaconda3/lib/python3.6/lib-dynload/_blake2.cpython-36m-darwin.so
_bootlocale -- /Users/simsong/anaconda3/lib/python3.6/_bootlocale.py
_bz2 -- /Users/simsong/anaconda3/lib/python3.6/lib-dynload/_bz2.cpython-36m-darwin.so
_codecs -- None
_collections -- None
_collections_abc -- /Users/simsong/anaconda3/lib/python3.6/_collections_abc.py
...

mod不是常规的Python模块对象;它是modulefinder.Module类的实例。不过,它确实具有全局名称的映射,以名为globalnames的字典属性的形式。您可以通过检查映射来验证模块是否具有全局名称__version__

for name, mod in sorted(finder.modules.items()):
ver = mod.globalnames.get('__version__', '--')
print(name, ver, mod.__file__)

这将打印1;表示名称存在。这是因为实际模块没有加载,只分析字节码而不执行。

您要么必须实际导入模块,要么执行自己的字节码分析以获取全局名称的值Module类具有一个__code__属性,您可以扫描该属性以查看存储__version__时堆栈上的值:

import dis
def load_version_string(codeobj):
"""Returns the constant value loaded for the `__version__` global
Requires that `__version__` is set from a literal constant value.
"""
instructions = dis.get_instructions(codeobj)
for instr in instructions:
if instr.opname == 'LOAD_CONST':
nxtop = next(instructions, None)
if nxtop.opname == 'STORE_NAME' and nxtop.argval == '__version__':
return instr.argval

然后使用:

for name, mod in sorted(finder.modules.items()):
ver = '--'
if '__version__' in mod.globalnames:
ver = load_version_string(mod.__code__)
print(name, ver, mod.__file__)

现在,__main__的输出更改为显示版本号:

$ python3 demo.py | grep __main__
__main__ 1.1.1 demo.py

最新更新