diff options
author | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2012-05-22 02:00:47 +0200 |
---|---|---|
committer | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2012-05-22 02:00:47 +0200 |
commit | 4691a44b37b94f36fd8e9027137065e076c3c35c (patch) | |
tree | be742a4a9e9c136a54d63371ec127b930a738cc7 | |
parent | aeeecf63275a2d0fea8ef38b7efeea88491576a7 (diff) | |
download | semantic-version-4691a44b37b94f36fd8e9027137065e076c3c35c.tar.gz |
Introduce Spec.filter and Spec.select.
Signed-off-by: Raphaël Barrois <raphael.barrois@polytechnique.org>
-rw-r--r-- | README | 13 | ||||
-rw-r--r-- | doc/changelog.rst | 12 | ||||
-rw-r--r-- | doc/index.rst | 22 | ||||
-rw-r--r-- | doc/reference.rst | 50 | ||||
-rw-r--r-- | src/semantic_version/__init__.py | 2 | ||||
-rw-r--r-- | src/semantic_version/base.py | 17 | ||||
-rwxr-xr-x | tests/test_base.py | 61 |
7 files changed, 159 insertions, 18 deletions
@@ -25,9 +25,9 @@ Compare it to other versions:: >>> v < Version('0.1.2') True >>> sorted([Version('0.1.1'), Version('0.11.1'), Version('0.1.1-alpha')]) - [<SemVer(0, 1, 1, ('alpha',), ())>, - <SemVer(0, 1, 1, (), ())>, - <SemVer(0, 11, 1, (), ())>] + [<Version(0, 1, 1, ('alpha',), ())>, + <Version(0, 1, 1, (), ())>, + <Version(0, 11, 1, (), ())>] Define a simple specification:: @@ -49,6 +49,13 @@ Define complex specifications:: False +Select the best compatible version from a list:: + + >>> s = Spec('>=0.1.1,<0.2.0') + >>> s.select([Version('0.1.1'), Version('0.1.9-alpha'), Version('0.1.9-alpha+1')) + <Version(0, 1, 9, ('alpha',), (1,))> + + Framework integration ===================== diff --git a/doc/changelog.rst b/doc/changelog.rst index 7b1cb8e..10b4ad3 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -1,9 +1,19 @@ ChangeLog ========= -2.0.0 (Master) +2.1.0 (Master) -------------- +*New:* + + * Add :func:`semantic_version.Spec.filter` (filter a list of :class:`~semantic_version.Version`) + * Add :func:`semantic_version.Spec.select` (select the highest + :class:`~semantic_version.Version` from a list) + * Update :func:`semantic_version.Version.__repr__` + +2.0.0 (22/05/2012) +------------------ + *Backwards incompatible changes:* * Removed "loose" specification support diff --git a/doc/index.rst b/doc/index.rst index 952e30e..38156cf 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -9,7 +9,7 @@ python-semanticversion This small python library provides a few tools to handle `SemVer`_ in Python. -The first release (1.0.0) should handle the 2.0.0-rc1 version of the SemVer scheme. +It follows strictly the 2.0.0-rc1 version of the SemVer scheme. Getting started @@ -116,6 +116,26 @@ Combining specifications can be expressed in two ways: >>> Spec('>=0.1.1', '!=0.2.4-alpha,<0.3.0') +Using a specification +""""""""""""""""""""" + +The :func:`Spec.filter` method filters an iterable of :class:`Version`:: + + >>> s = Spec('>=0.1.0,<0.4.0') + >>> versions = (Version('0.%d.0' % i) for i in range(6)) + >>> for v in s.filter(versions): + ... print v + 0.1.0 + 0.2.0 + 0.3.0 + +It is also possible to select the 'best' version from such iterables:: + + >>> s = Spec('>=0.1.0,<0.4.0') + >>> versions = (Version('0.%d.0' % i) for i in range(6)) + >>> s.select(versions) + <Version(0, 3, 0, (), ())> + Including pre-release identifiers in specifications """"""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/doc/reference.rst b/doc/reference.rst index f3b9087..6ac06e0 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -53,7 +53,7 @@ Representing a version (the Version class) Constructed from a textual version string:: >>> Version('1.1.1') - <SemVer(1, 1, 1, [], [])> + <Version(1, 1, 1, [], [])> >>> str(Version('1.1.1')) '1.1.1' @@ -156,7 +156,7 @@ Representing a version (the Version class) >>> v = Version('0.1.1-rc2+build4.4') >>> v - <SemVer(0, 1, 1, ['rc2'], ['build4', '4'])> + <Version(0, 1, 1, ['rc2'], ['build4', '4'])> >>> str(v) '0.1.1-rc2+build4.4' @@ -252,19 +252,19 @@ rules apply: >>> Spec('>=1.0.0,<1.2.0,!=1.1.4') <Spec: ( - <SpecItem: >= <~SemVer: 1 0 0 None None>>, - <SpecItem: < <~SemVer: 1 2 0 None None>>, - <SpecItem: != <~SemVer: 1 1 4 None None>> + <SpecItem: >= <~Version(1 0 0 None None)>>, + <SpecItem: < <~Version(1 2 0 None None)>>, + <SpecItem: != <~Version(1 1 4 None None)>> )> Version specifications may also be passed in separated arguments:: >>> Spec('>=1.0.0', '<1.2.0', '!=1.1.4,!=1.1.13') <Spec: ( - <SpecItem: >= <~SemVer: 1 0 0 None None>>, - <SpecItem: < <SemVer: 1 2 0 None None>>, - <SpecItem: != <~SemVer: 1 1 4 None None>> - <SpecItem: != <~SemVer: 1 1 13 None None>> + <SpecItem: >= <~Version(1 0 0 None None)>>, + <SpecItem: < <Version(1 2 0 None None)>>, + <SpecItem: != <~Version(1 1 4 None None)>> + <SpecItem: != <~Version(1 1 13 None None)>> )> @@ -290,6 +290,36 @@ rules apply: :type version: :class:`Version` :rtype: ``bool`` + + .. method:: filter(self, versions) + + Extract all compatible :class:`versions <Version>` from an iterable of + :class:`Version` objects. + + :param versions: The versions to filter + :type versions: iterable of :class:`Version` + :yield: :class:`Version` + + + .. method:: select(self, versions) + + Select the highest compatible version from an iterable of :class:`Version` + objects. + + .. sourcecode:: pycon + + >>> s = Spec('>=0.1.0') + >>> s.select([]) + None + >>> s.select([Version('0.1.0'), Version('0.1.3'), Version('0.1.1')]) + <Version(0, 1, 3, (), ())> + + :param versions: The versions to filter + :type versions: iterable of :class:`Version` + :rtype: The highest compatible :class:`Version` if at least one of the + given versions is compatible; :class:`None` otherwise. + + .. method:: __contains__(self, version) Alias of the :func:`match` method; @@ -341,7 +371,7 @@ rules apply: Stores a version specification, defined from a string:: >>> SpecItem('>=0.1.1') - <SpecItem: >= <SemVer(0, 1, 1, [], [])>> + <SpecItem: >= <Version(0, 1, 1, [], [])>> This allows to test :class:`Version` objects against the :class:`SpecItem`:: diff --git a/src/semantic_version/__init__.py b/src/semantic_version/__init__.py index 9826d65..c03d207 100644 --- a/src/semantic_version/__init__.py +++ b/src/semantic_version/__init__.py @@ -2,7 +2,7 @@ # Copyright (c) 2012 Raphaël Barrois -__version__ = '2.0.0' +__version__ = '2.1.0-alpha' from .base import compare, match, Spec, SpecItem, Version diff --git a/src/semantic_version/base.py b/src/semantic_version/base.py index 16a1404..67ffe92 100644 --- a/src/semantic_version/base.py +++ b/src/semantic_version/base.py @@ -127,8 +127,8 @@ class Version(object): return version def __repr__(self): - return '<%sSemVer(%s, %s, %s, %r, %r)>' % ( - '~' if self.partial else '', + return '<%sVersion(%s, %s, %s, %r, %r)>' % ( + ', partial=True' if self.partial else '', self.major, self.minor, self.patch, @@ -311,6 +311,19 @@ class Spec(object): """Check whether a Version satisfies the Spec.""" return all(spec.match(version) for spec in self.specs) + def filter(self, versions): + """Filter an iterable of versions satisfying the Spec.""" + for version in versions: + if self.match(version): + yield version + + def select(self, versions): + """Select the best compatible version among an iterable of options.""" + options = list(self.filter(versions)) + if options: + return max(options) + return None + def __contains__(self, version): if isinstance(version, Version): return self.match(version) diff --git a/tests/test_base.py b/tests/test_base.py index 22690b6..9bc19e8 100755 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -343,6 +343,67 @@ class SpecTestCase(unittest.TestCase): self.assertEqual(slist1, slist2) self.assertFalse(slist1 == spec_list_text) + def test_filter_empty(self): + s = base.Spec('>=0.1.1') + res = tuple(s.filter(())) + self.assertEqual((), res) + + def test_filter_incompatible(self): + s = base.Spec('>=0.1.1,!=0.1.4') + res = tuple(s.filter([ + base.Version('0.1.0'), + base.Version('0.1.4'), + base.Version('0.1.4-alpha'), + ])) + self.assertEqual((), res) + + def test_filter_compatible(self): + s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0') + res = tuple(s.filter([ + base.Version('0.1.0'), + base.Version('0.1.1'), + base.Version('0.1.5'), + base.Version('0.1.4-alpha'), + base.Version('0.1.2'), + base.Version('0.2.0-rc1'), + base.Version('3.14.15'), + ])) + + expected = ( + base.Version('0.1.1'), + base.Version('0.1.5'), + base.Version('0.1.2'), + ) + + self.assertEqual(expected, res) + + def test_select_empty(self): + s = base.Spec('>=0.1.1') + self.assertIsNone(s.select(())) + + def test_select_incompatible(self): + s = base.Spec('>=0.1.1,!=0.1.4') + res = s.select([ + base.Version('0.1.0'), + base.Version('0.1.4'), + base.Version('0.1.4-alpha'), + ]) + self.assertIsNone(res) + + def test_select_compatible(self): + s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0') + res = s.select([ + base.Version('0.1.0'), + base.Version('0.1.1'), + base.Version('0.1.5'), + base.Version('0.1.4-alpha'), + base.Version('0.1.2'), + base.Version('0.2.0-rc1'), + base.Version('3.14.15'), + ]) + + self.assertEqual(base.Version('0.1.5'), res) + def test_contains(self): self.assertFalse('ii' in base.Spec('>=0.1.1')) |