summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphaël Barrois <raphael.barrois@polytechnique.org>2012-05-20 21:49:00 +0200
committerRaphaël Barrois <raphael.barrois@polytechnique.org>2012-05-20 21:49:00 +0200
commite0ef7b8fe2f8f5f9945b008091c25de51f61f8aa (patch)
tree4081c85b061e87029eaa83439fe1766feb7c1f35
parentf075232bdf1af843d875350c1213e021da19f799 (diff)
downloadsemantic-version-e0ef7b8fe2f8f5f9945b008091c25de51f61f8aa.tar.gz
Update rules and code to follow readable specifications.
Signed-off-by: Raphaël Barrois <raphael.barrois@polytechnique.org>
-rw-r--r--doc/reference.rst8
-rw-r--r--src/semantic_version/base.py41
-rwxr-xr-xtests/test_base.py102
-rw-r--r--tests/test_django.py38
-rwxr-xr-xtests/test_match.py28
5 files changed, 99 insertions, 118 deletions
diff --git a/doc/reference.rst b/doc/reference.rst
index 698aa93..6882988 100644
--- a/doc/reference.rst
+++ b/doc/reference.rst
@@ -236,19 +236,13 @@ rules apply:
True
* Setting a build separator without a build identifier (``>1.1.1+``) forces
- satisfaction tests to include build identifiers::
+ satisfaction tests to include both prerelease and build identifiers::
>>> Version('1.1.1+build2') in Spec('>1.1.1')
False
>>> Version('1.1.1+build2') in Spec('>1.1.1+')
True
-* Including both pre-release and build separators while omitting identifiers is
- strictly equivalent to including only the build separator::
-
- >>> Spec('>1.1.1-+') == Spec('>1.1.1+')
- True
-
.. class:: Spec(spec_string)
Stores a version specification, defined from a string::
diff --git a/src/semantic_version/base.py b/src/semantic_version/base.py
index bec1a79..7b26981 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)
@@ -100,11 +100,13 @@ class Version(object):
patch = int(patch)
if prerelease is None:
- if partial and not build:
+ if partial and (build is None):
# No build info, strip here
return (major, minor, patch, None, None)
else:
prerelease = ()
+ elif prerelease == '':
+ prerelease = ()
else:
prerelease = tuple(prerelease.split('.'))
@@ -113,6 +115,8 @@ class Version(object):
build = None
else:
build = ()
+ elif build == '':
+ build = ()
else:
build = tuple(build.split('.'))
@@ -122,16 +126,11 @@ class Version(object):
return iter((self.major, self.minor, self.patch, self.prerelease, self.build))
def __str__(self):
- if self.minor is None:
- return '%d' % self.major
- elif self.patch is None:
- return '%d.%d' % (self.major, self.minor)
-
version = '%d.%d.%d' % (self.major, self.minor, self.patch)
- if self.prerelease:
+ if self.prerelease or (self.partial and self.prerelease == () and self.build is None):
version = '%s-%s' % (version, '.'.join(self.prerelease))
- if self.build:
+ if self.build or (self.partial and self.build == ()):
version = '%s+%s' % (version, '.'.join(self.build))
return version
@@ -255,19 +254,7 @@ class Spec(object):
KIND_NEQ,
)
- KIND_LTE_LOOSE = '<~'
- KIND_EQ_LOOSE = '~='
- KIND_GTE_LOOSE = '>~'
- KIND_NEQ_LOOSE = '!~'
-
- LOOSE_KINDS = (
- KIND_LTE_LOOSE,
- KIND_EQ_LOOSE,
- KIND_GTE_LOOSE,
- KIND_NEQ_LOOSE,
- )
-
- re_spec = re.compile(r'^(<|<=|==|>=|>|!=|<~|>~|~=|!~)(\d.*)$')
+ re_spec = re.compile(r'^(<|<=|==|>=|>|!=)(\d.*)$')
def __init__(self, requirement_string):
kind, spec = self.parse(requirement_string)
@@ -284,21 +271,21 @@ class Spec(object):
raise ValueError("Invalid requirement specification: %r" % requirement_string)
kind, version = match.groups()
- spec = Version(version, partial=(kind in cls.LOOSE_KINDS))
+ spec = Version(version, partial=True)
return (kind, spec)
def match(self, version):
if self.kind == self.KIND_LT:
return version < self.spec
- elif self.kind in (self.KIND_LTE, self.KIND_LTE_LOOSE):
+ elif self.kind == self.KIND_LTE:
return version <= self.spec
- elif self.kind in (self.KIND_EQUAL, self.KIND_EQ_LOOSE):
+ elif self.kind == self.KIND_EQUAL:
return version == self.spec
- elif self.kind in (self.KIND_GTE, self.KIND_GTE_LOOSE):
+ elif self.kind == self.KIND_GTE:
return version >= self.spec
elif self.kind == self.KIND_GT:
return version > self.spec
- elif self.kind in (self.KIND_NEQ, self.KIND_NEQ_LOOSE):
+ elif self.kind == self.KIND_NEQ:
return version != self.spec
else: # pragma: no cover
raise ValueError('Unexpected match kind: %r' % self.kind)
diff --git a/tests/test_base.py b/tests/test_base.py
index 894c4c3..49133c1 100755
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -101,22 +101,22 @@ class VersionTestCase(unittest.TestCase):
self.assertNotEqual(text, base.Version(text))
partial_versions = {
- '1.0': (1, 0, None, None, None),
- '1': (1, None, None, None, None),
'1.0.0-alpha': (1, 0, 0, ('alpha',), None),
'1.0.0-alpha.1': (1, 0, 0, ('alpha', '1'), None),
'1.0.0-beta.2': (1, 0, 0, ('beta', '2'), None),
'1.0.0-beta.11': (1, 0, 0, ('beta', '11'), None),
'1.0.0-rc.1': (1, 0, 0, ('rc', '1'), None),
- '1.0.0-rc.1+build.1': (1, 0, 0, ('rc', '1'), ('build', '1')),
'1.0.0': (1, 0, 0, None, None),
+ '1.1.1': (1, 1, 1, None, None),
+ '1.1.2': (1, 1, 2, None, None),
+ '1.1.3-rc4.5': (1, 1, 3, ('rc4', '5'), None),
+ '1.0.0-': (1, 0, 0, (), None),
+ '1.0.0+': (1, 0, 0, (), ()),
+ '1.0.0-rc.1+build.1': (1, 0, 0, ('rc', '1'), ('build', '1')),
'1.0.0+0.3.7': (1, 0, 0, (), ('0', '3', '7')),
'1.3.7+build': (1, 3, 7, (), ('build',)),
'1.3.7+build.2.b8f12d7': (1, 3, 7, (), ('build', '2', 'b8f12d7')),
'1.3.7+build.11.e0f985a': (1, 3, 7, (), ('build', '11', 'e0f985a')),
- '1.1.1': (1, 1, 1, None, None),
- '1.1.2': (1, 1, 2, None, None),
- '1.1.3-rc4.5': (1, 1, 3, ('rc4', '5'), None),
'1.1.3-rc42.3-14-15.24+build.2012-04-13.223':
(1, 1, 3, ('rc42', '3-14-15', '24'), ('build', '2012-04-13', '223')),
'1.1.3+build.2012-04-13.HUY.alpha-12.1':
@@ -163,18 +163,17 @@ class VersionTestCase(unittest.TestCase):
class SpecTestCase(unittest.TestCase):
components = {
- '~=0.1': (base.Spec.KIND_EQ_LOOSE, 0, 1, None, None, None),
- '~=0.1.2-rc3': (base.Spec.KIND_EQ_LOOSE, 0, 1, 2, ('rc3',), None),
- '~=0.1.2+build3.14': (base.Spec.KIND_EQ_LOOSE, 0, 1, 2, (), ('build3', '14')),
- '<=0.1.1': (base.Spec.KIND_LTE, 0, 1, 1, (), ()),
- '<0.1.1': (base.Spec.KIND_LT, 0, 1, 1, (), ()),
- '<~0.1.1': (base.Spec.KIND_LTE_LOOSE, 0, 1, 1, None, None),
- '<~0.1': (base.Spec.KIND_LTE_LOOSE, 0, 1, None, None, None),
- '>=0.2.3-rc2': (base.Spec.KIND_GTE, 0, 2, 3, ('rc2',), ()),
- '>0.2.3-rc2': (base.Spec.KIND_GT, 0, 2, 3, ('rc2',), ()),
- '>~2': (base.Spec.KIND_GTE_LOOSE, 2, None, None, None, None),
- '!=0.1.1': (base.Spec.KIND_NEQ, 0, 1, 1, (), ()),
- '!~0.3': (base.Spec.KIND_NEQ_LOOSE, 0, 3, None, None, None),
+ '==0.1.0': (base.Spec.KIND_EQUAL, 0, 1, 0, None, None),
+ '==0.1.2-rc3': (base.Spec.KIND_EQUAL, 0, 1, 2, ('rc3',), None),
+ '==0.1.2+build3.14': (base.Spec.KIND_EQUAL, 0, 1, 2, (), ('build3', '14')),
+ '<=0.1.1+': (base.Spec.KIND_LTE, 0, 1, 1, (), ()),
+ '<0.1.1': (base.Spec.KIND_LT, 0, 1, 1, None, None),
+ '<=0.1.1': (base.Spec.KIND_LTE, 0, 1, 1, None, None),
+ '>=0.2.3-rc2': (base.Spec.KIND_GTE, 0, 2, 3, ('rc2',), None),
+ '>0.2.3-rc2+': (base.Spec.KIND_GT, 0, 2, 3, ('rc2',), ()),
+ '>=2.0.0': (base.Spec.KIND_GTE, 2, 0, 0, None, None),
+ '!=0.1.1+': (base.Spec.KIND_NEQ, 0, 1, 1, (), ()),
+ '!=0.3.0': (base.Spec.KIND_NEQ, 0, 3, 0, None, None),
}
def test_components(self):
@@ -182,9 +181,6 @@ class SpecTestCase(unittest.TestCase):
kind, major, minor, patch, prerelease, build = components
spec = base.Spec(spec_text)
- self.assertNotEqual(spec, spec_text)
- self.assertEqual(spec_text, str(spec))
-
self.assertEqual(kind, spec.kind)
self.assertEqual(major, spec.spec.major)
self.assertEqual(minor, spec.spec.minor)
@@ -192,54 +188,57 @@ class SpecTestCase(unittest.TestCase):
self.assertEqual(prerelease, spec.spec.prerelease)
self.assertEqual(build, spec.spec.build)
+ self.assertNotEqual(spec, spec_text)
+ self.assertEqual(spec_text, str(spec))
+
matches = {
- '~=0.1': (
- ['0.1.0', '0.1.99', '0.1.0-rc1', '0.1.4-rc1+build2'],
- ['0.0.1', '0.2.0'],
+ '==0.1.0': (
+ ['0.1.0', '0.1.0-rc1', '0.1.0+build1', '0.1.0-rc1+build2'],
+ ['0.0.1', '0.2.0', '0.1.1'],
),
- '~=0.1.2-rc3': (
+ '==0.1.2-rc3': (
['0.1.2-rc3+build1', '0.1.2-rc3+build4.5'],
['0.1.2-rc4', '0.1.2', '0.1.3'],
),
- '~=0.1.2+build3.14': (
+ '==0.1.2+build3.14': (
['0.1.2+build3.14'],
['0.1.2-rc+build3.14', '0.1.2+build3.15'],
),
'<=0.1.1': (
- ['0.0.0', '0.1.1-alpha1', '0.1.1'],
- ['0.1.1+build2', '0.1.2'],
+ ['0.0.0', '0.1.1-alpha1', '0.1.1', '0.1.1+build2'],
+ ['0.1.2'],
),
'<0.1.1': (
- ['0.1.0', '0.1.1-zzz+999', '0.0.0'],
- ['0.1.1', '1.2.0', '0.1.1+build3'],
+ ['0.1.0', '0.0.0'],
+ ['0.1.1', '0.1.1-zzz+999', '1.2.0', '0.1.1+build3'],
),
- '<~0.1.1': (
+ '<=0.1.1': (
['0.1.1+build4', '0.1.1-alpha', '0.1.0'],
['0.2.3', '1.1.1', '0.1.2'],
),
- '<~0.1': (
- ['0.1.0', '0.1.1+4', '0.1.99', '0.1.0-alpha', '0.0.1'],
- ['0.2.0', '1.0.0'],
+ '<0.1.1-': (
+ ['0.1.0', '0.1.1-alpha', '0.1.1-alpha+4'],
+ ['0.2.0', '1.0.0', '0.1.1', '0.1.1+build1'],
),
'>=0.2.3-rc2': (
['0.2.3-rc3', '0.2.3', '0.2.3+1', '0.2.3-rc2', '0.2.3-rc2+1'],
['0.2.3-rc1', '0.2.2'],
),
- '>0.2.3-rc2': (
+ '>0.2.3-rc2+': (
['0.2.3-rc3', '0.2.3', '0.2.3-rc2+1'],
- ['0.2.3-rc1', '0.2.2'],
+ ['0.2.3-rc1', '0.2.2', '0.2.3-rc2'],
),
- '>~2': (
- ['2.1.1', '2.0.0-alpha1', '3.1.4'],
- ['1.9.9', '1.9.9999'],
+ '>2.0.0+': (
+ ['2.1.1', '2.0.0+b1', '3.1.4'],
+ ['1.9.9', '1.9.9999', '2.0.0', '2.0.0-rc4'],
),
'!=0.1.1': (
- ['0.1.1-alpha', '0.1.2', '0.1.0', '1.4.2'],
- ['0.1.1'],
+ ['0.1.2', '0.1.0', '1.4.2'],
+ ['0.1.1', '0.1.1-alpha', '0.1.1+b1'],
),
- '!~0.3': (
- ['0.4.0', '1.3.0'],
- ['0.3.0', '0.3.99', '0.3.0-alpha', '0.3.999999+4'],
+ '!=0.3.4-': (
+ ['0.4.0', '1.3.0', '0.3.4-alpha', '0.3.4-alpha+b1'],
+ ['0.3.4', '0.3.4+b1'],
),
}
@@ -279,7 +278,7 @@ class SpecTestCase(unittest.TestCase):
class SpecListTestCase(unittest.TestCase):
examples = {
'>=0.1.1,<0.1.2': ['>=0.1.1', '<0.1.2'],
- '>~0.1,!=0.1.3-rc1,<0.1.3': ['>~0.1', '!=0.1.3-rc1', '<0.1.3'],
+ '>=0.1.0,!=0.1.3-rc1,<0.1.3': ['>=0.1.0', '!=0.1.3-rc1', '<0.1.3'],
}
def test_parsing(self):
@@ -295,7 +294,7 @@ class SpecListTestCase(unittest.TestCase):
split_examples = {
('>=0.1.1', '<0.1.2', '!=0.1.1+build1'): ['>=0.1.1', '<0.1.2', '!=0.1.1+build1'],
- ('>~0.1', '!=0.1.3-rc1,<0.1.3'): ['>~0.1', '!=0.1.3-rc1', '<0.1.3'],
+ ('>=0.1.0', '!=0.1.3-rc1,<0.1.3'): ['>=0.1.0', '!=0.1.3-rc1', '<0.1.3'],
}
def test_parsing_split(self):
@@ -311,12 +310,13 @@ class SpecListTestCase(unittest.TestCase):
matches = {
'>=0.1.1,<0.1.2': (
- ['0.1.1', '0.1.2-alpha', '0.1.1+4'],
- ['0.1.1-alpha', '0.1.2', '1.3.4'],
+ ['0.1.1', '0.1.1+4', '0.1.1-alpha'],
+ ['0.1.2-alpha', '0.1.2', '1.3.4'],
),
- '>~0.1,!=0.1.3-rc1,<0.1.3': (
- ['0.1.1', '0.1.3-rc1+4', '0.1.3-alpha'],
- ['0.0.1', '0.1.3', '0.2.2', '0.1.3-rc1'],
+ '>=0.1.0+,!=0.1.3-rc1,<0.1.4': (
+ ['0.1.1', '0.1.0+b4', '0.1.2', '0.1.3-rc2'],
+ ['0.0.1', '0.1.4', '0.1.4-alpha', '0.1.3-rc1+4',
+ '0.1.0-alpha', '0.2.2', '0.1.4-rc1'],
),
}
diff --git a/tests/test_django.py b/tests/test_django.py
index 79cd1c0..d8eef7d 100644
--- a/tests/test_django.py
+++ b/tests/test_django.py
@@ -35,40 +35,46 @@ if django_loaded: # pragma: no cover
@unittest.skipIf(not django_loaded, "Django not installed")
class DjangoFieldTestCase(unittest.TestCase):
def test_version(self):
- obj = models.VersionModel(version='0.1.1', spec='>0.1.0', speclist='~=0.1,!~0.1.1')
+ obj = models.VersionModel(version='0.1.1', spec='>0.1.0', speclist='==0.1.1,!=0.1.1-alpha')
self.assertEqual(semantic_version.Version('0.1.1'), obj.version)
self.assertEqual(semantic_version.Spec('>0.1.0'), obj.spec)
- self.assertEqual(semantic_version.SpecList('~=0.1,!~0.1.1'), obj.speclist)
+ self.assertEqual(semantic_version.SpecList('==0.1.1,!=0.1.1-alpha'), obj.speclist)
alt_obj = models.VersionModel(version=obj.version, spec=obj.spec, speclist=obj.speclist)
self.assertEqual(semantic_version.Version('0.1.1'), alt_obj.version)
self.assertEqual(semantic_version.Spec('>0.1.0'), alt_obj.spec)
- self.assertEqual(semantic_version.SpecList('~=0.1,!~0.1.1'), alt_obj.speclist)
+ self.assertEqual(semantic_version.SpecList('==0.1.1,!=0.1.1-alpha'), alt_obj.speclist)
self.assertEqual(obj.spec, alt_obj.spec)
self.assertEqual(obj.version, alt_obj.version)
self.assertEqual(obj.speclist, alt_obj.speclist)
def test_invalid_input(self):
self.assertRaises(ValueError, models.VersionModel,
- version='0.1.1', spec='blah', speclist='~=0.1,!~0.1.1')
+ version='0.1.1', spec='blah', speclist='==0.1.1,!=0.1.1-alpha')
self.assertRaises(ValueError, models.VersionModel,
- version='0.1', spec='>0.1.1', speclist='~=0.1,!~0.1.1')
+ version='0.1', spec='>0.1.1', speclist='==0.1.1,!=0.1.1-alpha')
self.assertRaises(ValueError, models.VersionModel,
- version='0.1.1', spec='>0.1.1', speclist='~=0,!=0.2')
+ version='0.1.1', spec='>0.1.1', speclist='==0,!=0.2')
def test_partial(self):
- obj = models.PartialVersionModel(partial='0.1')
+ obj = models.PartialVersionModel(partial='0.1.0')
- self.assertEqual(semantic_version.Version('0.1', partial=True), obj.partial)
+ self.assertEqual(semantic_version.Version('0.1.0', partial=True), obj.partial)
self.assertIsNone(obj.optional)
self.assertIsNone(obj.optional_spec)
self.assertIsNone(obj.optional_speclist)
- alt_obj = models.PartialVersionModel(partial=obj.partial, optional=obj.optional,
- optional_spec=obj.optional_spec, optional_speclist=obj.optional_speclist)
- self.assertEqual(semantic_version.Version('0.1', partial=True), alt_obj.partial)
+ # Copy values to another model
+ alt_obj = models.PartialVersionModel(
+ partial=obj.partial,
+ optional=obj.optional,
+ optional_spec=obj.optional_spec,
+ optional_speclist=obj.optional_speclist,
+ )
+
+ self.assertEqual(semantic_version.Version('0.1.0', partial=True), alt_obj.partial)
self.assertEqual(obj.partial, alt_obj.partial)
self.assertIsNone(obj.optional)
self.assertIsNone(obj.optional_spec)
@@ -76,9 +82,9 @@ class DjangoFieldTestCase(unittest.TestCase):
def test_serialization(self):
o1 = models.VersionModel(version='0.1.1', spec='<0.2.4-rc42',
- speclist='~=0.1,!=0.1.1')
- o2 = models.VersionModel(version='0.4.3-rc3+build3', spec='~=0.4',
- speclist='<=0.1.1-rc2,!~0.1.1-rc1')
+ speclist='==0.1.1,!=0.1.1-alpha')
+ o2 = models.VersionModel(version='0.4.3-rc3+build3', spec='==0.4.3',
+ speclist='<=0.1.1-rc2,!=0.1.1-rc1')
data = serializers.serialize('json', [o1, o2])
@@ -90,7 +96,7 @@ class DjangoFieldTestCase(unittest.TestCase):
o1 = models.PartialVersionModel(partial='0.1.1', optional='0.2.4-rc42',
optional_spec=None, optional_speclist=None)
o2 = models.PartialVersionModel(partial='0.4.3-rc3+build3', optional='',
- optional_spec='~=1.1', optional_speclist='~=0.1,!=0.1.1')
+ optional_spec='==1.1.0', optional_speclist='==0.1.1,!=0.1.1-alpha')
data = serializers.serialize('json', [o1, o2])
@@ -115,7 +121,7 @@ if django_loaded:
def test_db_interaction(self):
o1 = models.VersionModel(version='0.1.1', spec='<0.2.4-rc42')
- o2 = models.VersionModel(version='0.4.3-rc3+build3', spec='~=0.4')
+ o2 = models.VersionModel(version='0.4.3-rc3+build3', spec='==0.4.3')
o1.save()
o2.save()
diff --git a/tests/test_match.py b/tests/test_match.py
index 2e88c60..f6888bc 100755
--- a/tests/test_match.py
+++ b/tests/test_match.py
@@ -17,7 +17,7 @@ class MatchTestCase(unittest.TestCase):
]
valid_specs = [
- '~=0.1',
+ '==0.1.0',
'<=0.1.1',
'>0.1.2-rc1',
'>=0.1.2-rc1.3.4',
@@ -26,14 +26,7 @@ class MatchTestCase(unittest.TestCase):
]
matches = {
- '~=0.1': [
- '0.1.1',
- '0.1.2-rc1',
- '0.1.2-rc1.3.4',
- '0.1.2+build42-12.2012-01-01.12h23',
- '0.1.2-rc1.3-14.15+build.2012-01-01.11h34',
- ],
- '~=0.1.2': [
+ '==0.1.2': [
'0.1.2-rc1',
'0.1.2-rc1.3.4',
'0.1.2+build42-12.2012-01-01.12h23',
@@ -44,8 +37,9 @@ class MatchTestCase(unittest.TestCase):
'0.1.2-rc1',
'0.1.2-rc1.3.4',
'0.1.2',
+ '0.1.2+build4',
],
- '<0.1.2': [
+ '<0.1.2+': [
'0.1.1',
'0.1.2-rc1',
'0.1.2-rc1.3.4',
@@ -59,19 +53,19 @@ class MatchTestCase(unittest.TestCase):
'1.0.0',
],
'>0.1.1': [
- '0.1.1+build4.5',
+ '0.1.2+build4.5',
'0.1.2-rc1.3',
'0.2.0',
'1.0.0',
],
- '>~0.1': [
- '0.1.1',
- '0.1.0-rc1',
+ '>0.1.1+': [
+ '0.1.1+b2',
+ '0.1.2-rc1',
'1.1.1',
'2.0.4',
],
- '<~0.1.1': [
- '0.1.1',
+ '<0.1.1-': [
+ '0.1.1-alpha',
'0.1.1-rc4',
'0.1.0+12.3',
],
@@ -101,7 +95,7 @@ class MatchTestCase(unittest.TestCase):
self.assertFalse('0.1.0' in spec, "0.1.0 should not be in %r" % spec)
version = semantic_version.Version('0.1.1+4.2')
- self.assertFalse(version in spec, "%r should not be in %r" % (version, spec))
+ self.assertTrue(version in spec, "%r should be in %r" % (version, spec))
version = semantic_version.Version('0.1.1-rc1+4.2')
self.assertTrue(version in spec, "%r should be in %r" % (version, spec))