diff --git a/conftest.py b/conftest.py index 3e05cb52..e6a1f048 100644 --- a/conftest.py +++ b/conftest.py @@ -5,9 +5,11 @@ sys.path.insert(0, "docs") from coerce import coerce # noqa:E402 +from semverwithvprefix import SemVerWithVPrefix @pytest.fixture(autouse=True) def add_semver(doctest_namespace): doctest_namespace["semver"] = semver doctest_namespace["coerce"] = coerce + doctest_namespace["SemVerWithVPrefix"] = SemVerWithVPrefix diff --git a/docs/semverwithvprefix.py b/docs/semverwithvprefix.py new file mode 100644 index 00000000..13298d5f --- /dev/null +++ b/docs/semverwithvprefix.py @@ -0,0 +1,31 @@ +from semver import VersionInfo + + +class SemVerWithVPrefix(VersionInfo): + """ + A subclass of VersionInfo which allows a "v" prefix + """ + + @classmethod + def parse(cls, version): + """ + Parse version string to a VersionInfo instance. + + :param version: version string with "v" or "V" prefix + :type version: str + :raises ValueError: when version does not start with "v" or "V" + :return: a new instance + :rtype: :class:`SemVerWithVPrefix` + """ + if not version[0] in ("v", "V"): + raise ValueError( + "{v!r}: not a valid semantic version tag. Must start with 'v' or 'V'".format( + v=version + ) + ) + self = super(SemVerWithVPrefix, cls).parse(version[1:]) + return self + + def __str__(self): + # Reconstruct the tag + return "v" + super(SemVerWithVPrefix, self).__str__() diff --git a/docs/usage.rst b/docs/usage.rst index 2f23e571..311bbac8 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -530,6 +530,8 @@ The "old way" with :func:`semver.max_ver` or :func:`semver.min_ver` is still ava '1.0.0' +.. _sec_dealing_with_invalid_versions: + Dealing with Invalid Versions ----------------------------- @@ -708,3 +710,39 @@ the following methods: For further details, see the section `Overriding the default filter `_ of the Python documentation. + + +.. _sec_creating_subclasses_from_versioninfo: + +Creating Subclasses from VersionInfo +------------------------------------ + +If you do not like creating functions to modify the behavior of semver +(as shown in section :ref:`sec_dealing_with_invalid_versions`), you can +also create a subclass of the :class:`VersionInfo` class. + +For example, if you want to output a "v" prefix before a version, +but the other behavior is the same, use the following code: + +.. literalinclude:: semverwithvprefix.py + :language: python + :lines: 4- + + +The derived class :class:`SemVerWithVPrefix` can be used like +the original class: + +.. code-block:: python + + >>> v1 = SemVerWithVPrefix.parse("v1.2.3") + >>> assert str(v1) == "v1.2.3" + >>> print(v1) + v1.2.3 + >>> v2 = SemVerWithVPrefix.parse("v2.3.4") + >>> v2 > v1 + True + >>> bad = SemVerWithVPrefix.parse("1.2.4") + Traceback (most recent call last): + ... + ValueError: '1.2.4': not a valid semantic version tag. Must start with 'v' or 'V' + diff --git a/setup.cfg b/setup.cfg index 1cefc4bf..6d1e30fc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,3 +21,5 @@ exclude = __pycache__, build, dist + docs + conftest.py diff --git a/test_semver.py b/test_semver.py index 0aeedbdb..951e3187 100644 --- a/test_semver.py +++ b/test_semver.py @@ -1134,9 +1134,9 @@ def test_subclass_from_versioninfo(): class SemVerWithVPrefix(VersionInfo): @classmethod def parse(cls, version): - if not version.startswith("v"): + if not version[0] in ("v", "V"): raise ValueError( - "{v}: not a valid semantic version tag".format(v=version) + "{v!r}: version must start with 'v' or 'V'".format(v=version) ) return super(SemVerWithVPrefix, cls).parse(version[1:])