Skip to content

Commit

Permalink
version: fix "next_" methods and increase test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
radoering committed Jul 31, 2022
1 parent 7efc33e commit 918a215
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 17 deletions.
57 changes: 45 additions & 12 deletions src/poetry/core/version/pep440/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import dataclasses
import functools
import warnings

from typing import TYPE_CHECKING
from typing import Any
Expand Down Expand Up @@ -201,46 +202,62 @@ def is_unstable(self) -> bool:
def is_stable(self) -> bool:
return not self.is_unstable()

def _is_increment_required(self) -> bool:
return self.is_stable() or (not self.is_prerelease() and self.is_postrelease())

def next_major(self: T) -> T:
release = self.release
if self.is_stable() or Release(self.release.major, 0, 0) < self.release:
release = self.release.next_major()
if self._is_increment_required() or Release(release.major, 0, 0) < release:
release = release.next_major()
return self.__class__(epoch=self.epoch, release=release)

def next_minor(self: T) -> T:
release = self.release
if (
self.is_stable()
or Release(self.release.major, self.release.minor, 0) < self.release
self._is_increment_required()
or Release(release.major, release.minor, 0) < release
):
release = self.release.next_minor()
release = release.next_minor()
return self.__class__(epoch=self.epoch, release=release)

def next_patch(self: T) -> T:
return self.__class__(
epoch=self.epoch,
release=self.release.next_patch() if self.is_stable() else self.release,
)
release = self.release
if (
self._is_increment_required()
or Release(release.major, release.minor, release.patch) < release
):
release = release.next_patch()
return self.__class__(epoch=self.epoch, release=release)

def next_prerelease(self: T, next_phase: bool = False) -> PEP440Version:
if self.is_stable():
warnings.warn(
"Calling next_prerelease() on a stable release is deprecated for its"
" ambiguity. Use next_major(), next_minor(), etc. together with"
" first_prerelease()",
DeprecationWarning,
stacklevel=2,
)
if self.is_prerelease():
assert self.pre is not None
pre = self.pre.next_phase() if next_phase else self.pre.next()
if not self.is_devrelease() or self.is_postrelease():
pre = self.pre.next_phase() if next_phase else self.pre.next()
else:
pre = self.pre
else:
pre = ReleaseTag(RELEASE_PHASE_ID_ALPHA)
return self.__class__(epoch=self.epoch, release=self.release, pre=pre)

def next_postrelease(self: T) -> T:
if self.is_postrelease():
assert self.post is not None
post = self.post.next()
post = self.post.next() if self.dev is None else self.post
else:
post = ReleaseTag(RELEASE_PHASE_ID_POST)
return self.__class__(
epoch=self.epoch,
release=self.release,
pre=self.pre,
dev=self.dev,
post=post,
)

Expand All @@ -249,6 +266,13 @@ def next_devrelease(self: T) -> T:
assert self.dev is not None
dev = self.dev.next()
else:
warnings.warn(
"Calling next_devrelease() on a non dev release is deprecated for its"
" ambiguity. Use next_major(), next_minor(), etc. together with"
" first_devrelease()",
DeprecationWarning,
stacklevel=2,
)
dev = ReleaseTag(RELEASE_PHASE_ID_DEV)
return self.__class__(
epoch=self.epoch,
Expand All @@ -265,6 +289,15 @@ def first_prerelease(self: T) -> T:
pre=ReleaseTag(RELEASE_PHASE_ID_ALPHA),
)

def first_devrelease(self: T) -> T:
return self.__class__(
epoch=self.epoch,
release=self.release,
pre=self.pre,
post=self.post,
dev=ReleaseTag(RELEASE_PHASE_ID_DEV),
)

def replace(self: T, **kwargs: Any) -> T:
return self.__class__(
**{
Expand Down
146 changes: 141 additions & 5 deletions tests/semver/test_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,11 +293,147 @@ def test_difference() -> None:
@pytest.mark.parametrize(
"version, expected",
[
("1.2.3", "1.2.3-dev.0"),
("1.2.3-alpha.0", "1.2.3-alpha.0-dev.0"),
("1.2.3-dev.0", "1.2.3-dev.1"),
("1", "2"),
("2!1", "2!2"),
("1+local", "2"),
("1.2", "2.0"),
("1.2.3", "2.0.0"),
("1.2.3.4", "2.0.0.0"),
("1.dev0", "1"),
("1.2.dev0", "2.0"),
("1.post1", "2"),
("1.2.post1", "2.0"),
("1.post1.dev0", "2"),
("1.2.post1.dev0", "2.0"),
("1.a1", "1"),
("1.2a1", "2.0"),
("1.a1.post2", "1"),
("1.2a1.post2", "2.0"),
("1.a1.post2.dev0", "1"),
("1.2a1.post2.dev0", "2.0"),
],
)
def test_next_devrelease(version: str, expected: str) -> None:
def test_next_major(version: str, expected: str) -> None:
v = Version.parse(version)
assert v.next_devrelease() == Version.parse(expected)
assert str(v.next_major()) == expected


@pytest.mark.parametrize(
"version, expected",
[
("1", "1.1"),
("1.2", "1.3"),
("2!1.2", "2!1.3"),
("1.2+local", "1.3"),
("1.2.3", "1.3.0"),
("1.2.3.4", "1.3.0.0"),
("1.dev0", "1"),
("1.2dev0", "1.2"),
("1.2.3dev0", "1.3.0"),
("1.post1", "1.1"),
("1.2.post1", "1.3"),
("1.2.3.post1", "1.3.0"),
("1.post1.dev0", "1.1"),
("1.2.post1.dev0", "1.3"),
("1.a1", "1"),
("1.2a1", "1.2"),
("1.2.3a1", "1.3.0"),
("1.a1.post2", "1"),
("1.2a1.post2", "1.2"),
("1.2.3a1.post2", "1.3.0"),
("1.a1.post2.dev0", "1"),
("1.2a1.post2.dev0", "1.2"),
("1.2.3a1.post2.dev0", "1.3.0"),
],
)
def test_next_minor(version: str, expected: str) -> None:
v = Version.parse(version)
assert str(v.next_minor()) == expected


@pytest.mark.parametrize(
"version, expected",
[
("1", "1.0.1"),
("1.2", "1.2.1"),
("1.2.3", "1.2.4"),
("2!1.2.3", "2!1.2.4"),
("1.2.3+local", "1.2.4"),
("1.2.3.4", "1.2.4.0"),
("1.dev0", "1"),
("1.2dev0", "1.2"),
("1.2.3dev0", "1.2.3"),
("1.2.3.4dev0", "1.2.4.0"),
("1.post1", "1.0.1"),
("1.2.post1", "1.2.1"),
("1.2.3.post1", "1.2.4"),
("1.post1.dev0", "1.0.1"),
("1.2.post1.dev0", "1.2.1"),
("1.2.3.post1.dev0", "1.2.4"),
("1.a1", "1"),
("1.2a1", "1.2"),
("1.2.3a1", "1.2.3"),
("1.2.3.4a1", "1.2.4.0"),
("1.a1.post2", "1"),
("1.2a1.post2", "1.2"),
("1.2.3a1.post2", "1.2.3"),
("1.2.3.4a1.post2", "1.2.4.0"),
("1.a1.post2.dev0", "1"),
("1.2a1.post2.dev0", "1.2"),
("1.2.3a1.post2.dev0", "1.2.3"),
("1.2.3.4a1.post2.dev0", "1.2.4.0"),
],
)
def test_next_patch(version: str, expected: str) -> None:
v = Version.parse(version)
assert str(v.next_patch()) == expected


@pytest.mark.parametrize(
"version, expected",
[
("1.2a1", "1.2a2"),
("2!1.2a1", "2!1.2a2"),
("1.2dev0", "1.2a0"),
("1.2a1.dev0", "1.2a1"),
("1.2a1.post1.dev0", "1.2a2"),
],
)
def test_next_prerelease(version: str, expected: str) -> None:
v = Version.parse(version)
assert str(v.next_prerelease()) == expected


@pytest.mark.parametrize(
"version, expected",
[
("1", "1.post0"),
("1.post1", "1.post2"),
("9!1.2.3.4", "9!1.2.3.4.post0"),
("9!1.2.3.4.post2", "9!1.2.3.4.post3"),
("1.dev0", "1.post0"),
("1.post1.dev0", "1.post1"),
("1a1", "1a1.post0"),
("1a1.dev0", "1a1.post0"),
("1a1.post2", "1a1.post3"),
("1a1.post2.dev0", "1a1.post2"),
],
)
def test_next_postrelease(version: str, expected: str) -> None:
v = Version.parse(version)
assert str(v.next_postrelease()) == expected


def test_next_devrelease() -> None:
v = Version.parse("9!1.2.3a1.post2.dev3")
assert str(v.next_devrelease()) == "9!1.2.3a1.post2.dev4"


def test_next_firstprerelease() -> None:
v = Version.parse("9!1.2.3a1.post2.dev3")
assert str(v.first_prerelease()) == "9!1.2.3a0"


def test_next_firstdevrelease() -> None:
v = Version.parse("9!1.2.3a1.post2.dev3")
assert str(v.first_devrelease()) == "9!1.2.3a1.post2.dev0"

0 comments on commit 918a215

Please sign in to comment.