summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphaël Barrois <raphael.barrois@polytechnique.org>2019-08-23 19:26:24 +0200
committerRaphaël Barrois <raphael.barrois@polytechnique.org>2019-08-24 15:13:09 +0200
commitc24f4e2157438be40b44e6ba02d90c6bfa934454 (patch)
tree66ecf2747c6a605688c0a934d94bab539085c11e
parent13902f1812697bac01ea1172663a6eedd20ac9d5 (diff)
downloadsemantic-version-c24f4e2157438be40b44e6ba02d90c6bfa934454.tar.gz
Fix inconsistent matching behaviour.
According to the stated goal of "intuitive" behaviour, we want: ``Version('0.1.1-a1') not in Spec('<0.1.1')``. Tests, code and docs have been fixed.
-rw-r--r--ChangeLog4
-rw-r--r--docs/reference.rst4
-rw-r--r--semantic_version/base.py6
-rwxr-xr-xtests/test_base.py48
-rwxr-xr-xtests/test_match.py13
5 files changed, 39 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index 8ad05dc..687d899 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,10 @@ ChangeLog
(``Version(major=1, minor=2, patch=3)``)
* Add ``Version.truncate()`` to build a truncated copy of a ``Version``
+*Bugfix:*
+
+ * Fix inconsistent behaviour regarding versions with a prerelease specification.
+
*Removed:*
* Remove support for Python2 (End of life 4 months after this release)
diff --git a/docs/reference.rst b/docs/reference.rst
index f9b4aed..a7fce0b 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -330,8 +330,8 @@ does not map well onto `SemVer`_ precedence rules:
In order to have version specification behave naturally, the rules are the following:
-* If no pre-release number was included in the specification, pre-release numbers
- are ignored when deciding whether a version satisfies a specification.
+* If no pre-release number was included in the specification, versions with a pre-release
+ numbers are excluded from matching that specification.
* If no build metadata was included in the specification, build metadata is ignored
when deciding whether a version satisfies a specification.
diff --git a/semantic_version/base.py b/semantic_version/base.py
index 8251efa..1caffa5 100644
--- a/semantic_version/base.py
+++ b/semantic_version/base.py
@@ -441,7 +441,7 @@ class Version:
base_cmp, # Major is still mandatory
make_optional(base_cmp),
make_optional(base_cmp),
- make_optional(prerelease_cmp),
+ prerelease_cmp,
make_optional(build_cmp),
]
else:
@@ -568,6 +568,8 @@ class SpecItem:
if self.kind == self.KIND_ANY:
return True
elif self.kind == self.KIND_LT:
+ if version.prerelease and self.spec.prerelease is None:
+ version = Version(major=version.major, minor=version.minor, patch=version.patch)
return version < self.spec
elif self.kind == self.KIND_LTE:
return version <= self.spec
@@ -578,6 +580,8 @@ class SpecItem:
elif self.kind == self.KIND_GT:
return version > self.spec
elif self.kind == self.KIND_NEQ:
+ if version.prerelease and version.truncate() == self.spec.truncate() and self.spec.prerelease is None:
+ return False
return version != self.spec
elif self.kind == self.KIND_CARET:
if self.spec.major != 0:
diff --git a/tests/test_base.py b/tests/test_base.py
index 76d120b..d5794b3 100755
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -83,7 +83,7 @@ class TopLevelTestCase(unittest.TestCase):
matches = (
('>=0.1.1', '0.1.2'),
('>=0.1.1', '0.1.1'),
- ('>=0.1.1', '0.1.1-alpha'),
+ ('>=0.1.1', '0.1.2-alpha'),
('>=0.1.1,!=0.2.0', '0.2.1'),
)
@@ -463,16 +463,16 @@ class SpecItemTestCase(unittest.TestCase):
matches = {
'==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.0', '0.1.0+build1'],
+ ['0.0.1', '0.1.0-rc1', '0.2.0', '0.1.1', '0.1.0-rc1+build2'],
),
'=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.0', '0.1.0+build1'],
+ ['0.0.1', '0.1.0-rc1', '0.2.0', '0.1.1', '0.1.0-rc1+build2'],
),
'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.0', '0.1.0+build1'],
+ ['0.0.1', '0.1.0-rc1', '0.2.0', '0.1.1', '0.1.0-rc1+build2'],
),
'==0.1.2-rc3': (
['0.1.2-rc3+build1', '0.1.2-rc3+build4.5'],
@@ -502,6 +502,10 @@ class SpecItemTestCase(unittest.TestCase):
['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': (
+ ['0.2.3', '0.2.3+1'],
+ ['0.2.3-rc3', '0.2.3-rc2', '0.2.3-rc2+1', '0.2.3-rc1', '0.2.2'],
+ ),
'==0.2.3+': (
['0.2.3'],
['0.2.3+rc1', '0.2.4', '0.2.3-rc2'],
@@ -523,32 +527,32 @@ class SpecItemTestCase(unittest.TestCase):
['0.3.4', '0.3.4+b1'],
),
'~1.1.2': (
- ['1.1.3', '1.1.2-alpha', '1.1.2-alpha+b1'],
- ['1.1.1', '1.2.1', '2.1.0'],
+ ['1.1.3', '1.1.2+b1'],
+ ['1.1.1', '1.1.2-alpha', '1.1.2-alpha+b1', '1.2.1', '2.1.0'],
),
'^1.1.2': (
- ['1.1.3', '1.2.1', '1.1.2-alpha', '1.1.2-alpha+b1'],
- ['1.1.1', '2.1.0'],
+ ['1.1.3', '1.1.2+b1', '1.2.1'],
+ ['1.1.1', '1.1.2-alpha', '1.1.2-alpha+b1', '2.1.0'],
),
'^0.1.2': (
- ['0.1.2', '0.1.2-alpha', '0.1.3'],
- ['0.2.0', '1.1.2', '0.1.1'],
+ ['0.1.2', '0.1.2+b1', '0.1.3'],
+ ['0.1.2-alpha', '0.2.0', '1.1.2', '0.1.1'],
),
'^0.0.2': (
- ['0.0.2', '0.0.2-alpha', '0.0.2+abb'],
- ['0.1.0', '0.0.3', '1.0.0'],
+ ['0.0.2', '0.0.2+abb'],
+ ['0.0.2-alpha', '0.1.0', '0.0.3', '1.0.0'],
),
'~=1.4.5': (
['1.4.5', '1.4.10-alpha', '1.4.10'],
- ['1.3.6', '1.4.4', '1.5.0'],
+ ['1.3.6', '1.4.4', '1.4.5-alpha', '1.5.0'],
),
'~=1.4.0': (
['1.4.0', '1.4.10-alpha', '1.4.10'],
- ['1.3.6', '1.3.9', '1.5.0'],
+ ['1.3.6', '1.3.9', '1.4.0-alpha', '1.5.0'],
),
'~=1.4': (
['1.4.0', '1.6.10-alpha', '1.6.10'],
- ['1.3.0', '2.0.0'],
+ ['1.3.0', '1.4.0-alpha', '2.0.0'],
),
}
@@ -646,12 +650,12 @@ class SpecTestCase(unittest.TestCase):
self.assertIn(str(base.SpecItem(spec_text)), repr(spec_list))
matches = {
- # At least 0.1.1 including pre-releases, less than 0.1.2 excluding pre-releases
+ # At least 0.1.1 excluding pre-releases, less than 0.1.2 excluding pre-releases
'>=0.1.1,<0.1.2': (
- ['0.1.1', '0.1.1+4', '0.1.1-alpha'],
- ['0.1.2-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'],
),
- # At least 0.1.0 without pre-releases, less than 0.1.4 excluding pre-releases,
+ # At least 0.1.0 with pre-releases, less than 0.1.4 excluding pre-releases,
# neither 0.1.3-rc1 nor any build of that version,
# not 0.1.0+b3 precisely
'>=0.1.0-,!=0.1.3-rc1,!=0.1.0+b3,<0.1.4': (
diff --git a/tests/test_match.py b/tests/test_match.py
index 16d7e5a..4bf7162 100755
--- a/tests/test_match.py
+++ b/tests/test_match.py
@@ -47,22 +47,13 @@ class MatchTestCase(unittest.TestCase):
'1.0.0',
],
'==0.1.2': [
- '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-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-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.1',
@@ -146,9 +137,9 @@ class MatchTestCase(unittest.TestCase):
spec = semantic_version.Spec(spec_text)
self.assertNotEqual(spec, spec_text)
version = semantic_version.Version(version_text)
+ self.assertIn(version, spec)
self.assertTrue(spec.match(version), "%r does not match %r" % (version, spec))
self.assertTrue(semantic_version.match(spec_text, version_text))
- self.assertTrue(version in spec, "%r not in %r" % (version, spec))
def test_contains(self):
spec = semantic_version.Spec('<=0.1.1')
@@ -164,7 +155,7 @@ class MatchTestCase(unittest.TestCase):
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 lax_spec, "%r should not 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):