You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

349 lines
12 KiB

Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Restructure comparison dramatically. There is no longer a default *ordering* between objects; there is only a default equality test (defined by an object being equal to itself only). Read the comment in object.c. The current implementation never uses a three-way comparison to compute a rich comparison, but it does use a rich comparison to compute a three-way comparison. I'm not quite done ripping out all the calls to PyObject_Compare/Cmp, or replacing tp_compare implementations with tp_richcompare implementations; but much of that has happened (to make most unit tests pass). The following tests still fail, because I need help deciding or understanding: test_codeop -- depends on comparing code objects test_datetime -- need Tim Peters' opinion test_marshal -- depends on comparing code objects test_mutants -- need help understanding it The problem with test_codeop and test_marshal is this: these tests compare two different code objects and expect them to be equal. Is that still a feature we'd like to support? I've temporarily removed the comparison and hash code from code objects, so they use the default (equality by pointer only) comparison. For the other two tests, run them to see for yourself. (There may be more failing test with "-u all".) A general problem with getting lots of these tests to pass is the reality that for object types that have a natural total ordering, implementing __cmp__ is much more convenient than implementing __eq__, __ne__, __lt__, and so on. Should we go back to allowing __cmp__ to provide a total ordering? Should we provide some other way to implement rich comparison with a single method override? Alex proposed a __key__() method; I've considered a __richcmp__() method. Or perhaps __cmp__() just shouldn't be killed off...
20 years ago
Merged revisions 56125-56153 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/p3yk ........ r56127 | georg.brandl | 2007-06-30 09:32:49 +0200 (Sat, 30 Jun 2007) | 2 lines Fix a place where floor division would be in order. ........ r56135 | guido.van.rossum | 2007-07-01 06:13:54 +0200 (Sun, 01 Jul 2007) | 28 lines Make map() and filter() identical to itertools.imap() and .ifilter(), respectively. I fixed two bootstrap issues, due to the dynamic import of itertools: 1. Starting python requires that map() and filter() are not used until site.py has added build/lib.<arch> to sys.path. 2. Building python requires that setup.py and distutils and everything they use is free of map() and filter() calls. Beyond this, I only fixed the tests in test_builtin.py. Others, please help fixing the remaining tests that are now broken! The fixes are usually simple: a. map(None, X) -> list(X) b. map(F, X) -> list(map(F, X)) c. map(lambda x: F(x), X) -> [F(x) for x in X] d. filter(F, X) -> list(filter(F, X)) e. filter(lambda x: P(x), X) -> [x for x in X if P(x)] Someone, please also contribute a fixer for 2to3 to do this. It can leave map()/filter() calls alone that are already inside a list() or sorted() call or for-loop. Only in rare cases have I seen code that depends on map() of lists of different lengths going to the end of the longest, or on filter() of a string or tuple returning an object of the same type; these will need more thought to fix. ........ r56136 | guido.van.rossum | 2007-07-01 06:22:01 +0200 (Sun, 01 Jul 2007) | 3 lines Make it so that test_decimal fails instead of hangs, to help automated test runners. ........ r56139 | georg.brandl | 2007-07-01 18:20:58 +0200 (Sun, 01 Jul 2007) | 2 lines Fix a few test cases after the map->imap change. ........ r56142 | neal.norwitz | 2007-07-02 06:38:12 +0200 (Mon, 02 Jul 2007) | 1 line Get a bunch more tests passing after converting map/filter to return iterators. ........ r56147 | guido.van.rossum | 2007-07-02 15:32:02 +0200 (Mon, 02 Jul 2007) | 4 lines Fix the remaining failing unit tests (at least on OSX). Also tweaked urllib2 so it doesn't raise socket.gaierror when all network interfaces are turned off. ........
19 years ago
Merged revisions 70578,70599,70641-70642,70650,70660-70661,70674,70691,70697-70698,70700,70704 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r70578 | benjamin.peterson | 2009-03-23 22:24:56 -0500 (Mon, 23 Mar 2009) | 1 line this is better written using assertRaises ........ r70599 | benjamin.peterson | 2009-03-25 16:42:51 -0500 (Wed, 25 Mar 2009) | 1 line this can be slightly less ugly ........ r70641 | guilherme.polo | 2009-03-27 16:43:08 -0500 (Fri, 27 Mar 2009) | 3 lines Adjusted _tkinter to compile without warnings when WITH_THREAD is not defined (part of issue #5035) ........ r70642 | georg.brandl | 2009-03-27 19:48:48 -0500 (Fri, 27 Mar 2009) | 1 line Fix typo. ........ r70650 | benjamin.peterson | 2009-03-28 14:16:10 -0500 (Sat, 28 Mar 2009) | 1 line give os.symlink and os.link() better parameter names #5564 ........ r70660 | georg.brandl | 2009-03-28 14:52:58 -0500 (Sat, 28 Mar 2009) | 1 line Switch to fixed Sphinx version. ........ r70661 | georg.brandl | 2009-03-28 14:57:36 -0500 (Sat, 28 Mar 2009) | 2 lines Add section numbering to some of the larger subdocuments. ........ r70674 | guilherme.polo | 2009-03-29 05:19:05 -0500 (Sun, 29 Mar 2009) | 1 line Typo fix. ........ r70691 | raymond.hettinger | 2009-03-29 13:51:11 -0500 (Sun, 29 Mar 2009) | 1 line Make life easier for non-CPython implementations. ........ r70697 | benjamin.peterson | 2009-03-29 16:22:35 -0500 (Sun, 29 Mar 2009) | 1 line this has been fixed since 2.6 (I love removing these) ........ r70698 | benjamin.peterson | 2009-03-29 16:31:05 -0500 (Sun, 29 Mar 2009) | 1 line thanks to guido's bytecode verifier, this is fixed ........ r70700 | benjamin.peterson | 2009-03-29 16:50:14 -0500 (Sun, 29 Mar 2009) | 1 line use the awesome new status iterator ........ r70704 | benjamin.peterson | 2009-03-29 21:49:32 -0500 (Sun, 29 Mar 2009) | 1 line there's actually three methods here #5600 ........
17 years ago
  1. #
  2. # distutils/version.py
  3. #
  4. # Implements multiple version numbering conventions for the
  5. # Python Module Distribution Utilities.
  6. #
  7. # $Id$
  8. #
  9. """Provides classes to represent module version numbers (one class for
  10. each style of version numbering). There are currently two such classes
  11. implemented: StrictVersion and LooseVersion.
  12. Every version number class implements the following interface:
  13. * the 'parse' method takes a string and parses it to some internal
  14. representation; if the string is an invalid version number,
  15. 'parse' raises a ValueError exception
  16. * the class constructor takes an optional string argument which,
  17. if supplied, is passed to 'parse'
  18. * __str__ reconstructs the string that was passed to 'parse' (or
  19. an equivalent string -- ie. one that will generate an equivalent
  20. version number instance)
  21. * __repr__ generates Python code to recreate the version number instance
  22. * _cmp compares the current instance with either another instance
  23. of the same class or a string (which will be parsed to an instance
  24. of the same class, thus must follow the same rules)
  25. """
  26. import re
  27. class Version:
  28. """Abstract base class for version numbering classes. Just provides
  29. constructor (__init__) and reproducer (__repr__), because those
  30. seem to be the same for all version numbering classes; and route
  31. rich comparisons to _cmp.
  32. """
  33. def __init__ (self, vstring=None):
  34. if vstring:
  35. self.parse(vstring)
  36. def __repr__ (self):
  37. return "%s ('%s')" % (self.__class__.__name__, str(self))
  38. def __eq__(self, other):
  39. c = self._cmp(other)
  40. if c is NotImplemented:
  41. return c
  42. return c == 0
  43. def __ne__(self, other):
  44. c = self._cmp(other)
  45. if c is NotImplemented:
  46. return c
  47. return c != 0
  48. def __lt__(self, other):
  49. c = self._cmp(other)
  50. if c is NotImplemented:
  51. return c
  52. return c < 0
  53. def __le__(self, other):
  54. c = self._cmp(other)
  55. if c is NotImplemented:
  56. return c
  57. return c <= 0
  58. def __gt__(self, other):
  59. c = self._cmp(other)
  60. if c is NotImplemented:
  61. return c
  62. return c > 0
  63. def __ge__(self, other):
  64. c = self._cmp(other)
  65. if c is NotImplemented:
  66. return c
  67. return c >= 0
  68. # Interface for version-number classes -- must be implemented
  69. # by the following classes (the concrete ones -- Version should
  70. # be treated as an abstract class).
  71. # __init__ (string) - create and take same action as 'parse'
  72. # (string parameter is optional)
  73. # parse (string) - convert a string representation to whatever
  74. # internal representation is appropriate for
  75. # this style of version numbering
  76. # __str__ (self) - convert back to a string; should be very similar
  77. # (if not identical to) the string supplied to parse
  78. # __repr__ (self) - generate Python code to recreate
  79. # the instance
  80. # _cmp (self, other) - compare two version numbers ('other' may
  81. # be an unparsed version string, or another
  82. # instance of your version class)
  83. class StrictVersion (Version):
  84. """Version numbering for anal retentives and software idealists.
  85. Implements the standard interface for version number classes as
  86. described above. A version number consists of two or three
  87. dot-separated numeric components, with an optional "pre-release" tag
  88. on the end. The pre-release tag consists of the letter 'a' or 'b'
  89. followed by a number. If the numeric components of two version
  90. numbers are equal, then one with a pre-release tag will always
  91. be deemed earlier (lesser) than one without.
  92. The following are valid version numbers (shown in the order that
  93. would be obtained by sorting according to the supplied cmp function):
  94. 0.4 0.4.0 (these two are equivalent)
  95. 0.4.1
  96. 0.5a1
  97. 0.5b3
  98. 0.5
  99. 0.9.6
  100. 1.0
  101. 1.0.4a3
  102. 1.0.4b1
  103. 1.0.4
  104. The following are examples of invalid version numbers:
  105. 1
  106. 2.7.2.2
  107. 1.3.a4
  108. 1.3pl1
  109. 1.3c4
  110. The rationale for this version numbering system will be explained
  111. in the distutils documentation.
  112. """
  113. version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$',
  114. re.VERBOSE | re.ASCII)
  115. def parse (self, vstring):
  116. match = self.version_re.match(vstring)
  117. if not match:
  118. raise ValueError("invalid version number '%s'" % vstring)
  119. (major, minor, patch, prerelease, prerelease_num) = \
  120. match.group(1, 2, 4, 5, 6)
  121. if patch:
  122. self.version = tuple(map(int, [major, minor, patch]))
  123. else:
  124. self.version = tuple(map(int, [major, minor])) + (0,)
  125. if prerelease:
  126. self.prerelease = (prerelease[0], int(prerelease_num))
  127. else:
  128. self.prerelease = None
  129. def __str__ (self):
  130. if self.version[2] == 0:
  131. vstring = '.'.join(map(str, self.version[0:2]))
  132. else:
  133. vstring = '.'.join(map(str, self.version))
  134. if self.prerelease:
  135. vstring = vstring + self.prerelease[0] + str(self.prerelease[1])
  136. return vstring
  137. def _cmp (self, other):
  138. if isinstance(other, str):
  139. other = StrictVersion(other)
  140. if self.version != other.version:
  141. # numeric versions don't match
  142. # prerelease stuff doesn't matter
  143. if self.version < other.version:
  144. return -1
  145. else:
  146. return 1
  147. # have to compare prerelease
  148. # case 1: neither has prerelease; they're equal
  149. # case 2: self has prerelease, other doesn't; other is greater
  150. # case 3: self doesn't have prerelease, other does: self is greater
  151. # case 4: both have prerelease: must compare them!
  152. if (not self.prerelease and not other.prerelease):
  153. return 0
  154. elif (self.prerelease and not other.prerelease):
  155. return -1
  156. elif (not self.prerelease and other.prerelease):
  157. return 1
  158. elif (self.prerelease and other.prerelease):
  159. if self.prerelease == other.prerelease:
  160. return 0
  161. elif self.prerelease < other.prerelease:
  162. return -1
  163. else:
  164. return 1
  165. else:
  166. assert False, "never get here"
  167. # end class StrictVersion
  168. # The rules according to Greg Stein:
  169. # 1) a version number has 1 or more numbers separated by a period or by
  170. # sequences of letters. If only periods, then these are compared
  171. # left-to-right to determine an ordering.
  172. # 2) sequences of letters are part of the tuple for comparison and are
  173. # compared lexicographically
  174. # 3) recognize the numeric components may have leading zeroes
  175. #
  176. # The LooseVersion class below implements these rules: a version number
  177. # string is split up into a tuple of integer and string components, and
  178. # comparison is a simple tuple comparison. This means that version
  179. # numbers behave in a predictable and obvious way, but a way that might
  180. # not necessarily be how people *want* version numbers to behave. There
  181. # wouldn't be a problem if people could stick to purely numeric version
  182. # numbers: just split on period and compare the numbers as tuples.
  183. # However, people insist on putting letters into their version numbers;
  184. # the most common purpose seems to be:
  185. # - indicating a "pre-release" version
  186. # ('alpha', 'beta', 'a', 'b', 'pre', 'p')
  187. # - indicating a post-release patch ('p', 'pl', 'patch')
  188. # but of course this can't cover all version number schemes, and there's
  189. # no way to know what a programmer means without asking him.
  190. #
  191. # The problem is what to do with letters (and other non-numeric
  192. # characters) in a version number. The current implementation does the
  193. # obvious and predictable thing: keep them as strings and compare
  194. # lexically within a tuple comparison. This has the desired effect if
  195. # an appended letter sequence implies something "post-release":
  196. # eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002".
  197. #
  198. # However, if letters in a version number imply a pre-release version,
  199. # the "obvious" thing isn't correct. Eg. you would expect that
  200. # "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison
  201. # implemented here, this just isn't so.
  202. #
  203. # Two possible solutions come to mind. The first is to tie the
  204. # comparison algorithm to a particular set of semantic rules, as has
  205. # been done in the StrictVersion class above. This works great as long
  206. # as everyone can go along with bondage and discipline. Hopefully a
  207. # (large) subset of Python module programmers will agree that the
  208. # particular flavour of bondage and discipline provided by StrictVersion
  209. # provides enough benefit to be worth using, and will submit their
  210. # version numbering scheme to its domination. The free-thinking
  211. # anarchists in the lot will never give in, though, and something needs
  212. # to be done to accommodate them.
  213. #
  214. # Perhaps a "moderately strict" version class could be implemented that
  215. # lets almost anything slide (syntactically), and makes some heuristic
  216. # assumptions about non-digits in version number strings. This could
  217. # sink into special-case-hell, though; if I was as talented and
  218. # idiosyncratic as Larry Wall, I'd go ahead and implement a class that
  219. # somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is
  220. # just as happy dealing with things like "2g6" and "1.13++". I don't
  221. # think I'm smart enough to do it right though.
  222. #
  223. # In any case, I've coded the test suite for this module (see
  224. # ../test/test_version.py) specifically to fail on things like comparing
  225. # "1.2a2" and "1.2". That's not because the *code* is doing anything
  226. # wrong, it's because the simple, obvious design doesn't match my
  227. # complicated, hairy expectations for real-world version numbers. It
  228. # would be a snap to fix the test suite to say, "Yep, LooseVersion does
  229. # the Right Thing" (ie. the code matches the conception). But I'd rather
  230. # have a conception that matches common notions about version numbers.
  231. class LooseVersion (Version):
  232. """Version numbering for anarchists and software realists.
  233. Implements the standard interface for version number classes as
  234. described above. A version number consists of a series of numbers,
  235. separated by either periods or strings of letters. When comparing
  236. version numbers, the numeric components will be compared
  237. numerically, and the alphabetic components lexically. The following
  238. are all valid version numbers, in no particular order:
  239. 1.5.1
  240. 1.5.2b2
  241. 161
  242. 3.10a
  243. 8.02
  244. 3.4j
  245. 1996.07.12
  246. 3.2.pl0
  247. 3.1.1.6
  248. 2g6
  249. 11g
  250. 0.960923
  251. 2.2beta29
  252. 1.13++
  253. 5.5.kw
  254. 2.0b1pl0
  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. component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
  261. def __init__ (self, vstring=None):
  262. if vstring:
  263. self.parse(vstring)
  264. def parse (self, vstring):
  265. # I've given up on thinking I can reconstruct the version string
  266. # from the parsed tuple -- so I just store the string here for
  267. # use by __str__
  268. self.vstring = vstring
  269. components = [x for x in self.component_re.split(vstring)
  270. if x and x != '.']
  271. for i, obj in enumerate(components):
  272. try:
  273. components[i] = int(obj)
  274. except ValueError:
  275. pass
  276. self.version = components
  277. def __str__ (self):
  278. return self.vstring
  279. def __repr__ (self):
  280. return "LooseVersion ('%s')" % str(self)
  281. def _cmp (self, other):
  282. if isinstance(other, str):
  283. other = LooseVersion(other)
  284. if self.version == other.version:
  285. return 0
  286. if self.version < other.version:
  287. return -1
  288. if self.version > other.version:
  289. return 1
  290. # end class LooseVersion