Skip to content

Commit cabfc81

Browse files
committed
FIX: Expand version comparison logic
1 parent 0ad47fe commit cabfc81

File tree

2 files changed

+44
-14
lines changed

2 files changed

+44
-14
lines changed

nibabel/pkg_info.py

+38-14
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@ def _cmp(a, b):
2222

2323

2424
def cmp_pkg_version(version_str, pkg_version_str=__version__):
25-
""" Compare `version_str` to current package version
25+
""" Compare ``version_str`` to current package version
2626
2727
To be valid, a version must have a numerical major version followed by a
2828
dot, followed by a numerical minor version. It may optionally be followed
2929
by a dot and a numerical micro version, and / or by an "extra" string.
30-
*Any* extra string labels the version as pre-release, so `1.2.0somestring`
31-
compares as prior to (pre-release for) `1.2.0`, where `somestring` can be
32-
any string.
30+
The extra string may further contain a "+". Any value to the left of a "+"
31+
labels the version as pre-release, while values to the right indicate a
32+
post-release relative to the values to the left. That is,
33+
``1.2.0+1`` is post-release for ``1.2.0``, while ``1.2.0rc1+1`` is
34+
post-release for ``1.2.0rc1`` and pre-release for ``1.2.0``.
35+
36+
This is an approximation of `PEP-440`_, and future versions will fully
37+
implement PEP-440.
3338
3439
Parameters
3540
----------
@@ -50,19 +55,38 @@ def cmp_pkg_version(version_str, pkg_version_str=__version__):
5055
1
5156
>>> cmp_pkg_version('1.2.0dev', '1.2.0')
5257
-1
58+
>>> cmp_pkg_version('1.2.0dev', '1.2.0rc1')
59+
-1
60+
>>> cmp_pkg_version('1.2.0rc1', '1.2.0')
61+
-1
62+
>>> cmp_pkg_version('1.2.0rc1+1', '1.2.0rc1')
63+
1
64+
>>> cmp_pkg_version('1.2.0rc1+1', '1.2.0')
65+
-1
66+
67+
.. _`PEP-440`: https://www.python.org/dev/peps/pep-0440/
5368
"""
5469
version, extra = _parse_version(version_str)
5570
pkg_version, pkg_extra = _parse_version(pkg_version_str)
56-
if version != pkg_version:
57-
return _cmp(StrictVersion(version), StrictVersion(pkg_version))
58-
if extra.startswith('+') or pkg_extra.startswith('+'):
59-
return (1 if pkg_extra == ''
60-
else -1 if extra == ''
61-
else _cmp(extra, pkg_extra))
62-
return (0 if extra == pkg_extra
63-
else 1 if extra == ''
64-
else -1 if pkg_extra == ''
65-
else _cmp(extra, pkg_extra))
71+
72+
# Normalize versions
73+
quick_check = _cmp(StrictVersion(version), StrictVersion(pkg_version))
74+
# Nothing further to check
75+
if quick_check != 0 or extra == pkg_extra == '':
76+
return quick_check
77+
78+
# Before + is pre-release, after + is additional increment
79+
pre, _, post = extra.partition('+')
80+
pkg_pre, _, pkg_post = pkg_extra.partition('+')
81+
quick_check = _cmp(pre, pkg_pre)
82+
if quick_check != 0: # Excludes case where pre and pkg_pre == ''
83+
# Pre-releases are ordered but strictly less than non-pre
84+
return (1 if pre == ''
85+
else -1 if pkg_pre == ''
86+
else quick_check)
87+
88+
# All else being equal, compare additional information lexically
89+
return _cmp(post, pkg_post)
6690

6791

6892
def pkg_commit_hash(pkg_path=None):

nibabel/tests/test_pkg_info.py

+6
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,14 @@ def test_cmp_pkg_version():
6363
('1.2.1rc', '1.2.1rc1', -1),
6464
('1.2.1b', '1.2.1a', 1),
6565
('1.2.1a', '1.2.1b', -1),
66+
('1.2.0+1', '1.2', 1),
67+
('1.2', '1.2.0+1', -1),
6668
('1.2.1+1', '1.2.1', 1),
6769
('1.2.1', '1.2.1+1', -1),
70+
('1.2.1rc1+1', '1.2.1', -1),
71+
('1.2.1', '1.2.1rc1+1', 1),
72+
('1.2.1rc1+1', '1.2.1+1', -1),
73+
('1.2.1+1', '1.2.1rc1+1', 1),
6874
):
6975
assert_equal(cmp_pkg_version(test_ver, pkg_ver), exp_out)
7076
assert_raises(ValueError, cmp_pkg_version, 'foo.2')

0 commit comments

Comments
 (0)