首页 > 解决方案 > 两个pip安装的模块同名,如何选择加载哪一个?

问题描述

我正在编写一个依赖于特定模块的 python程序rtmidi, . 问题是,PyPI 中至少有两个不同的包有一个名为rtmidipython-rtmidi的模块。它们提供几乎相同的功能,但语法不同。

当只安装“正确”的包时,一切正常。但是如果两个软件包都安装了,使用import rtmidi加载“错误”模块并且我的程序崩溃。让它再次工作的唯一方法是卸载这两个软件包,然后重新安装正确的软件包。当然,由于用户可能依赖其他模块来执行其他程序,我不能指望他们这样做。

尝试rtmidi.__name__用两个包来识别模块会得到相同的结果。

所以我的问题是,我该如何解决这个名称冲突问题?是否有最佳实践方法来处理此问题?

标签: pythonpippython-modulepypi

解决方案


您不能同时安装它们(如果依赖默认pip行为)。在这里,我将使用几个简单的纯 Python 包进行演示,它们存在导入名称冲突:coverallspython-coveralls.

# in a fresh environment
pip install python-coveralls
python -c "import coveralls; print(dir(coveralls)); print(coveralls.__file__)"
# ['__author__', '__builtins__', '__cached__', '__classifiers__', '__copyright__', 
# '__doc__', '__docformat__', '__file__', '__license__', '__loader__', '__name__', 
# '__package__', '__path__', '__spec__', '__version__', 'parse_args', 'wear']
# /path/to/lib/python3.8/site-packages/coveralls/__init__.py

这些是 的内容python-coveralls。请注意,实际__init__.py文件位于site-packages/coveralls/目录中。

pip install coveralls
python -c "import coveralls; print(dir(coveralls)); print(coveralls.__file__)"
# ['Coveralls', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', 
# '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 
# 'api', 'exception', 'git', 'reporter', 'version']
# /path/to/lib/python3.8/site-packages/coveralls/__init__.py

这些是 的内容coverallspython-coveralls已被覆盖。请注意,这是同一个文件。旧时__init__.py的任何东西都没有了。

pip uninstall coveralls
python -c "import coveralls; print(dir(coveralls)); print(coveralls.__file__)"
# ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', 
# '__spec__']
# None

那里仍然有包的幽灵,但它的内容已经消失(所有包内部都有的东西除外)。请注意,文件现在是None:此包没有__init__.py文件。

您可以通过运行pip uninstall python-coveralls然后重新安装任何您想要的来解除您的环境。

解决方案

确实必须要求您的用户只使用您要求中的包,但这就是我们使用虚拟环境的原因。或者,想要直接使用其他包的用户可以使用--target选项pip更改安装位置(以及加载时使用的名称) (但这不会帮助使用其他库的其他应用程序)。

在实践中,最好将此视为安装过程的一部分。您需要 (a) 告诉您的用户他们需要安装什么要求;或 (b) 有一些自动化流程来获得正确的要求。

我会说最佳做法是(b)。一种常见的方法是使用setuptools, 并定义函数的install_requires参数setup。这指的是 PyPI 上的包名称,而不是导入名称。setuptools 快速入门是一个很好的起点。


推荐阅读