blob: 21e098b989db7c8b25ad6a6a9027ea7c5025cd61 [file] [log] [blame]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001#!/usr/bin/env python
2
Brett Cannon8ab27df2003-08-05 03:52:04 +00003""" This module tries to retrieve as much platform-identifying data as
Marc-André Lemburg246d8472003-04-24 11:36:11 +00004 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
13# Python SourceForge Project Page and assign them to "lemburg".
14#
Marc-André Lemburg246d8472003-04-24 11:36:11 +000015# Still needed:
16# * more support for WinCE
17# * support for MS-DOS (PythonDX ?)
18# * support for Amiga and other still unsupported platforms running Python
19# * support for additional Linux distributions
20#
Brett Cannon8ab27df2003-08-05 03:52:04 +000021# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000022# checks (in no particular order):
23#
24# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
25# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
26# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000035# 1.0.6 - added linux_distribution()
36# 1.0.5 - fixed Java support to allow running the module on Jython
37# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000038# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000039# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000040# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000041# 1.0.0 - reformatted a bit and checked into Python CVS
42# 0.8.0 - added sys.version parser and various new access
43# APIs (python_version(), python_compiler(), etc.)
44# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
45# 0.7.1 - added support for Caldera OpenLinux
46# 0.7.0 - some fixes for WinCE; untabified the source file
47# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
48# vms_lib.getsyi() configured
49# 0.6.1 - added code to prevent 'uname -p' on platforms which are
50# known not to support it
51# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
52# did some cleanup of the interfaces - some APIs have changed
53# 0.5.5 - fixed another type in the MacOS code... should have
54# used more coffee today ;-)
55# 0.5.4 - fixed a few typos in the MacOS code
56# 0.5.3 - added experimental MacOS support; added better popen()
57# workarounds in _syscmd_ver() -- still not 100% elegant
58# though
59# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
60# return values (the system uname command tends to return
61# 'unknown' instead of just leaving the field emtpy)
62# 0.5.1 - included code for slackware dist; added exception handlers
63# to cover up situations where platforms don't have os.popen
64# (e.g. Mac) or fail on socket.gethostname(); fixed libc
65# detection RE
66# 0.5.0 - changed the API names referring to system commands to *syscmd*;
67# added java_ver(); made syscmd_ver() a private
68# API (was system_ver() in previous versions) -- use uname()
69# instead; extended the win32_ver() to also return processor
70# type information
71# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
72# 0.3.4 - fixed a bug in _follow_symlinks()
73# 0.3.3 - fixed popen() and "file" command invokation bugs
74# 0.3.2 - added architecture() API and support for it in platform()
75# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
76# 0.3.0 - added system alias support
77# 0.2.3 - removed 'wince' again... oh well.
78# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
79# 0.2.1 - added cache logic and changed the platform string format
80# 0.2.0 - changed the API to use functions instead of module globals
81# since some action take too long to be run on module import
82# 0.1.0 - first release
83#
84# You can always get the latest version of this module at:
85#
86# http://www.egenix.com/files/python/platform.py
87#
88# If that URL should fail, try contacting the author.
89
90__copyright__ = """
91 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Christian Heimes02781dc2008-03-21 01:11:52 +000092 Copyright (c) 2000-2008, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000093
94 Permission to use, copy, modify, and distribute this software and its
95 documentation for any purpose and without fee or royalty is hereby granted,
96 provided that the above copyright notice appear in all copies and that
97 both that copyright notice and this permission notice appear in
98 supporting documentation or portions thereof, including modifications,
99 that you make.
100
101 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
102 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
103 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
104 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
105 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
106 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
107 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
108
109"""
110
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000111__version__ = '1.0.6'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000112
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000113import sys, os, re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000114
115### Platform specific APIs
116
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000117_libc_search = re.compile(r'(__libc_init)'
118 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000119 '(GLIBC_([0-9.]+))'
120 '|'
Antoine Pitroufd036452008-08-19 17:56:33 +0000121 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000122
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000123def libc_ver(executable=sys.executable,lib='',version='',
124
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000125 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000126
Brett Cannon8ab27df2003-08-05 03:52:04 +0000127 """ Tries to determine the libc version that the file executable
128 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000129
130 Returns a tuple of strings (lib,version) which default to the
131 given parameters in case the lookup fails.
132
133 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000134 libc versions add symbols to the executable and thus is probably
135 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000136
137 The file is read and scanned in chunks of chunksize bytes.
138
139 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000140 if hasattr(os.path, 'realpath'):
141 # Python 2.2 introduced os.path.realpath(); it is used
142 # here to work around problems with Cygwin not being
143 # able to open symlinks for reading
144 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000145 f = open(executable,'rb')
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000146 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147 pos = 0
148 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000149 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000150 if not m:
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000151 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152 if not binary:
153 break
154 pos = 0
155 continue
156 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
157 if libcinit and not lib:
158 lib = 'libc'
159 elif glibc:
160 if lib != 'glibc':
161 lib = 'glibc'
162 version = glibcversion
163 elif glibcversion > version:
164 version = glibcversion
165 elif so:
166 if lib != 'glibc':
167 lib = 'libc'
168 if soversion > version:
169 version = soversion
170 if threads and version[-len(threads):] != threads:
171 version = version + threads
172 pos = m.end()
173 f.close()
174 return lib,version
175
176def _dist_try_harder(distname,version,id):
177
Tim Peters0eadaac2003-04-24 16:02:54 +0000178 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000179 information in case the default method fails.
180
181 Currently supports older SuSE Linux, Caldera OpenLinux and
182 Slackware Linux distributions.
183
184 """
185 if os.path.exists('/var/adm/inst-log/info'):
186 # SuSE Linux stores distribution information in that file
187 info = open('/var/adm/inst-log/info').readlines()
188 distname = 'SuSE'
189 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000190 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000191 if len(tv) == 2:
192 tag,value = tv
193 else:
194 continue
195 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000196 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000197 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000198 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000199 id = values[2]
200 return distname,version,id
201
202 if os.path.exists('/etc/.installed'):
203 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
204 info = open('/etc/.installed').readlines()
205 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000206 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
208 # XXX does Caldera support non Intel platforms ? If yes,
209 # where can we find the needed id ?
210 return 'OpenLinux',pkg[1],id
211
212 if os.path.isdir('/usr/lib/setup'):
213 # Check for slackware verson tag file (thanks to Greg Andruk)
214 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000215 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000216 if verfiles[n][:14] != 'slack-version-':
217 del verfiles[n]
218 if verfiles:
219 verfiles.sort()
220 distname = 'slackware'
221 version = verfiles[-1][14:]
222 return distname,version,id
223
224 return distname,version,id
225
Antoine Pitroufd036452008-08-19 17:56:33 +0000226_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000227_lsb_release_version = re.compile(r'(.+)'
228 ' release '
229 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000230 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000231_release_version = re.compile(r'([^0-9]+)'
232 '(?: release )?'
233 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000234 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000235
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000236# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000237# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000238# and http://data.linux-ntfs.org/rpm/whichrpm
239# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000240
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000241_supported_dists = (
242 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
243 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
244 'UnitedLinux', 'turbolinux')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000245
246def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000247
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000248 # Parse the first line
249 m = _lsb_release_version.match(firstline)
250 if m is not None:
251 # LSB format: "distro release x.x (codename)"
252 return tuple(m.groups())
253
254 # Pre-LSB format: "distro x.x (codename)"
255 m = _release_version.match(firstline)
256 if m is not None:
257 return tuple(m.groups())
258
259 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000260 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000261 if l:
262 version = l[0]
263 if len(l) > 1:
264 id = l[1]
265 else:
266 id = ''
267 return '', version, id
268
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000269def linux_distribution(distname='', version='', id='',
270
271 supported_dists=_supported_dists,
272 full_distribution_name=1):
273
274 """ Tries to determine the name of the Linux OS distribution name.
275
276 The function first looks for a distribution release file in
277 /etc and then reverts to _dist_try_harder() in case no
278 suitable files are found.
279
280 supported_dists may be given to define the set of Linux
281 distributions to look for. It defaults to a list of currently
282 supported Linux distributions identified by their release file
283 name.
284
285 If full_distribution_name is true (default), the full
286 distribution read from the OS is returned. Otherwise the short
287 name taken from supported_dists is used.
288
289 Returns a tuple (distname,version,id) which default to the
290 args given as parameters.
291
292 """
293 try:
294 etc = os.listdir('/etc')
295 except os.error:
296 # Probably not a Unix system
297 return distname,version,id
298 etc.sort()
299 for file in etc:
300 m = _release_filename.match(file)
301 if m is not None:
302 _distname,dummy = m.groups()
303 if _distname in supported_dists:
304 distname = _distname
305 break
306 else:
307 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000308
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000309 # Read the first line
310 f = open('/etc/'+file, 'r')
311 firstline = f.readline()
312 f.close()
313 _distname, _version, _id = _parse_release_file(firstline)
314
315 if _distname and full_distribution_name:
316 distname = _distname
317 if _version:
318 version = _version
319 if _id:
320 id = _id
321 return distname, version, id
322
323# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000324
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000325def dist(distname='',version='',id='',
326
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000327 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000328
Brett Cannon8ab27df2003-08-05 03:52:04 +0000329 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000330
331 The function first looks for a distribution release file in
332 /etc and then reverts to _dist_try_harder() in case no
333 suitable files are found.
334
Brett Cannon8ab27df2003-08-05 03:52:04 +0000335 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000336 args given as parameters.
337
338 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000339 return linux_distribution(distname, version, id,
340 supported_dists=supported_dists,
341 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000342
343class _popen:
344
345 """ Fairly portable (alternative) popen implementation.
346
347 This is mostly needed in case os.popen() is not available, or
348 doesn't work as advertised, e.g. in Win9X GUI programs like
349 PythonWin or IDLE.
350
351 Writing to the pipe is currently not supported.
352
353 """
354 tmpfile = ''
355 pipe = None
356 bufsize = None
357 mode = 'r'
358
359 def __init__(self,cmd,mode='r',bufsize=None):
360
361 if mode != 'r':
Collin Winterce36ad82007-08-30 01:19:48 +0000362 raise ValueError('popen()-emulation only supports read mode')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000363 import tempfile
364 self.tmpfile = tmpfile = tempfile.mktemp()
365 os.system(cmd + ' > %s' % tmpfile)
366 self.pipe = open(tmpfile,'rb')
367 self.bufsize = bufsize
368 self.mode = mode
369
370 def read(self):
371
372 return self.pipe.read()
373
374 def readlines(self):
375
376 if self.bufsize is not None:
377 return self.pipe.readlines()
378
379 def close(self,
380
381 remove=os.unlink,error=os.error):
382
383 if self.pipe:
384 rc = self.pipe.close()
385 else:
386 rc = 255
387 if self.tmpfile:
388 try:
389 remove(self.tmpfile)
390 except error:
391 pass
392 return rc
393
394 # Alias
395 __del__ = close
396
397def popen(cmd, mode='r', bufsize=None):
398
399 """ Portable popen() interface.
400 """
401 # Find a working popen implementation preferring win32pipe.popen
402 # over os.popen over _popen
403 popen = None
404 if os.environ.get('OS','') == 'Windows_NT':
405 # On NT win32pipe should work; on Win9x it hangs due to bugs
406 # in the MS C lib (see MS KnowledgeBase article Q150956)
407 try:
408 import win32pipe
409 except ImportError:
410 pass
411 else:
412 popen = win32pipe.popen
413 if popen is None:
414 if hasattr(os,'popen'):
415 popen = os.popen
416 # Check whether it works... it doesn't in GUI programs
417 # on Windows platforms
418 if sys.platform == 'win32': # XXX Others too ?
419 try:
420 popen('')
421 except os.error:
422 popen = _popen
423 else:
424 popen = _popen
425 if bufsize is None:
426 return popen(cmd,mode)
427 else:
428 return popen(cmd,mode,bufsize)
429
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000430def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000431
Brett Cannon8ab27df2003-08-05 03:52:04 +0000432 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000433 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000434 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000435 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000436 if build:
437 l.append(build)
438 try:
439 ints = map(int,l)
440 except ValueError:
441 strings = l
442 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000443 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000444 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000445 return version
446
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000447_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
448 '.*'
Antoine Pitroufd036452008-08-19 17:56:33 +0000449 'Version ([\d.]+))', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000450
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000451def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000453 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454
455 """ Tries to figure out the OS version used and returns
456 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000457
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458 It uses the "ver" shell command for this which is known
459 to exists on Windows, DOS and OS/2. XXX Others too ?
460
461 In case this fails, the given parameters are used as
462 defaults.
463
464 """
465 if sys.platform not in supported_platforms:
466 return system,release,version
467
468 # Try some common cmd strings
469 for cmd in ('ver','command /c ver','cmd /c ver'):
470 try:
471 pipe = popen(cmd)
472 info = pipe.read()
473 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000474 raise os.error('command failed')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000475 # XXX How can I supress shell errors from being written
476 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000477 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000478 #print 'Command %s failed: %s' % (cmd,why)
479 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000480 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000481 #print 'Command %s failed: %s' % (cmd,why)
482 continue
483 else:
484 break
485 else:
486 return system,release,version
487
488 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000489 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000490 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000491 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000492 system,release,version = m.groups()
493 # Strip trailing dots from version and release
494 if release[-1] == '.':
495 release = release[:-1]
496 if version[-1] == '.':
497 version = version[:-1]
498 # Normalize the version and build strings (eliminating additional
499 # zeros)
500 version = _norm_version(version)
501 return system,release,version
502
503def _win32_getvalue(key,name,default=''):
504
505 """ Read a value for name from the registry key.
506
507 In case this fails, default is returned.
508
509 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000510 try:
511 # Use win32api if available
512 from win32api import RegQueryValueEx
513 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000514 # On Python 2.0 and later, emulate using winreg
515 import winreg
516 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000517 try:
518 return RegQueryValueEx(key,name)
519 except:
520 return default
521
522def win32_ver(release='',version='',csd='',ptype=''):
523
524 """ Get additional version information from the Windows Registry
525 and return a tuple (version,csd,ptype) referring to version
526 number, CSD level and OS type (multi/single
527 processor).
528
529 As a hint: ptype returns 'Uniprocessor Free' on single
530 processor NT machines and 'Multiprocessor Free' on multi
531 processor machines. The 'Free' refers to the OS version being
532 free of debugging code. It could also state 'Checked' which
533 means the OS version uses debugging code, i.e. code that
534 checks arguments, ranges, etc. (Thomas Heller).
535
Christian Heimes02781dc2008-03-21 01:11:52 +0000536 Note: this function works best with Mark Hammond's win32
537 package installed, but also on Python 2.3 and later. It
538 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000539
540 """
541 # XXX Is there any way to find out the processor type on WinXX ?
542 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000543 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000544 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000545 #
546 # The mappings between reg. values and release names can be found
547 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548
549 # Import the needed APIs
550 try:
551 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000552 from win32api import RegQueryValueEx, RegOpenKeyEx, \
553 RegCloseKey, GetVersionEx
554 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
555 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000556 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000557 # Emulate the win32api module using Python APIs
558 try:
559 sys.getwindowsversion
560 except AttributeError:
561 # No emulation possible, so return the defaults...
562 return release,version,csd,ptype
563 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000564 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000565 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000566 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000567 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000568 RegQueryValueEx = winreg.QueryValueEx
569 RegOpenKeyEx = winreg.OpenKeyEx
570 RegCloseKey = winreg.CloseKey
571 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000572 VER_PLATFORM_WIN32_WINDOWS = 1
573 VER_PLATFORM_WIN32_NT = 2
574 VER_NT_WORKSTATION = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000575
576 # Find out the registry key and some general version infos
577 maj,min,buildno,plat,csd = GetVersionEx()
578 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
579 if csd[:13] == 'Service Pack ':
580 csd = 'SP' + csd[13:]
581 if plat == VER_PLATFORM_WIN32_WINDOWS:
582 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
583 # Try to guess the release name
584 if maj == 4:
585 if min == 0:
586 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000587 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000588 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000589 elif min == 90:
590 release = 'Me'
591 else:
592 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000593 elif maj == 5:
594 release = '2000'
595 elif plat == VER_PLATFORM_WIN32_NT:
596 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
597 if maj <= 4:
598 release = 'NT'
599 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000600 if min == 0:
601 release = '2000'
602 elif min == 1:
603 release = 'XP'
604 elif min == 2:
605 release = '2003Server'
606 else:
607 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000608 elif maj == 6:
609 if min == 0:
610 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
Christian Heimes02781dc2008-03-21 01:11:52 +0000611 try:
612 productType = GetVersionEx(1)[8]
613 except TypeError:
614 # sys.getwindowsversion() doesn't take any arguments, so
615 # we cannot detect 2008 Server that way.
616 # XXX Add some other means of detecting 2008 Server ?!
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000617 release = 'Vista'
618 else:
Christian Heimes02781dc2008-03-21 01:11:52 +0000619 if productType == VER_NT_WORKSTATION:
620 release = 'Vista'
621 else:
622 release = '2008Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000623 else:
624 release = 'post2008Server'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000625 else:
626 if not release:
627 # E.g. Win3.1 with win32s
628 release = '%i.%i' % (maj,min)
629 return release,version,csd,ptype
630
631 # Open the registry key
632 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000633 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000634 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000635 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636 except:
637 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000638
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000639 # Parse values
640 #subversion = _win32_getvalue(keyCurVer,
641 # 'SubVersionNumber',
642 # ('',1))[0]
643 #if subversion:
644 # release = release + subversion # 95a, 95b, etc.
645 build = _win32_getvalue(keyCurVer,
646 'CurrentBuildNumber',
647 ('',1))[0]
648 ptype = _win32_getvalue(keyCurVer,
649 'CurrentType',
650 (ptype,1))[0]
651
652 # Normalize version
653 version = _norm_version(version,build)
654
655 # Close key
656 RegCloseKey(keyCurVer)
657 return release,version,csd,ptype
658
659def _mac_ver_lookup(selectors,default=None):
660
Benjamin Petersonebacd262008-05-29 21:09:51 +0000661 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000662 l = []
663 append = l.append
664 for selector in selectors:
665 try:
666 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000667 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000668 append(default)
669 return l
670
671def _bcd2str(bcd):
672
673 return hex(bcd)[2:]
674
675def mac_ver(release='',versioninfo=('','',''),machine=''):
676
677 """ Get MacOS version information and return it as tuple (release,
678 versioninfo, machine) with versioninfo being a tuple (version,
679 dev_stage, non_release_version).
680
Brett Cannon8ab27df2003-08-05 03:52:04 +0000681 Entries which cannot be determined are set to the paramter values
682 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000683
684 Thanks to Mark R. Levinson for mailing documentation links and
685 code examples for this function. Documentation for the
686 gestalt() API is available online at:
687
688 http://www.rgaros.nl/gestalt/
689
690 """
691 # Check whether the version info module is available
692 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000693 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000694 except ImportError:
695 return release,versioninfo,machine
696 # Get the infos
697 sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
698 # Decode the infos
699 if sysv:
700 major = (sysv & 0xFF00) >> 8
701 minor = (sysv & 0x00F0) >> 4
702 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000703
704 if (major, minor) >= (10, 4):
705 # the 'sysv' gestald cannot return patchlevels
706 # higher than 9. Apple introduced 3 new
707 # gestalt codes in 10.4 to deal with this
708 # issue (needed because patch levels can
709 # run higher than 9, such as 10.4.11)
710 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
711 release = '%i.%i.%i' %(major, minor, patch)
712 else:
713 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000714
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000715 if sysu:
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000716 # NOTE: this block is left as documentation of the
717 # intention of this function, the 'sysu' gestalt is no
718 # longer available and there are no alternatives.
Guido van Rossume2a383d2007-01-15 16:59:06 +0000719 major = int((sysu & 0xFF000000) >> 24)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000720 minor = (sysu & 0x00F00000) >> 20
721 bugfix = (sysu & 0x000F0000) >> 16
722 stage = (sysu & 0x0000FF00) >> 8
723 nonrel = (sysu & 0x000000FF)
724 version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
725 nonrel = _bcd2str(nonrel)
726 stage = {0x20:'development',
727 0x40:'alpha',
728 0x60:'beta',
729 0x80:'final'}.get(stage,'')
730 versioninfo = (version,stage,nonrel)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000731
732
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000733 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000734 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000735 0x2: 'PowerPC',
736 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000737 return release,versioninfo,machine
738
Neal Norwitz9b924c62003-06-29 04:17:45 +0000739def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000740
741 from java.lang import System
742 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000743 value = System.getProperty(name)
744 if value is None:
745 return default
746 return value
747 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000748 return default
749
750def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000751
Brett Cannon8ab27df2003-08-05 03:52:04 +0000752 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000753
754 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
755 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
756 tuple (os_name,os_version,os_arch).
757
758 Values which cannot be determined are set to the defaults
759 given as parameters (which all default to '').
760
761 """
762 # Import the needed APIs
763 try:
764 import java.lang
765 except ImportError:
766 return release,vendor,vminfo,osinfo
767
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000768 vendor = _java_getprop('java.vendor', vendor)
769 release = _java_getprop('java.version', release)
770 vm_name, vm_release, vm_vendor = vminfo
771 vm_name = _java_getprop('java.vm.name', vm_name)
772 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
773 vm_release = _java_getprop('java.vm.version', vm_release)
774 vminfo = vm_name, vm_release, vm_vendor
775 os_name, os_version, os_arch = osinfo
776 os_arch = _java_getprop('java.os.arch', os_arch)
777 os_name = _java_getprop('java.os.name', os_name)
778 os_version = _java_getprop('java.os.version', os_version)
779 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000780
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000781 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000782
783### System name aliasing
784
785def system_alias(system,release,version):
786
787 """ Returns (system,release,version) aliased to common
788 marketing names used for some systems.
789
790 It also does some reordering of the information in some cases
791 where it would otherwise cause confusion.
792
793 """
794 if system == 'Rhapsody':
795 # Apple's BSD derivative
796 # XXX How can we determine the marketing release number ?
797 return 'MacOS X Server',system+release,version
798
799 elif system == 'SunOS':
800 # Sun's OS
801 if release < '5':
802 # These releases use the old name SunOS
803 return system,release,version
804 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000805 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000806 if l:
807 try:
808 major = int(l[0])
809 except ValueError:
810 pass
811 else:
812 major = major - 3
813 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000814 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000815 if release < '6':
816 system = 'Solaris'
817 else:
818 # XXX Whatever the new SunOS marketing name is...
819 system = 'Solaris'
820
821 elif system == 'IRIX64':
822 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
823 # is really a version and not a different platform, since 32-bit
824 # apps are also supported..
825 system = 'IRIX'
826 if version:
827 version = version + ' (64bit)'
828 else:
829 version = '64bit'
830
831 elif system in ('win32','win16'):
832 # In case one of the other tricks
833 system = 'Windows'
834
835 return system,release,version
836
837### Various internal helpers
838
839def _platform(*args):
840
841 """ Helper to format the platform string in a filename
842 compatible format e.g. "system-version-machine".
843 """
844 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000845 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000846
847 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000848 platform = platform.replace(' ','_')
849 platform = platform.replace('/','-')
850 platform = platform.replace('\\','-')
851 platform = platform.replace(':','-')
852 platform = platform.replace(';','-')
853 platform = platform.replace('"','-')
854 platform = platform.replace('(','-')
855 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000856
857 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000858 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000859
860 # Fold '--'s and remove trailing '-'
861 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000862 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000863 if cleaned == platform:
864 break
865 platform = cleaned
866 while platform[-1] == '-':
867 platform = platform[:-1]
868
869 return platform
870
871def _node(default=''):
872
873 """ Helper to determine the node name of this machine.
874 """
875 try:
876 import socket
877 except ImportError:
878 # No sockets...
879 return default
880 try:
881 return socket.gethostname()
882 except socket.error:
883 # Still not working...
884 return default
885
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000886def _follow_symlinks(filepath):
887
888 """ In case filepath is a symlink, follow it until a
889 real file is reached.
890 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000891 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000892 while os.path.islink(filepath):
893 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000894 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000895 return filepath
896
897def _syscmd_uname(option,default=''):
898
899 """ Interface to the system's uname command.
900 """
901 if sys.platform in ('dos','win32','win16','os2'):
902 # XXX Others too ?
903 return default
904 try:
905 f = os.popen('uname %s 2> /dev/null' % option)
906 except (AttributeError,os.error):
907 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000908 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000909 rc = f.close()
910 if not output or rc:
911 return default
912 else:
913 return output
914
915def _syscmd_file(target,default=''):
916
917 """ Interface to the system's file command.
918
919 The function uses the -b option of the file command to have it
920 ommit the filename in its output and if possible the -L option
921 to have the command follow symlinks. It returns default in
922 case the command should fail.
923
924 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000925 if sys.platform in ('dos','win32','win16','os2'):
926 # XXX Others too ?
927 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000928 target = _follow_symlinks(target)
929 try:
Marc-André Lemburg40779852008-09-02 10:33:55 +0000930 f = os.popen('file "%s" 2> /dev/null' % target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000931 except (AttributeError,os.error):
932 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000933 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000934 rc = f.close()
935 if not output or rc:
936 return default
937 else:
938 return output
939
940### Information about the used architecture
941
942# Default values for architecture; non-empty strings override the
943# defaults given as parameters
944_default_architecture = {
945 'win32': ('','WindowsPE'),
946 'win16': ('','Windows'),
947 'dos': ('','MSDOS'),
948}
949
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000950_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000951
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000952def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000953
954 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000955 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000956
Brett Cannon8ab27df2003-08-05 03:52:04 +0000957 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958 the bit architecture and the linkage format used for the
959 executable. Both values are returned as strings.
960
961 Values that cannot be determined are returned as given by the
962 parameter presets. If bits is given as '', the sizeof(pointer)
963 (or sizeof(long) on Python version < 1.5.2) is used as
964 indicator for the supported pointer size.
965
966 The function relies on the system's "file" command to do the
967 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000968 platforms. On some non-Unix platforms where the "file" command
969 does not exist and the executable is set to the Python interpreter
970 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000971
972 """
973 # Use the sizeof(pointer) as default number of bits if nothing
974 # else is given as default.
975 if not bits:
976 import struct
977 try:
978 size = struct.calcsize('P')
979 except struct.error:
980 # Older installations can only query longs
981 size = struct.calcsize('l')
982 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000983
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000984 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000985 if executable:
986 output = _syscmd_file(executable, '')
987 else:
988 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000989
990 if not output and \
991 executable == sys.executable:
992 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000993 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000994 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000995 b,l = _default_architecture[sys.platform]
996 if b:
997 bits = b
998 if l:
999 linkage = l
1000 return bits,linkage
1001
1002 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001003 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +00001004
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001005 if 'executable' not in fileout:
1006 # Format not supported
1007 return bits,linkage
1008
1009 # Bits
1010 if '32-bit' in fileout:
1011 bits = '32bit'
1012 elif 'N32' in fileout:
1013 # On Irix only
1014 bits = 'n32bit'
1015 elif '64-bit' in fileout:
1016 bits = '64bit'
1017
1018 # Linkage
1019 if 'ELF' in fileout:
1020 linkage = 'ELF'
1021 elif 'PE' in fileout:
1022 # E.g. Windows uses this format
1023 if 'Windows' in fileout:
1024 linkage = 'WindowsPE'
1025 else:
1026 linkage = 'PE'
1027 elif 'COFF' in fileout:
1028 linkage = 'COFF'
1029 elif 'MS-DOS' in fileout:
1030 linkage = 'MSDOS'
1031 else:
1032 # XXX the A.OUT format also falls under this class...
1033 pass
1034
1035 return bits,linkage
1036
1037### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001038
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001039_uname_cache = None
1040
1041def uname():
1042
1043 """ Fairly portable uname interface. Returns a tuple
1044 of strings (system,node,release,version,machine,processor)
1045 identifying the underlying platform.
1046
1047 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001048 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001049
1050 Entries which cannot be determined are set to ''.
1051
1052 """
1053 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001054 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001055
1056 if _uname_cache is not None:
1057 return _uname_cache
1058
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001059 processor = ''
1060
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001061 # Get some infos from the builtin os.uname API...
1062 try:
1063 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001065 no_os_uname = 1
1066
1067 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1068 # Hmm, no there is either no uname or uname has returned
1069 #'unknowns'... we'll have to poke around the system then.
1070 if no_os_uname:
1071 system = sys.platform
1072 release = ''
1073 version = ''
1074 node = _node()
1075 machine = ''
1076
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001077 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001078
1079 # Try win32_ver() on win32 platforms
1080 if system == 'win32':
1081 release,version,csd,ptype = win32_ver()
1082 if release and version:
1083 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001084 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001085 # available on Win XP and later; see
1086 # http://support.microsoft.com/kb/888731 and
1087 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001088 if not machine:
1089 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1090 if not processor:
1091 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001092
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001093 # Try the 'ver' system command available on some
1094 # platforms
1095 if use_syscmd_ver:
1096 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001097 # Normalize system to what win32_ver() normally returns
1098 # (_syscmd_ver() tends to return the vendor name as well)
1099 if system == 'Microsoft Windows':
1100 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001101 elif system == 'Microsoft' and release == 'Windows':
1102 # Under Windows Vista and Windows Server 2008,
1103 # Microsoft changed the output of the ver command. The
1104 # release is no longer printed. This causes the
1105 # system and release to be misidentified.
1106 system = 'Windows'
1107 if '6.0' == version[:3]:
1108 release = 'Vista'
1109 else:
1110 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001111
1112 # In case we still don't know anything useful, we'll try to
1113 # help ourselves
1114 if system in ('win32','win16'):
1115 if not version:
1116 if system == 'win32':
1117 version = '32bit'
1118 else:
1119 version = '16bit'
1120 system = 'Windows'
1121
1122 elif system[:4] == 'java':
1123 release,vendor,vminfo,osinfo = java_ver()
1124 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001125 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001126 if not version:
1127 version = vendor
1128
1129 elif os.name == 'mac':
1130 release,(version,stage,nonrel),machine = mac_ver()
1131 system = 'MacOS'
1132
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001133 # System specific extensions
1134 if system == 'OpenVMS':
1135 # OpenVMS seems to have release and version mixed up
1136 if not release or release == '0':
1137 release = version
1138 version = ''
1139 # Get processor information
1140 try:
1141 import vms_lib
1142 except ImportError:
1143 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001144 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001145 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1146 if (cpu_number >= 128):
1147 processor = 'Alpha'
1148 else:
1149 processor = 'VAX'
1150 if not processor:
1151 # Get processor information from the uname system command
1152 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001153
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001154 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001155 if system == 'unknown':
1156 system = ''
1157 if node == 'unknown':
1158 node = ''
1159 if release == 'unknown':
1160 release = ''
1161 if version == 'unknown':
1162 version = ''
1163 if machine == 'unknown':
1164 machine = ''
1165 if processor == 'unknown':
1166 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001167
1168 # normalize name
1169 if system == 'Microsoft' and release == 'Windows':
1170 system = 'Windows'
1171 release = 'Vista'
1172
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001173 _uname_cache = system,node,release,version,machine,processor
1174 return _uname_cache
1175
1176### Direct interfaces to some of the uname() return values
1177
1178def system():
1179
1180 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1181
1182 An empty string is returned if the value cannot be determined.
1183
1184 """
1185 return uname()[0]
1186
1187def node():
1188
Brett Cannon8ab27df2003-08-05 03:52:04 +00001189 """ Returns the computer's network name (which may not be fully
1190 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001191
1192 An empty string is returned if the value cannot be determined.
1193
1194 """
1195 return uname()[1]
1196
1197def release():
1198
1199 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1200
1201 An empty string is returned if the value cannot be determined.
1202
1203 """
1204 return uname()[2]
1205
1206def version():
1207
1208 """ Returns the system's release version, e.g. '#3 on degas'
1209
1210 An empty string is returned if the value cannot be determined.
1211
1212 """
1213 return uname()[3]
1214
1215def machine():
1216
1217 """ Returns the machine type, e.g. 'i386'
1218
1219 An empty string is returned if the value cannot be determined.
1220
1221 """
1222 return uname()[4]
1223
1224def processor():
1225
1226 """ Returns the (true) processor name, e.g. 'amdk6'
1227
1228 An empty string is returned if the value cannot be
1229 determined. Note that many platforms do not provide this
1230 information or simply return the same value as for machine(),
1231 e.g. NetBSD does this.
1232
1233 """
1234 return uname()[5]
1235
1236### Various APIs for extracting information from sys.version
1237
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001238_sys_version_parser = re.compile(
1239 r'([\w.+]+)\s*'
1240 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001241 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001242
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001243_ironpython_sys_version_parser = re.compile(
1244 r'IronPython\s*'
1245 '([\d\.]+)'
1246 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001247 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001248
Benjamin Petersone549ead2009-03-28 21:42:05 +00001249_pypy_sys_version_parser = re.compile(
1250 r'([\w.+]+)\s*'
1251 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1252 '\[PyPy [^\]]+\]?')
1253
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001254_sys_version_cache = {}
1255
1256def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001257
1258 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001259 (name, version, branch, revision, buildno, builddate, compiler)
1260 referring to the Python implementation name, version, branch,
1261 revision, build number, build date/time as string and the compiler
1262 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001263
1264 Note that unlike the Python sys.version, the returned value
1265 for the Python version will always include the patchlevel (it
1266 defaults to '.0').
1267
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001268 The function returns empty strings for tuple entries that
1269 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001270
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001271 sys_version may be given to parse an alternative version
1272 string, e.g. if the version was read from a different Python
1273 interpreter.
1274
1275 """
1276 # Get the Python version
1277 if sys_version is None:
1278 sys_version = sys.version
1279
1280 # Try the cache first
1281 result = _sys_version_cache.get(sys_version, None)
1282 if result is not None:
1283 return result
1284
1285 # Parse it
1286 if sys_version[:10] == 'IronPython':
1287 # IronPython
1288 name = 'IronPython'
1289 match = _ironpython_sys_version_parser.match(sys_version)
1290 if match is None:
1291 raise ValueError(
1292 'failed to parse IronPython sys.version: %s' %
1293 repr(sys_version))
1294 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001295 buildno = ''
1296 builddate = ''
1297
1298 elif sys.platform[:4] == 'java':
1299 # Jython
1300 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001301 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001302 if match is None:
1303 raise ValueError(
1304 'failed to parse Jython sys.version: %s' %
1305 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001306 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001307 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001308
1309 elif "PyPy" in sys_version:
1310 # PyPy
1311 name = "PyPy"
1312 match = _pypy_sys_version_parser.match(sys_version)
1313 if match is None:
1314 raise ValueError("failed to parse PyPy sys.version: %s" %
1315 repr(sys_version))
1316 version, buildno, builddate, buildtime = match.groups()
1317 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001318
1319 else:
1320 # CPython
1321 match = _sys_version_parser.match(sys_version)
1322 if match is None:
1323 raise ValueError(
1324 'failed to parse CPython sys.version: %s' %
1325 repr(sys_version))
1326 version, buildno, builddate, buildtime, compiler = \
1327 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001328 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001329 builddate = builddate + ' ' + buildtime
1330
Benjamin Petersone549ead2009-03-28 21:42:05 +00001331 if hasattr(sys, 'subversion'):
1332 # sys.subversion was added in Python 2.5
1333 _, branch, revision = sys.subversion
1334 else:
1335 branch = ''
1336 revision = ''
1337
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001338 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001339 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001340 if len(l) == 2:
1341 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001342 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001343
1344 # Build and cache the result
1345 result = (name, version, branch, revision, buildno, builddate, compiler)
1346 _sys_version_cache[sys_version] = result
1347 return result
1348
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001349def python_implementation():
1350
1351 """ Returns a string identifying the Python implementation.
1352
1353 Currently, the following implementations are identified:
1354 'CPython' (C implementation of Python),
1355 'IronPython' (.NET implementation of Python),
1356 'Jython' (Java implementation of Python).
1357
1358 """
1359 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001360
1361def python_version():
1362
1363 """ Returns the Python version as string 'major.minor.patchlevel'
1364
1365 Note that unlike the Python sys.version, the returned value
1366 will always include the patchlevel (it defaults to 0).
1367
1368 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001369 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001370
1371def python_version_tuple():
1372
1373 """ Returns the Python version as tuple (major, minor, patchlevel)
1374 of strings.
1375
1376 Note that unlike the Python sys.version, the returned value
1377 will always include the patchlevel (it defaults to 0).
1378
1379 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001380 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001381
1382def python_branch():
1383
1384 """ Returns a string identifying the Python implementation
1385 branch.
1386
1387 For CPython this is the Subversion branch from which the
1388 Python binary was built.
1389
1390 If not available, an empty string is returned.
1391
1392 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001393
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001394 return _sys_version()[2]
1395
1396def python_revision():
1397
1398 """ Returns a string identifying the Python implementation
1399 revision.
1400
1401 For CPython this is the Subversion revision from which the
1402 Python binary was built.
1403
1404 If not available, an empty string is returned.
1405
1406 """
1407 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001408
1409def python_build():
1410
1411 """ Returns a tuple (buildno, builddate) stating the Python
1412 build number and date as strings.
1413
1414 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001415 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001416
1417def python_compiler():
1418
1419 """ Returns a string identifying the compiler used for compiling
1420 Python.
1421
1422 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001423 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001424
1425### The Opus Magnum of platform strings :-)
1426
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001427_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001428
1429def platform(aliased=0, terse=0):
1430
1431 """ Returns a single string identifying the underlying platform
1432 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001433
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001434 The output is intended to be human readable rather than
1435 machine parseable. It may look different on different
1436 platforms and this is intended.
1437
1438 If "aliased" is true, the function will use aliases for
1439 various platforms that report system names which differ from
1440 their common names, e.g. SunOS will be reported as
1441 Solaris. The system_alias() function is used to implement
1442 this.
1443
1444 Setting terse to true causes the function to return only the
1445 absolute minimum information needed to identify the platform.
1446
1447 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001448 result = _platform_cache.get((aliased, terse), None)
1449 if result is not None:
1450 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001451
1452 # Get uname information and then apply platform specific cosmetics
1453 # to it...
1454 system,node,release,version,machine,processor = uname()
1455 if machine == processor:
1456 processor = ''
1457 if aliased:
1458 system,release,version = system_alias(system,release,version)
1459
1460 if system == 'Windows':
1461 # MS platforms
1462 rel,vers,csd,ptype = win32_ver(version)
1463 if terse:
1464 platform = _platform(system,release)
1465 else:
1466 platform = _platform(system,release,version,csd)
1467
1468 elif system in ('Linux',):
1469 # Linux based systems
1470 distname,distversion,distid = dist('')
1471 if distname and not terse:
1472 platform = _platform(system,release,machine,processor,
1473 'with',
1474 distname,distversion,distid)
1475 else:
1476 # If the distribution name is unknown check for libc vs. glibc
1477 libcname,libcversion = libc_ver(sys.executable)
1478 platform = _platform(system,release,machine,processor,
1479 'with',
1480 libcname+libcversion)
1481 elif system == 'Java':
1482 # Java platforms
1483 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001484 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001485 platform = _platform(system,release,version)
1486 else:
1487 platform = _platform(system,release,version,
1488 'on',
1489 os_name,os_version,os_arch)
1490
1491 elif system == 'MacOS':
1492 # MacOS platforms
1493 if terse:
1494 platform = _platform(system,release)
1495 else:
1496 platform = _platform(system,release,machine)
1497
1498 else:
1499 # Generic handler
1500 if terse:
1501 platform = _platform(system,release)
1502 else:
1503 bits,linkage = architecture(sys.executable)
1504 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001505
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001506 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001507 return platform
1508
1509### Command line interface
1510
1511if __name__ == '__main__':
1512 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001513 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001514 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001515 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001516 sys.exit(0)