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