Skip to content

Commit 6e8231c

Browse files
committed
Fix #344 Allow empty string for bump method
The methods .bump_prerelease('') and .bump_build('') generates a prerelease and build part without the token.
1 parent 5600d1e commit 6e8231c

File tree

4 files changed

+131
-12
lines changed

4 files changed

+131
-12
lines changed

CHANGELOG.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,51 @@ in our repository.
1616

1717
.. towncrier release notes start
1818
19+
Version 3.0.0-dev.3
20+
===================
21+
22+
:Released: 2022-10-04
23+
:Maintainer:
24+
25+
26+
Features
27+
--------
28+
29+
* :pr:`359`: Add optional parameter ``optional_minor_and_patch`` in :meth:`.Version.parse` to allow optional
30+
minor and patch parts.
31+
32+
* :pr:`362`: Make :meth:`.Version.match` accept a bare version string as match expression, defaulting to
33+
equality testing.
34+
35+
* :gh:`364`: Enhance :file:`pyproject.toml` to make it possible to use the
36+
:command:`pyproject-build` command from the build module.
37+
For more information, see :ref:`build-semver`.
38+
39+
40+
41+
Improved Documentation
42+
----------------------
43+
44+
* :gh:`335`: Add new section "Converting versions between PyPI and semver" the limitations
45+
and possible use cases to convert from one into the other versioning scheme.
46+
47+
* :gh:`340`: Describe how to get version from a file
48+
49+
* :gh:`343`: Describe combining Pydantic with semver in the "Advanced topic"
50+
section.
51+
52+
* :gh:`350`: Restructure usage section. Create subdirectory "usage/" and splitted
53+
all section into different files.
54+
55+
* :gh:`351`: Introduce new topics for:
56+
57+
* "Migration to semver3"
58+
* "Advanced topics"
59+
60+
61+
62+
----
63+
1964

2065
Version 3.0.0-dev.3
2166
===================

docs/usage/raise-parts-of-a-version.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,28 @@ a version:
2828
'3.4.5-pre.2+build.5'
2929
3030
Likewise the module level functions :func:`semver.bump_major`.
31+
32+
For the functions :func:`Version.bump_prerelease <semver.version.Version.bump_prerelease>` and :func:`Version.bump_build <semver.version.Version.bump_build>` it's possible to pass an empty string or ``None``. However,
33+
it gives different results::
34+
35+
.. code-block:: python
36+
37+
>>> str(Version.parse("3.4.5").bump_prerelease(''))
38+
'3.4.5-1'
39+
>>> str(Version.parse("3.4.5").bump_prerelease(None))
40+
'3.4.5-rc.1'
41+
42+
An empty string removes any prefix whereas ``None`` is the same as calling
43+
the method without any argument.
44+
45+
If you already have a prerelease, the argument for the method
46+
is not taken into account:
47+
48+
.. code-block:: python
49+
50+
>>> str(Version.parse("3.4.5-rc.1").bump_prerelease(None))
51+
'3.4.5-rc.2'
52+
>>> str(Version.parse("3.4.5-rc.1").bump_prerelease(''))
53+
'3.4.5-rc.2'
54+
55+

src/semver/version.py

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -298,39 +298,64 @@ def bump_patch(self) -> "Version":
298298
cls = type(self)
299299
return cls(self._major, self._minor, self._patch + 1)
300300

301-
def bump_prerelease(self, token: str = "rc") -> "Version":
301+
def bump_prerelease(self, token: Optional[str] = "rc") -> "Version":
302302
"""
303303
Raise the prerelease part of the version, return a new object but leave
304304
self untouched.
305305
306-
:param token: defaults to ``rc``
307-
:return: new object with the raised prerelease part
306+
:param token: defaults to ``'rc'``
307+
:return: new :class:`Version` object with the raised prerelease part.
308+
The original object is not modified.
308309
309310
>>> ver = semver.parse("3.4.5")
310-
>>> ver.bump_prerelease()
311-
Version(major=3, minor=4, patch=5, prerelease='rc.2', \
312-
build=None)
311+
>>> ver.bump_prerelease().prerelease
312+
'rc.2'
313+
>>> ver.bump_prerelease('').prerelease
314+
'1'
313315
"""
314316
cls = type(self)
315-
prerelease = cls._increment_string(self._prerelease or (token or "rc") + ".0")
317+
if self._prerelease is not None:
318+
prerelease = self._prerelease
319+
elif token == "":
320+
prerelease = "0"
321+
elif token is None:
322+
prerelease = "rc.0"
323+
else:
324+
prerelease = str(token) + ".0"
325+
326+
# self._prerelease or (token or "rc") + ".0"
327+
prerelease = cls._increment_string(prerelease)
316328
return cls(self._major, self._minor, self._patch, prerelease)
317329

318-
def bump_build(self, token: str = "build") -> "Version":
330+
# VersionPart = Union[int, Optional[str]]
331+
def bump_build(self, token: Optional[str] = "build") -> "Version":
319332
"""
320333
Raise the build part of the version, return a new object but leave self
321334
untouched.
322335
323-
:param token: defaults to ``build``
324-
:return: new object with the raised build part
336+
:param token: defaults to ``'build'``
337+
:return: new :class:`Version` object with the raised build part.
338+
The original object is not modified.
325339
326340
>>> ver = semver.parse("3.4.5-rc.1+build.9")
327341
>>> ver.bump_build()
328342
Version(major=3, minor=4, patch=5, prerelease='rc.1', \
329343
build='build.10')
330344
"""
331345
cls = type(self)
332-
build = cls._increment_string(self._build or (token or "build") + ".0")
333-
return cls(self._major, self._minor, self._patch, self._prerelease, build)
346+
if self._build is not None:
347+
build = self._build
348+
elif token == "":
349+
build = "0"
350+
elif token is None:
351+
build = "build.0"
352+
else:
353+
build = str(token) + ".0"
354+
355+
# self._build or (token or "build") + ".0"
356+
build = cls._increment_string(build)
357+
return cls(self._major, self._minor, self._patch,
358+
self._prerelease, build)
334359

335360
def compare(self, other: Comparable) -> int:
336361
"""

tests/test_bump.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ def test_should_versioninfo_bump_multiple():
6666
assert v.bump_prerelease().bump_build().bump_build().bump_prerelease() == expected
6767

6868

69+
def test_should_versioninfo_bump_prerelease_with_empty_str():
70+
v = parse_version_info("3.4.5")
71+
expected = parse_version_info("3.4.5-1")
72+
assert v.bump_prerelease("") == expected
73+
74+
75+
def test_should_versioninfo_bump_prerelease_with_none():
76+
v = parse_version_info("3.4.5")
77+
expected = parse_version_info("3.4.5-rc.1")
78+
assert v.bump_prerelease(None) == expected
79+
80+
81+
def test_should_versioninfo_bump_build_with_empty_str():
82+
v = parse_version_info("3.4.5")
83+
expected = parse_version_info("3.4.5+1")
84+
assert v.bump_build("") == expected
85+
86+
87+
def test_should_versioninfo_bump_build_with_none():
88+
v = parse_version_info("3.4.5")
89+
expected = parse_version_info("3.4.5+build.1")
90+
assert v.bump_build(None) == expected
91+
92+
6993
def test_should_ignore_extensions_for_bump():
7094
assert bump_patch("3.4.5-rc1+build4") == "3.4.6"
7195

0 commit comments

Comments
 (0)