blob: b525695cb981525c11b43c478e0cfcb3a333a3aa [file] [log] [blame]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001#!/usr/bin/env python
2
Brett Cannon8ab27df2003-08-05 03:52:04 +00003""" This module tries to retrieve as much platform-identifying data as
Marc-André Lemburg246d8472003-04-24 11:36:11 +00004 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
Benjamin Petersonf3d7dbe2009-10-04 14:54:52 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
Marc-André Lemburg246d8472003-04-24 11:36:11 +000015# Still needed:
16# * more support for WinCE
17# * support for MS-DOS (PythonDX ?)
18# * support for Amiga and other still unsupported platforms running Python
19# * support for additional Linux distributions
20#
Brett Cannon8ab27df2003-08-05 03:52:04 +000021# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000022# checks (in no particular order):
23#
24# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
25# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
26# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000035# 1.0.6 - added linux_distribution()
36# 1.0.5 - fixed Java support to allow running the module on Jython
37# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000038# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000039# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000040# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000041# 1.0.0 - reformatted a bit and checked into Python CVS
42# 0.8.0 - added sys.version parser and various new access
43# APIs (python_version(), python_compiler(), etc.)
44# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
45# 0.7.1 - added support for Caldera OpenLinux
46# 0.7.0 - some fixes for WinCE; untabified the source file
47# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
48# vms_lib.getsyi() configured
49# 0.6.1 - added code to prevent 'uname -p' on platforms which are
50# known not to support it
51# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
52# did some cleanup of the interfaces - some APIs have changed
53# 0.5.5 - fixed another type in the MacOS code... should have
54# used more coffee today ;-)
55# 0.5.4 - fixed a few typos in the MacOS code
56# 0.5.3 - added experimental MacOS support; added better popen()
57# workarounds in _syscmd_ver() -- still not 100% elegant
58# though
59# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
60# return values (the system uname command tends to return
61# 'unknown' instead of just leaving the field emtpy)
62# 0.5.1 - included code for slackware dist; added exception handlers
63# to cover up situations where platforms don't have os.popen
64# (e.g. Mac) or fail on socket.gethostname(); fixed libc
65# detection RE
66# 0.5.0 - changed the API names referring to system commands to *syscmd*;
67# added java_ver(); made syscmd_ver() a private
68# API (was system_ver() in previous versions) -- use uname()
69# instead; extended the win32_ver() to also return processor
70# type information
71# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
72# 0.3.4 - fixed a bug in _follow_symlinks()
73# 0.3.3 - fixed popen() and "file" command invokation bugs
74# 0.3.2 - added architecture() API and support for it in platform()
75# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
76# 0.3.0 - added system alias support
77# 0.2.3 - removed 'wince' again... oh well.
78# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
79# 0.2.1 - added cache logic and changed the platform string format
80# 0.2.0 - changed the API to use functions instead of module globals
81# since some action take too long to be run on module import
82# 0.1.0 - first release
83#
84# You can always get the latest version of this module at:
85#
86# http://www.egenix.com/files/python/platform.py
87#
88# If that URL should fail, try contacting the author.
89
90__copyright__ = """
91 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Petersonffeda292010-01-09 18:48:46 +000092 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000093
94 Permission to use, copy, modify, and distribute this software and its
95 documentation for any purpose and without fee or royalty is hereby granted,
96 provided that the above copyright notice appear in all copies and that
97 both that copyright notice and this permission notice appear in
98 supporting documentation or portions thereof, including modifications,
99 that you make.
100
101 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
102 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
103 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
104 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
105 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
106 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
107 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
108
109"""
110
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000111__version__ = '1.0.6'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000112
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000113import sys, os, re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000114
115### Platform specific APIs
116
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000117_libc_search = re.compile(r'(__libc_init)'
118 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000119 '(GLIBC_([0-9.]+))'
120 '|'
Antoine Pitroufd036452008-08-19 17:56:33 +0000121 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000122
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000123def libc_ver(executable=sys.executable,lib='',version='',
124
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000125 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000126
Brett Cannon8ab27df2003-08-05 03:52:04 +0000127 """ Tries to determine the libc version that the file executable
128 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000129
130 Returns a tuple of strings (lib,version) which default to the
131 given parameters in case the lookup fails.
132
133 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000134 libc versions add symbols to the executable and thus is probably
135 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000136
137 The file is read and scanned in chunks of chunksize bytes.
138
139 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000140 if hasattr(os.path, 'realpath'):
141 # Python 2.2 introduced os.path.realpath(); it is used
142 # here to work around problems with Cygwin not being
143 # able to open symlinks for reading
144 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000145 f = open(executable,'rb')
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000146 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147 pos = 0
148 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000149 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000150 if not m:
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000151 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152 if not binary:
153 break
154 pos = 0
155 continue
156 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
157 if libcinit and not lib:
158 lib = 'libc'
159 elif glibc:
160 if lib != 'glibc':
161 lib = 'glibc'
162 version = glibcversion
163 elif glibcversion > version:
164 version = glibcversion
165 elif so:
166 if lib != 'glibc':
167 lib = 'libc'
168 if soversion > version:
169 version = soversion
170 if threads and version[-len(threads):] != threads:
171 version = version + threads
172 pos = m.end()
173 f.close()
174 return lib,version
175
176def _dist_try_harder(distname,version,id):
177
Tim Peters0eadaac2003-04-24 16:02:54 +0000178 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000179 information in case the default method fails.
180
181 Currently supports older SuSE Linux, Caldera OpenLinux and
182 Slackware Linux distributions.
183
184 """
185 if os.path.exists('/var/adm/inst-log/info'):
186 # SuSE Linux stores distribution information in that file
187 info = open('/var/adm/inst-log/info').readlines()
188 distname = 'SuSE'
189 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000190 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000191 if len(tv) == 2:
192 tag,value = tv
193 else:
194 continue
195 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000196 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000197 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000198 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000199 id = values[2]
200 return distname,version,id
201
202 if os.path.exists('/etc/.installed'):
203 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
204 info = open('/etc/.installed').readlines()
205 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000206 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
208 # XXX does Caldera support non Intel platforms ? If yes,
209 # where can we find the needed id ?
210 return 'OpenLinux',pkg[1],id
211
212 if os.path.isdir('/usr/lib/setup'):
213 # Check for slackware verson tag file (thanks to Greg Andruk)
214 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000215 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000216 if verfiles[n][:14] != 'slack-version-':
217 del verfiles[n]
218 if verfiles:
219 verfiles.sort()
220 distname = 'slackware'
221 version = verfiles[-1][14:]
222 return distname,version,id
223
224 return distname,version,id
225
Antoine Pitroufd036452008-08-19 17:56:33 +0000226_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000227_lsb_release_version = re.compile(r'(.+)'
228 ' release '
229 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000230 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000231_release_version = re.compile(r'([^0-9]+)'
232 '(?: release )?'
233 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000234 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000235
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000236# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000237# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000238# and http://data.linux-ntfs.org/rpm/whichrpm
239# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000240
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000241_supported_dists = (
242 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
243 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
244 'UnitedLinux', 'turbolinux')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000245
246def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000247
Benjamin Peterson79e0b812010-01-25 03:40:53 +0000248 # Default to empty 'version' and 'id' strings. Both defaults are used
249 # when 'firstline' is empty. 'id' defaults to empty when an id can not
250 # be deduced.
251 version = ''
252 id = ''
253
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000254 # Parse the first line
255 m = _lsb_release_version.match(firstline)
256 if m is not None:
257 # LSB format: "distro release x.x (codename)"
258 return tuple(m.groups())
259
260 # Pre-LSB format: "distro x.x (codename)"
261 m = _release_version.match(firstline)
262 if m is not None:
263 return tuple(m.groups())
264
265 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000266 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000267 if l:
268 version = l[0]
269 if len(l) > 1:
270 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000271 return '', version, id
272
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000273def linux_distribution(distname='', version='', id='',
274
275 supported_dists=_supported_dists,
276 full_distribution_name=1):
277
278 """ Tries to determine the name of the Linux OS distribution name.
279
280 The function first looks for a distribution release file in
281 /etc and then reverts to _dist_try_harder() in case no
282 suitable files are found.
283
284 supported_dists may be given to define the set of Linux
285 distributions to look for. It defaults to a list of currently
286 supported Linux distributions identified by their release file
287 name.
288
289 If full_distribution_name is true (default), the full
290 distribution read from the OS is returned. Otherwise the short
291 name taken from supported_dists is used.
292
293 Returns a tuple (distname,version,id) which default to the
294 args given as parameters.
295
296 """
297 try:
298 etc = os.listdir('/etc')
299 except os.error:
300 # Probably not a Unix system
301 return distname,version,id
302 etc.sort()
303 for file in etc:
304 m = _release_filename.match(file)
305 if m is not None:
306 _distname,dummy = m.groups()
307 if _distname in supported_dists:
308 distname = _distname
309 break
310 else:
311 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000312
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000313 # Read the first line
314 f = open('/etc/'+file, 'r')
315 firstline = f.readline()
316 f.close()
317 _distname, _version, _id = _parse_release_file(firstline)
318
319 if _distname and full_distribution_name:
320 distname = _distname
321 if _version:
322 version = _version
323 if _id:
324 id = _id
325 return distname, version, id
326
327# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000328
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000329def dist(distname='',version='',id='',
330
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000331 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000332
Brett Cannon8ab27df2003-08-05 03:52:04 +0000333 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000334
335 The function first looks for a distribution release file in
336 /etc and then reverts to _dist_try_harder() in case no
337 suitable files are found.
338
Brett Cannon8ab27df2003-08-05 03:52:04 +0000339 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000340 args given as parameters.
341
342 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000343 return linux_distribution(distname, version, id,
344 supported_dists=supported_dists,
345 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000346
347class _popen:
348
349 """ Fairly portable (alternative) popen implementation.
350
351 This is mostly needed in case os.popen() is not available, or
352 doesn't work as advertised, e.g. in Win9X GUI programs like
353 PythonWin or IDLE.
354
355 Writing to the pipe is currently not supported.
356
357 """
358 tmpfile = ''
359 pipe = None
360 bufsize = None
361 mode = 'r'
362
363 def __init__(self,cmd,mode='r',bufsize=None):
364
365 if mode != 'r':
Collin Winterce36ad82007-08-30 01:19:48 +0000366 raise ValueError('popen()-emulation only supports read mode')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000367 import tempfile
368 self.tmpfile = tmpfile = tempfile.mktemp()
369 os.system(cmd + ' > %s' % tmpfile)
370 self.pipe = open(tmpfile,'rb')
371 self.bufsize = bufsize
372 self.mode = mode
373
374 def read(self):
375
376 return self.pipe.read()
377
378 def readlines(self):
379
380 if self.bufsize is not None:
381 return self.pipe.readlines()
382
383 def close(self,
384
385 remove=os.unlink,error=os.error):
386
387 if self.pipe:
388 rc = self.pipe.close()
389 else:
390 rc = 255
391 if self.tmpfile:
392 try:
393 remove(self.tmpfile)
394 except error:
395 pass
396 return rc
397
398 # Alias
399 __del__ = close
400
401def popen(cmd, mode='r', bufsize=None):
402
403 """ Portable popen() interface.
404 """
405 # Find a working popen implementation preferring win32pipe.popen
406 # over os.popen over _popen
407 popen = None
408 if os.environ.get('OS','') == 'Windows_NT':
409 # On NT win32pipe should work; on Win9x it hangs due to bugs
410 # in the MS C lib (see MS KnowledgeBase article Q150956)
411 try:
412 import win32pipe
413 except ImportError:
414 pass
415 else:
416 popen = win32pipe.popen
417 if popen is None:
418 if hasattr(os,'popen'):
419 popen = os.popen
420 # Check whether it works... it doesn't in GUI programs
421 # on Windows platforms
422 if sys.platform == 'win32': # XXX Others too ?
423 try:
424 popen('')
425 except os.error:
426 popen = _popen
427 else:
428 popen = _popen
429 if bufsize is None:
430 return popen(cmd,mode)
431 else:
432 return popen(cmd,mode,bufsize)
433
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000434def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000435
Brett Cannon8ab27df2003-08-05 03:52:04 +0000436 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000437 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000438 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000439 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000440 if build:
441 l.append(build)
442 try:
443 ints = map(int,l)
444 except ValueError:
445 strings = l
446 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000447 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000448 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000449 return version
450
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000451_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
452 '.*'
Antoine Pitroufd036452008-08-19 17:56:33 +0000453 'Version ([\d.]+))', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000454
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000455def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000457 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458
459 """ Tries to figure out the OS version used and returns
460 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000461
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 It uses the "ver" shell command for this which is known
463 to exists on Windows, DOS and OS/2. XXX Others too ?
464
465 In case this fails, the given parameters are used as
466 defaults.
467
468 """
469 if sys.platform not in supported_platforms:
470 return system,release,version
471
472 # Try some common cmd strings
473 for cmd in ('ver','command /c ver','cmd /c ver'):
474 try:
475 pipe = popen(cmd)
476 info = pipe.read()
477 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000478 raise os.error('command failed')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000479 # XXX How can I supress shell errors from being written
480 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000481 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000482 #print 'Command %s failed: %s' % (cmd,why)
483 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000484 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485 #print 'Command %s failed: %s' % (cmd,why)
486 continue
487 else:
488 break
489 else:
490 return system,release,version
491
492 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000493 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000494 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000495 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000496 system,release,version = m.groups()
497 # Strip trailing dots from version and release
498 if release[-1] == '.':
499 release = release[:-1]
500 if version[-1] == '.':
501 version = version[:-1]
502 # Normalize the version and build strings (eliminating additional
503 # zeros)
504 version = _norm_version(version)
505 return system,release,version
506
507def _win32_getvalue(key,name,default=''):
508
509 """ Read a value for name from the registry key.
510
511 In case this fails, default is returned.
512
513 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000514 try:
515 # Use win32api if available
516 from win32api import RegQueryValueEx
517 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000518 # On Python 2.0 and later, emulate using winreg
519 import winreg
520 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000521 try:
522 return RegQueryValueEx(key,name)
523 except:
524 return default
525
526def win32_ver(release='',version='',csd='',ptype=''):
527
528 """ Get additional version information from the Windows Registry
529 and return a tuple (version,csd,ptype) referring to version
530 number, CSD level and OS type (multi/single
531 processor).
532
533 As a hint: ptype returns 'Uniprocessor Free' on single
534 processor NT machines and 'Multiprocessor Free' on multi
535 processor machines. The 'Free' refers to the OS version being
536 free of debugging code. It could also state 'Checked' which
537 means the OS version uses debugging code, i.e. code that
538 checks arguments, ranges, etc. (Thomas Heller).
539
Christian Heimes02781dc2008-03-21 01:11:52 +0000540 Note: this function works best with Mark Hammond's win32
541 package installed, but also on Python 2.3 and later. It
542 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000543
544 """
545 # XXX Is there any way to find out the processor type on WinXX ?
546 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000547 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000549 #
550 # The mappings between reg. values and release names can be found
551 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000552
553 # Import the needed APIs
554 try:
555 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000556 from win32api import RegQueryValueEx, RegOpenKeyEx, \
557 RegCloseKey, GetVersionEx
558 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
559 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000560 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000561 # Emulate the win32api module using Python APIs
562 try:
563 sys.getwindowsversion
564 except AttributeError:
565 # No emulation possible, so return the defaults...
566 return release,version,csd,ptype
567 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000568 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000569 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000570 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000571 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000572 RegQueryValueEx = winreg.QueryValueEx
573 RegOpenKeyEx = winreg.OpenKeyEx
574 RegCloseKey = winreg.CloseKey
575 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000576 VER_PLATFORM_WIN32_WINDOWS = 1
577 VER_PLATFORM_WIN32_NT = 2
578 VER_NT_WORKSTATION = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000579
580 # Find out the registry key and some general version infos
581 maj,min,buildno,plat,csd = GetVersionEx()
582 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
583 if csd[:13] == 'Service Pack ':
584 csd = 'SP' + csd[13:]
585 if plat == VER_PLATFORM_WIN32_WINDOWS:
586 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
587 # Try to guess the release name
588 if maj == 4:
589 if min == 0:
590 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000591 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000592 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000593 elif min == 90:
594 release = 'Me'
595 else:
596 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000597 elif maj == 5:
598 release = '2000'
599 elif plat == VER_PLATFORM_WIN32_NT:
600 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
601 if maj <= 4:
602 release = 'NT'
603 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000604 if min == 0:
605 release = '2000'
606 elif min == 1:
607 release = 'XP'
608 elif min == 2:
609 release = '2003Server'
610 else:
611 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000612 elif maj == 6:
613 if min == 0:
614 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
Christian Heimes02781dc2008-03-21 01:11:52 +0000615 try:
616 productType = GetVersionEx(1)[8]
617 except TypeError:
618 # sys.getwindowsversion() doesn't take any arguments, so
619 # we cannot detect 2008 Server that way.
620 # XXX Add some other means of detecting 2008 Server ?!
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000621 release = 'Vista'
622 else:
Christian Heimes02781dc2008-03-21 01:11:52 +0000623 if productType == VER_NT_WORKSTATION:
624 release = 'Vista'
625 else:
626 release = '2008Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000627 else:
628 release = 'post2008Server'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000629 else:
630 if not release:
631 # E.g. Win3.1 with win32s
632 release = '%i.%i' % (maj,min)
633 return release,version,csd,ptype
634
635 # Open the registry key
636 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000637 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000639 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000640 except:
641 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000642
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000643 # Parse values
644 #subversion = _win32_getvalue(keyCurVer,
645 # 'SubVersionNumber',
646 # ('',1))[0]
647 #if subversion:
648 # release = release + subversion # 95a, 95b, etc.
649 build = _win32_getvalue(keyCurVer,
650 'CurrentBuildNumber',
651 ('',1))[0]
652 ptype = _win32_getvalue(keyCurVer,
653 'CurrentType',
654 (ptype,1))[0]
655
656 # Normalize version
657 version = _norm_version(version,build)
658
659 # Close key
660 RegCloseKey(keyCurVer)
661 return release,version,csd,ptype
662
663def _mac_ver_lookup(selectors,default=None):
664
Benjamin Petersonebacd262008-05-29 21:09:51 +0000665 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000666 l = []
667 append = l.append
668 for selector in selectors:
669 try:
670 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000671 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000672 append(default)
673 return l
674
675def _bcd2str(bcd):
676
677 return hex(bcd)[2:]
678
679def mac_ver(release='',versioninfo=('','',''),machine=''):
680
681 """ Get MacOS version information and return it as tuple (release,
682 versioninfo, machine) with versioninfo being a tuple (version,
683 dev_stage, non_release_version).
684
Brett Cannon8ab27df2003-08-05 03:52:04 +0000685 Entries which cannot be determined are set to the paramter values
686 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687
688 Thanks to Mark R. Levinson for mailing documentation links and
689 code examples for this function. Documentation for the
690 gestalt() API is available online at:
691
692 http://www.rgaros.nl/gestalt/
693
694 """
695 # Check whether the version info module is available
696 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000697 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698 except ImportError:
699 return release,versioninfo,machine
700 # Get the infos
Ronald Oussorene61b21e2010-02-07 11:34:48 +0000701 sysv, sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702 # Decode the infos
703 if sysv:
704 major = (sysv & 0xFF00) >> 8
705 minor = (sysv & 0x00F0) >> 4
706 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000707
708 if (major, minor) >= (10, 4):
709 # the 'sysv' gestald cannot return patchlevels
710 # higher than 9. Apple introduced 3 new
711 # gestalt codes in 10.4 to deal with this
712 # issue (needed because patch levels can
713 # run higher than 9, such as 10.4.11)
714 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
715 release = '%i.%i.%i' %(major, minor, patch)
716 else:
717 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000718
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000719 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000720 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000721 0x2: 'PowerPC',
722 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000723 return release,versioninfo,machine
724
Neal Norwitz9b924c62003-06-29 04:17:45 +0000725def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000726
727 from java.lang import System
728 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000729 value = System.getProperty(name)
730 if value is None:
731 return default
732 return value
733 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000734 return default
735
736def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000737
Brett Cannon8ab27df2003-08-05 03:52:04 +0000738 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000739
740 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
741 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
742 tuple (os_name,os_version,os_arch).
743
744 Values which cannot be determined are set to the defaults
745 given as parameters (which all default to '').
746
747 """
748 # Import the needed APIs
749 try:
750 import java.lang
751 except ImportError:
752 return release,vendor,vminfo,osinfo
753
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000754 vendor = _java_getprop('java.vendor', vendor)
755 release = _java_getprop('java.version', release)
756 vm_name, vm_release, vm_vendor = vminfo
757 vm_name = _java_getprop('java.vm.name', vm_name)
758 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
759 vm_release = _java_getprop('java.vm.version', vm_release)
760 vminfo = vm_name, vm_release, vm_vendor
761 os_name, os_version, os_arch = osinfo
762 os_arch = _java_getprop('java.os.arch', os_arch)
763 os_name = _java_getprop('java.os.name', os_name)
764 os_version = _java_getprop('java.os.version', os_version)
765 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000766
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000767 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000768
769### System name aliasing
770
771def system_alias(system,release,version):
772
773 """ Returns (system,release,version) aliased to common
774 marketing names used for some systems.
775
776 It also does some reordering of the information in some cases
777 where it would otherwise cause confusion.
778
779 """
780 if system == 'Rhapsody':
781 # Apple's BSD derivative
782 # XXX How can we determine the marketing release number ?
783 return 'MacOS X Server',system+release,version
784
785 elif system == 'SunOS':
786 # Sun's OS
787 if release < '5':
788 # These releases use the old name SunOS
789 return system,release,version
790 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000791 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000792 if l:
793 try:
794 major = int(l[0])
795 except ValueError:
796 pass
797 else:
798 major = major - 3
799 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000800 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000801 if release < '6':
802 system = 'Solaris'
803 else:
804 # XXX Whatever the new SunOS marketing name is...
805 system = 'Solaris'
806
807 elif system == 'IRIX64':
808 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
809 # is really a version and not a different platform, since 32-bit
810 # apps are also supported..
811 system = 'IRIX'
812 if version:
813 version = version + ' (64bit)'
814 else:
815 version = '64bit'
816
817 elif system in ('win32','win16'):
818 # In case one of the other tricks
819 system = 'Windows'
820
821 return system,release,version
822
823### Various internal helpers
824
825def _platform(*args):
826
827 """ Helper to format the platform string in a filename
828 compatible format e.g. "system-version-machine".
829 """
830 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000831 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000832
833 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000834 platform = platform.replace(' ','_')
835 platform = platform.replace('/','-')
836 platform = platform.replace('\\','-')
837 platform = platform.replace(':','-')
838 platform = platform.replace(';','-')
839 platform = platform.replace('"','-')
840 platform = platform.replace('(','-')
841 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000842
843 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000844 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000845
846 # Fold '--'s and remove trailing '-'
847 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000848 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000849 if cleaned == platform:
850 break
851 platform = cleaned
852 while platform[-1] == '-':
853 platform = platform[:-1]
854
855 return platform
856
857def _node(default=''):
858
859 """ Helper to determine the node name of this machine.
860 """
861 try:
862 import socket
863 except ImportError:
864 # No sockets...
865 return default
866 try:
867 return socket.gethostname()
868 except socket.error:
869 # Still not working...
870 return default
871
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000872def _follow_symlinks(filepath):
873
874 """ In case filepath is a symlink, follow it until a
875 real file is reached.
876 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000877 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000878 while os.path.islink(filepath):
879 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000880 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000881 return filepath
882
883def _syscmd_uname(option,default=''):
884
885 """ Interface to the system's uname command.
886 """
887 if sys.platform in ('dos','win32','win16','os2'):
888 # XXX Others too ?
889 return default
890 try:
891 f = os.popen('uname %s 2> /dev/null' % option)
892 except (AttributeError,os.error):
893 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000894 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000895 rc = f.close()
896 if not output or rc:
897 return default
898 else:
899 return output
900
901def _syscmd_file(target,default=''):
902
903 """ Interface to the system's file command.
904
905 The function uses the -b option of the file command to have it
906 ommit the filename in its output and if possible the -L option
907 to have the command follow symlinks. It returns default in
908 case the command should fail.
909
910 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000911 if sys.platform in ('dos','win32','win16','os2'):
912 # XXX Others too ?
913 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000914 target = _follow_symlinks(target)
915 try:
Marc-André Lemburg40779852008-09-02 10:33:55 +0000916 f = os.popen('file "%s" 2> /dev/null' % target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000917 except (AttributeError,os.error):
918 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000919 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000920 rc = f.close()
921 if not output or rc:
922 return default
923 else:
924 return output
925
926### Information about the used architecture
927
928# Default values for architecture; non-empty strings override the
929# defaults given as parameters
930_default_architecture = {
931 'win32': ('','WindowsPE'),
932 'win16': ('','Windows'),
933 'dos': ('','MSDOS'),
934}
935
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000936_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000937
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000938def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000939
940 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000941 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000942
Brett Cannon8ab27df2003-08-05 03:52:04 +0000943 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000944 the bit architecture and the linkage format used for the
945 executable. Both values are returned as strings.
946
947 Values that cannot be determined are returned as given by the
948 parameter presets. If bits is given as '', the sizeof(pointer)
949 (or sizeof(long) on Python version < 1.5.2) is used as
950 indicator for the supported pointer size.
951
952 The function relies on the system's "file" command to do the
953 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000954 platforms. On some non-Unix platforms where the "file" command
955 does not exist and the executable is set to the Python interpreter
956 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000957
958 """
959 # Use the sizeof(pointer) as default number of bits if nothing
960 # else is given as default.
961 if not bits:
962 import struct
963 try:
964 size = struct.calcsize('P')
965 except struct.error:
966 # Older installations can only query longs
967 size = struct.calcsize('l')
968 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000969
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000970 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000971 if executable:
972 output = _syscmd_file(executable, '')
973 else:
974 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000975
976 if not output and \
977 executable == sys.executable:
978 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000979 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000980 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000981 b,l = _default_architecture[sys.platform]
982 if b:
983 bits = b
984 if l:
985 linkage = l
986 return bits,linkage
987
988 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000989 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +0000990
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000991 if 'executable' not in fileout:
992 # Format not supported
993 return bits,linkage
994
995 # Bits
996 if '32-bit' in fileout:
997 bits = '32bit'
998 elif 'N32' in fileout:
999 # On Irix only
1000 bits = 'n32bit'
1001 elif '64-bit' in fileout:
1002 bits = '64bit'
1003
1004 # Linkage
1005 if 'ELF' in fileout:
1006 linkage = 'ELF'
1007 elif 'PE' in fileout:
1008 # E.g. Windows uses this format
1009 if 'Windows' in fileout:
1010 linkage = 'WindowsPE'
1011 else:
1012 linkage = 'PE'
1013 elif 'COFF' in fileout:
1014 linkage = 'COFF'
1015 elif 'MS-DOS' in fileout:
1016 linkage = 'MSDOS'
1017 else:
1018 # XXX the A.OUT format also falls under this class...
1019 pass
1020
1021 return bits,linkage
1022
1023### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001024
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001025_uname_cache = None
1026
1027def uname():
1028
1029 """ Fairly portable uname interface. Returns a tuple
1030 of strings (system,node,release,version,machine,processor)
1031 identifying the underlying platform.
1032
1033 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001034 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001035
1036 Entries which cannot be determined are set to ''.
1037
1038 """
1039 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001040 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001041
1042 if _uname_cache is not None:
1043 return _uname_cache
1044
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001045 processor = ''
1046
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001047 # Get some infos from the builtin os.uname API...
1048 try:
1049 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001050 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001051 no_os_uname = 1
1052
1053 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1054 # Hmm, no there is either no uname or uname has returned
1055 #'unknowns'... we'll have to poke around the system then.
1056 if no_os_uname:
1057 system = sys.platform
1058 release = ''
1059 version = ''
1060 node = _node()
1061 machine = ''
1062
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001063 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064
1065 # Try win32_ver() on win32 platforms
1066 if system == 'win32':
1067 release,version,csd,ptype = win32_ver()
1068 if release and version:
1069 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001070 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001071 # available on Win XP and later; see
1072 # http://support.microsoft.com/kb/888731 and
1073 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001074 if not machine:
1075 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1076 if not processor:
1077 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001078
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001079 # Try the 'ver' system command available on some
1080 # platforms
1081 if use_syscmd_ver:
1082 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001083 # Normalize system to what win32_ver() normally returns
1084 # (_syscmd_ver() tends to return the vendor name as well)
1085 if system == 'Microsoft Windows':
1086 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001087 elif system == 'Microsoft' and release == 'Windows':
1088 # Under Windows Vista and Windows Server 2008,
1089 # Microsoft changed the output of the ver command. The
1090 # release is no longer printed. This causes the
1091 # system and release to be misidentified.
1092 system = 'Windows'
1093 if '6.0' == version[:3]:
1094 release = 'Vista'
1095 else:
1096 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001097
1098 # In case we still don't know anything useful, we'll try to
1099 # help ourselves
1100 if system in ('win32','win16'):
1101 if not version:
1102 if system == 'win32':
1103 version = '32bit'
1104 else:
1105 version = '16bit'
1106 system = 'Windows'
1107
1108 elif system[:4] == 'java':
1109 release,vendor,vminfo,osinfo = java_ver()
1110 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001111 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001112 if not version:
1113 version = vendor
1114
1115 elif os.name == 'mac':
1116 release,(version,stage,nonrel),machine = mac_ver()
1117 system = 'MacOS'
1118
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001119 # System specific extensions
1120 if system == 'OpenVMS':
1121 # OpenVMS seems to have release and version mixed up
1122 if not release or release == '0':
1123 release = version
1124 version = ''
1125 # Get processor information
1126 try:
1127 import vms_lib
1128 except ImportError:
1129 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001130 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001131 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1132 if (cpu_number >= 128):
1133 processor = 'Alpha'
1134 else:
1135 processor = 'VAX'
1136 if not processor:
1137 # Get processor information from the uname system command
1138 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001139
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001140 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001141 if system == 'unknown':
1142 system = ''
1143 if node == 'unknown':
1144 node = ''
1145 if release == 'unknown':
1146 release = ''
1147 if version == 'unknown':
1148 version = ''
1149 if machine == 'unknown':
1150 machine = ''
1151 if processor == 'unknown':
1152 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001153
1154 # normalize name
1155 if system == 'Microsoft' and release == 'Windows':
1156 system = 'Windows'
1157 release = 'Vista'
1158
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001159 _uname_cache = system,node,release,version,machine,processor
1160 return _uname_cache
1161
1162### Direct interfaces to some of the uname() return values
1163
1164def system():
1165
1166 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1167
1168 An empty string is returned if the value cannot be determined.
1169
1170 """
1171 return uname()[0]
1172
1173def node():
1174
Brett Cannon8ab27df2003-08-05 03:52:04 +00001175 """ Returns the computer's network name (which may not be fully
1176 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177
1178 An empty string is returned if the value cannot be determined.
1179
1180 """
1181 return uname()[1]
1182
1183def release():
1184
1185 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1186
1187 An empty string is returned if the value cannot be determined.
1188
1189 """
1190 return uname()[2]
1191
1192def version():
1193
1194 """ Returns the system's release version, e.g. '#3 on degas'
1195
1196 An empty string is returned if the value cannot be determined.
1197
1198 """
1199 return uname()[3]
1200
1201def machine():
1202
1203 """ Returns the machine type, e.g. 'i386'
1204
1205 An empty string is returned if the value cannot be determined.
1206
1207 """
1208 return uname()[4]
1209
1210def processor():
1211
1212 """ Returns the (true) processor name, e.g. 'amdk6'
1213
1214 An empty string is returned if the value cannot be
1215 determined. Note that many platforms do not provide this
1216 information or simply return the same value as for machine(),
1217 e.g. NetBSD does this.
1218
1219 """
1220 return uname()[5]
1221
1222### Various APIs for extracting information from sys.version
1223
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001224_sys_version_parser = re.compile(
1225 r'([\w.+]+)\s*'
1226 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001227 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001228
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001229_ironpython_sys_version_parser = re.compile(
1230 r'IronPython\s*'
1231 '([\d\.]+)'
1232 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001233 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001234
Benjamin Petersone549ead2009-03-28 21:42:05 +00001235_pypy_sys_version_parser = re.compile(
1236 r'([\w.+]+)\s*'
1237 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1238 '\[PyPy [^\]]+\]?')
1239
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001240_sys_version_cache = {}
1241
1242def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001243
1244 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001245 (name, version, branch, revision, buildno, builddate, compiler)
1246 referring to the Python implementation name, version, branch,
1247 revision, build number, build date/time as string and the compiler
1248 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001249
1250 Note that unlike the Python sys.version, the returned value
1251 for the Python version will always include the patchlevel (it
1252 defaults to '.0').
1253
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001254 The function returns empty strings for tuple entries that
1255 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001256
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001257 sys_version may be given to parse an alternative version
1258 string, e.g. if the version was read from a different Python
1259 interpreter.
1260
1261 """
1262 # Get the Python version
1263 if sys_version is None:
1264 sys_version = sys.version
1265
1266 # Try the cache first
1267 result = _sys_version_cache.get(sys_version, None)
1268 if result is not None:
1269 return result
1270
1271 # Parse it
1272 if sys_version[:10] == 'IronPython':
1273 # IronPython
1274 name = 'IronPython'
1275 match = _ironpython_sys_version_parser.match(sys_version)
1276 if match is None:
1277 raise ValueError(
1278 'failed to parse IronPython sys.version: %s' %
1279 repr(sys_version))
1280 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001281 buildno = ''
1282 builddate = ''
1283
1284 elif sys.platform[:4] == 'java':
1285 # Jython
1286 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001287 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001288 if match is None:
1289 raise ValueError(
1290 'failed to parse Jython sys.version: %s' %
1291 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001292 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001293 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001294
1295 elif "PyPy" in sys_version:
1296 # PyPy
1297 name = "PyPy"
1298 match = _pypy_sys_version_parser.match(sys_version)
1299 if match is None:
1300 raise ValueError("failed to parse PyPy sys.version: %s" %
1301 repr(sys_version))
1302 version, buildno, builddate, buildtime = match.groups()
1303 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001304
1305 else:
1306 # CPython
1307 match = _sys_version_parser.match(sys_version)
1308 if match is None:
1309 raise ValueError(
1310 'failed to parse CPython sys.version: %s' %
1311 repr(sys_version))
1312 version, buildno, builddate, buildtime, compiler = \
1313 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001314 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001315 builddate = builddate + ' ' + buildtime
1316
Benjamin Petersone549ead2009-03-28 21:42:05 +00001317 if hasattr(sys, 'subversion'):
1318 # sys.subversion was added in Python 2.5
1319 _, branch, revision = sys.subversion
1320 else:
1321 branch = ''
1322 revision = ''
1323
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001324 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001325 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001326 if len(l) == 2:
1327 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001328 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001329
1330 # Build and cache the result
1331 result = (name, version, branch, revision, buildno, builddate, compiler)
1332 _sys_version_cache[sys_version] = result
1333 return result
1334
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001335def python_implementation():
1336
1337 """ Returns a string identifying the Python implementation.
1338
1339 Currently, the following implementations are identified:
1340 'CPython' (C implementation of Python),
1341 'IronPython' (.NET implementation of Python),
1342 'Jython' (Java implementation of Python).
1343
1344 """
1345 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001346
1347def python_version():
1348
1349 """ Returns the Python version as string 'major.minor.patchlevel'
1350
1351 Note that unlike the Python sys.version, the returned value
1352 will always include the patchlevel (it defaults to 0).
1353
1354 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001355 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001356
1357def python_version_tuple():
1358
1359 """ Returns the Python version as tuple (major, minor, patchlevel)
1360 of strings.
1361
1362 Note that unlike the Python sys.version, the returned value
1363 will always include the patchlevel (it defaults to 0).
1364
1365 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001366 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001367
1368def python_branch():
1369
1370 """ Returns a string identifying the Python implementation
1371 branch.
1372
1373 For CPython this is the Subversion branch from which the
1374 Python binary was built.
1375
1376 If not available, an empty string is returned.
1377
1378 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001379
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001380 return _sys_version()[2]
1381
1382def python_revision():
1383
1384 """ Returns a string identifying the Python implementation
1385 revision.
1386
1387 For CPython this is the Subversion revision from which the
1388 Python binary was built.
1389
1390 If not available, an empty string is returned.
1391
1392 """
1393 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001394
1395def python_build():
1396
1397 """ Returns a tuple (buildno, builddate) stating the Python
1398 build number and date as strings.
1399
1400 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001401 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001402
1403def python_compiler():
1404
1405 """ Returns a string identifying the compiler used for compiling
1406 Python.
1407
1408 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001409 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001410
1411### The Opus Magnum of platform strings :-)
1412
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001413_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001414
1415def platform(aliased=0, terse=0):
1416
1417 """ Returns a single string identifying the underlying platform
1418 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001419
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001420 The output is intended to be human readable rather than
1421 machine parseable. It may look different on different
1422 platforms and this is intended.
1423
1424 If "aliased" is true, the function will use aliases for
1425 various platforms that report system names which differ from
1426 their common names, e.g. SunOS will be reported as
1427 Solaris. The system_alias() function is used to implement
1428 this.
1429
1430 Setting terse to true causes the function to return only the
1431 absolute minimum information needed to identify the platform.
1432
1433 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001434 result = _platform_cache.get((aliased, terse), None)
1435 if result is not None:
1436 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001437
1438 # Get uname information and then apply platform specific cosmetics
1439 # to it...
1440 system,node,release,version,machine,processor = uname()
1441 if machine == processor:
1442 processor = ''
1443 if aliased:
1444 system,release,version = system_alias(system,release,version)
1445
1446 if system == 'Windows':
1447 # MS platforms
1448 rel,vers,csd,ptype = win32_ver(version)
1449 if terse:
1450 platform = _platform(system,release)
1451 else:
1452 platform = _platform(system,release,version,csd)
1453
1454 elif system in ('Linux',):
1455 # Linux based systems
1456 distname,distversion,distid = dist('')
1457 if distname and not terse:
1458 platform = _platform(system,release,machine,processor,
1459 'with',
1460 distname,distversion,distid)
1461 else:
1462 # If the distribution name is unknown check for libc vs. glibc
1463 libcname,libcversion = libc_ver(sys.executable)
1464 platform = _platform(system,release,machine,processor,
1465 'with',
1466 libcname+libcversion)
1467 elif system == 'Java':
1468 # Java platforms
1469 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001470 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001471 platform = _platform(system,release,version)
1472 else:
1473 platform = _platform(system,release,version,
1474 'on',
1475 os_name,os_version,os_arch)
1476
1477 elif system == 'MacOS':
1478 # MacOS platforms
1479 if terse:
1480 platform = _platform(system,release)
1481 else:
1482 platform = _platform(system,release,machine)
1483
1484 else:
1485 # Generic handler
1486 if terse:
1487 platform = _platform(system,release)
1488 else:
1489 bits,linkage = architecture(sys.executable)
1490 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001491
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001492 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001493 return platform
1494
1495### Command line interface
1496
1497if __name__ == '__main__':
1498 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001499 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001500 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001501 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001502 sys.exit(0)