有没有一种方法可以通过编程确认python包版本满足需求说明符?

有没有一种方法可以通过编程确认python包版本满足需求说明符?,python,pip,python-packaging,requirements.txt,Python,Pip,Python Packaging,Requirements.txt,我试图找到是否有一种方法来获取已安装的包和版本,并检查它是否满足需求规范 例如,如果我有包pip==20.0.2,我希望程序执行以下操作: CheckReqSpec("pip==20.0.2", "pip>=19.0.0") -> True CheckReqSpec("pip==20.0.2", "pip<=20.1") -> True CheckReqSpec("pip==20.0.2", "pip~=20.0.0") -> True CheckReqS

我试图找到是否有一种方法来获取已安装的包和版本,并检查它是否满足需求规范

例如,如果我有包pip==20.0.2,我希望程序执行以下操作:

CheckReqSpec("pip==20.0.2", "pip>=19.0.0")  -> True
CheckReqSpec("pip==20.0.2", "pip<=20.1")    -> True
CheckReqSpec("pip==20.0.2", "pip~=20.0.0")  -> True
CheckReqSpec("pip==20.0.2", "pip>20.0.2")   -> False
>>> import packaging.requirements
>>> import packaging.version
>>> packaging.version.parse('20.0.2') in packaging.requirements.Requirement('pip>=19.0.0').specifier
True
>>> packaging.version.parse('20.0.2') in packaging.requirements.Requirement('pip~=20.0').specifier
True
>>> packaging.requirements.Requirement('pip==20.0.*').specifier.contains('20.0.2')
True
>>> packaging.requirements.Requirement('pip==20.0.*').specifier.contains('21')
False
>>> packaging.requirements.Requirement('PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1').specifier
<SpecifierSet('!=1.9.6,<1.6,<2.0a0,==2.4c1,>1.9')>
CheckReqSpec(“pip==20.0.2”,“pip>=19.0.0”)->True
CheckReqSpec(“pip==20.0.2”,“pip20.0.2”)->错误
我发现pkg_resources.extern.packaging有version.parse,这对于比较大于或小于的不同版本很有用,但是需求规范可能非常复杂,并且有一些像~=这样的运算符不是标准的数学运算符

setuptools文档有以下示例:

PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1
PickyThing1.9=1.9.6,=version.parse(“20.0.0”)#False
也许吧

来自打包导入版本
version.parse(“20.0.2”)>version.parse(“19.0.0”)#True
version.parse(“20.0.2”)=version.parse(“20.0.0”)#True
version.parse(“20.0.2”)>version.parse(“20.0.2”)#False

使用setuptools解析说明符集,然后使用中的
检查成员资格:

>>> from pkg_resources import Requirement
>>> req = Requirement.parse("pip~=20.0.0")
>>> pin = "pip==20.0.2"
>>> name, version = pin.split("==")
>>> name == req.name and version in req.specifier
True
发布后工作。必须明确选择预发布版本

>>> "20.0.0post1" in req.specifier
True
>>> req.specifier.contains("20.0.1b3")
False
>>> req.specifier.contains("20.0.1b3", prereleases=True)
True
我建议如下使用:

CheckReqSpec("pip==20.0.2", "pip>=19.0.0")  -> True
CheckReqSpec("pip==20.0.2", "pip<=20.1")    -> True
CheckReqSpec("pip==20.0.2", "pip~=20.0.0")  -> True
CheckReqSpec("pip==20.0.2", "pip>20.0.2")   -> False
>>> import packaging.requirements
>>> import packaging.version
>>> packaging.version.parse('20.0.2') in packaging.requirements.Requirement('pip>=19.0.0').specifier
True
>>> packaging.version.parse('20.0.2') in packaging.requirements.Requirement('pip~=20.0').specifier
True
>>> packaging.requirements.Requirement('pip==20.0.*').specifier.contains('20.0.2')
True
>>> packaging.requirements.Requirement('pip==20.0.*').specifier.contains('21')
False
>>> packaging.requirements.Requirement('PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1').specifier
<SpecifierSet('!=1.9.6,<1.6,<2.0a0,==2.4c1,>1.9')>
>>进口包装要求
>>>导入packaging.version
>>>packaging.version.parse('20.0.2')在packaging.requirements.Requirement('pip>=19.0.0')中。说明符
真的
>>>packaging.version.parse('20.0.2')在packaging.requirements.Requirement('pip~=20.0')中。说明符
真的
>>>包装。要求。要求('pip==20.0.*')。说明符。包含('20.0.2'))
真的
>>>包装。要求。要求('pip==20.0.*')。说明符。包含('21'))
假的

>>>包装.要求.要求('PickyThing1.9,!=1.9.6,是的,这是我提到的pkg_resources.extern.packaging版本-它适用于大多数比较,如,!=,等等,但它不处理~=。最好是内置一个特定的方法,因为我不确定所有可能的需求规范是什么…通过一些解析,你应该(理论上)这样做)如中所述,能够模拟
~=
。我刚刚添加了一个小编辑-需求规范中的*字符很难比较。version.parse有点奇怪:
version.parse(“20.0.*”)!=version.parse(“20.0.1”)
\True
version.parse(“20.0.”
#True
version.parse(“20.0.*”)>=version.parse(“20.0.0”)
#False,不幸的是,它是~=”的PEP440定义的一部分。这将很快变得笨拙。对于
“PickyThing1.9,!=1.9.6,哦,可能就是这样!我注意到它不像version.parse那样处理预发布版本/发布后版本,所以我可能只为*和~=。非常感谢!@FutureGadget发布后:它处理它们。无需更改。预发布:它处理它们,但默认情况下是不允许的(因为pip默认情况下不会使用它们)。如果您想包含预发布,可以使用
req.specifier.contains(v,prereleases=True)
。为了完整性,可能需要明确说明:1.导入包
pkg_资源
是分发包的一部分。2.在
pkg_资源
中提供的基础库(以及
设置工具
)是的。这实际上与我的答案是相同的方法:
pip
pkg_资源
供应商包装的
SpecifierSet
用于此功能。不同的是,安装工具通常应该已经在站点包中可用,因为它是随EnsureIP和venv一起安装的,但是
包装
would必须单独安装才能作为这样的顶级导入。如果单独安装,可能会得到更新的版本,因此不能保证获得与pip/setuptools实际使用的相同的代码(我想这是好是坏取决于用例)。@wim绝对,我对你的答案投了赞成票(和另一个一样)。我想只是一个稍微不同的方法。