blob: d5100a86c2eb69f4dda2bf44a2e6664048242eb3 [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
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000579
580 # Find out the registry key and some general version infos
581 maj,min,buildno,plat,csd = GetVersionEx()
582 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
583 if csd[:13] == 'Service Pack ':
584 csd = 'SP' + csd[13:]
585 if plat == VER_PLATFORM_WIN32_WINDOWS:
586 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
587 # Try to guess the release name
588 if maj == 4:
589 if min == 0:
590 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000591 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000592 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000593 elif min == 90:
594 release = 'Me'
595 else:
596 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000597 elif maj == 5:
598 release = '2000'
599 elif plat == VER_PLATFORM_WIN32_NT:
600 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
601 if maj <= 4:
602 release = 'NT'
603 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000604 if min == 0:
605 release = '2000'
606 elif min == 1:
607 release = 'XP'
608 elif min == 2:
609 release = '2003Server'
610 else:
611 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000612 elif maj == 6:
613 if min == 0:
614 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
Christian Heimes02781dc2008-03-21 01:11:52 +0000615 try:
616 productType = GetVersionEx(1)[8]
617 except TypeError:
618 # sys.getwindowsversion() doesn't take any arguments, so
619 # we cannot detect 2008 Server that way.
620 # XXX Add some other means of detecting 2008 Server ?!
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000621 release = 'Vista'
622 else:
Christian Heimes02781dc2008-03-21 01:11:52 +0000623 if productType == VER_NT_WORKSTATION:
624 release = 'Vista'
625 else:
626 release = '2008Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000627 else:
628 release = 'post2008Server'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000629 else:
630 if not release:
631 # E.g. Win3.1 with win32s
632 release = '%i.%i' % (maj,min)
633 return release,version,csd,ptype
634
635 # Open the registry key
636 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000637 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000639 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000640 except:
641 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000642
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000643 # Parse values
644 #subversion = _win32_getvalue(keyCurVer,
645 # 'SubVersionNumber',
646 # ('',1))[0]
647 #if subversion:
648 # release = release + subversion # 95a, 95b, etc.
649 build = _win32_getvalue(keyCurVer,
650 'CurrentBuildNumber',
651 ('',1))[0]
652 ptype = _win32_getvalue(keyCurVer,
653 'CurrentType',
654 (ptype,1))[0]
655
656 # Normalize version
657 version = _norm_version(version,build)
658
659 # Close key
660 RegCloseKey(keyCurVer)
661 return release,version,csd,ptype
662
663def _mac_ver_lookup(selectors,default=None):
664
Benjamin Petersonebacd262008-05-29 21:09:51 +0000665 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000666 l = []
667 append = l.append
668 for selector in selectors:
669 try:
670 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000671 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000672 append(default)
673 return l
674
675def _bcd2str(bcd):
676
677 return hex(bcd)[2:]
678
679def mac_ver(release='',versioninfo=('','',''),machine=''):
680
681 """ Get MacOS version information and return it as tuple (release,
682 versioninfo, machine) with versioninfo being a tuple (version,
683 dev_stage, non_release_version).
684
Brett Cannon8ab27df2003-08-05 03:52:04 +0000685 Entries which cannot be determined are set to the paramter values
686 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687
688 Thanks to Mark R. Levinson for mailing documentation links and
689 code examples for this function. Documentation for the
690 gestalt() API is available online at:
691
692 http://www.rgaros.nl/gestalt/
693
694 """
695 # Check whether the version info module is available
696 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000697 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698 except ImportError:
699 return release,versioninfo,machine
700 # Get the infos
701 sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
702 # Decode the infos
703 if sysv:
704 major = (sysv & 0xFF00) >> 8
705 minor = (sysv & 0x00F0) >> 4
706 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000707
708 if (major, minor) >= (10, 4):
709 # the 'sysv' gestald cannot return patchlevels
710 # higher than 9. Apple introduced 3 new
711 # gestalt codes in 10.4 to deal with this
712 # issue (needed because patch levels can
713 # run higher than 9, such as 10.4.11)
714 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
715 release = '%i.%i.%i' %(major, minor, patch)
716 else:
717 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000718
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000719 if sysu:
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000720 # NOTE: this block is left as documentation of the
721 # intention of this function, the 'sysu' gestalt is no
722 # longer available and there are no alternatives.
Guido van Rossume2a383d2007-01-15 16:59:06 +0000723 major = int((sysu & 0xFF000000) >> 24)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000724 minor = (sysu & 0x00F00000) >> 20
725 bugfix = (sysu & 0x000F0000) >> 16
726 stage = (sysu & 0x0000FF00) >> 8
727 nonrel = (sysu & 0x000000FF)
728 version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
729 nonrel = _bcd2str(nonrel)
730 stage = {0x20:'development',
731 0x40:'alpha',
732 0x60:'beta',
733 0x80:'final'}.get(stage,'')
734 versioninfo = (version,stage,nonrel)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000735
736
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000737 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000738 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000739 0x2: 'PowerPC',
740 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000741 return release,versioninfo,machine
742
Neal Norwitz9b924c62003-06-29 04:17:45 +0000743def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744
745 from java.lang import System
746 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000747 value = System.getProperty(name)
748 if value is None:
749 return default
750 return value
751 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000752 return default
753
754def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000755
Brett Cannon8ab27df2003-08-05 03:52:04 +0000756 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000757
758 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
759 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
760 tuple (os_name,os_version,os_arch).
761
762 Values which cannot be determined are set to the defaults
763 given as parameters (which all default to '').
764
765 """
766 # Import the needed APIs
767 try:
768 import java.lang
769 except ImportError:
770 return release,vendor,vminfo,osinfo
771
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000772 vendor = _java_getprop('java.vendor', vendor)
773 release = _java_getprop('java.version', release)
774 vm_name, vm_release, vm_vendor = vminfo
775 vm_name = _java_getprop('java.vm.name', vm_name)
776 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
777 vm_release = _java_getprop('java.vm.version', vm_release)
778 vminfo = vm_name, vm_release, vm_vendor
779 os_name, os_version, os_arch = osinfo
780 os_arch = _java_getprop('java.os.arch', os_arch)
781 os_name = _java_getprop('java.os.name', os_name)
782 os_version = _java_getprop('java.os.version', os_version)
783 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000784
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000785 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000786
787### System name aliasing
788
789def system_alias(system,release,version):
790
791 """ Returns (system,release,version) aliased to common
792 marketing names used for some systems.
793
794 It also does some reordering of the information in some cases
795 where it would otherwise cause confusion.
796
797 """
798 if system == 'Rhapsody':
799 # Apple's BSD derivative
800 # XXX How can we determine the marketing release number ?
801 return 'MacOS X Server',system+release,version
802
803 elif system == 'SunOS':
804 # Sun's OS
805 if release < '5':
806 # These releases use the old name SunOS
807 return system,release,version
808 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000809 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000810 if l:
811 try:
812 major = int(l[0])
813 except ValueError:
814 pass
815 else:
816 major = major - 3
817 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000818 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000819 if release < '6':
820 system = 'Solaris'
821 else:
822 # XXX Whatever the new SunOS marketing name is...
823 system = 'Solaris'
824
825 elif system == 'IRIX64':
826 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
827 # is really a version and not a different platform, since 32-bit
828 # apps are also supported..
829 system = 'IRIX'
830 if version:
831 version = version + ' (64bit)'
832 else:
833 version = '64bit'
834
835 elif system in ('win32','win16'):
836 # In case one of the other tricks
837 system = 'Windows'
838
839 return system,release,version
840
841### Various internal helpers
842
843def _platform(*args):
844
845 """ Helper to format the platform string in a filename
846 compatible format e.g. "system-version-machine".
847 """
848 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000849 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000850
851 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000852 platform = platform.replace(' ','_')
853 platform = platform.replace('/','-')
854 platform = platform.replace('\\','-')
855 platform = platform.replace(':','-')
856 platform = platform.replace(';','-')
857 platform = platform.replace('"','-')
858 platform = platform.replace('(','-')
859 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000860
861 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000862 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000863
864 # Fold '--'s and remove trailing '-'
865 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000866 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000867 if cleaned == platform:
868 break
869 platform = cleaned
870 while platform[-1] == '-':
871 platform = platform[:-1]
872
873 return platform
874
875def _node(default=''):
876
877 """ Helper to determine the node name of this machine.
878 """
879 try:
880 import socket
881 except ImportError:
882 # No sockets...
883 return default
884 try:
885 return socket.gethostname()
886 except socket.error:
887 # Still not working...
888 return default
889
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000890def _follow_symlinks(filepath):
891
892 """ In case filepath is a symlink, follow it until a
893 real file is reached.
894 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000895 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000896 while os.path.islink(filepath):
897 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000898 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899 return filepath
900
901def _syscmd_uname(option,default=''):
902
903 """ Interface to the system's uname command.
904 """
905 if sys.platform in ('dos','win32','win16','os2'):
906 # XXX Others too ?
907 return default
908 try:
909 f = os.popen('uname %s 2> /dev/null' % option)
910 except (AttributeError,os.error):
911 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000912 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000913 rc = f.close()
914 if not output or rc:
915 return default
916 else:
917 return output
918
919def _syscmd_file(target,default=''):
920
921 """ Interface to the system's file command.
922
923 The function uses the -b option of the file command to have it
924 ommit the filename in its output and if possible the -L option
925 to have the command follow symlinks. It returns default in
926 case the command should fail.
927
928 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000929 if sys.platform in ('dos','win32','win16','os2'):
930 # XXX Others too ?
931 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000932 target = _follow_symlinks(target)
933 try:
Marc-André Lemburg40779852008-09-02 10:33:55 +0000934 f = os.popen('file "%s" 2> /dev/null' % target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000935 except (AttributeError,os.error):
936 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000937 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000938 rc = f.close()
939 if not output or rc:
940 return default
941 else:
942 return output
943
944### Information about the used architecture
945
946# Default values for architecture; non-empty strings override the
947# defaults given as parameters
948_default_architecture = {
949 'win32': ('','WindowsPE'),
950 'win16': ('','Windows'),
951 'dos': ('','MSDOS'),
952}
953
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000954_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000955
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000956def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000957
958 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000959 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000960
Brett Cannon8ab27df2003-08-05 03:52:04 +0000961 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000962 the bit architecture and the linkage format used for the
963 executable. Both values are returned as strings.
964
965 Values that cannot be determined are returned as given by the
966 parameter presets. If bits is given as '', the sizeof(pointer)
967 (or sizeof(long) on Python version < 1.5.2) is used as
968 indicator for the supported pointer size.
969
970 The function relies on the system's "file" command to do the
971 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000972 platforms. On some non-Unix platforms where the "file" command
973 does not exist and the executable is set to the Python interpreter
974 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000975
976 """
977 # Use the sizeof(pointer) as default number of bits if nothing
978 # else is given as default.
979 if not bits:
980 import struct
981 try:
982 size = struct.calcsize('P')
983 except struct.error:
984 # Older installations can only query longs
985 size = struct.calcsize('l')
986 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000987
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000988 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000989 if executable:
990 output = _syscmd_file(executable, '')
991 else:
992 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000993
994 if not output and \
995 executable == sys.executable:
996 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000997 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000998 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000999 b,l = _default_architecture[sys.platform]
1000 if b:
1001 bits = b
1002 if l:
1003 linkage = l
1004 return bits,linkage
1005
1006 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001007 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +00001008
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001009 if 'executable' not in fileout:
1010 # Format not supported
1011 return bits,linkage
1012
1013 # Bits
1014 if '32-bit' in fileout:
1015 bits = '32bit'
1016 elif 'N32' in fileout:
1017 # On Irix only
1018 bits = 'n32bit'
1019 elif '64-bit' in fileout:
1020 bits = '64bit'
1021
1022 # Linkage
1023 if 'ELF' in fileout:
1024 linkage = 'ELF'
1025 elif 'PE' in fileout:
1026 # E.g. Windows uses this format
1027 if 'Windows' in fileout:
1028 linkage = 'WindowsPE'
1029 else:
1030 linkage = 'PE'
1031 elif 'COFF' in fileout:
1032 linkage = 'COFF'
1033 elif 'MS-DOS' in fileout:
1034 linkage = 'MSDOS'
1035 else:
1036 # XXX the A.OUT format also falls under this class...
1037 pass
1038
1039 return bits,linkage
1040
1041### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001042
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001043_uname_cache = None
1044
1045def uname():
1046
1047 """ Fairly portable uname interface. Returns a tuple
1048 of strings (system,node,release,version,machine,processor)
1049 identifying the underlying platform.
1050
1051 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001052 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001053
1054 Entries which cannot be determined are set to ''.
1055
1056 """
1057 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001058 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001059
1060 if _uname_cache is not None:
1061 return _uname_cache
1062
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001063 processor = ''
1064
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001065 # Get some infos from the builtin os.uname API...
1066 try:
1067 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001068 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001069 no_os_uname = 1
1070
1071 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1072 # Hmm, no there is either no uname or uname has returned
1073 #'unknowns'... we'll have to poke around the system then.
1074 if no_os_uname:
1075 system = sys.platform
1076 release = ''
1077 version = ''
1078 node = _node()
1079 machine = ''
1080
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001081 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001082
1083 # Try win32_ver() on win32 platforms
1084 if system == 'win32':
1085 release,version,csd,ptype = win32_ver()
1086 if release and version:
1087 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001088 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001089 # available on Win XP and later; see
1090 # http://support.microsoft.com/kb/888731 and
1091 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001092 if not machine:
1093 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1094 if not processor:
1095 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001096
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001097 # Try the 'ver' system command available on some
1098 # platforms
1099 if use_syscmd_ver:
1100 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001101 # Normalize system to what win32_ver() normally returns
1102 # (_syscmd_ver() tends to return the vendor name as well)
1103 if system == 'Microsoft Windows':
1104 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001105 elif system == 'Microsoft' and release == 'Windows':
1106 # Under Windows Vista and Windows Server 2008,
1107 # Microsoft changed the output of the ver command. The
1108 # release is no longer printed. This causes the
1109 # system and release to be misidentified.
1110 system = 'Windows'
1111 if '6.0' == version[:3]:
1112 release = 'Vista'
1113 else:
1114 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001115
1116 # In case we still don't know anything useful, we'll try to
1117 # help ourselves
1118 if system in ('win32','win16'):
1119 if not version:
1120 if system == 'win32':
1121 version = '32bit'
1122 else:
1123 version = '16bit'
1124 system = 'Windows'
1125
1126 elif system[:4] == 'java':
1127 release,vendor,vminfo,osinfo = java_ver()
1128 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001129 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001130 if not version:
1131 version = vendor
1132
1133 elif os.name == 'mac':
1134 release,(version,stage,nonrel),machine = mac_ver()
1135 system = 'MacOS'
1136
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001137 # System specific extensions
1138 if system == 'OpenVMS':
1139 # OpenVMS seems to have release and version mixed up
1140 if not release or release == '0':
1141 release = version
1142 version = ''
1143 # Get processor information
1144 try:
1145 import vms_lib
1146 except ImportError:
1147 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001148 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001149 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1150 if (cpu_number >= 128):
1151 processor = 'Alpha'
1152 else:
1153 processor = 'VAX'
1154 if not processor:
1155 # Get processor information from the uname system command
1156 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001157
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001158 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001159 if system == 'unknown':
1160 system = ''
1161 if node == 'unknown':
1162 node = ''
1163 if release == 'unknown':
1164 release = ''
1165 if version == 'unknown':
1166 version = ''
1167 if machine == 'unknown':
1168 machine = ''
1169 if processor == 'unknown':
1170 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001171
1172 # normalize name
1173 if system == 'Microsoft' and release == 'Windows':
1174 system = 'Windows'
1175 release = 'Vista'
1176
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177 _uname_cache = system,node,release,version,machine,processor
1178 return _uname_cache
1179
1180### Direct interfaces to some of the uname() return values
1181
1182def system():
1183
1184 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1185
1186 An empty string is returned if the value cannot be determined.
1187
1188 """
1189 return uname()[0]
1190
1191def node():
1192
Brett Cannon8ab27df2003-08-05 03:52:04 +00001193 """ Returns the computer's network name (which may not be fully
1194 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001195
1196 An empty string is returned if the value cannot be determined.
1197
1198 """
1199 return uname()[1]
1200
1201def release():
1202
1203 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1204
1205 An empty string is returned if the value cannot be determined.
1206
1207 """
1208 return uname()[2]
1209
1210def version():
1211
1212 """ Returns the system's release version, e.g. '#3 on degas'
1213
1214 An empty string is returned if the value cannot be determined.
1215
1216 """
1217 return uname()[3]
1218
1219def machine():
1220
1221 """ Returns the machine type, e.g. 'i386'
1222
1223 An empty string is returned if the value cannot be determined.
1224
1225 """
1226 return uname()[4]
1227
1228def processor():
1229
1230 """ Returns the (true) processor name, e.g. 'amdk6'
1231
1232 An empty string is returned if the value cannot be
1233 determined. Note that many platforms do not provide this
1234 information or simply return the same value as for machine(),
1235 e.g. NetBSD does this.
1236
1237 """
1238 return uname()[5]
1239
1240### Various APIs for extracting information from sys.version
1241
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001242_sys_version_parser = re.compile(
1243 r'([\w.+]+)\s*'
1244 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001245 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001246
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001247_ironpython_sys_version_parser = re.compile(
1248 r'IronPython\s*'
1249 '([\d\.]+)'
1250 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001251 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001252
Benjamin Petersone549ead2009-03-28 21:42:05 +00001253_pypy_sys_version_parser = re.compile(
1254 r'([\w.+]+)\s*'
1255 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1256 '\[PyPy [^\]]+\]?')
1257
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001258_sys_version_cache = {}
1259
1260def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001261
1262 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001263 (name, version, branch, revision, buildno, builddate, compiler)
1264 referring to the Python implementation name, version, branch,
1265 revision, build number, build date/time as string and the compiler
1266 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001267
1268 Note that unlike the Python sys.version, the returned value
1269 for the Python version will always include the patchlevel (it
1270 defaults to '.0').
1271
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001272 The function returns empty strings for tuple entries that
1273 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001274
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001275 sys_version may be given to parse an alternative version
1276 string, e.g. if the version was read from a different Python
1277 interpreter.
1278
1279 """
1280 # Get the Python version
1281 if sys_version is None:
1282 sys_version = sys.version
1283
1284 # Try the cache first
1285 result = _sys_version_cache.get(sys_version, None)
1286 if result is not None:
1287 return result
1288
1289 # Parse it
1290 if sys_version[:10] == 'IronPython':
1291 # IronPython
1292 name = 'IronPython'
1293 match = _ironpython_sys_version_parser.match(sys_version)
1294 if match is None:
1295 raise ValueError(
1296 'failed to parse IronPython sys.version: %s' %
1297 repr(sys_version))
1298 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001299 buildno = ''
1300 builddate = ''
1301
1302 elif sys.platform[:4] == 'java':
1303 # Jython
1304 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001305 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001306 if match is None:
1307 raise ValueError(
1308 'failed to parse Jython sys.version: %s' %
1309 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001310 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001311 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001312
1313 elif "PyPy" in sys_version:
1314 # PyPy
1315 name = "PyPy"
1316 match = _pypy_sys_version_parser.match(sys_version)
1317 if match is None:
1318 raise ValueError("failed to parse PyPy sys.version: %s" %
1319 repr(sys_version))
1320 version, buildno, builddate, buildtime = match.groups()
1321 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001322
1323 else:
1324 # CPython
1325 match = _sys_version_parser.match(sys_version)
1326 if match is None:
1327 raise ValueError(
1328 'failed to parse CPython sys.version: %s' %
1329 repr(sys_version))
1330 version, buildno, builddate, buildtime, compiler = \
1331 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001332 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001333 builddate = builddate + ' ' + buildtime
1334
Benjamin Petersone549ead2009-03-28 21:42:05 +00001335 if hasattr(sys, 'subversion'):
1336 # sys.subversion was added in Python 2.5
1337 _, branch, revision = sys.subversion
1338 else:
1339 branch = ''
1340 revision = ''
1341
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001342 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001343 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001344 if len(l) == 2:
1345 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001346 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001347
1348 # Build and cache the result
1349 result = (name, version, branch, revision, buildno, builddate, compiler)
1350 _sys_version_cache[sys_version] = result
1351 return result
1352
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001353def python_implementation():
1354
1355 """ Returns a string identifying the Python implementation.
1356
1357 Currently, the following implementations are identified:
1358 'CPython' (C implementation of Python),
1359 'IronPython' (.NET implementation of Python),
1360 'Jython' (Java implementation of Python).
1361
1362 """
1363 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001364
1365def python_version():
1366
1367 """ Returns the Python version as string 'major.minor.patchlevel'
1368
1369 Note that unlike the Python sys.version, the returned value
1370 will always include the patchlevel (it defaults to 0).
1371
1372 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001373 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001374
1375def python_version_tuple():
1376
1377 """ Returns the Python version as tuple (major, minor, patchlevel)
1378 of strings.
1379
1380 Note that unlike the Python sys.version, the returned value
1381 will always include the patchlevel (it defaults to 0).
1382
1383 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001384 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001385
1386def python_branch():
1387
1388 """ Returns a string identifying the Python implementation
1389 branch.
1390
1391 For CPython this is the Subversion branch from which the
1392 Python binary was built.
1393
1394 If not available, an empty string is returned.
1395
1396 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001397
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001398 return _sys_version()[2]
1399
1400def python_revision():
1401
1402 """ Returns a string identifying the Python implementation
1403 revision.
1404
1405 For CPython this is the Subversion revision from which the
1406 Python binary was built.
1407
1408 If not available, an empty string is returned.
1409
1410 """
1411 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001412
1413def python_build():
1414
1415 """ Returns a tuple (buildno, builddate) stating the Python
1416 build number and date as strings.
1417
1418 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001419 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001420
1421def python_compiler():
1422
1423 """ Returns a string identifying the compiler used for compiling
1424 Python.
1425
1426 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001427 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001428
1429### The Opus Magnum of platform strings :-)
1430
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001431_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001432
1433def platform(aliased=0, terse=0):
1434
1435 """ Returns a single string identifying the underlying platform
1436 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001437
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001438 The output is intended to be human readable rather than
1439 machine parseable. It may look different on different
1440 platforms and this is intended.
1441
1442 If "aliased" is true, the function will use aliases for
1443 various platforms that report system names which differ from
1444 their common names, e.g. SunOS will be reported as
1445 Solaris. The system_alias() function is used to implement
1446 this.
1447
1448 Setting terse to true causes the function to return only the
1449 absolute minimum information needed to identify the platform.
1450
1451 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001452 result = _platform_cache.get((aliased, terse), None)
1453 if result is not None:
1454 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001455
1456 # Get uname information and then apply platform specific cosmetics
1457 # to it...
1458 system,node,release,version,machine,processor = uname()
1459 if machine == processor:
1460 processor = ''
1461 if aliased:
1462 system,release,version = system_alias(system,release,version)
1463
1464 if system == 'Windows':
1465 # MS platforms
1466 rel,vers,csd,ptype = win32_ver(version)
1467 if terse:
1468 platform = _platform(system,release)
1469 else:
1470 platform = _platform(system,release,version,csd)
1471
1472 elif system in ('Linux',):
1473 # Linux based systems
1474 distname,distversion,distid = dist('')
1475 if distname and not terse:
1476 platform = _platform(system,release,machine,processor,
1477 'with',
1478 distname,distversion,distid)
1479 else:
1480 # If the distribution name is unknown check for libc vs. glibc
1481 libcname,libcversion = libc_ver(sys.executable)
1482 platform = _platform(system,release,machine,processor,
1483 'with',
1484 libcname+libcversion)
1485 elif system == 'Java':
1486 # Java platforms
1487 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001488 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001489 platform = _platform(system,release,version)
1490 else:
1491 platform = _platform(system,release,version,
1492 'on',
1493 os_name,os_version,os_arch)
1494
1495 elif system == 'MacOS':
1496 # MacOS platforms
1497 if terse:
1498 platform = _platform(system,release)
1499 else:
1500 platform = _platform(system,release,machine)
1501
1502 else:
1503 # Generic handler
1504 if terse:
1505 platform = _platform(system,release)
1506 else:
1507 bits,linkage = architecture(sys.executable)
1508 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001509
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001510 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001511 return platform
1512
1513### Command line interface
1514
1515if __name__ == '__main__':
1516 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001517 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001518 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001519 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001520 sys.exit(0)