From c42aae342ca7a8e933773ea2dc8a2a14f2fb5698 Mon Sep 17 00:00:00 2001 From: Thomas Schraitle Date: Mon, 19 Dec 2016 20:43:03 +0100 Subject: [PATCH 1/3] Add test case for docstring --- tests.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests.py b/tests.py index 377a7d2..5681aef 100644 --- a/tests.py +++ b/tests.py @@ -13,6 +13,19 @@ from semver import min_ver from semver import max_ver +SEMVERFUNCS = [ + compare, match, parse, format_version, + bump_major, bump_minor, bump_patch, bump_prerelease, bump_build, + max_ver, min_ver, +] + + +@pytest.mark.parametrize("func", SEMVERFUNCS, + ids=[func.__name__ for func in SEMVERFUNCS]) +def test_fordocstrings(func): + assert func.__doc__, "Need a docstring for function %r" % func.__name + + def test_should_parse_version(): result = parse("1.2.3-alpha.1.2+build.11.e0f985a") assert result == { From 7afb3805db85f6127d571863e94a75e72e8f795a Mon Sep 17 00:00:00 2001 From: Thomas Schraitle Date: Mon, 19 Dec 2016 20:43:15 +0100 Subject: [PATCH 2/3] Add docstrings for each function --- semver.py | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/semver.py b/semver.py index 0164bed..e264c6f 100644 --- a/semver.py +++ b/semver.py @@ -1,9 +1,49 @@ """ Python helper for Semantic Versioning (http://semver.org/) + +Examples: +>>> import semver +>>> semver.compare("1.0.0", "2.0.0") +-1 +>>> semver.compare("2.0.0", "1.0.0") +1 +>>> semver.compare("2.0.0", "2.0.0") +0 +>>> semver.match("2.0.0", ">=1.0.0") +True +>>> semver.match("1.0.0", ">1.0.0") +False +>>> semver.format_version(3, 4, 5, 'pre.2', 'build.4') +'3.4.5-pre.2+build.4' +>>> version_parts = semver.parse("3.4.5-pre.2+build.4") +>>> version_parts == { +... 'major': 3, 'minor': 4, 'patch': 5, +... 'prerelease': 'pre.2', 'build': 'build.4'} +True +>>> version_info = semver.parse_version_info("3.4.5-pre.2+build.4") +>>> version_info +VersionInfo(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4') +>>> version_info.major +3 +>>> version_info > (1, 0) +True +>>> version_info < (3, 5) +True +>>> semver.bump_major("3.4.5") +'4.0.0' +>>> semver.bump_minor("3.4.5") +'3.5.0' +>>> semver.bump_patch("3.4.5") +'3.4.6' +>>> semver.max_ver("1.0.0", "2.0.0") +'2.0.0' +>>> semver.min_ver("1.0.0", "2.0.0") +'1.0.0' """ import collections import re +import sys __version__ = '2.7.2' @@ -37,8 +77,13 @@ if not hasattr(__builtins__, 'cmp'): def parse(version): - """ - Parse version to major, minor, patch, pre-release, build parts. + """Parse version to major, minor, patch, pre-release, build parts. + + :param version: version string + :return: dictionary with the keys 'build', 'major', 'minor', 'patch', + and 'prerelease'. The prerelease or build keys can be None + if not provided + :rtype: dict """ match = _REGEX.match(version) if match is None: @@ -56,10 +101,31 @@ def parse(version): VersionInfo = collections.namedtuple( 'VersionInfo', 'major minor patch prerelease build') +# Only change it for Python > 3 as it is readonly +# for version 2 +if sys.version_info > (3,0): + VersionInfo.__doc__ = """ +:param int major: version when you make incompatible API changes. +:param int minor: version when you add functionality in + a backwards-compatible manner. +:param int patch: version when you make backwards-compatible bug fixes. +:param str prerelease: an optional prerelease string +:param str build: an optional build string + +>>> import semver +>>> ver = semver.parse('3.4.5-pre.2+build.4') +>>> ver +{'build': 'build.4', 'major': 3, 'minor': 4, 'patch': 5, +'prerelease': 'pre.2'} +""" + def parse_version_info(version): - """ - Parse version string to a VersionInfo instance. + """Parse version string to a VersionInfo instance. + + :param version: version string + :return: a :class:`VersionInfo` instance + :rtype: :class:`VersionInfo` """ parts = parse(version) version_info = VersionInfo( @@ -70,6 +136,14 @@ def parse_version_info(version): def compare(ver1, ver2): + """Compare two versions + + :param ver1: version string 1 + :param ver2: version string 2 + :return: The return value is negative if ver1 < ver2, + zero if ver1 == ver2 and strictly positive if ver1 > ver2 + :rtype: int + """ def nat_cmp(a, b): def convert(text): return (2, int(text)) if re.match('[0-9]+', text) else (1, text) @@ -104,6 +178,19 @@ def compare(ver1, ver2): def match(version, match_expr): + """Compare two versions through a comparison + + :param str version: a version string + :param str match_expr: operator and version; valid operators are + < smaller than + > greater than + >= greator or equal than + <= smaller or equal than + == equal + != not equal + :return: True if the expression matches the version, otherwise False + :rtype: bool + """ prefix = match_expr[:2] if prefix in ('>=', '<=', '==', '!='): match_version = match_expr[2:] @@ -132,6 +219,13 @@ def match(version, match_expr): def max_ver(ver1, ver2): + """Returns the greater version of two versions + + :param ver1: version string 1 + :param ver2: version string 2 + :return: the greater version of the two + :rtype: :class:`VersionInfo` + """ cmp_res = compare(ver1, ver2) if cmp_res == 0 or cmp_res == 1: return ver1 @@ -140,6 +234,13 @@ def max_ver(ver1, ver2): def min_ver(ver1, ver2): + """Returns the smaller version of two versions + + :param ver1: version string 1 + :param ver2: version string 2 + :return: the smaller version of the two + :rtype: :class:`VersionInfo` + """ cmp_res = compare(ver1, ver2) if cmp_res == 0 or cmp_res == -1: return ver1 @@ -148,6 +249,16 @@ def min_ver(ver1, ver2): def format_version(major, minor, patch, prerelease=None, build=None): + """Format a version according to the Semantic Versioning specification + + :param str major: the required major part of a version + :param str minor: the required minor part of a version + :param str patch: the required patch part of a version + :param str prerelease: the optional prerelease part of a version + :param str build: the optional build part of a version + :return: the formatted string + :rtype: str + """ version = "%d.%d.%d" % (major, minor, patch) if prerelease is not None: version = version + "-%s" % prerelease @@ -172,22 +283,46 @@ def _increment_string(string): def bump_major(version): + """Raise the major part of the version + + :param: version string + :return: the raised version string + :rtype: str + """ verinfo = parse(version) return format_version(verinfo['major'] + 1, 0, 0) def bump_minor(version): + """Raise the minor part of the version + + :param: version string + :return: the raised version string + :rtype: str + """ verinfo = parse(version) return format_version(verinfo['major'], verinfo['minor'] + 1, 0) def bump_patch(version): + """Raise the patch part of the version + + :param: version string + :return: the raised version string + :rtype: str + """ verinfo = parse(version) return format_version(verinfo['major'], verinfo['minor'], verinfo['patch'] + 1) def bump_prerelease(version): + """Raise the prerelease part of the version + + :param: version string + :return: the raised version string + :rtype: str + """ verinfo = parse(version) verinfo['prerelease'] = _increment_string(verinfo['prerelease'] or 'rc.0') return format_version(verinfo['major'], verinfo['minor'], verinfo['patch'], @@ -195,6 +330,12 @@ def bump_prerelease(version): def bump_build(version): + """Raise the build part of the version + + :param: version string + :return: the raised version string + :rtype: str + """ verinfo = parse(version) verinfo['build'] = _increment_string(verinfo['build'] or 'build.0') return format_version(verinfo['major'], verinfo['minor'], verinfo['patch'], From 9f60ad5a49dbaecf9fdae6a8338f1bb66c149562 Mon Sep 17 00:00:00 2001 From: Thomas Schraitle Date: Mon, 19 Dec 2016 20:58:28 +0100 Subject: [PATCH 3/3] Fix flake8 errors --- semver.py | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/semver.py b/semver.py index e264c6f..7af1266 100644 --- a/semver.py +++ b/semver.py @@ -103,7 +103,7 @@ VersionInfo = collections.namedtuple( # Only change it for Python > 3 as it is readonly # for version 2 -if sys.version_info > (3,0): +if sys.version_info > (3, 0): VersionInfo.__doc__ = """ :param int major: version when you make incompatible API changes. :param int minor: version when you add functionality in diff --git a/setup.py b/setup.py index ea363bc..e9f60b1 100755 --- a/setup.py +++ b/setup.py @@ -69,6 +69,7 @@ def read_file(filename): with open(join(dirname(__file__), filename)) as f: return f.read() + setup( name=package.__name__, version=package.__version__,