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