From 8066b94316661376428126b6a8ca2fcad2003cef Mon Sep 17 00:00:00 2001 From: Apeksha_2022 <70309060+Apeksha9389@users.noreply.github.com> Date: Sat, 17 Oct 2026 18:21:07 +0530 Subject: [PATCH] fix: preserve version order when switching prerelease tokens --- changelog.d/497.bugfix.rst | 4 ++++ src/semver/version.py | 13 ++++++++++++- tests/test_bump.py | 3 ++- tests/test_issue484.py | 21 +++++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 changelog.d/497.bugfix.rst diff --git a/changelog.d/497.bugfix.rst b/changelog.d/497.bugfix.rst new file mode 100644 index 0000000..46743c9 --- /dev/null +++ b/changelog.d/497.bugfix.rst @@ -0,0 +1,4 @@ +``Version.next_version("prerelease", prerelease_token=...)`` now advances the +patch version when switching tokens would otherwise produce a lower version. +For example, switching from ``1.2.3-rc.1`` to ``alpha`` returns +``1.2.4-alpha.1``. Forward token changes retain the current patch version. diff --git a/src/semver/version.py b/src/semver/version.py index 7ead382..739e999 100644 --- a/src/semver/version.py +++ b/src/semver/version.py @@ -518,6 +518,12 @@ def next_version(self, part: str, prerelease_token: str = "rc") -> "Version": >>> str(semver.Version.parse("0.1.4").next_version("prerelease")) '0.1.5-rc.1' + Switching to an earlier prerelease token advances the patch version + so the result remains greater than the original version: + + >>> str(semver.Version.parse("1.2.3-rc.1").next_version("prerelease", "alpha")) + '1.2.4-alpha.1' + :param part: One of "major", "minor", "patch", or "prerelease" :param prerelease_token: prefix string of prerelease, defaults to 'rc' :return: new object with the appropriate part raised @@ -562,7 +568,12 @@ def next_version(self, part: str, prerelease_token: str = "rc") -> "Version": version.prerelease == prerelease_token or version.prerelease.startswith(prerelease_token + ".") ): - return version.replace(prerelease=f"{prerelease_token}.1", build=None) + candidate = version.replace( + prerelease=f"{prerelease_token}.1", build=None + ) + if candidate > version: + return candidate + return version.bump_patch().bump_prerelease(prerelease_token) return version.bump_prerelease(prerelease_token, bump_when_empty=True) @_comparator diff --git a/tests/test_bump.py b/tests/test_bump.py index 767d38f..0eacaee 100644 --- a/tests/test_bump.py +++ b/tests/test_bump.py @@ -160,7 +160,7 @@ def test_should_ignore_build_on_prerelease_bump(): ("1.2.3-alpha.beta.gamma.1", "alpha", "1.2.3-alpha.beta.gamma.2"), ("1.2.3-rc3", "rc", "1.2.3-rc4"), ("1.2.3-rc.3", "rc", "1.2.3-rc.4"), - ("1.2.3-alphaXbeta9", "alpha.beta", "1.2.3-alpha.beta.1"), + ("1.2.3-alphaXbeta9", "alpha.beta", "1.2.4-alpha.beta.1"), ], ) def test_next_version_matches_literal_prerelease_token_family( @@ -170,6 +170,7 @@ def test_next_version_matches_literal_prerelease_token_family( result = original.next_version("prerelease", token) assert str(result) == expected assert Version.parse(str(result)).to_tuple() == result.to_tuple() + assert result > original assert str(original) == version diff --git a/tests/test_issue484.py b/tests/test_issue484.py index 5b11d68..d4df956 100644 --- a/tests/test_issue484.py +++ b/tests/test_issue484.py @@ -1,8 +1,29 @@ """Regression test for issue #484: next_version with old-style prereleases.""" +import pytest + from semver import Version +@pytest.mark.parametrize( + "current, token, expected", + [ + ("1.2.3-rc.1", "alpha", "1.2.4-alpha.1"), + ("1.2.3-beta.3", "alpha", "1.2.4-alpha.1"), + ("1.2.3-rc.1+build.7", "dev", "1.2.4-dev.1"), + ("1.2.3-rc3", "alpha", "1.2.4-alpha.1"), + ("1.2.3-rc.1", "2", "1.2.4-2.1"), + ("1.2.3-alpha.4", "rc", "1.2.3-rc.1"), + ], +) +def test_token_switch_preserves_version_order(current, token, expected): + original = Version.parse(current) + result = original.next_version("prerelease", token) + assert str(result) == expected + assert result > original + assert str(original) == current + + def test_issue_484_rc3_to_rc4(): """Old-style prerelease 'rc3' should bump to 'rc4', not reset to 'rc.1'.""" v = Version.parse("0.1.2-rc3")