fix parse_version, add tests, fixes #2556

This commit is contained in:
Thomas Waldmann 2017-06-06 00:42:12 +02:00
parent 68b61acffd
commit a7e8e8ccd9
2 changed files with 58 additions and 20 deletions

View File

@ -0,0 +1,38 @@
import pytest
from ..version import parse_version
@pytest.mark.parametrize("version_str, version_tuple", [
# setuptools < 8.0 uses "-"
('1.0.0a1.dev204-g8866961.d20170606', (1, 0, 0, -4, 1)),
('1.0.0a1.dev204-g8866961', (1, 0, 0, -4, 1)),
('1.0.0-d20170606', (1, 0, 0, -1)),
# setuptools >= 8.0 uses "+"
('1.0.0a1.dev204+g8866961.d20170606', (1, 0, 0, -4, 1)),
('1.0.0a1.dev204+g8866961', (1, 0, 0, -4, 1)),
('1.0.0+d20170606', (1, 0, 0, -1)),
# pre-release versions:
('1.0.0a1', (1, 0, 0, -4, 1)),
('1.0.0a2', (1, 0, 0, -4, 2)),
('1.0.0b3', (1, 0, 0, -3, 3)),
('1.0.0rc4', (1, 0, 0, -2, 4)),
# release versions:
('0.0.0', (0, 0, 0, -1)),
('0.0.11', (0, 0, 11, -1)),
('0.11.0', (0, 11, 0, -1)),
('11.0.0', (11, 0, 0, -1)),
])
def test_parse_version(version_str, version_tuple):
assert parse_version(version_str) == version_tuple
def test_parse_version_invalid():
with pytest.raises(ValueError):
assert parse_version('') # we require x.y.z versions
with pytest.raises(ValueError):
assert parse_version('1') # we require x.y.z versions
with pytest.raises(ValueError):
assert parse_version('1.2') # we require x.y.z versions
with pytest.raises(ValueError):
assert parse_version('crap')

View File

@ -3,33 +3,33 @@ import re
def parse_version(version): def parse_version(version):
""" """
simplistic parser for setuptools_scm versions Simplistic parser for setuptools_scm versions.
supports final versions and alpha ('a'), beta ('b') and rc versions. It just discards commits since last tag Supports final versions and alpha ('a'), beta ('b') and release candidate ('rc') versions.
and git revision hash. It does not try to parse anything else than that, even if there is more in the version string.
Output is a version tuple containing integers. It ends with one or two elements that ensure that relational Output is a version tuple containing integers. It ends with one or two elements that ensure that relational
operators yield correct relations for alpha, beta and rc versions too. For final versions the last element operators yield correct relations for alpha, beta and rc versions, too.
is a -1, for prerelease versions the last two elements are a smaller negative number and the number of e.g. For final versions the last element is a -1.
the beta. For prerelease versions the last two elements are a smaller negative number and the number of e.g. the beta.
Note, this sorts version 1.0 before 1.0.0.
This version format is part of the remote protocol, dont change in breaking ways. This version format is part of the remote protocol, dont change in breaking ways.
""" """
version_re = r"""
parts = version.split('+')[0].split('.') (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+) # version, e.g. 1.2.33
if parts[-1].startswith('dev'): (?P<prerelease>(?P<ptype>a|b|rc)(?P<pnum>\d+))? # optional prerelease, e.g. a1 or b2 or rc33
del parts[-1] """
version = [int(segment) for segment in parts[:-1]] m = re.match(version_re, version, re.VERBOSE)
if m is None:
prerelease = re.fullmatch('([0-9]+)(a|b|rc)([0-9]+)', parts[-1]) raise ValueError('Invalid version string %s' % version)
if prerelease: gd = m.groupdict()
version_type = {'a': -4, 'b': -3, 'rc': -2}[prerelease.group(2)] version = [int(gd['major']), int(gd['minor']), int(gd['patch'])]
version += [int(prerelease.group(1)), version_type, int(prerelease.group(3))] if m.lastgroup == 'prerelease':
p_type = {'a': -4, 'b': -3, 'rc': -2}[gd['ptype']]
p_num = int(gd['pnum'])
version += [p_type, p_num]
else: else:
version += [int(parts[-1]), -1] version += [-1]
return tuple(version) return tuple(version)