blob: 829d5f0fd596fc673de1fc6e2b83bccec927d99a [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
Georg Brandl52c17942009-09-19 08:43:16 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
15# Note: Please keep this module compatible to Python 1.5.2.
16#
17# Still needed:
18# * more support for WinCE
19# * support for MS-DOS (PythonDX ?)
20# * support for Amiga and other still unsupported platforms running Python
21# * support for additional Linux distributions
22#
Brett Cannon8ab27df2003-08-05 03:52:04 +000023# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000024# checks (in no particular order):
25#
26# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
27# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
28# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
29# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
30# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +000031# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
Marc-André Lemburg246d8472003-04-24 11:36:11 +000032#
33# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000034#
35# <see CVS and SVN checkin messages for history>
36#
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +000037# 1.0.7 - added DEV_NULL
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +000038# 1.0.6 - added linux_distribution()
39# 1.0.5 - fixed Java support to allow running the module on Jython
40# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000041# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000042# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000043# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000044# 1.0.0 - reformatted a bit and checked into Python CVS
45# 0.8.0 - added sys.version parser and various new access
46# APIs (python_version(), python_compiler(), etc.)
47# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
48# 0.7.1 - added support for Caldera OpenLinux
49# 0.7.0 - some fixes for WinCE; untabified the source file
50# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
51# vms_lib.getsyi() configured
52# 0.6.1 - added code to prevent 'uname -p' on platforms which are
53# known not to support it
54# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
55# did some cleanup of the interfaces - some APIs have changed
56# 0.5.5 - fixed another type in the MacOS code... should have
57# used more coffee today ;-)
58# 0.5.4 - fixed a few typos in the MacOS code
59# 0.5.3 - added experimental MacOS support; added better popen()
60# workarounds in _syscmd_ver() -- still not 100% elegant
61# though
62# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
63# return values (the system uname command tends to return
64# 'unknown' instead of just leaving the field emtpy)
65# 0.5.1 - included code for slackware dist; added exception handlers
66# to cover up situations where platforms don't have os.popen
67# (e.g. Mac) or fail on socket.gethostname(); fixed libc
68# detection RE
69# 0.5.0 - changed the API names referring to system commands to *syscmd*;
70# added java_ver(); made syscmd_ver() a private
71# API (was system_ver() in previous versions) -- use uname()
72# instead; extended the win32_ver() to also return processor
73# type information
74# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
75# 0.3.4 - fixed a bug in _follow_symlinks()
76# 0.3.3 - fixed popen() and "file" command invokation bugs
77# 0.3.2 - added architecture() API and support for it in platform()
78# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
79# 0.3.0 - added system alias support
80# 0.2.3 - removed 'wince' again... oh well.
81# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
82# 0.2.1 - added cache logic and changed the platform string format
83# 0.2.0 - changed the API to use functions instead of module globals
84# since some action take too long to be run on module import
85# 0.1.0 - first release
86#
87# You can always get the latest version of this module at:
88#
89# http://www.egenix.com/files/python/platform.py
90#
91# If that URL should fail, try contacting the author.
92
93__copyright__ = """
94 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Georg Brandl8cdc9bc2010-01-01 13:07:05 +000095 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000096
97 Permission to use, copy, modify, and distribute this software and its
98 documentation for any purpose and without fee or royalty is hereby granted,
99 provided that the above copyright notice appear in all copies and that
100 both that copyright notice and this permission notice appear in
101 supporting documentation or portions thereof, including modifications,
102 that you make.
103
104 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
105 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
106 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
107 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
108 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
109 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
110 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
111
112"""
113
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000114__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000115
116import sys,string,os,re
117
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000118### Globals & Constants
119
120# Determine the platform's /dev/null device
121try:
122 DEV_NULL = os.devnull
123except AttributeError:
124 # os.devnull was added in Python 2.4, so emulate it for earlier
125 # Python versions
126 if sys.platform in ('dos','win32','win16','os2'):
127 # Use the old CP/M NUL as device name
128 DEV_NULL = 'NUL'
129 else:
130 # Standard Unix uses /dev/null
131 DEV_NULL = '/dev/null'
132
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000133### Platform specific APIs
134
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000135_libc_search = re.compile(r'(__libc_init)'
136 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000137 '(GLIBC_([0-9.]+))'
138 '|'
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000139 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
140
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000141def libc_ver(executable=sys.executable,lib='',version='',
142
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000143 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000144
Brett Cannon8ab27df2003-08-05 03:52:04 +0000145 """ Tries to determine the libc version that the file executable
146 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147
148 Returns a tuple of strings (lib,version) which default to the
149 given parameters in case the lookup fails.
150
151 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000152 libc versions add symbols to the executable and thus is probably
153 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000154
155 The file is read and scanned in chunks of chunksize bytes.
156
157 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000158 if hasattr(os.path, 'realpath'):
159 # Python 2.2 introduced os.path.realpath(); it is used
160 # here to work around problems with Cygwin not being
161 # able to open symlinks for reading
162 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000163 f = open(executable,'rb')
164 binary = f.read(chunksize)
165 pos = 0
166 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000167 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000168 if not m:
169 binary = f.read(chunksize)
170 if not binary:
171 break
172 pos = 0
173 continue
174 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
175 if libcinit and not lib:
176 lib = 'libc'
177 elif glibc:
178 if lib != 'glibc':
179 lib = 'glibc'
180 version = glibcversion
181 elif glibcversion > version:
182 version = glibcversion
183 elif so:
184 if lib != 'glibc':
185 lib = 'libc'
186 if soversion > version:
187 version = soversion
188 if threads and version[-len(threads):] != threads:
189 version = version + threads
190 pos = m.end()
191 f.close()
192 return lib,version
193
194def _dist_try_harder(distname,version,id):
195
Tim Peters0eadaac2003-04-24 16:02:54 +0000196 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000197 information in case the default method fails.
198
199 Currently supports older SuSE Linux, Caldera OpenLinux and
200 Slackware Linux distributions.
201
202 """
203 if os.path.exists('/var/adm/inst-log/info'):
204 # SuSE Linux stores distribution information in that file
205 info = open('/var/adm/inst-log/info').readlines()
206 distname = 'SuSE'
207 for line in info:
208 tv = string.split(line)
209 if len(tv) == 2:
210 tag,value = tv
211 else:
212 continue
213 if tag == 'MIN_DIST_VERSION':
214 version = string.strip(value)
215 elif tag == 'DIST_IDENT':
216 values = string.split(value,'-')
217 id = values[2]
218 return distname,version,id
219
220 if os.path.exists('/etc/.installed'):
221 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
222 info = open('/etc/.installed').readlines()
223 for line in info:
224 pkg = string.split(line,'-')
225 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
226 # XXX does Caldera support non Intel platforms ? If yes,
227 # where can we find the needed id ?
228 return 'OpenLinux',pkg[1],id
229
230 if os.path.isdir('/usr/lib/setup'):
231 # Check for slackware verson tag file (thanks to Greg Andruk)
232 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000233 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000234 if verfiles[n][:14] != 'slack-version-':
235 del verfiles[n]
236 if verfiles:
237 verfiles.sort()
238 distname = 'slackware'
239 version = verfiles[-1][14:]
240 return distname,version,id
241
242 return distname,version,id
243
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000244_release_filename = re.compile(r'(\w+)[-_](release|version)')
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000245_lsb_release_version = re.compile(r'(.+)'
246 ' release '
247 '([\d.]+)'
248 '[^(]*(?:\((.+)\))?')
249_release_version = re.compile(r'([^0-9]+)'
250 '(?: release )?'
251 '([\d.]+)'
252 '[^(]*(?:\((.+)\))?')
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000253
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000254# See also http://www.novell.com/coolsolutions/feature/11251.html
Tim Petersf733abb2007-01-30 03:03:46 +0000255# and http://linuxmafia.com/faq/Admin/release-files.html
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000256# and http://data.linux-ntfs.org/rpm/whichrpm
257# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000258
Marc-André Lemburg50967bd2008-03-08 10:01:43 +0000259_supported_dists = (
260 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
261 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
262 'UnitedLinux', 'turbolinux')
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000263
264def _parse_release_file(firstline):
Tim Petersf733abb2007-01-30 03:03:46 +0000265
Benjamin Petersona43f34c2010-01-25 03:31:13 +0000266 # Default to empty 'version' and 'id' strings. Both defaults are used
267 # when 'firstline' is empty. 'id' defaults to empty when an id can not
268 # be deduced.
269 version = ''
270 id = ''
271
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000272 # Parse the first line
273 m = _lsb_release_version.match(firstline)
274 if m is not None:
275 # LSB format: "distro release x.x (codename)"
276 return tuple(m.groups())
277
278 # Pre-LSB format: "distro x.x (codename)"
279 m = _release_version.match(firstline)
280 if m is not None:
281 return tuple(m.groups())
282
283 # Unkown format... take the first two words
284 l = string.split(string.strip(firstline))
285 if l:
286 version = l[0]
287 if len(l) > 1:
288 id = l[1]
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000289 return '', version, id
290
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000291def linux_distribution(distname='', version='', id='',
292
293 supported_dists=_supported_dists,
294 full_distribution_name=1):
295
296 """ Tries to determine the name of the Linux OS distribution name.
297
298 The function first looks for a distribution release file in
299 /etc and then reverts to _dist_try_harder() in case no
300 suitable files are found.
301
302 supported_dists may be given to define the set of Linux
303 distributions to look for. It defaults to a list of currently
304 supported Linux distributions identified by their release file
305 name.
306
307 If full_distribution_name is true (default), the full
308 distribution read from the OS is returned. Otherwise the short
309 name taken from supported_dists is used.
310
311 Returns a tuple (distname,version,id) which default to the
312 args given as parameters.
313
314 """
315 try:
316 etc = os.listdir('/etc')
317 except os.error:
318 # Probably not a Unix system
319 return distname,version,id
320 etc.sort()
321 for file in etc:
322 m = _release_filename.match(file)
323 if m is not None:
324 _distname,dummy = m.groups()
325 if _distname in supported_dists:
326 distname = _distname
327 break
328 else:
329 return _dist_try_harder(distname,version,id)
Tim Petersf733abb2007-01-30 03:03:46 +0000330
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000331 # Read the first line
332 f = open('/etc/'+file, 'r')
333 firstline = f.readline()
334 f.close()
335 _distname, _version, _id = _parse_release_file(firstline)
336
337 if _distname and full_distribution_name:
338 distname = _distname
339 if _version:
340 version = _version
341 if _id:
342 id = _id
343 return distname, version, id
344
345# To maintain backwards compatibility:
Tim Petersf733abb2007-01-30 03:03:46 +0000346
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000347def dist(distname='',version='',id='',
348
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000349 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000350
Brett Cannon8ab27df2003-08-05 03:52:04 +0000351 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000352
353 The function first looks for a distribution release file in
354 /etc and then reverts to _dist_try_harder() in case no
355 suitable files are found.
356
Brett Cannon8ab27df2003-08-05 03:52:04 +0000357 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000358 args given as parameters.
359
360 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000361 return linux_distribution(distname, version, id,
362 supported_dists=supported_dists,
363 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000364
365class _popen:
366
367 """ Fairly portable (alternative) popen implementation.
368
369 This is mostly needed in case os.popen() is not available, or
370 doesn't work as advertised, e.g. in Win9X GUI programs like
371 PythonWin or IDLE.
372
373 Writing to the pipe is currently not supported.
374
375 """
376 tmpfile = ''
377 pipe = None
378 bufsize = None
379 mode = 'r'
380
381 def __init__(self,cmd,mode='r',bufsize=None):
382
383 if mode != 'r':
384 raise ValueError,'popen()-emulation only supports read mode'
385 import tempfile
386 self.tmpfile = tmpfile = tempfile.mktemp()
387 os.system(cmd + ' > %s' % tmpfile)
388 self.pipe = open(tmpfile,'rb')
389 self.bufsize = bufsize
390 self.mode = mode
391
392 def read(self):
393
394 return self.pipe.read()
395
396 def readlines(self):
397
398 if self.bufsize is not None:
399 return self.pipe.readlines()
400
401 def close(self,
402
403 remove=os.unlink,error=os.error):
404
405 if self.pipe:
406 rc = self.pipe.close()
407 else:
408 rc = 255
409 if self.tmpfile:
410 try:
411 remove(self.tmpfile)
412 except error:
413 pass
414 return rc
415
416 # Alias
417 __del__ = close
418
419def popen(cmd, mode='r', bufsize=None):
420
421 """ Portable popen() interface.
422 """
423 # Find a working popen implementation preferring win32pipe.popen
424 # over os.popen over _popen
425 popen = None
426 if os.environ.get('OS','') == 'Windows_NT':
427 # On NT win32pipe should work; on Win9x it hangs due to bugs
428 # in the MS C lib (see MS KnowledgeBase article Q150956)
429 try:
430 import win32pipe
431 except ImportError:
432 pass
433 else:
434 popen = win32pipe.popen
435 if popen is None:
436 if hasattr(os,'popen'):
437 popen = os.popen
438 # Check whether it works... it doesn't in GUI programs
439 # on Windows platforms
440 if sys.platform == 'win32': # XXX Others too ?
441 try:
442 popen('')
443 except os.error:
444 popen = _popen
445 else:
446 popen = _popen
447 if bufsize is None:
448 return popen(cmd,mode)
449 else:
450 return popen(cmd,mode,bufsize)
451
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000452def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000453
Brett Cannon8ab27df2003-08-05 03:52:04 +0000454 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000455 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456 """
457 l = string.split(version,'.')
458 if build:
459 l.append(build)
460 try:
461 ints = map(int,l)
462 except ValueError:
463 strings = l
464 else:
465 strings = map(str,ints)
466 version = string.join(strings[:3],'.')
467 return version
468
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000469_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
470 '.*'
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000471 '\[.* ([\d.]+)\])')
472
473# Examples of VER command output:
474#
475# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
476# Windows XP: Microsoft Windows XP [Version 5.1.2600]
477# Windows Vista: Microsoft Windows [Version 6.0.6002]
478#
479# Note that the "Version" string gets localized on different
480# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000481
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000482def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000483
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000484 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485
486 """ Tries to figure out the OS version used and returns
487 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000488
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000489 It uses the "ver" shell command for this which is known
490 to exists on Windows, DOS and OS/2. XXX Others too ?
491
492 In case this fails, the given parameters are used as
493 defaults.
494
495 """
496 if sys.platform not in supported_platforms:
497 return system,release,version
498
499 # Try some common cmd strings
500 for cmd in ('ver','command /c ver','cmd /c ver'):
501 try:
502 pipe = popen(cmd)
503 info = pipe.read()
504 if pipe.close():
505 raise os.error,'command failed'
506 # XXX How can I supress shell errors from being written
507 # to stderr ?
508 except os.error,why:
509 #print 'Command %s failed: %s' % (cmd,why)
510 continue
511 except IOError,why:
512 #print 'Command %s failed: %s' % (cmd,why)
513 continue
514 else:
515 break
516 else:
517 return system,release,version
518
519 # Parse the output
520 info = string.strip(info)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000521 m = _ver_output.match(info)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000522 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000523 system,release,version = m.groups()
524 # Strip trailing dots from version and release
525 if release[-1] == '.':
526 release = release[:-1]
527 if version[-1] == '.':
528 version = version[:-1]
529 # Normalize the version and build strings (eliminating additional
530 # zeros)
531 version = _norm_version(version)
532 return system,release,version
533
534def _win32_getvalue(key,name,default=''):
535
536 """ Read a value for name from the registry key.
537
538 In case this fails, default is returned.
539
540 """
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000541 try:
542 # Use win32api if available
543 from win32api import RegQueryValueEx
544 except ImportError:
545 # On Python 2.0 and later, emulate using _winreg
546 import _winreg
547 RegQueryValueEx = _winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548 try:
549 return RegQueryValueEx(key,name)
550 except:
551 return default
552
553def win32_ver(release='',version='',csd='',ptype=''):
554
555 """ Get additional version information from the Windows Registry
556 and return a tuple (version,csd,ptype) referring to version
557 number, CSD level and OS type (multi/single
558 processor).
559
560 As a hint: ptype returns 'Uniprocessor Free' on single
561 processor NT machines and 'Multiprocessor Free' on multi
562 processor machines. The 'Free' refers to the OS version being
563 free of debugging code. It could also state 'Checked' which
564 means the OS version uses debugging code, i.e. code that
565 checks arguments, ranges, etc. (Thomas Heller).
566
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000567 Note: this function works best with Mark Hammond's win32
568 package installed, but also on Python 2.3 and later. It
569 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000570
571 """
572 # XXX Is there any way to find out the processor type on WinXX ?
573 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000574 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000575 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000576 #
577 # The mappings between reg. values and release names can be found
578 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000579
580 # Import the needed APIs
581 try:
582 import win32api
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000583 from win32api import RegQueryValueEx, RegOpenKeyEx, \
584 RegCloseKey, GetVersionEx
585 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
586 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000587 except ImportError:
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000588 # Emulate the win32api module using Python APIs
589 try:
590 sys.getwindowsversion
591 except AttributeError:
592 # No emulation possible, so return the defaults...
593 return release,version,csd,ptype
594 else:
595 # Emulation using _winreg (added in Python 2.0) and
596 # sys.getwindowsversion() (added in Python 2.3)
597 import _winreg
598 GetVersionEx = sys.getwindowsversion
599 RegQueryValueEx = _winreg.QueryValueEx
600 RegOpenKeyEx = _winreg.OpenKeyEx
601 RegCloseKey = _winreg.CloseKey
602 HKEY_LOCAL_MACHINE = _winreg.HKEY_LOCAL_MACHINE
603 VER_PLATFORM_WIN32_WINDOWS = 1
604 VER_PLATFORM_WIN32_NT = 2
605 VER_NT_WORKSTATION = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606
607 # Find out the registry key and some general version infos
608 maj,min,buildno,plat,csd = GetVersionEx()
609 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
610 if csd[:13] == 'Service Pack ':
611 csd = 'SP' + csd[13:]
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000612
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000613 if plat == VER_PLATFORM_WIN32_WINDOWS:
614 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
615 # Try to guess the release name
616 if maj == 4:
617 if min == 0:
618 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000619 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000620 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000621 elif min == 90:
622 release = 'Me'
623 else:
624 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000625 elif maj == 5:
626 release = '2000'
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000627
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000628 elif plat == VER_PLATFORM_WIN32_NT:
629 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
630 if maj <= 4:
631 release = 'NT'
632 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000633 if min == 0:
634 release = '2000'
635 elif min == 1:
636 release = 'XP'
637 elif min == 2:
638 release = '2003Server'
639 else:
640 release = 'post2003'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +0000641 elif maj == 6:
642 if min == 0:
643 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000644 try:
645 productType = GetVersionEx(1)[8]
646 except TypeError:
647 # sys.getwindowsversion() doesn't take any arguments, so
648 # we cannot detect 2008 Server that way.
649 # XXX Add some other means of detecting 2008 Server ?!
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +0000650 release = 'Vista'
651 else:
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000652 if productType == VER_NT_WORKSTATION:
653 release = 'Vista'
654 else:
655 release = '2008Server'
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000656 #elif min == 1:
657 # # Windows 7 release candidate uses version 6.1.7100
658 # release = '7RC'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +0000659 else:
660 release = 'post2008Server'
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000661
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000662 else:
663 if not release:
664 # E.g. Win3.1 with win32s
665 release = '%i.%i' % (maj,min)
666 return release,version,csd,ptype
667
668 # Open the registry key
669 try:
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000670 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000671 # Get a value to make sure the key exists...
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000672 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000673 except:
674 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000675
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000676 # Parse values
677 #subversion = _win32_getvalue(keyCurVer,
678 # 'SubVersionNumber',
679 # ('',1))[0]
680 #if subversion:
681 # release = release + subversion # 95a, 95b, etc.
682 build = _win32_getvalue(keyCurVer,
683 'CurrentBuildNumber',
684 ('',1))[0]
685 ptype = _win32_getvalue(keyCurVer,
686 'CurrentType',
687 (ptype,1))[0]
688
689 # Normalize version
690 version = _norm_version(version,build)
691
692 # Close key
693 RegCloseKey(keyCurVer)
694 return release,version,csd,ptype
695
696def _mac_ver_lookup(selectors,default=None):
697
698 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000699 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000700 l = []
701 append = l.append
702 for selector in selectors:
703 try:
704 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000705 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000706 append(default)
707 return l
708
709def _bcd2str(bcd):
710
711 return hex(bcd)[2:]
712
713def mac_ver(release='',versioninfo=('','',''),machine=''):
714
715 """ Get MacOS version information and return it as tuple (release,
716 versioninfo, machine) with versioninfo being a tuple (version,
717 dev_stage, non_release_version).
718
Brett Cannon8ab27df2003-08-05 03:52:04 +0000719 Entries which cannot be determined are set to the paramter values
720 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000721
722 Thanks to Mark R. Levinson for mailing documentation links and
723 code examples for this function. Documentation for the
724 gestalt() API is available online at:
725
726 http://www.rgaros.nl/gestalt/
727
728 """
729 # Check whether the version info module is available
730 try:
731 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000732 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000733 except ImportError:
734 return release,versioninfo,machine
735 # Get the infos
736 sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
737 # Decode the infos
738 if sysv:
739 major = (sysv & 0xFF00) >> 8
740 minor = (sysv & 0x00F0) >> 4
741 patch = (sysv & 0x000F)
Ronald Oussorenc27b8b82008-05-08 10:34:39 +0000742
743 if (major, minor) >= (10, 4):
744 # the 'sysv' gestald cannot return patchlevels
745 # higher than 9. Apple introduced 3 new
746 # gestalt codes in 10.4 to deal with this
747 # issue (needed because patch levels can
748 # run higher than 9, such as 10.4.11)
749 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
750 release = '%i.%i.%i' %(major, minor, patch)
751 else:
752 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000753
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000754 if sysu:
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000755 # NOTE: this block is left as documentation of the
756 # intention of this function, the 'sysu' gestalt is no
757 # longer available and there are no alternatives.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000758 major = int((sysu & 0xFF000000L) >> 24)
759 minor = (sysu & 0x00F00000) >> 20
760 bugfix = (sysu & 0x000F0000) >> 16
761 stage = (sysu & 0x0000FF00) >> 8
762 nonrel = (sysu & 0x000000FF)
763 version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
764 nonrel = _bcd2str(nonrel)
765 stage = {0x20:'development',
766 0x40:'alpha',
767 0x60:'beta',
768 0x80:'final'}.get(stage,'')
769 versioninfo = (version,stage,nonrel)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000770
771
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000772 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000773 machine = {0x1: '68k',
Ronald Oussoren749d0702006-04-17 13:37:15 +0000774 0x2: 'PowerPC',
775 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000776 return release,versioninfo,machine
777
Neal Norwitz9b924c62003-06-29 04:17:45 +0000778def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000779
780 from java.lang import System
781 try:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000782 value = System.getProperty(name)
783 if value is None:
784 return default
785 return value
786 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000787 return default
788
789def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000790
Brett Cannon8ab27df2003-08-05 03:52:04 +0000791 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000792
793 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
794 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
795 tuple (os_name,os_version,os_arch).
796
797 Values which cannot be determined are set to the defaults
798 given as parameters (which all default to '').
799
800 """
801 # Import the needed APIs
802 try:
803 import java.lang
804 except ImportError:
805 return release,vendor,vminfo,osinfo
806
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000807 vendor = _java_getprop('java.vendor', vendor)
808 release = _java_getprop('java.version', release)
809 vm_name, vm_release, vm_vendor = vminfo
810 vm_name = _java_getprop('java.vm.name', vm_name)
811 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
812 vm_release = _java_getprop('java.vm.version', vm_release)
813 vminfo = vm_name, vm_release, vm_vendor
814 os_name, os_version, os_arch = osinfo
815 os_arch = _java_getprop('java.os.arch', os_arch)
816 os_name = _java_getprop('java.os.name', os_name)
817 os_version = _java_getprop('java.os.version', os_version)
818 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000819
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000820 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821
822### System name aliasing
823
824def system_alias(system,release,version):
825
826 """ Returns (system,release,version) aliased to common
827 marketing names used for some systems.
828
829 It also does some reordering of the information in some cases
830 where it would otherwise cause confusion.
831
832 """
833 if system == 'Rhapsody':
834 # Apple's BSD derivative
835 # XXX How can we determine the marketing release number ?
836 return 'MacOS X Server',system+release,version
837
838 elif system == 'SunOS':
839 # Sun's OS
840 if release < '5':
841 # These releases use the old name SunOS
842 return system,release,version
843 # Modify release (marketing release = SunOS release - 3)
844 l = string.split(release,'.')
845 if l:
846 try:
847 major = int(l[0])
848 except ValueError:
849 pass
850 else:
851 major = major - 3
852 l[0] = str(major)
853 release = string.join(l,'.')
854 if release < '6':
855 system = 'Solaris'
856 else:
857 # XXX Whatever the new SunOS marketing name is...
858 system = 'Solaris'
859
860 elif system == 'IRIX64':
861 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
862 # is really a version and not a different platform, since 32-bit
863 # apps are also supported..
864 system = 'IRIX'
865 if version:
866 version = version + ' (64bit)'
867 else:
868 version = '64bit'
869
870 elif system in ('win32','win16'):
871 # In case one of the other tricks
872 system = 'Windows'
873
874 return system,release,version
875
876### Various internal helpers
877
878def _platform(*args):
879
880 """ Helper to format the platform string in a filename
881 compatible format e.g. "system-version-machine".
882 """
883 # Format the platform string
884 platform = string.join(
885 map(string.strip,
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000886 filter(len, args)),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000887 '-')
888
889 # Cleanup some possible filename obstacles...
890 replace = string.replace
891 platform = replace(platform,' ','_')
892 platform = replace(platform,'/','-')
893 platform = replace(platform,'\\','-')
894 platform = replace(platform,':','-')
895 platform = replace(platform,';','-')
896 platform = replace(platform,'"','-')
897 platform = replace(platform,'(','-')
898 platform = replace(platform,')','-')
899
900 # No need to report 'unknown' information...
901 platform = replace(platform,'unknown','')
902
903 # Fold '--'s and remove trailing '-'
904 while 1:
905 cleaned = replace(platform,'--','-')
906 if cleaned == platform:
907 break
908 platform = cleaned
909 while platform[-1] == '-':
910 platform = platform[:-1]
911
912 return platform
913
914def _node(default=''):
915
916 """ Helper to determine the node name of this machine.
917 """
918 try:
919 import socket
920 except ImportError:
921 # No sockets...
922 return default
923 try:
924 return socket.gethostname()
925 except socket.error:
926 # Still not working...
927 return default
928
929# os.path.abspath is new in Python 1.5.2:
930if not hasattr(os.path,'abspath'):
931
932 def _abspath(path,
933
934 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
935 normpath=os.path.normpath):
936
937 if not isabs(path):
938 path = join(getcwd(), path)
939 return normpath(path)
940
941else:
942
943 _abspath = os.path.abspath
944
945def _follow_symlinks(filepath):
946
947 """ In case filepath is a symlink, follow it until a
948 real file is reached.
949 """
950 filepath = _abspath(filepath)
951 while os.path.islink(filepath):
952 filepath = os.path.normpath(
Hirokazu Yamamoto171c4aa2008-09-04 11:15:14 +0000953 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000954 return filepath
955
956def _syscmd_uname(option,default=''):
957
958 """ Interface to the system's uname command.
959 """
960 if sys.platform in ('dos','win32','win16','os2'):
961 # XXX Others too ?
962 return default
963 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000964 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000965 except (AttributeError,os.error):
966 return default
967 output = string.strip(f.read())
968 rc = f.close()
969 if not output or rc:
970 return default
971 else:
972 return output
973
974def _syscmd_file(target,default=''):
975
976 """ Interface to the system's file command.
977
978 The function uses the -b option of the file command to have it
979 ommit the filename in its output and if possible the -L option
980 to have the command follow symlinks. It returns default in
981 case the command should fail.
982
983 """
Hirokazu Yamamotoed8c6442008-09-01 14:32:58 +0000984 if sys.platform in ('dos','win32','win16','os2'):
985 # XXX Others too ?
986 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000987 target = _follow_symlinks(target)
988 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000989 f = os.popen('file "%s" 2> %s' % (target, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000990 except (AttributeError,os.error):
991 return default
992 output = string.strip(f.read())
993 rc = f.close()
994 if not output or rc:
995 return default
996 else:
997 return output
998
999### Information about the used architecture
1000
1001# Default values for architecture; non-empty strings override the
1002# defaults given as parameters
1003_default_architecture = {
1004 'win32': ('','WindowsPE'),
1005 'win16': ('','Windows'),
1006 'dos': ('','MSDOS'),
1007}
1008
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001009_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001010
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001011def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001012
1013 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001014 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001015
Brett Cannon8ab27df2003-08-05 03:52:04 +00001016 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001017 the bit architecture and the linkage format used for the
1018 executable. Both values are returned as strings.
1019
1020 Values that cannot be determined are returned as given by the
1021 parameter presets. If bits is given as '', the sizeof(pointer)
1022 (or sizeof(long) on Python version < 1.5.2) is used as
1023 indicator for the supported pointer size.
1024
1025 The function relies on the system's "file" command to do the
1026 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001027 platforms. On some non-Unix platforms where the "file" command
1028 does not exist and the executable is set to the Python interpreter
1029 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001030
1031 """
1032 # Use the sizeof(pointer) as default number of bits if nothing
1033 # else is given as default.
1034 if not bits:
1035 import struct
1036 try:
1037 size = struct.calcsize('P')
1038 except struct.error:
1039 # Older installations can only query longs
1040 size = struct.calcsize('l')
1041 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001042
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001043 # Get data from the 'file' system command
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001044 if executable:
1045 output = _syscmd_file(executable, '')
1046 else:
1047 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001048
1049 if not output and \
1050 executable == sys.executable:
1051 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001052 # some sensible defaults then...
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001053 if _default_architecture.has_key(sys.platform):
1054 b,l = _default_architecture[sys.platform]
1055 if b:
1056 bits = b
1057 if l:
1058 linkage = l
1059 return bits,linkage
1060
1061 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001062 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +00001063
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064 if 'executable' not in fileout:
1065 # Format not supported
1066 return bits,linkage
1067
1068 # Bits
1069 if '32-bit' in fileout:
1070 bits = '32bit'
1071 elif 'N32' in fileout:
1072 # On Irix only
1073 bits = 'n32bit'
1074 elif '64-bit' in fileout:
1075 bits = '64bit'
1076
1077 # Linkage
1078 if 'ELF' in fileout:
1079 linkage = 'ELF'
1080 elif 'PE' in fileout:
1081 # E.g. Windows uses this format
1082 if 'Windows' in fileout:
1083 linkage = 'WindowsPE'
1084 else:
1085 linkage = 'PE'
1086 elif 'COFF' in fileout:
1087 linkage = 'COFF'
1088 elif 'MS-DOS' in fileout:
1089 linkage = 'MSDOS'
1090 else:
1091 # XXX the A.OUT format also falls under this class...
1092 pass
1093
1094 return bits,linkage
1095
1096### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001097
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001098_uname_cache = None
1099
1100def uname():
1101
1102 """ Fairly portable uname interface. Returns a tuple
1103 of strings (system,node,release,version,machine,processor)
1104 identifying the underlying platform.
1105
1106 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001107 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001108
1109 Entries which cannot be determined are set to ''.
1110
1111 """
1112 global _uname_cache
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001113 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001114
1115 if _uname_cache is not None:
1116 return _uname_cache
1117
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001118 processor = ''
1119
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001120 # Get some infos from the builtin os.uname API...
1121 try:
1122 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001123 except AttributeError:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001124 no_os_uname = 1
1125
1126 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1127 # Hmm, no there is either no uname or uname has returned
1128 #'unknowns'... we'll have to poke around the system then.
1129 if no_os_uname:
1130 system = sys.platform
1131 release = ''
1132 version = ''
1133 node = _node()
1134 machine = ''
1135
Marc-André Lemburgcecaa652009-07-13 21:28:33 +00001136 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001137
1138 # Try win32_ver() on win32 platforms
1139 if system == 'win32':
1140 release,version,csd,ptype = win32_ver()
1141 if release and version:
1142 use_syscmd_ver = 0
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +00001143 # Try to use the PROCESSOR_* environment variables
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001144 # available on Win XP and later; see
1145 # http://support.microsoft.com/kb/888731 and
1146 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001147 if not machine:
1148 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1149 if not processor:
1150 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001151
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001152 # Try the 'ver' system command available on some
1153 # platforms
1154 if use_syscmd_ver:
1155 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001156 # Normalize system to what win32_ver() normally returns
1157 # (_syscmd_ver() tends to return the vendor name as well)
1158 if system == 'Microsoft Windows':
1159 system = 'Windows'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +00001160 elif system == 'Microsoft' and release == 'Windows':
1161 # Under Windows Vista and Windows Server 2008,
1162 # Microsoft changed the output of the ver command. The
1163 # release is no longer printed. This causes the
1164 # system and release to be misidentified.
1165 system = 'Windows'
1166 if '6.0' == version[:3]:
1167 release = 'Vista'
1168 else:
1169 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001170
1171 # In case we still don't know anything useful, we'll try to
1172 # help ourselves
1173 if system in ('win32','win16'):
1174 if not version:
1175 if system == 'win32':
1176 version = '32bit'
1177 else:
1178 version = '16bit'
1179 system = 'Windows'
1180
1181 elif system[:4] == 'java':
1182 release,vendor,vminfo,osinfo = java_ver()
1183 system = 'Java'
1184 version = string.join(vminfo,', ')
1185 if not version:
1186 version = vendor
1187
1188 elif os.name == 'mac':
1189 release,(version,stage,nonrel),machine = mac_ver()
1190 system = 'MacOS'
1191
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001192 # System specific extensions
1193 if system == 'OpenVMS':
1194 # OpenVMS seems to have release and version mixed up
1195 if not release or release == '0':
1196 release = version
1197 version = ''
1198 # Get processor information
1199 try:
1200 import vms_lib
1201 except ImportError:
1202 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001203 else:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001204 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1205 if (cpu_number >= 128):
1206 processor = 'Alpha'
1207 else:
1208 processor = 'VAX'
1209 if not processor:
1210 # Get processor information from the uname system command
1211 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001212
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001213 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001214 if system == 'unknown':
1215 system = ''
1216 if node == 'unknown':
1217 node = ''
1218 if release == 'unknown':
1219 release = ''
1220 if version == 'unknown':
1221 version = ''
1222 if machine == 'unknown':
1223 machine = ''
1224 if processor == 'unknown':
1225 processor = ''
Sean Reifscheiderf09597c2007-09-17 20:53:21 +00001226
1227 # normalize name
1228 if system == 'Microsoft' and release == 'Windows':
1229 system = 'Windows'
1230 release = 'Vista'
1231
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001232 _uname_cache = system,node,release,version,machine,processor
1233 return _uname_cache
1234
1235### Direct interfaces to some of the uname() return values
1236
1237def system():
1238
1239 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1240
1241 An empty string is returned if the value cannot be determined.
1242
1243 """
1244 return uname()[0]
1245
1246def node():
1247
Brett Cannon8ab27df2003-08-05 03:52:04 +00001248 """ Returns the computer's network name (which may not be fully
1249 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001250
1251 An empty string is returned if the value cannot be determined.
1252
1253 """
1254 return uname()[1]
1255
1256def release():
1257
1258 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1259
1260 An empty string is returned if the value cannot be determined.
1261
1262 """
1263 return uname()[2]
1264
1265def version():
1266
1267 """ Returns the system's release version, e.g. '#3 on degas'
1268
1269 An empty string is returned if the value cannot be determined.
1270
1271 """
1272 return uname()[3]
1273
1274def machine():
1275
1276 """ Returns the machine type, e.g. 'i386'
1277
1278 An empty string is returned if the value cannot be determined.
1279
1280 """
1281 return uname()[4]
1282
1283def processor():
1284
1285 """ Returns the (true) processor name, e.g. 'amdk6'
1286
1287 An empty string is returned if the value cannot be
1288 determined. Note that many platforms do not provide this
1289 information or simply return the same value as for machine(),
1290 e.g. NetBSD does this.
1291
1292 """
1293 return uname()[5]
1294
1295### Various APIs for extracting information from sys.version
1296
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001297_sys_version_parser = re.compile(
1298 r'([\w.+]+)\s*'
1299 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1300 '\[([^\]]+)\]?')
1301
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001302_ironpython_sys_version_parser = re.compile(
1303 r'IronPython\s*'
1304 '([\d\.]+)'
1305 '(?: \(([\d\.]+)\))?'
1306 ' on (.NET [\d\.]+)')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001307
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001308_pypy_sys_version_parser = re.compile(
1309 r'([\w.+]+)\s*'
1310 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1311 '\[PyPy [^\]]+\]?')
1312
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001313_sys_version_cache = {}
1314
1315def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001316
1317 """ Returns a parsed version of Python's sys.version as tuple
Marc-André Lemburga519cfc2009-03-25 19:44:58 +00001318 (name, version, branch, revision, buildno, builddate, compiler)
1319 referring to the Python implementation name, version, branch,
1320 revision, build number, build date/time as string and the compiler
1321 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001322
1323 Note that unlike the Python sys.version, the returned value
1324 for the Python version will always include the patchlevel (it
1325 defaults to '.0').
1326
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001327 The function returns empty strings for tuple entries that
1328 cannot be determined.
1329
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001330 sys_version may be given to parse an alternative version
1331 string, e.g. if the version was read from a different Python
1332 interpreter.
1333
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001334 """
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001335 # Get the Python version
1336 if sys_version is None:
1337 sys_version = sys.version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001338
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001339 # Try the cache first
1340 result = _sys_version_cache.get(sys_version, None)
1341 if result is not None:
1342 return result
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001343
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001344 # Parse it
1345 if sys_version[:10] == 'IronPython':
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001346 # IronPython
1347 name = 'IronPython'
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001348 match = _ironpython_sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001349 if match is None:
1350 raise ValueError(
1351 'failed to parse IronPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001352 repr(sys_version))
1353 version, alt_version, compiler = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001354 buildno = ''
1355 builddate = ''
1356
1357 elif sys.platform[:4] == 'java':
1358 # Jython
1359 name = 'Jython'
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001360 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001361 if match is None:
1362 raise ValueError(
1363 'failed to parse Jython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001364 repr(sys_version))
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001365 version, buildno, builddate, buildtime, _ = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001366 compiler = sys.platform
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001367
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001368 elif "PyPy" in sys_version:
1369 # PyPy
1370 name = "PyPy"
1371 match = _pypy_sys_version_parser.match(sys_version)
1372 if match is None:
1373 raise ValueError("failed to parse PyPy sys.version: %s" %
1374 repr(sys_version))
1375 version, buildno, builddate, buildtime = match.groups()
1376 compiler = ""
1377
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001378 else:
1379 # CPython
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001380 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001381 if match is None:
1382 raise ValueError(
1383 'failed to parse CPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001384 repr(sys_version))
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001385 version, buildno, builddate, buildtime, compiler = \
1386 match.groups()
Benjamin Petersonb457b892009-03-26 18:55:48 +00001387 name = 'CPython'
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001388 builddate = builddate + ' ' + buildtime
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001389
Benjamin Petersonb457b892009-03-26 18:55:48 +00001390 if hasattr(sys, 'subversion'):
1391 # sys.subversion was added in Python 2.5
1392 _, branch, revision = sys.subversion
1393 else:
1394 branch = ''
1395 revision = ''
1396
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001397 # Add the patchlevel version if missing
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001398 l = string.split(version, '.')
1399 if len(l) == 2:
1400 l.append('0')
1401 version = string.join(l, '.')
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001402
1403 # Build and cache the result
1404 result = (name, version, branch, revision, buildno, builddate, compiler)
1405 _sys_version_cache[sys_version] = result
1406 return result
1407
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001408def python_implementation():
1409
1410 """ Returns a string identifying the Python implementation.
1411
1412 Currently, the following implementations are identified:
1413 'CPython' (C implementation of Python),
1414 'IronPython' (.NET implementation of Python),
1415 'Jython' (Java implementation of Python).
1416
1417 """
1418 return _sys_version()[0]
1419
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001420def python_version():
1421
1422 """ Returns the Python version as string 'major.minor.patchlevel'
1423
1424 Note that unlike the Python sys.version, the returned value
1425 will always include the patchlevel (it defaults to 0).
1426
1427 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001428 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001429
1430def python_version_tuple():
1431
1432 """ Returns the Python version as tuple (major, minor, patchlevel)
1433 of strings.
1434
1435 Note that unlike the Python sys.version, the returned value
1436 will always include the patchlevel (it defaults to 0).
1437
1438 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001439 return tuple(string.split(_sys_version()[1], '.'))
1440
1441def python_branch():
1442
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001443 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001444 branch.
1445
1446 For CPython this is the Subversion branch from which the
1447 Python binary was built.
1448
1449 If not available, an empty string is returned.
1450
1451 """
Tim Petersf733abb2007-01-30 03:03:46 +00001452
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001453 return _sys_version()[2]
1454
1455def python_revision():
1456
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001457 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001458 revision.
1459
1460 For CPython this is the Subversion revision from which the
1461 Python binary was built.
1462
1463 If not available, an empty string is returned.
1464
1465 """
1466 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001467
1468def python_build():
1469
1470 """ Returns a tuple (buildno, builddate) stating the Python
1471 build number and date as strings.
1472
1473 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001474 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001475
1476def python_compiler():
1477
1478 """ Returns a string identifying the compiler used for compiling
1479 Python.
1480
1481 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001482 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001483
1484### The Opus Magnum of platform strings :-)
1485
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001486_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001487
1488def platform(aliased=0, terse=0):
1489
1490 """ Returns a single string identifying the underlying platform
1491 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001492
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001493 The output is intended to be human readable rather than
1494 machine parseable. It may look different on different
1495 platforms and this is intended.
1496
1497 If "aliased" is true, the function will use aliases for
1498 various platforms that report system names which differ from
1499 their common names, e.g. SunOS will be reported as
1500 Solaris. The system_alias() function is used to implement
1501 this.
1502
1503 Setting terse to true causes the function to return only the
1504 absolute minimum information needed to identify the platform.
1505
1506 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001507 result = _platform_cache.get((aliased, terse), None)
1508 if result is not None:
1509 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001510
1511 # Get uname information and then apply platform specific cosmetics
1512 # to it...
1513 system,node,release,version,machine,processor = uname()
1514 if machine == processor:
1515 processor = ''
1516 if aliased:
1517 system,release,version = system_alias(system,release,version)
1518
1519 if system == 'Windows':
1520 # MS platforms
1521 rel,vers,csd,ptype = win32_ver(version)
1522 if terse:
1523 platform = _platform(system,release)
1524 else:
1525 platform = _platform(system,release,version,csd)
1526
1527 elif system in ('Linux',):
1528 # Linux based systems
1529 distname,distversion,distid = dist('')
1530 if distname and not terse:
1531 platform = _platform(system,release,machine,processor,
1532 'with',
1533 distname,distversion,distid)
1534 else:
1535 # If the distribution name is unknown check for libc vs. glibc
1536 libcname,libcversion = libc_ver(sys.executable)
1537 platform = _platform(system,release,machine,processor,
1538 'with',
1539 libcname+libcversion)
1540 elif system == 'Java':
1541 # Java platforms
1542 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001543 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001544 platform = _platform(system,release,version)
1545 else:
1546 platform = _platform(system,release,version,
1547 'on',
1548 os_name,os_version,os_arch)
1549
1550 elif system == 'MacOS':
1551 # MacOS platforms
1552 if terse:
1553 platform = _platform(system,release)
1554 else:
1555 platform = _platform(system,release,machine)
1556
1557 else:
1558 # Generic handler
1559 if terse:
1560 platform = _platform(system,release)
1561 else:
1562 bits,linkage = architecture(sys.executable)
1563 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001564
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001565 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001566 return platform
1567
1568### Command line interface
1569
1570if __name__ == '__main__':
1571 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001572 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001573 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1574 print platform(aliased,terse)
1575 sys.exit(0)