blob: 81e31479db9cd53f69e679f6c750b976c2fe159e [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Marc-André Lemburg246d8472003-04-24 11:36:11 +00002
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 Peterson4ac9ce42009-10-04 14:49:41 +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#
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
Benjamin Peterson46a99002010-01-09 18:45:30 +000093 Copyright (c) 2000-2010, 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
Larry Hastings68386bc2012-06-24 14:30:41 -0700114import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200115import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000116
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000117### Globals & Constants
118
119# Determine the platform's /dev/null device
120try:
121 DEV_NULL = os.devnull
122except AttributeError:
123 # os.devnull was added in Python 2.4, so emulate it for earlier
124 # Python versions
Jesus Cea4791a242012-10-05 03:15:39 +0200125 if sys.platform in ('dos','win32','win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000126 # Use the old CP/M NUL as device name
127 DEV_NULL = 'NUL'
128 else:
129 # Standard Unix uses /dev/null
130 DEV_NULL = '/dev/null'
131
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000132### Platform specific APIs
133
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200134_libc_search = re.compile(b'(__libc_init)'
135 b'|'
136 b'(GLIBC_([0-9.]+))'
137 b'|'
138 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000139
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000140def libc_ver(executable=sys.executable,lib='',version='',
141
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200142 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000143
Brett Cannon8ab27df2003-08-05 03:52:04 +0000144 """ Tries to determine the libc version that the file executable
145 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000146
147 Returns a tuple of strings (lib,version) which default to the
148 given parameters in case the lookup fails.
149
150 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000151 libc versions add symbols to the executable and thus is probably
152 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000153
154 The file is read and scanned in chunks of chunksize bytes.
155
156 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000157 if hasattr(os.path, 'realpath'):
158 # Python 2.2 introduced os.path.realpath(); it is used
159 # here to work around problems with Cygwin not being
160 # able to open symlinks for reading
161 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000162 f = open(executable,'rb')
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200163 binary = f.read(chunksize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000164 pos = 0
165 while 1:
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200166 if b'libc' in binary or b'GLIBC' in binary:
167 m = _libc_search.search(binary,pos)
168 else:
169 m = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000170 if not m:
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200171 binary = f.read(chunksize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000172 if not binary:
173 break
174 pos = 0
175 continue
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200176 libcinit,glibc,glibcversion,so,threads,soversion = [
177 s.decode('latin1') if s is not None else s
178 for s in m.groups()]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000179 if libcinit and not lib:
180 lib = 'libc'
181 elif glibc:
182 if lib != 'glibc':
183 lib = 'glibc'
184 version = glibcversion
185 elif glibcversion > version:
186 version = glibcversion
187 elif so:
188 if lib != 'glibc':
189 lib = 'libc'
Victor Stinner87448812011-12-15 21:42:03 +0100190 if soversion and soversion > version:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000191 version = soversion
192 if threads and version[-len(threads):] != threads:
193 version = version + threads
194 pos = m.end()
195 f.close()
196 return lib,version
197
198def _dist_try_harder(distname,version,id):
199
Tim Peters0eadaac2003-04-24 16:02:54 +0000200 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000201 information in case the default method fails.
202
203 Currently supports older SuSE Linux, Caldera OpenLinux and
204 Slackware Linux distributions.
205
206 """
207 if os.path.exists('/var/adm/inst-log/info'):
208 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000209 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000210 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000211 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000212 if len(tv) == 2:
213 tag,value = tv
214 else:
215 continue
216 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000217 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000218 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000219 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000220 id = values[2]
221 return distname,version,id
222
223 if os.path.exists('/etc/.installed'):
224 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000225 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000226 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000227 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
228 # XXX does Caldera support non Intel platforms ? If yes,
229 # where can we find the needed id ?
230 return 'OpenLinux',pkg[1],id
231
232 if os.path.isdir('/usr/lib/setup'):
233 # Check for slackware verson tag file (thanks to Greg Andruk)
234 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000235 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000236 if verfiles[n][:14] != 'slack-version-':
237 del verfiles[n]
238 if verfiles:
239 verfiles.sort()
240 distname = 'slackware'
241 version = verfiles[-1][14:]
242 return distname,version,id
243
244 return distname,version,id
245
Antoine Pitroufd036452008-08-19 17:56:33 +0000246_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000247_lsb_release_version = re.compile(r'(.+)'
248 ' release '
249 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000250 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000251_release_version = re.compile(r'([^0-9]+)'
252 '(?: release )?'
253 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000254 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000255
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000256# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000257# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000258# and http://data.linux-ntfs.org/rpm/whichrpm
259# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000260
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000261_supported_dists = (
262 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
263 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200264 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000265
266def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000267
Benjamin Peterson25001472010-01-25 03:37:42 +0000268 # Default to empty 'version' and 'id' strings. Both defaults are used
269 # when 'firstline' is empty. 'id' defaults to empty when an id can not
270 # be deduced.
271 version = ''
272 id = ''
273
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000274 # Parse the first line
275 m = _lsb_release_version.match(firstline)
276 if m is not None:
277 # LSB format: "distro release x.x (codename)"
278 return tuple(m.groups())
279
280 # Pre-LSB format: "distro x.x (codename)"
281 m = _release_version.match(firstline)
282 if m is not None:
283 return tuple(m.groups())
284
285 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000286 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000287 if l:
288 version = l[0]
289 if len(l) > 1:
290 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000291 return '', version, id
292
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000293def linux_distribution(distname='', version='', id='',
294
295 supported_dists=_supported_dists,
296 full_distribution_name=1):
297
298 """ Tries to determine the name of the Linux OS distribution name.
299
300 The function first looks for a distribution release file in
301 /etc and then reverts to _dist_try_harder() in case no
302 suitable files are found.
303
304 supported_dists may be given to define the set of Linux
305 distributions to look for. It defaults to a list of currently
306 supported Linux distributions identified by their release file
307 name.
308
309 If full_distribution_name is true (default), the full
310 distribution read from the OS is returned. Otherwise the short
311 name taken from supported_dists is used.
312
313 Returns a tuple (distname,version,id) which default to the
314 args given as parameters.
315
316 """
317 try:
318 etc = os.listdir('/etc')
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200319 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000320 # Probably not a Unix system
321 return distname,version,id
322 etc.sort()
323 for file in etc:
324 m = _release_filename.match(file)
325 if m is not None:
326 _distname,dummy = m.groups()
327 if _distname in supported_dists:
328 distname = _distname
329 break
330 else:
331 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000332
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000333 # Read the first line
Florent Xicluna7dde7922010-09-03 19:52:03 +0000334 with open('/etc/'+file, 'r') as f:
335 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000336 _distname, _version, _id = _parse_release_file(firstline)
337
338 if _distname and full_distribution_name:
339 distname = _distname
340 if _version:
341 version = _version
342 if _id:
343 id = _id
344 return distname, version, id
345
346# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000347
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000348def dist(distname='',version='',id='',
349
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000350 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000351
Brett Cannon8ab27df2003-08-05 03:52:04 +0000352 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000353
354 The function first looks for a distribution release file in
355 /etc and then reverts to _dist_try_harder() in case no
356 suitable files are found.
357
Brett Cannon8ab27df2003-08-05 03:52:04 +0000358 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000359 args given as parameters.
360
361 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000362 return linux_distribution(distname, version, id,
363 supported_dists=supported_dists,
364 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000365
Antoine Pitrou877766d2011-03-19 17:00:37 +0100366def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000367
368 """ Portable popen() interface.
369 """
Victor Stinner25000d42011-05-24 00:16:16 +0200370 import warnings
371 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000372 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000373
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000374def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000375
Brett Cannon8ab27df2003-08-05 03:52:04 +0000376 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000377 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000378 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000379 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000380 if build:
381 l.append(build)
382 try:
383 ints = map(int,l)
384 except ValueError:
385 strings = l
386 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000387 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000388 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000389 return version
390
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000391_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
392 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000393 '\[.* ([\d.]+)\])')
394
395# Examples of VER command output:
396#
397# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
398# Windows XP: Microsoft Windows XP [Version 5.1.2600]
399# Windows Vista: Microsoft Windows [Version 6.0.6002]
400#
401# Note that the "Version" string gets localized on different
402# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000403
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000404def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000405
Jesus Ceaf1af7052012-10-05 02:48:46 +0200406 supported_platforms=('win32','win16','dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000407
408 """ Tries to figure out the OS version used and returns
409 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000410
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000411 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200412 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000413
414 In case this fails, the given parameters are used as
415 defaults.
416
417 """
418 if sys.platform not in supported_platforms:
419 return system,release,version
420
421 # Try some common cmd strings
422 for cmd in ('ver','command /c ver','cmd /c ver'):
423 try:
424 pipe = popen(cmd)
425 info = pipe.read()
426 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200427 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200428 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000429 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200430 except OSError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000431 #print 'Command %s failed: %s' % (cmd,why)
432 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000433 else:
434 break
435 else:
436 return system,release,version
437
438 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000439 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000440 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000441 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000442 system,release,version = m.groups()
443 # Strip trailing dots from version and release
444 if release[-1] == '.':
445 release = release[:-1]
446 if version[-1] == '.':
447 version = version[:-1]
448 # Normalize the version and build strings (eliminating additional
449 # zeros)
450 version = _norm_version(version)
451 return system,release,version
452
453def _win32_getvalue(key,name,default=''):
454
455 """ Read a value for name from the registry key.
456
457 In case this fails, default is returned.
458
459 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000460 try:
461 # Use win32api if available
462 from win32api import RegQueryValueEx
Brett Cannoncd171c82013-07-04 17:43:24 -0400463 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000464 # On Python 2.0 and later, emulate using winreg
465 import winreg
466 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000467 try:
468 return RegQueryValueEx(key,name)
469 except:
470 return default
471
472def win32_ver(release='',version='',csd='',ptype=''):
473
474 """ Get additional version information from the Windows Registry
475 and return a tuple (version,csd,ptype) referring to version
Brian Curtin10dda6e2012-02-01 15:14:00 -0600476 number, CSD level (service pack), and OS type (multi/single
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000477 processor).
478
479 As a hint: ptype returns 'Uniprocessor Free' on single
480 processor NT machines and 'Multiprocessor Free' on multi
481 processor machines. The 'Free' refers to the OS version being
482 free of debugging code. It could also state 'Checked' which
483 means the OS version uses debugging code, i.e. code that
484 checks arguments, ranges, etc. (Thomas Heller).
485
Christian Heimes02781dc2008-03-21 01:11:52 +0000486 Note: this function works best with Mark Hammond's win32
487 package installed, but also on Python 2.3 and later. It
488 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000489
490 """
491 # XXX Is there any way to find out the processor type on WinXX ?
492 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000493 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000494 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000495 #
496 # The mappings between reg. values and release names can be found
497 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000498
499 # Import the needed APIs
500 try:
501 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000502 from win32api import RegQueryValueEx, RegOpenKeyEx, \
503 RegCloseKey, GetVersionEx
504 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
505 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Brett Cannoncd171c82013-07-04 17:43:24 -0400506 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000507 # Emulate the win32api module using Python APIs
508 try:
509 sys.getwindowsversion
510 except AttributeError:
511 # No emulation possible, so return the defaults...
512 return release,version,csd,ptype
513 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000514 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000515 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000516 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000517 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000518 RegQueryValueEx = winreg.QueryValueEx
519 RegOpenKeyEx = winreg.OpenKeyEx
520 RegCloseKey = winreg.CloseKey
521 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000522 VER_PLATFORM_WIN32_WINDOWS = 1
523 VER_PLATFORM_WIN32_NT = 2
524 VER_NT_WORKSTATION = 1
Brian Curtin6e2824d2010-05-06 03:05:50 +0000525 VER_NT_SERVER = 3
526 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000527
528 # Find out the registry key and some general version infos
Brian Curtin6e2824d2010-05-06 03:05:50 +0000529 winver = GetVersionEx()
530 maj,min,buildno,plat,csd = winver
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000531 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
Brian Curtin6e2824d2010-05-06 03:05:50 +0000532 if hasattr(winver, "service_pack"):
533 if winver.service_pack != "":
534 csd = 'SP%s' % winver.service_pack_major
535 else:
536 if csd[:13] == 'Service Pack ':
537 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000538
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000539 if plat == VER_PLATFORM_WIN32_WINDOWS:
540 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
541 # Try to guess the release name
542 if maj == 4:
543 if min == 0:
544 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000545 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000546 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000547 elif min == 90:
548 release = 'Me'
549 else:
550 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000551 elif maj == 5:
552 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000553
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000554 elif plat == VER_PLATFORM_WIN32_NT:
555 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
556 if maj <= 4:
557 release = 'NT'
558 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000559 if min == 0:
560 release = '2000'
561 elif min == 1:
562 release = 'XP'
563 elif min == 2:
564 release = '2003Server'
565 else:
566 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000567 elif maj == 6:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000568 if hasattr(winver, "product_type"):
569 product_type = winver.product_type
570 else:
571 product_type = VER_NT_WORKSTATION
572 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
573 # or help from the registry, we cannot properly identify
574 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000575 try:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000576 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
577 name, type = RegQueryValueEx(key, "ProductName")
578 # Discard any type that isn't REG_SZ
579 if type == REG_SZ and name.find("Server") != -1:
580 product_type = VER_NT_SERVER
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200581 except OSError:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000582 # Use default of VER_NT_WORKSTATION
583 pass
584
585 if min == 0:
586 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000587 release = 'Vista'
588 else:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000589 release = '2008Server'
590 elif min == 1:
591 if product_type == VER_NT_WORKSTATION:
592 release = '7'
593 else:
594 release = '2008ServerR2'
Brian Curtin0b960f52012-10-11 16:07:52 -0500595 elif min == 2:
596 if product_type == VER_NT_WORKSTATION:
597 release = '8'
598 else:
599 release = '2012Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000600 else:
Brian Curtin0b960f52012-10-11 16:07:52 -0500601 release = 'post2012Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000602
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000603 else:
604 if not release:
605 # E.g. Win3.1 with win32s
606 release = '%i.%i' % (maj,min)
607 return release,version,csd,ptype
608
609 # Open the registry key
610 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000611 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000612 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000613 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000614 except:
615 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000616
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000617 # Parse values
618 #subversion = _win32_getvalue(keyCurVer,
619 # 'SubVersionNumber',
620 # ('',1))[0]
621 #if subversion:
622 # release = release + subversion # 95a, 95b, etc.
623 build = _win32_getvalue(keyCurVer,
624 'CurrentBuildNumber',
625 ('',1))[0]
626 ptype = _win32_getvalue(keyCurVer,
627 'CurrentType',
628 (ptype,1))[0]
629
630 # Normalize version
631 version = _norm_version(version,build)
632
633 # Close key
634 RegCloseKey(keyCurVer)
635 return release,version,csd,ptype
636
Ronald Oussorene186e382010-07-23 11:54:59 +0000637def _mac_ver_xml():
638 fn = '/System/Library/CoreServices/SystemVersion.plist'
639 if not os.path.exists(fn):
640 return None
641
642 try:
643 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400644 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000645 return None
646
647 pl = plistlib.readPlist(fn)
648 release = pl['ProductVersion']
649 versioninfo=('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700650 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000651 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussoren0fedb372013-07-15 18:32:09 +0200652 # Cannonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000653 machine = 'PowerPC'
654
655 return release,versioninfo,machine
656
657
658def mac_ver(release='',versioninfo=('','',''),machine=''):
659
660 """ Get MacOS version information and return it as tuple (release,
661 versioninfo, machine) with versioninfo being a tuple (version,
662 dev_stage, non_release_version).
663
664 Entries which cannot be determined are set to the paramter values
665 which default to ''. All tuple entries are strings.
666 """
667
668 # First try reading the information from an XML file which should
669 # always be present
670 info = _mac_ver_xml()
671 if info is not None:
672 return info
673
Ronald Oussorene186e382010-07-23 11:54:59 +0000674 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000675 return release,versioninfo,machine
676
Neal Norwitz9b924c62003-06-29 04:17:45 +0000677def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000678
679 from java.lang import System
680 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000681 value = System.getProperty(name)
682 if value is None:
683 return default
684 return value
685 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686 return default
687
688def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000689
Brett Cannon8ab27df2003-08-05 03:52:04 +0000690 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000691
692 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
693 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
694 tuple (os_name,os_version,os_arch).
695
696 Values which cannot be determined are set to the defaults
697 given as parameters (which all default to '').
698
699 """
700 # Import the needed APIs
701 try:
702 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400703 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000704 return release,vendor,vminfo,osinfo
705
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000706 vendor = _java_getprop('java.vendor', vendor)
707 release = _java_getprop('java.version', release)
708 vm_name, vm_release, vm_vendor = vminfo
709 vm_name = _java_getprop('java.vm.name', vm_name)
710 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
711 vm_release = _java_getprop('java.vm.version', vm_release)
712 vminfo = vm_name, vm_release, vm_vendor
713 os_name, os_version, os_arch = osinfo
714 os_arch = _java_getprop('java.os.arch', os_arch)
715 os_name = _java_getprop('java.os.name', os_name)
716 os_version = _java_getprop('java.os.version', os_version)
717 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000718
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000719 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000720
721### System name aliasing
722
723def system_alias(system,release,version):
724
725 """ Returns (system,release,version) aliased to common
726 marketing names used for some systems.
727
728 It also does some reordering of the information in some cases
729 where it would otherwise cause confusion.
730
731 """
732 if system == 'Rhapsody':
733 # Apple's BSD derivative
734 # XXX How can we determine the marketing release number ?
735 return 'MacOS X Server',system+release,version
736
737 elif system == 'SunOS':
738 # Sun's OS
739 if release < '5':
740 # These releases use the old name SunOS
741 return system,release,version
742 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000743 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744 if l:
745 try:
746 major = int(l[0])
747 except ValueError:
748 pass
749 else:
750 major = major - 3
751 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000752 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000753 if release < '6':
754 system = 'Solaris'
755 else:
756 # XXX Whatever the new SunOS marketing name is...
757 system = 'Solaris'
758
759 elif system == 'IRIX64':
760 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
761 # is really a version and not a different platform, since 32-bit
762 # apps are also supported..
763 system = 'IRIX'
764 if version:
765 version = version + ' (64bit)'
766 else:
767 version = '64bit'
768
769 elif system in ('win32','win16'):
770 # In case one of the other tricks
771 system = 'Windows'
772
773 return system,release,version
774
775### Various internal helpers
776
777def _platform(*args):
778
779 """ Helper to format the platform string in a filename
780 compatible format e.g. "system-version-machine".
781 """
782 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000783 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000784
785 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000786 platform = platform.replace(' ','_')
787 platform = platform.replace('/','-')
788 platform = platform.replace('\\','-')
789 platform = platform.replace(':','-')
790 platform = platform.replace(';','-')
791 platform = platform.replace('"','-')
792 platform = platform.replace('(','-')
793 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000794
795 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000796 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000797
798 # Fold '--'s and remove trailing '-'
799 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000800 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000801 if cleaned == platform:
802 break
803 platform = cleaned
804 while platform[-1] == '-':
805 platform = platform[:-1]
806
807 return platform
808
809def _node(default=''):
810
811 """ Helper to determine the node name of this machine.
812 """
813 try:
814 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400815 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000816 # No sockets...
817 return default
818 try:
819 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200820 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821 # Still not working...
822 return default
823
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000824def _follow_symlinks(filepath):
825
826 """ In case filepath is a symlink, follow it until a
827 real file is reached.
828 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000829 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000830 while os.path.islink(filepath):
831 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000832 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000833 return filepath
834
835def _syscmd_uname(option,default=''):
836
837 """ Interface to the system's uname command.
838 """
Jesus Cea4791a242012-10-05 03:15:39 +0200839 if sys.platform in ('dos','win32','win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840 # XXX Others too ?
841 return default
842 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000843 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200844 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000845 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000846 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000847 rc = f.close()
848 if not output or rc:
849 return default
850 else:
851 return output
852
853def _syscmd_file(target,default=''):
854
855 """ Interface to the system's file command.
856
857 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000858 omit the filename in its output. Follow the symlinks. It returns
859 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000860
861 """
Jesus Cea4791a242012-10-05 03:15:39 +0200862 if sys.platform in ('dos','win32','win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000863 # XXX Others too ?
864 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200865 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000866 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200867 proc = subprocess.Popen(['file', target],
868 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200869
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200870 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000871 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200872 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200873 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000874 if not output or rc:
875 return default
876 else:
877 return output
878
879### Information about the used architecture
880
881# Default values for architecture; non-empty strings override the
882# defaults given as parameters
883_default_architecture = {
884 'win32': ('','WindowsPE'),
885 'win16': ('','Windows'),
886 'dos': ('','MSDOS'),
887}
888
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000889def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000890
891 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000892 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000893
Brett Cannon8ab27df2003-08-05 03:52:04 +0000894 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000895 the bit architecture and the linkage format used for the
896 executable. Both values are returned as strings.
897
898 Values that cannot be determined are returned as given by the
899 parameter presets. If bits is given as '', the sizeof(pointer)
900 (or sizeof(long) on Python version < 1.5.2) is used as
901 indicator for the supported pointer size.
902
903 The function relies on the system's "file" command to do the
904 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000905 platforms. On some non-Unix platforms where the "file" command
906 does not exist and the executable is set to the Python interpreter
907 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000908
909 """
910 # Use the sizeof(pointer) as default number of bits if nothing
911 # else is given as default.
912 if not bits:
913 import struct
914 try:
915 size = struct.calcsize('P')
916 except struct.error:
917 # Older installations can only query longs
918 size = struct.calcsize('l')
919 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000920
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000921 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000922 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000923 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000924 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000925 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000926
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000927 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000928 executable == sys.executable:
929 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000930 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000931 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000932 b,l = _default_architecture[sys.platform]
933 if b:
934 bits = b
935 if l:
936 linkage = l
937 return bits,linkage
938
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000939 if 'executable' not in fileout:
940 # Format not supported
941 return bits,linkage
942
943 # Bits
944 if '32-bit' in fileout:
945 bits = '32bit'
946 elif 'N32' in fileout:
947 # On Irix only
948 bits = 'n32bit'
949 elif '64-bit' in fileout:
950 bits = '64bit'
951
952 # Linkage
953 if 'ELF' in fileout:
954 linkage = 'ELF'
955 elif 'PE' in fileout:
956 # E.g. Windows uses this format
957 if 'Windows' in fileout:
958 linkage = 'WindowsPE'
959 else:
960 linkage = 'PE'
961 elif 'COFF' in fileout:
962 linkage = 'COFF'
963 elif 'MS-DOS' in fileout:
964 linkage = 'MSDOS'
965 else:
966 # XXX the A.OUT format also falls under this class...
967 pass
968
969 return bits,linkage
970
971### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000972
Larry Hastings68386bc2012-06-24 14:30:41 -0700973uname_result = collections.namedtuple("uname_result",
974 "system node release version machine processor")
975
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000976_uname_cache = None
977
978def uname():
979
980 """ Fairly portable uname interface. Returns a tuple
981 of strings (system,node,release,version,machine,processor)
982 identifying the underlying platform.
983
984 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000985 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000986
987 Entries which cannot be determined are set to ''.
988
989 """
990 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000991 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000992
993 if _uname_cache is not None:
994 return _uname_cache
995
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000996 processor = ''
997
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000998 # Get some infos from the builtin os.uname API...
999 try:
1000 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001001 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001002 no_os_uname = 1
1003
Georg Brandl62e2ca22010-07-31 21:54:24 +00001004 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001005 # Hmm, no there is either no uname or uname has returned
1006 #'unknowns'... we'll have to poke around the system then.
1007 if no_os_uname:
1008 system = sys.platform
1009 release = ''
1010 version = ''
1011 node = _node()
1012 machine = ''
1013
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001014 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001015
1016 # Try win32_ver() on win32 platforms
1017 if system == 'win32':
1018 release,version,csd,ptype = win32_ver()
1019 if release and version:
1020 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001021 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001022 # available on Win XP and later; see
1023 # http://support.microsoft.com/kb/888731 and
1024 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001025 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001026 # WOW64 processes mask the native architecture
1027 if "PROCESSOR_ARCHITEW6432" in os.environ:
1028 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1029 else:
1030 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001031 if not processor:
1032 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001033
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001034 # Try the 'ver' system command available on some
1035 # platforms
1036 if use_syscmd_ver:
1037 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001038 # Normalize system to what win32_ver() normally returns
1039 # (_syscmd_ver() tends to return the vendor name as well)
1040 if system == 'Microsoft Windows':
1041 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001042 elif system == 'Microsoft' and release == 'Windows':
1043 # Under Windows Vista and Windows Server 2008,
1044 # Microsoft changed the output of the ver command. The
1045 # release is no longer printed. This causes the
1046 # system and release to be misidentified.
1047 system = 'Windows'
1048 if '6.0' == version[:3]:
1049 release = 'Vista'
1050 else:
1051 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001052
1053 # In case we still don't know anything useful, we'll try to
1054 # help ourselves
1055 if system in ('win32','win16'):
1056 if not version:
1057 if system == 'win32':
1058 version = '32bit'
1059 else:
1060 version = '16bit'
1061 system = 'Windows'
1062
1063 elif system[:4] == 'java':
1064 release,vendor,vminfo,osinfo = java_ver()
1065 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001066 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067 if not version:
1068 version = vendor
1069
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001070 # System specific extensions
1071 if system == 'OpenVMS':
1072 # OpenVMS seems to have release and version mixed up
1073 if not release or release == '0':
1074 release = version
1075 version = ''
1076 # Get processor information
1077 try:
1078 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001079 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001080 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001081 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001082 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1083 if (cpu_number >= 128):
1084 processor = 'Alpha'
1085 else:
1086 processor = 'VAX'
1087 if not processor:
1088 # Get processor information from the uname system command
1089 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001090
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001091 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001092 if system == 'unknown':
1093 system = ''
1094 if node == 'unknown':
1095 node = ''
1096 if release == 'unknown':
1097 release = ''
1098 if version == 'unknown':
1099 version = ''
1100 if machine == 'unknown':
1101 machine = ''
1102 if processor == 'unknown':
1103 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001104
1105 # normalize name
1106 if system == 'Microsoft' and release == 'Windows':
1107 system = 'Windows'
1108 release = 'Vista'
1109
Larry Hastings68386bc2012-06-24 14:30:41 -07001110 _uname_cache = uname_result(system,node,release,version,machine,processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001111 return _uname_cache
1112
1113### Direct interfaces to some of the uname() return values
1114
1115def system():
1116
1117 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1118
1119 An empty string is returned if the value cannot be determined.
1120
1121 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001122 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001123
1124def node():
1125
Brett Cannon8ab27df2003-08-05 03:52:04 +00001126 """ Returns the computer's network name (which may not be fully
1127 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001128
1129 An empty string is returned if the value cannot be determined.
1130
1131 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001132 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001133
1134def release():
1135
1136 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1137
1138 An empty string is returned if the value cannot be determined.
1139
1140 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001141 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001142
1143def version():
1144
1145 """ Returns the system's release version, e.g. '#3 on degas'
1146
1147 An empty string is returned if the value cannot be determined.
1148
1149 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001150 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001151
1152def machine():
1153
1154 """ Returns the machine type, e.g. 'i386'
1155
1156 An empty string is returned if the value cannot be determined.
1157
1158 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001159 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001160
1161def processor():
1162
1163 """ Returns the (true) processor name, e.g. 'amdk6'
1164
1165 An empty string is returned if the value cannot be
1166 determined. Note that many platforms do not provide this
1167 information or simply return the same value as for machine(),
1168 e.g. NetBSD does this.
1169
1170 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001171 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001172
1173### Various APIs for extracting information from sys.version
1174
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001175_sys_version_parser = re.compile(
1176 r'([\w.+]+)\s*'
1177 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001178 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001179
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001180_ironpython_sys_version_parser = re.compile(
1181 r'IronPython\s*'
1182 '([\d\.]+)'
1183 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001184 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001185
Benjamin Petersone549ead2009-03-28 21:42:05 +00001186_pypy_sys_version_parser = re.compile(
1187 r'([\w.+]+)\s*'
1188 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1189 '\[PyPy [^\]]+\]?')
1190
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001191_sys_version_cache = {}
1192
1193def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001194
1195 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001196 (name, version, branch, revision, buildno, builddate, compiler)
1197 referring to the Python implementation name, version, branch,
1198 revision, build number, build date/time as string and the compiler
1199 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001200
1201 Note that unlike the Python sys.version, the returned value
1202 for the Python version will always include the patchlevel (it
1203 defaults to '.0').
1204
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001205 The function returns empty strings for tuple entries that
1206 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001207
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001208 sys_version may be given to parse an alternative version
1209 string, e.g. if the version was read from a different Python
1210 interpreter.
1211
1212 """
1213 # Get the Python version
1214 if sys_version is None:
1215 sys_version = sys.version
1216
1217 # Try the cache first
1218 result = _sys_version_cache.get(sys_version, None)
1219 if result is not None:
1220 return result
1221
1222 # Parse it
1223 if sys_version[:10] == 'IronPython':
1224 # IronPython
1225 name = 'IronPython'
1226 match = _ironpython_sys_version_parser.match(sys_version)
1227 if match is None:
1228 raise ValueError(
1229 'failed to parse IronPython sys.version: %s' %
1230 repr(sys_version))
1231 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001232 buildno = ''
1233 builddate = ''
1234
1235 elif sys.platform[:4] == 'java':
1236 # Jython
1237 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001238 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001239 if match is None:
1240 raise ValueError(
1241 'failed to parse Jython sys.version: %s' %
1242 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001243 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001244 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001245
1246 elif "PyPy" in sys_version:
1247 # PyPy
1248 name = "PyPy"
1249 match = _pypy_sys_version_parser.match(sys_version)
1250 if match is None:
1251 raise ValueError("failed to parse PyPy sys.version: %s" %
1252 repr(sys_version))
1253 version, buildno, builddate, buildtime = match.groups()
1254 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001255
1256 else:
1257 # CPython
1258 match = _sys_version_parser.match(sys_version)
1259 if match is None:
1260 raise ValueError(
1261 'failed to parse CPython sys.version: %s' %
1262 repr(sys_version))
1263 version, buildno, builddate, buildtime, compiler = \
1264 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001265 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001266 builddate = builddate + ' ' + buildtime
1267
Georg Brandl82562422011-03-05 21:09:22 +01001268 if hasattr(sys, '_mercurial'):
1269 _, branch, revision = sys._mercurial
1270 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001271 # sys.subversion was added in Python 2.5
1272 _, branch, revision = sys.subversion
1273 else:
1274 branch = ''
1275 revision = ''
1276
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001277 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001278 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001279 if len(l) == 2:
1280 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001281 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001282
1283 # Build and cache the result
1284 result = (name, version, branch, revision, buildno, builddate, compiler)
1285 _sys_version_cache[sys_version] = result
1286 return result
1287
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001288def python_implementation():
1289
1290 """ Returns a string identifying the Python implementation.
1291
1292 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001293 'CPython' (C implementation of Python),
1294 'IronPython' (.NET implementation of Python),
1295 'Jython' (Java implementation of Python),
1296 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001297
1298 """
1299 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001300
1301def python_version():
1302
1303 """ Returns the Python version as string 'major.minor.patchlevel'
1304
1305 Note that unlike the Python sys.version, the returned value
1306 will always include the patchlevel (it defaults to 0).
1307
1308 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001309 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001310
1311def python_version_tuple():
1312
1313 """ Returns the Python version as tuple (major, minor, patchlevel)
1314 of strings.
1315
1316 Note that unlike the Python sys.version, the returned value
1317 will always include the patchlevel (it defaults to 0).
1318
1319 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001320 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001321
1322def python_branch():
1323
1324 """ Returns a string identifying the Python implementation
1325 branch.
1326
1327 For CPython this is the Subversion branch from which the
1328 Python binary was built.
1329
1330 If not available, an empty string is returned.
1331
1332 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001333
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001334 return _sys_version()[2]
1335
1336def python_revision():
1337
1338 """ Returns a string identifying the Python implementation
1339 revision.
1340
1341 For CPython this is the Subversion revision from which the
1342 Python binary was built.
1343
1344 If not available, an empty string is returned.
1345
1346 """
1347 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001348
1349def python_build():
1350
1351 """ Returns a tuple (buildno, builddate) stating the Python
1352 build number and date as strings.
1353
1354 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001355 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001356
1357def python_compiler():
1358
1359 """ Returns a string identifying the compiler used for compiling
1360 Python.
1361
1362 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001363 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001364
1365### The Opus Magnum of platform strings :-)
1366
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001367_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001368
1369def platform(aliased=0, terse=0):
1370
1371 """ Returns a single string identifying the underlying platform
1372 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001373
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001374 The output is intended to be human readable rather than
1375 machine parseable. It may look different on different
1376 platforms and this is intended.
1377
1378 If "aliased" is true, the function will use aliases for
1379 various platforms that report system names which differ from
1380 their common names, e.g. SunOS will be reported as
1381 Solaris. The system_alias() function is used to implement
1382 this.
1383
1384 Setting terse to true causes the function to return only the
1385 absolute minimum information needed to identify the platform.
1386
1387 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001388 result = _platform_cache.get((aliased, terse), None)
1389 if result is not None:
1390 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001391
1392 # Get uname information and then apply platform specific cosmetics
1393 # to it...
1394 system,node,release,version,machine,processor = uname()
1395 if machine == processor:
1396 processor = ''
1397 if aliased:
1398 system,release,version = system_alias(system,release,version)
1399
1400 if system == 'Windows':
1401 # MS platforms
1402 rel,vers,csd,ptype = win32_ver(version)
1403 if terse:
1404 platform = _platform(system,release)
1405 else:
1406 platform = _platform(system,release,version,csd)
1407
1408 elif system in ('Linux',):
1409 # Linux based systems
1410 distname,distversion,distid = dist('')
1411 if distname and not terse:
1412 platform = _platform(system,release,machine,processor,
1413 'with',
1414 distname,distversion,distid)
1415 else:
1416 # If the distribution name is unknown check for libc vs. glibc
1417 libcname,libcversion = libc_ver(sys.executable)
1418 platform = _platform(system,release,machine,processor,
1419 'with',
1420 libcname+libcversion)
1421 elif system == 'Java':
1422 # Java platforms
1423 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001424 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001425 platform = _platform(system,release,version)
1426 else:
1427 platform = _platform(system,release,version,
1428 'on',
1429 os_name,os_version,os_arch)
1430
1431 elif system == 'MacOS':
1432 # MacOS platforms
1433 if terse:
1434 platform = _platform(system,release)
1435 else:
1436 platform = _platform(system,release,machine)
1437
1438 else:
1439 # Generic handler
1440 if terse:
1441 platform = _platform(system,release)
1442 else:
1443 bits,linkage = architecture(sys.executable)
1444 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001445
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001446 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001447 return platform
1448
1449### Command line interface
1450
1451if __name__ == '__main__':
1452 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001453 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001454 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001455 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001456 sys.exit(0)