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