Introduce Spec.filter and Spec.select.
Signed-off-by: Raphaël Barrois <raphael.barrois@polytechnique.org>
This commit is contained in:
13
README
13
README
@@ -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
|
||||
=====================
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
|
||||
@@ -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`::
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user