代码之家  ›  专栏  ›  技术社区  ›  vy32

对于使用modulefinder找到的模块,如何读取\版本?

  •  0
  • vy32  · 技术社区  · 7 年前

    ModuleFinder 获取在我的python程序中导入的所有模块的列表。我的一些模块 __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
    ...
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Martijn Pieters    7 年前

    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__ 属性可以扫描以查看堆栈上的值 正在存储:

    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
    
    推荐文章