Version Number Comparison Function

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

  1. Keith

    Keith Guest

    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
    #1
    1. Advertising

  2. 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
    #2
    1. Advertising

  3. Keith

    Bill Mill Guest

    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
    #3
  4. "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
    #4
  5. Keith

    Keith Guest

    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
    #5
  6. Keith

    Dan Sommers Guest

    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
    Type "help", "copyright", "credits" or "license" for more information.
    >>> '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
    #6
  7. Keith

    Mark Rowe Guest

    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
    #7
  8. Keith

    Robert Kern Guest

    [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
    #8
  9. Keith

    Keith Guest

    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
    #9
  10. Keith

    Robert Kern Guest

    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
    #10
  11. Keith

    Steve M Guest

    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
    #11
  12. 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
    #12
  13. 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):

    http://groups-beta.google.com/group...4&mode=thread&noheader=1#doc_7599103bb19c7332
    --
    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
    #13
  14. Keith

    El Pitonero Guest

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

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

    http://groups-beta.google.com/group...4&mode=thread&noheader=1#doc_7599103bb19c7332

    Another previous message on this issue:

    http://groups-beta.google.com/group/comp.lang.lisp/msg/1615d8b83cca5b20

    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
    #14
  15. 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):
    >>

    >http://groups-beta.google.com/group...4&mode=thread&noheader=1#doc_7599103bb19c7332
    >
    >Another previous message on this issue:
    >
    >http://groups-beta.google.com/group/comp.lang.lisp/msg/1615d8b83cca5b20
    >
    >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
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. V Green
    Replies:
    0
    Views:
    840
    V Green
    Feb 5, 2008
  2. PA Bear [MS MVP]
    Replies:
    0
    Views:
    952
    PA Bear [MS MVP]
    Feb 5, 2008
  3. MowGreen [MVP]
    Replies:
    5
    Views:
    2,014
    PA Bear [MS MVP]
    Feb 9, 2008
  4. Une bévue
    Replies:
    2
    Views:
    169
    Une bévue
    Sep 19, 2006
  5. Deepu
    Replies:
    1
    Views:
    236
    ccc31807
    Feb 7, 2011
Loading...

Share This Page