blob: 9f7b59f9e67ef5ad228e216f1f5a8cf083533081 [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:
Marc-André Lemburg246d8472003-04-24 11:36:11 +000016# * support for MS-DOS (PythonDX ?)
17# * support for Amiga and other still unsupported platforms running Python
18# * support for additional Linux distributions
19#
Brett Cannon8ab27df2003-08-05 03:52:04 +000020# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000021# checks (in no particular order):
22#
23# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
24# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
25# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
26# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
27# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Steve Dowerb9f4fea2015-09-22 17:23:39 -070028# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
29# Dower
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#
Steve Dowerb9f4fea2015-09-22 17:23:39 -070035# 1.0.8 - changed Windows support to read version from kernel32.dll
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000036# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000037# 1.0.6 - added linux_distribution()
38# 1.0.5 - fixed Java support to allow running the module on Jython
39# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000040# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000041# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000042# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000043# 1.0.0 - reformatted a bit and checked into Python CVS
44# 0.8.0 - added sys.version parser and various new access
45# APIs (python_version(), python_compiler(), etc.)
46# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
47# 0.7.1 - added support for Caldera OpenLinux
48# 0.7.0 - some fixes for WinCE; untabified the source file
49# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
50# vms_lib.getsyi() configured
51# 0.6.1 - added code to prevent 'uname -p' on platforms which are
52# known not to support it
53# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
54# did some cleanup of the interfaces - some APIs have changed
55# 0.5.5 - fixed another type in the MacOS code... should have
56# used more coffee today ;-)
57# 0.5.4 - fixed a few typos in the MacOS code
58# 0.5.3 - added experimental MacOS support; added better popen()
59# workarounds in _syscmd_ver() -- still not 100% elegant
60# though
61# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
62# return values (the system uname command tends to return
Martin Pantereb995702016-07-28 01:11:04 +000063# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000064# 0.5.1 - included code for slackware dist; added exception handlers
65# to cover up situations where platforms don't have os.popen
66# (e.g. Mac) or fail on socket.gethostname(); fixed libc
67# detection RE
68# 0.5.0 - changed the API names referring to system commands to *syscmd*;
69# added java_ver(); made syscmd_ver() a private
70# API (was system_ver() in previous versions) -- use uname()
71# instead; extended the win32_ver() to also return processor
72# type information
73# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
74# 0.3.4 - fixed a bug in _follow_symlinks()
75# 0.3.3 - fixed popen() and "file" command invokation bugs
76# 0.3.2 - added architecture() API and support for it in platform()
77# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
78# 0.3.0 - added system alias support
79# 0.2.3 - removed 'wince' again... oh well.
80# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
81# 0.2.1 - added cache logic and changed the platform string format
82# 0.2.0 - changed the API to use functions instead of module globals
83# since some action take too long to be run on module import
84# 0.1.0 - first release
85#
86# You can always get the latest version of this module at:
87#
88# http://www.egenix.com/files/python/platform.py
89#
90# If that URL should fail, try contacting the author.
91
92__copyright__ = """
93 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Peterson46a99002010-01-09 18:45:30 +000094 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000095
96 Permission to use, copy, modify, and distribute this software and its
97 documentation for any purpose and without fee or royalty is hereby granted,
98 provided that the above copyright notice appear in all copies and that
99 both that copyright notice and this permission notice appear in
100 supporting documentation or portions thereof, including modifications,
101 that you make.
102
103 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
104 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
105 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
106 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
107 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
108 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
109 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
110
111"""
112
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000113__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000114
Larry Hastings68386bc2012-06-24 14:30:41 -0700115import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200116import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000117
Berker Peksag1392f712015-05-16 20:24:28 +0300118import warnings
119
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000120### Globals & Constants
121
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100128 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
Victor Stinner620c48b2013-12-09 00:01:27 +0100135# Directory to search for configuration information on Unix.
136# Constant used by test_platform to test linux_distribution().
137_UNIXCONFDIR = '/etc'
138
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000139### Platform specific APIs
140
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200141_libc_search = re.compile(b'(__libc_init)'
142 b'|'
143 b'(GLIBC_([0-9.]+))'
144 b'|'
145 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000146
Victor Stinnerced39362013-12-09 00:14:52 +0100147def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000148
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200149 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000150
Brett Cannon8ab27df2003-08-05 03:52:04 +0000151 """ Tries to determine the libc version that the file executable
152 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000153
154 Returns a tuple of strings (lib,version) which default to the
155 given parameters in case the lookup fails.
156
157 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000158 libc versions add symbols to the executable and thus is probably
159 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000160
161 The file is read and scanned in chunks of chunksize bytes.
162
163 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000164 if hasattr(os.path, 'realpath'):
165 # Python 2.2 introduced os.path.realpath(); it is used
166 # here to work around problems with Cygwin not being
167 # able to open symlinks for reading
168 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300169 with open(executable, 'rb') as f:
170 binary = f.read(chunksize)
171 pos = 0
172 while 1:
173 if b'libc' in binary or b'GLIBC' in binary:
174 m = _libc_search.search(binary, pos)
175 else:
176 m = None
177 if not m:
178 binary = f.read(chunksize)
179 if not binary:
180 break
181 pos = 0
182 continue
183 libcinit, glibc, glibcversion, so, threads, soversion = [
184 s.decode('latin1') if s is not None else s
185 for s in m.groups()]
186 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000187 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300188 elif glibc:
189 if lib != 'glibc':
190 lib = 'glibc'
191 version = glibcversion
192 elif glibcversion > version:
193 version = glibcversion
194 elif so:
195 if lib != 'glibc':
196 lib = 'libc'
197 if soversion and soversion > version:
198 version = soversion
199 if threads and version[-len(threads):] != threads:
200 version = version + threads
201 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100202 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000203
Victor Stinnerced39362013-12-09 00:14:52 +0100204def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000205
Tim Peters0eadaac2003-04-24 16:02:54 +0000206 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 information in case the default method fails.
208
209 Currently supports older SuSE Linux, Caldera OpenLinux and
210 Slackware Linux distributions.
211
212 """
213 if os.path.exists('/var/adm/inst-log/info'):
214 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000216 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000217 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000218 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100219 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000220 else:
221 continue
222 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000223 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000224 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000225 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000226 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100227 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000228
229 if os.path.exists('/etc/.installed'):
230 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000231 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000232 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000233 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
234 # XXX does Caldera support non Intel platforms ? If yes,
235 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100236 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000237
238 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300239 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000240 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000241 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000242 if verfiles[n][:14] != 'slack-version-':
243 del verfiles[n]
244 if verfiles:
245 verfiles.sort()
246 distname = 'slackware'
247 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100248 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000249
Victor Stinnerced39362013-12-09 00:14:52 +0100250 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000251
Antoine Pitroufd036452008-08-19 17:56:33 +0000252_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000253_lsb_release_version = re.compile(r'(.+)'
R David Murray44b548d2016-09-08 13:59:53 -0400254 r' release '
255 r'([\d.]+)'
256 r'[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000257_release_version = re.compile(r'([^0-9]+)'
R David Murray44b548d2016-09-08 13:59:53 -0400258 r'(?: release )?'
259 r'([\d.]+)'
260 r'[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000261
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000262# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000263# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000264# and http://data.linux-ntfs.org/rpm/whichrpm
265# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000266
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000267_supported_dists = (
268 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
269 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200270 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000271
272def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000273
Benjamin Peterson25001472010-01-25 03:37:42 +0000274 # Default to empty 'version' and 'id' strings. Both defaults are used
275 # when 'firstline' is empty. 'id' defaults to empty when an id can not
276 # be deduced.
277 version = ''
278 id = ''
279
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000280 # Parse the first line
281 m = _lsb_release_version.match(firstline)
282 if m is not None:
283 # LSB format: "distro release x.x (codename)"
284 return tuple(m.groups())
285
286 # Pre-LSB format: "distro x.x (codename)"
287 m = _release_version.match(firstline)
288 if m is not None:
289 return tuple(m.groups())
290
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300291 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000292 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000293 if l:
294 version = l[0]
295 if len(l) > 1:
296 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000297 return '', version, id
298
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000299def linux_distribution(distname='', version='', id='',
300
301 supported_dists=_supported_dists,
302 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300303 import warnings
304 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300305 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300306 return _linux_distribution(distname, version, id, supported_dists,
307 full_distribution_name)
308
309def _linux_distribution(distname, version, id, supported_dists,
310 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000311
312 """ Tries to determine the name of the Linux OS distribution name.
313
314 The function first looks for a distribution release file in
315 /etc and then reverts to _dist_try_harder() in case no
316 suitable files are found.
317
318 supported_dists may be given to define the set of Linux
319 distributions to look for. It defaults to a list of currently
320 supported Linux distributions identified by their release file
321 name.
322
323 If full_distribution_name is true (default), the full
324 distribution read from the OS is returned. Otherwise the short
325 name taken from supported_dists is used.
326
Victor Stinnerced39362013-12-09 00:14:52 +0100327 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000328 args given as parameters.
329
330 """
331 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100332 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200333 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000334 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100335 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000336 etc.sort()
337 for file in etc:
338 m = _release_filename.match(file)
339 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100340 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000341 if _distname in supported_dists:
342 distname = _distname
343 break
344 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100345 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000346
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000347 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100348 with open(os.path.join(_UNIXCONFDIR, file), 'r',
349 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000350 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000351 _distname, _version, _id = _parse_release_file(firstline)
352
353 if _distname and full_distribution_name:
354 distname = _distname
355 if _version:
356 version = _version
357 if _id:
358 id = _id
359 return distname, version, id
360
361# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000362
Victor Stinnerced39362013-12-09 00:14:52 +0100363def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000364
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000365 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000366
Brett Cannon8ab27df2003-08-05 03:52:04 +0000367 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000368
369 The function first looks for a distribution release file in
370 /etc and then reverts to _dist_try_harder() in case no
371 suitable files are found.
372
Victor Stinnerced39362013-12-09 00:14:52 +0100373 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000374 args given as parameters.
375
376 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300377 import warnings
378 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300379 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300380 return _linux_distribution(distname, version, id,
381 supported_dists=supported_dists,
382 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383
Antoine Pitrou877766d2011-03-19 17:00:37 +0100384def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000385
386 """ Portable popen() interface.
387 """
Victor Stinner25000d42011-05-24 00:16:16 +0200388 import warnings
389 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000390 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000391
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000392def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000393
Brett Cannon8ab27df2003-08-05 03:52:04 +0000394 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000395 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000396 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000397 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000398 if build:
399 l.append(build)
400 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100401 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000402 except ValueError:
403 strings = l
404 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100405 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000406 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000407 return version
408
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000409_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400410 r'.*'
411 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000412
413# Examples of VER command output:
414#
415# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
416# Windows XP: Microsoft Windows XP [Version 5.1.2600]
417# Windows Vista: Microsoft Windows [Version 6.0.6002]
418#
419# Note that the "Version" string gets localized on different
420# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000421
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000422def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000423
Victor Stinnerced39362013-12-09 00:14:52 +0100424 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000425
426 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100427 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000428
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000429 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200430 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000431
432 In case this fails, the given parameters are used as
433 defaults.
434
435 """
436 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100437 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000438
439 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100440 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700442 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000443 info = pipe.read()
444 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200445 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200446 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000447 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200448 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100449 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000450 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000451 else:
452 break
453 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100454 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000455
456 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000457 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000458 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000459 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100460 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000461 # Strip trailing dots from version and release
462 if release[-1] == '.':
463 release = release[:-1]
464 if version[-1] == '.':
465 version = version[:-1]
466 # Normalize the version and build strings (eliminating additional
467 # zeros)
468 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100469 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000470
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700471_WIN32_CLIENT_RELEASES = {
472 (5, 0): "2000",
473 (5, 1): "XP",
474 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
475 # has always called it 2003 Server
476 (5, 2): "2003Server",
477 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000478
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700479 (6, 0): "Vista",
480 (6, 1): "7",
481 (6, 2): "8",
482 (6, 3): "8.1",
483 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000484
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700485 (10, 0): "10",
486 (10, None): "post10",
487}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700489# Server release name lookup will default to client names if necessary
490_WIN32_SERVER_RELEASES = {
491 (5, 2): "2003Server",
492
493 (6, 0): "2008Server",
494 (6, 1): "2008ServerR2",
495 (6, 2): "2012Server",
496 (6, 3): "2012ServerR2",
497 (6, None): "post2012ServerR2",
498}
499
500def _get_real_winver(maj, min, build):
501 if maj < 6 or (maj == 6 and min < 2):
502 return maj, min, build
503
504 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
505 Structure, WinDLL)
506 from ctypes.wintypes import DWORD, HANDLE
507
508 class VS_FIXEDFILEINFO(Structure):
509 _fields_ = [
510 ("dwSignature", DWORD),
511 ("dwStrucVersion", DWORD),
512 ("dwFileVersionMS", DWORD),
513 ("dwFileVersionLS", DWORD),
514 ("dwProductVersionMS", DWORD),
515 ("dwProductVersionLS", DWORD),
516 ("dwFileFlagsMask", DWORD),
517 ("dwFileFlags", DWORD),
518 ("dwFileOS", DWORD),
519 ("dwFileType", DWORD),
520 ("dwFileSubtype", DWORD),
521 ("dwFileDateMS", DWORD),
522 ("dwFileDateLS", DWORD),
523 ]
524
525 kernel32 = WinDLL('kernel32')
526 version = WinDLL('version')
527
528 # We will immediately double the length up to MAX_PATH, but the
529 # path may be longer, so we retry until the returned string is
530 # shorter than our buffer.
531 name_len = actual_len = 130
532 while actual_len == name_len:
533 name_len *= 2
534 name = create_unicode_buffer(name_len)
535 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
536 name, len(name))
537 if not actual_len:
538 return maj, min, build
539
540 size = version.GetFileVersionInfoSizeW(name, None)
541 if not size:
542 return maj, min, build
543
544 ver_block = c_buffer(size)
545 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
546 not ver_block):
547 return maj, min, build
548
549 pvi = POINTER(VS_FIXEDFILEINFO)()
550 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
551 return maj, min, build
552
553 maj = pvi.contents.dwProductVersionMS >> 16
554 min = pvi.contents.dwProductVersionMS & 0xFFFF
555 build = pvi.contents.dwProductVersionLS >> 16
556
557 return maj, min, build
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000558
Victor Stinnerced39362013-12-09 00:14:52 +0100559def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700560 try:
561 from sys import getwindowsversion
562 except ImportError:
563 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000564 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700565 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400566 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700567 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
568
569 winver = getwindowsversion()
570 maj, min, build = _get_real_winver(*winver[:3])
571 version = '{0}.{1}.{2}'.format(maj, min, build)
572
573 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
574 _WIN32_CLIENT_RELEASES.get((maj, None)) or
575 release)
576
577 # getwindowsversion() reflect the compatibility mode Python is
578 # running under, and so the service pack value is only going to be
579 # valid if the versions match.
580 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000581 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700582 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000583 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700584 if csd[:13] == 'Service Pack ':
585 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000586
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700587 # VER_NT_SERVER = 3
Steve Dower126c9c12016-03-12 08:06:23 -0800588 if getattr(winver, 'product', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700589 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
590 _WIN32_SERVER_RELEASES.get((maj, None)) or
591 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000592
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700593 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000594 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700595 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
596 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
597 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000598 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700599 pass
600 finally:
601 if key:
602 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000603
Victor Stinnerced39362013-12-09 00:14:52 +0100604 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000605
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700606
Ronald Oussorene186e382010-07-23 11:54:59 +0000607def _mac_ver_xml():
608 fn = '/System/Library/CoreServices/SystemVersion.plist'
609 if not os.path.exists(fn):
610 return None
611
612 try:
613 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400614 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000615 return None
616
Ned Deily936dfae2014-01-13 11:34:19 -0800617 with open(fn, 'rb') as f:
618 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000619 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100620 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700621 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000622 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300623 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000624 machine = 'PowerPC'
625
Victor Stinnerced39362013-12-09 00:14:52 +0100626 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000627
628
Victor Stinnerced39362013-12-09 00:14:52 +0100629def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000630
631 """ Get MacOS version information and return it as tuple (release,
632 versioninfo, machine) with versioninfo being a tuple (version,
633 dev_stage, non_release_version).
634
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300635 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000636 which default to ''. All tuple entries are strings.
637 """
638
639 # First try reading the information from an XML file which should
640 # always be present
641 info = _mac_ver_xml()
642 if info is not None:
643 return info
644
Ronald Oussorene186e382010-07-23 11:54:59 +0000645 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100646 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000647
Victor Stinnerced39362013-12-09 00:14:52 +0100648def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000649
650 from java.lang import System
651 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000652 value = System.getProperty(name)
653 if value is None:
654 return default
655 return value
656 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000657 return default
658
Victor Stinnerced39362013-12-09 00:14:52 +0100659def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000660
Brett Cannon8ab27df2003-08-05 03:52:04 +0000661 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000662
Victor Stinnerced39362013-12-09 00:14:52 +0100663 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
664 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
665 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000666
667 Values which cannot be determined are set to the defaults
668 given as parameters (which all default to '').
669
670 """
671 # Import the needed APIs
672 try:
673 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400674 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100675 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000676
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000677 vendor = _java_getprop('java.vendor', vendor)
678 release = _java_getprop('java.version', release)
679 vm_name, vm_release, vm_vendor = vminfo
680 vm_name = _java_getprop('java.vm.name', vm_name)
681 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
682 vm_release = _java_getprop('java.vm.version', vm_release)
683 vminfo = vm_name, vm_release, vm_vendor
684 os_name, os_version, os_arch = osinfo
685 os_arch = _java_getprop('java.os.arch', os_arch)
686 os_name = _java_getprop('java.os.name', os_name)
687 os_version = _java_getprop('java.os.version', os_version)
688 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000689
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000690 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000691
692### System name aliasing
693
Victor Stinnerced39362013-12-09 00:14:52 +0100694def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000695
Victor Stinnerced39362013-12-09 00:14:52 +0100696 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000697 marketing names used for some systems.
698
699 It also does some reordering of the information in some cases
700 where it would otherwise cause confusion.
701
702 """
703 if system == 'Rhapsody':
704 # Apple's BSD derivative
705 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100706 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000707
708 elif system == 'SunOS':
709 # Sun's OS
710 if release < '5':
711 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100712 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000713 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000714 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000715 if l:
716 try:
717 major = int(l[0])
718 except ValueError:
719 pass
720 else:
721 major = major - 3
722 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000723 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000724 if release < '6':
725 system = 'Solaris'
726 else:
727 # XXX Whatever the new SunOS marketing name is...
728 system = 'Solaris'
729
730 elif system == 'IRIX64':
731 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
732 # is really a version and not a different platform, since 32-bit
733 # apps are also supported..
734 system = 'IRIX'
735 if version:
736 version = version + ' (64bit)'
737 else:
738 version = '64bit'
739
Victor Stinnerced39362013-12-09 00:14:52 +0100740 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000741 # In case one of the other tricks
742 system = 'Windows'
743
Victor Stinnerced39362013-12-09 00:14:52 +0100744 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000745
746### Various internal helpers
747
748def _platform(*args):
749
750 """ Helper to format the platform string in a filename
751 compatible format e.g. "system-version-machine".
752 """
753 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000754 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000755
756 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100757 platform = platform.replace(' ', '_')
758 platform = platform.replace('/', '-')
759 platform = platform.replace('\\', '-')
760 platform = platform.replace(':', '-')
761 platform = platform.replace(';', '-')
762 platform = platform.replace('"', '-')
763 platform = platform.replace('(', '-')
764 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000765
766 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100767 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000768
769 # Fold '--'s and remove trailing '-'
770 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100771 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000772 if cleaned == platform:
773 break
774 platform = cleaned
775 while platform[-1] == '-':
776 platform = platform[:-1]
777
778 return platform
779
780def _node(default=''):
781
782 """ Helper to determine the node name of this machine.
783 """
784 try:
785 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400786 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000787 # No sockets...
788 return default
789 try:
790 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200791 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000792 # Still not working...
793 return default
794
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000795def _follow_symlinks(filepath):
796
797 """ In case filepath is a symlink, follow it until a
798 real file is reached.
799 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000800 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000801 while os.path.islink(filepath):
802 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100803 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000804 return filepath
805
Victor Stinnerced39362013-12-09 00:14:52 +0100806def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000807
808 """ Interface to the system's uname command.
809 """
Victor Stinnerced39362013-12-09 00:14:52 +0100810 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000811 # XXX Others too ?
812 return default
813 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000814 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200815 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000816 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000817 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000818 rc = f.close()
819 if not output or rc:
820 return default
821 else:
822 return output
823
Victor Stinnerced39362013-12-09 00:14:52 +0100824def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000825
826 """ Interface to the system's file command.
827
828 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000829 omit the filename in its output. Follow the symlinks. It returns
830 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000831
832 """
Victor Stinnerced39362013-12-09 00:14:52 +0100833 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000834 # XXX Others too ?
835 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200836 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000837 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200838 proc = subprocess.Popen(['file', target],
839 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200840
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200841 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000842 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200843 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200844 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000845 if not output or rc:
846 return default
847 else:
848 return output
849
850### Information about the used architecture
851
852# Default values for architecture; non-empty strings override the
853# defaults given as parameters
854_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100855 'win32': ('', 'WindowsPE'),
856 'win16': ('', 'Windows'),
857 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000858}
859
Victor Stinnerced39362013-12-09 00:14:52 +0100860def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000861
862 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000863 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000864
Victor Stinnerced39362013-12-09 00:14:52 +0100865 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000866 the bit architecture and the linkage format used for the
867 executable. Both values are returned as strings.
868
869 Values that cannot be determined are returned as given by the
870 parameter presets. If bits is given as '', the sizeof(pointer)
871 (or sizeof(long) on Python version < 1.5.2) is used as
872 indicator for the supported pointer size.
873
874 The function relies on the system's "file" command to do the
875 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000876 platforms. On some non-Unix platforms where the "file" command
877 does not exist and the executable is set to the Python interpreter
878 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000879
880 """
881 # Use the sizeof(pointer) as default number of bits if nothing
882 # else is given as default.
883 if not bits:
884 import struct
885 try:
886 size = struct.calcsize('P')
887 except struct.error:
888 # Older installations can only query longs
889 size = struct.calcsize('l')
890 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000891
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000892 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000893 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000894 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000895 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000896 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000897
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000898 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899 executable == sys.executable:
900 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000901 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000902 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100903 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000904 if b:
905 bits = b
906 if l:
907 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100908 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000909
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000910 if 'executable' not in fileout:
911 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100912 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000913
914 # Bits
915 if '32-bit' in fileout:
916 bits = '32bit'
917 elif 'N32' in fileout:
918 # On Irix only
919 bits = 'n32bit'
920 elif '64-bit' in fileout:
921 bits = '64bit'
922
923 # Linkage
924 if 'ELF' in fileout:
925 linkage = 'ELF'
926 elif 'PE' in fileout:
927 # E.g. Windows uses this format
928 if 'Windows' in fileout:
929 linkage = 'WindowsPE'
930 else:
931 linkage = 'PE'
932 elif 'COFF' in fileout:
933 linkage = 'COFF'
934 elif 'MS-DOS' in fileout:
935 linkage = 'MSDOS'
936 else:
937 # XXX the A.OUT format also falls under this class...
938 pass
939
Victor Stinnerced39362013-12-09 00:14:52 +0100940 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000941
942### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000943
Larry Hastings68386bc2012-06-24 14:30:41 -0700944uname_result = collections.namedtuple("uname_result",
945 "system node release version machine processor")
946
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000947_uname_cache = None
948
949def uname():
950
951 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100952 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000953 identifying the underlying platform.
954
955 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000956 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000957
958 Entries which cannot be determined are set to ''.
959
960 """
961 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000962 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000963
964 if _uname_cache is not None:
965 return _uname_cache
966
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000967 processor = ''
968
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000969 # Get some infos from the builtin os.uname API...
970 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100971 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000972 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000973 no_os_uname = 1
974
Georg Brandl62e2ca22010-07-31 21:54:24 +0000975 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000976 # Hmm, no there is either no uname or uname has returned
977 #'unknowns'... we'll have to poke around the system then.
978 if no_os_uname:
979 system = sys.platform
980 release = ''
981 version = ''
982 node = _node()
983 machine = ''
984
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000985 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000986
987 # Try win32_ver() on win32 platforms
988 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100989 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000990 if release and version:
991 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000992 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000993 # available on Win XP and later; see
994 # http://support.microsoft.com/kb/888731 and
995 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000996 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000997 # WOW64 processes mask the native architecture
998 if "PROCESSOR_ARCHITEW6432" in os.environ:
999 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1000 else:
1001 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001002 if not processor:
1003 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001004
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001005 # Try the 'ver' system command available on some
1006 # platforms
1007 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +01001008 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001009 # Normalize system to what win32_ver() normally returns
1010 # (_syscmd_ver() tends to return the vendor name as well)
1011 if system == 'Microsoft Windows':
1012 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001013 elif system == 'Microsoft' and release == 'Windows':
1014 # Under Windows Vista and Windows Server 2008,
1015 # Microsoft changed the output of the ver command. The
1016 # release is no longer printed. This causes the
1017 # system and release to be misidentified.
1018 system = 'Windows'
1019 if '6.0' == version[:3]:
1020 release = 'Vista'
1021 else:
1022 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001023
1024 # In case we still don't know anything useful, we'll try to
1025 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001026 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001027 if not version:
1028 if system == 'win32':
1029 version = '32bit'
1030 else:
1031 version = '16bit'
1032 system = 'Windows'
1033
1034 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001035 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001036 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001037 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001038 if not version:
1039 version = vendor
1040
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001041 # System specific extensions
1042 if system == 'OpenVMS':
1043 # OpenVMS seems to have release and version mixed up
1044 if not release or release == '0':
1045 release = version
1046 version = ''
1047 # Get processor information
1048 try:
1049 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001050 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001051 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001052 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001053 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001054 if (cpu_number >= 128):
1055 processor = 'Alpha'
1056 else:
1057 processor = 'VAX'
1058 if not processor:
1059 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001060 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001061
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001062 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001063 if system == 'unknown':
1064 system = ''
1065 if node == 'unknown':
1066 node = ''
1067 if release == 'unknown':
1068 release = ''
1069 if version == 'unknown':
1070 version = ''
1071 if machine == 'unknown':
1072 machine = ''
1073 if processor == 'unknown':
1074 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001075
1076 # normalize name
1077 if system == 'Microsoft' and release == 'Windows':
1078 system = 'Windows'
1079 release = 'Vista'
1080
Victor Stinnerced39362013-12-09 00:14:52 +01001081 _uname_cache = uname_result(system, node, release, version,
1082 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001083 return _uname_cache
1084
1085### Direct interfaces to some of the uname() return values
1086
1087def system():
1088
1089 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1090
1091 An empty string is returned if the value cannot be determined.
1092
1093 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001094 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001095
1096def node():
1097
Brett Cannon8ab27df2003-08-05 03:52:04 +00001098 """ Returns the computer's network name (which may not be fully
1099 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001100
1101 An empty string is returned if the value cannot be determined.
1102
1103 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001104 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001105
1106def release():
1107
1108 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1109
1110 An empty string is returned if the value cannot be determined.
1111
1112 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001113 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001114
1115def version():
1116
1117 """ Returns the system's release version, e.g. '#3 on degas'
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().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001123
1124def machine():
1125
1126 """ Returns the machine type, e.g. 'i386'
1127
1128 An empty string is returned if the value cannot be determined.
1129
1130 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001131 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001132
1133def processor():
1134
1135 """ Returns the (true) processor name, e.g. 'amdk6'
1136
1137 An empty string is returned if the value cannot be
1138 determined. Note that many platforms do not provide this
1139 information or simply return the same value as for machine(),
1140 e.g. NetBSD does this.
1141
1142 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001143 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001144
1145### Various APIs for extracting information from sys.version
1146
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001147_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001148 r'([\w.+]+)\s*' # "version<space>"
1149 r'\(#?([^,]+)' # "(#buildno"
1150 r'(?:,\s*([\w ]*)' # ", builddate"
1151 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1152 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001153
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001154_ironpython_sys_version_parser = re.compile(
1155 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001156 r'([\d\.]+)'
1157 r'(?: \(([\d\.]+)\))?'
1158 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001159
Ezio Melottif076f532013-10-21 03:03:32 +03001160# IronPython covering 2.6 and 2.7
1161_ironpython26_sys_version_parser = re.compile(
1162 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001163 r'\(IronPython\s*'
1164 r'[\d.]+\s*'
1165 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +03001166)
1167
Benjamin Petersone549ead2009-03-28 21:42:05 +00001168_pypy_sys_version_parser = re.compile(
1169 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001170 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1171 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +00001172
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001173_sys_version_cache = {}
1174
1175def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001176
1177 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001178 (name, version, branch, revision, buildno, builddate, compiler)
1179 referring to the Python implementation name, version, branch,
1180 revision, build number, build date/time as string and the compiler
1181 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001182
1183 Note that unlike the Python sys.version, the returned value
1184 for the Python version will always include the patchlevel (it
1185 defaults to '.0').
1186
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001187 The function returns empty strings for tuple entries that
1188 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001189
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001190 sys_version may be given to parse an alternative version
1191 string, e.g. if the version was read from a different Python
1192 interpreter.
1193
1194 """
1195 # Get the Python version
1196 if sys_version is None:
1197 sys_version = sys.version
1198
1199 # Try the cache first
1200 result = _sys_version_cache.get(sys_version, None)
1201 if result is not None:
1202 return result
1203
1204 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001205 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001206 # IronPython
1207 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001208 if sys_version.startswith('IronPython'):
1209 match = _ironpython_sys_version_parser.match(sys_version)
1210 else:
1211 match = _ironpython26_sys_version_parser.match(sys_version)
1212
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001213 if match is None:
1214 raise ValueError(
1215 'failed to parse IronPython sys.version: %s' %
1216 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001217
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001218 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001219 buildno = ''
1220 builddate = ''
1221
Ezio Melottif076f532013-10-21 03:03:32 +03001222 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001223 # Jython
1224 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001225 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001226 if match is None:
1227 raise ValueError(
1228 'failed to parse Jython sys.version: %s' %
1229 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001230 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001231 if builddate is None:
1232 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001233 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001234
1235 elif "PyPy" in sys_version:
1236 # PyPy
1237 name = "PyPy"
1238 match = _pypy_sys_version_parser.match(sys_version)
1239 if match is None:
1240 raise ValueError("failed to parse PyPy sys.version: %s" %
1241 repr(sys_version))
1242 version, buildno, builddate, buildtime = match.groups()
1243 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001244
1245 else:
1246 # CPython
1247 match = _sys_version_parser.match(sys_version)
1248 if match is None:
1249 raise ValueError(
1250 'failed to parse CPython sys.version: %s' %
1251 repr(sys_version))
1252 version, buildno, builddate, buildtime, compiler = \
1253 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001254 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001255 if builddate is None:
1256 builddate = ''
1257 elif buildtime:
1258 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001259
Georg Brandl82562422011-03-05 21:09:22 +01001260 if hasattr(sys, '_mercurial'):
1261 _, branch, revision = sys._mercurial
1262 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001263 # sys.subversion was added in Python 2.5
1264 _, branch, revision = sys.subversion
1265 else:
1266 branch = ''
1267 revision = ''
1268
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001269 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001270 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001271 if len(l) == 2:
1272 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001273 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001274
1275 # Build and cache the result
1276 result = (name, version, branch, revision, buildno, builddate, compiler)
1277 _sys_version_cache[sys_version] = result
1278 return result
1279
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001280def python_implementation():
1281
1282 """ Returns a string identifying the Python implementation.
1283
1284 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001285 'CPython' (C implementation of Python),
1286 'IronPython' (.NET implementation of Python),
1287 'Jython' (Java implementation of Python),
1288 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001289
1290 """
1291 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001292
1293def python_version():
1294
1295 """ Returns the Python version as string 'major.minor.patchlevel'
1296
1297 Note that unlike the Python sys.version, the returned value
1298 will always include the patchlevel (it defaults to 0).
1299
1300 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001301 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001302
1303def python_version_tuple():
1304
1305 """ Returns the Python version as tuple (major, minor, patchlevel)
1306 of strings.
1307
1308 Note that unlike the Python sys.version, the returned value
1309 will always include the patchlevel (it defaults to 0).
1310
1311 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001312 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001313
1314def python_branch():
1315
1316 """ Returns a string identifying the Python implementation
1317 branch.
1318
1319 For CPython this is the Subversion branch from which the
1320 Python binary was built.
1321
1322 If not available, an empty string is returned.
1323
1324 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001325
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001326 return _sys_version()[2]
1327
1328def python_revision():
1329
1330 """ Returns a string identifying the Python implementation
1331 revision.
1332
1333 For CPython this is the Subversion revision from which the
1334 Python binary was built.
1335
1336 If not available, an empty string is returned.
1337
1338 """
1339 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001340
1341def python_build():
1342
1343 """ Returns a tuple (buildno, builddate) stating the Python
1344 build number and date as strings.
1345
1346 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001347 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001348
1349def python_compiler():
1350
1351 """ Returns a string identifying the compiler used for compiling
1352 Python.
1353
1354 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001355 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001356
1357### The Opus Magnum of platform strings :-)
1358
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001359_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001360
1361def platform(aliased=0, terse=0):
1362
1363 """ Returns a single string identifying the underlying platform
1364 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001365
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001366 The output is intended to be human readable rather than
1367 machine parseable. It may look different on different
1368 platforms and this is intended.
1369
1370 If "aliased" is true, the function will use aliases for
1371 various platforms that report system names which differ from
1372 their common names, e.g. SunOS will be reported as
1373 Solaris. The system_alias() function is used to implement
1374 this.
1375
1376 Setting terse to true causes the function to return only the
1377 absolute minimum information needed to identify the platform.
1378
1379 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001380 result = _platform_cache.get((aliased, terse), None)
1381 if result is not None:
1382 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001383
1384 # Get uname information and then apply platform specific cosmetics
1385 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001386 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001387 if machine == processor:
1388 processor = ''
1389 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001390 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001391
1392 if system == 'Windows':
1393 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001394 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001395 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001396 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001397 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001398 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001399
1400 elif system in ('Linux',):
1401 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001402 with warnings.catch_warnings():
1403 # see issue #1322 for more information
1404 warnings.filterwarnings(
1405 'ignore',
R David Murray44b548d2016-09-08 13:59:53 -04001406 r'dist\(\) and linux_distribution\(\) '
Berker Peksag1392f712015-05-16 20:24:28 +03001407 'functions are deprecated .*',
1408 PendingDeprecationWarning,
1409 )
1410 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001411 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001412 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001413 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001414 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001415 else:
1416 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001417 libcname, libcversion = libc_ver(sys.executable)
1418 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001419 'with',
1420 libcname+libcversion)
1421 elif system == 'Java':
1422 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001423 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:
Victor Stinnerced39362013-12-09 00:14:52 +01001425 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001426 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001427 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001428 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001429 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001430
1431 elif system == 'MacOS':
1432 # MacOS platforms
1433 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001434 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001435 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001436 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001437
1438 else:
1439 # Generic handler
1440 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001441 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001442 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001443 bits, linkage = architecture(sys.executable)
1444 platform = _platform(system, release, machine,
1445 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001446
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001447 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001448 return platform
1449
1450### Command line interface
1451
1452if __name__ == '__main__':
1453 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001454 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001455 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001456 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001457 sys.exit(0)