How to Compare Version Numbers in Python

How do I compare version numbers in Python?

Use packaging.version.parse.

>>> # pip install packaging
>>> from packaging import version
>>> version.parse("2.3.1") < version.parse("10.1.2")
True
>>> version.parse("1.3.a4") < version.parse("10.1.2")
True
>>> isinstance(version.parse("1.3.a4"), version.Version)
True
>>> isinstance(version.parse("1.3.xy123"), version.LegacyVersion)
True
>>> version.Version("1.3.xy123")
Traceback (most recent call last):
...
packaging.version.InvalidVersion: Invalid version: '1.3.xy123'

packaging.version.parse is a third-party utility but is used by setuptools (so you probably already have it installed) and is conformant to the current PEP 440; it will return a packaging.version.Version if the version is compliant and a packaging.version.LegacyVersion if not. The latter will always sort before valid versions.

Note: packaging has recently been vendored into setuptools.


An ancient and now deprecated method you might encounter is distutils.version, it's undocumented and conforms only to the superseded PEP 386;

>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion("2.3.1") < LooseVersion("10.1.2")
True
>>> StrictVersion("2.3.1") < StrictVersion("10.1.2")
True
>>> StrictVersion("1.3.a4")
Traceback (most recent call last):
...
ValueError: invalid version number '1.3.a4'

As you can see it sees valid PEP 440 versions as “not strict” and therefore doesn’t match modern Python’s notion of what a valid version is.

As distutils.version is undocumented, here are the relevant docstrings.

Version number comparison in Python

Remove the uninteresting part of the string (trailing zeroes and dots), and then compare the lists of numbers.

import re

def mycmp(version1, version2):
def normalize(v):
return [int(x) for x in re.sub(r'(\.0+)*$','', v).split(".")]
return cmp(normalize(version1), normalize(version2))

This is the same approach as Pär Wieslander, but a bit more compact:

Here are some tests, thanks to "How to compare two strings in dot separated version format in Bash?":

assert mycmp("1", "1") == 0
assert mycmp("2.1", "2.2") < 0
assert mycmp("3.0.4.10", "3.0.4.2") > 0
assert mycmp("4.08", "4.08.01") < 0
assert mycmp("3.2.1.9.8144", "3.2") > 0
assert mycmp("3.2", "3.2.1.9.8144") < 0
assert mycmp("1.2", "2.1") < 0
assert mycmp("2.1", "1.2") > 0
assert mycmp("5.6.7", "5.6.7") == 0
assert mycmp("1.01.1", "1.1.1") == 0
assert mycmp("1.1.1", "1.01.1") == 0
assert mycmp("1", "1.0") == 0
assert mycmp("1.0", "1") == 0
assert mycmp("1.0", "1.0.1") < 0
assert mycmp("1.0.1", "1.0") > 0
assert mycmp("1.0.2.0", "1.0.2") == 0

Python version number comparison with != (not equal)

If your end goal is just to compare version compatibility against a PEP 440 version specifier, it looks like packaging.specifiers already supports this:

>>> from packaging.specifiers import SpecifierSet
>>> vspec = SpecifierSet(">=11.3,!=11.3.2")
>>> "11.3.1" in vspec
True
>>> "11.3.2" in vspec
False
>>>

The specifiers.py source may be helpful if you are really going for your own implementation. Looks like the general approach is to regex-match each operator, mapping them to appropriate Specifier methods where the comparison is deferred to the Version operators after any special handling (e.g., _compare_equal() handles the ".*" case you asked about).

Version number comparison

Try this

def compare_versions_greater_than(v1, v2):
for i, j in zip(map(int, v1.split(".")), map(int, v2.split("."))):
if i == j:
continue
return i > j
return len(v1.split(".")) > len(v2.split("."))

a = "2.0.3"
b = "2.1"
print(compare_versions_greater_than(a, b))
print(compare_versions_greater_than(b, a))

Output

False
True

Python compare version numbers with dynamic comparison specifier

Instead of creating a dictionary with all possible comparisons for the versions, you can just create a lookup for the used operators, e.g:

import operator as op
from distutils.version import LooseVersion

lookup = {'<': op.lt, '<=': op.le, '==': op.eq, '>=': op.ge, '>': op.gt}

def check_versions(ver1, specifier, ver2):
try:
return lookup[specifier](LooseVersion(ver1), LooseVersion(ver2))
except KeyError:
# unknown specifier
return False

python: dot separated versions comparizon

You can borrow the code that distutils and its successors use to compare version numbers

from distutils.version import StrictVersion # Or LooseVersion, if you prefer

if StrictVersion('10.2.3') > StrictVersion('10.2'):
print "10.2.3 is newer"

Compare two version numbers (true if different minor version)

awk may help for this case. Here's a simple script to do that,

#!/bin/bash

old_version="$1"
new_version="$2"

awk -v u=${old_version} -v v=${new_version} '
BEGIN{
split(u,a,".");
split(v,b,".");
printf "old:%s new:%s => ",u,v;
for(i=1;i<=2;i++) if(b[i]!=a[i]){print "true";exit}
print "false"
}'

The script would only compare major and minor version number, return false if they're matched, else return true.



Related Topics



Leave a reply



Submit