blob: c2f34b573af47cf56537777e6b1fd1adc1e8bca5 [file] [log] [blame]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001#!/usr/bin/env python
2
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
13# Python SourceForge Project Page and assign them to "lemburg".
14#
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#
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000035# 1.0.6 - added linux_distribution()
36# 1.0.5 - fixed Java support to allow running the module on Jython
37# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000038# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000039# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000040# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000041# 1.0.0 - reformatted a bit and checked into Python CVS
42# 0.8.0 - added sys.version parser and various new access
43# APIs (python_version(), python_compiler(), etc.)
44# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
45# 0.7.1 - added support for Caldera OpenLinux
46# 0.7.0 - some fixes for WinCE; untabified the source file
47# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
48# vms_lib.getsyi() configured
49# 0.6.1 - added code to prevent 'uname -p' on platforms which are
50# known not to support it
51# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
52# did some cleanup of the interfaces - some APIs have changed
53# 0.5.5 - fixed another type in the MacOS code... should have
54# used more coffee today ;-)
55# 0.5.4 - fixed a few typos in the MacOS code
56# 0.5.3 - added experimental MacOS support; added better popen()
57# workarounds in _syscmd_ver() -- still not 100% elegant
58# though
59# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
60# return values (the system uname command tends to return
61# 'unknown' instead of just leaving the field emtpy)
62# 0.5.1 - included code for slackware dist; added exception handlers
63# to cover up situations where platforms don't have os.popen
64# (e.g. Mac) or fail on socket.gethostname(); fixed libc
65# detection RE
66# 0.5.0 - changed the API names referring to system commands to *syscmd*;
67# added java_ver(); made syscmd_ver() a private
68# API (was system_ver() in previous versions) -- use uname()
69# instead; extended the win32_ver() to also return processor
70# type information
71# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
72# 0.3.4 - fixed a bug in _follow_symlinks()
73# 0.3.3 - fixed popen() and "file" command invokation bugs
74# 0.3.2 - added architecture() API and support for it in platform()
75# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
76# 0.3.0 - added system alias support
77# 0.2.3 - removed 'wince' again... oh well.
78# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
79# 0.2.1 - added cache logic and changed the platform string format
80# 0.2.0 - changed the API to use functions instead of module globals
81# since some action take too long to be run on module import
82# 0.1.0 - first release
83#
84# You can always get the latest version of this module at:
85#
86# http://www.egenix.com/files/python/platform.py
87#
88# If that URL should fail, try contacting the author.
89
90__copyright__ = """
91 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000092 Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000093
94 Permission to use, copy, modify, and distribute this software and its
95 documentation for any purpose and without fee or royalty is hereby granted,
96 provided that the above copyright notice appear in all copies and that
97 both that copyright notice and this permission notice appear in
98 supporting documentation or portions thereof, including modifications,
99 that you make.
100
101 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
102 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
103 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
104 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
105 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
106 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
107 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
108
109"""
110
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000111__version__ = '1.0.6'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000112
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000113import sys, os, re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000114
115### Platform specific APIs
116
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000117_libc_search = re.compile(r'(__libc_init)'
118 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000119 '(GLIBC_([0-9.]+))'
120 '|'
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000121 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
122
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000123def libc_ver(executable=sys.executable,lib='',version='',
124
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000125 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000126
Brett Cannon8ab27df2003-08-05 03:52:04 +0000127 """ Tries to determine the libc version that the file executable
128 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000129
130 Returns a tuple of strings (lib,version) which default to the
131 given parameters in case the lookup fails.
132
133 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000134 libc versions add symbols to the executable and thus is probably
135 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000136
137 The file is read and scanned in chunks of chunksize bytes.
138
139 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000140 if hasattr(os.path, 'realpath'):
141 # Python 2.2 introduced os.path.realpath(); it is used
142 # here to work around problems with Cygwin not being
143 # able to open symlinks for reading
144 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000145 f = open(executable,'rb')
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000146 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147 pos = 0
148 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000149 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000150 if not m:
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000151 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152 if not binary:
153 break
154 pos = 0
155 continue
156 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
157 if libcinit and not lib:
158 lib = 'libc'
159 elif glibc:
160 if lib != 'glibc':
161 lib = 'glibc'
162 version = glibcversion
163 elif glibcversion > version:
164 version = glibcversion
165 elif so:
166 if lib != 'glibc':
167 lib = 'libc'
168 if soversion > version:
169 version = soversion
170 if threads and version[-len(threads):] != threads:
171 version = version + threads
172 pos = m.end()
173 f.close()
174 return lib,version
175
176def _dist_try_harder(distname,version,id):
177
Tim Peters0eadaac2003-04-24 16:02:54 +0000178 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000179 information in case the default method fails.
180
181 Currently supports older SuSE Linux, Caldera OpenLinux and
182 Slackware Linux distributions.
183
184 """
185 if os.path.exists('/var/adm/inst-log/info'):
186 # SuSE Linux stores distribution information in that file
187 info = open('/var/adm/inst-log/info').readlines()
188 distname = 'SuSE'
189 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000190 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000191 if len(tv) == 2:
192 tag,value = tv
193 else:
194 continue
195 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000196 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000197 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000198 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000199 id = values[2]
200 return distname,version,id
201
202 if os.path.exists('/etc/.installed'):
203 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
204 info = open('/etc/.installed').readlines()
205 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000206 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
208 # XXX does Caldera support non Intel platforms ? If yes,
209 # where can we find the needed id ?
210 return 'OpenLinux',pkg[1],id
211
212 if os.path.isdir('/usr/lib/setup'):
213 # Check for slackware verson tag file (thanks to Greg Andruk)
214 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000215 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000216 if verfiles[n][:14] != 'slack-version-':
217 del verfiles[n]
218 if verfiles:
219 verfiles.sort()
220 distname = 'slackware'
221 version = verfiles[-1][14:]
222 return distname,version,id
223
224 return distname,version,id
225
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000226_release_filename = re.compile(r'(\w+)[-_](release|version)')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000227_lsb_release_version = re.compile(r'(.+)'
228 ' release '
229 '([\d.]+)'
230 '[^(]*(?:\((.+)\))?')
231_release_version = re.compile(r'([^0-9]+)'
232 '(?: release )?'
233 '([\d.]+)'
234 '[^(]*(?:\((.+)\))?')
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000235
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000236# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000237# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000238# and http://data.linux-ntfs.org/rpm/whichrpm
239# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000240
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000241_supported_dists = (
242 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
243 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
244 'UnitedLinux', 'turbolinux')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000245
246def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000247
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000248 # Parse the first line
249 m = _lsb_release_version.match(firstline)
250 if m is not None:
251 # LSB format: "distro release x.x (codename)"
252 return tuple(m.groups())
253
254 # Pre-LSB format: "distro x.x (codename)"
255 m = _release_version.match(firstline)
256 if m is not None:
257 return tuple(m.groups())
258
259 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000260 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000261 if l:
262 version = l[0]
263 if len(l) > 1:
264 id = l[1]
265 else:
266 id = ''
267 return '', version, id
268
269def _test_parse_release_file():
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000270
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000271 for input, output in (
272 # Examples of release file contents:
273 ('SuSE Linux 9.3 (x86-64)', ('SuSE Linux ', '9.3', 'x86-64'))
274 ('SUSE LINUX 10.1 (X86-64)', ('SUSE LINUX ', '10.1', 'X86-64'))
275 ('SUSE LINUX 10.1 (i586)', ('SUSE LINUX ', '10.1', 'i586'))
276 ('Fedora Core release 5 (Bordeaux)', ('Fedora Core', '5', 'Bordeaux'))
277 ('Red Hat Linux release 8.0 (Psyche)', ('Red Hat Linux', '8.0', 'Psyche'))
278 ('Red Hat Linux release 9 (Shrike)', ('Red Hat Linux', '9', 'Shrike'))
279 ('Red Hat Enterprise Linux release 4 (Nahant)', ('Red Hat Enterprise Linux', '4', 'Nahant'))
280 ('CentOS release 4', ('CentOS', '4', None))
281 ('Rocks release 4.2.1 (Cydonia)', ('Rocks', '4.2.1', 'Cydonia'))
282 ):
283 parsed = _parse_release_file(input)
284 if parsed != output:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000285 print((input, parsed))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000286
287def linux_distribution(distname='', version='', id='',
288
289 supported_dists=_supported_dists,
290 full_distribution_name=1):
291
292 """ Tries to determine the name of the Linux OS distribution name.
293
294 The function first looks for a distribution release file in
295 /etc and then reverts to _dist_try_harder() in case no
296 suitable files are found.
297
298 supported_dists may be given to define the set of Linux
299 distributions to look for. It defaults to a list of currently
300 supported Linux distributions identified by their release file
301 name.
302
303 If full_distribution_name is true (default), the full
304 distribution read from the OS is returned. Otherwise the short
305 name taken from supported_dists is used.
306
307 Returns a tuple (distname,version,id) which default to the
308 args given as parameters.
309
310 """
311 try:
312 etc = os.listdir('/etc')
313 except os.error:
314 # Probably not a Unix system
315 return distname,version,id
316 etc.sort()
317 for file in etc:
318 m = _release_filename.match(file)
319 if m is not None:
320 _distname,dummy = m.groups()
321 if _distname in supported_dists:
322 distname = _distname
323 break
324 else:
325 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000326
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000327 # Read the first line
328 f = open('/etc/'+file, 'r')
329 firstline = f.readline()
330 f.close()
331 _distname, _version, _id = _parse_release_file(firstline)
332
333 if _distname and full_distribution_name:
334 distname = _distname
335 if _version:
336 version = _version
337 if _id:
338 id = _id
339 return distname, version, id
340
341# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000342
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000343def dist(distname='',version='',id='',
344
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000345 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000346
Brett Cannon8ab27df2003-08-05 03:52:04 +0000347 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000348
349 The function first looks for a distribution release file in
350 /etc and then reverts to _dist_try_harder() in case no
351 suitable files are found.
352
Brett Cannon8ab27df2003-08-05 03:52:04 +0000353 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000354 args given as parameters.
355
356 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000357 return linux_distribution(distname, version, id,
358 supported_dists=supported_dists,
359 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000360
361class _popen:
362
363 """ Fairly portable (alternative) popen implementation.
364
365 This is mostly needed in case os.popen() is not available, or
366 doesn't work as advertised, e.g. in Win9X GUI programs like
367 PythonWin or IDLE.
368
369 Writing to the pipe is currently not supported.
370
371 """
372 tmpfile = ''
373 pipe = None
374 bufsize = None
375 mode = 'r'
376
377 def __init__(self,cmd,mode='r',bufsize=None):
378
379 if mode != 'r':
Collin Winterce36ad82007-08-30 01:19:48 +0000380 raise ValueError('popen()-emulation only supports read mode')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000381 import tempfile
382 self.tmpfile = tmpfile = tempfile.mktemp()
383 os.system(cmd + ' > %s' % tmpfile)
384 self.pipe = open(tmpfile,'rb')
385 self.bufsize = bufsize
386 self.mode = mode
387
388 def read(self):
389
390 return self.pipe.read()
391
392 def readlines(self):
393
394 if self.bufsize is not None:
395 return self.pipe.readlines()
396
397 def close(self,
398
399 remove=os.unlink,error=os.error):
400
401 if self.pipe:
402 rc = self.pipe.close()
403 else:
404 rc = 255
405 if self.tmpfile:
406 try:
407 remove(self.tmpfile)
408 except error:
409 pass
410 return rc
411
412 # Alias
413 __del__ = close
414
415def popen(cmd, mode='r', bufsize=None):
416
417 """ Portable popen() interface.
418 """
419 # Find a working popen implementation preferring win32pipe.popen
420 # over os.popen over _popen
421 popen = None
422 if os.environ.get('OS','') == 'Windows_NT':
423 # On NT win32pipe should work; on Win9x it hangs due to bugs
424 # in the MS C lib (see MS KnowledgeBase article Q150956)
425 try:
426 import win32pipe
427 except ImportError:
428 pass
429 else:
430 popen = win32pipe.popen
431 if popen is None:
432 if hasattr(os,'popen'):
433 popen = os.popen
434 # Check whether it works... it doesn't in GUI programs
435 # on Windows platforms
436 if sys.platform == 'win32': # XXX Others too ?
437 try:
438 popen('')
439 except os.error:
440 popen = _popen
441 else:
442 popen = _popen
443 if bufsize is None:
444 return popen(cmd,mode)
445 else:
446 return popen(cmd,mode,bufsize)
447
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000448def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000449
Brett Cannon8ab27df2003-08-05 03:52:04 +0000450 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000451 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000453 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454 if build:
455 l.append(build)
456 try:
457 ints = map(int,l)
458 except ValueError:
459 strings = l
460 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000461 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000462 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000463 return version
464
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000465_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
466 '.*'
467 'Version ([\d.]+))')
468
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000469def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000470
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000471 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000472
473 """ Tries to figure out the OS version used and returns
474 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000475
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000476 It uses the "ver" shell command for this which is known
477 to exists on Windows, DOS and OS/2. XXX Others too ?
478
479 In case this fails, the given parameters are used as
480 defaults.
481
482 """
483 if sys.platform not in supported_platforms:
484 return system,release,version
485
486 # Try some common cmd strings
487 for cmd in ('ver','command /c ver','cmd /c ver'):
488 try:
489 pipe = popen(cmd)
490 info = pipe.read()
491 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000492 raise os.error('command failed')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000493 # XXX How can I supress shell errors from being written
494 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000495 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000496 #print 'Command %s failed: %s' % (cmd,why)
497 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000498 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000499 #print 'Command %s failed: %s' % (cmd,why)
500 continue
501 else:
502 break
503 else:
504 return system,release,version
505
506 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000507 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000508 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000509 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000510 system,release,version = m.groups()
511 # Strip trailing dots from version and release
512 if release[-1] == '.':
513 release = release[:-1]
514 if version[-1] == '.':
515 version = version[:-1]
516 # Normalize the version and build strings (eliminating additional
517 # zeros)
518 version = _norm_version(version)
519 return system,release,version
520
521def _win32_getvalue(key,name,default=''):
522
523 """ Read a value for name from the registry key.
524
525 In case this fails, default is returned.
526
527 """
528 from win32api import RegQueryValueEx
529 try:
530 return RegQueryValueEx(key,name)
531 except:
532 return default
533
534def win32_ver(release='',version='',csd='',ptype=''):
535
536 """ Get additional version information from the Windows Registry
537 and return a tuple (version,csd,ptype) referring to version
538 number, CSD level and OS type (multi/single
539 processor).
540
541 As a hint: ptype returns 'Uniprocessor Free' on single
542 processor NT machines and 'Multiprocessor Free' on multi
543 processor machines. The 'Free' refers to the OS version being
544 free of debugging code. It could also state 'Checked' which
545 means the OS version uses debugging code, i.e. code that
546 checks arguments, ranges, etc. (Thomas Heller).
547
Andrew M. Kuchling47c2ab62003-04-24 16:36:49 +0000548 Note: this function only works if Mark Hammond's win32
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000549 package is installed and obviously only runs on Win32
550 compatible platforms.
551
552 """
553 # XXX Is there any way to find out the processor type on WinXX ?
554 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000555 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000556 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000557 #
558 # The mappings between reg. values and release names can be found
559 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000560
561 # Import the needed APIs
562 try:
563 import win32api
564 except ImportError:
565 return release,version,csd,ptype
566 from win32api import RegQueryValueEx,RegOpenKeyEx,RegCloseKey,GetVersionEx
567 from win32con import HKEY_LOCAL_MACHINE,VER_PLATFORM_WIN32_NT,\
568 VER_PLATFORM_WIN32_WINDOWS
569
570 # Find out the registry key and some general version infos
571 maj,min,buildno,plat,csd = GetVersionEx()
572 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
573 if csd[:13] == 'Service Pack ':
574 csd = 'SP' + csd[13:]
575 if plat == VER_PLATFORM_WIN32_WINDOWS:
576 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
577 # Try to guess the release name
578 if maj == 4:
579 if min == 0:
580 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000581 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000582 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000583 elif min == 90:
584 release = 'Me'
585 else:
586 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000587 elif maj == 5:
588 release = '2000'
589 elif plat == VER_PLATFORM_WIN32_NT:
590 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
591 if maj <= 4:
592 release = 'NT'
593 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000594 if min == 0:
595 release = '2000'
596 elif min == 1:
597 release = 'XP'
598 elif min == 2:
599 release = '2003Server'
600 else:
601 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000602 elif maj == 6:
603 if min == 0:
604 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
605 productType = GetVersionEx(1)[8]
606 if productType == 1: # VER_NT_WORKSTATION
607 release = 'Vista'
608 else:
609 release = '2008Server'
610 else:
611 release = 'post2008Server'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000612 else:
613 if not release:
614 # E.g. Win3.1 with win32s
615 release = '%i.%i' % (maj,min)
616 return release,version,csd,ptype
617
618 # Open the registry key
619 try:
620 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE,regkey)
621 # Get a value to make sure the key exists...
622 RegQueryValueEx(keyCurVer,'SystemRoot')
623 except:
624 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000625
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000626 # Parse values
627 #subversion = _win32_getvalue(keyCurVer,
628 # 'SubVersionNumber',
629 # ('',1))[0]
630 #if subversion:
631 # release = release + subversion # 95a, 95b, etc.
632 build = _win32_getvalue(keyCurVer,
633 'CurrentBuildNumber',
634 ('',1))[0]
635 ptype = _win32_getvalue(keyCurVer,
636 'CurrentType',
637 (ptype,1))[0]
638
639 # Normalize version
640 version = _norm_version(version,build)
641
642 # Close key
643 RegCloseKey(keyCurVer)
644 return release,version,csd,ptype
645
646def _mac_ver_lookup(selectors,default=None):
647
648 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000649 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650 l = []
651 append = l.append
652 for selector in selectors:
653 try:
654 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000655 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000656 append(default)
657 return l
658
659def _bcd2str(bcd):
660
661 return hex(bcd)[2:]
662
663def mac_ver(release='',versioninfo=('','',''),machine=''):
664
665 """ Get MacOS version information and return it as tuple (release,
666 versioninfo, machine) with versioninfo being a tuple (version,
667 dev_stage, non_release_version).
668
Brett Cannon8ab27df2003-08-05 03:52:04 +0000669 Entries which cannot be determined are set to the paramter values
670 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000671
672 Thanks to Mark R. Levinson for mailing documentation links and
673 code examples for this function. Documentation for the
674 gestalt() API is available online at:
675
676 http://www.rgaros.nl/gestalt/
677
678 """
679 # Check whether the version info module is available
680 try:
681 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000682 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000683 except ImportError:
684 return release,versioninfo,machine
685 # Get the infos
686 sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
687 # Decode the infos
688 if sysv:
689 major = (sysv & 0xFF00) >> 8
690 minor = (sysv & 0x00F0) >> 4
691 patch = (sysv & 0x000F)
692 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
693 if sysu:
Guido van Rossume2a383d2007-01-15 16:59:06 +0000694 major = int((sysu & 0xFF000000) >> 24)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000695 minor = (sysu & 0x00F00000) >> 20
696 bugfix = (sysu & 0x000F0000) >> 16
697 stage = (sysu & 0x0000FF00) >> 8
698 nonrel = (sysu & 0x000000FF)
699 version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
700 nonrel = _bcd2str(nonrel)
701 stage = {0x20:'development',
702 0x40:'alpha',
703 0x60:'beta',
704 0x80:'final'}.get(stage,'')
705 versioninfo = (version,stage,nonrel)
706 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000707 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000708 0x2: 'PowerPC',
709 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000710 return release,versioninfo,machine
711
Neal Norwitz9b924c62003-06-29 04:17:45 +0000712def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000713
714 from java.lang import System
715 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000716 value = System.getProperty(name)
717 if value is None:
718 return default
719 return value
720 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000721 return default
722
723def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000724
Brett Cannon8ab27df2003-08-05 03:52:04 +0000725 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000726
727 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
728 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
729 tuple (os_name,os_version,os_arch).
730
731 Values which cannot be determined are set to the defaults
732 given as parameters (which all default to '').
733
734 """
735 # Import the needed APIs
736 try:
737 import java.lang
738 except ImportError:
739 return release,vendor,vminfo,osinfo
740
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000741 vendor = _java_getprop('java.vendor', vendor)
742 release = _java_getprop('java.version', release)
743 vm_name, vm_release, vm_vendor = vminfo
744 vm_name = _java_getprop('java.vm.name', vm_name)
745 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
746 vm_release = _java_getprop('java.vm.version', vm_release)
747 vminfo = vm_name, vm_release, vm_vendor
748 os_name, os_version, os_arch = osinfo
749 os_arch = _java_getprop('java.os.arch', os_arch)
750 os_name = _java_getprop('java.os.name', os_name)
751 os_version = _java_getprop('java.os.version', os_version)
752 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000753
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000754 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000755
756### System name aliasing
757
758def system_alias(system,release,version):
759
760 """ Returns (system,release,version) aliased to common
761 marketing names used for some systems.
762
763 It also does some reordering of the information in some cases
764 where it would otherwise cause confusion.
765
766 """
767 if system == 'Rhapsody':
768 # Apple's BSD derivative
769 # XXX How can we determine the marketing release number ?
770 return 'MacOS X Server',system+release,version
771
772 elif system == 'SunOS':
773 # Sun's OS
774 if release < '5':
775 # These releases use the old name SunOS
776 return system,release,version
777 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000778 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000779 if l:
780 try:
781 major = int(l[0])
782 except ValueError:
783 pass
784 else:
785 major = major - 3
786 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000787 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000788 if release < '6':
789 system = 'Solaris'
790 else:
791 # XXX Whatever the new SunOS marketing name is...
792 system = 'Solaris'
793
794 elif system == 'IRIX64':
795 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
796 # is really a version and not a different platform, since 32-bit
797 # apps are also supported..
798 system = 'IRIX'
799 if version:
800 version = version + ' (64bit)'
801 else:
802 version = '64bit'
803
804 elif system in ('win32','win16'):
805 # In case one of the other tricks
806 system = 'Windows'
807
808 return system,release,version
809
810### Various internal helpers
811
812def _platform(*args):
813
814 """ Helper to format the platform string in a filename
815 compatible format e.g. "system-version-machine".
816 """
817 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000818 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000819
820 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000821 platform = platform.replace(' ','_')
822 platform = platform.replace('/','-')
823 platform = platform.replace('\\','-')
824 platform = platform.replace(':','-')
825 platform = platform.replace(';','-')
826 platform = platform.replace('"','-')
827 platform = platform.replace('(','-')
828 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000829
830 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000831 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000832
833 # Fold '--'s and remove trailing '-'
834 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000835 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000836 if cleaned == platform:
837 break
838 platform = cleaned
839 while platform[-1] == '-':
840 platform = platform[:-1]
841
842 return platform
843
844def _node(default=''):
845
846 """ Helper to determine the node name of this machine.
847 """
848 try:
849 import socket
850 except ImportError:
851 # No sockets...
852 return default
853 try:
854 return socket.gethostname()
855 except socket.error:
856 # Still not working...
857 return default
858
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000859def _follow_symlinks(filepath):
860
861 """ In case filepath is a symlink, follow it until a
862 real file is reached.
863 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000864 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000865 while os.path.islink(filepath):
866 filepath = os.path.normpath(
867 os.path.join(filepath,os.readlink(filepath)))
868 return filepath
869
870def _syscmd_uname(option,default=''):
871
872 """ Interface to the system's uname command.
873 """
874 if sys.platform in ('dos','win32','win16','os2'):
875 # XXX Others too ?
876 return default
877 try:
878 f = os.popen('uname %s 2> /dev/null' % option)
879 except (AttributeError,os.error):
880 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000881 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000882 rc = f.close()
883 if not output or rc:
884 return default
885 else:
886 return output
887
888def _syscmd_file(target,default=''):
889
890 """ Interface to the system's file command.
891
892 The function uses the -b option of the file command to have it
893 ommit the filename in its output and if possible the -L option
894 to have the command follow symlinks. It returns default in
895 case the command should fail.
896
897 """
898 target = _follow_symlinks(target)
899 try:
900 f = os.popen('file %s 2> /dev/null' % target)
901 except (AttributeError,os.error):
902 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000903 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000904 rc = f.close()
905 if not output or rc:
906 return default
907 else:
908 return output
909
910### Information about the used architecture
911
912# Default values for architecture; non-empty strings override the
913# defaults given as parameters
914_default_architecture = {
915 'win32': ('','WindowsPE'),
916 'win16': ('','Windows'),
917 'dos': ('','MSDOS'),
918}
919
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000920_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000921
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000922def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000923
924 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000925 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000926
Brett Cannon8ab27df2003-08-05 03:52:04 +0000927 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000928 the bit architecture and the linkage format used for the
929 executable. Both values are returned as strings.
930
931 Values that cannot be determined are returned as given by the
932 parameter presets. If bits is given as '', the sizeof(pointer)
933 (or sizeof(long) on Python version < 1.5.2) is used as
934 indicator for the supported pointer size.
935
936 The function relies on the system's "file" command to do the
937 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000938 platforms. On some non-Unix platforms where the "file" command
939 does not exist and the executable is set to the Python interpreter
940 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000941
942 """
943 # Use the sizeof(pointer) as default number of bits if nothing
944 # else is given as default.
945 if not bits:
946 import struct
947 try:
948 size = struct.calcsize('P')
949 except struct.error:
950 # Older installations can only query longs
951 size = struct.calcsize('l')
952 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000953
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000954 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000955 if executable:
956 output = _syscmd_file(executable, '')
957 else:
958 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000959
960 if not output and \
961 executable == sys.executable:
962 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000963 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000964 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000965 b,l = _default_architecture[sys.platform]
966 if b:
967 bits = b
968 if l:
969 linkage = l
970 return bits,linkage
971
972 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000973 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +0000974
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000975 if 'executable' not in fileout:
976 # Format not supported
977 return bits,linkage
978
979 # Bits
980 if '32-bit' in fileout:
981 bits = '32bit'
982 elif 'N32' in fileout:
983 # On Irix only
984 bits = 'n32bit'
985 elif '64-bit' in fileout:
986 bits = '64bit'
987
988 # Linkage
989 if 'ELF' in fileout:
990 linkage = 'ELF'
991 elif 'PE' in fileout:
992 # E.g. Windows uses this format
993 if 'Windows' in fileout:
994 linkage = 'WindowsPE'
995 else:
996 linkage = 'PE'
997 elif 'COFF' in fileout:
998 linkage = 'COFF'
999 elif 'MS-DOS' in fileout:
1000 linkage = 'MSDOS'
1001 else:
1002 # XXX the A.OUT format also falls under this class...
1003 pass
1004
1005 return bits,linkage
1006
1007### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001008
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001009_uname_cache = None
1010
1011def uname():
1012
1013 """ Fairly portable uname interface. Returns a tuple
1014 of strings (system,node,release,version,machine,processor)
1015 identifying the underlying platform.
1016
1017 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001018 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001019
1020 Entries which cannot be determined are set to ''.
1021
1022 """
1023 global _uname_cache
1024
1025 if _uname_cache is not None:
1026 return _uname_cache
1027
1028 # Get some infos from the builtin os.uname API...
1029 try:
1030 system,node,release,version,machine = os.uname()
1031
1032 except AttributeError:
1033 # Hmm, no uname... we'll have to poke around the system then.
1034 system = sys.platform
1035 release = ''
1036 version = ''
1037 node = _node()
1038 machine = ''
1039 processor = ''
1040 use_syscmd_ver = 1
1041
1042 # Try win32_ver() on win32 platforms
1043 if system == 'win32':
1044 release,version,csd,ptype = win32_ver()
1045 if release and version:
1046 use_syscmd_ver = 0
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001047 # XXX Should try to parse the PROCESSOR_* environment variables
1048 # available on Win XP and later; see
1049 # http://support.microsoft.com/kb/888731 and
1050 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Tim Peters0eadaac2003-04-24 16:02:54 +00001051
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001052 # Try the 'ver' system command available on some
1053 # platforms
1054 if use_syscmd_ver:
1055 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001056 # Normalize system to what win32_ver() normally returns
1057 # (_syscmd_ver() tends to return the vendor name as well)
1058 if system == 'Microsoft Windows':
1059 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001060 elif system == 'Microsoft' and release == 'Windows':
1061 # Under Windows Vista and Windows Server 2008,
1062 # Microsoft changed the output of the ver command. The
1063 # release is no longer printed. This causes the
1064 # system and release to be misidentified.
1065 system = 'Windows'
1066 if '6.0' == version[:3]:
1067 release = 'Vista'
1068 else:
1069 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001070
1071 # In case we still don't know anything useful, we'll try to
1072 # help ourselves
1073 if system in ('win32','win16'):
1074 if not version:
1075 if system == 'win32':
1076 version = '32bit'
1077 else:
1078 version = '16bit'
1079 system = 'Windows'
1080
1081 elif system[:4] == 'java':
1082 release,vendor,vminfo,osinfo = java_ver()
1083 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001084 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001085 if not version:
1086 version = vendor
1087
1088 elif os.name == 'mac':
1089 release,(version,stage,nonrel),machine = mac_ver()
1090 system = 'MacOS'
1091
1092 else:
1093 # System specific extensions
1094 if system == 'OpenVMS':
1095 # OpenVMS seems to have release and version mixed up
1096 if not release or release == '0':
1097 release = version
1098 version = ''
1099 # Get processor information
1100 try:
1101 import vms_lib
1102 except ImportError:
1103 pass
1104 else:
1105 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1106 if (cpu_number >= 128):
1107 processor = 'Alpha'
1108 else:
1109 processor = 'VAX'
1110 else:
1111 # Get processor information from the uname system command
1112 processor = _syscmd_uname('-p','')
1113
1114 # 'unknown' is not really any useful as information; we'll convert
1115 # it to '' which is more portable
1116 if system == 'unknown':
1117 system = ''
1118 if node == 'unknown':
1119 node = ''
1120 if release == 'unknown':
1121 release = ''
1122 if version == 'unknown':
1123 version = ''
1124 if machine == 'unknown':
1125 machine = ''
1126 if processor == 'unknown':
1127 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001128
1129 # normalize name
1130 if system == 'Microsoft' and release == 'Windows':
1131 system = 'Windows'
1132 release = 'Vista'
1133
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001134 _uname_cache = system,node,release,version,machine,processor
1135 return _uname_cache
1136
1137### Direct interfaces to some of the uname() return values
1138
1139def system():
1140
1141 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1142
1143 An empty string is returned if the value cannot be determined.
1144
1145 """
1146 return uname()[0]
1147
1148def node():
1149
Brett Cannon8ab27df2003-08-05 03:52:04 +00001150 """ Returns the computer's network name (which may not be fully
1151 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001152
1153 An empty string is returned if the value cannot be determined.
1154
1155 """
1156 return uname()[1]
1157
1158def release():
1159
1160 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1161
1162 An empty string is returned if the value cannot be determined.
1163
1164 """
1165 return uname()[2]
1166
1167def version():
1168
1169 """ Returns the system's release version, e.g. '#3 on degas'
1170
1171 An empty string is returned if the value cannot be determined.
1172
1173 """
1174 return uname()[3]
1175
1176def machine():
1177
1178 """ Returns the machine type, e.g. 'i386'
1179
1180 An empty string is returned if the value cannot be determined.
1181
1182 """
1183 return uname()[4]
1184
1185def processor():
1186
1187 """ Returns the (true) processor name, e.g. 'amdk6'
1188
1189 An empty string is returned if the value cannot be
1190 determined. Note that many platforms do not provide this
1191 information or simply return the same value as for machine(),
1192 e.g. NetBSD does this.
1193
1194 """
1195 return uname()[5]
1196
1197### Various APIs for extracting information from sys.version
1198
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001199_sys_version_parser = re.compile(
1200 r'([\w.+]+)\s*'
1201 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1202 '\[([^\]]+)\]?')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001203
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001204_jython_sys_version_parser = re.compile(
1205 r'([\d\.]+)')
1206
1207_ironpython_sys_version_parser = re.compile(
1208 r'IronPython\s*'
1209 '([\d\.]+)'
1210 '(?: \(([\d\.]+)\))?'
1211 ' on (.NET [\d\.]+)')
1212
1213_sys_version_cache = {}
1214
1215def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001216
1217 """ Returns a parsed version of Python's sys.version as tuple
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001218 (name, version, branch, revision, buildno, builddate, compiler)
1219 referring to the Python implementation name, version, branch,
1220 revision, build number, build date/time as string and the compiler
1221 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001222
1223 Note that unlike the Python sys.version, the returned value
1224 for the Python version will always include the patchlevel (it
1225 defaults to '.0').
1226
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001227 The function returns empty strings for tuple entries that
1228 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001229
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001230 sys_version may be given to parse an alternative version
1231 string, e.g. if the version was read from a different Python
1232 interpreter.
1233
1234 """
1235 # Get the Python version
1236 if sys_version is None:
1237 sys_version = sys.version
1238
1239 # Try the cache first
1240 result = _sys_version_cache.get(sys_version, None)
1241 if result is not None:
1242 return result
1243
1244 # Parse it
1245 if sys_version[:10] == 'IronPython':
1246 # IronPython
1247 name = 'IronPython'
1248 match = _ironpython_sys_version_parser.match(sys_version)
1249 if match is None:
1250 raise ValueError(
1251 'failed to parse IronPython sys.version: %s' %
1252 repr(sys_version))
1253 version, alt_version, compiler = match.groups()
1254 branch = ''
1255 revision = ''
1256 buildno = ''
1257 builddate = ''
1258
1259 elif sys.platform[:4] == 'java':
1260 # Jython
1261 name = 'Jython'
1262 match = _jython_sys_version_parser.match(sys_version)
1263 if match is None:
1264 raise ValueError(
1265 'failed to parse Jython sys.version: %s' %
1266 repr(sys_version))
1267 version, = match.groups()
1268 branch = ''
1269 revision = ''
1270 compiler = sys.platform
1271 buildno = ''
1272 builddate = ''
1273
1274 else:
1275 # CPython
1276 match = _sys_version_parser.match(sys_version)
1277 if match is None:
1278 raise ValueError(
1279 'failed to parse CPython sys.version: %s' %
1280 repr(sys_version))
1281 version, buildno, builddate, buildtime, compiler = \
1282 match.groups()
1283 if hasattr(sys, 'subversion'):
1284 # sys.subversion was added in Python 2.5
1285 name, branch, revision = sys.subversion
1286 else:
1287 name = 'CPython'
1288 branch = ''
1289 revision = ''
1290 builddate = builddate + ' ' + buildtime
1291
1292 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001293 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001294 if len(l) == 2:
1295 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001296 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001297
1298 # Build and cache the result
1299 result = (name, version, branch, revision, buildno, builddate, compiler)
1300 _sys_version_cache[sys_version] = result
1301 return result
1302
1303def _test_sys_version():
1304
1305 _sys_version_cache.clear()
1306 for input, output in (
1307 ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]',
1308 ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')),
1309 ('IronPython 1.0.60816 on .NET 2.0.50727.42',
1310 ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')),
1311 ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42',
1312 ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')),
1313 ):
1314 parsed = _sys_version(input)
1315 if parsed != output:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001316 print((input, parsed))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001317
1318def python_implementation():
1319
1320 """ Returns a string identifying the Python implementation.
1321
1322 Currently, the following implementations are identified:
1323 'CPython' (C implementation of Python),
1324 'IronPython' (.NET implementation of Python),
1325 'Jython' (Java implementation of Python).
1326
1327 """
1328 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001329
1330def python_version():
1331
1332 """ Returns the Python version as string 'major.minor.patchlevel'
1333
1334 Note that unlike the Python sys.version, the returned value
1335 will always include the patchlevel (it defaults to 0).
1336
1337 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001338 if hasattr(sys, 'version_info'):
1339 return '%i.%i.%i' % sys.version_info[:3]
1340 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001341
1342def python_version_tuple():
1343
1344 """ Returns the Python version as tuple (major, minor, patchlevel)
1345 of strings.
1346
1347 Note that unlike the Python sys.version, the returned value
1348 will always include the patchlevel (it defaults to 0).
1349
1350 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001351 if hasattr(sys, 'version_info'):
1352 return sys.version_info[:3]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001353 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001354
1355def python_branch():
1356
1357 """ Returns a string identifying the Python implementation
1358 branch.
1359
1360 For CPython this is the Subversion branch from which the
1361 Python binary was built.
1362
1363 If not available, an empty string is returned.
1364
1365 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001366
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001367 return _sys_version()[2]
1368
1369def python_revision():
1370
1371 """ Returns a string identifying the Python implementation
1372 revision.
1373
1374 For CPython this is the Subversion revision from which the
1375 Python binary was built.
1376
1377 If not available, an empty string is returned.
1378
1379 """
1380 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001381
1382def python_build():
1383
1384 """ Returns a tuple (buildno, builddate) stating the Python
1385 build number and date as strings.
1386
1387 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001388 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001389
1390def python_compiler():
1391
1392 """ Returns a string identifying the compiler used for compiling
1393 Python.
1394
1395 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001396 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001397
1398### The Opus Magnum of platform strings :-)
1399
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001400_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401
1402def platform(aliased=0, terse=0):
1403
1404 """ Returns a single string identifying the underlying platform
1405 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001406
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001407 The output is intended to be human readable rather than
1408 machine parseable. It may look different on different
1409 platforms and this is intended.
1410
1411 If "aliased" is true, the function will use aliases for
1412 various platforms that report system names which differ from
1413 their common names, e.g. SunOS will be reported as
1414 Solaris. The system_alias() function is used to implement
1415 this.
1416
1417 Setting terse to true causes the function to return only the
1418 absolute minimum information needed to identify the platform.
1419
1420 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001421 result = _platform_cache.get((aliased, terse), None)
1422 if result is not None:
1423 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001424
1425 # Get uname information and then apply platform specific cosmetics
1426 # to it...
1427 system,node,release,version,machine,processor = uname()
1428 if machine == processor:
1429 processor = ''
1430 if aliased:
1431 system,release,version = system_alias(system,release,version)
1432
1433 if system == 'Windows':
1434 # MS platforms
1435 rel,vers,csd,ptype = win32_ver(version)
1436 if terse:
1437 platform = _platform(system,release)
1438 else:
1439 platform = _platform(system,release,version,csd)
1440
1441 elif system in ('Linux',):
1442 # Linux based systems
1443 distname,distversion,distid = dist('')
1444 if distname and not terse:
1445 platform = _platform(system,release,machine,processor,
1446 'with',
1447 distname,distversion,distid)
1448 else:
1449 # If the distribution name is unknown check for libc vs. glibc
1450 libcname,libcversion = libc_ver(sys.executable)
1451 platform = _platform(system,release,machine,processor,
1452 'with',
1453 libcname+libcversion)
1454 elif system == 'Java':
1455 # Java platforms
1456 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001457 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001458 platform = _platform(system,release,version)
1459 else:
1460 platform = _platform(system,release,version,
1461 'on',
1462 os_name,os_version,os_arch)
1463
1464 elif system == 'MacOS':
1465 # MacOS platforms
1466 if terse:
1467 platform = _platform(system,release)
1468 else:
1469 platform = _platform(system,release,machine)
1470
1471 else:
1472 # Generic handler
1473 if terse:
1474 platform = _platform(system,release)
1475 else:
1476 bits,linkage = architecture(sys.executable)
1477 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001478
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001479 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001480 return platform
1481
1482### Command line interface
1483
1484if __name__ == '__main__':
1485 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001486 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001487 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001488 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001489 sys.exit(0)