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
Replace Non-Ascii Characters with a Single Space
What Is the Standard Way to Add N Seconds to Datetime.Time in Python
Append Multiple Values for One Key in a Dictionary
Method Resolution Order (Mro) in New-Style Classes
Unicodedecodeerror: 'Utf8' Codec Can't Decode Byte 0Xa5 in Position 0: Invalid Start Byte
How to Filter a Dictionary According to an Arbitrary Condition Function
How to Save a New Sheet in an Existing Excel File, Using Pandas
How to Jump to a Particular Line in a Huge Text File
How to Read a Text File into a List or an Array with Python
Python Re.Sub Group: Number After \Number
Plot a Horizontal Line on a Given Plot
Pythonic Way to Check If a List Is Sorted or Not
Elegant Python Code for Integer Partitioning
How to Have Clusters of Stacked Bars