Python3(pip):查找哪个包提供了特定的模块 [英] Python3 (pip): find which package provides a particular module

查看:100
本文介绍了Python3(pip):查找哪个包提供了特定的模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不要感到困惑,关于安装包、如何导入生成的模块以及列出可用包的问题有很多.但似乎没有--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() 函数,看起来这会变得更容易:

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:

这篇关于Python3(pip):查找哪个包提供了特定的模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆