blob: 640098fc7616bace4a0fb0bd34f15ae622e8860b [file] [log] [blame]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001#!/usr/bin/env python
2
Brett Cannon8ab27df2003-08-05 03:52:04 +00003""" This module tries to retrieve as much platform-identifying data as
Marc-André Lemburg246d8472003-04-24 11:36:11 +00004 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
13# Python SourceForge Project Page and assign them to "lemburg".
14#
Marc-André Lemburg246d8472003-04-24 11:36:11 +000015# Still needed:
16# * more support for WinCE
17# * support for MS-DOS (PythonDX ?)
18# * support for Amiga and other still unsupported platforms running Python
19# * support for additional Linux distributions
20#
Brett Cannon8ab27df2003-08-05 03:52:04 +000021# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000022# checks (in no particular order):
23#
24# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
25# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
26# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000035# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000036# 1.0.6 - added linux_distribution()
37# 1.0.5 - fixed Java support to allow running the module on Jython
38# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000039# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000040# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000041# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000042# 1.0.0 - reformatted a bit and checked into Python CVS
43# 0.8.0 - added sys.version parser and various new access
44# APIs (python_version(), python_compiler(), etc.)
45# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
46# 0.7.1 - added support for Caldera OpenLinux
47# 0.7.0 - some fixes for WinCE; untabified the source file
48# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
49# vms_lib.getsyi() configured
50# 0.6.1 - added code to prevent 'uname -p' on platforms which are
51# known not to support it
52# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
53# did some cleanup of the interfaces - some APIs have changed
54# 0.5.5 - fixed another type in the MacOS code... should have
55# used more coffee today ;-)
56# 0.5.4 - fixed a few typos in the MacOS code
57# 0.5.3 - added experimental MacOS support; added better popen()
58# workarounds in _syscmd_ver() -- still not 100% elegant
59# though
60# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
61# return values (the system uname command tends to return
62# 'unknown' instead of just leaving the field emtpy)
63# 0.5.1 - included code for slackware dist; added exception handlers
64# to cover up situations where platforms don't have os.popen
65# (e.g. Mac) or fail on socket.gethostname(); fixed libc
66# detection RE
67# 0.5.0 - changed the API names referring to system commands to *syscmd*;
68# added java_ver(); made syscmd_ver() a private
69# API (was system_ver() in previous versions) -- use uname()
70# instead; extended the win32_ver() to also return processor
71# type information
72# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
73# 0.3.4 - fixed a bug in _follow_symlinks()
74# 0.3.3 - fixed popen() and "file" command invokation bugs
75# 0.3.2 - added architecture() API and support for it in platform()
76# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
77# 0.3.0 - added system alias support
78# 0.2.3 - removed 'wince' again... oh well.
79# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
80# 0.2.1 - added cache logic and changed the platform string format
81# 0.2.0 - changed the API to use functions instead of module globals
82# since some action take too long to be run on module import
83# 0.1.0 - first release
84#
85# You can always get the latest version of this module at:
86#
87# http://www.egenix.com/files/python/platform.py
88#
89# If that URL should fail, try contacting the author.
90
91__copyright__ = """
92 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000093 Copyright (c) 2000-2009, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000094
95 Permission to use, copy, modify, and distribute this software and its
96 documentation for any purpose and without fee or royalty is hereby granted,
97 provided that the above copyright notice appear in all copies and that
98 both that copyright notice and this permission notice appear in
99 supporting documentation or portions thereof, including modifications,
100 that you make.
101
102 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
103 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
104 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
105 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
106 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
107 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
108 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
109
110"""
111
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000112__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000113
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000114import sys, os, re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000115
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000116### Globals & Constants
117
118# Determine the platform's /dev/null device
119try:
120 DEV_NULL = os.devnull
121except AttributeError:
122 # os.devnull was added in Python 2.4, so emulate it for earlier
123 # Python versions
124 if sys.platform in ('dos','win32','win16','os2'):
125 # Use the old CP/M NUL as device name
126 DEV_NULL = 'NUL'
127 else:
128 # Standard Unix uses /dev/null
129 DEV_NULL = '/dev/null'
130
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000131### Platform specific APIs
132
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000133_libc_search = re.compile(r'(__libc_init)'
134 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000135 '(GLIBC_([0-9.]+))'
136 '|'
Antoine Pitroufd036452008-08-19 17:56:33 +0000137 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000138
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000139def libc_ver(executable=sys.executable,lib='',version='',
140
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000141 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000142
Brett Cannon8ab27df2003-08-05 03:52:04 +0000143 """ Tries to determine the libc version that the file executable
144 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000145
146 Returns a tuple of strings (lib,version) which default to the
147 given parameters in case the lookup fails.
148
149 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000150 libc versions add symbols to the executable and thus is probably
151 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152
153 The file is read and scanned in chunks of chunksize bytes.
154
155 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000156 if hasattr(os.path, 'realpath'):
157 # Python 2.2 introduced os.path.realpath(); it is used
158 # here to work around problems with Cygwin not being
159 # able to open symlinks for reading
160 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000161 f = open(executable,'rb')
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000162 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000163 pos = 0
164 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000165 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000166 if not m:
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000167 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000168 if not binary:
169 break
170 pos = 0
171 continue
172 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
173 if libcinit and not lib:
174 lib = 'libc'
175 elif glibc:
176 if lib != 'glibc':
177 lib = 'glibc'
178 version = glibcversion
179 elif glibcversion > version:
180 version = glibcversion
181 elif so:
182 if lib != 'glibc':
183 lib = 'libc'
184 if soversion > version:
185 version = soversion
186 if threads and version[-len(threads):] != threads:
187 version = version + threads
188 pos = m.end()
189 f.close()
190 return lib,version
191
192def _dist_try_harder(distname,version,id):
193
Tim Peters0eadaac2003-04-24 16:02:54 +0000194 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000195 information in case the default method fails.
196
197 Currently supports older SuSE Linux, Caldera OpenLinux and
198 Slackware Linux distributions.
199
200 """
201 if os.path.exists('/var/adm/inst-log/info'):
202 # SuSE Linux stores distribution information in that file
203 info = open('/var/adm/inst-log/info').readlines()
204 distname = 'SuSE'
205 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000206 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 if len(tv) == 2:
208 tag,value = tv
209 else:
210 continue
211 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000212 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000213 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000214 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 id = values[2]
216 return distname,version,id
217
218 if os.path.exists('/etc/.installed'):
219 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
220 info = open('/etc/.installed').readlines()
221 for line in info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000222 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000223 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
224 # XXX does Caldera support non Intel platforms ? If yes,
225 # where can we find the needed id ?
226 return 'OpenLinux',pkg[1],id
227
228 if os.path.isdir('/usr/lib/setup'):
229 # Check for slackware verson tag file (thanks to Greg Andruk)
230 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000231 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000232 if verfiles[n][:14] != 'slack-version-':
233 del verfiles[n]
234 if verfiles:
235 verfiles.sort()
236 distname = 'slackware'
237 version = verfiles[-1][14:]
238 return distname,version,id
239
240 return distname,version,id
241
Antoine Pitroufd036452008-08-19 17:56:33 +0000242_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000243_lsb_release_version = re.compile(r'(.+)'
244 ' release '
245 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000246 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000247_release_version = re.compile(r'([^0-9]+)'
248 '(?: release )?'
249 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000250 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000251
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000252# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000253# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000254# and http://data.linux-ntfs.org/rpm/whichrpm
255# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000256
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000257_supported_dists = (
258 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
259 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
260 'UnitedLinux', 'turbolinux')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000261
262def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000263
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000264 # Parse the first line
265 m = _lsb_release_version.match(firstline)
266 if m is not None:
267 # LSB format: "distro release x.x (codename)"
268 return tuple(m.groups())
269
270 # Pre-LSB format: "distro x.x (codename)"
271 m = _release_version.match(firstline)
272 if m is not None:
273 return tuple(m.groups())
274
275 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000276 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000277 if l:
278 version = l[0]
279 if len(l) > 1:
280 id = l[1]
281 else:
282 id = ''
283 return '', version, id
284
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000285def linux_distribution(distname='', version='', id='',
286
287 supported_dists=_supported_dists,
288 full_distribution_name=1):
289
290 """ Tries to determine the name of the Linux OS distribution name.
291
292 The function first looks for a distribution release file in
293 /etc and then reverts to _dist_try_harder() in case no
294 suitable files are found.
295
296 supported_dists may be given to define the set of Linux
297 distributions to look for. It defaults to a list of currently
298 supported Linux distributions identified by their release file
299 name.
300
301 If full_distribution_name is true (default), the full
302 distribution read from the OS is returned. Otherwise the short
303 name taken from supported_dists is used.
304
305 Returns a tuple (distname,version,id) which default to the
306 args given as parameters.
307
308 """
309 try:
310 etc = os.listdir('/etc')
311 except os.error:
312 # Probably not a Unix system
313 return distname,version,id
314 etc.sort()
315 for file in etc:
316 m = _release_filename.match(file)
317 if m is not None:
318 _distname,dummy = m.groups()
319 if _distname in supported_dists:
320 distname = _distname
321 break
322 else:
323 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000324
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000325 # Read the first line
326 f = open('/etc/'+file, 'r')
327 firstline = f.readline()
328 f.close()
329 _distname, _version, _id = _parse_release_file(firstline)
330
331 if _distname and full_distribution_name:
332 distname = _distname
333 if _version:
334 version = _version
335 if _id:
336 id = _id
337 return distname, version, id
338
339# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000340
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000341def dist(distname='',version='',id='',
342
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000343 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000344
Brett Cannon8ab27df2003-08-05 03:52:04 +0000345 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000346
347 The function first looks for a distribution release file in
348 /etc and then reverts to _dist_try_harder() in case no
349 suitable files are found.
350
Brett Cannon8ab27df2003-08-05 03:52:04 +0000351 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000352 args given as parameters.
353
354 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000355 return linux_distribution(distname, version, id,
356 supported_dists=supported_dists,
357 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000358
359class _popen:
360
361 """ Fairly portable (alternative) popen implementation.
362
363 This is mostly needed in case os.popen() is not available, or
364 doesn't work as advertised, e.g. in Win9X GUI programs like
365 PythonWin or IDLE.
366
367 Writing to the pipe is currently not supported.
368
369 """
370 tmpfile = ''
371 pipe = None
372 bufsize = None
373 mode = 'r'
374
375 def __init__(self,cmd,mode='r',bufsize=None):
376
377 if mode != 'r':
Collin Winterce36ad82007-08-30 01:19:48 +0000378 raise ValueError('popen()-emulation only supports read mode')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000379 import tempfile
380 self.tmpfile = tmpfile = tempfile.mktemp()
381 os.system(cmd + ' > %s' % tmpfile)
382 self.pipe = open(tmpfile,'rb')
383 self.bufsize = bufsize
384 self.mode = mode
385
386 def read(self):
387
388 return self.pipe.read()
389
390 def readlines(self):
391
392 if self.bufsize is not None:
393 return self.pipe.readlines()
394
395 def close(self,
396
397 remove=os.unlink,error=os.error):
398
399 if self.pipe:
400 rc = self.pipe.close()
401 else:
402 rc = 255
403 if self.tmpfile:
404 try:
405 remove(self.tmpfile)
406 except error:
407 pass
408 return rc
409
410 # Alias
411 __del__ = close
412
413def popen(cmd, mode='r', bufsize=None):
414
415 """ Portable popen() interface.
416 """
417 # Find a working popen implementation preferring win32pipe.popen
418 # over os.popen over _popen
419 popen = None
420 if os.environ.get('OS','') == 'Windows_NT':
421 # On NT win32pipe should work; on Win9x it hangs due to bugs
422 # in the MS C lib (see MS KnowledgeBase article Q150956)
423 try:
424 import win32pipe
425 except ImportError:
426 pass
427 else:
428 popen = win32pipe.popen
429 if popen is None:
430 if hasattr(os,'popen'):
431 popen = os.popen
432 # Check whether it works... it doesn't in GUI programs
433 # on Windows platforms
434 if sys.platform == 'win32': # XXX Others too ?
435 try:
436 popen('')
437 except os.error:
438 popen = _popen
439 else:
440 popen = _popen
441 if bufsize is None:
442 return popen(cmd,mode)
443 else:
444 return popen(cmd,mode,bufsize)
445
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000446def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000447
Brett Cannon8ab27df2003-08-05 03:52:04 +0000448 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000449 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000450 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000451 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452 if build:
453 l.append(build)
454 try:
455 ints = map(int,l)
456 except ValueError:
457 strings = l
458 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000459 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000460 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000461 return version
462
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000463_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
464 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000465 '\[.* ([\d.]+)\])')
466
467# Examples of VER command output:
468#
469# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
470# Windows XP: Microsoft Windows XP [Version 5.1.2600]
471# Windows Vista: Microsoft Windows [Version 6.0.6002]
472#
473# Note that the "Version" string gets localized on different
474# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000475
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000476def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000477
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000478 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000479
480 """ Tries to figure out the OS version used and returns
481 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000482
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000483 It uses the "ver" shell command for this which is known
484 to exists on Windows, DOS and OS/2. XXX Others too ?
485
486 In case this fails, the given parameters are used as
487 defaults.
488
489 """
490 if sys.platform not in supported_platforms:
491 return system,release,version
492
493 # Try some common cmd strings
494 for cmd in ('ver','command /c ver','cmd /c ver'):
495 try:
496 pipe = popen(cmd)
497 info = pipe.read()
498 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000499 raise os.error('command failed')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000500 # XXX How can I supress shell errors from being written
501 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000502 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000503 #print 'Command %s failed: %s' % (cmd,why)
504 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000505 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000506 #print 'Command %s failed: %s' % (cmd,why)
507 continue
508 else:
509 break
510 else:
511 return system,release,version
512
513 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000514 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000515 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000516 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000517 system,release,version = m.groups()
518 # Strip trailing dots from version and release
519 if release[-1] == '.':
520 release = release[:-1]
521 if version[-1] == '.':
522 version = version[:-1]
523 # Normalize the version and build strings (eliminating additional
524 # zeros)
525 version = _norm_version(version)
526 return system,release,version
527
528def _win32_getvalue(key,name,default=''):
529
530 """ Read a value for name from the registry key.
531
532 In case this fails, default is returned.
533
534 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000535 try:
536 # Use win32api if available
537 from win32api import RegQueryValueEx
538 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000539 # On Python 2.0 and later, emulate using winreg
540 import winreg
541 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000542 try:
543 return RegQueryValueEx(key,name)
544 except:
545 return default
546
547def win32_ver(release='',version='',csd='',ptype=''):
548
549 """ Get additional version information from the Windows Registry
550 and return a tuple (version,csd,ptype) referring to version
551 number, CSD level and OS type (multi/single
552 processor).
553
554 As a hint: ptype returns 'Uniprocessor Free' on single
555 processor NT machines and 'Multiprocessor Free' on multi
556 processor machines. The 'Free' refers to the OS version being
557 free of debugging code. It could also state 'Checked' which
558 means the OS version uses debugging code, i.e. code that
559 checks arguments, ranges, etc. (Thomas Heller).
560
Christian Heimes02781dc2008-03-21 01:11:52 +0000561 Note: this function works best with Mark Hammond's win32
562 package installed, but also on Python 2.3 and later. It
563 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000564
565 """
566 # XXX Is there any way to find out the processor type on WinXX ?
567 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000568 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000569 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000570 #
571 # The mappings between reg. values and release names can be found
572 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000573
574 # Import the needed APIs
575 try:
576 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000577 from win32api import RegQueryValueEx, RegOpenKeyEx, \
578 RegCloseKey, GetVersionEx
579 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
580 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000581 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000582 # Emulate the win32api module using Python APIs
583 try:
584 sys.getwindowsversion
585 except AttributeError:
586 # No emulation possible, so return the defaults...
587 return release,version,csd,ptype
588 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000589 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000590 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000591 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000592 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000593 RegQueryValueEx = winreg.QueryValueEx
594 RegOpenKeyEx = winreg.OpenKeyEx
595 RegCloseKey = winreg.CloseKey
596 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000597 VER_PLATFORM_WIN32_WINDOWS = 1
598 VER_PLATFORM_WIN32_NT = 2
599 VER_NT_WORKSTATION = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000600
601 # Find out the registry key and some general version infos
602 maj,min,buildno,plat,csd = GetVersionEx()
603 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
604 if csd[:13] == 'Service Pack ':
605 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000606
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000607 if plat == VER_PLATFORM_WIN32_WINDOWS:
608 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
609 # Try to guess the release name
610 if maj == 4:
611 if min == 0:
612 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000613 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000614 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000615 elif min == 90:
616 release = 'Me'
617 else:
618 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000619 elif maj == 5:
620 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000621
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000622 elif plat == VER_PLATFORM_WIN32_NT:
623 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
624 if maj <= 4:
625 release = 'NT'
626 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000627 if min == 0:
628 release = '2000'
629 elif min == 1:
630 release = 'XP'
631 elif min == 2:
632 release = '2003Server'
633 else:
634 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000635 elif maj == 6:
636 if min == 0:
637 # Per http://msdn2.microsoft.com/en-us/library/ms724429.aspx
Christian Heimes02781dc2008-03-21 01:11:52 +0000638 try:
639 productType = GetVersionEx(1)[8]
640 except TypeError:
641 # sys.getwindowsversion() doesn't take any arguments, so
642 # we cannot detect 2008 Server that way.
643 # XXX Add some other means of detecting 2008 Server ?!
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000644 release = 'Vista'
645 else:
Christian Heimes02781dc2008-03-21 01:11:52 +0000646 if productType == VER_NT_WORKSTATION:
647 release = 'Vista'
648 else:
649 release = '2008Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000650 #elif min == 1:
651 # # Windows 7 release candidate uses version 6.1.7100
652 # release = '7RC'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000653 else:
654 release = 'post2008Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000655
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000656 else:
657 if not release:
658 # E.g. Win3.1 with win32s
659 release = '%i.%i' % (maj,min)
660 return release,version,csd,ptype
661
662 # Open the registry key
663 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000664 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000666 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667 except:
668 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000669
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000670 # Parse values
671 #subversion = _win32_getvalue(keyCurVer,
672 # 'SubVersionNumber',
673 # ('',1))[0]
674 #if subversion:
675 # release = release + subversion # 95a, 95b, etc.
676 build = _win32_getvalue(keyCurVer,
677 'CurrentBuildNumber',
678 ('',1))[0]
679 ptype = _win32_getvalue(keyCurVer,
680 'CurrentType',
681 (ptype,1))[0]
682
683 # Normalize version
684 version = _norm_version(version,build)
685
686 # Close key
687 RegCloseKey(keyCurVer)
688 return release,version,csd,ptype
689
690def _mac_ver_lookup(selectors,default=None):
691
Benjamin Petersonebacd262008-05-29 21:09:51 +0000692 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000693 l = []
694 append = l.append
695 for selector in selectors:
696 try:
697 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000698 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000699 append(default)
700 return l
701
702def _bcd2str(bcd):
703
704 return hex(bcd)[2:]
705
706def mac_ver(release='',versioninfo=('','',''),machine=''):
707
708 """ Get MacOS version information and return it as tuple (release,
709 versioninfo, machine) with versioninfo being a tuple (version,
710 dev_stage, non_release_version).
711
Brett Cannon8ab27df2003-08-05 03:52:04 +0000712 Entries which cannot be determined are set to the paramter values
713 which default to ''. All tuple entries are strings.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000714
715 Thanks to Mark R. Levinson for mailing documentation links and
716 code examples for this function. Documentation for the
717 gestalt() API is available online at:
718
719 http://www.rgaros.nl/gestalt/
720
721 """
722 # Check whether the version info module is available
723 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000724 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000725 except ImportError:
726 return release,versioninfo,machine
727 # Get the infos
728 sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
729 # Decode the infos
730 if sysv:
731 major = (sysv & 0xFF00) >> 8
732 minor = (sysv & 0x00F0) >> 4
733 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000734
735 if (major, minor) >= (10, 4):
736 # the 'sysv' gestald cannot return patchlevels
737 # higher than 9. Apple introduced 3 new
738 # gestalt codes in 10.4 to deal with this
739 # issue (needed because patch levels can
740 # run higher than 9, such as 10.4.11)
741 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
742 release = '%i.%i.%i' %(major, minor, patch)
743 else:
744 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000745
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746 if sysu:
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000747 # NOTE: this block is left as documentation of the
748 # intention of this function, the 'sysu' gestalt is no
749 # longer available and there are no alternatives.
Guido van Rossume2a383d2007-01-15 16:59:06 +0000750 major = int((sysu & 0xFF000000) >> 24)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000751 minor = (sysu & 0x00F00000) >> 20
752 bugfix = (sysu & 0x000F0000) >> 16
753 stage = (sysu & 0x0000FF00) >> 8
754 nonrel = (sysu & 0x000000FF)
755 version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
756 nonrel = _bcd2str(nonrel)
757 stage = {0x20:'development',
758 0x40:'alpha',
759 0x60:'beta',
760 0x80:'final'}.get(stage,'')
761 versioninfo = (version,stage,nonrel)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000762
763
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000764 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000765 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000766 0x2: 'PowerPC',
767 0xa: 'i386'}.get(sysa,'')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000768 return release,versioninfo,machine
769
Neal Norwitz9b924c62003-06-29 04:17:45 +0000770def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000771
772 from java.lang import System
773 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000774 value = System.getProperty(name)
775 if value is None:
776 return default
777 return value
778 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000779 return default
780
781def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000782
Brett Cannon8ab27df2003-08-05 03:52:04 +0000783 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000784
785 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
786 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
787 tuple (os_name,os_version,os_arch).
788
789 Values which cannot be determined are set to the defaults
790 given as parameters (which all default to '').
791
792 """
793 # Import the needed APIs
794 try:
795 import java.lang
796 except ImportError:
797 return release,vendor,vminfo,osinfo
798
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000799 vendor = _java_getprop('java.vendor', vendor)
800 release = _java_getprop('java.version', release)
801 vm_name, vm_release, vm_vendor = vminfo
802 vm_name = _java_getprop('java.vm.name', vm_name)
803 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
804 vm_release = _java_getprop('java.vm.version', vm_release)
805 vminfo = vm_name, vm_release, vm_vendor
806 os_name, os_version, os_arch = osinfo
807 os_arch = _java_getprop('java.os.arch', os_arch)
808 os_name = _java_getprop('java.os.name', os_name)
809 os_version = _java_getprop('java.os.version', os_version)
810 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000811
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000812 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000813
814### System name aliasing
815
816def system_alias(system,release,version):
817
818 """ Returns (system,release,version) aliased to common
819 marketing names used for some systems.
820
821 It also does some reordering of the information in some cases
822 where it would otherwise cause confusion.
823
824 """
825 if system == 'Rhapsody':
826 # Apple's BSD derivative
827 # XXX How can we determine the marketing release number ?
828 return 'MacOS X Server',system+release,version
829
830 elif system == 'SunOS':
831 # Sun's OS
832 if release < '5':
833 # These releases use the old name SunOS
834 return system,release,version
835 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000836 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000837 if l:
838 try:
839 major = int(l[0])
840 except ValueError:
841 pass
842 else:
843 major = major - 3
844 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000845 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000846 if release < '6':
847 system = 'Solaris'
848 else:
849 # XXX Whatever the new SunOS marketing name is...
850 system = 'Solaris'
851
852 elif system == 'IRIX64':
853 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
854 # is really a version and not a different platform, since 32-bit
855 # apps are also supported..
856 system = 'IRIX'
857 if version:
858 version = version + ' (64bit)'
859 else:
860 version = '64bit'
861
862 elif system in ('win32','win16'):
863 # In case one of the other tricks
864 system = 'Windows'
865
866 return system,release,version
867
868### Various internal helpers
869
870def _platform(*args):
871
872 """ Helper to format the platform string in a filename
873 compatible format e.g. "system-version-machine".
874 """
875 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000876 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000877
878 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000879 platform = platform.replace(' ','_')
880 platform = platform.replace('/','-')
881 platform = platform.replace('\\','-')
882 platform = platform.replace(':','-')
883 platform = platform.replace(';','-')
884 platform = platform.replace('"','-')
885 platform = platform.replace('(','-')
886 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000887
888 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000889 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000890
891 # Fold '--'s and remove trailing '-'
892 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000893 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000894 if cleaned == platform:
895 break
896 platform = cleaned
897 while platform[-1] == '-':
898 platform = platform[:-1]
899
900 return platform
901
902def _node(default=''):
903
904 """ Helper to determine the node name of this machine.
905 """
906 try:
907 import socket
908 except ImportError:
909 # No sockets...
910 return default
911 try:
912 return socket.gethostname()
913 except socket.error:
914 # Still not working...
915 return default
916
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000917def _follow_symlinks(filepath):
918
919 """ In case filepath is a symlink, follow it until a
920 real file is reached.
921 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000922 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000923 while os.path.islink(filepath):
924 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000925 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000926 return filepath
927
928def _syscmd_uname(option,default=''):
929
930 """ Interface to the system's uname command.
931 """
932 if sys.platform in ('dos','win32','win16','os2'):
933 # XXX Others too ?
934 return default
935 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000936 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000937 except (AttributeError,os.error):
938 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000939 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000940 rc = f.close()
941 if not output or rc:
942 return default
943 else:
944 return output
945
946def _syscmd_file(target,default=''):
947
948 """ Interface to the system's file command.
949
950 The function uses the -b option of the file command to have it
951 ommit the filename in its output and if possible the -L option
952 to have the command follow symlinks. It returns default in
953 case the command should fail.
954
955 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000956 if sys.platform in ('dos','win32','win16','os2'):
957 # XXX Others too ?
958 return default
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000959 target = _follow_symlinks(target)
960 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000961 f = os.popen('file "%s" 2> %s' % (target, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000962 except (AttributeError,os.error):
963 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000964 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000965 rc = f.close()
966 if not output or rc:
967 return default
968 else:
969 return output
970
971### Information about the used architecture
972
973# Default values for architecture; non-empty strings override the
974# defaults given as parameters
975_default_architecture = {
976 'win32': ('','WindowsPE'),
977 'win16': ('','Windows'),
978 'dos': ('','MSDOS'),
979}
980
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000981_architecture_split = re.compile(r'[\s,]').split
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000982
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000983def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000984
985 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000986 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000987
Brett Cannon8ab27df2003-08-05 03:52:04 +0000988 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000989 the bit architecture and the linkage format used for the
990 executable. Both values are returned as strings.
991
992 Values that cannot be determined are returned as given by the
993 parameter presets. If bits is given as '', the sizeof(pointer)
994 (or sizeof(long) on Python version < 1.5.2) is used as
995 indicator for the supported pointer size.
996
997 The function relies on the system's "file" command to do the
998 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000999 platforms. On some non-Unix platforms where the "file" command
1000 does not exist and the executable is set to the Python interpreter
1001 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001002
1003 """
1004 # Use the sizeof(pointer) as default number of bits if nothing
1005 # else is given as default.
1006 if not bits:
1007 import struct
1008 try:
1009 size = struct.calcsize('P')
1010 except struct.error:
1011 # Older installations can only query longs
1012 size = struct.calcsize('l')
1013 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001014
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001015 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001016 if executable:
1017 output = _syscmd_file(executable, '')
1018 else:
1019 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001020
1021 if not output and \
1022 executable == sys.executable:
1023 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001024 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +00001025 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001026 b,l = _default_architecture[sys.platform]
1027 if b:
1028 bits = b
1029 if l:
1030 linkage = l
1031 return bits,linkage
1032
1033 # Split the output into a list of strings omitting the filename
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001034 fileout = _architecture_split(output)[1:]
Tim Peters0eadaac2003-04-24 16:02:54 +00001035
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001036 if 'executable' not in fileout:
1037 # Format not supported
1038 return bits,linkage
1039
1040 # Bits
1041 if '32-bit' in fileout:
1042 bits = '32bit'
1043 elif 'N32' in fileout:
1044 # On Irix only
1045 bits = 'n32bit'
1046 elif '64-bit' in fileout:
1047 bits = '64bit'
1048
1049 # Linkage
1050 if 'ELF' in fileout:
1051 linkage = 'ELF'
1052 elif 'PE' in fileout:
1053 # E.g. Windows uses this format
1054 if 'Windows' in fileout:
1055 linkage = 'WindowsPE'
1056 else:
1057 linkage = 'PE'
1058 elif 'COFF' in fileout:
1059 linkage = 'COFF'
1060 elif 'MS-DOS' in fileout:
1061 linkage = 'MSDOS'
1062 else:
1063 # XXX the A.OUT format also falls under this class...
1064 pass
1065
1066 return bits,linkage
1067
1068### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001069
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001070_uname_cache = None
1071
1072def uname():
1073
1074 """ Fairly portable uname interface. Returns a tuple
1075 of strings (system,node,release,version,machine,processor)
1076 identifying the underlying platform.
1077
1078 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001079 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001080
1081 Entries which cannot be determined are set to ''.
1082
1083 """
1084 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001085 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001086
1087 if _uname_cache is not None:
1088 return _uname_cache
1089
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001090 processor = ''
1091
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001092 # Get some infos from the builtin os.uname API...
1093 try:
1094 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001095 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001096 no_os_uname = 1
1097
1098 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1099 # Hmm, no there is either no uname or uname has returned
1100 #'unknowns'... we'll have to poke around the system then.
1101 if no_os_uname:
1102 system = sys.platform
1103 release = ''
1104 version = ''
1105 node = _node()
1106 machine = ''
1107
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001108 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001109
1110 # Try win32_ver() on win32 platforms
1111 if system == 'win32':
1112 release,version,csd,ptype = win32_ver()
1113 if release and version:
1114 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001115 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001116 # available on Win XP and later; see
1117 # http://support.microsoft.com/kb/888731 and
1118 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001119 if not machine:
1120 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1121 if not processor:
1122 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001123
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001124 # Try the 'ver' system command available on some
1125 # platforms
1126 if use_syscmd_ver:
1127 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001128 # Normalize system to what win32_ver() normally returns
1129 # (_syscmd_ver() tends to return the vendor name as well)
1130 if system == 'Microsoft Windows':
1131 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001132 elif system == 'Microsoft' and release == 'Windows':
1133 # Under Windows Vista and Windows Server 2008,
1134 # Microsoft changed the output of the ver command. The
1135 # release is no longer printed. This causes the
1136 # system and release to be misidentified.
1137 system = 'Windows'
1138 if '6.0' == version[:3]:
1139 release = 'Vista'
1140 else:
1141 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001142
1143 # In case we still don't know anything useful, we'll try to
1144 # help ourselves
1145 if system in ('win32','win16'):
1146 if not version:
1147 if system == 'win32':
1148 version = '32bit'
1149 else:
1150 version = '16bit'
1151 system = 'Windows'
1152
1153 elif system[:4] == 'java':
1154 release,vendor,vminfo,osinfo = java_ver()
1155 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001156 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001157 if not version:
1158 version = vendor
1159
1160 elif os.name == 'mac':
1161 release,(version,stage,nonrel),machine = mac_ver()
1162 system = 'MacOS'
1163
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001164 # System specific extensions
1165 if system == 'OpenVMS':
1166 # OpenVMS seems to have release and version mixed up
1167 if not release or release == '0':
1168 release = version
1169 version = ''
1170 # Get processor information
1171 try:
1172 import vms_lib
1173 except ImportError:
1174 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001175 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001176 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1177 if (cpu_number >= 128):
1178 processor = 'Alpha'
1179 else:
1180 processor = 'VAX'
1181 if not processor:
1182 # Get processor information from the uname system command
1183 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001184
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001185 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001186 if system == 'unknown':
1187 system = ''
1188 if node == 'unknown':
1189 node = ''
1190 if release == 'unknown':
1191 release = ''
1192 if version == 'unknown':
1193 version = ''
1194 if machine == 'unknown':
1195 machine = ''
1196 if processor == 'unknown':
1197 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001198
1199 # normalize name
1200 if system == 'Microsoft' and release == 'Windows':
1201 system = 'Windows'
1202 release = 'Vista'
1203
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001204 _uname_cache = system,node,release,version,machine,processor
1205 return _uname_cache
1206
1207### Direct interfaces to some of the uname() return values
1208
1209def system():
1210
1211 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1212
1213 An empty string is returned if the value cannot be determined.
1214
1215 """
1216 return uname()[0]
1217
1218def node():
1219
Brett Cannon8ab27df2003-08-05 03:52:04 +00001220 """ Returns the computer's network name (which may not be fully
1221 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001222
1223 An empty string is returned if the value cannot be determined.
1224
1225 """
1226 return uname()[1]
1227
1228def release():
1229
1230 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1231
1232 An empty string is returned if the value cannot be determined.
1233
1234 """
1235 return uname()[2]
1236
1237def version():
1238
1239 """ Returns the system's release version, e.g. '#3 on degas'
1240
1241 An empty string is returned if the value cannot be determined.
1242
1243 """
1244 return uname()[3]
1245
1246def machine():
1247
1248 """ Returns the machine type, e.g. 'i386'
1249
1250 An empty string is returned if the value cannot be determined.
1251
1252 """
1253 return uname()[4]
1254
1255def processor():
1256
1257 """ Returns the (true) processor name, e.g. 'amdk6'
1258
1259 An empty string is returned if the value cannot be
1260 determined. Note that many platforms do not provide this
1261 information or simply return the same value as for machine(),
1262 e.g. NetBSD does this.
1263
1264 """
1265 return uname()[5]
1266
1267### Various APIs for extracting information from sys.version
1268
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001269_sys_version_parser = re.compile(
1270 r'([\w.+]+)\s*'
1271 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001272 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001273
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001274_ironpython_sys_version_parser = re.compile(
1275 r'IronPython\s*'
1276 '([\d\.]+)'
1277 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001278 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001279
Benjamin Petersone549ead2009-03-28 21:42:05 +00001280_pypy_sys_version_parser = re.compile(
1281 r'([\w.+]+)\s*'
1282 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1283 '\[PyPy [^\]]+\]?')
1284
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001285_sys_version_cache = {}
1286
1287def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001288
1289 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001290 (name, version, branch, revision, buildno, builddate, compiler)
1291 referring to the Python implementation name, version, branch,
1292 revision, build number, build date/time as string and the compiler
1293 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001294
1295 Note that unlike the Python sys.version, the returned value
1296 for the Python version will always include the patchlevel (it
1297 defaults to '.0').
1298
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001299 The function returns empty strings for tuple entries that
1300 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001301
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001302 sys_version may be given to parse an alternative version
1303 string, e.g. if the version was read from a different Python
1304 interpreter.
1305
1306 """
1307 # Get the Python version
1308 if sys_version is None:
1309 sys_version = sys.version
1310
1311 # Try the cache first
1312 result = _sys_version_cache.get(sys_version, None)
1313 if result is not None:
1314 return result
1315
1316 # Parse it
1317 if sys_version[:10] == 'IronPython':
1318 # IronPython
1319 name = 'IronPython'
1320 match = _ironpython_sys_version_parser.match(sys_version)
1321 if match is None:
1322 raise ValueError(
1323 'failed to parse IronPython sys.version: %s' %
1324 repr(sys_version))
1325 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001326 buildno = ''
1327 builddate = ''
1328
1329 elif sys.platform[:4] == 'java':
1330 # Jython
1331 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001332 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001333 if match is None:
1334 raise ValueError(
1335 'failed to parse Jython sys.version: %s' %
1336 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001337 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001338 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001339
1340 elif "PyPy" in sys_version:
1341 # PyPy
1342 name = "PyPy"
1343 match = _pypy_sys_version_parser.match(sys_version)
1344 if match is None:
1345 raise ValueError("failed to parse PyPy sys.version: %s" %
1346 repr(sys_version))
1347 version, buildno, builddate, buildtime = match.groups()
1348 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001349
1350 else:
1351 # CPython
1352 match = _sys_version_parser.match(sys_version)
1353 if match is None:
1354 raise ValueError(
1355 'failed to parse CPython sys.version: %s' %
1356 repr(sys_version))
1357 version, buildno, builddate, buildtime, compiler = \
1358 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001359 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001360 builddate = builddate + ' ' + buildtime
1361
Benjamin Petersone549ead2009-03-28 21:42:05 +00001362 if hasattr(sys, 'subversion'):
1363 # sys.subversion was added in Python 2.5
1364 _, branch, revision = sys.subversion
1365 else:
1366 branch = ''
1367 revision = ''
1368
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001369 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001370 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001371 if len(l) == 2:
1372 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001373 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001374
1375 # Build and cache the result
1376 result = (name, version, branch, revision, buildno, builddate, compiler)
1377 _sys_version_cache[sys_version] = result
1378 return result
1379
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001380def python_implementation():
1381
1382 """ Returns a string identifying the Python implementation.
1383
1384 Currently, the following implementations are identified:
1385 'CPython' (C implementation of Python),
1386 'IronPython' (.NET implementation of Python),
1387 'Jython' (Java implementation of Python).
1388
1389 """
1390 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001391
1392def python_version():
1393
1394 """ Returns the Python version as string 'major.minor.patchlevel'
1395
1396 Note that unlike the Python sys.version, the returned value
1397 will always include the patchlevel (it defaults to 0).
1398
1399 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001400 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401
1402def python_version_tuple():
1403
1404 """ Returns the Python version as tuple (major, minor, patchlevel)
1405 of strings.
1406
1407 Note that unlike the Python sys.version, the returned value
1408 will always include the patchlevel (it defaults to 0).
1409
1410 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001411 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001412
1413def python_branch():
1414
1415 """ Returns a string identifying the Python implementation
1416 branch.
1417
1418 For CPython this is the Subversion branch from which the
1419 Python binary was built.
1420
1421 If not available, an empty string is returned.
1422
1423 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001424
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001425 return _sys_version()[2]
1426
1427def python_revision():
1428
1429 """ Returns a string identifying the Python implementation
1430 revision.
1431
1432 For CPython this is the Subversion revision from which the
1433 Python binary was built.
1434
1435 If not available, an empty string is returned.
1436
1437 """
1438 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001439
1440def python_build():
1441
1442 """ Returns a tuple (buildno, builddate) stating the Python
1443 build number and date as strings.
1444
1445 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001446 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001447
1448def python_compiler():
1449
1450 """ Returns a string identifying the compiler used for compiling
1451 Python.
1452
1453 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001454 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001455
1456### The Opus Magnum of platform strings :-)
1457
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001458_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001459
1460def platform(aliased=0, terse=0):
1461
1462 """ Returns a single string identifying the underlying platform
1463 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001464
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001465 The output is intended to be human readable rather than
1466 machine parseable. It may look different on different
1467 platforms and this is intended.
1468
1469 If "aliased" is true, the function will use aliases for
1470 various platforms that report system names which differ from
1471 their common names, e.g. SunOS will be reported as
1472 Solaris. The system_alias() function is used to implement
1473 this.
1474
1475 Setting terse to true causes the function to return only the
1476 absolute minimum information needed to identify the platform.
1477
1478 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001479 result = _platform_cache.get((aliased, terse), None)
1480 if result is not None:
1481 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001482
1483 # Get uname information and then apply platform specific cosmetics
1484 # to it...
1485 system,node,release,version,machine,processor = uname()
1486 if machine == processor:
1487 processor = ''
1488 if aliased:
1489 system,release,version = system_alias(system,release,version)
1490
1491 if system == 'Windows':
1492 # MS platforms
1493 rel,vers,csd,ptype = win32_ver(version)
1494 if terse:
1495 platform = _platform(system,release)
1496 else:
1497 platform = _platform(system,release,version,csd)
1498
1499 elif system in ('Linux',):
1500 # Linux based systems
1501 distname,distversion,distid = dist('')
1502 if distname and not terse:
1503 platform = _platform(system,release,machine,processor,
1504 'with',
1505 distname,distversion,distid)
1506 else:
1507 # If the distribution name is unknown check for libc vs. glibc
1508 libcname,libcversion = libc_ver(sys.executable)
1509 platform = _platform(system,release,machine,processor,
1510 'with',
1511 libcname+libcversion)
1512 elif system == 'Java':
1513 # Java platforms
1514 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001515 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001516 platform = _platform(system,release,version)
1517 else:
1518 platform = _platform(system,release,version,
1519 'on',
1520 os_name,os_version,os_arch)
1521
1522 elif system == 'MacOS':
1523 # MacOS platforms
1524 if terse:
1525 platform = _platform(system,release)
1526 else:
1527 platform = _platform(system,release,machine)
1528
1529 else:
1530 # Generic handler
1531 if terse:
1532 platform = _platform(system,release)
1533 else:
1534 bits,linkage = architecture(sys.executable)
1535 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001536
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001537 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001538 return platform
1539
1540### Command line interface
1541
1542if __name__ == '__main__':
1543 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001544 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001545 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001546 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001547 sys.exit(0)