1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# distutils/version.py 3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Implements multiple version numbering conventions for the 5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Python Module Distribution Utilities. 6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# $Id$ 8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""Provides classes to represent module version numbers (one class for 11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieheach style of version numbering). There are currently two such classes 12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimplemented: StrictVersion and LooseVersion. 13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehEvery version number class implements the following interface: 15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * the 'parse' method takes a string and parses it to some internal 16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh representation; if the string is an invalid version number, 17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 'parse' raises a ValueError exception 18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * the class constructor takes an optional string argument which, 19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if supplied, is passed to 'parse' 20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * __str__ reconstructs the string that was passed to 'parse' (or 21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh an equivalent string -- ie. one that will generate an equivalent 22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh version number instance) 23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * __repr__ generates Python code to recreate the version number instance 24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh * __cmp__ compares the current instance with either another instance 25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh of the same class or a string (which will be parsed to an instance 26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh of the same class, thus must follow the same rules) 27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh""" 28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport string, re 30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom types import StringType 31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass Version: 33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Abstract base class for version numbering classes. Just provides 34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh constructor (__init__) and reproducer (__repr__), because those 35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh seem to be the same for all version numbering classes. 36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__ (self, vstring=None): 39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if vstring: 40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.parse(vstring) 41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __repr__ (self): 43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return "%s ('%s')" % (self.__class__.__name__, str(self)) 44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Interface for version-number classes -- must be implemented 47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# by the following classes (the concrete ones -- Version should 48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# be treated as an abstract class). 49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# __init__ (string) - create and take same action as 'parse' 50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# (string parameter is optional) 51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# parse (string) - convert a string representation to whatever 52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# internal representation is appropriate for 53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# this style of version numbering 54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# __str__ (self) - convert back to a string; should be very similar 55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# (if not identical to) the string supplied to parse 56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# __repr__ (self) - generate Python code to recreate 57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# the instance 58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# __cmp__ (self, other) - compare two version numbers ('other' may 59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# be an unparsed version string, or another 60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# instance of your version class) 61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass StrictVersion (Version): 64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Version numbering for anal retentives and software idealists. 66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Implements the standard interface for version number classes as 67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh described above. A version number consists of two or three 68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh dot-separated numeric components, with an optional "pre-release" tag 69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh on the end. The pre-release tag consists of the letter 'a' or 'b' 70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh followed by a number. If the numeric components of two version 71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh numbers are equal, then one with a pre-release tag will always 72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh be deemed earlier (lesser) than one without. 73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh The following are valid version numbers (shown in the order that 75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh would be obtained by sorting according to the supplied cmp function): 76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0.4 0.4.0 (these two are equivalent) 78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0.4.1 79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0.5a1 80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0.5b3 81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0.5 82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0.9.6 83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.0 84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.0.4a3 85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.0.4b1 86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.0.4 87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh The following are examples of invalid version numbers: 89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1 91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 2.7.2.2 92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.3.a4 93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.3pl1 94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.3c4 95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh The rationale for this version numbering system will be explained 97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh in the distutils documentation. 98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$', 101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh re.VERBOSE) 102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def parse (self, vstring): 105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh match = self.version_re.match(vstring) 106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not match: 107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise ValueError, "invalid version number '%s'" % vstring 108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh (major, minor, patch, prerelease, prerelease_num) = \ 110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh match.group(1, 2, 4, 5, 6) 111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if patch: 113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.version = tuple(map(string.atoi, [major, minor, patch])) 114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.version = tuple(map(string.atoi, [major, minor]) + [0]) 116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if prerelease: 118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.prerelease = (prerelease[0], string.atoi(prerelease_num)) 119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.prerelease = None 121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __str__ (self): 124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self.version[2] == 0: 126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh vstring = string.join(map(str, self.version[0:2]), '.') 127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: 128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh vstring = string.join(map(str, self.version), '.') 129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self.prerelease: 131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh vstring = vstring + self.prerelease[0] + str(self.prerelease[1]) 132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return vstring 134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __cmp__ (self, other): 137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if isinstance(other, StringType): 138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh other = StrictVersion(other) 139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh compare = cmp(self.version, other.version) 141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if (compare == 0): # have to compare prerelease 142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # case 1: neither has prerelease; they're equal 144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # case 2: self has prerelease, other doesn't; other is greater 145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # case 3: self doesn't have prerelease, other does: self is greater 146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # case 4: both have prerelease: must compare them! 147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if (not self.prerelease and not other.prerelease): 149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 0 150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif (self.prerelease and not other.prerelease): 151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return -1 152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif (not self.prerelease and other.prerelease): 153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return 1 154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh elif (self.prerelease and other.prerelease): 155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return cmp(self.prerelease, other.prerelease) 156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh else: # numeric versions don't match -- 158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return compare # prerelease stuff doesn't matter 159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# end class StrictVersion 162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# The rules according to Greg Stein: 165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 1) a version number has 1 or more numbers separated by a period or by 166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# sequences of letters. If only periods, then these are compared 167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# left-to-right to determine an ordering. 168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 2) sequences of letters are part of the tuple for comparison and are 169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# compared lexicographically 170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 3) recognize the numeric components may have leading zeroes 171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# The LooseVersion class below implements these rules: a version number 173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# string is split up into a tuple of integer and string components, and 174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# comparison is a simple tuple comparison. This means that version 175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# numbers behave in a predictable and obvious way, but a way that might 176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# not necessarily be how people *want* version numbers to behave. There 177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# wouldn't be a problem if people could stick to purely numeric version 178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# numbers: just split on period and compare the numbers as tuples. 179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# However, people insist on putting letters into their version numbers; 180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# the most common purpose seems to be: 181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# - indicating a "pre-release" version 182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# ('alpha', 'beta', 'a', 'b', 'pre', 'p') 183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# - indicating a post-release patch ('p', 'pl', 'patch') 184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# but of course this can't cover all version number schemes, and there's 185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# no way to know what a programmer means without asking him. 186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# The problem is what to do with letters (and other non-numeric 188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# characters) in a version number. The current implementation does the 189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# obvious and predictable thing: keep them as strings and compare 190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# lexically within a tuple comparison. This has the desired effect if 191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# an appended letter sequence implies something "post-release": 192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002". 193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# However, if letters in a version number imply a pre-release version, 195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# the "obvious" thing isn't correct. Eg. you would expect that 196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison 197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# implemented here, this just isn't so. 198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Two possible solutions come to mind. The first is to tie the 200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# comparison algorithm to a particular set of semantic rules, as has 201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# been done in the StrictVersion class above. This works great as long 202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# as everyone can go along with bondage and discipline. Hopefully a 203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# (large) subset of Python module programmers will agree that the 204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# particular flavour of bondage and discipline provided by StrictVersion 205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# provides enough benefit to be worth using, and will submit their 206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# version numbering scheme to its domination. The free-thinking 207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# anarchists in the lot will never give in, though, and something needs 208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# to be done to accommodate them. 209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Perhaps a "moderately strict" version class could be implemented that 211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# lets almost anything slide (syntactically), and makes some heuristic 212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# assumptions about non-digits in version number strings. This could 213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# sink into special-case-hell, though; if I was as talented and 214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# idiosyncratic as Larry Wall, I'd go ahead and implement a class that 215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is 216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# just as happy dealing with things like "2g6" and "1.13++". I don't 217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# think I'm smart enough to do it right though. 218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# 219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# In any case, I've coded the test suite for this module (see 220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# ../test/test_version.py) specifically to fail on things like comparing 221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# "1.2a2" and "1.2". That's not because the *code* is doing anything 222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# wrong, it's because the simple, obvious design doesn't match my 223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# complicated, hairy expectations for real-world version numbers. It 224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# would be a snap to fix the test suite to say, "Yep, LooseVersion does 225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# the Right Thing" (ie. the code matches the conception). But I'd rather 226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# have a conception that matches common notions about version numbers. 227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass LooseVersion (Version): 229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """Version numbering for anarchists and software realists. 231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh Implements the standard interface for version number classes as 232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh described above. A version number consists of a series of numbers, 233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh separated by either periods or strings of letters. When comparing 234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh version numbers, the numeric components will be compared 235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh numerically, and the alphabetic components lexically. The following 236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh are all valid version numbers, in no particular order: 237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.5.1 239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.5.2b2 240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 161 241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 3.10a 242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 8.02 243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 3.4j 244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1996.07.12 245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 3.2.pl0 246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 3.1.1.6 247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 2g6 248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 11g 249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0.960923 250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 2.2beta29 251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 1.13++ 252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 5.5.kw 253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 2.0b1pl0 254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh In fact, there is no such thing as an invalid version number under 256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh this scheme; the rules for comparison are simple and predictable, 257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh but may not always give the results you want (for some definition 258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh of "want"). 259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh """ 260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) 262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__ (self, vstring=None): 264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if vstring: 265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.parse(vstring) 266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def parse (self, vstring): 269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # I've given up on thinking I can reconstruct the version string 270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # from the parsed tuple -- so I just store the string here for 271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh # use by __str__ 272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.vstring = vstring 273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh components = filter(lambda x: x and x != '.', 274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.component_re.split(vstring)) 275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for i in range(len(components)): 276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh try: 277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh components[i] = int(components[i]) 278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh except ValueError: 279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh pass 280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.version = components 282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __str__ (self): 285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return self.vstring 286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __repr__ (self): 289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return "LooseVersion ('%s')" % str(self) 290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __cmp__ (self, other): 293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if isinstance(other, StringType): 294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh other = LooseVersion(other) 295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return cmp(self.version, other.version) 297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# end class LooseVersion 300