Add comparision between VersionInfo objects
This commit is contained in:
parent
c679d138ab
commit
a69b632f65
161
semver.py
161
semver.py
@ -4,7 +4,6 @@ Python helper for Semantic Versioning (http://semver.org/)
|
||||
|
||||
import collections
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
__version__ = '2.7.6'
|
||||
@ -59,26 +58,59 @@ def parse(version):
|
||||
return version_parts
|
||||
|
||||
|
||||
VersionInfo = collections.namedtuple(
|
||||
'VersionInfo', 'major minor patch prerelease build')
|
||||
class VersionInfo(collections.namedtuple(
|
||||
'VersionInfo', 'major minor patch prerelease build')):
|
||||
"""
|
||||
:param int major: version when you make incompatible API changes.
|
||||
:param int minor: version when you add functionality in
|
||||
a backwards-compatible manner.
|
||||
:param int patch: version when you make backwards-compatible bug fixes.
|
||||
:param str prerelease: an optional prerelease string
|
||||
:param str build: an optional build string
|
||||
|
||||
# Only change it for Python > 3 as it is readonly
|
||||
# for version 2
|
||||
if sys.version_info >= (3, 5):
|
||||
VersionInfo.__doc__ = """
|
||||
:param int major: version when you make incompatible API changes.
|
||||
:param int minor: version when you add functionality in
|
||||
a backwards-compatible manner.
|
||||
:param int patch: version when you make backwards-compatible bug fixes.
|
||||
:param str prerelease: an optional prerelease string
|
||||
:param str build: an optional build string
|
||||
>>> import semver
|
||||
>>> ver = semver.parse('3.4.5-pre.2+build.4')
|
||||
>>> ver
|
||||
{'build': 'build.4', 'major': 3, 'minor': 4, 'patch': 5,
|
||||
'prerelease': 'pre.2'}
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
>>> import semver
|
||||
>>> ver = semver.parse('3.4.5-pre.2+build.4')
|
||||
>>> ver
|
||||
{'build': 'build.4', 'major': 3, 'minor': 4, 'patch': 5,
|
||||
'prerelease': 'pre.2'}
|
||||
"""
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, (VersionInfo, dict)):
|
||||
return NotImplemented
|
||||
return _compare_by_keys(self._asdict(), _to_dict(other)) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
if not isinstance(other, (VersionInfo, dict)):
|
||||
return NotImplemented
|
||||
return _compare_by_keys(self._asdict(), _to_dict(other)) != 0
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, (VersionInfo, dict)):
|
||||
return NotImplemented
|
||||
return _compare_by_keys(self._asdict(), _to_dict(other)) < 0
|
||||
|
||||
def __le__(self, other):
|
||||
if not isinstance(other, (VersionInfo, dict)):
|
||||
return NotImplemented
|
||||
return _compare_by_keys(self._asdict(), _to_dict(other)) <= 0
|
||||
|
||||
def __gt__(self, other):
|
||||
if not isinstance(other, (VersionInfo, dict)):
|
||||
return NotImplemented
|
||||
return _compare_by_keys(self._asdict(), _to_dict(other)) > 0
|
||||
|
||||
def __ge__(self, other):
|
||||
if not isinstance(other, (VersionInfo, dict)):
|
||||
return NotImplemented
|
||||
return _compare_by_keys(self._asdict(), _to_dict(other)) >= 0
|
||||
|
||||
|
||||
def _to_dict(obj):
|
||||
if isinstance(obj, VersionInfo):
|
||||
return obj._asdict()
|
||||
return obj
|
||||
|
||||
|
||||
def parse_version_info(version):
|
||||
@ -96,6 +128,52 @@ def parse_version_info(version):
|
||||
return version_info
|
||||
|
||||
|
||||
def _nat_cmp(a, b):
|
||||
def convert(text):
|
||||
return int(text) if re.match('[0-9]+', text) else text
|
||||
|
||||
def split_key(key):
|
||||
return [convert(c) for c in key.split('.')]
|
||||
|
||||
def cmp_prerelease_tag(a, b):
|
||||
if isinstance(a, int) and isinstance(b, int):
|
||||
return cmp(a, b)
|
||||
elif isinstance(a, int):
|
||||
return -1
|
||||
elif isinstance(b, int):
|
||||
return 1
|
||||
else:
|
||||
return cmp(a, b)
|
||||
|
||||
a, b = a or '', b or ''
|
||||
a_parts, b_parts = split_key(a), split_key(b)
|
||||
for sub_a, sub_b in zip(a_parts, b_parts):
|
||||
cmp_result = cmp_prerelease_tag(sub_a, sub_b)
|
||||
if cmp_result != 0:
|
||||
return cmp_result
|
||||
else:
|
||||
return cmp(len(a), len(b))
|
||||
|
||||
|
||||
def _compare_by_keys(d1, d2):
|
||||
for key in ['major', 'minor', 'patch']:
|
||||
v = cmp(d1.get(key), d2.get(key))
|
||||
if v:
|
||||
return v
|
||||
|
||||
rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
|
||||
rccmp = _nat_cmp(rc1, rc2)
|
||||
|
||||
if not rccmp:
|
||||
return 0
|
||||
if not rc1:
|
||||
return 1
|
||||
elif not rc2:
|
||||
return -1
|
||||
|
||||
return rccmp
|
||||
|
||||
|
||||
def compare(ver1, ver2):
|
||||
"""Compare two versions
|
||||
|
||||
@ -105,53 +183,10 @@ def compare(ver1, ver2):
|
||||
zero if ver1 == ver2 and strictly positive if ver1 > ver2
|
||||
:rtype: int
|
||||
"""
|
||||
def nat_cmp(a, b):
|
||||
def convert(text):
|
||||
return int(text) if re.match('[0-9]+', text) else text
|
||||
|
||||
def split_key(key):
|
||||
return [convert(c) for c in key.split('.')]
|
||||
|
||||
def cmp_prerelease_tag(a, b):
|
||||
if isinstance(a, int) and isinstance(b, int):
|
||||
return cmp(a, b)
|
||||
elif isinstance(a, int):
|
||||
return -1
|
||||
elif isinstance(b, int):
|
||||
return 1
|
||||
else:
|
||||
return cmp(a, b)
|
||||
|
||||
a, b = a or '', b or ''
|
||||
a_parts, b_parts = split_key(a), split_key(b)
|
||||
for sub_a, sub_b in zip(a_parts, b_parts):
|
||||
cmp_result = cmp_prerelease_tag(sub_a, sub_b)
|
||||
if cmp_result != 0:
|
||||
return cmp_result
|
||||
else:
|
||||
return cmp(len(a), len(b))
|
||||
|
||||
def compare_by_keys(d1, d2):
|
||||
for key in ['major', 'minor', 'patch']:
|
||||
v = cmp(d1.get(key), d2.get(key))
|
||||
if v:
|
||||
return v
|
||||
|
||||
rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
|
||||
rccmp = nat_cmp(rc1, rc2)
|
||||
|
||||
if not rccmp:
|
||||
return 0
|
||||
if not rc1:
|
||||
return 1
|
||||
elif not rc2:
|
||||
return -1
|
||||
|
||||
return rccmp
|
||||
|
||||
v1, v2 = parse(ver1), parse(ver2)
|
||||
|
||||
return compare_by_keys(v1, v2)
|
||||
return _compare_by_keys(v1, v2)
|
||||
|
||||
|
||||
def match(version, match_expr):
|
||||
|
61
tests.py
61
tests.py
@ -11,6 +11,7 @@ from semver import bump_prerelease
|
||||
from semver import bump_build
|
||||
from semver import min_ver
|
||||
from semver import max_ver
|
||||
from semver import VersionInfo
|
||||
|
||||
|
||||
SEMVERFUNCS = [
|
||||
@ -270,3 +271,63 @@ def test_should_bump_build():
|
||||
assert bump_build('3.4.5-rc.1+0009.dev') == '3.4.5-rc.1+0010.dev'
|
||||
assert bump_build('3.4.5-rc.1') == '3.4.5-rc.1+build.1'
|
||||
assert bump_build('3.4.5') == '3.4.5+build.1'
|
||||
|
||||
|
||||
def test_should_compare_version_info_objects():
|
||||
v1 = VersionInfo(major=0, minor=10, patch=4, prerelease=None, build=None)
|
||||
v2 = VersionInfo(
|
||||
major=0, minor=10, patch=4, prerelease='beta.1', build=None)
|
||||
|
||||
# use `not` to enforce using comparision operators
|
||||
assert v1 != v2
|
||||
assert v1 > v2
|
||||
assert v1 >= v2
|
||||
assert not(v1 < v2)
|
||||
assert not(v1 <= v2)
|
||||
assert not(v1 == v2)
|
||||
|
||||
v3 = VersionInfo(major=0, minor=10, patch=4, prerelease=None, build=None)
|
||||
|
||||
assert not(v1 != v3)
|
||||
assert not(v1 > v3)
|
||||
assert v1 >= v3
|
||||
assert not(v1 < v3)
|
||||
assert v1 <= v3
|
||||
assert v1 == v3
|
||||
|
||||
v4 = VersionInfo(major=0, minor=10, patch=5, prerelease=None, build=None)
|
||||
assert v1 != v4
|
||||
assert not(v1 > v4)
|
||||
assert not(v1 >= v4)
|
||||
assert v1 < v4
|
||||
assert v1 <= v4
|
||||
assert not(v1 == v4)
|
||||
|
||||
|
||||
def test_should_compare_version_dictionaries():
|
||||
v1 = VersionInfo(major=0, minor=10, patch=4, prerelease=None, build=None)
|
||||
v2 = dict(major=0, minor=10, patch=4, prerelease='beta.1', build=None)
|
||||
|
||||
assert v1 != v2
|
||||
assert v1 > v2
|
||||
assert v1 >= v2
|
||||
assert not(v1 < v2)
|
||||
assert not(v1 <= v2)
|
||||
assert not(v1 == v2)
|
||||
|
||||
v3 = dict(major=0, minor=10, patch=4, prerelease=None, build=None)
|
||||
|
||||
assert not(v1 != v3)
|
||||
assert not(v1 > v3)
|
||||
assert v1 >= v3
|
||||
assert not(v1 < v3)
|
||||
assert v1 <= v3
|
||||
assert v1 == v3
|
||||
|
||||
v4 = dict(major=0, minor=10, patch=5, prerelease=None, build=None)
|
||||
assert v1 != v4
|
||||
assert not(v1 > v4)
|
||||
assert not(v1 >= v4)
|
||||
assert v1 < v4
|
||||
assert v1 <= v4
|
||||
assert not(v1 == v4)
|
||||
|
Loading…
x
Reference in New Issue
Block a user