pip安装包重复了

3 投票
3 回答
2670 浏览
提问于 2025-04-18 06:46

很遗憾,我无法重现这个问题,但我们已经遇到过几次:

pip安装了一个包两次。

如果你先卸载第一个,第二个就会显现出来,也可以被卸载。

我想问的是:怎么用Python检查一个包是否安装了两次?

背景:我想写一个测试来检查这个问题(开发运维)。

更新

  • 这些包是在一个虚拟环境中安装的。
  • 这两个包的版本不同。
  • 这不是手动解决的重复问题。我想找一个用Python代码检测这个的解决方案。如何解决这个问题不是我问题的一部分。

更新 2

命令 pip freeze 只输出包一次:

pip freeze | grep -i south
South==0.8.1

但在虚拟环境中,它实际上存在两次:

find lib -name top_level.txt |xargs cat | grep -i south
south
south

ls lib/python2.7/site-packages/| grep -i south
south
South-0.8.1-py2.7.egg
South-0.8.4-py2.7.egg-info

3 个回答

0

South-0.8.1-py2.7.egg 是一个压缩文件,里面包含了 South 的源代码,而 South-0.8.4-py2.7.egg-info 是一个文件夹,里面有关于 South 库的元数据文件。

.egg-info(对于从 .tar.gz 文件构建的库)或者 .dist-info(对于从 .whl 文件安装的库)会在每个通过 pip 安装的库中出现。

如果库的元数据中标记为 zip_safe(在 setup.py 中使用 setup(zip_safe=True)),那么就会创建 .egg 压缩文件。否则,pip 会创建一个文件夹,里面是解压后的 Python 源代码文件。

很早以前的 setuptools 版本可以安装同一个库的多个版本,并标记其中一个为 活跃,但如果我没记错的话,这个功能在很多年前就被取消了。

1

这个应该可以正常工作:

def count_installs(pkg_name):
    import imp, sys
    n = 0
    for location in sys.path:
        try:
            imp.find_module(pkg_name, [location])
        except ImportError: pass
        else: n += 1
    return n

比如说:

>>> count_installs("numpy")
2
>>> count_installs("numpyd")
0
>>> count_installs("sympy")
1
1

我用这个方法来检查一个包是否被安装了两次:

def test_pip_python_packages_installed_twice(self):
    # https://stackoverflow.com/a/23941861/633961
    pkg_name_to_locations=defaultdict(set)
    for dist in pkg_resources.working_set:
        for pkg_name in dist._get_metadata('top_level.txt'):
            for location in sys.path:
                try:
                    importutils.does_module_exist_at_given_path(pkg_name, [location])
                except ImportError:
                    continue
                if location.startswith('/usr'):
                    # ignore packages from "root" level.
                    continue
                pkg_name_to_locations[pkg_name].add(location)

    errors=dict()
    for pkg_name, locations in sorted(pkg_name_to_locations.items()):
        if pkg_name in ['_markerlib', 'pkg_resources', 'site', 'easy_install', 'setuptools', 'pip']:
            continue
        if len(locations)==1:
            continue
        errors[pkg_name]=locations
    self.assertFalse(errors, 
                     'Some modules are installed twice:\n%s' % '\n'.join(['%s: %s' % (key, value) for key, value in sorted(errors.items())]))

importutils

def does_module_exist_at_given_path(module_name, path):
    '''
    imp.find_module() does not find zipped eggs.
    Needed for check: check if a package is installed twice.
    '''
    for path_item in path:
        result=None
        try:
            result=imp.find_module(module_name, [path_item])
        except ImportError:
            pass

        if result:
            return bool(result)
        if not os.path.isfile(path_item):
            continue
        # could be a zipped egg
        module=zipimport.zipimporter(path_item).find_module(module_name)
        if module:
            return bool(module)
    raise ImportError(module_name)

相关内容:imp.find_module() 支持压缩包

撰写回答