diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
commit | 4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch) | |
tree | 65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/tools/python-semver/semver.py | |
parent | 0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff) |
add circuitpython code
Diffstat (limited to 'circuitpython/tools/python-semver/semver.py')
-rw-r--r-- | circuitpython/tools/python-semver/semver.py | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/circuitpython/tools/python-semver/semver.py b/circuitpython/tools/python-semver/semver.py new file mode 100644 index 0000000..6ed7887 --- /dev/null +++ b/circuitpython/tools/python-semver/semver.py @@ -0,0 +1,371 @@ +""" +Python helper for Semantic Versioning (http://semver.org/) +""" + +import collections +import re + + +__version__ = '2.7.9' +__author__ = 'Kostiantyn Rybnikov' +__author_email__ = 'k-bx@k-bx.com' + +_REGEX = re.compile( + r""" + ^ + (?P<major>(?:0|[1-9][0-9]*)) + \. + (?P<minor>(?:0|[1-9][0-9]*)) + \. + (?P<patch>(?:0|[1-9][0-9]*)) + (\-(?P<prerelease> + (?:0|[1-9A-Za-z-][0-9A-Za-z-]*) + (\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))* + ))? + (\+(?P<build> + [0-9A-Za-z-]+ + (\.[0-9A-Za-z-]+)* + ))? + $ + """, re.VERBOSE) + +_LAST_NUMBER = re.compile(r'(?:[^\d]*(\d+)[^\d]*)+') + +if not hasattr(__builtins__, 'cmp'): + def cmp(a, b): + return (a > b) - (a < b) + + +def parse(version): + """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: + raise ValueError('%s is not valid SemVer string' % version) + + version_parts = match.groupdict() + + version_parts['major'] = int(version_parts['major']) + version_parts['minor'] = int(version_parts['minor']) + version_parts['patch'] = int(version_parts['patch']) + + return version_parts + + +class VersionInfo(collections.namedtuple( + 'VersionInfo', 'major minor patch prerelease build')): + """ + :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'} + """ + __slots__ = () + + def __eq__(self, other): + if not isinstance(other, (VersionInfo, dict)): + return NotImplemented + return _compare_by_keys(self._asdict(), _to_dict(other)) == 0 + + def __ne__(self, other): + if not isinstance(other, (VersionInfo, dict)): + return NotImplemented + return _compare_by_keys(self._asdict(), _to_dict(other)) != 0 + + def __lt__(self, other): + if not isinstance(other, (VersionInfo, dict)): + return NotImplemented + return _compare_by_keys(self._asdict(), _to_dict(other)) < 0 + + def __le__(self, other): + if not isinstance(other, (VersionInfo, dict)): + return NotImplemented + return _compare_by_keys(self._asdict(), _to_dict(other)) <= 0 + + def __gt__(self, other): + if not isinstance(other, (VersionInfo, dict)): + return NotImplemented + return _compare_by_keys(self._asdict(), _to_dict(other)) > 0 + + def __ge__(self, other): + if not isinstance(other, (VersionInfo, dict)): + return NotImplemented + return _compare_by_keys(self._asdict(), _to_dict(other)) >= 0 + + +def _to_dict(obj): + if isinstance(obj, VersionInfo): + return obj._asdict() + return obj + + +def parse_version_info(version): + """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( + parts['major'], parts['minor'], parts['patch'], + parts['prerelease'], parts['build']) + + return version_info + + +def _nat_cmp(a, b): + def convert(text): + return int(text) if re.match('^[0-9]+$', text) else text + + def split_key(key): + return [convert(c) for c in key.split('.')] + + def cmp_prerelease_tag(a, b): + if isinstance(a, int) and isinstance(b, int): + return cmp(a, b) + elif isinstance(a, int): + return -1 + elif isinstance(b, int): + return 1 + else: + return cmp(a, b) + + a, b = a or '', b or '' + a_parts, b_parts = split_key(a), split_key(b) + for sub_a, sub_b in zip(a_parts, b_parts): + cmp_result = cmp_prerelease_tag(sub_a, sub_b) + if cmp_result != 0: + return cmp_result + else: + return cmp(len(a), len(b)) + + +def _compare_by_keys(d1, d2): + for key in ['major', 'minor', 'patch']: + v = cmp(d1.get(key), d2.get(key)) + if v: + return v + + rc1, rc2 = d1.get('prerelease'), d2.get('prerelease') + rccmp = _nat_cmp(rc1, rc2) + + if not rccmp: + return 0 + if not rc1: + return 1 + elif not rc2: + return -1 + + return rccmp + + +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 + """ + + v1, v2 = parse(ver1), parse(ver2) + + return _compare_by_keys(v1, v2) + + +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:] + elif prefix and prefix[0] in ('>', '<'): + prefix = prefix[0] + match_version = match_expr[1:] + else: + raise ValueError("match_expr parameter should be in format <op><ver>, " + "where <op> is one of " + "['<', '>', '==', '<=', '>=', '!=']. " + "You provided: %r" % match_expr) + + possibilities_dict = { + '>': (1,), + '<': (-1,), + '==': (0,), + '!=': (-1, 1), + '>=': (0, 1), + '<=': (-1, 0) + } + + possibilities = possibilities_dict[prefix] + cmp_res = compare(version, match_version) + + return cmp_res in possibilities + + +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 + else: + return 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 + else: + return 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 + + if build is not None: + version = version + "+%s" % build + + return version + + +def _increment_string(string): + """ + Look for the last sequence of number(s) in a string and increment, from: + http://code.activestate.com/recipes/442460-increment-numbers-in-a-string/#c1 + """ + match = _LAST_NUMBER.search(string) + if match: + next_ = str(int(match.group(1)) + 1) + start, end = match.span(1) + string = string[:max(end - len(next_), start)] + next_ + string[end:] + return 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, token='rc'): + """Raise the prerelease part of the version + + :param version: version string + :param token: defaults to 'rc' + :return: the raised version string + :rtype: str + """ + verinfo = parse(version) + verinfo['prerelease'] = _increment_string( + verinfo['prerelease'] or (token or 'rc') + '.0' + ) + return format_version(verinfo['major'], verinfo['minor'], verinfo['patch'], + verinfo['prerelease']) + + +def bump_build(version, token='build'): + """Raise the build part of the version + + :param version: version string + :param token: defaults to 'build' + :return: the raised version string + :rtype: str + """ + verinfo = parse(version) + verinfo['build'] = _increment_string( + verinfo['build'] or (token or 'build') + '.0' + ) + return format_version(verinfo['major'], verinfo['minor'], verinfo['patch'], + verinfo['prerelease'], verinfo['build']) + + +def finalize_version(version): + """Remove any prerelease and build metadata from the version + + :param version: version string + :return: the finalized version string + :rtype: str + """ + verinfo = parse(version) + return format_version(verinfo['major'], verinfo['minor'], verinfo['patch']) |