Skip to content

Commit c5c779a

Browse files
authored
Merge pull request #427 from tomschr/fix-426-match-derivedclass
Fix #426: call subclass when deriving from Version
2 parents 757ada6 + 2dda51c commit c5c779a

File tree

4 files changed

+40
-4
lines changed

4 files changed

+40
-4
lines changed

.github/workflows/python-testing.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
cache: 'pip'
6161
- name: Install dependencies
6262
run: |
63-
python3 -m pip install --upgrade pip setuptools setuptools-scm
63+
python3 -m pip install --upgrade pip setuptools>60 setuptools-scm>=60
6464
pip install tox tox-gh-actions
6565
- name: Check
6666
run: |

changelog.d/426.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :meth:`~semver.version.Version.replace` method to use the derived class
2+
of an instance instead of :class:`~semver.version.Version` class.

src/semver/version.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,8 @@ def parse(
655655

656656
def replace(self, **parts: Union[int, Optional[str]]) -> "Version":
657657
"""
658-
Replace one or more parts of a version and return a new
659-
:class:`Version` object, but leave self untouched
658+
Replace one or more parts of a version and return a new :class:`Version`
659+
object, but leave self untouched.
660660
661661
.. versionadded:: 2.9.0
662662
Added :func:`Version.replace`
@@ -670,7 +670,7 @@ def replace(self, **parts: Union[int, Optional[str]]) -> "Version":
670670
version = self.to_dict()
671671
version.update(parts)
672672
try:
673-
return Version(**version) # type: ignore
673+
return type(self)(**version) # type: ignore
674674
except TypeError:
675675
unknownkeys = set(parts) - set(self.to_dict())
676676
error = "replace() got %d unexpected keyword argument(s): %s" % (

tests/test_subclass.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,37 @@ def __str__(self):
1717

1818
v = SemVerWithVPrefix.parse("v1.2.3")
1919
assert str(v) == "v1.2.3"
20+
21+
22+
def test_replace_from_subclass():
23+
# Issue#426
24+
# Taken from the example "Creating Subclasses from Version"
25+
class SemVerWithVPrefix(Version):
26+
"""
27+
A subclass of Version which allows a "v" prefix
28+
"""
29+
30+
@classmethod
31+
def parse(cls, version: str) -> "SemVerWithVPrefix":
32+
"""
33+
Parse version string to a Version instance.
34+
35+
:param version: version string with "v" or "V" prefix
36+
:raises ValueError: when version does not start with "v" or "V"
37+
:return: a new instance
38+
"""
39+
if not version[0] in ("v", "V"):
40+
raise ValueError(
41+
f"{version!r}: not a valid semantic version tag. "
42+
"Must start with 'v' or 'V'"
43+
)
44+
return super().parse(version[1:], optional_minor_and_patch=True)
45+
46+
def __str__(self) -> str:
47+
# Reconstruct the tag
48+
return "v" + super().__str__()
49+
50+
version = SemVerWithVPrefix.parse("v1.1.0")
51+
dev_version = version.replace(prerelease="dev.0")
52+
53+
assert str(dev_version) == "v1.1.0-dev.0"

0 commit comments

Comments
 (0)