diff --git a/docs/usage.rst b/docs/usage.rst index 91e4d069..fd2af5fa 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -244,8 +244,8 @@ It is possible to convert a :class:`semver.VersionInfo` instance: (5, 4, 2, None, None) -Increasing Parts of a Version ------------------------------ +Raising Parts of a Version +-------------------------- The ``semver`` module contains the following functions to raise parts of a version: @@ -276,6 +276,30 @@ a version: Likewise the module level functions :func:`semver.bump_major`. +Increasing Parts of a Version Taking into Account Prereleases +------------------------------------------------------------- + +.. versionadded:: 2.10.0 + Added :func:`semver.VersionInfo.next_version`. + +If you want to raise your version and take prereleases into account, +the function :func:`semver.VersionInfo.next_version` would perhaps a +better fit. + + +.. code-block:: python + + >>> v = semver.VersionInfo.parse("3.4.5-pre.2+build.4") + >>> str(v.next_version(part="prerelease")) + '3.4.5-pre.3' + >>> str(semver.VersionInfo.parse("3.4.5-pre.2+build.4").next_version(part="patch")) + '3.4.5' + >>> str(semver.VersionInfo.parse("3.4.5+build.4").next_version(part="patch")) + '3.4.5' + >>> str(semver.VersionInfo.parse("0.1.4").next_version("prerelease")) + '0.1.5-rc.1' + + Comparing Versions ------------------ diff --git a/semver.py b/semver.py index a5739b16..35192ed9 100644 --- a/semver.py +++ b/semver.py @@ -422,6 +422,53 @@ def compare(self, other): return rccmp + def next_version(self, part, prerelease_token="rc"): + """ + Determines next version, preserving natural order. + + .. versionadded:: 2.10.0 + + This function is taking prereleases into account. + The "major", "minor", and "patch" raises the respective parts like + the ``bump_*`` functions. The real difference is using the + "preprelease" part. It gives you the next patch version of the prerelease, + for example: + + >>> str(semver.VersionInfo.parse("0.1.4").next_version("prerelease")) + '0.1.5-rc.1' + + :param part: One of "major", "minor", "patch", or "prerelease" + :param prerelease_token: prefix string of prerelease, defaults to 'rc' + :return: + """ + validparts = { + "major", + "minor", + "patch", + "prerelease", + # "build", # currently not used + } + if part not in validparts: + raise ValueError( + "Invalid part. Expected one of {validparts}, but got {part!r}".format( + validparts=validparts, part=part + ) + ) + version = self + if (version.prerelease or version.build) and ( + part == "patch" + or (part == "minor" and version.patch == 0) + or (part == "major" and version.minor == version.patch == 0) + ): + return version.replace(prerelease=None, build=None) + + if part in ("major", "minor", "patch"): + return str(getattr(version, "bump_" + part)()) + + if not version.prerelease: + version = version.bump_patch() + return version.bump_prerelease(prerelease_token) + @comparator def __eq__(self, other): return self.compare(other) == 0 @@ -709,7 +756,10 @@ def max_ver(ver1, ver2): >>> semver.max_ver("1.0.0", "2.0.0") '2.0.0' """ - ver1 = VersionInfo.parse(ver1) + if isinstance(ver1, str): + ver1 = VersionInfo.parse(ver1) + elif not isinstance(ver1, VersionInfo): + raise TypeError() cmp_res = ver1.compare(ver2) if cmp_res >= 0: return str(ver1) @@ -898,6 +948,7 @@ def replace(version, **parts): return str(VersionInfo.parse(version).replace(**parts)) +# ---- CLI def cmd_bump(args): """ Subcommand: Bumps a version. @@ -953,6 +1004,19 @@ def cmd_compare(args): return str(compare(args.version1, args.version2)) +def cmd_nextver(args): + """ + Subcommand: Determines the next version, taking prereleases into account. + + Synopsis: nextver + + :param args: The parsed arguments + :type args: :class:`argparse.Namespace` + """ + version = VersionInfo.parse(args.version) + return str(version.next_version(args.part)) + + def createparser(): """ Create an :class:`argparse.ArgumentParser` instance. @@ -995,6 +1059,15 @@ def createparser(): parser_check.set_defaults(func=cmd_check) parser_check.add_argument("version", help="Version to check") + # Create the nextver subcommand + parser_nextver = s.add_parser( + "nextver", help="Determines the next version, taking prereleases into account." + ) + parser_nextver.set_defaults(func=cmd_nextver) + parser_nextver.add_argument("version", help="Version to raise") + parser_nextver.add_argument( + "part", help="One of 'major', 'minor', 'patch', or 'prerelease'" + ) return parser diff --git a/test_semver.py b/test_semver.py index 5daf3f1a..8ac42c81 100644 --- a/test_semver.py +++ b/test_semver.py @@ -881,3 +881,39 @@ def mock_func(): with pytest.deprecated_call(): assert mock_func() + + +def test_next_version_with_invalid_parts(): + version = VersionInfo.parse("1.0.1") + with pytest.raises(ValueError): + version.next_version("invalid") + + +@pytest.mark.parametrize( + "version, part, expected", + [ + # major + ("1.0.4-rc.1", "major", "2.0.0"), + ("1.1.0-rc.1", "major", "2.0.0"), + ("1.1.4-rc.1", "major", "2.0.0"), + ("1.2.3", "major", "2.0.0"), + ("1.0.0-rc.1", "major", "1.0.0"), + # minor + ("0.2.0-rc.1", "minor", "0.2.0"), + ("0.2.5-rc.1", "minor", "0.3.0"), + ("1.3.1", "minor", "1.4.0"), + # patch + ("1.3.2", "patch", "1.3.3"), + ("0.1.5-rc.2", "patch", "0.1.5"), + # prerelease + ("0.1.4", "prerelease", "0.1.5-rc.1"), + ("0.1.5-rc.1", "prerelease", "0.1.5-rc.2"), + # special cases + ("0.2.0-rc.1", "patch", "0.2.0"), # same as "minor" + ("1.0.0-rc.1", "patch", "1.0.0"), # same as "major" + ("1.0.0-rc.1", "minor", "1.0.0"), # same as "major" + ], +) +def test_next_version_with_versioninfo(version, part, expected): + ver = VersionInfo.parse(version) + assert str(ver.next_version(part)) == expected pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy