Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to programmatically confirm that a python package version satisfies a requirements specifier?

I am trying to find whether there is a way to take an installed package and version and check whether it satisfies a requirements spec.

For example, if I have the package pip==20.0.2, I want the program to do the following:

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

I found that pkg_resources.extern.packaging has version.parse, which is useful for comparing different versions greater than or less than, but requirement specs can be very complex, and there are operators like ~= that are not standard mathematical operators.

The setuptools docs has this example:

PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1

Is there an existing way to do this check, or an easy way to make my own?

edit: The ~= in particular is difficult, especially if the specs are input as a variable. * in the version requirement is also hard to figure out, since

 version.parse("20.0.*") == version.parse("20.0.1") # False
 version.parse("20.0.*") < version.parse("20.0.0")  # True 
 version.parse("20.0.*") < version.parse("20.1.1")  # True 
 version.parse("20.0.*") >= version.parse("20.0.0") # False
like image 967
FutureGadget Avatar asked Jan 26 '23 01:01

FutureGadget


1 Answers

Parse the specifier set using setuptools, and then check membership using in:

>>> 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

Post releases work. Pre-releases have to be opted in for explicitly.

>>> "20.0.0post1" in req.specifier
True
>>> req.specifier.contains("20.0.1b3")
False
>>> req.specifier.contains("20.0.1b3", prereleases=True)
True
like image 197
wim Avatar answered Jan 28 '23 12:01

wim