blob: 56ab759cfc07c3152ef3172477babd0a5627a6a8 [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
Christian Heimes02781dc2008-03-21 01:11:52 +000092 Copyright (c) 2000-2008, 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 '|'
Antoine Pitroufd036452008-08-19 17:56:33 +0000121 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000122
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
Antoine Pitroufd036452008-08-19 17:56:33 +0000226_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000227_lsb_release_version = re.compile(r'(.+)'
228 ' release '
229 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000230 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000231_release_version = re.compile(r'([^0-9]+)'
232 '(?: release )?'
233 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000234 '[^(]*(?:\((.+)\))?', re.ASCII)
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 '.*'
Antoine Pitroufd036452008-08-19 17:56:33 +0000467 'Version ([\d.]+))', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000468
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 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000528 try:
529 # Use win32api if available
530 from win32api import RegQueryValueEx
531 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000532 # On Python 2.0 and later, emulate using winreg
533 import winreg
534 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000535 try:
536 return RegQueryValueEx(key,name)
537 except:
538 return default
539
540def win32_ver(release='',version='',csd='',ptype=''):
541
542 """ Get additional version information from the Windows Registry
543 and return a tuple (version,csd,ptype) referring to version
544 number, CSD level and OS type (multi/single
545 processor).
546
547 As a hint: ptype returns 'Uniprocessor Free' on single
548 processor NT machines and 'Multiprocessor Free' on multi
549 processor machines. The 'Free' refers to the OS version being
550 free of debugging code. It could also state 'Checked' which
551 means the OS version uses debugging code, i.e. code that
552 checks arguments, ranges, etc. (Thomas Heller).
553
Christian Heimes02781dc2008-03-21 01:11:52 +0000554 Note: this function works best with Mark Hammond's win32
555 package installed, but also on Python 2.3 and later. It
556 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000557
558 """
559 # XXX Is there any way to find out the processor type on WinXX ?
560 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000561 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000562 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000563 #
564 # The mappings between reg. values and release names can be found
565 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000566
567 # Import the needed APIs
568 try:
569 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000570 from win32api import RegQueryValueEx, RegOpenKeyEx, \
571 RegCloseKey, GetVersionEx
572 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
573 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000574 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000575 # Emulate the win32api module using Python APIs
576 try:
577 sys.getwindowsversion
578 except AttributeError:
579 # No emulation possible, so return the defaults...
580 return release,version,csd,ptype
581 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000582 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000583 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000584 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000585 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000586 RegQueryValueEx = winreg.QueryValueEx
587 RegOpenKeyEx = winreg.OpenKeyEx
588 RegCloseKey = winreg.CloseKey
589 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000590 VER_PLATFORM_WIN32_WINDOWS = 1
591 VER_PLATFORM_WIN32_NT = 2
592 VER_NT_WORKSTATION = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000593
594 # Find out the registry key and some general version infos
595 maj,min,buildno,plat,csd = GetVersionEx()
596 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
597 if csd[:13] == 'Service Pack ':
598 csd = 'SP' + csd[13:]
599 if plat == VER_PLATFORM_WIN32_WINDOWS:
600 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
601 # Try to guess the release name
602 if maj == 4:
603 if min == 0:
604 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000605 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000607 elif min == 90:
608 release = 'Me'
609 else:
610 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000611 elif maj == 5:
612 release = '2000'
613 elif plat == VER_PLATFORM_WIN32_NT:
614 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
615 if maj <= 4:
616 release = 'NT'
617 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000618 if min == 0:
619 release = '2000'
620 elif min == 1:
621 release = 'XP'
622 elif min == 2:
623 release = '2003Server'
624 else:
625 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000626 elif maj == 6:
627 if min == 0:
628 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
Christian Heimes02781dc2008-03-21 01:11:52 +0000629 try:
630 productType = GetVersionEx(1)[8]
631 except TypeError:
632 # sys.getwindowsversion() doesn't take any arguments, so
633 # we cannot detect 2008 Server that way.
634 # XXX Add some other means of detecting 2008 Server ?!
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000635 release = 'Vista'
636 else:
Christian Heimes02781dc2008-03-21 01:11:52 +0000637 if productType == VER_NT_WORKSTATION:
638 release = 'Vista'
639 else:
640 release = '2008Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000641 else:
642 release = 'post2008Server'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000643 else:
644 if not release:
645 # E.g. Win3.1 with win32s
646 release = '%i.%i' % (maj,min)
647 return release,version,csd,ptype
648
649 # Open the registry key
650 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000651 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000653 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654 except:
655 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000656
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000657 # Parse values
658 #subversion = _win32_getvalue(keyCurVer,
659 # 'SubVersionNumber',
660 # ('',1))[0]
661 #if subversion:
662 # release = release + subversion # 95a, 95b, etc.
663 build = _win32_getvalue(keyCurVer,
664 'CurrentBuildNumber',
665 ('',1))[0]
666 ptype = _win32_getvalue(keyCurVer,
667 'CurrentType',
668 (ptype,1))[0]
669
670 # Normalize version
671 version = _norm_version(version,build)
672
673 # Close key
674 RegCloseKey(keyCurVer)
675 return release,version,csd,ptype
676
677def _mac_ver_lookup(selectors,default=None):
678
Benjamin Petersonebacd262008-05-29 21:09:51 +0000679 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000680 l = []
681 append = l.append
682 for selector in selectors:
683 try:
684 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000685 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686 append(default)
687 return l
688
689def _bcd2str(bcd):
690
691 return hex(bcd)[2:]
692
693def mac_ver(release='',versioninfo=('','',''),machine=''):
694
695 """ Get MacOS version information and return it as tuple (release,
696 versioninfo, machine) with versioninfo being a tuple (version,
697 dev_stage, non_release_version).
698
Brett Cannon8ab27df2003-08-05 03:52:04 +0000699 Entries which cannot be determined are set to the paramter values
700 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000701
702 Thanks to Mark R. Levinson for mailing documentation links and
703 code examples for this function. Documentation for the
704 gestalt() API is available online at:
705
706 http://www.rgaros.nl/gestalt/
707
708 """
709 # Check whether the version info module is available
710 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000711 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000712 except ImportError:
713 return release,versioninfo,machine
714 # Get the infos
715 sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
716 # Decode the infos
717 if sysv:
718 major = (sysv & 0xFF00) >> 8
719 minor = (sysv & 0x00F0) >> 4
720 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000721
722 if (major, minor) >= (10, 4):
723 # the 'sysv' gestald cannot return patchlevels
724 # higher than 9. Apple introduced 3 new
725 # gestalt codes in 10.4 to deal with this
726 # issue (needed because patch levels can
727 # run higher than 9, such as 10.4.11)
728 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
729 release = '%i.%i.%i' %(major, minor, patch)
730 else:
731 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000732
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000733 if sysu:
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000734 # NOTE: this block is left as documentation of the
735 # intention of this function, the 'sysu' gestalt is no
736 # longer available and there are no alternatives.
Guido van Rossume2a383d2007-01-15 16:59:06 +0000737 major = int((sysu & 0xFF000000) >> 24)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000738 minor = (sysu & 0x00F00000) >> 20
739 bugfix = (sysu & 0x000F0000) >> 16
740 stage = (sysu & 0x0000FF00) >> 8
741 nonrel = (sysu & 0x000000FF)
742 version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
743 nonrel = _bcd2str(nonrel)
744 stage = {0x20:'development',
745 0x40:'alpha',
746 0x60:'beta',
747 0x80:'final'}.get(stage,'')
748 versioninfo = (version,stage,nonrel)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000749
750
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000751 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000752 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000753 0x2: 'PowerPC',
754 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000755 return release,versioninfo,machine
756
Neal Norwitz9b924c62003-06-29 04:17:45 +0000757def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000758
759 from java.lang import System
760 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000761 value = System.getProperty(name)
762 if value is None:
763 return default
764 return value
765 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000766 return default
767
768def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000769
Brett Cannon8ab27df2003-08-05 03:52:04 +0000770 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000771
772 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
773 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
774 tuple (os_name,os_version,os_arch).
775
776 Values which cannot be determined are set to the defaults
777 given as parameters (which all default to '').
778
779 """
780 # Import the needed APIs
781 try:
782 import java.lang
783 except ImportError:
784 return release,vendor,vminfo,osinfo
785
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000786 vendor = _java_getprop('java.vendor', vendor)
787 release = _java_getprop('java.version', release)
788 vm_name, vm_release, vm_vendor = vminfo
789 vm_name = _java_getprop('java.vm.name', vm_name)
790 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
791 vm_release = _java_getprop('java.vm.version', vm_release)
792 vminfo = vm_name, vm_release, vm_vendor
793 os_name, os_version, os_arch = osinfo
794 os_arch = _java_getprop('java.os.arch', os_arch)
795 os_name = _java_getprop('java.os.name', os_name)
796 os_version = _java_getprop('java.os.version', os_version)
797 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000798
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000799 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000800
801### System name aliasing
802
803def system_alias(system,release,version):
804
805 """ Returns (system,release,version) aliased to common
806 marketing names used for some systems.
807
808 It also does some reordering of the information in some cases
809 where it would otherwise cause confusion.
810
811 """
812 if system == 'Rhapsody':
813 # Apple's BSD derivative
814 # XXX How can we determine the marketing release number ?
815 return 'MacOS X Server',system+release,version
816
817 elif system == 'SunOS':
818 # Sun's OS
819 if release < '5':
820 # These releases use the old name SunOS
821 return system,release,version
822 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000823 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000824 if l:
825 try:
826 major = int(l[0])
827 except ValueError:
828 pass
829 else:
830 major = major - 3
831 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000832 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000833 if release < '6':
834 system = 'Solaris'
835 else:
836 # XXX Whatever the new SunOS marketing name is...
837 system = 'Solaris'
838
839 elif system == 'IRIX64':
840 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
841 # is really a version and not a different platform, since 32-bit
842 # apps are also supported..
843 system = 'IRIX'
844 if version:
845 version = version + ' (64bit)'
846 else:
847 version = '64bit'
848
849 elif system in ('win32','win16'):
850 # In case one of the other tricks
851 system = 'Windows'
852
853 return system,release,version
854
855### Various internal helpers
856
857def _platform(*args):
858
859 """ Helper to format the platform string in a filename
860 compatible format e.g. "system-version-machine".
861 """
862 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000863 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000864
865 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000866 platform = platform.replace(' ','_')
867 platform = platform.replace('/','-')
868 platform = platform.replace('\\','-')
869 platform = platform.replace(':','-')
870 platform = platform.replace(';','-')
871 platform = platform.replace('"','-')
872 platform = platform.replace('(','-')
873 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000874
875 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000876 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000877
878 # Fold '--'s and remove trailing '-'
879 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000880 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000881 if cleaned == platform:
882 break
883 platform = cleaned
884 while platform[-1] == '-':
885 platform = platform[:-1]
886
887 return platform
888
889def _node(default=''):
890
891 """ Helper to determine the node name of this machine.
892 """
893 try:
894 import socket
895 except ImportError:
896 # No sockets...
897 return default
898 try:
899 return socket.gethostname()
900 except socket.error:
901 # Still not working...
902 return default
903
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000904def _follow_symlinks(filepath):
905
906 """ In case filepath is a symlink, follow it until a
907 real file is reached.
908 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000909 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000910 while os.path.islink(filepath):
911 filepath = os.path.normpath(
912 os.path.join(filepath,os.readlink(filepath)))
913 return filepath
914
915def _syscmd_uname(option,default=''):
916
917 """ Interface to the system's uname command.
918 """
919 if sys.platform in ('dos','win32','win16','os2'):
920 # XXX Others too ?
921 return default
922 try:
923 f = os.popen('uname %s 2> /dev/null' % option)
924 except (AttributeError,os.error):
925 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000926 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000927 rc = f.close()
928 if not output or rc:
929 return default
930 else:
931 return output
932
933def _syscmd_file(target,default=''):
934
935 """ Interface to the system's file command.
936
937 The function uses the -b option of the file command to have it
938 ommit the filename in its output and if possible the -L option
939 to have the command follow symlinks. It returns default in
940 case the command should fail.
941
942 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000943 if sys.platform in ('dos','win32','win16','os2'):
944 # XXX Others too ?
945 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000946 target = _follow_symlinks(target)
947 try:
Marc-André Lemburg40779852008-09-02 10:33:55 +0000948 f = os.popen('file "%s" 2> /dev/null' % target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000949 except (AttributeError,os.error):
950 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000951 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000952 rc = f.close()
953 if not output or rc:
954 return default
955 else:
956 return output
957
958### Information about the used architecture
959
960# Default values for architecture; non-empty strings override the
961# defaults given as parameters
962_default_architecture = {
963 'win32': ('','WindowsPE'),
964 'win16': ('','Windows'),
965 'dos': ('','MSDOS'),
966}
967
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000968_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000969
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000970def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000971
972 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000973 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000974
Brett Cannon8ab27df2003-08-05 03:52:04 +0000975 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000976 the bit architecture and the linkage format used for the
977 executable. Both values are returned as strings.
978
979 Values that cannot be determined are returned as given by the
980 parameter presets. If bits is given as '', the sizeof(pointer)
981 (or sizeof(long) on Python version < 1.5.2) is used as
982 indicator for the supported pointer size.
983
984 The function relies on the system's "file" command to do the
985 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000986 platforms. On some non-Unix platforms where the "file" command
987 does not exist and the executable is set to the Python interpreter
988 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000989
990 """
991 # Use the sizeof(pointer) as default number of bits if nothing
992 # else is given as default.
993 if not bits:
994 import struct
995 try:
996 size = struct.calcsize('P')
997 except struct.error:
998 # Older installations can only query longs
999 size = struct.calcsize('l')
1000 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001001
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001002 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001003 if executable:
1004 output = _syscmd_file(executable, '')
1005 else:
1006 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001007
1008 if not output and \
1009 executable == sys.executable:
1010 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001011 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +00001012 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001013 b,l = _default_architecture[sys.platform]
1014 if b:
1015 bits = b
1016 if l:
1017 linkage = l
1018 return bits,linkage
1019
1020 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001021 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +00001022
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001023 if 'executable' not in fileout:
1024 # Format not supported
1025 return bits,linkage
1026
1027 # Bits
1028 if '32-bit' in fileout:
1029 bits = '32bit'
1030 elif 'N32' in fileout:
1031 # On Irix only
1032 bits = 'n32bit'
1033 elif '64-bit' in fileout:
1034 bits = '64bit'
1035
1036 # Linkage
1037 if 'ELF' in fileout:
1038 linkage = 'ELF'
1039 elif 'PE' in fileout:
1040 # E.g. Windows uses this format
1041 if 'Windows' in fileout:
1042 linkage = 'WindowsPE'
1043 else:
1044 linkage = 'PE'
1045 elif 'COFF' in fileout:
1046 linkage = 'COFF'
1047 elif 'MS-DOS' in fileout:
1048 linkage = 'MSDOS'
1049 else:
1050 # XXX the A.OUT format also falls under this class...
1051 pass
1052
1053 return bits,linkage
1054
1055### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001056
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001057_uname_cache = None
1058
1059def uname():
1060
1061 """ Fairly portable uname interface. Returns a tuple
1062 of strings (system,node,release,version,machine,processor)
1063 identifying the underlying platform.
1064
1065 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001066 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067
1068 Entries which cannot be determined are set to ''.
1069
1070 """
1071 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001072 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001073
1074 if _uname_cache is not None:
1075 return _uname_cache
1076
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001077 processor = ''
1078
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001079 # Get some infos from the builtin os.uname API...
1080 try:
1081 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001082 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001083 no_os_uname = 1
1084
1085 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1086 # Hmm, no there is either no uname or uname has returned
1087 #'unknowns'... we'll have to poke around the system then.
1088 if no_os_uname:
1089 system = sys.platform
1090 release = ''
1091 version = ''
1092 node = _node()
1093 machine = ''
1094
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001095 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001096
1097 # Try win32_ver() on win32 platforms
1098 if system == 'win32':
1099 release,version,csd,ptype = win32_ver()
1100 if release and version:
1101 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001102 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001103 # available on Win XP and later; see
1104 # http://support.microsoft.com/kb/888731 and
1105 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001106 if not machine:
1107 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1108 if not processor:
1109 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001110
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001111 # Try the 'ver' system command available on some
1112 # platforms
1113 if use_syscmd_ver:
1114 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001115 # Normalize system to what win32_ver() normally returns
1116 # (_syscmd_ver() tends to return the vendor name as well)
1117 if system == 'Microsoft Windows':
1118 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001119 elif system == 'Microsoft' and release == 'Windows':
1120 # Under Windows Vista and Windows Server 2008,
1121 # Microsoft changed the output of the ver command. The
1122 # release is no longer printed. This causes the
1123 # system and release to be misidentified.
1124 system = 'Windows'
1125 if '6.0' == version[:3]:
1126 release = 'Vista'
1127 else:
1128 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001129
1130 # In case we still don't know anything useful, we'll try to
1131 # help ourselves
1132 if system in ('win32','win16'):
1133 if not version:
1134 if system == 'win32':
1135 version = '32bit'
1136 else:
1137 version = '16bit'
1138 system = 'Windows'
1139
1140 elif system[:4] == 'java':
1141 release,vendor,vminfo,osinfo = java_ver()
1142 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001143 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001144 if not version:
1145 version = vendor
1146
1147 elif os.name == 'mac':
1148 release,(version,stage,nonrel),machine = mac_ver()
1149 system = 'MacOS'
1150
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001151 # System specific extensions
1152 if system == 'OpenVMS':
1153 # OpenVMS seems to have release and version mixed up
1154 if not release or release == '0':
1155 release = version
1156 version = ''
1157 # Get processor information
1158 try:
1159 import vms_lib
1160 except ImportError:
1161 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001162 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001163 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1164 if (cpu_number >= 128):
1165 processor = 'Alpha'
1166 else:
1167 processor = 'VAX'
1168 if not processor:
1169 # Get processor information from the uname system command
1170 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001171
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001172 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001173 if system == 'unknown':
1174 system = ''
1175 if node == 'unknown':
1176 node = ''
1177 if release == 'unknown':
1178 release = ''
1179 if version == 'unknown':
1180 version = ''
1181 if machine == 'unknown':
1182 machine = ''
1183 if processor == 'unknown':
1184 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001185
1186 # normalize name
1187 if system == 'Microsoft' and release == 'Windows':
1188 system = 'Windows'
1189 release = 'Vista'
1190
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001191 _uname_cache = system,node,release,version,machine,processor
1192 return _uname_cache
1193
1194### Direct interfaces to some of the uname() return values
1195
1196def system():
1197
1198 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1199
1200 An empty string is returned if the value cannot be determined.
1201
1202 """
1203 return uname()[0]
1204
1205def node():
1206
Brett Cannon8ab27df2003-08-05 03:52:04 +00001207 """ Returns the computer's network name (which may not be fully
1208 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001209
1210 An empty string is returned if the value cannot be determined.
1211
1212 """
1213 return uname()[1]
1214
1215def release():
1216
1217 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1218
1219 An empty string is returned if the value cannot be determined.
1220
1221 """
1222 return uname()[2]
1223
1224def version():
1225
1226 """ Returns the system's release version, e.g. '#3 on degas'
1227
1228 An empty string is returned if the value cannot be determined.
1229
1230 """
1231 return uname()[3]
1232
1233def machine():
1234
1235 """ Returns the machine type, e.g. 'i386'
1236
1237 An empty string is returned if the value cannot be determined.
1238
1239 """
1240 return uname()[4]
1241
1242def processor():
1243
1244 """ Returns the (true) processor name, e.g. 'amdk6'
1245
1246 An empty string is returned if the value cannot be
1247 determined. Note that many platforms do not provide this
1248 information or simply return the same value as for machine(),
1249 e.g. NetBSD does this.
1250
1251 """
1252 return uname()[5]
1253
1254### Various APIs for extracting information from sys.version
1255
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001256_sys_version_parser = re.compile(
1257 r'([\w.+]+)\s*'
1258 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001259 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001260
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001261_jython_sys_version_parser = re.compile(
Antoine Pitroufd036452008-08-19 17:56:33 +00001262 r'([\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001263
1264_ironpython_sys_version_parser = re.compile(
1265 r'IronPython\s*'
1266 '([\d\.]+)'
1267 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001268 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001269
1270_sys_version_cache = {}
1271
1272def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001273
1274 """ Returns a parsed version of Python's sys.version as tuple
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001275 (name, version, branch, revision, buildno, builddate, compiler)
1276 referring to the Python implementation name, version, branch,
1277 revision, build number, build date/time as string and the compiler
1278 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001279
1280 Note that unlike the Python sys.version, the returned value
1281 for the Python version will always include the patchlevel (it
1282 defaults to '.0').
1283
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001284 The function returns empty strings for tuple entries that
1285 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001286
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001287 sys_version may be given to parse an alternative version
1288 string, e.g. if the version was read from a different Python
1289 interpreter.
1290
1291 """
1292 # Get the Python version
1293 if sys_version is None:
1294 sys_version = sys.version
1295
1296 # Try the cache first
1297 result = _sys_version_cache.get(sys_version, None)
1298 if result is not None:
1299 return result
1300
1301 # Parse it
1302 if sys_version[:10] == 'IronPython':
1303 # IronPython
1304 name = 'IronPython'
1305 match = _ironpython_sys_version_parser.match(sys_version)
1306 if match is None:
1307 raise ValueError(
1308 'failed to parse IronPython sys.version: %s' %
1309 repr(sys_version))
1310 version, alt_version, compiler = match.groups()
1311 branch = ''
1312 revision = ''
1313 buildno = ''
1314 builddate = ''
1315
1316 elif sys.platform[:4] == 'java':
1317 # Jython
1318 name = 'Jython'
1319 match = _jython_sys_version_parser.match(sys_version)
1320 if match is None:
1321 raise ValueError(
1322 'failed to parse Jython sys.version: %s' %
1323 repr(sys_version))
1324 version, = match.groups()
1325 branch = ''
1326 revision = ''
1327 compiler = sys.platform
1328 buildno = ''
1329 builddate = ''
1330
1331 else:
1332 # CPython
1333 match = _sys_version_parser.match(sys_version)
1334 if match is None:
1335 raise ValueError(
1336 'failed to parse CPython sys.version: %s' %
1337 repr(sys_version))
1338 version, buildno, builddate, buildtime, compiler = \
1339 match.groups()
1340 if hasattr(sys, 'subversion'):
1341 # sys.subversion was added in Python 2.5
1342 name, branch, revision = sys.subversion
1343 else:
1344 name = 'CPython'
1345 branch = ''
1346 revision = ''
1347 builddate = builddate + ' ' + buildtime
1348
1349 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001350 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001351 if len(l) == 2:
1352 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001353 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001354
1355 # Build and cache the result
1356 result = (name, version, branch, revision, buildno, builddate, compiler)
1357 _sys_version_cache[sys_version] = result
1358 return result
1359
1360def _test_sys_version():
1361
1362 _sys_version_cache.clear()
1363 for input, output in (
1364 ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]',
1365 ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')),
1366 ('IronPython 1.0.60816 on .NET 2.0.50727.42',
1367 ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')),
1368 ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42',
1369 ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')),
1370 ):
1371 parsed = _sys_version(input)
1372 if parsed != output:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001373 print((input, parsed))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001374
1375def python_implementation():
1376
1377 """ Returns a string identifying the Python implementation.
1378
1379 Currently, the following implementations are identified:
1380 'CPython' (C implementation of Python),
1381 'IronPython' (.NET implementation of Python),
1382 'Jython' (Java implementation of Python).
1383
1384 """
1385 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001386
1387def python_version():
1388
1389 """ Returns the Python version as string 'major.minor.patchlevel'
1390
1391 Note that unlike the Python sys.version, the returned value
1392 will always include the patchlevel (it defaults to 0).
1393
1394 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001395 if hasattr(sys, 'version_info'):
1396 return '%i.%i.%i' % sys.version_info[:3]
1397 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001398
1399def python_version_tuple():
1400
1401 """ Returns the Python version as tuple (major, minor, patchlevel)
1402 of strings.
1403
1404 Note that unlike the Python sys.version, the returned value
1405 will always include the patchlevel (it defaults to 0).
1406
1407 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001408 if hasattr(sys, 'version_info'):
1409 return sys.version_info[:3]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001410 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001411
1412def python_branch():
1413
1414 """ Returns a string identifying the Python implementation
1415 branch.
1416
1417 For CPython this is the Subversion branch from which the
1418 Python binary was built.
1419
1420 If not available, an empty string is returned.
1421
1422 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001423
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001424 return _sys_version()[2]
1425
1426def python_revision():
1427
1428 """ Returns a string identifying the Python implementation
1429 revision.
1430
1431 For CPython this is the Subversion revision from which the
1432 Python binary was built.
1433
1434 If not available, an empty string is returned.
1435
1436 """
1437 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001438
1439def python_build():
1440
1441 """ Returns a tuple (buildno, builddate) stating the Python
1442 build number and date as strings.
1443
1444 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001445 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001446
1447def python_compiler():
1448
1449 """ Returns a string identifying the compiler used for compiling
1450 Python.
1451
1452 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001453 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001454
1455### The Opus Magnum of platform strings :-)
1456
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001457_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001458
1459def platform(aliased=0, terse=0):
1460
1461 """ Returns a single string identifying the underlying platform
1462 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001463
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001464 The output is intended to be human readable rather than
1465 machine parseable. It may look different on different
1466 platforms and this is intended.
1467
1468 If "aliased" is true, the function will use aliases for
1469 various platforms that report system names which differ from
1470 their common names, e.g. SunOS will be reported as
1471 Solaris. The system_alias() function is used to implement
1472 this.
1473
1474 Setting terse to true causes the function to return only the
1475 absolute minimum information needed to identify the platform.
1476
1477 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001478 result = _platform_cache.get((aliased, terse), None)
1479 if result is not None:
1480 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001481
1482 # Get uname information and then apply platform specific cosmetics
1483 # to it...
1484 system,node,release,version,machine,processor = uname()
1485 if machine == processor:
1486 processor = ''
1487 if aliased:
1488 system,release,version = system_alias(system,release,version)
1489
1490 if system == 'Windows':
1491 # MS platforms
1492 rel,vers,csd,ptype = win32_ver(version)
1493 if terse:
1494 platform = _platform(system,release)
1495 else:
1496 platform = _platform(system,release,version,csd)
1497
1498 elif system in ('Linux',):
1499 # Linux based systems
1500 distname,distversion,distid = dist('')
1501 if distname and not terse:
1502 platform = _platform(system,release,machine,processor,
1503 'with',
1504 distname,distversion,distid)
1505 else:
1506 # If the distribution name is unknown check for libc vs. glibc
1507 libcname,libcversion = libc_ver(sys.executable)
1508 platform = _platform(system,release,machine,processor,
1509 'with',
1510 libcname+libcversion)
1511 elif system == 'Java':
1512 # Java platforms
1513 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001514 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001515 platform = _platform(system,release,version)
1516 else:
1517 platform = _platform(system,release,version,
1518 'on',
1519 os_name,os_version,os_arch)
1520
1521 elif system == 'MacOS':
1522 # MacOS platforms
1523 if terse:
1524 platform = _platform(system,release)
1525 else:
1526 platform = _platform(system,release,machine)
1527
1528 else:
1529 # Generic handler
1530 if terse:
1531 platform = _platform(system,release)
1532 else:
1533 bits,linkage = architecture(sys.executable)
1534 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001535
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001536 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001537 return platform
1538
1539### Command line interface
1540
1541if __name__ == '__main__':
1542 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001543 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001544 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001545 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001546 sys.exit(0)