Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ee789b9

Browse files
committed
Initial checkin of distutils source files.
1 parent b083a9f commit ee789b9

2 files changed

Lines changed: 301 additions & 0 deletions

File tree

Lib/distutils/__init__.py

Whitespace-only changes.

Lib/distutils/version.py

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

0 commit comments

Comments
 (0)