pkg_resources
, distributed with setuptools
, does what you need and handles situations where package.__version__
doesn't exist.
Here is how you'd require a minimal version of pypfopt==1.2.6
in your example:
python -c 'import pkg_resources; pkg_resources.require("pypfopt>=1.2.6")'
I don't have this package installed so I get:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "python3.8/site-packages/pkg_resources/__init__.py", line 884, in require
needed = self.resolve(parse_requirements(requirements))
File "python3.8/site-packages/pkg_resources/__init__.py", line 770, in resolve
raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'pypfopt>=1.2.6' distribution was not found
and is required by the application
caveat: I used it a lot until now that I have encountered a problem where the package in question has the right version, but its dependencies are not met, and so pkg_resources
reports a failure.
For example: I have pytorch_lightning==1.0.5
installed, but I installed a new version for one of its dependencies that it doesn't list as supported. I was expecting the following to pass, but it fails:
python -c 'import pkg_resources; pkg_resources.require("pytorch_lightning>=1.0.4")'
with:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "python3.8/site-packages/pkg_resources/__init__.py", line 884, in require
needed = self.resolve(parse_requirements(requirements))
File "python3.8/site-packages/pkg_resources/__init__.py", line 775, in resolve
raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.ContextualVersionConflict:
(torch 1.8.0.dev20201106+cu110 (python3.8/site-packages),
Requirement.parse('torch<1.8,>=1.3'), {'pytorch-lightning'})
which is the right thing to do if you want to ensure that not only the desired module is there and has the correct version, but that its dependencies are correct too.
So I'm signalling here, that pkg_resources
does more than comparing the version number of the installed package - it also checks its dependencies. Which may or may not meet your needs.
And here is the version that doesn't check whether the dependencies are OK. In it we use pkg_resources
to just get the package's version, and delegate the comparison to packaging
as described in various answers on SO:
import pkg_resources
from packaging import version
pkg = "pytorch_lightning"
min_ver = "1.0.4"
got_ver = pkg_resources.get_distribution("pytorch_lightning").version
if version.parse(got_ver) < version.parse(min_ver):
raise pkg_resources.VersionConflict(f"{pkg}>={min_ver} is needed, but found {pkg}=={got_ver}")
This time despite the dependencies being incorrect (in my example), it's sufficient that the version number is high enough, so the script can go ahead and use pytorch_lightning
(I validated that it works just fine with newer versions of its dependencies).