blob: be49f8925a78f06f6d4041b575c46a63e1e5e50d [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
Benjamin Petersonf3d7dbe2009-10-04 14:54:52 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
Marc-André Lemburg246d8472003-04-24 11:36:11 +000015# Still needed:
16# * more support for WinCE
17# * support for MS-DOS (PythonDX ?)
18# * support for Amiga and other still unsupported platforms running Python
19# * support for additional Linux distributions
20#
Brett Cannon8ab27df2003-08-05 03:52:04 +000021# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000022# checks (in no particular order):
23#
24# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
25# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
26# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
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
Benjamin Petersonffeda292010-01-09 18:48:46 +000092 Copyright (c) 2000-2010, 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
Benjamin Peterson79e0b812010-01-25 03:40:53 +0000248 # Default to empty 'version' and 'id' strings. Both defaults are used
249 # when 'firstline' is empty. 'id' defaults to empty when an id can not
250 # be deduced.
251 version = ''
252 id = ''
253
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000254 # Parse the first line
255 m = _lsb_release_version.match(firstline)
256 if m is not None:
257 # LSB format: "distro release x.x (codename)"
258 return tuple(m.groups())
259
260 # Pre-LSB format: "distro x.x (codename)"
261 m = _release_version.match(firstline)
262 if m is not None:
263 return tuple(m.groups())
264
265 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000266 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000267 if l:
268 version = l[0]
269 if len(l) > 1:
270 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000271 return '', version, id
272
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000273def linux_distribution(distname='', version='', id='',
274
275 supported_dists=_supported_dists,
276 full_distribution_name=1):
277
278 """ Tries to determine the name of the Linux OS distribution name.
279
280 The function first looks for a distribution release file in
281 /etc and then reverts to _dist_try_harder() in case no
282 suitable files are found.
283
284 supported_dists may be given to define the set of Linux
285 distributions to look for. It defaults to a list of currently
286 supported Linux distributions identified by their release file
287 name.
288
289 If full_distribution_name is true (default), the full
290 distribution read from the OS is returned. Otherwise the short
291 name taken from supported_dists is used.
292
293 Returns a tuple (distname,version,id) which default to the
294 args given as parameters.
295
296 """
297 try:
298 etc = os.listdir('/etc')
299 except os.error:
300 # Probably not a Unix system
301 return distname,version,id
302 etc.sort()
303 for file in etc:
304 m = _release_filename.match(file)
305 if m is not None:
306 _distname,dummy = m.groups()
307 if _distname in supported_dists:
308 distname = _distname
309 break
310 else:
311 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000312
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000313 # Read the first line
314 f = open('/etc/'+file, 'r')
315 firstline = f.readline()
316 f.close()
317 _distname, _version, _id = _parse_release_file(firstline)
318
319 if _distname and full_distribution_name:
320 distname = _distname
321 if _version:
322 version = _version
323 if _id:
324 id = _id
325 return distname, version, id
326
327# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000328
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000329def dist(distname='',version='',id='',
330
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000331 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000332
Brett Cannon8ab27df2003-08-05 03:52:04 +0000333 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000334
335 The function first looks for a distribution release file in
336 /etc and then reverts to _dist_try_harder() in case no
337 suitable files are found.
338
Brett Cannon8ab27df2003-08-05 03:52:04 +0000339 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000340 args given as parameters.
341
342 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000343 return linux_distribution(distname, version, id,
344 supported_dists=supported_dists,
345 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000346
347class _popen:
348
349 """ Fairly portable (alternative) popen implementation.
350
351 This is mostly needed in case os.popen() is not available, or
352 doesn't work as advertised, e.g. in Win9X GUI programs like
353 PythonWin or IDLE.
354
355 Writing to the pipe is currently not supported.
356
357 """
358 tmpfile = ''
359 pipe = None
360 bufsize = None
361 mode = 'r'
362
363 def __init__(self,cmd,mode='r',bufsize=None):
364
365 if mode != 'r':
Collin Winterce36ad82007-08-30 01:19:48 +0000366 raise ValueError('popen()-emulation only supports read mode')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000367 import tempfile
368 self.tmpfile = tmpfile = tempfile.mktemp()
369 os.system(cmd + ' > %s' % tmpfile)
370 self.pipe = open(tmpfile,'rb')
371 self.bufsize = bufsize
372 self.mode = mode
373
374 def read(self):
375
376 return self.pipe.read()
377
378 def readlines(self):
379
380 if self.bufsize is not None:
381 return self.pipe.readlines()
382
383 def close(self,
384
385 remove=os.unlink,error=os.error):
386
387 if self.pipe:
388 rc = self.pipe.close()
389 else:
390 rc = 255
391 if self.tmpfile:
392 try:
393 remove(self.tmpfile)
394 except error:
395 pass
396 return rc
397
398 # Alias
399 __del__ = close
400
401def popen(cmd, mode='r', bufsize=None):
402
403 """ Portable popen() interface.
404 """
405 # Find a working popen implementation preferring win32pipe.popen
406 # over os.popen over _popen
407 popen = None
408 if os.environ.get('OS','') == 'Windows_NT':
409 # On NT win32pipe should work; on Win9x it hangs due to bugs
410 # in the MS C lib (see MS KnowledgeBase article Q150956)
411 try:
412 import win32pipe
413 except ImportError:
414 pass
415 else:
416 popen = win32pipe.popen
417 if popen is None:
418 if hasattr(os,'popen'):
419 popen = os.popen
420 # Check whether it works... it doesn't in GUI programs
421 # on Windows platforms
422 if sys.platform == 'win32': # XXX Others too ?
423 try:
424 popen('')
425 except os.error:
426 popen = _popen
427 else:
428 popen = _popen
429 if bufsize is None:
430 return popen(cmd,mode)
431 else:
432 return popen(cmd,mode,bufsize)
433
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000434def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000435
Brett Cannon8ab27df2003-08-05 03:52:04 +0000436 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000437 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000438 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000439 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000440 if build:
441 l.append(build)
442 try:
443 ints = map(int,l)
444 except ValueError:
445 strings = l
446 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000447 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000448 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000449 return version
450
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000451_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
452 '.*'
Antoine Pitroufd036452008-08-19 17:56:33 +0000453 'Version ([\d.]+))', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000454
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000455def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000457 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458
459 """ Tries to figure out the OS version used and returns
460 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000461
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 It uses the "ver" shell command for this which is known
463 to exists on Windows, DOS and OS/2. XXX Others too ?
464
465 In case this fails, the given parameters are used as
466 defaults.
467
468 """
469 if sys.platform not in supported_platforms:
470 return system,release,version
471
472 # Try some common cmd strings
473 for cmd in ('ver','command /c ver','cmd /c ver'):
474 try:
475 pipe = popen(cmd)
476 info = pipe.read()
477 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000478 raise os.error('command failed')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000479 # XXX How can I supress shell errors from being written
480 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000481 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000482 #print 'Command %s failed: %s' % (cmd,why)
483 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000484 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485 #print 'Command %s failed: %s' % (cmd,why)
486 continue
487 else:
488 break
489 else:
490 return system,release,version
491
492 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000493 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000494 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000495 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000496 system,release,version = m.groups()
497 # Strip trailing dots from version and release
498 if release[-1] == '.':
499 release = release[:-1]
500 if version[-1] == '.':
501 version = version[:-1]
502 # Normalize the version and build strings (eliminating additional
503 # zeros)
504 version = _norm_version(version)
505 return system,release,version
506
507def _win32_getvalue(key,name,default=''):
508
509 """ Read a value for name from the registry key.
510
511 In case this fails, default is returned.
512
513 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000514 try:
515 # Use win32api if available
516 from win32api import RegQueryValueEx
517 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000518 # On Python 2.0 and later, emulate using winreg
519 import winreg
520 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000521 try:
522 return RegQueryValueEx(key,name)
523 except:
524 return default
525
526def win32_ver(release='',version='',csd='',ptype=''):
527
528 """ Get additional version information from the Windows Registry
529 and return a tuple (version,csd,ptype) referring to version
530 number, CSD level and OS type (multi/single
531 processor).
532
533 As a hint: ptype returns 'Uniprocessor Free' on single
534 processor NT machines and 'Multiprocessor Free' on multi
535 processor machines. The 'Free' refers to the OS version being
536 free of debugging code. It could also state 'Checked' which
537 means the OS version uses debugging code, i.e. code that
538 checks arguments, ranges, etc. (Thomas Heller).
539
Christian Heimes02781dc2008-03-21 01:11:52 +0000540 Note: this function works best with Mark Hammond's win32
541 package installed, but also on Python 2.3 and later. It
542 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000543
544 """
545 # XXX Is there any way to find out the processor type on WinXX ?
546 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000547 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000549 #
550 # The mappings between reg. values and release names can be found
551 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000552
553 # Import the needed APIs
554 try:
555 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000556 from win32api import RegQueryValueEx, RegOpenKeyEx, \
557 RegCloseKey, GetVersionEx
558 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
559 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000560 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000561 # Emulate the win32api module using Python APIs
562 try:
563 sys.getwindowsversion
564 except AttributeError:
565 # No emulation possible, so return the defaults...
566 return release,version,csd,ptype
567 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000568 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000569 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000570 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000571 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000572 RegQueryValueEx = winreg.QueryValueEx
573 RegOpenKeyEx = winreg.OpenKeyEx
574 RegCloseKey = winreg.CloseKey
575 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000576 VER_PLATFORM_WIN32_WINDOWS = 1
577 VER_PLATFORM_WIN32_NT = 2
578 VER_NT_WORKSTATION = 1
Brian Curtine7837352010-05-06 03:09:10 +0000579 VER_NT_SERVER = 3
580 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000581
582 # Find out the registry key and some general version infos
Brian Curtine7837352010-05-06 03:09:10 +0000583 winver = GetVersionEx()
584 maj,min,buildno,plat,csd = winver
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000585 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
Brian Curtine7837352010-05-06 03:09:10 +0000586 if hasattr(winver, "service_pack"):
587 if winver.service_pack != "":
588 csd = 'SP%s' % winver.service_pack_major
589 else:
590 if csd[:13] == 'Service Pack ':
591 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000592 if plat == VER_PLATFORM_WIN32_WINDOWS:
593 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
594 # Try to guess the release name
595 if maj == 4:
596 if min == 0:
597 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000598 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000599 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000600 elif min == 90:
601 release = 'Me'
602 else:
603 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000604 elif maj == 5:
605 release = '2000'
606 elif plat == VER_PLATFORM_WIN32_NT:
607 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
608 if maj <= 4:
609 release = 'NT'
610 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000611 if min == 0:
612 release = '2000'
613 elif min == 1:
614 release = 'XP'
615 elif min == 2:
616 release = '2003Server'
617 else:
618 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000619 elif maj == 6:
Brian Curtine7837352010-05-06 03:09:10 +0000620 if hasattr(winver, "product_type"):
621 product_type = winver.product_type
622 else:
623 product_type = VER_NT_WORKSTATION
624 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
625 # or help from the registry, we cannot properly identify
626 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000627 try:
Brian Curtine7837352010-05-06 03:09:10 +0000628 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
629 name, type = RegQueryValueEx(key, "ProductName")
630 # Discard any type that isn't REG_SZ
631 if type == REG_SZ and name.find("Server") != -1:
632 product_type = VER_NT_SERVER
633 except WindowsError:
634 # Use default of VER_NT_WORKSTATION
635 pass
636
637 if min == 0:
638 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000639 release = 'Vista'
640 else:
Brian Curtine7837352010-05-06 03:09:10 +0000641 release = '2008Server'
642 elif min == 1:
643 if product_type == VER_NT_WORKSTATION:
644 release = '7'
645 else:
646 release = '2008ServerR2'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000647 else:
648 release = 'post2008Server'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000649 else:
650 if not release:
651 # E.g. Win3.1 with win32s
652 release = '%i.%i' % (maj,min)
653 return release,version,csd,ptype
654
655 # Open the registry key
656 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000657 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000658 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000659 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000660 except:
661 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000662
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000663 # Parse values
664 #subversion = _win32_getvalue(keyCurVer,
665 # 'SubVersionNumber',
666 # ('',1))[0]
667 #if subversion:
668 # release = release + subversion # 95a, 95b, etc.
669 build = _win32_getvalue(keyCurVer,
670 'CurrentBuildNumber',
671 ('',1))[0]
672 ptype = _win32_getvalue(keyCurVer,
673 'CurrentType',
674 (ptype,1))[0]
675
676 # Normalize version
677 version = _norm_version(version,build)
678
679 # Close key
680 RegCloseKey(keyCurVer)
681 return release,version,csd,ptype
682
683def _mac_ver_lookup(selectors,default=None):
684
Benjamin Petersonebacd262008-05-29 21:09:51 +0000685 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686 l = []
687 append = l.append
688 for selector in selectors:
689 try:
690 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000691 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000692 append(default)
693 return l
694
695def _bcd2str(bcd):
696
697 return hex(bcd)[2:]
698
699def mac_ver(release='',versioninfo=('','',''),machine=''):
700
701 """ Get MacOS version information and return it as tuple (release,
702 versioninfo, machine) with versioninfo being a tuple (version,
703 dev_stage, non_release_version).
704
Brett Cannon8ab27df2003-08-05 03:52:04 +0000705 Entries which cannot be determined are set to the paramter values
706 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000707
708 Thanks to Mark R. Levinson for mailing documentation links and
709 code examples for this function. Documentation for the
710 gestalt() API is available online at:
711
712 http://www.rgaros.nl/gestalt/
713
714 """
715 # Check whether the version info module is available
716 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000717 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000718 except ImportError:
719 return release,versioninfo,machine
720 # Get the infos
Ronald Oussorene61b21e2010-02-07 11:34:48 +0000721 sysv, sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000722 # Decode the infos
723 if sysv:
724 major = (sysv & 0xFF00) >> 8
725 minor = (sysv & 0x00F0) >> 4
726 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000727
728 if (major, minor) >= (10, 4):
729 # the 'sysv' gestald cannot return patchlevels
730 # higher than 9. Apple introduced 3 new
731 # gestalt codes in 10.4 to deal with this
732 # issue (needed because patch levels can
733 # run higher than 9, such as 10.4.11)
734 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
735 release = '%i.%i.%i' %(major, minor, patch)
736 else:
737 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000738
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000739 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000740 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000741 0x2: 'PowerPC',
742 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000743 return release,versioninfo,machine
744
Neal Norwitz9b924c62003-06-29 04:17:45 +0000745def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746
747 from java.lang import System
748 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000749 value = System.getProperty(name)
750 if value is None:
751 return default
752 return value
753 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000754 return default
755
756def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000757
Brett Cannon8ab27df2003-08-05 03:52:04 +0000758 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000759
760 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
761 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
762 tuple (os_name,os_version,os_arch).
763
764 Values which cannot be determined are set to the defaults
765 given as parameters (which all default to '').
766
767 """
768 # Import the needed APIs
769 try:
770 import java.lang
771 except ImportError:
772 return release,vendor,vminfo,osinfo
773
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000774 vendor = _java_getprop('java.vendor', vendor)
775 release = _java_getprop('java.version', release)
776 vm_name, vm_release, vm_vendor = vminfo
777 vm_name = _java_getprop('java.vm.name', vm_name)
778 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
779 vm_release = _java_getprop('java.vm.version', vm_release)
780 vminfo = vm_name, vm_release, vm_vendor
781 os_name, os_version, os_arch = osinfo
782 os_arch = _java_getprop('java.os.arch', os_arch)
783 os_name = _java_getprop('java.os.name', os_name)
784 os_version = _java_getprop('java.os.version', os_version)
785 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000786
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000787 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000788
789### System name aliasing
790
791def system_alias(system,release,version):
792
793 """ Returns (system,release,version) aliased to common
794 marketing names used for some systems.
795
796 It also does some reordering of the information in some cases
797 where it would otherwise cause confusion.
798
799 """
800 if system == 'Rhapsody':
801 # Apple's BSD derivative
802 # XXX How can we determine the marketing release number ?
803 return 'MacOS X Server',system+release,version
804
805 elif system == 'SunOS':
806 # Sun's OS
807 if release < '5':
808 # These releases use the old name SunOS
809 return system,release,version
810 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000811 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000812 if l:
813 try:
814 major = int(l[0])
815 except ValueError:
816 pass
817 else:
818 major = major - 3
819 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000820 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821 if release < '6':
822 system = 'Solaris'
823 else:
824 # XXX Whatever the new SunOS marketing name is...
825 system = 'Solaris'
826
827 elif system == 'IRIX64':
828 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
829 # is really a version and not a different platform, since 32-bit
830 # apps are also supported..
831 system = 'IRIX'
832 if version:
833 version = version + ' (64bit)'
834 else:
835 version = '64bit'
836
837 elif system in ('win32','win16'):
838 # In case one of the other tricks
839 system = 'Windows'
840
841 return system,release,version
842
843### Various internal helpers
844
845def _platform(*args):
846
847 """ Helper to format the platform string in a filename
848 compatible format e.g. "system-version-machine".
849 """
850 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000851 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000852
853 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000854 platform = platform.replace(' ','_')
855 platform = platform.replace('/','-')
856 platform = platform.replace('\\','-')
857 platform = platform.replace(':','-')
858 platform = platform.replace(';','-')
859 platform = platform.replace('"','-')
860 platform = platform.replace('(','-')
861 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000862
863 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000864 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000865
866 # Fold '--'s and remove trailing '-'
867 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000868 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000869 if cleaned == platform:
870 break
871 platform = cleaned
872 while platform[-1] == '-':
873 platform = platform[:-1]
874
875 return platform
876
877def _node(default=''):
878
879 """ Helper to determine the node name of this machine.
880 """
881 try:
882 import socket
883 except ImportError:
884 # No sockets...
885 return default
886 try:
887 return socket.gethostname()
888 except socket.error:
889 # Still not working...
890 return default
891
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000892def _follow_symlinks(filepath):
893
894 """ In case filepath is a symlink, follow it until a
895 real file is reached.
896 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000897 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000898 while os.path.islink(filepath):
899 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000900 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000901 return filepath
902
903def _syscmd_uname(option,default=''):
904
905 """ Interface to the system's uname command.
906 """
907 if sys.platform in ('dos','win32','win16','os2'):
908 # XXX Others too ?
909 return default
910 try:
911 f = os.popen('uname %s 2> /dev/null' % option)
912 except (AttributeError,os.error):
913 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000914 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000915 rc = f.close()
916 if not output or rc:
917 return default
918 else:
919 return output
920
921def _syscmd_file(target,default=''):
922
923 """ Interface to the system's file command.
924
925 The function uses the -b option of the file command to have it
926 ommit the filename in its output and if possible the -L option
927 to have the command follow symlinks. It returns default in
928 case the command should fail.
929
930 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000931 if sys.platform in ('dos','win32','win16','os2'):
932 # XXX Others too ?
933 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000934 target = _follow_symlinks(target)
935 try:
Marc-André Lemburg40779852008-09-02 10:33:55 +0000936 f = os.popen('file "%s" 2> /dev/null' % target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000937 except (AttributeError,os.error):
938 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000939 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000940 rc = f.close()
941 if not output or rc:
942 return default
943 else:
944 return output
945
946### Information about the used architecture
947
948# Default values for architecture; non-empty strings override the
949# defaults given as parameters
950_default_architecture = {
951 'win32': ('','WindowsPE'),
952 'win16': ('','Windows'),
953 'dos': ('','MSDOS'),
954}
955
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000956_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000957
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000958def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000959
960 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000961 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000962
Brett Cannon8ab27df2003-08-05 03:52:04 +0000963 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000964 the bit architecture and the linkage format used for the
965 executable. Both values are returned as strings.
966
967 Values that cannot be determined are returned as given by the
968 parameter presets. If bits is given as '', the sizeof(pointer)
969 (or sizeof(long) on Python version < 1.5.2) is used as
970 indicator for the supported pointer size.
971
972 The function relies on the system's "file" command to do the
973 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000974 platforms. On some non-Unix platforms where the "file" command
975 does not exist and the executable is set to the Python interpreter
976 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000977
978 """
979 # Use the sizeof(pointer) as default number of bits if nothing
980 # else is given as default.
981 if not bits:
982 import struct
983 try:
984 size = struct.calcsize('P')
985 except struct.error:
986 # Older installations can only query longs
987 size = struct.calcsize('l')
988 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000989
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000990 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000991 if executable:
992 output = _syscmd_file(executable, '')
993 else:
994 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000995
996 if not output and \
997 executable == sys.executable:
998 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000999 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +00001000 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001001 b,l = _default_architecture[sys.platform]
1002 if b:
1003 bits = b
1004 if l:
1005 linkage = l
1006 return bits,linkage
1007
1008 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001009 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +00001010
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001011 if 'executable' not in fileout:
1012 # Format not supported
1013 return bits,linkage
1014
1015 # Bits
1016 if '32-bit' in fileout:
1017 bits = '32bit'
1018 elif 'N32' in fileout:
1019 # On Irix only
1020 bits = 'n32bit'
1021 elif '64-bit' in fileout:
1022 bits = '64bit'
1023
1024 # Linkage
1025 if 'ELF' in fileout:
1026 linkage = 'ELF'
1027 elif 'PE' in fileout:
1028 # E.g. Windows uses this format
1029 if 'Windows' in fileout:
1030 linkage = 'WindowsPE'
1031 else:
1032 linkage = 'PE'
1033 elif 'COFF' in fileout:
1034 linkage = 'COFF'
1035 elif 'MS-DOS' in fileout:
1036 linkage = 'MSDOS'
1037 else:
1038 # XXX the A.OUT format also falls under this class...
1039 pass
1040
1041 return bits,linkage
1042
1043### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001044
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001045_uname_cache = None
1046
1047def uname():
1048
1049 """ Fairly portable uname interface. Returns a tuple
1050 of strings (system,node,release,version,machine,processor)
1051 identifying the underlying platform.
1052
1053 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001054 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001055
1056 Entries which cannot be determined are set to ''.
1057
1058 """
1059 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001060 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001061
1062 if _uname_cache is not None:
1063 return _uname_cache
1064
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001065 processor = ''
1066
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067 # Get some infos from the builtin os.uname API...
1068 try:
1069 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001070 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001071 no_os_uname = 1
1072
1073 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1074 # Hmm, no there is either no uname or uname has returned
1075 #'unknowns'... we'll have to poke around the system then.
1076 if no_os_uname:
1077 system = sys.platform
1078 release = ''
1079 version = ''
1080 node = _node()
1081 machine = ''
1082
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001083 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001084
1085 # Try win32_ver() on win32 platforms
1086 if system == 'win32':
1087 release,version,csd,ptype = win32_ver()
1088 if release and version:
1089 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001090 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001091 # available on Win XP and later; see
1092 # http://support.microsoft.com/kb/888731 and
1093 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001094 if not machine:
1095 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1096 if not processor:
1097 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001098
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001099 # Try the 'ver' system command available on some
1100 # platforms
1101 if use_syscmd_ver:
1102 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001103 # Normalize system to what win32_ver() normally returns
1104 # (_syscmd_ver() tends to return the vendor name as well)
1105 if system == 'Microsoft Windows':
1106 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001107 elif system == 'Microsoft' and release == 'Windows':
1108 # Under Windows Vista and Windows Server 2008,
1109 # Microsoft changed the output of the ver command. The
1110 # release is no longer printed. This causes the
1111 # system and release to be misidentified.
1112 system = 'Windows'
1113 if '6.0' == version[:3]:
1114 release = 'Vista'
1115 else:
1116 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001117
1118 # In case we still don't know anything useful, we'll try to
1119 # help ourselves
1120 if system in ('win32','win16'):
1121 if not version:
1122 if system == 'win32':
1123 version = '32bit'
1124 else:
1125 version = '16bit'
1126 system = 'Windows'
1127
1128 elif system[:4] == 'java':
1129 release,vendor,vminfo,osinfo = java_ver()
1130 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001131 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001132 if not version:
1133 version = vendor
1134
1135 elif os.name == 'mac':
1136 release,(version,stage,nonrel),machine = mac_ver()
1137 system = 'MacOS'
1138
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001139 # System specific extensions
1140 if system == 'OpenVMS':
1141 # OpenVMS seems to have release and version mixed up
1142 if not release or release == '0':
1143 release = version
1144 version = ''
1145 # Get processor information
1146 try:
1147 import vms_lib
1148 except ImportError:
1149 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001150 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001151 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1152 if (cpu_number >= 128):
1153 processor = 'Alpha'
1154 else:
1155 processor = 'VAX'
1156 if not processor:
1157 # Get processor information from the uname system command
1158 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001159
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001160 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001161 if system == 'unknown':
1162 system = ''
1163 if node == 'unknown':
1164 node = ''
1165 if release == 'unknown':
1166 release = ''
1167 if version == 'unknown':
1168 version = ''
1169 if machine == 'unknown':
1170 machine = ''
1171 if processor == 'unknown':
1172 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001173
1174 # normalize name
1175 if system == 'Microsoft' and release == 'Windows':
1176 system = 'Windows'
1177 release = 'Vista'
1178
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001179 _uname_cache = system,node,release,version,machine,processor
1180 return _uname_cache
1181
1182### Direct interfaces to some of the uname() return values
1183
1184def system():
1185
1186 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1187
1188 An empty string is returned if the value cannot be determined.
1189
1190 """
1191 return uname()[0]
1192
1193def node():
1194
Brett Cannon8ab27df2003-08-05 03:52:04 +00001195 """ Returns the computer's network name (which may not be fully
1196 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001197
1198 An empty string is returned if the value cannot be determined.
1199
1200 """
1201 return uname()[1]
1202
1203def release():
1204
1205 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1206
1207 An empty string is returned if the value cannot be determined.
1208
1209 """
1210 return uname()[2]
1211
1212def version():
1213
1214 """ Returns the system's release version, e.g. '#3 on degas'
1215
1216 An empty string is returned if the value cannot be determined.
1217
1218 """
1219 return uname()[3]
1220
1221def machine():
1222
1223 """ Returns the machine type, e.g. 'i386'
1224
1225 An empty string is returned if the value cannot be determined.
1226
1227 """
1228 return uname()[4]
1229
1230def processor():
1231
1232 """ Returns the (true) processor name, e.g. 'amdk6'
1233
1234 An empty string is returned if the value cannot be
1235 determined. Note that many platforms do not provide this
1236 information or simply return the same value as for machine(),
1237 e.g. NetBSD does this.
1238
1239 """
1240 return uname()[5]
1241
1242### Various APIs for extracting information from sys.version
1243
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001244_sys_version_parser = re.compile(
1245 r'([\w.+]+)\s*'
1246 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001247 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001248
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001249_ironpython_sys_version_parser = re.compile(
1250 r'IronPython\s*'
1251 '([\d\.]+)'
1252 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001253 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001254
Benjamin Petersone549ead2009-03-28 21:42:05 +00001255_pypy_sys_version_parser = re.compile(
1256 r'([\w.+]+)\s*'
1257 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1258 '\[PyPy [^\]]+\]?')
1259
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001260_sys_version_cache = {}
1261
1262def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001263
1264 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001265 (name, version, branch, revision, buildno, builddate, compiler)
1266 referring to the Python implementation name, version, branch,
1267 revision, build number, build date/time as string and the compiler
1268 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001269
1270 Note that unlike the Python sys.version, the returned value
1271 for the Python version will always include the patchlevel (it
1272 defaults to '.0').
1273
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001274 The function returns empty strings for tuple entries that
1275 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001276
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001277 sys_version may be given to parse an alternative version
1278 string, e.g. if the version was read from a different Python
1279 interpreter.
1280
1281 """
1282 # Get the Python version
1283 if sys_version is None:
1284 sys_version = sys.version
1285
1286 # Try the cache first
1287 result = _sys_version_cache.get(sys_version, None)
1288 if result is not None:
1289 return result
1290
1291 # Parse it
1292 if sys_version[:10] == 'IronPython':
1293 # IronPython
1294 name = 'IronPython'
1295 match = _ironpython_sys_version_parser.match(sys_version)
1296 if match is None:
1297 raise ValueError(
1298 'failed to parse IronPython sys.version: %s' %
1299 repr(sys_version))
1300 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001301 buildno = ''
1302 builddate = ''
1303
1304 elif sys.platform[:4] == 'java':
1305 # Jython
1306 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001307 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001308 if match is None:
1309 raise ValueError(
1310 'failed to parse Jython sys.version: %s' %
1311 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001312 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001313 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001314
1315 elif "PyPy" in sys_version:
1316 # PyPy
1317 name = "PyPy"
1318 match = _pypy_sys_version_parser.match(sys_version)
1319 if match is None:
1320 raise ValueError("failed to parse PyPy sys.version: %s" %
1321 repr(sys_version))
1322 version, buildno, builddate, buildtime = match.groups()
1323 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001324
1325 else:
1326 # CPython
1327 match = _sys_version_parser.match(sys_version)
1328 if match is None:
1329 raise ValueError(
1330 'failed to parse CPython sys.version: %s' %
1331 repr(sys_version))
1332 version, buildno, builddate, buildtime, compiler = \
1333 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001334 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001335 builddate = builddate + ' ' + buildtime
1336
Benjamin Petersone549ead2009-03-28 21:42:05 +00001337 if hasattr(sys, 'subversion'):
1338 # sys.subversion was added in Python 2.5
1339 _, branch, revision = sys.subversion
1340 else:
1341 branch = ''
1342 revision = ''
1343
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001344 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001345 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001346 if len(l) == 2:
1347 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001348 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001349
1350 # Build and cache the result
1351 result = (name, version, branch, revision, buildno, builddate, compiler)
1352 _sys_version_cache[sys_version] = result
1353 return result
1354
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001355def python_implementation():
1356
1357 """ Returns a string identifying the Python implementation.
1358
1359 Currently, the following implementations are identified:
1360 'CPython' (C implementation of Python),
1361 'IronPython' (.NET implementation of Python),
1362 'Jython' (Java implementation of Python).
1363
1364 """
1365 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001366
1367def python_version():
1368
1369 """ Returns the Python version as string 'major.minor.patchlevel'
1370
1371 Note that unlike the Python sys.version, the returned value
1372 will always include the patchlevel (it defaults to 0).
1373
1374 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001375 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001376
1377def python_version_tuple():
1378
1379 """ Returns the Python version as tuple (major, minor, patchlevel)
1380 of strings.
1381
1382 Note that unlike the Python sys.version, the returned value
1383 will always include the patchlevel (it defaults to 0).
1384
1385 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001386 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001387
1388def python_branch():
1389
1390 """ Returns a string identifying the Python implementation
1391 branch.
1392
1393 For CPython this is the Subversion branch from which the
1394 Python binary was built.
1395
1396 If not available, an empty string is returned.
1397
1398 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001399
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001400 return _sys_version()[2]
1401
1402def python_revision():
1403
1404 """ Returns a string identifying the Python implementation
1405 revision.
1406
1407 For CPython this is the Subversion revision from which the
1408 Python binary was built.
1409
1410 If not available, an empty string is returned.
1411
1412 """
1413 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001414
1415def python_build():
1416
1417 """ Returns a tuple (buildno, builddate) stating the Python
1418 build number and date as strings.
1419
1420 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001421 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001422
1423def python_compiler():
1424
1425 """ Returns a string identifying the compiler used for compiling
1426 Python.
1427
1428 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001429 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001430
1431### The Opus Magnum of platform strings :-)
1432
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001433_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001434
1435def platform(aliased=0, terse=0):
1436
1437 """ Returns a single string identifying the underlying platform
1438 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001439
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001440 The output is intended to be human readable rather than
1441 machine parseable. It may look different on different
1442 platforms and this is intended.
1443
1444 If "aliased" is true, the function will use aliases for
1445 various platforms that report system names which differ from
1446 their common names, e.g. SunOS will be reported as
1447 Solaris. The system_alias() function is used to implement
1448 this.
1449
1450 Setting terse to true causes the function to return only the
1451 absolute minimum information needed to identify the platform.
1452
1453 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001454 result = _platform_cache.get((aliased, terse), None)
1455 if result is not None:
1456 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001457
1458 # Get uname information and then apply platform specific cosmetics
1459 # to it...
1460 system,node,release,version,machine,processor = uname()
1461 if machine == processor:
1462 processor = ''
1463 if aliased:
1464 system,release,version = system_alias(system,release,version)
1465
1466 if system == 'Windows':
1467 # MS platforms
1468 rel,vers,csd,ptype = win32_ver(version)
1469 if terse:
1470 platform = _platform(system,release)
1471 else:
1472 platform = _platform(system,release,version,csd)
1473
1474 elif system in ('Linux',):
1475 # Linux based systems
1476 distname,distversion,distid = dist('')
1477 if distname and not terse:
1478 platform = _platform(system,release,machine,processor,
1479 'with',
1480 distname,distversion,distid)
1481 else:
1482 # If the distribution name is unknown check for libc vs. glibc
1483 libcname,libcversion = libc_ver(sys.executable)
1484 platform = _platform(system,release,machine,processor,
1485 'with',
1486 libcname+libcversion)
1487 elif system == 'Java':
1488 # Java platforms
1489 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001490 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001491 platform = _platform(system,release,version)
1492 else:
1493 platform = _platform(system,release,version,
1494 'on',
1495 os_name,os_version,os_arch)
1496
1497 elif system == 'MacOS':
1498 # MacOS platforms
1499 if terse:
1500 platform = _platform(system,release)
1501 else:
1502 platform = _platform(system,release,machine)
1503
1504 else:
1505 # Generic handler
1506 if terse:
1507 platform = _platform(system,release)
1508 else:
1509 bits,linkage = architecture(sys.executable)
1510 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001511
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001512 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001513 return platform
1514
1515### Command line interface
1516
1517if __name__ == '__main__':
1518 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001519 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001520 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001521 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001522 sys.exit(0)