Source code for versions.version

import re
import sys

from .errors import Error


if sys.version_info[0] == 3:
    def cmp(a, b):
        if a > b:
            return 1
        elif a < b:
            return -1
        else:  # a == b
            return 0


# Regular expression used to parse versions.
# It parses semantic versions and tries to normalize not semantic versions
# into semantic ones.
RE = re.compile("""
^
(?P<major>\d+)
(?:
    \.
    (?P<minor>\d+)
    (?:
        \.
        (?P<patch>\d+)
    )?
)?
(?:
    -
    (?P<prerelease>[0-9a-zA-Z.-]*)
)?
(?:
    \+
    (?P<build_metadata>[0-9a-zA-Z.-]*)
)?
$
""", re.X)


[docs]class InvalidVersion(Error): """Raised when failing to parse a ``version``. """ def __init__(self, version): #: The bogus version. self.version = version message = 'Invalid version: %r' % version super(InvalidVersion, self).__init__(message)
[docs]class Version(object): """A package version. :param int major: Version major number :param int minor: Version minor number :param int patch: Version patch number :param prerelease: Version prerelease :type prerelease: ``str``, ``int`` or ``None`` :param build_metadata: Version build metadata :type build_metadata: ``None`` or ``set`` of ``str`` This class constructor is usually not called directly. For version string parsing, see ``Version.parse``. """ def __init__(self, major, minor=0, patch=0, prerelease=None, build_metadata=None): #: Version major number self.major = major #: Version minor number self.minor = minor #: Version patch number self.patch = patch #: Version prerelease self.prerelease = prerelease #: Version build metadata self.build_metadata = build_metadata def __hash__(self): build_md_h = hash(tuple(self.build_metadata)) if self.build_metadata \ else hash(None) return hash(self.major) ^ hash(self.minor) ^ hash(self.patch) ^ \ hash(self.prerelease) ^ build_md_h @classmethod
[docs] def parse(cls, version_string): """Parses a ``version_string`` and returns a :py:class:`~Version` object:: >>> Version.parse('1.0.0') > Version.parse('0.1') True """ match = RE.match(version_string) if match: major_str, minor_str, patch_str, prerelease_str, \ build_metadata_str = match.groups() major = int(major_str) if minor_str: minor = int(minor_str) else: minor = 0 if patch_str: patch = int(patch_str) else: patch = 0 if prerelease_str: try: prerelease = int(prerelease_str) except ValueError: prerelease = prerelease_str else: prerelease = None if build_metadata_str: build_metadata = set( s for s in build_metadata_str.split('.') if s) else: build_metadata = None return cls(major, minor, patch, prerelease, build_metadata) else: raise InvalidVersion(version_string)
def __cmp__(self, other): if isinstance(other, str): other = Version.parse(other) if not isinstance(other, Version): raise InvalidVersion(other) if self.major > other.major: return 1 elif self.major < other.major: return -1 else: # self.major == other.major if self.minor > other.minor: return 1 elif self.minor < other.minor: return -1 else: # self.minor == other.minor if self.patch > other.patch: return 1 elif self.patch < other.patch: return -1 else: # self.patch == other.patch if self.prerelease is None and other.prerelease is None: return 0 elif self.prerelease is not None \ and other.prerelease is None: return -1 elif self.prerelease is None \ and other.prerelease is not None: return 1 # self.prerelease is not None and # other.prerelease is not None else: if isinstance(self.prerelease, int) and \ not isinstance(other.prerelease, int): # other string prerelease has precedence return -1 if not isinstance(self.prerelease, int) and \ isinstance(other.prerelease, int): # self string prerelease has precedence return 1 # self.prerelease and other.prerelease are both str # or int return cmp(self.prerelease, other.prerelease) def __eq__(self, other): return self.__cmp__(other) == 0 def __ne__(self, other): return self.__cmp__(other) != 0 def __lt__(self, other): return self.__cmp__(other) < 0 def __gt__(self, other): return self.__cmp__(other) > 0 def __le__(self, other): return self.__cmp__(other) <= 0 def __ge__(self, other): return self.__cmp__(other) >= 0 def __str__(self): """Convert version objects to strings:: >>> str(Version.parse('1.0.0')) == '1.0.0' True >>> str(Version.parse('1.0')) == '1.0.0' True """ version = '%i.%i.%i' % (self.major, self.minor, self.patch) if self.prerelease: version += '-%s' % self.prerelease if self.build_metadata: version += '+' + '.'.join(sorted(self.build_metadata)) return version def __repr__(self): return 'Version.parse(%r)' % str(self)