diff options
author | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2015-09-15 23:18:13 +0200 |
---|---|---|
committer | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2015-09-15 23:40:59 +0200 |
commit | 2ed3d39c291080c61edd9139370939e1fdc3209a (patch) | |
tree | 22a90dfae0e0fc9fd7949ca18e7e47daa8f8aabb /semantic_version/base.py | |
parent | 4aac5768db2fc158fa87900b54210ecba4dfe6d5 (diff) | |
download | semantic-version-2ed3d39c291080c61edd9139370939e1fdc3209a.tar.gz |
Forbid build metadata ordering (See #18)
SemVer 2.0.0 states that "Build metadata SHOULD be ignored when
determining version precedence".
This means that, when comparing ``0.1.0+1`` to ``0.1.0+bcd``::
>>> Version('0.1.0+1') == Version('0.1.0+bcd')
False
>>> Version('0.1.0+1') != Version('0.1.0+bcd')
True
>>> Version('0.1.0+1') < Version('0.1.0+bcd')
False
>>> Version('0.1.0+1') > Version('0.1.0+bcd')
False
>>> Version('0.1.0+1') <= Version('0.1.0+bcd')
False
>>> Version('0.1.0+1') >= Version('0.1.0+bcd')
False
>>> compare(Version('0.1.0+1'), Version('0.1.0+bcd'))
NotImplemented
This change also has the following effects:
- When including build metadata in a ``Spec``, the only valid options
are ``Spec('==0.1.0+sth')`` and ``Spec('!=0.1.0+sth')``
- The meaning of ``Spec('==0.1.0+')`` is now "Only version 0.1.0 without
build metadata"
- ``Spec('==0.1.0')`` now matches ``Version('0.1.0+anything')``
Diffstat (limited to 'semantic_version/base.py')
-rw-r--r-- | semantic_version/base.py | 73 |
1 files changed, 36 insertions, 37 deletions
diff --git a/semantic_version/base.py b/semantic_version/base.py index 841c5f3..982fcc8 100644 --- a/semantic_version/base.py +++ b/semantic_version/base.py @@ -290,20 +290,14 @@ class Version(object): return 0 def build_cmp(a, b): - """Compare build components. + """Compare build metadata. - Special rule: a version without build component has lower - precedence than one with a build component. + Special rule: there is no ordering on build metadata. """ - if a and b: - return identifier_list_cmp(a, b) - elif a: - # Versions with build field have higher precedence - return 1 - elif b: - return -1 - else: + if a == b: return 0 + else: + return NotImplemented def make_optional(orig_cmp_fun): """Convert a cmp-like function to consider 'None == *'.""" @@ -332,10 +326,7 @@ class Version(object): build_cmp, ] - def __cmp__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - + def __compare(self, other): field_pairs = zip(self, other) comparison_functions = self._comparison_functions(partial=self.partial or other.partial) comparisons = zip(comparison_functions, self, other) @@ -347,44 +338,48 @@ class Version(object): return 0 - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - - return self.__cmp__(other) == 0 - def __hash__(self): return hash((self.major, self.minor, self.patch, self.prerelease, self.build)) - def __ne__(self, other): + def __cmp__(self, other): if not isinstance(other, self.__class__): return NotImplemented + return self.__compare(other) - return self.__cmp__(other) != 0 + def __compare_helper(self, other, condition, notimpl_target): + """Helper for comparison. - def __lt__(self, other): + Allows the caller to provide: + - The condition + - The return value if the comparison is meaningless (ie versions with + build metadata). + """ if not isinstance(other, self.__class__): return NotImplemented - return self.__cmp__(other) < 0 + cmp_res = self.__cmp__(other) + if cmp_res is NotImplemented: + return notimpl_target - def __le__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented + return condition(cmp_res) - return self.__cmp__(other) <= 0 + def __eq__(self, other): + return self.__compare_helper(other, lambda x: x == 0, notimpl_target=False) - def __gt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented + def __ne__(self, other): + return self.__compare_helper(other, lambda x: x != 0, notimpl_target=True) - return self.__cmp__(other) > 0 + def __lt__(self, other): + return self.__compare_helper(other, lambda x: x < 0, notimpl_target=False) - def __ge__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented + def __le__(self, other): + return self.__compare_helper(other, lambda x: x <= 0, notimpl_target=False) + + def __gt__(self, other): + return self.__compare_helper(other, lambda x: x > 0, notimpl_target=False) - return self.__cmp__(other) >= 0 + def __ge__(self, other): + return self.__compare_helper(other, lambda x: x >= 0, notimpl_target=False) class SpecItem(object): @@ -420,6 +415,10 @@ class SpecItem(object): kind, version = match.groups() spec = Version(version, partial=True) + if spec.build is not None and kind not in (cls.KIND_EQUAL, cls.KIND_NEQ): + raise ValueError( + "Invalid requirement specification %r: build numbers have no ordering." + % requirement_string) return (kind, spec) def match(self, version): |