【问题标题】:How can I find the module(s) provided by a given Python distribution?如何找到给定 Python 发行版提供的模块?
【发布时间】:2012-01-06 19:27:40
【问题描述】:

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

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

【问题讨论】:

  • 您是否反对在每个发行版中运行 python 脚本?
  • @GWW 我不太清楚你的意思,但我并不反对任何选择,真的。
  • 我不明白你的问题,如果你有 requirements.txt 那么这些是模块,你到底在找什么?事实上,如果它们将被安装和检查,那么您将使用 requirements.txt 的内容来做到这一点。
  • “发行版”在 requirements.txt 中指定,而不是模块。它们通常具有相同的名称,但有时却没有。见:guide.python-distribute.org/glossary.html

标签: python pip


【解决方案1】:

如果您的 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

【讨论】:

    【解决方案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 并继续前进。

    我不确定第三步是否可以通过其他更好的方式实现。此外,您仍然冒着丢失动态创建的模块或其他技巧的风险,但这应该会捕获大部分模块。

    编辑:

    这里有一些代码应该适用于除 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 有正确的想法。比我的更好的解决方案。

    【讨论】:

    • 我认为这几乎是我要走的路线。 1. 查找当前可用的模块。 2. 安装需要的包 3. 安装新包后查找可用的模块。
    猜你喜欢
    • 1970-01-01
    • 2012-09-06
    • 2020-07-13
    • 2015-09-24
    • 2010-12-30
    • 1970-01-01
    • 2015-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多