Python3(pip):查找哪个包提供了特定的模块 [英] Python3 (pip): find which package provides a particular module
问题描述
不要感到困惑,关于安装包、如何导入生成的模块以及列出可用包的问题有很多.但似乎没有--what-provides"的等价物.pip 选项,如果您没有 requirements.txt 或 pipenv.这个问题与上一个问题类似,但要求提供父包,而不是额外的元数据.也就是说,这些其他问题没有得到很多关注或许多公认的答案 - 例如.如何找到python包给定模块的元数据信息.如此奋进……
举例来说,有两个包(仅举几例)将安装名为serial"的模块.- 即pyserial"和串行".因此,假设安装了其中一个软件包,我们可能会使用 pip list 找到它:
python3 -m pip list |序列号
然而,如果包的名称与模块的名称不匹配,或者如果您只想找出要安装的包,在旧服务器或开发机器上工作,就会出现问题.
您可以检查导入模块的路径 - 这可以为您提供线索.但是继续这个例子...
<预><代码>>>>导入序列>>>打印(串行.__文件__)/usr/lib/python3.6/site-packages/serial/__init__.py它在一个系列"中目录,但实际上只安装了pyserial,而不是serial:
<代码>>python3 -m pip 列表 |序列号pyserial 3.4
我最接近的是通过pipreqs ./"生成一个requirements.txt;这可能会在依赖子文件上失败(就像我一样),或者通过 pipenv 反向检查依赖项(这会带来一整套新问题以完成所有设置):
<代码>>pipenv 图 --reversecymysql==0.9.15FTP工具==0.7.1网面==0.10.9pip==20.2.2PyQt5-sip==12.8.1- PyQt5==5.15.0 [要求:PyQt5-sip>=12.8,<13]设置工具==50.3.0轮==0.35.1
有谁知道我错过了一个简单的解决方案来找到哪个 pip 包提供特定模块的命令?
我相信以下内容应该可以工作:
#!/usr/bin/env python3导入 importlib.util导入路径库导入 importlib_metadatadef get_distribution(file_name):结果 = 无在 importlib_metadata.distributions() 中分发:尝试:相对 = (pathlib.Path(file_name).relative_to(distribution.locate_file('')))除了值错误:经过别的:如果 distribution.files 和相对在 distribution.files 中:结果 = 分布休息返回结果定义阿尔法():file_name = importlib.util.find_spec('serial').origin分布 = get_distribution(file_name)打印(alpha",distribution.metadata['Name'])def Bravo():导入序列file_name = serial.__file__分布 = get_distribution(file_name)打印(bravo",distribution.metadata['Name'])如果 __name__ == '__main__':α()布拉沃()
这只是一个代码示例,展示了如何获取特定模块所属的已安装项目的元数据.
重要的是 get_distribution
函数,它以文件名作为参数.它可以是模块或包数据的文件名.如果该文件名属于环境中安装的项目(例如通过 pip install
),则 importlib.metadata.Distribution
对象被返回.
更新(2021 年 2 月):
由于 importlib_metadata
中新添加的 packages_distributions()
函数,看起来这会变得更容易:
- https://importlib-metadata.readthedocs.io/en/stable/using.html#package-distributions
- https://github.com/python/importlib_metadata/pull/287/files
Without getting confused, there are tons of questions about installing packages, how to import the resulting modules, and listing what packages are available. But there doesn't seem to be the equivalent of a "--what-provides" option for pip, if you don't have a requirements.txt or pipenv. This question is similar to a previous question, but asks for the parent package, and not additional metadata. That said, these other questions did not get a lot of attention or many accepted answers - eg. How do you find python package metadata information given a module. So forging ahead... .
By way of example, there are two packages (to name a few) that will install a module called "serial" - namely "pyserial" and "serial". So assuming that one of the packages was installed, we might find it by using pip list:
python3 -m pip list | grep serial
However, the problem comes in if the name of the package does not match the name of the module, or if you just want to find out what package to install, working on a legacy server or dev machine.
You can check the path of the imported module - which can give you a clue. But continuing the example...
>>> import serial
>>> print(serial.__file__)
/usr/lib/python3.6/site-packages/serial/__init__.py
It is in a "serial" directory, but only pyserial is in fact installed, not serial:
> python3 -m pip list | grep serial
pyserial 3.4
The closest I can come is to generate a requirements.txt via "pipreqs ./" which may fail on a dependent child file (as it does with me), or to reverse check dependencies via pipenv (which brings a whole set of new issues along to get it all setup):
> pipenv graph --reverse
cymysql==0.9.15
ftptool==0.7.1
netifaces==0.10.9
pip==20.2.2
PyQt5-sip==12.8.1
- PyQt5==5.15.0 [requires: PyQt5-sip>=12.8,<13]
setuptools==50.3.0
wheel==0.35.1
Does anyone know of a command that I have missed for a simple solution to finding what pip package provides a particular module?
I believe something like the following should work:
#!/usr/bin/env python3
import importlib.util
import pathlib
import importlib_metadata
def get_distribution(file_name):
result = None
for distribution in importlib_metadata.distributions():
try:
relative = (
pathlib.Path(file_name)
.relative_to(distribution.locate_file(''))
)
except ValueError:
pass
else:
if distribution.files and relative in distribution.files:
result = distribution
break
return result
def alpha():
file_name = importlib.util.find_spec('serial').origin
distribution = get_distribution(file_name)
print("alpha", distribution.metadata['Name'])
def bravo():
import serial
file_name = serial.__file__
distribution = get_distribution(file_name)
print("bravo", distribution.metadata['Name'])
if __name__ == '__main__':
alpha()
bravo()
This is just an example of code showing how to get the metadata of the installed project a specific module belongs to.
The important bit is the get_distribution
function, it takes a file name as an argument. It could be the file name of a module or package data. If that file name belongs to a project installed in the environment (via pip install
for example) then the importlib.metadata.Distribution
object is returned.
Update (February 2021):
Looks like this could become easier thanks to the newly added packages_distributions()
function in importlib_metadata
:
- https://importlib-metadata.readthedocs.io/en/stable/using.html#package-distributions
- https://github.com/python/importlib_metadata/pull/287/files
这篇关于Python3(pip):查找哪个包提供了特定的模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!