blob: 95a3a74815133263275796396b76d24f10774c99 [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#
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
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +000095 Copyright (c) 2000-2009, 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
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000266 # Parse the first line
267 m = _lsb_release_version.match(firstline)
268 if m is not None:
269 # LSB format: "distro release x.x (codename)"
270 return tuple(m.groups())
271
272 # Pre-LSB format: "distro x.x (codename)"
273 m = _release_version.match(firstline)
274 if m is not None:
275 return tuple(m.groups())
276
277 # Unkown format... take the first two words
278 l = string.split(string.strip(firstline))
279 if l:
280 version = l[0]
281 if len(l) > 1:
282 id = l[1]
283 else:
284 id = ''
285 return '', version, id
286
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000287def linux_distribution(distname='', version='', id='',
288
289 supported_dists=_supported_dists,
290 full_distribution_name=1):
291
292 """ Tries to determine the name of the Linux OS distribution name.
293
294 The function first looks for a distribution release file in
295 /etc and then reverts to _dist_try_harder() in case no
296 suitable files are found.
297
298 supported_dists may be given to define the set of Linux
299 distributions to look for. It defaults to a list of currently
300 supported Linux distributions identified by their release file
301 name.
302
303 If full_distribution_name is true (default), the full
304 distribution read from the OS is returned. Otherwise the short
305 name taken from supported_dists is used.
306
307 Returns a tuple (distname,version,id) which default to the
308 args given as parameters.
309
310 """
311 try:
312 etc = os.listdir('/etc')
313 except os.error:
314 # Probably not a Unix system
315 return distname,version,id
316 etc.sort()
317 for file in etc:
318 m = _release_filename.match(file)
319 if m is not None:
320 _distname,dummy = m.groups()
321 if _distname in supported_dists:
322 distname = _distname
323 break
324 else:
325 return _dist_try_harder(distname,version,id)
Tim Petersf733abb2007-01-30 03:03:46 +0000326
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000327 # Read the first line
328 f = open('/etc/'+file, 'r')
329 firstline = f.readline()
330 f.close()
331 _distname, _version, _id = _parse_release_file(firstline)
332
333 if _distname and full_distribution_name:
334 distname = _distname
335 if _version:
336 version = _version
337 if _id:
338 id = _id
339 return distname, version, id
340
341# To maintain backwards compatibility:
Tim Petersf733abb2007-01-30 03:03:46 +0000342
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000343def dist(distname='',version='',id='',
344
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000345 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000346
Brett Cannon8ab27df2003-08-05 03:52:04 +0000347 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000348
349 The function first looks for a distribution release file in
350 /etc and then reverts to _dist_try_harder() in case no
351 suitable files are found.
352
Brett Cannon8ab27df2003-08-05 03:52:04 +0000353 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000354 args given as parameters.
355
356 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000357 return linux_distribution(distname, version, id,
358 supported_dists=supported_dists,
359 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000360
361class _popen:
362
363 """ Fairly portable (alternative) popen implementation.
364
365 This is mostly needed in case os.popen() is not available, or
366 doesn't work as advertised, e.g. in Win9X GUI programs like
367 PythonWin or IDLE.
368
369 Writing to the pipe is currently not supported.
370
371 """
372 tmpfile = ''
373 pipe = None
374 bufsize = None
375 mode = 'r'
376
377 def __init__(self,cmd,mode='r',bufsize=None):
378
379 if mode != 'r':
380 raise ValueError,'popen()-emulation only supports read mode'
381 import tempfile
382 self.tmpfile = tmpfile = tempfile.mktemp()
383 os.system(cmd + ' > %s' % tmpfile)
384 self.pipe = open(tmpfile,'rb')
385 self.bufsize = bufsize
386 self.mode = mode
387
388 def read(self):
389
390 return self.pipe.read()
391
392 def readlines(self):
393
394 if self.bufsize is not None:
395 return self.pipe.readlines()
396
397 def close(self,
398
399 remove=os.unlink,error=os.error):
400
401 if self.pipe:
402 rc = self.pipe.close()
403 else:
404 rc = 255
405 if self.tmpfile:
406 try:
407 remove(self.tmpfile)
408 except error:
409 pass
410 return rc
411
412 # Alias
413 __del__ = close
414
415def popen(cmd, mode='r', bufsize=None):
416
417 """ Portable popen() interface.
418 """
419 # Find a working popen implementation preferring win32pipe.popen
420 # over os.popen over _popen
421 popen = None
422 if os.environ.get('OS','') == 'Windows_NT':
423 # On NT win32pipe should work; on Win9x it hangs due to bugs
424 # in the MS C lib (see MS KnowledgeBase article Q150956)
425 try:
426 import win32pipe
427 except ImportError:
428 pass
429 else:
430 popen = win32pipe.popen
431 if popen is None:
432 if hasattr(os,'popen'):
433 popen = os.popen
434 # Check whether it works... it doesn't in GUI programs
435 # on Windows platforms
436 if sys.platform == 'win32': # XXX Others too ?
437 try:
438 popen('')
439 except os.error:
440 popen = _popen
441 else:
442 popen = _popen
443 if bufsize is None:
444 return popen(cmd,mode)
445 else:
446 return popen(cmd,mode,bufsize)
447
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000448def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000449
Brett Cannon8ab27df2003-08-05 03:52:04 +0000450 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000451 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452 """
453 l = string.split(version,'.')
454 if build:
455 l.append(build)
456 try:
457 ints = map(int,l)
458 except ValueError:
459 strings = l
460 else:
461 strings = map(str,ints)
462 version = string.join(strings[:3],'.')
463 return version
464
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000465_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
466 '.*'
467 'Version ([\d.]+))')
468
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000469def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000470
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000471 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000472
473 """ Tries to figure out the OS version used and returns
474 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000475
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000476 It uses the "ver" shell command for this which is known
477 to exists on Windows, DOS and OS/2. XXX Others too ?
478
479 In case this fails, the given parameters are used as
480 defaults.
481
482 """
483 if sys.platform not in supported_platforms:
484 return system,release,version
485
486 # Try some common cmd strings
487 for cmd in ('ver','command /c ver','cmd /c ver'):
488 try:
489 pipe = popen(cmd)
490 info = pipe.read()
491 if pipe.close():
492 raise os.error,'command failed'
493 # XXX How can I supress shell errors from being written
494 # to stderr ?
495 except os.error,why:
496 #print 'Command %s failed: %s' % (cmd,why)
497 continue
498 except IOError,why:
499 #print 'Command %s failed: %s' % (cmd,why)
500 continue
501 else:
502 break
503 else:
504 return system,release,version
505
506 # Parse the output
507 info = string.strip(info)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000508 m = _ver_output.match(info)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000509 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000510 system,release,version = m.groups()
511 # Strip trailing dots from version and release
512 if release[-1] == '.':
513 release = release[:-1]
514 if version[-1] == '.':
515 version = version[:-1]
516 # Normalize the version and build strings (eliminating additional
517 # zeros)
518 version = _norm_version(version)
519 return system,release,version
520
521def _win32_getvalue(key,name,default=''):
522
523 """ Read a value for name from the registry key.
524
525 In case this fails, default is returned.
526
527 """
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000528 try:
529 # Use win32api if available
530 from win32api import RegQueryValueEx
531 except ImportError:
532 # On Python 2.0 and later, emulate using _winreg
533 import _winreg
534 RegQueryValueEx = _winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000535 try:
536 return RegQueryValueEx(key,name)
537 except:
538 return default
539
540def win32_ver(release='',version='',csd='',ptype=''):
541
542 """ Get additional version information from the Windows Registry
543 and return a tuple (version,csd,ptype) referring to version
544 number, CSD level and OS type (multi/single
545 processor).
546
547 As a hint: ptype returns 'Uniprocessor Free' on single
548 processor NT machines and 'Multiprocessor Free' on multi
549 processor machines. The 'Free' refers to the OS version being
550 free of debugging code. It could also state 'Checked' which
551 means the OS version uses debugging code, i.e. code that
552 checks arguments, ranges, etc. (Thomas Heller).
553
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000554 Note: this function works best with Mark Hammond's win32
555 package installed, but also on Python 2.3 and later. It
556 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000557
558 """
559 # XXX Is there any way to find out the processor type on WinXX ?
560 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000561 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000562 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000563 #
564 # The mappings between reg. values and release names can be found
565 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000566
567 # Import the needed APIs
568 try:
569 import win32api
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000570 from win32api import RegQueryValueEx, RegOpenKeyEx, \
571 RegCloseKey, GetVersionEx
572 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
573 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000574 except ImportError:
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000575 # Emulate the win32api module using Python APIs
576 try:
577 sys.getwindowsversion
578 except AttributeError:
579 # No emulation possible, so return the defaults...
580 return release,version,csd,ptype
581 else:
582 # Emulation using _winreg (added in Python 2.0) and
583 # sys.getwindowsversion() (added in Python 2.3)
584 import _winreg
585 GetVersionEx = sys.getwindowsversion
586 RegQueryValueEx = _winreg.QueryValueEx
587 RegOpenKeyEx = _winreg.OpenKeyEx
588 RegCloseKey = _winreg.CloseKey
589 HKEY_LOCAL_MACHINE = _winreg.HKEY_LOCAL_MACHINE
590 VER_PLATFORM_WIN32_WINDOWS = 1
591 VER_PLATFORM_WIN32_NT = 2
592 VER_NT_WORKSTATION = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000593
594 # Find out the registry key and some general version infos
595 maj,min,buildno,plat,csd = GetVersionEx()
596 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
597 if csd[:13] == 'Service Pack ':
598 csd = 'SP' + csd[13:]
599 if plat == VER_PLATFORM_WIN32_WINDOWS:
600 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
601 # Try to guess the release name
602 if maj == 4:
603 if min == 0:
604 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000605 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000607 elif min == 90:
608 release = 'Me'
609 else:
610 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000611 elif maj == 5:
612 release = '2000'
613 elif plat == VER_PLATFORM_WIN32_NT:
614 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
615 if maj <= 4:
616 release = 'NT'
617 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000618 if min == 0:
619 release = '2000'
620 elif min == 1:
621 release = 'XP'
622 elif min == 2:
623 release = '2003Server'
624 else:
625 release = 'post2003'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +0000626 elif maj == 6:
627 if min == 0:
628 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000629 try:
630 productType = GetVersionEx(1)[8]
631 except TypeError:
632 # sys.getwindowsversion() doesn't take any arguments, so
633 # we cannot detect 2008 Server that way.
634 # XXX Add some other means of detecting 2008 Server ?!
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +0000635 release = 'Vista'
636 else:
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000637 if productType == VER_NT_WORKSTATION:
638 release = 'Vista'
639 else:
640 release = '2008Server'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +0000641 else:
642 release = 'post2008Server'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000643 else:
644 if not release:
645 # E.g. Win3.1 with win32s
646 release = '%i.%i' % (maj,min)
647 return release,version,csd,ptype
648
649 # Open the registry key
650 try:
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000651 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652 # Get a value to make sure the key exists...
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000653 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654 except:
655 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000656
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000657 # Parse values
658 #subversion = _win32_getvalue(keyCurVer,
659 # 'SubVersionNumber',
660 # ('',1))[0]
661 #if subversion:
662 # release = release + subversion # 95a, 95b, etc.
663 build = _win32_getvalue(keyCurVer,
664 'CurrentBuildNumber',
665 ('',1))[0]
666 ptype = _win32_getvalue(keyCurVer,
667 'CurrentType',
668 (ptype,1))[0]
669
670 # Normalize version
671 version = _norm_version(version,build)
672
673 # Close key
674 RegCloseKey(keyCurVer)
675 return release,version,csd,ptype
676
677def _mac_ver_lookup(selectors,default=None):
678
679 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000680 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000681 l = []
682 append = l.append
683 for selector in selectors:
684 try:
685 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000686 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687 append(default)
688 return l
689
690def _bcd2str(bcd):
691
692 return hex(bcd)[2:]
693
694def mac_ver(release='',versioninfo=('','',''),machine=''):
695
696 """ Get MacOS version information and return it as tuple (release,
697 versioninfo, machine) with versioninfo being a tuple (version,
698 dev_stage, non_release_version).
699
Brett Cannon8ab27df2003-08-05 03:52:04 +0000700 Entries which cannot be determined are set to the paramter values
701 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702
703 Thanks to Mark R. Levinson for mailing documentation links and
704 code examples for this function. Documentation for the
705 gestalt() API is available online at:
706
707 http://www.rgaros.nl/gestalt/
708
709 """
710 # Check whether the version info module is available
711 try:
712 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000713 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000714 except ImportError:
715 return release,versioninfo,machine
716 # Get the infos
717 sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
718 # Decode the infos
719 if sysv:
720 major = (sysv & 0xFF00) >> 8
721 minor = (sysv & 0x00F0) >> 4
722 patch = (sysv & 0x000F)
Ronald Oussorenc27b8b82008-05-08 10:34:39 +0000723
724 if (major, minor) >= (10, 4):
725 # the 'sysv' gestald cannot return patchlevels
726 # higher than 9. Apple introduced 3 new
727 # gestalt codes in 10.4 to deal with this
728 # issue (needed because patch levels can
729 # run higher than 9, such as 10.4.11)
730 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
731 release = '%i.%i.%i' %(major, minor, patch)
732 else:
733 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000734
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000735 if sysu:
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000736 # NOTE: this block is left as documentation of the
737 # intention of this function, the 'sysu' gestalt is no
738 # longer available and there are no alternatives.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000739 major = int((sysu & 0xFF000000L) >> 24)
740 minor = (sysu & 0x00F00000) >> 20
741 bugfix = (sysu & 0x000F0000) >> 16
742 stage = (sysu & 0x0000FF00) >> 8
743 nonrel = (sysu & 0x000000FF)
744 version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
745 nonrel = _bcd2str(nonrel)
746 stage = {0x20:'development',
747 0x40:'alpha',
748 0x60:'beta',
749 0x80:'final'}.get(stage,'')
750 versioninfo = (version,stage,nonrel)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000751
752
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000753 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000754 machine = {0x1: '68k',
Ronald Oussoren749d0702006-04-17 13:37:15 +0000755 0x2: 'PowerPC',
756 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000757 return release,versioninfo,machine
758
Neal Norwitz9b924c62003-06-29 04:17:45 +0000759def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000760
761 from java.lang import System
762 try:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000763 value = System.getProperty(name)
764 if value is None:
765 return default
766 return value
767 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000768 return default
769
770def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000771
Brett Cannon8ab27df2003-08-05 03:52:04 +0000772 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000773
774 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
775 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
776 tuple (os_name,os_version,os_arch).
777
778 Values which cannot be determined are set to the defaults
779 given as parameters (which all default to '').
780
781 """
782 # Import the needed APIs
783 try:
784 import java.lang
785 except ImportError:
786 return release,vendor,vminfo,osinfo
787
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000788 vendor = _java_getprop('java.vendor', vendor)
789 release = _java_getprop('java.version', release)
790 vm_name, vm_release, vm_vendor = vminfo
791 vm_name = _java_getprop('java.vm.name', vm_name)
792 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
793 vm_release = _java_getprop('java.vm.version', vm_release)
794 vminfo = vm_name, vm_release, vm_vendor
795 os_name, os_version, os_arch = osinfo
796 os_arch = _java_getprop('java.os.arch', os_arch)
797 os_name = _java_getprop('java.os.name', os_name)
798 os_version = _java_getprop('java.os.version', os_version)
799 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000800
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000801 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000802
803### System name aliasing
804
805def system_alias(system,release,version):
806
807 """ Returns (system,release,version) aliased to common
808 marketing names used for some systems.
809
810 It also does some reordering of the information in some cases
811 where it would otherwise cause confusion.
812
813 """
814 if system == 'Rhapsody':
815 # Apple's BSD derivative
816 # XXX How can we determine the marketing release number ?
817 return 'MacOS X Server',system+release,version
818
819 elif system == 'SunOS':
820 # Sun's OS
821 if release < '5':
822 # These releases use the old name SunOS
823 return system,release,version
824 # Modify release (marketing release = SunOS release - 3)
825 l = string.split(release,'.')
826 if l:
827 try:
828 major = int(l[0])
829 except ValueError:
830 pass
831 else:
832 major = major - 3
833 l[0] = str(major)
834 release = string.join(l,'.')
835 if release < '6':
836 system = 'Solaris'
837 else:
838 # XXX Whatever the new SunOS marketing name is...
839 system = 'Solaris'
840
841 elif system == 'IRIX64':
842 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
843 # is really a version and not a different platform, since 32-bit
844 # apps are also supported..
845 system = 'IRIX'
846 if version:
847 version = version + ' (64bit)'
848 else:
849 version = '64bit'
850
851 elif system in ('win32','win16'):
852 # In case one of the other tricks
853 system = 'Windows'
854
855 return system,release,version
856
857### Various internal helpers
858
859def _platform(*args):
860
861 """ Helper to format the platform string in a filename
862 compatible format e.g. "system-version-machine".
863 """
864 # Format the platform string
865 platform = string.join(
866 map(string.strip,
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000867 filter(len, args)),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000868 '-')
869
870 # Cleanup some possible filename obstacles...
871 replace = string.replace
872 platform = replace(platform,' ','_')
873 platform = replace(platform,'/','-')
874 platform = replace(platform,'\\','-')
875 platform = replace(platform,':','-')
876 platform = replace(platform,';','-')
877 platform = replace(platform,'"','-')
878 platform = replace(platform,'(','-')
879 platform = replace(platform,')','-')
880
881 # No need to report 'unknown' information...
882 platform = replace(platform,'unknown','')
883
884 # Fold '--'s and remove trailing '-'
885 while 1:
886 cleaned = replace(platform,'--','-')
887 if cleaned == platform:
888 break
889 platform = cleaned
890 while platform[-1] == '-':
891 platform = platform[:-1]
892
893 return platform
894
895def _node(default=''):
896
897 """ Helper to determine the node name of this machine.
898 """
899 try:
900 import socket
901 except ImportError:
902 # No sockets...
903 return default
904 try:
905 return socket.gethostname()
906 except socket.error:
907 # Still not working...
908 return default
909
910# os.path.abspath is new in Python 1.5.2:
911if not hasattr(os.path,'abspath'):
912
913 def _abspath(path,
914
915 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
916 normpath=os.path.normpath):
917
918 if not isabs(path):
919 path = join(getcwd(), path)
920 return normpath(path)
921
922else:
923
924 _abspath = os.path.abspath
925
926def _follow_symlinks(filepath):
927
928 """ In case filepath is a symlink, follow it until a
929 real file is reached.
930 """
931 filepath = _abspath(filepath)
932 while os.path.islink(filepath):
933 filepath = os.path.normpath(
Hirokazu Yamamoto171c4aa2008-09-04 11:15:14 +0000934 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000935 return filepath
936
937def _syscmd_uname(option,default=''):
938
939 """ Interface to the system's uname command.
940 """
941 if sys.platform in ('dos','win32','win16','os2'):
942 # XXX Others too ?
943 return default
944 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000945 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000946 except (AttributeError,os.error):
947 return default
948 output = string.strip(f.read())
949 rc = f.close()
950 if not output or rc:
951 return default
952 else:
953 return output
954
955def _syscmd_file(target,default=''):
956
957 """ Interface to the system's file command.
958
959 The function uses the -b option of the file command to have it
960 ommit the filename in its output and if possible the -L option
961 to have the command follow symlinks. It returns default in
962 case the command should fail.
963
964 """
Hirokazu Yamamotoed8c6442008-09-01 14:32:58 +0000965 if sys.platform in ('dos','win32','win16','os2'):
966 # XXX Others too ?
967 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000968 target = _follow_symlinks(target)
969 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000970 f = os.popen('file "%s" 2> %s' % (target, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000971 except (AttributeError,os.error):
972 return default
973 output = string.strip(f.read())
974 rc = f.close()
975 if not output or rc:
976 return default
977 else:
978 return output
979
980### Information about the used architecture
981
982# Default values for architecture; non-empty strings override the
983# defaults given as parameters
984_default_architecture = {
985 'win32': ('','WindowsPE'),
986 'win16': ('','Windows'),
987 'dos': ('','MSDOS'),
988}
989
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000990_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000991
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000992def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000993
994 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000995 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000996
Brett Cannon8ab27df2003-08-05 03:52:04 +0000997 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000998 the bit architecture and the linkage format used for the
999 executable. Both values are returned as strings.
1000
1001 Values that cannot be determined are returned as given by the
1002 parameter presets. If bits is given as '', the sizeof(pointer)
1003 (or sizeof(long) on Python version < 1.5.2) is used as
1004 indicator for the supported pointer size.
1005
1006 The function relies on the system's "file" command to do the
1007 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001008 platforms. On some non-Unix platforms where the "file" command
1009 does not exist and the executable is set to the Python interpreter
1010 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001011
1012 """
1013 # Use the sizeof(pointer) as default number of bits if nothing
1014 # else is given as default.
1015 if not bits:
1016 import struct
1017 try:
1018 size = struct.calcsize('P')
1019 except struct.error:
1020 # Older installations can only query longs
1021 size = struct.calcsize('l')
1022 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001023
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001024 # Get data from the 'file' system command
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001025 if executable:
1026 output = _syscmd_file(executable, '')
1027 else:
1028 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001029
1030 if not output and \
1031 executable == sys.executable:
1032 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001033 # some sensible defaults then...
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001034 if _default_architecture.has_key(sys.platform):
1035 b,l = _default_architecture[sys.platform]
1036 if b:
1037 bits = b
1038 if l:
1039 linkage = l
1040 return bits,linkage
1041
1042 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001043 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +00001044
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001045 if 'executable' not in fileout:
1046 # Format not supported
1047 return bits,linkage
1048
1049 # Bits
1050 if '32-bit' in fileout:
1051 bits = '32bit'
1052 elif 'N32' in fileout:
1053 # On Irix only
1054 bits = 'n32bit'
1055 elif '64-bit' in fileout:
1056 bits = '64bit'
1057
1058 # Linkage
1059 if 'ELF' in fileout:
1060 linkage = 'ELF'
1061 elif 'PE' in fileout:
1062 # E.g. Windows uses this format
1063 if 'Windows' in fileout:
1064 linkage = 'WindowsPE'
1065 else:
1066 linkage = 'PE'
1067 elif 'COFF' in fileout:
1068 linkage = 'COFF'
1069 elif 'MS-DOS' in fileout:
1070 linkage = 'MSDOS'
1071 else:
1072 # XXX the A.OUT format also falls under this class...
1073 pass
1074
1075 return bits,linkage
1076
1077### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001078
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001079_uname_cache = None
1080
1081def uname():
1082
1083 """ Fairly portable uname interface. Returns a tuple
1084 of strings (system,node,release,version,machine,processor)
1085 identifying the underlying platform.
1086
1087 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001088 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001089
1090 Entries which cannot be determined are set to ''.
1091
1092 """
1093 global _uname_cache
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001094 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001095
1096 if _uname_cache is not None:
1097 return _uname_cache
1098
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001099 processor = ''
1100
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001101 # Get some infos from the builtin os.uname API...
1102 try:
1103 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001104 except AttributeError:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001105 no_os_uname = 1
1106
1107 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1108 # Hmm, no there is either no uname or uname has returned
1109 #'unknowns'... we'll have to poke around the system then.
1110 if no_os_uname:
1111 system = sys.platform
1112 release = ''
1113 version = ''
1114 node = _node()
1115 machine = ''
1116
1117 use_syscmd_ver = 01
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001118
1119 # Try win32_ver() on win32 platforms
1120 if system == 'win32':
1121 release,version,csd,ptype = win32_ver()
1122 if release and version:
1123 use_syscmd_ver = 0
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +00001124 # Try to use the PROCESSOR_* environment variables
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001125 # available on Win XP and later; see
1126 # http://support.microsoft.com/kb/888731 and
1127 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001128 if not machine:
1129 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1130 if not processor:
1131 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001132
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001133 # Try the 'ver' system command available on some
1134 # platforms
1135 if use_syscmd_ver:
1136 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001137 # Normalize system to what win32_ver() normally returns
1138 # (_syscmd_ver() tends to return the vendor name as well)
1139 if system == 'Microsoft Windows':
1140 system = 'Windows'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +00001141 elif system == 'Microsoft' and release == 'Windows':
1142 # Under Windows Vista and Windows Server 2008,
1143 # Microsoft changed the output of the ver command. The
1144 # release is no longer printed. This causes the
1145 # system and release to be misidentified.
1146 system = 'Windows'
1147 if '6.0' == version[:3]:
1148 release = 'Vista'
1149 else:
1150 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001151
1152 # In case we still don't know anything useful, we'll try to
1153 # help ourselves
1154 if system in ('win32','win16'):
1155 if not version:
1156 if system == 'win32':
1157 version = '32bit'
1158 else:
1159 version = '16bit'
1160 system = 'Windows'
1161
1162 elif system[:4] == 'java':
1163 release,vendor,vminfo,osinfo = java_ver()
1164 system = 'Java'
1165 version = string.join(vminfo,', ')
1166 if not version:
1167 version = vendor
1168
1169 elif os.name == 'mac':
1170 release,(version,stage,nonrel),machine = mac_ver()
1171 system = 'MacOS'
1172
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001173 # System specific extensions
1174 if system == 'OpenVMS':
1175 # OpenVMS seems to have release and version mixed up
1176 if not release or release == '0':
1177 release = version
1178 version = ''
1179 # Get processor information
1180 try:
1181 import vms_lib
1182 except ImportError:
1183 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001184 else:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001185 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1186 if (cpu_number >= 128):
1187 processor = 'Alpha'
1188 else:
1189 processor = 'VAX'
1190 if not processor:
1191 # Get processor information from the uname system command
1192 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001193
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001194 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001195 if system == 'unknown':
1196 system = ''
1197 if node == 'unknown':
1198 node = ''
1199 if release == 'unknown':
1200 release = ''
1201 if version == 'unknown':
1202 version = ''
1203 if machine == 'unknown':
1204 machine = ''
1205 if processor == 'unknown':
1206 processor = ''
Sean Reifscheiderf09597c2007-09-17 20:53:21 +00001207
1208 # normalize name
1209 if system == 'Microsoft' and release == 'Windows':
1210 system = 'Windows'
1211 release = 'Vista'
1212
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001213 _uname_cache = system,node,release,version,machine,processor
1214 return _uname_cache
1215
1216### Direct interfaces to some of the uname() return values
1217
1218def system():
1219
1220 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1221
1222 An empty string is returned if the value cannot be determined.
1223
1224 """
1225 return uname()[0]
1226
1227def node():
1228
Brett Cannon8ab27df2003-08-05 03:52:04 +00001229 """ Returns the computer's network name (which may not be fully
1230 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001231
1232 An empty string is returned if the value cannot be determined.
1233
1234 """
1235 return uname()[1]
1236
1237def release():
1238
1239 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1240
1241 An empty string is returned if the value cannot be determined.
1242
1243 """
1244 return uname()[2]
1245
1246def version():
1247
1248 """ Returns the system's release version, e.g. '#3 on degas'
1249
1250 An empty string is returned if the value cannot be determined.
1251
1252 """
1253 return uname()[3]
1254
1255def machine():
1256
1257 """ Returns the machine type, e.g. 'i386'
1258
1259 An empty string is returned if the value cannot be determined.
1260
1261 """
1262 return uname()[4]
1263
1264def processor():
1265
1266 """ Returns the (true) processor name, e.g. 'amdk6'
1267
1268 An empty string is returned if the value cannot be
1269 determined. Note that many platforms do not provide this
1270 information or simply return the same value as for machine(),
1271 e.g. NetBSD does this.
1272
1273 """
1274 return uname()[5]
1275
1276### Various APIs for extracting information from sys.version
1277
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001278_sys_version_parser = re.compile(
1279 r'([\w.+]+)\s*'
1280 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1281 '\[([^\]]+)\]?')
1282
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001283_ironpython_sys_version_parser = re.compile(
1284 r'IronPython\s*'
1285 '([\d\.]+)'
1286 '(?: \(([\d\.]+)\))?'
1287 ' on (.NET [\d\.]+)')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001288
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001289_pypy_sys_version_parser = re.compile(
1290 r'([\w.+]+)\s*'
1291 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1292 '\[PyPy [^\]]+\]?')
1293
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001294_sys_version_cache = {}
1295
1296def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001297
1298 """ Returns a parsed version of Python's sys.version as tuple
Marc-André Lemburga519cfc2009-03-25 19:44:58 +00001299 (name, version, branch, revision, buildno, builddate, compiler)
1300 referring to the Python implementation name, version, branch,
1301 revision, build number, build date/time as string and the compiler
1302 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001303
1304 Note that unlike the Python sys.version, the returned value
1305 for the Python version will always include the patchlevel (it
1306 defaults to '.0').
1307
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001308 The function returns empty strings for tuple entries that
1309 cannot be determined.
1310
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001311 sys_version may be given to parse an alternative version
1312 string, e.g. if the version was read from a different Python
1313 interpreter.
1314
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001315 """
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001316 # Get the Python version
1317 if sys_version is None:
1318 sys_version = sys.version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001319
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001320 # Try the cache first
1321 result = _sys_version_cache.get(sys_version, None)
1322 if result is not None:
1323 return result
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001324
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001325 # Parse it
1326 if sys_version[:10] == 'IronPython':
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001327 # IronPython
1328 name = 'IronPython'
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001329 match = _ironpython_sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001330 if match is None:
1331 raise ValueError(
1332 'failed to parse IronPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001333 repr(sys_version))
1334 version, alt_version, compiler = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001335 buildno = ''
1336 builddate = ''
1337
1338 elif sys.platform[:4] == 'java':
1339 # Jython
1340 name = 'Jython'
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001341 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001342 if match is None:
1343 raise ValueError(
1344 'failed to parse Jython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001345 repr(sys_version))
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001346 version, buildno, builddate, buildtime, _ = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001347 compiler = sys.platform
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001348
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001349 elif "PyPy" in sys_version:
1350 # PyPy
1351 name = "PyPy"
1352 match = _pypy_sys_version_parser.match(sys_version)
1353 if match is None:
1354 raise ValueError("failed to parse PyPy sys.version: %s" %
1355 repr(sys_version))
1356 version, buildno, builddate, buildtime = match.groups()
1357 compiler = ""
1358
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001359 else:
1360 # CPython
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001361 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001362 if match is None:
1363 raise ValueError(
1364 'failed to parse CPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001365 repr(sys_version))
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001366 version, buildno, builddate, buildtime, compiler = \
1367 match.groups()
Benjamin Petersonb457b892009-03-26 18:55:48 +00001368 name = 'CPython'
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001369 builddate = builddate + ' ' + buildtime
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001370
Benjamin Petersonb457b892009-03-26 18:55:48 +00001371 if hasattr(sys, 'subversion'):
1372 # sys.subversion was added in Python 2.5
1373 _, branch, revision = sys.subversion
1374 else:
1375 branch = ''
1376 revision = ''
1377
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001378 # Add the patchlevel version if missing
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001379 l = string.split(version, '.')
1380 if len(l) == 2:
1381 l.append('0')
1382 version = string.join(l, '.')
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001383
1384 # Build and cache the result
1385 result = (name, version, branch, revision, buildno, builddate, compiler)
1386 _sys_version_cache[sys_version] = result
1387 return result
1388
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001389def python_implementation():
1390
1391 """ Returns a string identifying the Python implementation.
1392
1393 Currently, the following implementations are identified:
1394 'CPython' (C implementation of Python),
1395 'IronPython' (.NET implementation of Python),
1396 'Jython' (Java implementation of Python).
1397
1398 """
1399 return _sys_version()[0]
1400
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401def python_version():
1402
1403 """ Returns the Python version as string 'major.minor.patchlevel'
1404
1405 Note that unlike the Python sys.version, the returned value
1406 will always include the patchlevel (it defaults to 0).
1407
1408 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001409 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001410
1411def python_version_tuple():
1412
1413 """ Returns the Python version as tuple (major, minor, patchlevel)
1414 of strings.
1415
1416 Note that unlike the Python sys.version, the returned value
1417 will always include the patchlevel (it defaults to 0).
1418
1419 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001420 return tuple(string.split(_sys_version()[1], '.'))
1421
1422def python_branch():
1423
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001424 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001425 branch.
1426
1427 For CPython this is the Subversion branch from which the
1428 Python binary was built.
1429
1430 If not available, an empty string is returned.
1431
1432 """
Tim Petersf733abb2007-01-30 03:03:46 +00001433
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001434 return _sys_version()[2]
1435
1436def python_revision():
1437
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001438 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001439 revision.
1440
1441 For CPython this is the Subversion revision from which the
1442 Python binary was built.
1443
1444 If not available, an empty string is returned.
1445
1446 """
1447 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001448
1449def python_build():
1450
1451 """ Returns a tuple (buildno, builddate) stating the Python
1452 build number and date as strings.
1453
1454 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001455 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001456
1457def python_compiler():
1458
1459 """ Returns a string identifying the compiler used for compiling
1460 Python.
1461
1462 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001463 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001464
1465### The Opus Magnum of platform strings :-)
1466
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001467_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001468
1469def platform(aliased=0, terse=0):
1470
1471 """ Returns a single string identifying the underlying platform
1472 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001473
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001474 The output is intended to be human readable rather than
1475 machine parseable. It may look different on different
1476 platforms and this is intended.
1477
1478 If "aliased" is true, the function will use aliases for
1479 various platforms that report system names which differ from
1480 their common names, e.g. SunOS will be reported as
1481 Solaris. The system_alias() function is used to implement
1482 this.
1483
1484 Setting terse to true causes the function to return only the
1485 absolute minimum information needed to identify the platform.
1486
1487 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001488 result = _platform_cache.get((aliased, terse), None)
1489 if result is not None:
1490 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001491
1492 # Get uname information and then apply platform specific cosmetics
1493 # to it...
1494 system,node,release,version,machine,processor = uname()
1495 if machine == processor:
1496 processor = ''
1497 if aliased:
1498 system,release,version = system_alias(system,release,version)
1499
1500 if system == 'Windows':
1501 # MS platforms
1502 rel,vers,csd,ptype = win32_ver(version)
1503 if terse:
1504 platform = _platform(system,release)
1505 else:
1506 platform = _platform(system,release,version,csd)
1507
1508 elif system in ('Linux',):
1509 # Linux based systems
1510 distname,distversion,distid = dist('')
1511 if distname and not terse:
1512 platform = _platform(system,release,machine,processor,
1513 'with',
1514 distname,distversion,distid)
1515 else:
1516 # If the distribution name is unknown check for libc vs. glibc
1517 libcname,libcversion = libc_ver(sys.executable)
1518 platform = _platform(system,release,machine,processor,
1519 'with',
1520 libcname+libcversion)
1521 elif system == 'Java':
1522 # Java platforms
1523 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001524 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001525 platform = _platform(system,release,version)
1526 else:
1527 platform = _platform(system,release,version,
1528 'on',
1529 os_name,os_version,os_arch)
1530
1531 elif system == 'MacOS':
1532 # MacOS platforms
1533 if terse:
1534 platform = _platform(system,release)
1535 else:
1536 platform = _platform(system,release,machine)
1537
1538 else:
1539 # Generic handler
1540 if terse:
1541 platform = _platform(system,release)
1542 else:
1543 bits,linkage = architecture(sys.executable)
1544 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001545
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001546 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001547 return platform
1548
1549### Command line interface
1550
1551if __name__ == '__main__':
1552 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001553 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001554 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1555 print platform(aliased,terse)
1556 sys.exit(0)