Python Forum

Full Version: Python 2.7 LooseVersion version comparison unexpectedly fails
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello all,

I have written some tests for LooseVersion from which some seem to be failing unexpectedly.

Code:
from distutils.version import LooseVersion

failed_tests = []

# the tests at hand: the bool at the end is the expected result
# 3   <  3.0: False
# 3   == 3.0: True
# 3   >= 3.0: True
# 3.0 <= 3  : True
# 3.0 == 3  : True
# 3.0 >  3  : False

# must invert the boolean logic with not for the tests in the middle...
if     (LooseVersion('3')   <  LooseVersion('3.0')):
    failed_tests.append(('3 < 3.0', False))
if not (LooseVersion('3')   == LooseVersion('3.0')):
    failed_tests.append(('3 == 3.0', True))
if not (LooseVersion('3')   >= LooseVersion('3.0')):
    failed_tests.append(('3 >= 3.0', True))
if not (LooseVersion('3.0') <= LooseVersion('3')):
    failed_tests.append(('3.0 <= 3', True))
if not (LooseVersion('3.0') == LooseVersion('3')):
    failed_tests.append(('3.0 == 3', True))
if     (LooseVersion('3.0') >  LooseVersion('3')):
    failed_tests.append(('3.0 > 3', False))

if failed_tests:
    print
    print 'Failed tests: ' + str(len(failed_tests))
    for test_string, expected_result in failed_tests:
        print test_string + ': ' + str(expected_result)
    print
    raise ValueError('Some tests failed!')
The above tests should not be failing, but they do:
Error:
12:43:59 [INF][ print]: Failed tests: 6 12:43:59 [INF][ print]: 3 < 3.0: False 12:43:59 [INF][ print]: 3 == 3.0: True 12:43:59 [INF][ print]: 3 >= 3.0: True 12:43:59 [INF][ print]: 3.0 <= 3: True 12:43:59 [INF][ print]: 3.0 == 3: True 12:43:59 [INF][ print]: 3.0 > 3: False
Why is this happening and how do you fix this? Is this a bug? Are my tests bugged?

I really stared at the code for some time, but I cannot find the reason.

See https://github.com/python/cpython/blob/m...version.py for how the regex etc. looks like.

I also tried StrictVersion, which fails with:

Error:
13:03:26 [ERR][ python]: File "C:\Users\Kawu\AppData\Roaming\MySQL\Workbench\modules\jpa_export_plugin_grt.py", line 267, in export_jpa_annotated_classes 13:03:26 [ERR][ python]: if (StrictVersion('3') < StrictVersion('3.0')): 13:03:26 [ERR][ python]: File "C:\Program Files\MySQL\MySQL Workbench 8.0 CE\Python\Lib\distutils\version.py", line 40, in __init__ 13:03:26 [ERR][ python]: self.parse(vstring) 13:03:26 [ERR][ python]: File "C:\Program Files\MySQL\MySQL Workbench 8.0 CE\Python\Lib\distutils\version.py", line 107, in parse 13:03:26 [ERR][ python]: raise ValueError, "invalid version number '%s'" % vstring 13:03:26 [ERR][ python]: ValueError: invalid version number '3'
StrictVersion considers simple numbers as invalid, so I cannot go with StrictVersion anyway, because I need to compare version numbers without minor/sub numbers.

Can anyone help me please?

Kawu
Remember that a floating point number is made up of an exponent and mantissa, therefore is an approximation of the integer value. In addition, those numbers are represented as base 2 in hardware as sum of 10's, 100's, 1000's, etc.

from docs: https://docs.python.org/3/tutorial/floatingpoint.html
Quote:Unfortunately, most decimal fractions cannot be represented exactly as binary fractions. A consequence is that, in general, the decimal floating-point numbers you enter are only approximated by the binary floating-point numbers actually stored in the machine.

The difference may be miniscule, but it's still there.
I don't think there is anything mysterious here, considering the instances' data
>>> a, b = LooseVersion('3'), LooseVersion('3.0')
>>> a.__dict__
{'version': [3], 'vstring': '3'}
>>> b.__dict__
{'version': [3, 0], 'vstring': '3.0'}
>>> [3] < [3, 0]
True
Hmmm. I understand the problem now.

Thanks.

But I wonder:

Does it make sense for an out-of-the-box version comparison facility to define that

[3] < [3, 0] < [3, 0, 0] < [3, 0, 0, 0] ...

?

Karsten
current version of python is 3.7.1. 2.7 is rapidly approaching EOL, just over a year left.
Thanks for the info.

I cannot upgrade Python on my own. I am solely using Python for my MySQL Workbench project. That software comes with an interpreter of their choice.

I will be asking them about a Python 3 upgrade.

Thanks for helping.

Karsten