pip安装包重复了
很遗憾,我无法重现这个问题,但我们已经遇到过几次:
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)