aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/tools/python-semver
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
commit4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch)
tree65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/tools/python-semver
parent0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff)
add circuitpython code
Diffstat (limited to 'circuitpython/tools/python-semver')
-rw-r--r--circuitpython/tools/python-semver/.travis.yml28
-rw-r--r--circuitpython/tools/python-semver/CHANGELOG308
-rw-r--r--circuitpython/tools/python-semver/CONTRIBUTORS45
-rw-r--r--circuitpython/tools/python-semver/LICENSE.txt27
-rw-r--r--circuitpython/tools/python-semver/MANIFEST.in1
-rw-r--r--circuitpython/tools/python-semver/Makefile5
-rw-r--r--circuitpython/tools/python-semver/README.rst113
-rw-r--r--circuitpython/tools/python-semver/__pycache__/semver.cpython-310.pycbin0 -> 10458 bytes
-rw-r--r--circuitpython/tools/python-semver/semver.py371
-rwxr-xr-xcircuitpython/tools/python-semver/setup.py107
-rw-r--r--circuitpython/tools/python-semver/tests.py354
-rw-r--r--circuitpython/tools/python-semver/tox.ini16
12 files changed, 1375 insertions, 0 deletions
diff --git a/circuitpython/tools/python-semver/.travis.yml b/circuitpython/tools/python-semver/.travis.yml
new file mode 100644
index 0000000..5fbc4df
--- /dev/null
+++ b/circuitpython/tools/python-semver/.travis.yml
@@ -0,0 +1,28 @@
+language: python
+install: pip install "virtualenv<14.0.0"
+script: python setup.py test
+matrix:
+ include:
+ - python: "2.6"
+ env: TOXENV=py26
+
+ - python: "2.7"
+ env: TOXENV=py27
+
+ - python: "3.3"
+ env: TOXENV=py33
+
+ - python: "3.4"
+ env: TOXENV=py34
+
+ - python: "3.4"
+ env: TOXENV=flake8
+
+ - python: "3.5"
+ env: TOXENV=py35
+
+ - python: "3.6"
+ env: TOXENV=py36
+
+ - python: "pypy"
+ env: TOXENV=pypy
diff --git a/circuitpython/tools/python-semver/CHANGELOG b/circuitpython/tools/python-semver/CHANGELOG
new file mode 100644
index 0000000..d13b887
--- /dev/null
+++ b/circuitpython/tools/python-semver/CHANGELOG
@@ -0,0 +1,308 @@
+##########
+Change Log
+##########
+
+Python SemVer library
+#####################
+
+All notable changes to this code base will be documented in this file,
+in every released version.
+
+Version 2.7.9
+=============
+
+:Released: 2017-09-23
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+* Issue #65 (PR #66). Add finalize_version function
+
+Version 2.7.8
+=============
+
+:Released: 2017-08-25
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+* PR #62. Support custom default names for pre and build
+
+Version 2.7.7
+=============
+
+:Released: 2017-05-25
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+* Issue #54 (PR #55) Add comparision between VersionInfo objects
+* PR #56. Add support for Python 3.6
+
+Version 2.7.2
+=============
+
+:Released: 2016-11-08
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Fix issue #37 (Remove trailing zeros from prelease doesn't allow to
+ parse 0 pre-release version)
+* Add ‘parse_version_info’ to parse a version string to a version info
+ tuple.
+
+Bug Fixes
+---------
+
+* Refine parsing to conform more strictly to SemVer 2.0.0.
+
+ SemVer 2.0.0 specification §9 forbids leading zero on identifiers in
+ the prerelease version.
+
+
+Version 2.6.0
+=============
+
+:Released: 2016-06-08
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Removals
+--------
+
+* Remove comparison of build component.
+
+ SemVer 2.0.0 specification recommends that build component is
+ ignored in comparisons.
+
+
+Version 2.5.0
+=============
+
+:Released: 2016-05-25
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Support matching 'not equal' with “!=”.
+
+Changes
+-------
+
+* Make separate builds for tests on Travis CI.
+
+
+Version 2.4.2
+=============
+
+:Released: 2016-05-16
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Changes
+-------
+
+* Migrate README document to reStructuredText format.
+
+* Use Setuptools for distribution management.
+
+* Migrate test cases to Py.test.
+
+* Add configuration for Tox test runner.
+
+
+Version 2.4.1
+=============
+
+:Released: 2016-03-04
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* [GitHub issue #23] Compare build component of a version.
+
+
+Version 2.4.0
+=============
+
+:Released: 2016-02-12
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Bug Fixes
+---------
+
+* [GitHub issue #21] Compare alphanumeric components correctly.
+
+
+Version 2.3.1
+=============
+
+:Released: 2016-01-30
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Declare granted license name in distribution metadata.
+
+
+Version 2.3.0
+=============
+
+:Released: 2016-01-29
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Add functions to increment prerelease and build components in a
+ version.
+
+
+Version 2.2.1
+=============
+
+:Released: 2015-08-04
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Bug Fixes
+---------
+
+* Correct comparison when any component includes zero.
+
+
+Version 2.2.0
+=============
+
+:Released: 2015-06-21
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Add functions to determined minimum and maximum version.
+
+* Add code examples for recently-added functions.
+
+
+Version 2.1.2
+=============
+
+:Released: 2015-05-23
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Bug Fixes
+---------
+
+* Restore current README document to distribution manifest.
+
+
+Version 2.1.1
+=============
+
+:Released: 2015-05-23
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Bug Fixes
+---------
+
+* Remove absent document from distribution manifest.
+
+
+Version 2.1.0
+=============
+
+:Released: 2015-05-22
+:Maintainer: Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Document installation instructions.
+
+* Document project home page.
+
+* Add function to format a version string from components.
+
+* Add functions to increment specific components in a version.
+
+Changes
+-------
+
+* Migrate README document to Markdown format.
+
+Bug Fixes
+---------
+
+* Correct code examples in README document.
+
+
+Version 2.0.2
+=============
+
+:Released: 2015-04-14
+:Maintainer: Konstantine Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Add configuration for Travis continuous integration.
+
+* Explicitly declare supported Python versions.
+
+
+Version 2.0.1
+=============
+
+:Released: 2014-09-24
+:Maintainer: Konstantine Rybnikov <k-bx@k-bx.com>
+
+Bug Fixes
+---------
+
+* [GitHub issue #9] Correct comparison of equal version strings.
+
+
+Version 2.0.0
+=============
+
+:Released: 2014-05-24
+:Maintainer: Konstantine Rybnikov <k-bx@k-bx.com>
+
+Additions
+---------
+
+* Grant license in this code base under BSD 3-clause license terms.
+
+Changes
+-------
+
+* Update parser to SemVer standard 2.0.0.
+
+* Ignore build component for comparison.
+
+
+Version 0.0.2
+=============
+
+:Released: 2012-05-10
+:Maintainer: Konstantine Rybnikov <k-bx@k-bx.com>
+
+Changes
+-------
+
+* Use standard library Distutils for distribution management.
+
+
+Version 0.0.1
+=============
+
+:Released: 2012-04-28
+:Maintainer: Konstantine Rybnikov <kost-bebix@yandex.ru>
+
+* Initial release.
+
+
+..
+ Local variables:
+ coding: utf-8
+ mode: text
+ mode: rst
+ End:
+ vim: fileencoding=utf-8 filetype=rst :
diff --git a/circuitpython/tools/python-semver/CONTRIBUTORS b/circuitpython/tools/python-semver/CONTRIBUTORS
new file mode 100644
index 0000000..6841099
--- /dev/null
+++ b/circuitpython/tools/python-semver/CONTRIBUTORS
@@ -0,0 +1,45 @@
+############
+Contributors
+############
+
+Python SemVer library
+#####################
+
+This document records the primary maintainers and significant
+contributors to this code base.
+
+Thank you to everyone whose work has made this possible.
+
+
+Primary maintainers
+===================
+
+* Kostiantyn Rybnikov <k-bx@k-bx.com>
+
+
+Significant contributors
+========================
+
+* Alexander Puzynia <werwolf.by@gmail.com>
+* Alexander Shorin <kxepal@gmail.com>
+* Anton Talevnin <TalAntR@users.noreply.github.com>
+* Ben Finney <ben+python@benfinney.id.au>
+* Carles Barrobés <carles@barrobes.com>
+* Craig Blaszczyk <masterjakul@gmail.com>
+* Jan Pieter Waagmeester <jieter@jieter.nl>
+* Jelo Agnasin <jelo@icannhas.com>
+* Karol Werner <karol.werner@codete.co>
+* Peter Bittner <django@bittner.it>
+* robi-wan <robi-wan@suyu.de>
+* T. Jameson Little <t.jameson.little@gmail.com>
+* Tuure Laurinolli <tuure@laurinolli.net>
+* Tyler Cross <tyler@crosscollab.com>
+* Zack Lalanne <zack.lalanne@gmail.com>
+
+..
+ Local variables:
+ coding: utf-8
+ mode: text
+ mode: rst
+ End:
+ vim: fileencoding=utf-8 filetype=rst :
diff --git a/circuitpython/tools/python-semver/LICENSE.txt b/circuitpython/tools/python-semver/LICENSE.txt
new file mode 100644
index 0000000..f98e22b
--- /dev/null
+++ b/circuitpython/tools/python-semver/LICENSE.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2013, Konstantine Rybnikov
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ Neither the name of the {organization} nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/circuitpython/tools/python-semver/MANIFEST.in b/circuitpython/tools/python-semver/MANIFEST.in
new file mode 100644
index 0000000..9561fb1
--- /dev/null
+++ b/circuitpython/tools/python-semver/MANIFEST.in
@@ -0,0 +1 @@
+include README.rst
diff --git a/circuitpython/tools/python-semver/Makefile b/circuitpython/tools/python-semver/Makefile
new file mode 100644
index 0000000..f1272fa
--- /dev/null
+++ b/circuitpython/tools/python-semver/Makefile
@@ -0,0 +1,5 @@
+sdist:
+ python setup.py sdist bdist_wheel --universal
+
+.PHONY sdist
+
diff --git a/circuitpython/tools/python-semver/README.rst b/circuitpython/tools/python-semver/README.rst
new file mode 100644
index 0000000..ecc95e1
--- /dev/null
+++ b/circuitpython/tools/python-semver/README.rst
@@ -0,0 +1,113 @@
+Semver |latest-version|
+=======================
+
+|build-status| |python-support| |downloads| |license|
+
+A Python module for `semantic versioning`_. Simplifies comparing versions.
+
+
+.. |latest-version| image:: https://img.shields.io/pypi/v/semver.svg
+ :alt: Latest version on PyPI
+ :target: https://pypi.python.org/pypi/semver
+.. |build-status| image:: https://travis-ci.org/k-bx/python-semver.svg?branch=master
+ :alt: Build status
+ :target: https://travis-ci.org/k-bx/python-semver
+.. |python-support| image:: https://img.shields.io/pypi/pyversions/semver.svg
+ :target: https://pypi.python.org/pypi/semver
+ :alt: Python versions
+.. |downloads| image:: https://img.shields.io/pypi/dm/semver.svg
+ :alt: Monthly downloads from PyPI
+ :target: https://pypi.python.org/pypi/semver
+.. |license| image:: https://img.shields.io/pypi/l/semver.svg
+ :alt: Software license
+ :target: https://github.com/k-bx/python-semver/blob/master/LICENSE.txt
+.. _semantic versioning: http://semver.org/
+
+Usage
+-----
+
+This module provides just couple of functions, main of which are:
+
+.. code-block:: python
+
+ >>> 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'
+
+Installation
+------------
+
+For Python 2:
+
+.. code-block:: bash
+
+ pip install semver
+
+For Python 3:
+
+.. code-block:: bash
+
+ pip3 install semver
+
+How to Contribute
+-----------------
+
+When you make changes to the code please run the tests before pushing your
+code to your fork and opening a `pull request`_:
+
+.. code-block:: bash
+
+ python setup.py test
+
+We use `py.test`_ and `tox`_ to run tests against all supported Python
+versions. All test dependencies are resolved automatically, apart from
+virtualenv, which for the moment you still may have to install manually:
+
+.. code-block:: bash
+
+ pip install "virtualenv<14.0.0" # <14.0.0 needed for Python 3.2 only
+
+You can use the ``clean`` command to remove build and test files and folders:
+
+.. code-block:: bash
+
+ python setup.py clean
+
+
+.. _pull request: https://github.com/k-bx/python-semver/pulls
+.. _py.test: http://pytest.org/
+.. _tox: http://tox.testrun.org/
diff --git a/circuitpython/tools/python-semver/__pycache__/semver.cpython-310.pyc b/circuitpython/tools/python-semver/__pycache__/semver.cpython-310.pyc
new file mode 100644
index 0000000..ad2a468
--- /dev/null
+++ b/circuitpython/tools/python-semver/__pycache__/semver.cpython-310.pyc
Binary files differ
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'])
diff --git a/circuitpython/tools/python-semver/setup.py b/circuitpython/tools/python-semver/setup.py
new file mode 100755
index 0000000..4b02e18
--- /dev/null
+++ b/circuitpython/tools/python-semver/setup.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+import semver as package
+from glob import glob
+from os import remove
+from os.path import dirname, join
+from setuptools import setup
+from setuptools.command.test import test as TestCommand
+from shlex import split
+from shutil import rmtree
+
+
+class Tox(TestCommand):
+ user_options = [('tox-args=', 'a', "Arguments to pass to tox")]
+
+ def initialize_options(self):
+ TestCommand.initialize_options(self)
+ self.tox_args = None
+
+ def finalize_options(self):
+ TestCommand.finalize_options(self)
+ self.test_args = []
+ self.test_suite = True
+
+ def run_tests(self):
+ from tox import cmdline
+ args = self.tox_args
+ if args:
+ args = split(self.tox_args)
+ errno = cmdline(args=args)
+ exit(errno)
+
+
+class Clean(TestCommand):
+ def run(self):
+ delete_in_root = [
+ 'build',
+ '.cache',
+ 'dist',
+ '.eggs',
+ '*.egg-info',
+ '.tox',
+ ]
+ delete_everywhere = [
+ '__pycache__',
+ '*.pyc',
+ ]
+ for candidate in delete_in_root:
+ rmtree_glob(candidate)
+ for visible_dir in glob('[A-Za-z0-9]*'):
+ for candidate in delete_everywhere:
+ rmtree_glob(join(visible_dir, candidate))
+ rmtree_glob(join(visible_dir, '*', candidate))
+
+
+def rmtree_glob(file_glob):
+ for fobj in glob(file_glob):
+ try:
+ rmtree(fobj)
+ print('%s/ removed ...' % fobj)
+ except OSError:
+ try:
+ remove(fobj)
+ print('%s removed ...' % fobj)
+ except OSError:
+ pass
+
+
+def read_file(filename):
+ with open(join(dirname(__file__), filename)) as f:
+ return f.read()
+
+
+setup(
+ name=package.__name__,
+ version=package.__version__,
+ description=package.__doc__.strip(),
+ long_description=read_file('README.rst'),
+ author=package.__author__,
+ author_email=package.__author_email__,
+ url='https://github.com/k-bx/python-semver',
+ download_url='https://github.com/k-bx/python-semver/downloads',
+ py_modules=[package.__name__],
+ include_package_data=True,
+ license='BSD',
+ classifiers=[
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ ],
+ tests_require=['tox', 'virtualenv<14.0.0'],
+ cmdclass={
+ 'clean': Clean,
+ 'test': Tox,
+ },
+)
diff --git a/circuitpython/tools/python-semver/tests.py b/circuitpython/tools/python-semver/tests.py
new file mode 100644
index 0000000..a3e2ab7
--- /dev/null
+++ b/circuitpython/tools/python-semver/tests.py
@@ -0,0 +1,354 @@
+import pytest # noqa
+
+from semver import compare
+from semver import match
+from semver import parse
+from semver import format_version
+from semver import bump_major
+from semver import bump_minor
+from semver import bump_patch
+from semver import bump_prerelease
+from semver import bump_build
+from semver import finalize_version
+from semver import min_ver
+from semver import max_ver
+from semver import VersionInfo
+
+
+SEMVERFUNCS = [
+ compare, match, parse, format_version,
+ bump_major, bump_minor, bump_patch, bump_prerelease, bump_build,
+ max_ver, min_ver, finalize_version
+]
+
+
+@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 == {
+ 'major': 1,
+ 'minor': 2,
+ 'patch': 3,
+ 'prerelease': 'alpha.1.2',
+ 'build': 'build.11.e0f985a',
+ }
+
+ result = parse("1.2.3-alpha-1+build.11.e0f985a")
+ assert result == {
+ 'major': 1,
+ 'minor': 2,
+ 'patch': 3,
+ 'prerelease': 'alpha-1',
+ 'build': 'build.11.e0f985a',
+ }
+
+
+def test_should_parse_zero_prerelease():
+ result = parse("1.2.3-rc.0+build.0")
+
+ assert result == {
+ 'major': 1,
+ 'minor': 2,
+ 'patch': 3,
+ 'prerelease': 'rc.0',
+ 'build': 'build.0',
+ }
+
+ result = parse("1.2.3-rc.0.0+build.0")
+
+ assert result == {
+ 'major': 1,
+ 'minor': 2,
+ 'patch': 3,
+ 'prerelease': 'rc.0.0',
+ 'build': 'build.0',
+ }
+
+
+def test_should_get_less():
+ assert compare("1.0.0", "2.0.0") == -1
+ assert compare('1.0.0-alpha', '1.0.0-alpha.1') == -1
+ assert compare('1.0.0-alpha.1', '1.0.0-alpha.beta') == -1
+ assert compare('1.0.0-alpha.beta', '1.0.0-beta') == -1
+ assert compare('1.0.0-beta', '1.0.0-beta.2') == -1
+ assert compare('1.0.0-beta.2', '1.0.0-beta.11') == -1
+ assert compare('1.0.0-beta.11', '1.0.0-rc.1') == -1
+ assert compare('1.0.0-rc.1', '1.0.0') == -1
+
+
+def test_should_get_greater():
+ assert compare("2.0.0", "1.0.0") == 1
+ assert compare('1.0.0-alpha.1', '1.0.0-alpha') == 1
+ assert compare('1.0.0-alpha.beta', '1.0.0-alpha.1') == 1
+ assert compare('1.0.0-beta', '1.0.0-alpha.beta') == 1
+ assert compare('1.0.0-beta.2', '1.0.0-beta') == 1
+ assert compare('1.0.0-beta.11', '1.0.0-beta.2') == 1
+ assert compare('1.0.0-rc.1', '1.0.0-beta.11') == 1
+ assert compare('1.0.0', '1.0.0-rc.1') == 1
+
+
+def test_should_match_simple():
+ assert match("2.3.7", ">=2.3.6") is True
+
+
+def test_should_no_match_simple():
+ assert match("2.3.7", ">=2.3.8") is False
+
+
+def test_should_match_not_equal():
+ assert match("2.3.7", "!=2.3.8") is True
+ assert match("2.3.7", "!=2.3.6") is True
+ assert match("2.3.7", "!=2.3.7") is False
+
+
+def test_should_not_raise_value_error_for_expected_match_expression():
+ assert match("2.3.7", "<2.4.0") is True
+ assert match("2.3.7", ">2.3.5") is True
+
+ assert match("2.3.7", "<=2.3.9") is True
+ assert match("2.3.7", ">=2.3.5") is True
+ assert match("2.3.7", "==2.3.7") is True
+ assert match("2.3.7", "!=2.3.7") is False
+
+
+def test_should_raise_value_error_for_unexpected_match_expression():
+ with pytest.raises(ValueError):
+ match("2.3.7", "=2.3.7")
+ with pytest.raises(ValueError):
+ match("2.3.7", "~2.3.7")
+ with pytest.raises(ValueError):
+ match("2.3.7", "^2.3.7")
+
+
+def test_should_raise_value_error_for_zero_prefixed_versions():
+ with pytest.raises(ValueError):
+ parse("01.2.3")
+ with pytest.raises(ValueError):
+ parse("1.02.3")
+ with pytest.raises(ValueError):
+ parse("1.2.03")
+
+
+def test_should_raise_value_error_for_invalid_value():
+ with pytest.raises(ValueError):
+ compare('foo', 'bar')
+ with pytest.raises(ValueError):
+ compare('1.0', '1.0.0')
+ with pytest.raises(ValueError):
+ compare('1.x', '1.0.0')
+
+
+def test_should_raise_value_error_for_invalid_match_expression():
+ with pytest.raises(ValueError):
+ match('1.0.0', '')
+ with pytest.raises(ValueError):
+ match('1.0.0', '!')
+ with pytest.raises(ValueError):
+ match('1.0.0', '1.0.0')
+
+
+def test_should_follow_specification_comparison():
+ """
+ produce comparison chain:
+ 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < 1.0.0-beta.11
+ < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 < 1.3.7+build
+ < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a
+ and in backward too.
+ """
+ chain = [
+ '1.0.0-alpha', '1.0.0-alpha.1', '1.0.0-beta.2', '1.0.0-beta.11',
+ '1.0.0-rc.1', '1.0.0', '1.3.7+build',
+ ]
+ versions = zip(chain[:-1], chain[1:])
+ for low_version, high_version in versions:
+ assert compare(low_version, high_version) == -1, \
+ '%s should be lesser than %s' % (low_version, high_version)
+ assert compare(high_version, low_version) == 1, \
+ '%s should be higher than %s' % (high_version, low_version)
+
+
+def test_should_compare_rc_builds():
+ assert compare('1.0.0-beta.2', '1.0.0-beta.11') == -1
+
+
+def test_should_compare_release_candidate_with_release():
+ assert compare('1.0.0-rc.1', '1.0.0') == -1
+ assert compare('1.0.0-rc.1+build.1', '1.0.0') == -1
+
+
+def test_should_say_equal_versions_are_equal():
+ assert compare('2.0.0', '2.0.0') == 0
+ assert compare('1.1.9-rc.1', '1.1.9-rc.1') == 0
+ assert compare('1.1.9+build.1', '1.1.9+build.1') == 0
+ assert compare('1.1.9-rc.1+build.1', '1.1.9-rc.1+build.1') == 0
+
+
+def test_should_compare_versions_with_build_and_release():
+ assert compare('1.1.9-rc.1', '1.1.9-rc.1+build.1') == 0
+ assert compare('1.1.9-rc.1', '1.1.9+build.1') == -1
+
+
+def test_should_ignore_builds_on_compare():
+ assert compare('1.0.0+build.1', '1.0.0') == 0
+ assert compare('1.0.0-alpha.1+build.1', '1.0.0-alpha.1') == 0
+ assert compare('1.0.0+build.1', '1.0.0-alpha.1') == 1
+ assert compare('1.0.0+build.1', '1.0.0-alpha.1+build.1') == 1
+
+
+def test_should_correctly_format_version():
+ assert format_version(3, 4, 5) == '3.4.5'
+ assert format_version(3, 4, 5, 'rc.1') == '3.4.5-rc.1'
+ assert format_version(3, 4, 5, prerelease='rc.1') == '3.4.5-rc.1'
+ assert format_version(3, 4, 5, build='build.4') == '3.4.5+build.4'
+ assert format_version(3, 4, 5, 'rc.1', 'build.4') == '3.4.5-rc.1+build.4'
+
+
+def test_should_bump_major():
+ assert bump_major('3.4.5') == '4.0.0'
+
+
+def test_should_bump_minor():
+ assert bump_minor('3.4.5') == '3.5.0'
+
+
+def test_should_bump_patch():
+ assert bump_patch('3.4.5') == '3.4.6'
+
+
+def test_should_ignore_extensions_for_bump():
+ assert bump_patch('3.4.5-rc1+build4') == '3.4.6'
+
+
+def test_should_get_max():
+ assert max_ver('3.4.5', '4.0.2') == '4.0.2'
+
+
+def test_should_get_min():
+ assert min_ver('3.4.5', '4.0.2') == '3.4.5'
+
+
+def test_should_get_min_same():
+ assert min_ver('3.4.5', '3.4.5') == '3.4.5'
+
+
+def test_should_get_more_rc1():
+ assert compare("1.0.0-rc1", "1.0.0-rc0") == 1
+
+
+def test_prerelease_order():
+ assert min_ver('1.2.3-rc.2', '1.2.3-rc.10') == '1.2.3-rc.2'
+ assert min_ver('1.2.3-rc2', '1.2.3-rc10') == '1.2.3-rc10'
+ # identifiers with letters or hyphens are compared lexically in ASCII sort
+ # order.
+ assert min_ver('1.2.3-Rc10', '1.2.3-rc10') == '1.2.3-Rc10'
+ # Numeric identifiers always have lower precedence than non-numeric
+ # identifiers.
+ assert min_ver('1.2.3-2', '1.2.3-rc') == '1.2.3-2'
+ # A larger set of pre-release fields has a higher precedence than a
+ # smaller set, if all of the preceding identifiers are equal.
+ assert min_ver('1.2.3-rc.2.1', '1.2.3-rc.2') == '1.2.3-rc.2'
+ # When major, minor, and patch are equal, a pre-release version has lower
+ # precedence than a normal version.
+ assert min_ver('1.2.3', '1.2.3-1') == '1.2.3-1'
+ assert min_ver('1.0.0-alpha', '1.0.0-alpha.1') == '1.0.0-alpha'
+
+
+def test_should_bump_prerelease():
+ assert bump_prerelease('3.4.5-rc.9') == '3.4.5-rc.10'
+ assert bump_prerelease('3.4.5') == '3.4.5-rc.1'
+ assert bump_prerelease('3.4.5', 'dev') == '3.4.5-dev.1'
+ assert bump_prerelease('3.4.5', '') == '3.4.5-rc.1'
+
+
+def test_should_ignore_build_on_prerelease_bump():
+ assert bump_prerelease('3.4.5-rc.1+build.4') == '3.4.5-rc.2'
+
+
+def test_should_bump_build():
+ assert bump_build('3.4.5-rc.1+build.9') == '3.4.5-rc.1+build.10'
+ 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'
+ assert bump_build('3.4.5', 'nightly') == '3.4.5+nightly.1'
+ assert bump_build('3.4.5', '') == '3.4.5+build.1'
+
+
+def test_should_finalize_version():
+ assert finalize_version('1.2.3') == '1.2.3'
+ assert finalize_version('1.2.3-rc.5') == '1.2.3'
+ assert finalize_version('1.2.3+build.2') == '1.2.3'
+ assert finalize_version('1.2.3-rc.1+build.5') == '1.2.3'
+ assert finalize_version('1.2.3-alpha') == '1.2.3'
+ assert finalize_version('1.2.0') == '1.2.0'
+
+
+def test_should_compare_version_info_objects():
+ v1 = VersionInfo(major=0, minor=10, patch=4, prerelease=None, build=None)
+ v2 = VersionInfo(
+ major=0, minor=10, patch=4, prerelease='beta.1', build=None)
+
+ # use `not` to enforce using comparision operators
+ assert v1 != v2
+ assert v1 > v2
+ assert v1 >= v2
+ assert not(v1 < v2)
+ assert not(v1 <= v2)
+ assert not(v1 == v2)
+
+ v3 = VersionInfo(major=0, minor=10, patch=4, prerelease=None, build=None)
+
+ assert not(v1 != v3)
+ assert not(v1 > v3)
+ assert v1 >= v3
+ assert not(v1 < v3)
+ assert v1 <= v3
+ assert v1 == v3
+
+ v4 = VersionInfo(major=0, minor=10, patch=5, prerelease=None, build=None)
+ assert v1 != v4
+ assert not(v1 > v4)
+ assert not(v1 >= v4)
+ assert v1 < v4
+ assert v1 <= v4
+ assert not(v1 == v4)
+
+
+def test_should_compare_version_dictionaries():
+ v1 = VersionInfo(major=0, minor=10, patch=4, prerelease=None, build=None)
+ v2 = dict(major=0, minor=10, patch=4, prerelease='beta.1', build=None)
+
+ assert v1 != v2
+ assert v1 > v2
+ assert v1 >= v2
+ assert not(v1 < v2)
+ assert not(v1 <= v2)
+ assert not(v1 == v2)
+
+ v3 = dict(major=0, minor=10, patch=4, prerelease=None, build=None)
+
+ assert not(v1 != v3)
+ assert not(v1 > v3)
+ assert v1 >= v3
+ assert not(v1 < v3)
+ assert v1 <= v3
+ assert v1 == v3
+
+ v4 = dict(major=0, minor=10, patch=5, prerelease=None, build=None)
+ assert v1 != v4
+ assert not(v1 > v4)
+ assert not(v1 >= v4)
+ assert v1 < v4
+ assert v1 <= v4
+ assert not(v1 == v4)
+
+
+def test_should_compare_prerelease_with_numbers_and_letters():
+ v1 = VersionInfo(major=1, minor=9, patch=1, prerelease='1unms', build=None)
+ v2 = VersionInfo(major=1, minor=9, patch=1, prerelease=None, build='1asd')
+ assert v1 < v2
+ assert compare("1.9.1-1unms", "1.9.1+1") == -1
diff --git a/circuitpython/tools/python-semver/tox.ini b/circuitpython/tools/python-semver/tox.ini
new file mode 100644
index 0000000..c909157
--- /dev/null
+++ b/circuitpython/tools/python-semver/tox.ini
@@ -0,0 +1,16 @@
+[tox]
+envlist =
+ flake8
+ py{26,27,32,33,34,35,36}
+ pypy
+
+[testenv]
+commands = py.test -q tests.py
+deps = pytest
+setenv =
+ PIP_DISABLE_PIP_VERSION_CHECK = 1
+
+[testenv:flake8]
+basepython = python3.4
+deps = flake8
+commands = flake8