Commit 4c833892 by Sébastien Eustace Committed by GitHub

Fix version comparison for versions with precision > 3 (#351)

Fixes #350
parent 490ddf00
...@@ -6,7 +6,9 @@ MODIFIERS = ( ...@@ -6,7 +6,9 @@ MODIFIERS = (
"([+-]?([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?" "([+-]?([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?"
) )
_COMPLETE_VERSION = "v?(\d+)(?:\.(\d+))?(?:\.(\d+))?{}(?:\+[^\s]+)?".format(MODIFIERS) _COMPLETE_VERSION = "v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?{}(?:\+[^\s]+)?".format(
MODIFIERS
)
COMPLETE_VERSION = re.compile("(?i)" + _COMPLETE_VERSION) COMPLETE_VERSION = re.compile("(?i)" + _COMPLETE_VERSION)
......
...@@ -20,6 +20,7 @@ class Version(VersionRange): ...@@ -20,6 +20,7 @@ class Version(VersionRange):
major, # type: int major, # type: int
minor=None, # type: Union[int, None] minor=None, # type: Union[int, None]
patch=None, # type: Union[int, None] patch=None, # type: Union[int, None]
rest=None, # type: Union[int, None]
pre=None, # type: Union[str, None] pre=None, # type: Union[str, None]
build=None, # type: Union[str, None] build=None, # type: Union[str, None]
text=None, # type: Union[str, None] text=None, # type: Union[str, None]
...@@ -44,10 +45,17 @@ class Version(VersionRange): ...@@ -44,10 +45,17 @@ class Version(VersionRange):
if self._precision is not None: if self._precision is not None:
self._precision += 1 self._precision += 1
if rest is None:
rest = 0
else:
if self._precision is not None:
self._precision += 1
if precision is not None: if precision is not None:
self._precision = precision self._precision = precision
self._patch = int(patch) self._patch = int(patch)
self._rest = int(rest)
if text is None: if text is None:
parts = [str(major)] parts = [str(major)]
...@@ -57,6 +65,9 @@ class Version(VersionRange): ...@@ -57,6 +65,9 @@ class Version(VersionRange):
if self._precision >= 3 or patch != 0: if self._precision >= 3 or patch != 0:
parts.append(str(patch)) parts.append(str(patch))
if self._precision >= 4 or rest != 0:
parts.append(str(rest))
text = ".".join(parts) text = ".".join(parts)
if pre: if pre:
text += "-{}".format(pre) text += "-{}".format(pre)
...@@ -94,6 +105,10 @@ class Version(VersionRange): ...@@ -94,6 +105,10 @@ class Version(VersionRange):
return self._patch return self._patch
@property @property
def rest(self): # type: () -> int
return self._rest
@property
def prerelease(self): # type: () -> List[str] def prerelease(self): # type: () -> List[str]
return self._prerelease return self._prerelease
...@@ -185,14 +200,15 @@ class Version(VersionRange): ...@@ -185,14 +200,15 @@ class Version(VersionRange):
major = int(match.group(1)) major = int(match.group(1))
minor = int(match.group(2)) if match.group(2) else None minor = int(match.group(2)) if match.group(2) else None
patch = int(match.group(3)) if match.group(3) else None patch = int(match.group(3)) if match.group(3) else None
rest = int(match.group(4)) if match.group(4) else None
pre = match.group(4) pre = match.group(5)
build = match.group(5) build = match.group(6)
if build: if build:
build = build.lstrip("+") build = build.lstrip("+")
return Version(major, minor, patch, pre, build, text) return Version(major, minor, patch, rest, pre, build, text)
def is_any(self): def is_any(self):
return False return False
...@@ -289,9 +305,6 @@ class Version(VersionRange): ...@@ -289,9 +305,6 @@ class Version(VersionRange):
if not build: if not build:
return return
if build == "0":
return
if build.startswith("post"): if build.startswith("post"):
build = build.lstrip("post") build = build.lstrip("post")
...@@ -339,6 +352,9 @@ class Version(VersionRange): ...@@ -339,6 +352,9 @@ class Version(VersionRange):
if self.patch != other.patch: if self.patch != other.patch:
return self._cmp_parts(self.patch, other.patch) return self._cmp_parts(self.patch, other.patch)
if self.rest != other.rest:
return self._cmp_parts(self.rest, other.rest)
# Pre-releases always come before no pre-release string. # Pre-releases always come before no pre-release string.
if not self.is_prerelease() and other.is_prerelease(): if not self.is_prerelease() and other.is_prerelease():
return 1 return 1
...@@ -380,7 +396,7 @@ class Version(VersionRange): ...@@ -380,7 +396,7 @@ class Version(VersionRange):
if a_part == b_part: if a_part == b_part:
continue continue
# Missing parts come before present ones. # Missing parts come after present ones.
if a_part is None: if a_part is None:
return -1 return -1
...@@ -408,6 +424,7 @@ class Version(VersionRange): ...@@ -408,6 +424,7 @@ class Version(VersionRange):
self._major == other.major self._major == other.major
and self._minor == other.minor and self._minor == other.minor
and self._patch == other.patch and self._patch == other.patch
and self._rest == other.rest
and self._prerelease == other.prerelease and self._prerelease == other.prerelease
and self._build == other.build and self._build == other.build
) )
......
...@@ -22,7 +22,7 @@ from poetry.semver import VersionUnion ...@@ -22,7 +22,7 @@ from poetry.semver import VersionUnion
("=1.2.3", Version(1, 2, 3)), ("=1.2.3", Version(1, 2, 3)),
("1.2.3", Version(1, 2, 3)), ("1.2.3", Version(1, 2, 3)),
("=1.0", Version(1, 0, 0)), ("=1.0", Version(1, 0, 0)),
("1.2.3b5", Version(1, 2, 3, "b5")), ("1.2.3b5", Version(1, 2, 3, pre="b5")),
(">= 1.2.3", VersionRange(min=Version(1, 2, 3), include_min=True)), (">= 1.2.3", VersionRange(min=Version(1, 2, 3), include_min=True)),
(">dev", VersionRange(min=Version(0, 0, pre="dev"))), # Issue 206 (">dev", VersionRange(min=Version(0, 0, pre="dev"))), # Issue 206
], ],
...@@ -59,8 +59,11 @@ def test_parse_constraint_wildcard(input, constraint): ...@@ -59,8 +59,11 @@ def test_parse_constraint_wildcard(input, constraint):
("~1.0.0", VersionRange(Version(1, 0, 0), Version(1, 1, 0), True)), ("~1.0.0", VersionRange(Version(1, 0, 0), Version(1, 1, 0), True)),
("~1.2", VersionRange(Version(1, 2, 0), Version(1, 3, 0), True)), ("~1.2", VersionRange(Version(1, 2, 0), Version(1, 3, 0), True)),
("~1.2.3", VersionRange(Version(1, 2, 3), Version(1, 3, 0), True)), ("~1.2.3", VersionRange(Version(1, 2, 3), Version(1, 3, 0), True)),
("~1.2-beta", VersionRange(Version(1, 2, 0, "beta"), Version(1, 3, 0), True)), (
("~1.2-b2", VersionRange(Version(1, 2, 0, "b2"), Version(1, 3, 0), True)), "~1.2-beta",
VersionRange(Version(1, 2, 0, pre="beta"), Version(1, 3, 0), True),
),
("~1.2-b2", VersionRange(Version(1, 2, 0, pre="b2"), Version(1, 3, 0), True)),
("~0.3", VersionRange(Version(0, 3, 0), Version(0, 4, 0), True)), ("~0.3", VersionRange(Version(0, 3, 0), Version(0, 4, 0), True)),
("~3.5", VersionRange(Version(3, 5, 0), Version(3, 6, 0), True)), ("~3.5", VersionRange(Version(3, 5, 0), Version(3, 6, 0), True)),
("~=3.5", VersionRange(Version(3, 5, 0), Version(4, 0, 0), True)), # PEP 440 ("~=3.5", VersionRange(Version(3, 5, 0), Version(4, 0, 0), True)), # PEP 440
...@@ -80,7 +83,7 @@ def test_parse_constraint_tilde(input, constraint): ...@@ -80,7 +83,7 @@ def test_parse_constraint_tilde(input, constraint):
("^1.2", VersionRange(Version(1, 2, 0), Version(2, 0, 0), True)), ("^1.2", VersionRange(Version(1, 2, 0), Version(2, 0, 0), True)),
( (
"^1.2.3-beta.2", "^1.2.3-beta.2",
VersionRange(Version(1, 2, 3, "beta.2"), Version(2, 0, 0), True), VersionRange(Version(1, 2, 3, pre="beta.2"), Version(2, 0, 0), True),
), ),
("^1.2.3", VersionRange(Version(1, 2, 3), Version(2, 0, 0), True)), ("^1.2.3", VersionRange(Version(1, 2, 3), Version(2, 0, 0), True)),
("^0.2.3", VersionRange(Version(0, 2, 3), Version(0, 3, 0), True)), ("^0.2.3", VersionRange(Version(0, 2, 3), Version(0, 3, 0), True)),
...@@ -173,3 +176,21 @@ def test_parse_constraints_negative_wildcard(input, constraint): ...@@ -173,3 +176,21 @@ def test_parse_constraints_negative_wildcard(input, constraint):
) )
def test_constraints_keep_version_precision(input, expected): def test_constraints_keep_version_precision(input, expected):
assert str(parse_constraint(input)) == expected assert str(parse_constraint(input)) == expected
@pytest.mark.parametrize(
"unsorted, sorted_",
[
(["1.0.3", "1.0.2", "1.0.1"], ["1.0.1", "1.0.2", "1.0.3"]),
(["1.0.0.2", "1.0.0.0rc2"], ["1.0.0.0rc2", "1.0.0.2"]),
(["1.0.0.0", "1.0.0.0rc2"], ["1.0.0.0rc2", "1.0.0.0"]),
(["1.0.0.0.0", "1.0.0.0rc2"], ["1.0.0.0rc2", "1.0.0.0.0"]),
(["1.0.0rc2", "1.0.0rc1"], ["1.0.0rc1", "1.0.0rc2"]),
(["1.0.0rc2", "1.0.0b1"], ["1.0.0b1", "1.0.0rc2"]),
],
)
def test_versions_are_sortable(unsorted, sorted_):
unsorted = [parse_constraint(u) for u in unsorted]
sorted_ = [parse_constraint(s) for s in sorted_]
assert sorted(unsorted) == sorted_
...@@ -11,18 +11,18 @@ from poetry.semver import VersionRange ...@@ -11,18 +11,18 @@ from poetry.semver import VersionRange
("1.0.0", Version(1, 0, 0)), ("1.0.0", Version(1, 0, 0)),
("1", Version(1, 0, 0)), ("1", Version(1, 0, 0)),
("1.0", Version(1, 0, 0)), ("1.0", Version(1, 0, 0)),
("1b1", Version(1, 0, 0, "beta1")), ("1b1", Version(1, 0, 0, pre="beta1")),
("1.0b1", Version(1, 0, 0, "beta1")), ("1.0b1", Version(1, 0, 0, pre="beta1")),
("1.0.0b1", Version(1, 0, 0, "beta1")), ("1.0.0b1", Version(1, 0, 0, pre="beta1")),
("1.0.0-b1", Version(1, 0, 0, "beta1")), ("1.0.0-b1", Version(1, 0, 0, pre="beta1")),
("1.0.0-beta.1", Version(1, 0, 0, "beta1")), ("1.0.0-beta.1", Version(1, 0, 0, pre="beta1")),
("1.0.0+1", Version(1, 0, 0, None, "1")), ("1.0.0+1", Version(1, 0, 0, build="1")),
("1.0.0-1", Version(1, 0, 0, None, "1")), ("1.0.0-1", Version(1, 0, 0, build="1")),
("1.0.0.0", Version(1, 0, 0)), ("1.0.0.0", Version(1, 0, 0)),
("1.0.0-post", Version(1, 0, 0)), ("1.0.0-post", Version(1, 0, 0)),
("1.0.0-post1", Version(1, 0, 0, None, "1")), ("1.0.0-post1", Version(1, 0, 0, build="1")),
("0.6c", Version(0, 6, 0, "rc0")), ("0.6c", Version(0, 6, 0, pre="rc0")),
("0.6pre", Version(0, 6, 0, "rc0")), ("0.6pre", Version(0, 6, 0, pre="rc0")),
], ],
) )
def test_parse_valid(input, version): def test_parse_valid(input, version):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment