Skip to content

Commit

Permalink
Fix version comparison for versions with precision > 3 (python-poetry…
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater authored Jul 28, 2018
1 parent 490ddf0 commit 4c83389
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 22 deletions.
4 changes: 3 additions & 1 deletion poetry/semver/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"([+-]?([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)

Expand Down
31 changes: 24 additions & 7 deletions poetry/semver/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def __init__(
major, # type: int
minor=None, # type: Union[int, None]
patch=None, # type: Union[int, None]
rest=None, # type: Union[int, None]
pre=None, # type: Union[str, None]
build=None, # type: Union[str, None]
text=None, # type: Union[str, None]
Expand All @@ -44,10 +45,17 @@ def __init__(
if self._precision is not None:
self._precision += 1

if rest is None:
rest = 0
else:
if self._precision is not None:
self._precision += 1

if precision is not None:
self._precision = precision

self._patch = int(patch)
self._rest = int(rest)

if text is None:
parts = [str(major)]
Expand All @@ -57,6 +65,9 @@ def __init__(
if self._precision >= 3 or patch != 0:
parts.append(str(patch))

if self._precision >= 4 or rest != 0:
parts.append(str(rest))

text = ".".join(parts)
if pre:
text += "-{}".format(pre)
Expand Down Expand Up @@ -93,6 +104,10 @@ def minor(self): # type: () -> int
def patch(self): # type: () -> int
return self._patch

@property
def rest(self): # type: () -> int
return self._rest

@property
def prerelease(self): # type: () -> List[str]
return self._prerelease
Expand Down Expand Up @@ -185,14 +200,15 @@ def parse(cls, text): # type: (str) -> Version
major = int(match.group(1))
minor = int(match.group(2)) if match.group(2) 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)
build = match.group(5)
pre = match.group(5)
build = match.group(6)

if build:
build = build.lstrip("+")

return Version(major, minor, patch, pre, build, text)
return Version(major, minor, patch, rest, pre, build, text)

def is_any(self):
return False
Expand Down Expand Up @@ -289,9 +305,6 @@ def _normalize_build(self, build): # type: (str) -> str
if not build:
return

if build == "0":
return

if build.startswith("post"):
build = build.lstrip("post")

Expand Down Expand Up @@ -339,6 +352,9 @@ def _cmp(self, other):
if 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.
if not self.is_prerelease() and other.is_prerelease():
return 1
Expand Down Expand Up @@ -380,7 +396,7 @@ def _cmp_lists(self, a, b): # type: (List, List) -> int
if a_part == b_part:
continue

# Missing parts come before present ones.
# Missing parts come after present ones.
if a_part is None:
return -1

Expand Down Expand Up @@ -408,6 +424,7 @@ def __eq__(self, other): # type: (Version) -> bool
self._major == other.major
and self._minor == other.minor
and self._patch == other.patch
and self._rest == other.rest
and self._prerelease == other.prerelease
and self._build == other.build
)
Expand Down
29 changes: 25 additions & 4 deletions tests/semver/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
("=1.2.3", Version(1, 2, 3)),
("1.2.3", Version(1, 2, 3)),
("=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)),
(">dev", VersionRange(min=Version(0, 0, pre="dev"))), # Issue 206
],
Expand Down Expand Up @@ -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.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-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)),
("~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
Expand All @@ -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.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)),
("^0.2.3", VersionRange(Version(0, 2, 3), Version(0, 3, 0), True)),
Expand Down Expand Up @@ -173,3 +176,21 @@ def test_parse_constraints_negative_wildcard(input, constraint):
)
def test_constraints_keep_version_precision(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_
20 changes: 10 additions & 10 deletions tests/semver/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
("1.0.0", Version(1, 0, 0)),
("1", Version(1, 0, 0)),
("1.0", Version(1, 0, 0)),
("1b1", Version(1, 0, 0, "beta1")),
("1.0b1", Version(1, 0, 0, "beta1")),
("1.0.0b1", Version(1, 0, 0, "beta1")),
("1.0.0-b1", Version(1, 0, 0, "beta1")),
("1.0.0-beta.1", Version(1, 0, 0, "beta1")),
("1.0.0+1", Version(1, 0, 0, None, "1")),
("1.0.0-1", Version(1, 0, 0, None, "1")),
("1b1", Version(1, 0, 0, pre="beta1")),
("1.0b1", Version(1, 0, 0, pre="beta1")),
("1.0.0b1", Version(1, 0, 0, pre="beta1")),
("1.0.0-b1", Version(1, 0, 0, pre="beta1")),
("1.0.0-beta.1", Version(1, 0, 0, pre="beta1")),
("1.0.0+1", Version(1, 0, 0, build="1")),
("1.0.0-1", Version(1, 0, 0, build="1")),
("1.0.0.0", Version(1, 0, 0)),
("1.0.0-post", Version(1, 0, 0)),
("1.0.0-post1", Version(1, 0, 0, None, "1")),
("0.6c", Version(0, 6, 0, "rc0")),
("0.6pre", Version(0, 6, 0, "rc0")),
("1.0.0-post1", Version(1, 0, 0, build="1")),
("0.6c", Version(0, 6, 0, pre="rc0")),
("0.6pre", Version(0, 6, 0, pre="rc0")),
],
)
def test_parse_valid(input, version):
Expand Down

0 comments on commit 4c83389

Please sign in to comment.