blob: 8051041679be7ef7d8d5bee989d305b313302dd3 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Marc-André Lemburg246d8472003-04-24 11:36:11 +00002
Brett Cannon8ab27df2003-08-05 03:52:04 +00003""" This module tries to retrieve as much platform-identifying data as
Marc-André Lemburg246d8472003-04-24 11:36:11 +00004 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
Marc-André Lemburg246d8472003-04-24 11:36:11 +000015# Still needed:
16# * more support for WinCE
17# * support for MS-DOS (PythonDX ?)
18# * support for Amiga and other still unsupported platforms running Python
19# * support for additional Linux distributions
20#
Brett Cannon8ab27df2003-08-05 03:52:04 +000021# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000022# checks (in no particular order):
23#
24# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
25# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
26# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000035# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000036# 1.0.6 - added linux_distribution()
37# 1.0.5 - fixed Java support to allow running the module on Jython
38# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000039# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000040# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000041# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000042# 1.0.0 - reformatted a bit and checked into Python CVS
43# 0.8.0 - added sys.version parser and various new access
44# APIs (python_version(), python_compiler(), etc.)
45# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
46# 0.7.1 - added support for Caldera OpenLinux
47# 0.7.0 - some fixes for WinCE; untabified the source file
48# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
49# vms_lib.getsyi() configured
50# 0.6.1 - added code to prevent 'uname -p' on platforms which are
51# known not to support it
52# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
53# did some cleanup of the interfaces - some APIs have changed
54# 0.5.5 - fixed another type in the MacOS code... should have
55# used more coffee today ;-)
56# 0.5.4 - fixed a few typos in the MacOS code
57# 0.5.3 - added experimental MacOS support; added better popen()
58# workarounds in _syscmd_ver() -- still not 100% elegant
59# though
60# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
61# return values (the system uname command tends to return
62# 'unknown' instead of just leaving the field emtpy)
63# 0.5.1 - included code for slackware dist; added exception handlers
64# to cover up situations where platforms don't have os.popen
65# (e.g. Mac) or fail on socket.gethostname(); fixed libc
66# detection RE
67# 0.5.0 - changed the API names referring to system commands to *syscmd*;
68# added java_ver(); made syscmd_ver() a private
69# API (was system_ver() in previous versions) -- use uname()
70# instead; extended the win32_ver() to also return processor
71# type information
72# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
73# 0.3.4 - fixed a bug in _follow_symlinks()
74# 0.3.3 - fixed popen() and "file" command invokation bugs
75# 0.3.2 - added architecture() API and support for it in platform()
76# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
77# 0.3.0 - added system alias support
78# 0.2.3 - removed 'wince' again... oh well.
79# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
80# 0.2.1 - added cache logic and changed the platform string format
81# 0.2.0 - changed the API to use functions instead of module globals
82# since some action take too long to be run on module import
83# 0.1.0 - first release
84#
85# You can always get the latest version of this module at:
86#
87# http://www.egenix.com/files/python/platform.py
88#
89# If that URL should fail, try contacting the author.
90
91__copyright__ = """
92 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Peterson46a99002010-01-09 18:45:30 +000093 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000094
95 Permission to use, copy, modify, and distribute this software and its
96 documentation for any purpose and without fee or royalty is hereby granted,
97 provided that the above copyright notice appear in all copies and that
98 both that copyright notice and this permission notice appear in
99 supporting documentation or portions thereof, including modifications,
100 that you make.
101
102 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
103 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
104 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
105 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
106 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
107 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
108 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
109
110"""
111
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000112__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000113
Victor Stinnerb27ee202010-04-18 18:28:09 +0000114import sys, os, re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000115
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000116### Globals & Constants
117
118# Determine the platform's /dev/null device
119try:
120 DEV_NULL = os.devnull
121except AttributeError:
122 # os.devnull was added in Python 2.4, so emulate it for earlier
123 # Python versions
124 if sys.platform in ('dos','win32','win16','os2'):
125 # Use the old CP/M NUL as device name
126 DEV_NULL = 'NUL'
127 else:
128 # Standard Unix uses /dev/null
129 DEV_NULL = '/dev/null'
130
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000131### Platform specific APIs
132
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000133_libc_search = re.compile(r'(__libc_init)'
134 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000135 '(GLIBC_([0-9.]+))'
136 '|'
Antoine Pitroufd036452008-08-19 17:56:33 +0000137 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000138
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000139def libc_ver(executable=sys.executable,lib='',version='',
140
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000141 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000142
Brett Cannon8ab27df2003-08-05 03:52:04 +0000143 """ Tries to determine the libc version that the file executable
144 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000145
146 Returns a tuple of strings (lib,version) which default to the
147 given parameters in case the lookup fails.
148
149 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000150 libc versions add symbols to the executable and thus is probably
151 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152
153 The file is read and scanned in chunks of chunksize bytes.
154
155 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000156 if hasattr(os.path, 'realpath'):
157 # Python 2.2 introduced os.path.realpath(); it is used
158 # here to work around problems with Cygwin not being
159 # able to open symlinks for reading
160 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000161 f = open(executable,'rb')
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000162 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000163 pos = 0
164 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000165 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000166 if not m:
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000167 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000168 if not binary:
169 break
170 pos = 0
171 continue
172 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
173 if libcinit and not lib:
174 lib = 'libc'
175 elif glibc:
176 if lib != 'glibc':
177 lib = 'glibc'
178 version = glibcversion
179 elif glibcversion > version:
180 version = glibcversion
181 elif so:
182 if lib != 'glibc':
183 lib = 'libc'
184 if soversion > version:
185 version = soversion
186 if threads and version[-len(threads):] != threads:
187 version = version + threads
188 pos = m.end()
189 f.close()
190 return lib,version
191
192def _dist_try_harder(distname,version,id):
193
Tim Peters0eadaac2003-04-24 16:02:54 +0000194 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000195 information in case the default method fails.
196
197 Currently supports older SuSE Linux, Caldera OpenLinux and
198 Slackware Linux distributions.
199
200 """
201 if os.path.exists('/var/adm/inst-log/info'):
202 # SuSE Linux stores distribution information in that file
203 info = open('/var/adm/inst-log/info').readlines()
204 distname = 'SuSE'
205 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000206 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 if len(tv) == 2:
208 tag,value = tv
209 else:
210 continue
211 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000212 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000213 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000214 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 id = values[2]
216 return distname,version,id
217
218 if os.path.exists('/etc/.installed'):
219 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
220 info = open('/etc/.installed').readlines()
221 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000222 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000223 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
224 # XXX does Caldera support non Intel platforms ? If yes,
225 # where can we find the needed id ?
226 return 'OpenLinux',pkg[1],id
227
228 if os.path.isdir('/usr/lib/setup'):
229 # Check for slackware verson tag file (thanks to Greg Andruk)
230 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000231 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000232 if verfiles[n][:14] != 'slack-version-':
233 del verfiles[n]
234 if verfiles:
235 verfiles.sort()
236 distname = 'slackware'
237 version = verfiles[-1][14:]
238 return distname,version,id
239
240 return distname,version,id
241
Antoine Pitroufd036452008-08-19 17:56:33 +0000242_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000243_lsb_release_version = re.compile(r'(.+)'
244 ' release '
245 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000246 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000247_release_version = re.compile(r'([^0-9]+)'
248 '(?: release )?'
249 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000250 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000251
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000252# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000253# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000254# and http://data.linux-ntfs.org/rpm/whichrpm
255# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000256
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000257_supported_dists = (
258 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
259 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
260 'UnitedLinux', 'turbolinux')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000261
262def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000263
Benjamin Peterson25001472010-01-25 03:37:42 +0000264 # Default to empty 'version' and 'id' strings. Both defaults are used
265 # when 'firstline' is empty. 'id' defaults to empty when an id can not
266 # be deduced.
267 version = ''
268 id = ''
269
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000270 # Parse the first line
271 m = _lsb_release_version.match(firstline)
272 if m is not None:
273 # LSB format: "distro release x.x (codename)"
274 return tuple(m.groups())
275
276 # Pre-LSB format: "distro x.x (codename)"
277 m = _release_version.match(firstline)
278 if m is not None:
279 return tuple(m.groups())
280
281 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000282 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000283 if l:
284 version = l[0]
285 if len(l) > 1:
286 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000287 return '', version, id
288
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000289def linux_distribution(distname='', version='', id='',
290
291 supported_dists=_supported_dists,
292 full_distribution_name=1):
293
294 """ Tries to determine the name of the Linux OS distribution name.
295
296 The function first looks for a distribution release file in
297 /etc and then reverts to _dist_try_harder() in case no
298 suitable files are found.
299
300 supported_dists may be given to define the set of Linux
301 distributions to look for. It defaults to a list of currently
302 supported Linux distributions identified by their release file
303 name.
304
305 If full_distribution_name is true (default), the full
306 distribution read from the OS is returned. Otherwise the short
307 name taken from supported_dists is used.
308
309 Returns a tuple (distname,version,id) which default to the
310 args given as parameters.
311
312 """
313 try:
314 etc = os.listdir('/etc')
315 except os.error:
316 # Probably not a Unix system
317 return distname,version,id
318 etc.sort()
319 for file in etc:
320 m = _release_filename.match(file)
321 if m is not None:
322 _distname,dummy = m.groups()
323 if _distname in supported_dists:
324 distname = _distname
325 break
326 else:
327 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000328
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000329 # Read the first line
330 f = open('/etc/'+file, 'r')
331 firstline = f.readline()
332 f.close()
333 _distname, _version, _id = _parse_release_file(firstline)
334
335 if _distname and full_distribution_name:
336 distname = _distname
337 if _version:
338 version = _version
339 if _id:
340 id = _id
341 return distname, version, id
342
343# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000344
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000345def dist(distname='',version='',id='',
346
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000347 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000348
Brett Cannon8ab27df2003-08-05 03:52:04 +0000349 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000350
351 The function first looks for a distribution release file in
352 /etc and then reverts to _dist_try_harder() in case no
353 suitable files are found.
354
Brett Cannon8ab27df2003-08-05 03:52:04 +0000355 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000356 args given as parameters.
357
358 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000359 return linux_distribution(distname, version, id,
360 supported_dists=supported_dists,
361 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000362
363class _popen:
364
365 """ Fairly portable (alternative) popen implementation.
366
367 This is mostly needed in case os.popen() is not available, or
368 doesn't work as advertised, e.g. in Win9X GUI programs like
369 PythonWin or IDLE.
370
371 Writing to the pipe is currently not supported.
372
373 """
374 tmpfile = ''
375 pipe = None
376 bufsize = None
377 mode = 'r'
378
379 def __init__(self,cmd,mode='r',bufsize=None):
380
381 if mode != 'r':
Collin Winterce36ad82007-08-30 01:19:48 +0000382 raise ValueError('popen()-emulation only supports read mode')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383 import tempfile
384 self.tmpfile = tmpfile = tempfile.mktemp()
385 os.system(cmd + ' > %s' % tmpfile)
386 self.pipe = open(tmpfile,'rb')
387 self.bufsize = bufsize
388 self.mode = mode
389
390 def read(self):
391
392 return self.pipe.read()
393
394 def readlines(self):
395
396 if self.bufsize is not None:
397 return self.pipe.readlines()
398
399 def close(self,
400
401 remove=os.unlink,error=os.error):
402
403 if self.pipe:
404 rc = self.pipe.close()
405 else:
406 rc = 255
407 if self.tmpfile:
408 try:
409 remove(self.tmpfile)
410 except error:
411 pass
412 return rc
413
414 # Alias
415 __del__ = close
416
417def popen(cmd, mode='r', bufsize=None):
418
419 """ Portable popen() interface.
420 """
421 # Find a working popen implementation preferring win32pipe.popen
422 # over os.popen over _popen
423 popen = None
424 if os.environ.get('OS','') == 'Windows_NT':
425 # On NT win32pipe should work; on Win9x it hangs due to bugs
426 # in the MS C lib (see MS KnowledgeBase article Q150956)
427 try:
428 import win32pipe
429 except ImportError:
430 pass
431 else:
432 popen = win32pipe.popen
433 if popen is None:
434 if hasattr(os,'popen'):
435 popen = os.popen
436 # Check whether it works... it doesn't in GUI programs
437 # on Windows platforms
438 if sys.platform == 'win32': # XXX Others too ?
439 try:
440 popen('')
441 except os.error:
442 popen = _popen
443 else:
444 popen = _popen
445 if bufsize is None:
446 return popen(cmd,mode)
447 else:
448 return popen(cmd,mode,bufsize)
449
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000450def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000451
Brett Cannon8ab27df2003-08-05 03:52:04 +0000452 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000453 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000455 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456 if build:
457 l.append(build)
458 try:
459 ints = map(int,l)
460 except ValueError:
461 strings = l
462 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000463 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000464 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000465 return version
466
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000467_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
468 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000469 '\[.* ([\d.]+)\])')
470
471# Examples of VER command output:
472#
473# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
474# Windows XP: Microsoft Windows XP [Version 5.1.2600]
475# Windows Vista: Microsoft Windows [Version 6.0.6002]
476#
477# Note that the "Version" string gets localized on different
478# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000479
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000480def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000481
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000482 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000483
484 """ Tries to figure out the OS version used and returns
485 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000486
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000487 It uses the "ver" shell command for this which is known
488 to exists on Windows, DOS and OS/2. XXX Others too ?
489
490 In case this fails, the given parameters are used as
491 defaults.
492
493 """
494 if sys.platform not in supported_platforms:
495 return system,release,version
496
497 # Try some common cmd strings
498 for cmd in ('ver','command /c ver','cmd /c ver'):
499 try:
500 pipe = popen(cmd)
501 info = pipe.read()
502 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000503 raise os.error('command failed')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000504 # XXX How can I supress shell errors from being written
505 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000506 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000507 #print 'Command %s failed: %s' % (cmd,why)
508 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000509 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000510 #print 'Command %s failed: %s' % (cmd,why)
511 continue
512 else:
513 break
514 else:
515 return system,release,version
516
517 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000518 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000519 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000520 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000521 system,release,version = m.groups()
522 # Strip trailing dots from version and release
523 if release[-1] == '.':
524 release = release[:-1]
525 if version[-1] == '.':
526 version = version[:-1]
527 # Normalize the version and build strings (eliminating additional
528 # zeros)
529 version = _norm_version(version)
530 return system,release,version
531
532def _win32_getvalue(key,name,default=''):
533
534 """ Read a value for name from the registry key.
535
536 In case this fails, default is returned.
537
538 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000539 try:
540 # Use win32api if available
541 from win32api import RegQueryValueEx
542 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000543 # On Python 2.0 and later, emulate using winreg
544 import winreg
545 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000546 try:
547 return RegQueryValueEx(key,name)
548 except:
549 return default
550
551def win32_ver(release='',version='',csd='',ptype=''):
552
553 """ Get additional version information from the Windows Registry
554 and return a tuple (version,csd,ptype) referring to version
555 number, CSD level and OS type (multi/single
556 processor).
557
558 As a hint: ptype returns 'Uniprocessor Free' on single
559 processor NT machines and 'Multiprocessor Free' on multi
560 processor machines. The 'Free' refers to the OS version being
561 free of debugging code. It could also state 'Checked' which
562 means the OS version uses debugging code, i.e. code that
563 checks arguments, ranges, etc. (Thomas Heller).
564
Christian Heimes02781dc2008-03-21 01:11:52 +0000565 Note: this function works best with Mark Hammond's win32
566 package installed, but also on Python 2.3 and later. It
567 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000568
569 """
570 # XXX Is there any way to find out the processor type on WinXX ?
571 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000572 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000573 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000574 #
575 # The mappings between reg. values and release names can be found
576 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000577
578 # Import the needed APIs
579 try:
580 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000581 from win32api import RegQueryValueEx, RegOpenKeyEx, \
582 RegCloseKey, GetVersionEx
583 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
584 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000585 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000586 # Emulate the win32api module using Python APIs
587 try:
588 sys.getwindowsversion
589 except AttributeError:
590 # No emulation possible, so return the defaults...
591 return release,version,csd,ptype
592 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000593 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000594 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000595 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000596 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000597 RegQueryValueEx = winreg.QueryValueEx
598 RegOpenKeyEx = winreg.OpenKeyEx
599 RegCloseKey = winreg.CloseKey
600 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000601 VER_PLATFORM_WIN32_WINDOWS = 1
602 VER_PLATFORM_WIN32_NT = 2
603 VER_NT_WORKSTATION = 1
Brian Curtin6e2824d2010-05-06 03:05:50 +0000604 VER_NT_SERVER = 3
605 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606
607 # Find out the registry key and some general version infos
Brian Curtin6e2824d2010-05-06 03:05:50 +0000608 winver = GetVersionEx()
609 maj,min,buildno,plat,csd = winver
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000610 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
Brian Curtin6e2824d2010-05-06 03:05:50 +0000611 if hasattr(winver, "service_pack"):
612 if winver.service_pack != "":
613 csd = 'SP%s' % winver.service_pack_major
614 else:
615 if csd[:13] == 'Service Pack ':
616 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000617
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000618 if plat == VER_PLATFORM_WIN32_WINDOWS:
619 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
620 # Try to guess the release name
621 if maj == 4:
622 if min == 0:
623 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000624 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000625 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000626 elif min == 90:
627 release = 'Me'
628 else:
629 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000630 elif maj == 5:
631 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000632
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000633 elif plat == VER_PLATFORM_WIN32_NT:
634 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
635 if maj <= 4:
636 release = 'NT'
637 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000638 if min == 0:
639 release = '2000'
640 elif min == 1:
641 release = 'XP'
642 elif min == 2:
643 release = '2003Server'
644 else:
645 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000646 elif maj == 6:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000647 if hasattr(winver, "product_type"):
648 product_type = winver.product_type
649 else:
650 product_type = VER_NT_WORKSTATION
651 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
652 # or help from the registry, we cannot properly identify
653 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000654 try:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000655 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
656 name, type = RegQueryValueEx(key, "ProductName")
657 # Discard any type that isn't REG_SZ
658 if type == REG_SZ and name.find("Server") != -1:
659 product_type = VER_NT_SERVER
660 except WindowsError:
661 # Use default of VER_NT_WORKSTATION
662 pass
663
664 if min == 0:
665 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000666 release = 'Vista'
667 else:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000668 release = '2008Server'
669 elif min == 1:
670 if product_type == VER_NT_WORKSTATION:
671 release = '7'
672 else:
673 release = '2008ServerR2'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000674 else:
675 release = 'post2008Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000676
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000677 else:
678 if not release:
679 # E.g. Win3.1 with win32s
680 release = '%i.%i' % (maj,min)
681 return release,version,csd,ptype
682
683 # Open the registry key
684 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000685 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000687 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000688 except:
689 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000690
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000691 # Parse values
692 #subversion = _win32_getvalue(keyCurVer,
693 # 'SubVersionNumber',
694 # ('',1))[0]
695 #if subversion:
696 # release = release + subversion # 95a, 95b, etc.
697 build = _win32_getvalue(keyCurVer,
698 'CurrentBuildNumber',
699 ('',1))[0]
700 ptype = _win32_getvalue(keyCurVer,
701 'CurrentType',
702 (ptype,1))[0]
703
704 # Normalize version
705 version = _norm_version(version,build)
706
707 # Close key
708 RegCloseKey(keyCurVer)
709 return release,version,csd,ptype
710
711def _mac_ver_lookup(selectors,default=None):
712
Benjamin Petersonebacd262008-05-29 21:09:51 +0000713 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000714 l = []
715 append = l.append
716 for selector in selectors:
717 try:
718 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000719 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000720 append(default)
721 return l
722
723def _bcd2str(bcd):
724
725 return hex(bcd)[2:]
726
Ronald Oussorene186e382010-07-23 11:54:59 +0000727def _mac_ver_gestalt():
728 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000729 Thanks to Mark R. Levinson for mailing documentation links and
730 code examples for this function. Documentation for the
731 gestalt() API is available online at:
732
733 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000734 """
735 # Check whether the version info module is available
736 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000737 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000738 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000739 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000740 # Get the infos
Ronald Oussoren19258d52010-02-07 11:33:33 +0000741 sysv, sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000742 # Decode the infos
743 if sysv:
744 major = (sysv & 0xFF00) >> 8
745 minor = (sysv & 0x00F0) >> 4
746 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000747
748 if (major, minor) >= (10, 4):
749 # the 'sysv' gestald cannot return patchlevels
750 # higher than 9. Apple introduced 3 new
751 # gestalt codes in 10.4 to deal with this
752 # issue (needed because patch levels can
753 # run higher than 9, such as 10.4.11)
754 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
755 release = '%i.%i.%i' %(major, minor, patch)
756 else:
757 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000758
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000759 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000760 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000761 0x2: 'PowerPC',
762 0xa: 'i386'}.get(sysa,'')
Ronald Oussorene186e382010-07-23 11:54:59 +0000763
764 return release,versioninfo,machine
765
766def _mac_ver_xml():
767 fn = '/System/Library/CoreServices/SystemVersion.plist'
768 if not os.path.exists(fn):
769 return None
770
771 try:
772 import plistlib
773 except ImportError:
774 return None
775
776 pl = plistlib.readPlist(fn)
777 release = pl['ProductVersion']
778 versioninfo=('', '', '')
779 machine = os.uname()[4]
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000780 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussorene186e382010-07-23 11:54:59 +0000781 # for compatibility with the gestalt based code
782 machine = 'PowerPC'
783
784 return release,versioninfo,machine
785
786
787def mac_ver(release='',versioninfo=('','',''),machine=''):
788
789 """ Get MacOS version information and return it as tuple (release,
790 versioninfo, machine) with versioninfo being a tuple (version,
791 dev_stage, non_release_version).
792
793 Entries which cannot be determined are set to the paramter values
794 which default to ''. All tuple entries are strings.
795 """
796
797 # First try reading the information from an XML file which should
798 # always be present
799 info = _mac_ver_xml()
800 if info is not None:
801 return info
802
803 # If that doesn't work for some reason fall back to reading the
804 # information using gestalt calls.
805 info = _mac_ver_gestalt()
806 if info is not None:
807 return info
808
809 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000810 return release,versioninfo,machine
811
Neal Norwitz9b924c62003-06-29 04:17:45 +0000812def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000813
814 from java.lang import System
815 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000816 value = System.getProperty(name)
817 if value is None:
818 return default
819 return value
820 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821 return default
822
823def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000824
Brett Cannon8ab27df2003-08-05 03:52:04 +0000825 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000826
827 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
828 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
829 tuple (os_name,os_version,os_arch).
830
831 Values which cannot be determined are set to the defaults
832 given as parameters (which all default to '').
833
834 """
835 # Import the needed APIs
836 try:
837 import java.lang
838 except ImportError:
839 return release,vendor,vminfo,osinfo
840
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000841 vendor = _java_getprop('java.vendor', vendor)
842 release = _java_getprop('java.version', release)
843 vm_name, vm_release, vm_vendor = vminfo
844 vm_name = _java_getprop('java.vm.name', vm_name)
845 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
846 vm_release = _java_getprop('java.vm.version', vm_release)
847 vminfo = vm_name, vm_release, vm_vendor
848 os_name, os_version, os_arch = osinfo
849 os_arch = _java_getprop('java.os.arch', os_arch)
850 os_name = _java_getprop('java.os.name', os_name)
851 os_version = _java_getprop('java.os.version', os_version)
852 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000853
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000854 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000855
856### System name aliasing
857
858def system_alias(system,release,version):
859
860 """ Returns (system,release,version) aliased to common
861 marketing names used for some systems.
862
863 It also does some reordering of the information in some cases
864 where it would otherwise cause confusion.
865
866 """
867 if system == 'Rhapsody':
868 # Apple's BSD derivative
869 # XXX How can we determine the marketing release number ?
870 return 'MacOS X Server',system+release,version
871
872 elif system == 'SunOS':
873 # Sun's OS
874 if release < '5':
875 # These releases use the old name SunOS
876 return system,release,version
877 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000878 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000879 if l:
880 try:
881 major = int(l[0])
882 except ValueError:
883 pass
884 else:
885 major = major - 3
886 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000887 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000888 if release < '6':
889 system = 'Solaris'
890 else:
891 # XXX Whatever the new SunOS marketing name is...
892 system = 'Solaris'
893
894 elif system == 'IRIX64':
895 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
896 # is really a version and not a different platform, since 32-bit
897 # apps are also supported..
898 system = 'IRIX'
899 if version:
900 version = version + ' (64bit)'
901 else:
902 version = '64bit'
903
904 elif system in ('win32','win16'):
905 # In case one of the other tricks
906 system = 'Windows'
907
908 return system,release,version
909
910### Various internal helpers
911
912def _platform(*args):
913
914 """ Helper to format the platform string in a filename
915 compatible format e.g. "system-version-machine".
916 """
917 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000918 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000919
920 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000921 platform = platform.replace(' ','_')
922 platform = platform.replace('/','-')
923 platform = platform.replace('\\','-')
924 platform = platform.replace(':','-')
925 platform = platform.replace(';','-')
926 platform = platform.replace('"','-')
927 platform = platform.replace('(','-')
928 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000929
930 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000931 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000932
933 # Fold '--'s and remove trailing '-'
934 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000935 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000936 if cleaned == platform:
937 break
938 platform = cleaned
939 while platform[-1] == '-':
940 platform = platform[:-1]
941
942 return platform
943
944def _node(default=''):
945
946 """ Helper to determine the node name of this machine.
947 """
948 try:
949 import socket
950 except ImportError:
951 # No sockets...
952 return default
953 try:
954 return socket.gethostname()
955 except socket.error:
956 # Still not working...
957 return default
958
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000959def _follow_symlinks(filepath):
960
961 """ In case filepath is a symlink, follow it until a
962 real file is reached.
963 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000964 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000965 while os.path.islink(filepath):
966 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000967 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000968 return filepath
969
970def _syscmd_uname(option,default=''):
971
972 """ Interface to the system's uname command.
973 """
974 if sys.platform in ('dos','win32','win16','os2'):
975 # XXX Others too ?
976 return default
977 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000978 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000979 except (AttributeError,os.error):
980 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000981 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000982 rc = f.close()
983 if not output or rc:
984 return default
985 else:
986 return output
987
988def _syscmd_file(target,default=''):
989
990 """ Interface to the system's file command.
991
992 The function uses the -b option of the file command to have it
993 ommit the filename in its output and if possible the -L option
994 to have the command follow symlinks. It returns default in
995 case the command should fail.
996
997 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000998 if sys.platform in ('dos','win32','win16','os2'):
999 # XXX Others too ?
1000 return default
Victor Stinnerb27ee202010-04-18 18:28:09 +00001001 target = _follow_symlinks(target).replace('"', '\\"')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001002 try:
Victor Stinnerb27ee202010-04-18 18:28:09 +00001003 f = os.popen('file "%s" 2> %s' % (target, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001004 except (AttributeError,os.error):
1005 return default
Victor Stinnerb27ee202010-04-18 18:28:09 +00001006 output = f.read().strip()
1007 rc = f.close()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001008 if not output or rc:
1009 return default
1010 else:
1011 return output
1012
1013### Information about the used architecture
1014
1015# Default values for architecture; non-empty strings override the
1016# defaults given as parameters
1017_default_architecture = {
1018 'win32': ('','WindowsPE'),
1019 'win16': ('','Windows'),
1020 'dos': ('','MSDOS'),
1021}
1022
Victor Stinnerb27ee202010-04-18 18:28:09 +00001023_architecture_split = re.compile(r'[\s,]').split
1024
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001025def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001026
1027 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001028 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001029
Brett Cannon8ab27df2003-08-05 03:52:04 +00001030 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001031 the bit architecture and the linkage format used for the
1032 executable. Both values are returned as strings.
1033
1034 Values that cannot be determined are returned as given by the
1035 parameter presets. If bits is given as '', the sizeof(pointer)
1036 (or sizeof(long) on Python version < 1.5.2) is used as
1037 indicator for the supported pointer size.
1038
1039 The function relies on the system's "file" command to do the
1040 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001041 platforms. On some non-Unix platforms where the "file" command
1042 does not exist and the executable is set to the Python interpreter
1043 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001044
1045 """
1046 # Use the sizeof(pointer) as default number of bits if nothing
1047 # else is given as default.
1048 if not bits:
1049 import struct
1050 try:
1051 size = struct.calcsize('P')
1052 except struct.error:
1053 # Older installations can only query longs
1054 size = struct.calcsize('l')
1055 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001056
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001057 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001058 if executable:
Victor Stinnerb27ee202010-04-18 18:28:09 +00001059 output = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001060 else:
Victor Stinnerb27ee202010-04-18 18:28:09 +00001061 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001062
Victor Stinnerb27ee202010-04-18 18:28:09 +00001063 if not output and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064 executable == sys.executable:
1065 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001066 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +00001067 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001068 b,l = _default_architecture[sys.platform]
1069 if b:
1070 bits = b
1071 if l:
1072 linkage = l
1073 return bits,linkage
1074
Victor Stinnerb27ee202010-04-18 18:28:09 +00001075 # Split the output into a list of strings omitting the filename
1076 fileout = _architecture_split(output)[1:]
1077
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001078 if 'executable' not in fileout:
1079 # Format not supported
1080 return bits,linkage
1081
1082 # Bits
1083 if '32-bit' in fileout:
1084 bits = '32bit'
1085 elif 'N32' in fileout:
1086 # On Irix only
1087 bits = 'n32bit'
1088 elif '64-bit' in fileout:
1089 bits = '64bit'
1090
1091 # Linkage
1092 if 'ELF' in fileout:
1093 linkage = 'ELF'
1094 elif 'PE' in fileout:
1095 # E.g. Windows uses this format
1096 if 'Windows' in fileout:
1097 linkage = 'WindowsPE'
1098 else:
1099 linkage = 'PE'
1100 elif 'COFF' in fileout:
1101 linkage = 'COFF'
1102 elif 'MS-DOS' in fileout:
1103 linkage = 'MSDOS'
1104 else:
1105 # XXX the A.OUT format also falls under this class...
1106 pass
1107
1108 return bits,linkage
1109
1110### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001111
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001112_uname_cache = None
1113
1114def uname():
1115
1116 """ Fairly portable uname interface. Returns a tuple
1117 of strings (system,node,release,version,machine,processor)
1118 identifying the underlying platform.
1119
1120 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001121 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001122
1123 Entries which cannot be determined are set to ''.
1124
1125 """
1126 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001127 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001128
1129 if _uname_cache is not None:
1130 return _uname_cache
1131
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001132 processor = ''
1133
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001134 # Get some infos from the builtin os.uname API...
1135 try:
1136 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001137 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001138 no_os_uname = 1
1139
Georg Brandl62e2ca22010-07-31 21:54:24 +00001140 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001141 # Hmm, no there is either no uname or uname has returned
1142 #'unknowns'... we'll have to poke around the system then.
1143 if no_os_uname:
1144 system = sys.platform
1145 release = ''
1146 version = ''
1147 node = _node()
1148 machine = ''
1149
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001150 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001151
1152 # Try win32_ver() on win32 platforms
1153 if system == 'win32':
1154 release,version,csd,ptype = win32_ver()
1155 if release and version:
1156 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001157 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001158 # available on Win XP and later; see
1159 # http://support.microsoft.com/kb/888731 and
1160 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001161 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001162 # WOW64 processes mask the native architecture
1163 if "PROCESSOR_ARCHITEW6432" in os.environ:
1164 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1165 else:
1166 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001167 if not processor:
1168 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001169
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001170 # Try the 'ver' system command available on some
1171 # platforms
1172 if use_syscmd_ver:
1173 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001174 # Normalize system to what win32_ver() normally returns
1175 # (_syscmd_ver() tends to return the vendor name as well)
1176 if system == 'Microsoft Windows':
1177 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001178 elif system == 'Microsoft' and release == 'Windows':
1179 # Under Windows Vista and Windows Server 2008,
1180 # Microsoft changed the output of the ver command. The
1181 # release is no longer printed. This causes the
1182 # system and release to be misidentified.
1183 system = 'Windows'
1184 if '6.0' == version[:3]:
1185 release = 'Vista'
1186 else:
1187 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001188
1189 # In case we still don't know anything useful, we'll try to
1190 # help ourselves
1191 if system in ('win32','win16'):
1192 if not version:
1193 if system == 'win32':
1194 version = '32bit'
1195 else:
1196 version = '16bit'
1197 system = 'Windows'
1198
1199 elif system[:4] == 'java':
1200 release,vendor,vminfo,osinfo = java_ver()
1201 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001202 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001203 if not version:
1204 version = vendor
1205
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001206 # System specific extensions
1207 if system == 'OpenVMS':
1208 # OpenVMS seems to have release and version mixed up
1209 if not release or release == '0':
1210 release = version
1211 version = ''
1212 # Get processor information
1213 try:
1214 import vms_lib
1215 except ImportError:
1216 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001217 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001218 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1219 if (cpu_number >= 128):
1220 processor = 'Alpha'
1221 else:
1222 processor = 'VAX'
1223 if not processor:
1224 # Get processor information from the uname system command
1225 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001226
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001227 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001228 if system == 'unknown':
1229 system = ''
1230 if node == 'unknown':
1231 node = ''
1232 if release == 'unknown':
1233 release = ''
1234 if version == 'unknown':
1235 version = ''
1236 if machine == 'unknown':
1237 machine = ''
1238 if processor == 'unknown':
1239 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001240
1241 # normalize name
1242 if system == 'Microsoft' and release == 'Windows':
1243 system = 'Windows'
1244 release = 'Vista'
1245
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001246 _uname_cache = system,node,release,version,machine,processor
1247 return _uname_cache
1248
1249### Direct interfaces to some of the uname() return values
1250
1251def system():
1252
1253 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1254
1255 An empty string is returned if the value cannot be determined.
1256
1257 """
1258 return uname()[0]
1259
1260def node():
1261
Brett Cannon8ab27df2003-08-05 03:52:04 +00001262 """ Returns the computer's network name (which may not be fully
1263 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001264
1265 An empty string is returned if the value cannot be determined.
1266
1267 """
1268 return uname()[1]
1269
1270def release():
1271
1272 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1273
1274 An empty string is returned if the value cannot be determined.
1275
1276 """
1277 return uname()[2]
1278
1279def version():
1280
1281 """ Returns the system's release version, e.g. '#3 on degas'
1282
1283 An empty string is returned if the value cannot be determined.
1284
1285 """
1286 return uname()[3]
1287
1288def machine():
1289
1290 """ Returns the machine type, e.g. 'i386'
1291
1292 An empty string is returned if the value cannot be determined.
1293
1294 """
1295 return uname()[4]
1296
1297def processor():
1298
1299 """ Returns the (true) processor name, e.g. 'amdk6'
1300
1301 An empty string is returned if the value cannot be
1302 determined. Note that many platforms do not provide this
1303 information or simply return the same value as for machine(),
1304 e.g. NetBSD does this.
1305
1306 """
1307 return uname()[5]
1308
1309### Various APIs for extracting information from sys.version
1310
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001311_sys_version_parser = re.compile(
1312 r'([\w.+]+)\s*'
1313 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001314 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001315
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001316_ironpython_sys_version_parser = re.compile(
1317 r'IronPython\s*'
1318 '([\d\.]+)'
1319 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001320 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001321
Benjamin Petersone549ead2009-03-28 21:42:05 +00001322_pypy_sys_version_parser = re.compile(
1323 r'([\w.+]+)\s*'
1324 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1325 '\[PyPy [^\]]+\]?')
1326
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001327_sys_version_cache = {}
1328
1329def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001330
1331 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001332 (name, version, branch, revision, buildno, builddate, compiler)
1333 referring to the Python implementation name, version, branch,
1334 revision, build number, build date/time as string and the compiler
1335 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001336
1337 Note that unlike the Python sys.version, the returned value
1338 for the Python version will always include the patchlevel (it
1339 defaults to '.0').
1340
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001341 The function returns empty strings for tuple entries that
1342 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001343
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001344 sys_version may be given to parse an alternative version
1345 string, e.g. if the version was read from a different Python
1346 interpreter.
1347
1348 """
1349 # Get the Python version
1350 if sys_version is None:
1351 sys_version = sys.version
1352
1353 # Try the cache first
1354 result = _sys_version_cache.get(sys_version, None)
1355 if result is not None:
1356 return result
1357
1358 # Parse it
1359 if sys_version[:10] == 'IronPython':
1360 # IronPython
1361 name = 'IronPython'
1362 match = _ironpython_sys_version_parser.match(sys_version)
1363 if match is None:
1364 raise ValueError(
1365 'failed to parse IronPython sys.version: %s' %
1366 repr(sys_version))
1367 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001368 buildno = ''
1369 builddate = ''
1370
1371 elif sys.platform[:4] == 'java':
1372 # Jython
1373 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001374 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001375 if match is None:
1376 raise ValueError(
1377 'failed to parse Jython sys.version: %s' %
1378 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001379 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001380 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001381
1382 elif "PyPy" in sys_version:
1383 # PyPy
1384 name = "PyPy"
1385 match = _pypy_sys_version_parser.match(sys_version)
1386 if match is None:
1387 raise ValueError("failed to parse PyPy sys.version: %s" %
1388 repr(sys_version))
1389 version, buildno, builddate, buildtime = match.groups()
1390 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001391
1392 else:
1393 # CPython
1394 match = _sys_version_parser.match(sys_version)
1395 if match is None:
1396 raise ValueError(
1397 'failed to parse CPython sys.version: %s' %
1398 repr(sys_version))
1399 version, buildno, builddate, buildtime, compiler = \
1400 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001401 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001402 builddate = builddate + ' ' + buildtime
1403
Benjamin Petersone549ead2009-03-28 21:42:05 +00001404 if hasattr(sys, 'subversion'):
1405 # sys.subversion was added in Python 2.5
1406 _, branch, revision = sys.subversion
1407 else:
1408 branch = ''
1409 revision = ''
1410
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001411 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001412 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001413 if len(l) == 2:
1414 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001415 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001416
1417 # Build and cache the result
1418 result = (name, version, branch, revision, buildno, builddate, compiler)
1419 _sys_version_cache[sys_version] = result
1420 return result
1421
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001422def python_implementation():
1423
1424 """ Returns a string identifying the Python implementation.
1425
1426 Currently, the following implementations are identified:
1427 'CPython' (C implementation of Python),
1428 'IronPython' (.NET implementation of Python),
1429 'Jython' (Java implementation of Python).
1430
1431 """
1432 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001433
1434def python_version():
1435
1436 """ Returns the Python version as string 'major.minor.patchlevel'
1437
1438 Note that unlike the Python sys.version, the returned value
1439 will always include the patchlevel (it defaults to 0).
1440
1441 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001442 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001443
1444def python_version_tuple():
1445
1446 """ Returns the Python version as tuple (major, minor, patchlevel)
1447 of strings.
1448
1449 Note that unlike the Python sys.version, the returned value
1450 will always include the patchlevel (it defaults to 0).
1451
1452 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001453 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001454
1455def python_branch():
1456
1457 """ Returns a string identifying the Python implementation
1458 branch.
1459
1460 For CPython this is the Subversion branch from which the
1461 Python binary was built.
1462
1463 If not available, an empty string is returned.
1464
1465 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001466
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001467 return _sys_version()[2]
1468
1469def python_revision():
1470
1471 """ Returns a string identifying the Python implementation
1472 revision.
1473
1474 For CPython this is the Subversion revision from which the
1475 Python binary was built.
1476
1477 If not available, an empty string is returned.
1478
1479 """
1480 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001481
1482def python_build():
1483
1484 """ Returns a tuple (buildno, builddate) stating the Python
1485 build number and date as strings.
1486
1487 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001488 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001489
1490def python_compiler():
1491
1492 """ Returns a string identifying the compiler used for compiling
1493 Python.
1494
1495 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001496 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001497
1498### The Opus Magnum of platform strings :-)
1499
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001500_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001501
1502def platform(aliased=0, terse=0):
1503
1504 """ Returns a single string identifying the underlying platform
1505 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001506
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001507 The output is intended to be human readable rather than
1508 machine parseable. It may look different on different
1509 platforms and this is intended.
1510
1511 If "aliased" is true, the function will use aliases for
1512 various platforms that report system names which differ from
1513 their common names, e.g. SunOS will be reported as
1514 Solaris. The system_alias() function is used to implement
1515 this.
1516
1517 Setting terse to true causes the function to return only the
1518 absolute minimum information needed to identify the platform.
1519
1520 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001521 result = _platform_cache.get((aliased, terse), None)
1522 if result is not None:
1523 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001524
1525 # Get uname information and then apply platform specific cosmetics
1526 # to it...
1527 system,node,release,version,machine,processor = uname()
1528 if machine == processor:
1529 processor = ''
1530 if aliased:
1531 system,release,version = system_alias(system,release,version)
1532
1533 if system == 'Windows':
1534 # MS platforms
1535 rel,vers,csd,ptype = win32_ver(version)
1536 if terse:
1537 platform = _platform(system,release)
1538 else:
1539 platform = _platform(system,release,version,csd)
1540
1541 elif system in ('Linux',):
1542 # Linux based systems
1543 distname,distversion,distid = dist('')
1544 if distname and not terse:
1545 platform = _platform(system,release,machine,processor,
1546 'with',
1547 distname,distversion,distid)
1548 else:
1549 # If the distribution name is unknown check for libc vs. glibc
1550 libcname,libcversion = libc_ver(sys.executable)
1551 platform = _platform(system,release,machine,processor,
1552 'with',
1553 libcname+libcversion)
1554 elif system == 'Java':
1555 # Java platforms
1556 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001557 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001558 platform = _platform(system,release,version)
1559 else:
1560 platform = _platform(system,release,version,
1561 'on',
1562 os_name,os_version,os_arch)
1563
1564 elif system == 'MacOS':
1565 # MacOS platforms
1566 if terse:
1567 platform = _platform(system,release)
1568 else:
1569 platform = _platform(system,release,machine)
1570
1571 else:
1572 # Generic handler
1573 if terse:
1574 platform = _platform(system,release)
1575 else:
1576 bits,linkage = architecture(sys.executable)
1577 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001578
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001579 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001580 return platform
1581
1582### Command line interface
1583
1584if __name__ == '__main__':
1585 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001586 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001587 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001588 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001589 sys.exit(0)