diff --git a/.github/workflows/python-testing.yml b/.github/workflows/python-testing.yml index f6decc03..adb06d4a 100644 --- a/.github/workflows/python-testing.yml +++ b/.github/workflows/python-testing.yml @@ -60,7 +60,7 @@ jobs: cache: 'pip' - name: Install dependencies run: | - python3 -m pip install --upgrade pip setuptools setuptools-scm + python3 -m pip install --upgrade pip setuptools>60 setuptools-scm>=60 pip install tox tox-gh-actions - name: Check run: | diff --git a/changelog.d/426.bugfix.rst b/changelog.d/426.bugfix.rst new file mode 100644 index 00000000..2c2d0eac --- /dev/null +++ b/changelog.d/426.bugfix.rst @@ -0,0 +1,2 @@ +Fix :meth:`~semver.version.Version.replace` method to use the derived class +of an instance instead of :class:`~semver.version.Version` class. diff --git a/src/semver/version.py b/src/semver/version.py index 9a7a4ffc..29309ab4 100644 --- a/src/semver/version.py +++ b/src/semver/version.py @@ -655,8 +655,8 @@ def parse( def replace(self, **parts: Union[int, Optional[str]]) -> "Version": """ - Replace one or more parts of a version and return a new - :class:`Version` object, but leave self untouched + Replace one or more parts of a version and return a new :class:`Version` + object, but leave self untouched. .. versionadded:: 2.9.0 Added :func:`Version.replace` @@ -670,7 +670,7 @@ def replace(self, **parts: Union[int, Optional[str]]) -> "Version": version = self.to_dict() version.update(parts) try: - return Version(**version) # type: ignore + return type(self)(**version) # type: ignore except TypeError: unknownkeys = set(parts) - set(self.to_dict()) error = "replace() got %d unexpected keyword argument(s): %s" % ( diff --git a/tests/test_subclass.py b/tests/test_subclass.py index cbf9d271..b33f4969 100644 --- a/tests/test_subclass.py +++ b/tests/test_subclass.py @@ -17,3 +17,37 @@ def __str__(self): v = SemVerWithVPrefix.parse("v1.2.3") assert str(v) == "v1.2.3" + + +def test_replace_from_subclass(): + # Issue#426 + # Taken from the example "Creating Subclasses from Version" + class SemVerWithVPrefix(Version): + """ + A subclass of Version which allows a "v" prefix + """ + + @classmethod + def parse(cls, version: str) -> "SemVerWithVPrefix": + """ + Parse version string to a Version instance. + + :param version: version string with "v" or "V" prefix + :raises ValueError: when version does not start with "v" or "V" + :return: a new instance + """ + if not version[0] in ("v", "V"): + raise ValueError( + f"{version!r}: not a valid semantic version tag. " + "Must start with 'v' or 'V'" + ) + return super().parse(version[1:], optional_minor_and_patch=True) + + def __str__(self) -> str: + # Reconstruct the tag + return "v" + super().__str__() + + version = SemVerWithVPrefix.parse("v1.1.0") + dev_version = version.replace(prerelease="dev.0") + + assert str(dev_version) == "v1.1.0-dev.0" 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