3

I need to ensure that one of the imported packages is at least v1.2.6. All the questions I have seen on here check the version of Python running. I would like to check the version of the module.

My current solution is messy. There must be a pythonic solution to this.

import pypfopt
ver = pypfopt.__version__

major, minor, iter = ver.split('.')

major = int(major)
minor = int(minor)
iter  = int(iter)

if major < 1:
    logger.error("major version less than 1")

if minor < 2:
    logger.error("minor version less than 2")

if iter < 6:
    logger.error("iter version less than 6")

Possible duplicate:

While there are similar questions on SO, 1, 2, 3, these are addressing how to get and print the result from module.__version__, which I am already doing.

My question, is whether there is a clean, pythonic way to check that version number against the minimum version number. eg:

if pypfopt.__version__ < 1.2.6:
    logger.error("Version is too low. Update")

but __version__ returns a string, and since there are two decimals (1.2.6) it can't be converted to a float, and then compared. Currently, I am converting each individual number to an int, and then doing comparisons.

  • There's no way a solution this messy is the right way to do it.
  • I'm using 10 lines to compare two numbers.
John Mansell
  • 624
  • 5
  • 16
  • I believe this kind of thing would usually be dealt with at install-time. How are you distributing the module? – AMC Oct 02 '20 at 00:07
  • Normally I would. We had an older version running on most of our machines, and I want to make sure that before any of them start running the script, they've updated to the latest version since we need a bug fix that came out with 1.2.6 – John Mansell Oct 02 '20 at 00:15
  • Does this answer your question? [How to check version of python modules?](https://stackoverflow.com/questions/20180543/how-to-check-version-of-python-modules) – AMC Oct 02 '20 at 01:02
  • @AMC, Not quite. I am able to get a string of the version "1.2.6" but converting each part to an int, and then checking it against the minimum version seems convoluted. Seems like there is probably a pythonic way that I'm not aware of. – John Mansell Oct 02 '20 at 01:45
  • 2
    I think this is what you're looking for: https://stackoverflow.com/questions/11887762/how-do-i-compare-version-numbers-in-python – AMC Oct 02 '20 at 02:03

2 Answers2

4

You can use packaging module. Install it with pip install packaging and then:

from packaging import version

import pypfopt


ver = pypfopt.__version__

if version.parse(ver) < version.parse('1.2.6'):
    logger.error('Version is too low. Update')
Fedor Soldatkin
  • 1,133
  • 8
  • 23
2

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.5installed, 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).

stason
  • 5,409
  • 4
  • 34
  • 48