# Version Number Comparison Function

Discussion in 'Python' started by Keith, Mar 25, 2005.

1. ### KeithGuest

Is there a function for comparing version numbers?

E.g.

0.1.0 < 0.1.2
1.876b < 1.876c
3.2.2 < 3.4

Keith

Keith, Mar 25, 2005

2. ### Christos TZOTZIOY GeorgiouGuest

On 25 Mar 2005 07:34:38 -0800, rumours say that "Keith"
<> might have written:

>Is there a function for comparing version numbers?
>
>E.g.
>
>0.1.0 < 0.1.2
>1.876b < 1.876c
>3.2.2 < 3.4
>
>Keith

Convert your version numbers into tuples:

(0, 1, 0) < (0, 1, 2)
(1, 876, 'b') < (1, 876, 'c')
(3, 2, 2) < (3, 4)

All of the above are True.
--
TZOTZIOY, I speak England very best.
"Be strict when sending and tolerant when receiving." (from RFC1958)
I really should keep that in mind when talking with people, actually...

Christos TZOTZIOY Georgiou, Mar 25, 2005

3. ### Bill MillGuest

On 25 Mar 2005 07:34:38 -0800, Keith <> wrote:
> Is there a function for comparing version numbers?
>
> E.g.
>
> 0.1.0 < 0.1.2
> 1.876b < 1.876c
> 3.2.2 < 3.4
>

Not by default AFAIK. How about something like (untested):

def test_version(v1, v2):
v1, v2 = v1.split('.'), v2.split('.')
for x, y in zip(v1, v2):
if x < y: return v1
if y > x: return v2

It assumes that v1 and v2 have the same amount of '.'s and that all of
the version numbers are of the same length (i.e. 1.1000 would be <
1.999). How general do you need to be?

Peace
Bill Mill
bill.mill at gmail.com

Bill Mill, Mar 25, 2005
4. ### Fredrik LundhGuest

"Keith" wrote:

> Is there a function for comparing version numbers?
>
> E.g.
>
> 0.1.0 < 0.1.2
> 1.876b < 1.876c
> 3.2.2 < 3.4

the following works for many common cases:

import re

def cmpver(a, b):
def fixup(i):
try:
return int(i)
except ValueError:
return i
a = map(fixup, re.findall("\d+|\w+", a))
b = map(fixup, re.findall("\d+|\w+", b))
return cmp(a, b) # -1 if a<b, 0 if a=b, 1 if a>b

>>> cmpver("0.1.0", "0.1.2")

-1
>>> cmpver("1.876b", "1.876c")

-1
>>> cmpver("3.2.2", "3.4")

-1

ymmv.

</F>

Fredrik Lundh, Mar 25, 2005
5. ### KeithGuest

I can't assume there are the same number of '.'s or there are the same
number of digits per version.

I don't know how the tuple comparison works offhand. But that seems
like it would work if you split it.

The suggestion with the "re" module seems generic enough and looks like
it will work as is.

Thanks.

Keith, Mar 25, 2005
6. ### Dan SommersGuest

On 25 Mar 2005 07:34:38 -0800,
"Keith" <> wrote:

> Is there a function for comparing version numbers?
> E.g.

> 0.1.0 < 0.1.2
> 1.876b < 1.876c
> 3.2.2 < 3.4

How about a simple string comparison?

Python 2.3.3 (#1, Mar 9 2004, 14:21:31)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1493)] on darwin
>>> '0.1.0' < '0.1.2'

True
>>> '1.876b' < '1.876c'

True
>>> '3.2.2' < '3.4'

True
>>>

Beyond that, there seems to be sufficient variation between version
number schemes, and something "interesting" often happens immediately
before the final version (e.g. "1.0rc4" becomes "1.0"), that you may
have to know something more about where you particular version numbers
come from.

Regards,
Dan

--
Dan Sommers
<http://www.tombstonezero.net/dan/>
Î¼â‚€ Ã— Îµâ‚€ Ã— cÂ² = 1

Dan Sommers, Mar 25, 2005
7. ### Mark RoweGuest

On Mar 26, 2005, at 3:34 AM, Keith wrote:

> Is there a function for comparing version numbers?
>
> E.g.
>
> 0.1.0 < 0.1.2
> 1.876b < 1.876c
> 3.2.2 < 3.4

FWIW,

>>> from distutils import version
>>> version_list = "3.4 3.2.2 1.867c 1.867b 0.1.2 0.1.0".split()
>>> version_list = map(version.LooseVersion, version_list)
>>> version_list.sort()
>>> print version_list

[LooseVersion ('0.1.0'), LooseVersion ('0.1.2'), LooseVersion
('1.867b'), LooseVersion ('1.867c'), LooseVersion ('3.2.2'),
LooseVersion ('3.4')]
>>> print ' < '.join(map(str, version_list))

0.1.0 < 0.1.2 < 1.867b < 1.867c < 3.2.2 < 3.4
>>>

It should be noted that distutils.version provides a StrictVersion
class that offers less flexible but more predictable ordering -- see
the module docstrings for more details.

Regards,

Mark Rowe
<http://bdash.net.nz/>

Mark Rowe, Mar 25, 2005
8. ### Robert KernGuest

[Pardon the piggybacking. My news-server does not see the OP's message.]

Fredrik Lundh wrote:
> "Keith" wrote:
>
>
>>Is there a function for comparing version numbers?
>>
>>E.g.
>>
>>0.1.0 < 0.1.2
>>1.876b < 1.876c
>>3.2.2 < 3.4

distutils has a set of version classes with comparisons.

In [1]:from distutils import version

In [2]:version?
Type: module
Base Class: <type 'module'>
String Form: <module 'distutils.version' from
'/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/distutils/version.pyc'>
Namespace: Interactive
File:
/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/distutils/version.py
Docstring:
Provides classes to represent module version numbers (one class for
each style of version numbering). There are currently two such classes
implemented: StrictVersion and LooseVersion.

Every version number class implements the following interface:
* the 'parse' method takes a string and parses it to some internal
representation; if the string is an invalid version number,
'parse' raises a ValueError exception
* the class constructor takes an optional string argument which,
if supplied, is passed to 'parse'
* __str__ reconstructs the string that was passed to 'parse' (or
an equivalent string -- ie. one that will generate an equivalent
version number instance)
* __repr__ generates Python code to recreate the version number
instance
* __cmp__ compares the current instance with either another instance
of the same class or a string (which will be parsed to an instance
of the same class, thus must follow the same rules)

--
Robert Kern

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter

Robert Kern, Mar 25, 2005
9. ### KeithGuest

distutils is one of the places I looked:
http://www.python.org/doc/2.3.5/lib/module-distutils.html

But I didn't see the functions documented. I am new to Python so I
didn't know where else to look.

Using distutils seems like it would be the most generic and supported
way to compare version numbers.

Keith, Mar 25, 2005
10. ### Robert KernGuest

Keith wrote:
> distutils is one of the places I looked:
> http://www.python.org/doc/2.3.5/lib/module-distutils.html
>
> But I didn't see the functions documented. I am new to Python so I
> didn't know where else to look.

The source! I don't think they're documented elsewhere.

> Using distutils seems like it would be the most generic and supported
> way to compare version numbers.

Indeed.

--
Robert Kern

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter

Robert Kern, Mar 25, 2005
11. ### Steve MGuest

I recently saw this:

http://www.egenix.com/files/python/mxTools.html

mx.Tools.verscmp(a,b)
Compares two version strings and returns a cmp() function
compatible value (<,==,> 0). The function is useful for sorting lists
containing version strings.

The logic used is as follows: the strings are compared at each
level, empty levels defaulting to '0', numbers with attached strings
(e.g. '1a1') compare less than numbers without attachement (e.g. '1a1'
< '1).

Keith wrote:
> Is there a function for comparing version numbers?
>
> E.g.
>
> 0.1.0 < 0.1.2
> 1.876b < 1.876c
> 3.2.2 < 3.4
>
> Keith

Steve M, Mar 25, 2005
12. ### Bengt RichterGuest

On Fri, 25 Mar 2005 17:02:31 +0100, "Fredrik Lundh" <> wrote:

>"Keith" wrote:
>
>> Is there a function for comparing version numbers?
>>
>> E.g.
>>
>> 0.1.0 < 0.1.2
>> 1.876b < 1.876c
>> 3.2.2 < 3.4

>
>the following works for many common cases:
>
>import re
>
>def cmpver(a, b):
> def fixup(i):
> try:
> return int(i)
> except ValueError:
> return i
> a = map(fixup, re.findall("\d+|\w+", a))
> b = map(fixup, re.findall("\d+|\w+", b))
> return cmp(a, b) # -1 if a<b, 0 if a=b, 1 if a>b

[OT] Visually, I like the nested def fixup, and I realize
that for cmpver execution overhead is not likely to be an issue,
but in general, what do you think of not being able
to write it that way if MAKE_FUNCTION overhead is unacceptable?

What if we had something like

@sticky('fixup') # evaluate binding only first time
def cmpver(a , b):
def fixup ... ?

Regards,
Bengt Richter

Bengt Richter, Mar 25, 2005
13. ### Christos TZOTZIOY GeorgiouGuest

Re: "static" variables in functions (was: Version Number Comparison Function)

On Fri, 25 Mar 2005 19:23:37 GMT, rumours say that (Bengt
Richter) might have written:

>On Fri, 25 Mar 2005 17:02:31 +0100, "Fredrik Lundh" <> wrote:
>
>>"Keith" wrote:
>>
>>> Is there a function for comparing version numbers?
>>>
>>> E.g.
>>>
>>> 0.1.0 < 0.1.2
>>> 1.876b < 1.876c
>>> 3.2.2 < 3.4

>>
>>the following works for many common cases:
>>
>>import re
>>
>>def cmpver(a, b):
>> def fixup(i):
>> try:
>> return int(i)
>> except ValueError:
>> return i
>> a = map(fixup, re.findall("\d+|\w+", a))
>> b = map(fixup, re.findall("\d+|\w+", b))
>> return cmp(a, b) # -1 if a<b, 0 if a=b, 1 if a>b

>
>[OT] Visually, I like the nested def fixup, and I realize
>that for cmpver execution overhead is not likely to be an issue,
>but in general, what do you think of not being able
>to write it that way if MAKE_FUNCTION overhead is unacceptable?
>
>What if we had something like
>
>@sticky('fixup') # evaluate binding only first time
>def cmpver(a , b):
> def fixup ... ?

One of the previous related threads is this (long URL):

--
TZOTZIOY, I speak England very best.
"Be strict when sending and tolerant when receiving." (from RFC1958)
I really should keep that in mind when talking with people, actually...

Christos TZOTZIOY Georgiou, Mar 28, 2005
14. ### El PitoneroGuest

Re: "static" variables in functions (was: Version Number Comparison Function)

Christos TZOTZIOY Georgiou wrote:
>
> One of the previous related threads is this (long URL):
>

Another previous message on this issue:

Python's syntax surely is not clean enough for concise metaprogramming.
At any rate, I'd agree with Fernando's assessment:

Fernando wrote:
> The real problem with Python is ... Python is
> going the C++ way: piling feature upon feature, adding bells
> and whistles while ignoring or damaging its core design.

If the core design were better, many "new features" in Python could
have been rendered unnecessary.

El Pitonero, Mar 29, 2005
15. ### Bengt RichterGuest

Re: "static" variables in functions (was: Version Number Comparison Function)

On 29 Mar 2005 00:29:06 -0800, "El Pitonero" <> wrote:

>Christos TZOTZIOY Georgiou wrote:
>>
>> One of the previous related threads is this (long URL):
>>

>
>Another previous message on this issue:
>
>
>Python's syntax surely is not clean enough for concise metaprogramming.
>At any rate, I'd agree with Fernando's assessment:
>
>Fernando wrote:
>> The real problem with Python is ... Python is
>> going the C++ way: piling feature upon feature, adding bells
>> and whistles while ignoring or damaging its core design.

>
>If the core design were better, many "new features" in Python could
>have been rendered unnecessary.
>

Do you have specific recommendations that might benefit python 3000?
What better "core design" features would have eliminated what "new features"?
;-)

Regards,
Bengt Richter

Bengt Richter, Mar 29, 2005