diff --git a/README.rst b/README.rst index ecc95e1a..106f8f6b 100644 --- a/README.rst +++ b/README.rst @@ -68,6 +68,70 @@ This module provides just couple of functions, main of which are: >>> semver.min_ver("1.0.0", "2.0.0") '1.0.0' +The version 1.7.4 supports lenient mode for these versions: +* major.minor. For e.g: 1.0 +* dot in patch. For e.g: 5.2.6.Final, 2.0.4.RELEASE + +By default the lenient mode is false, if you want to have these above support, you need to turn on the lenient mode by +calling method: + +.. code-block:: python + + semver.set_lenient(True) + + +Below are examples with lenient mode is False: + +.. code-block:: python + + >>> import semver + >>> semver.parse("1") + Traceback (most recent call last): + File "", line 1, in + File "semver.py", line 99, in parse + raise ValueError('%s is not valid SemVer string' % version) + ValueError: 1 is not valid SemVer string + >>> semver.parse("1.0") + Traceback (most recent call last): + File "", line 1, in + File "semver.py", line 132, in parse + raise ValueError('%s is not valid SemVer string' % version) + ValueError: 1.0 is not valid SemVer string + >>> semver.parse("1.0.0.FINAL") + Traceback (most recent call last): + File "", line 1, in + File "semver.py", line 132, in parse + raise ValueError('%s is not valid SemVer string' % version) + ValueError: 1.0.0.FINAL is not valid SemVer string + >>> semver.parse("5.2.6.Final") + Traceback (most recent call last): + File "", line 1, in + File "semver.py", line 132, in parse + raise ValueError('%s is not valid SemVer string' % version) + ValueError: 5.2.6.Final is not valid SemVer string + >>> semver.parse("2.0.4.RELEASE") + Traceback (most recent call last): + File "", line 1, in + File "semver.py", line 132, in parse + raise ValueError('%s is not valid SemVer string' % version) + ValueError: 2.0.4.RELEASE is not valid SemVer string + + +Below are examples when we turn on lenient mode: + +.. code-block:: python + + >>> import semver + >>> semver.set_lenient(True) + >>> semver.parse("1") + {'major': 1, 'prerelease': None, 'build': None, 'minor': 0, 'patch': 0} + >>> semver.parse("1.0") + {'major': 1, 'prerelease': None, 'build': None, 'minor': 0, 'patch': 0} + >>> semver.parse("5.2.6.Final") + {'major': 5, 'prerelease': None, 'build': 'Final', 'minor': 2, 'patch': 6} + >>> semver.parse("2.0.4.RELEASE") + {'major': 2, 'prerelease': None, 'build': 'RELEASE', 'minor': 0, 'patch': 4} + Installation ------------ diff --git a/semver.py b/semver.py index d82718b6..bfef80f3 100644 --- a/semver.py +++ b/semver.py @@ -50,30 +50,74 @@ __author__ = 'Kostiantyn Rybnikov' __author_email__ = 'k-bx@k-bx.com' -_REGEX = re.compile( - r""" - ^ - (?P(?:0|[1-9][0-9]*)) - \. - (?P(?:0|[1-9][0-9]*)) - \. - (?P(?:0|[1-9][0-9]*)) - (\-(?P - (?:0|[1-9A-Za-z-][0-9A-Za-z-]*) - (\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))* - ))? - (\+(?P - [0-9A-Za-z-]+ - (\.[0-9A-Za-z-]+)* - ))? - $ - """, re.VERBOSE) +# Lenient mode is off by default +lenient = False _LAST_NUMBER = re.compile(r'(?:[^\d]*(\d+)[^\d]*)+') if not hasattr(__builtins__, 'cmp'): def cmp(a, b): - return (a > b) - (a < b) + if lenient: + if a is not None and b is not None: + return (a > b) - (a < b) + elif a is not None and b is None: + return 1 + elif a is None and b is not None: + return -1 + else: + return 0 + else: + return (a > b) - (a < b) + + +def set_lenient(a): + global lenient + lenient = a + + +def get_regex(): + if lenient: + return re.compile( + r""" + ^ + (?P(?:0|[1-9][0-9]*)) + ( + \. + (?P(?:0|[1-9][0-9]*)) + ( + \. + (?P(?:0|[1-9][0-9]*)) + (\-(?P + (?:0|[1-9A-Za-z-][0-9A-Za-z-]*) + (\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))* + ))? + ((\+|\.)(?P + [0-9A-Za-z-]+ + (\.[0-9A-Za-z-]+)* + ))? + )? + )? + $ + """, re.VERBOSE) + else: + return re.compile( + r""" + ^ + (?P(?:0|[1-9][0-9]*)) + \. + (?P(?:0|[1-9][0-9]*)) + \. + (?P(?:0|[1-9][0-9]*)) + (\-(?P + (?:0|[1-9A-Za-z-][0-9A-Za-z-]*) + (\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))* + ))? + (\+(?P + [0-9A-Za-z-]+ + (\.[0-9A-Za-z-]+)* + ))? + $ + """, re.VERBOSE) def parse(version): @@ -85,15 +129,26 @@ def parse(version): if not provided :rtype: dict """ - match = _REGEX.match(version) + match = get_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']) + if lenient: + if version_parts['minor'] is not None: + version_parts['minor'] = int(version_parts['minor']) + else: + version_parts['minor'] = 0 + + if version_parts['patch'] is not None: + version_parts['patch'] = int(version_parts['patch']) + else: + version_parts['patch'] = 0 + else: + version_parts['minor'] = int(version_parts['minor']) + version_parts['patch'] = int(version_parts['patch']) return version_parts diff --git a/tests.py b/tests.py index 5681aefc..9dfa6151 100644 --- a/tests.py +++ b/tests.py @@ -11,6 +11,7 @@ from semver import bump_build from semver import min_ver from semver import max_ver +from semver import set_lenient SEMVERFUNCS = [ @@ -256,3 +257,66 @@ def test_should_bump_build(): assert bump_build('3.4.5-rc.1+0009.dev') == '3.4.5-rc.1+0010.dev' assert bump_build('3.4.5-rc.1') == '3.4.5-rc.1+build.1' assert bump_build('3.4.5') == '3.4.5+build.1' + + +def test_parse_version_has_major_and_minor_only(): + set_lenient(True) + version_info = parse('1.0') + assert version_info['major'] == 1 + assert version_info['minor'] == 0 + set_lenient(False) + + +def test_parse_version_with_patch_has_plus(): + set_lenient(True) + version_info = parse('3.4.5+Final') + assert version_info['major'] == 3 + assert version_info['minor'] == 4 + assert version_info['patch'] == 5 + assert version_info['build'] == 'Final' + set_lenient(False) + + +def test_parse_version_with_patch_has_dot(): + set_lenient(True) + version_info = parse('3.4.5.Final') + assert version_info['major'] == 3 + assert version_info['minor'] == 4 + assert version_info['patch'] == 5 + assert version_info['build'] == 'Final' + set_lenient(False) + + +def test_compare_versions_having_major_only(): + set_lenient(True) + assert compare('1', '1.0') == 0 + assert compare('1', '1.0.0') == 0 + assert compare('1.1', '1') == 1 + set_lenient(False) + + +def test_compare_versions_having_major_and_minor_only(): + set_lenient(True) + assert compare('1.0', '2.0') == -1 + assert compare('2.0', '1.0') == 1 + assert compare('2.0', '2.0') == 0 + assert compare('2.0', '2.0.0') == 0 + set_lenient(False) + + +def test_compare_versions_with_patch_has_plus(): + set_lenient(True) + assert compare('3.4.5+Final', '3.4.5') == 0 + assert compare('3.4.5+Final', '3.4.6') == -1 + assert compare('3.4.5+Final', '3.4.4') == 1 + assert compare('3.4.5+Final', '3.4.5.Final') == 0 + set_lenient(False) + + +def test_compare_versions_with_patch_has_dot(): + set_lenient(True) + assert compare('3.4.5.Final', '3.4.5') == 0 + assert compare('3.4.5.Final', '3.4.6') == -1 + assert compare('3.4.5.Final', '3.4.4') == 1 + assert compare('3.4.5.Final', '3.4.5.Final') == 0 + set_lenient(False) 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