如何找到给定Python发行版提供的模块?

时间:2012-01-06 19:27:40

标签: python pip

我需要构建一个由requirements.txt文件中指定的Python分发列表提供的模块列表。首先安装这些发行版,以便在本地进行检查。

看起来我应该能够使用pip.req.parse_requirements从需求文件中获取分发列表。从那里,我如何找到分发提供的模块的名称?

2 个答案:

答案 0 :(得分:3)

如果你的python版本是2.3 +

,你可以使用内置的pkgutil模块

例如,

import sys, pkgutil
mods = set()

#You may not need this part if you don't care about the builtin modules
print sys.builtin_module_names
for m in sys.builtin_module_names:
    if m != '__main__':
        mods.add(m)
        #mods.add(m)


for loader, name, ispkg in pkgutil.walk_packages():
    if name.find('.') == -1:
        mods.add(name)

print mods

答案 1 :(得分:2)

因为,就像你说的那样,发行版不是它们包含的模块,我们遇到了一个问题:发行版的典型安装过程 - 即afaik,包的集合以及安装程序 - 是下载,解压缩,然后运行setup.py,它处理安装过程的其余部分。

结果是,即使给出了Python发行版,你实际上无法告诉setup.py在没有运行它的情况下会做什么。可能存在约定,您可以提取大量信息并制定很多好的猜测,但运行“setup.py”文件实际上是查看它实际安装到站点包中的唯一方法。因此,parse_requirements或者任何pip内部实际上对你没有用,除非你只对发行版感兴趣。

所以,话虽如此,我认为管理问题的最佳方法是:

  1. 设置没有网站包的虚拟环境
  2. pip -r requirements.txt实际安装所有软件包
  3. 浏览sys.path,查找.py,.pyc以及__init__.py?个文件的子文件夹,以构建模块列表。
  4. 杀死那个virtualenv并继续前进。
  5. 第三步可能是其他更好的方式,我不确定。此外,您仍然存在丢失动态创建的模块或其他技巧的风险,但这应该捕获大多数模块。

    修改

    这里的一些代码应该适用于除zip文件之外的所有内容:

    import sys, os
    
    def walk_modules_os(root):
        def inner_walk(dir_path, mod_path):
            filelist = os.listdir(dir_path)
            pyfiles = set()
            dirs = []
            for name in filelist:
                if os.path.isdir(os.path.join(dir_path, name)):
                    dirs.append(name)
                else:
                    pre, ext = os.path.splitext(name)
                    if ext in ('.py', '.pyc', '.pyo'):
                        pyfiles.add(pre)
    
            if len(mod_path):
                if '__init__' not in pyfiles:
                    return
                pyfiles.remove('__init__')
                yield mod_path
    
            for pyfile in pyfiles:
                yield mod_path + (pyfile,)
    
            for directory in dirs:
                sub = os.path.join(dir_path, directory)
                for mod in inner_walk(sub, mod_path + (directory,)):
                    yield mod
    
        root = os.path.realpath(root)
        if not os.path.isdir(root):
            return iter([])
        return iter(inner_walk(root, tuple()))
    
    # you could collect as a set of tuples and do set subtraction, too
    for path in sys.path:
        for mod in walk_modules_os(path):
            print mod 
    

    编辑2:

    嗯,老鼠。 GWW有正确的想法。比我的解决方案要好得多。