summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphaël Barrois <raphael.barrois@polytechnique.org>2013-03-20 02:02:02 +0100
committerRaphaël Barrois <raphael.barrois@polytechnique.org>2013-03-20 02:02:02 +0100
commitf84d754af1ae86aaa9a891445d6ae5be36668a85 (patch)
treed56cb28242391a2d05b3601efd03202298e00cb3
parent658ac42850e3b4c4923365287d55ec17be4806de (diff)
downloadsemantic-version-f84d754af1ae86aaa9a891445d6ae5be36668a85.tar.gz
Fix handling of partial versions (Closes #1).
-rw-r--r--doc/changelog.rst8
-rw-r--r--src/semantic_version/base.py18
-rwxr-xr-xtests/test_base.py1
-rw-r--r--tests/test_django.py7
-rwxr-xr-xtests/test_match.py16
5 files changed, 43 insertions, 7 deletions
diff --git a/doc/changelog.rst b/doc/changelog.rst
index 13a3336..67b6cde 100644
--- a/doc/changelog.rst
+++ b/doc/changelog.rst
@@ -1,6 +1,14 @@
ChangeLog
=========
+2.2.0 (current)
+---------------
+
+*Bugfix:*
+
+ * `#1 <https://github.com/rbarrois/python-semanticversion/issues/1>`_: Allow partial
+ versions without minor or patch level
+
2.1.2 (22/05/2012)
------------------
diff --git a/src/semantic_version/base.py b/src/semantic_version/base.py
index 932614c..b8e7fcf 100644
--- a/src/semantic_version/base.py
+++ b/src/semantic_version/base.py
@@ -58,7 +58,7 @@ def identifier_list_cmp(a, b):
class Version(object):
version_re = re.compile('^(\d+)\.(\d+)\.(\d+)(?:-([0-9a-zA-Z.-]+))?(?:\+([0-9a-zA-Z.-]+))?$')
- partial_version_re = re.compile('^(\d+)\.(\d+)\.(\d+)(?:-([0-9a-zA-Z.-]*))?(?:\+([0-9a-zA-Z.-]*))?$')
+ partial_version_re = re.compile('^(\d+)(?:\.(\d+)(?:\.(\d+))?)?(?:-([0-9a-zA-Z.-]*))?(?:\+([0-9a-zA-Z.-]*))?$')
def __init__(self, version_string, partial=False):
major, minor, patch, prerelease, build = self.parse(version_string, partial)
@@ -72,6 +72,12 @@ class Version(object):
self.partial = partial
@classmethod
+ def _coerce(cls, value, allow_none=False):
+ if value is None and allow_none:
+ return value
+ return int(value)
+
+ @classmethod
def parse(cls, version_string, partial=False):
if not version_string:
raise ValueError('Invalid empty version string: %r' % version_string)
@@ -88,8 +94,8 @@ class Version(object):
major, minor, patch, prerelease, build = match.groups()
major = int(major)
- minor = int(minor)
- patch = int(patch)
+ minor = cls._coerce(minor, partial)
+ patch = cls._coerce(patch, partial)
if prerelease is None:
if partial and (build is None):
@@ -118,7 +124,11 @@ class Version(object):
return iter((self.major, self.minor, self.patch, self.prerelease, self.build))
def __str__(self):
- version = '%d.%d.%d' % (self.major, self.minor, self.patch)
+ version = '%d' % self.major
+ if self.minor is not None:
+ version = '%s.%d' % (version, self.minor)
+ if self.patch is not None:
+ version = '%s.%d' % (version, self.patch)
if self.prerelease or (self.partial and self.prerelease == () and self.build is None):
version = '%s-%s' % (version, '.'.join(self.prerelease))
diff --git a/tests/test_base.py b/tests/test_base.py
index 52d2e84..90dbe96 100755
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -197,6 +197,7 @@ class SpecItemTestCase(unittest.TestCase):
'<=0.1.1+': (base.SpecItem.KIND_LTE, 0, 1, 1, (), ()),
'<0.1.1': (base.SpecItem.KIND_LT, 0, 1, 1, None, None),
'<=0.1.1': (base.SpecItem.KIND_LTE, 0, 1, 1, None, None),
+ '<=0.1.1-': (base.SpecItem.KIND_LTE, 0, 1, 1, (), None),
'>=0.2.3-rc2': (base.SpecItem.KIND_GTE, 0, 2, 3, ('rc2',), None),
'>0.2.3-rc2+': (base.SpecItem.KIND_GT, 0, 2, 3, ('rc2',), ()),
'>=2.0.0': (base.SpecItem.KIND_GTE, 2, 0, 0, None, None),
diff --git a/tests/test_django.py b/tests/test_django.py
index e55ec28..a2d4c9b 100644
--- a/tests/test_django.py
+++ b/tests/test_django.py
@@ -56,13 +56,16 @@ class DjangoFieldTestCase(unittest.TestCase):
obj.full_clean()
+ def test_partial_spec(self):
+ obj = models.VersionModel(version='0.1.1', spec='==0,!=0.2')
+ self.assertEqual(semantic_version.Version('0.1.1'), obj.version)
+ self.assertEqual(semantic_version.Spec('==0,!=0.2'), obj.spec)
+
def test_invalid_input(self):
self.assertRaises(ValueError, models.VersionModel,
version='0.1.1', spec='blah')
self.assertRaises(ValueError, models.VersionModel,
version='0.1', spec='==0.1.1,!=0.1.1-alpha')
- self.assertRaises(ValueError, models.VersionModel,
- version='0.1.1', spec='==0,!=0.2')
def test_partial(self):
obj = models.PartialVersionModel(partial='0.1.0')
diff --git a/tests/test_match.py b/tests/test_match.py
index e0fd5e7..5f7a988 100755
--- a/tests/test_match.py
+++ b/tests/test_match.py
@@ -11,7 +11,6 @@ class MatchTestCase(unittest.TestCase):
invalid_specs = [
'',
'!0.1',
- '<0.1',
'<=0.1.4a',
'>0.1.1.1',
'~0.1.2-rc23,1',
@@ -20,6 +19,7 @@ class MatchTestCase(unittest.TestCase):
valid_specs = [
'==0.1.0',
'<=0.1.1',
+ '<0.1',
'>0.1.2-rc1',
'>=0.1.2-rc1.3.4',
'==0.1.2+build42-12.2012-01-01.12h23',
@@ -101,6 +101,20 @@ class MatchTestCase(unittest.TestCase):
version = semantic_version.Version('0.1.1-rc1+4.2')
self.assertTrue(version in spec, "%r should be in %r" % (version, spec))
+ def test_prerelease_check(self):
+ strict_spec = semantic_version.Spec('>=0.1.1-')
+ lax_spec = semantic_version.Spec('>=0.1.1')
+ version = semantic_version.Version('0.1.1-rc1+4.2')
+ self.assertTrue(version in lax_spec, "%r should be in %r" % (version, lax_spec))
+ self.assertFalse(version in strict_spec, "%r should not be in %r" % (version, strict_spec))
+
+ def test_build_check(self):
+ strict_spec = semantic_version.Spec('<=0.1.1-rc1+')
+ lax_spec = semantic_version.Spec('<=0.1.1-rc1')
+ version = semantic_version.Version('0.1.1-rc1+4.2')
+ self.assertTrue(version in lax_spec, "%r should be in %r" % (version, lax_spec))
+ self.assertFalse(version in strict_spec, "%r should not be in %r" % (version, strict_spec))
+
if __name__ == '__main__': # pragma: no cover
unittest.main()