Skip to content

Fix #344 Allow empty string for bump method #365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog.d/344.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Allow empty string, a string with a prefix, or ``None``
as token in
:meth:`Version.bump_build <semver.Version.bump_build>` and
:meth:`Version.bump_prerelease <semver.Version.bump_prerelease>`.

1 change: 1 addition & 0 deletions docs/usage/increase-parts-of-a-version_prereleases.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.. _increase-parts-of-a-version:
Increasing Parts of a Version Taking into Account Prereleases
=============================================================

Expand Down
40 changes: 40 additions & 0 deletions docs/usage/raise-parts-of-a-version.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
Raising Parts of a Version
==========================

.. note::

Keep in mind, "raising" the pre-release only will make your
complete version *lower* than before.

For example, having version ``1.0.0`` and raising the pre-release
will lead to ``1.0.0-rc.1``, but ``1.0.0-rc.1`` is smaller than ``1.0.0``.

If you search for a way to take into account this behavior, look for the
method :meth:`Version.next_version <semver.version.Version.next_version>`
in section :ref:`increase-parts-of-a-version`.


The ``semver`` module contains the following functions to raise parts of
a version:

Expand All @@ -14,6 +27,7 @@ a version:
``build`` to ``None``.
* :func:`Version.bump_build <semver.version.Version.bump_build>`: raises the build part.


.. code-block:: python

>>> str(Version.parse("3.4.5-pre.2+build.4").bump_major())
Expand All @@ -28,3 +42,29 @@ a version:
'3.4.5-pre.2+build.5'

Likewise the module level functions :func:`semver.bump_major`.

For the methods :meth:`Version.bump_prerelease <semver.version.Version.bump_prerelease>`
and :meth:`Version.bump_build <semver.version.Version.bump_build>` it's possible to pass an empty string or ``None``.
However, it gives different results::

.. code-block:: python

>>> str(Version.parse("3.4.5").bump_prerelease(''))
'3.4.5-1'
>>> str(Version.parse("3.4.5").bump_prerelease(None))
'3.4.5-rc.1'

An empty string removes any prefix whereas ``None`` is the same as calling
the method without any argument.

If you already have a prerelease, the argument for the method
is not taken into account:

.. code-block:: python

>>> str(Version.parse("3.4.5-rc.1").bump_prerelease(None))
'3.4.5-rc.2'
>>> str(Version.parse("3.4.5-rc.1").bump_prerelease(''))
'3.4.5-rc.2'


57 changes: 46 additions & 11 deletions src/semver/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,38 +305,73 @@ def bump_patch(self) -> "Version":
cls = type(self)
return cls(self._major, self._minor, self._patch + 1)

def bump_prerelease(self, token: str = "rc") -> "Version":
def bump_prerelease(self, token: Optional[str] = "rc") -> "Version":
"""
Raise the prerelease part of the version, return a new object but leave
self untouched.

:param token: defaults to ``rc``
:return: new object with the raised prerelease part
:param token: defaults to ``'rc'``
:return: new :class:`Version` object with the raised prerelease part.
The original object is not modified.

>>> ver = semver.parse("3.4.5")
>>> ver.bump_prerelease()
Version(major=3, minor=4, patch=5, prerelease='rc.2', \
build=None)
>>> ver.bump_prerelease().prerelease
'rc.2'
>>> ver.bump_prerelease('').prerelease
'1'
>>> ver.bump_prerelease(None).prerelease
'rc.1'
"""
cls = type(self)
prerelease = cls._increment_string(self._prerelease or (token or "rc") + ".0")
if self._prerelease is not None:
prerelease = self._prerelease
elif token == "":
prerelease = "0"
elif token is None:
prerelease = "rc.0"
else:
prerelease = str(token) + ".0"

prerelease = cls._increment_string(prerelease)
return cls(self._major, self._minor, self._patch, prerelease)

def bump_build(self, token: str = "build") -> "Version":
def bump_build(self, token: Optional[str] = "build") -> "Version":
"""
Raise the build part of the version, return a new object but leave self
untouched.

:param token: defaults to ``build``
:return: new object with the raised build part
:param token: defaults to ``'build'``
:return: new :class:`Version` object with the raised build part.
The original object is not modified.

>>> ver = semver.parse("3.4.5-rc.1+build.9")
>>> ver.bump_build()
Version(major=3, minor=4, patch=5, prerelease='rc.1', \
build='build.10')
"""
cls = type(self)
build = cls._increment_string(self._build or (token or "build") + ".0")
if self._build is not None:
build = self._build
elif token == "":
build = "0"
elif token is None:
build = "build.0"
else:
build = str(token) + ".0"

# self._build or (token or "build") + ".0"
build = cls._increment_string(build)
if self._build is not None:
build = self._build
elif token == "":
build = "0"
elif token is None:
build = "build.0"
else:
build = str(token) + ".0"

# self._build or (token or "build") + ".0"
build = cls._increment_string(build)
return cls(self._major, self._minor, self._patch, self._prerelease, build)

def compare(self, other: Comparable) -> int:
Expand Down
24 changes: 24 additions & 0 deletions tests/test_bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,30 @@ def test_should_versioninfo_bump_multiple():
assert v.bump_prerelease().bump_build().bump_build().bump_prerelease() == expected


def test_should_versioninfo_bump_prerelease_with_empty_str():
v = parse_version_info("3.4.5")
expected = parse_version_info("3.4.5-1")
assert v.bump_prerelease("") == expected


def test_should_versioninfo_bump_prerelease_with_none():
v = parse_version_info("3.4.5")
expected = parse_version_info("3.4.5-rc.1")
assert v.bump_prerelease(None) == expected


def test_should_versioninfo_bump_build_with_empty_str():
v = parse_version_info("3.4.5")
expected = parse_version_info("3.4.5+1")
assert v.bump_build("") == expected


def test_should_versioninfo_bump_build_with_none():
v = parse_version_info("3.4.5")
expected = parse_version_info("3.4.5+build.1")
assert v.bump_build(None) == expected


def test_should_ignore_extensions_for_bump():
assert bump_patch("3.4.5-rc1+build4") == "3.4.6"

Expand Down