blob: b8f3ebc7b1e234a6bcb62114c3aa043e0a7456dc [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),
Steve Dowerb9f4fea2015-09-22 17:23:39 -070029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
30# Dower
Marc-André Lemburg246d8472003-04-24 11:36:11 +000031#
32# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000033#
34# <see CVS and SVN checkin messages for history>
35#
Steve Dowerb9f4fea2015-09-22 17:23:39 -070036# 1.0.8 - changed Windows support to read version from kernel32.dll
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000037# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000038# 1.0.6 - added linux_distribution()
39# 1.0.5 - fixed Java support to allow running the module on Jython
40# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000041# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000042# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000043# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000044# 1.0.0 - reformatted a bit and checked into Python CVS
45# 0.8.0 - added sys.version parser and various new access
46# APIs (python_version(), python_compiler(), etc.)
47# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
48# 0.7.1 - added support for Caldera OpenLinux
49# 0.7.0 - some fixes for WinCE; untabified the source file
50# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
51# vms_lib.getsyi() configured
52# 0.6.1 - added code to prevent 'uname -p' on platforms which are
53# known not to support it
54# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
55# did some cleanup of the interfaces - some APIs have changed
56# 0.5.5 - fixed another type in the MacOS code... should have
57# used more coffee today ;-)
58# 0.5.4 - fixed a few typos in the MacOS code
59# 0.5.3 - added experimental MacOS support; added better popen()
60# workarounds in _syscmd_ver() -- still not 100% elegant
61# though
62# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
63# return values (the system uname command tends to return
Martin Pantereb995702016-07-28 01:11:04 +000064# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000065# 0.5.1 - included code for slackware dist; added exception handlers
66# to cover up situations where platforms don't have os.popen
67# (e.g. Mac) or fail on socket.gethostname(); fixed libc
68# detection RE
69# 0.5.0 - changed the API names referring to system commands to *syscmd*;
70# added java_ver(); made syscmd_ver() a private
71# API (was system_ver() in previous versions) -- use uname()
72# instead; extended the win32_ver() to also return processor
73# type information
74# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
75# 0.3.4 - fixed a bug in _follow_symlinks()
76# 0.3.3 - fixed popen() and "file" command invokation bugs
77# 0.3.2 - added architecture() API and support for it in platform()
78# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
79# 0.3.0 - added system alias support
80# 0.2.3 - removed 'wince' again... oh well.
81# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
82# 0.2.1 - added cache logic and changed the platform string format
83# 0.2.0 - changed the API to use functions instead of module globals
84# since some action take too long to be run on module import
85# 0.1.0 - first release
86#
87# You can always get the latest version of this module at:
88#
89# http://www.egenix.com/files/python/platform.py
90#
91# If that URL should fail, try contacting the author.
92
93__copyright__ = """
94 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Peterson46a99002010-01-09 18:45:30 +000095 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000096
97 Permission to use, copy, modify, and distribute this software and its
98 documentation for any purpose and without fee or royalty is hereby granted,
99 provided that the above copyright notice appear in all copies and that
100 both that copyright notice and this permission notice appear in
101 supporting documentation or portions thereof, including modifications,
102 that you make.
103
104 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
105 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
106 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
107 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
108 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
109 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
110 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
111
112"""
113
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000114__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000115
Larry Hastings68386bc2012-06-24 14:30:41 -0700116import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200117import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000118
Berker Peksag1392f712015-05-16 20:24:28 +0300119import warnings
120
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000121### Globals & Constants
122
123# Determine the platform's /dev/null device
124try:
125 DEV_NULL = os.devnull
126except AttributeError:
127 # os.devnull was added in Python 2.4, so emulate it for earlier
128 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100129 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000130 # Use the old CP/M NUL as device name
131 DEV_NULL = 'NUL'
132 else:
133 # Standard Unix uses /dev/null
134 DEV_NULL = '/dev/null'
135
Victor Stinner620c48b2013-12-09 00:01:27 +0100136# Directory to search for configuration information on Unix.
137# Constant used by test_platform to test linux_distribution().
138_UNIXCONFDIR = '/etc'
139
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000140### Platform specific APIs
141
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200142_libc_search = re.compile(b'(__libc_init)'
143 b'|'
144 b'(GLIBC_([0-9.]+))'
145 b'|'
146 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000147
Victor Stinnerced39362013-12-09 00:14:52 +0100148def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000149
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200150 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000151
Brett Cannon8ab27df2003-08-05 03:52:04 +0000152 """ Tries to determine the libc version that the file executable
153 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000154
155 Returns a tuple of strings (lib,version) which default to the
156 given parameters in case the lookup fails.
157
158 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000159 libc versions add symbols to the executable and thus is probably
160 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000161
162 The file is read and scanned in chunks of chunksize bytes.
163
164 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000165 if hasattr(os.path, 'realpath'):
166 # Python 2.2 introduced os.path.realpath(); it is used
167 # here to work around problems with Cygwin not being
168 # able to open symlinks for reading
169 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300170 with open(executable, 'rb') as f:
171 binary = f.read(chunksize)
172 pos = 0
173 while 1:
174 if b'libc' in binary or b'GLIBC' in binary:
175 m = _libc_search.search(binary, pos)
176 else:
177 m = None
178 if not m:
179 binary = f.read(chunksize)
180 if not binary:
181 break
182 pos = 0
183 continue
184 libcinit, glibc, glibcversion, so, threads, soversion = [
185 s.decode('latin1') if s is not None else s
186 for s in m.groups()]
187 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000188 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300189 elif glibc:
190 if lib != 'glibc':
191 lib = 'glibc'
192 version = glibcversion
193 elif glibcversion > version:
194 version = glibcversion
195 elif so:
196 if lib != 'glibc':
197 lib = 'libc'
198 if soversion and soversion > version:
199 version = soversion
200 if threads and version[-len(threads):] != threads:
201 version = version + threads
202 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100203 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000204
Victor Stinnerced39362013-12-09 00:14:52 +0100205def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000206
Tim Peters0eadaac2003-04-24 16:02:54 +0000207 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000208 information in case the default method fails.
209
210 Currently supports older SuSE Linux, Caldera OpenLinux and
211 Slackware Linux distributions.
212
213 """
214 if os.path.exists('/var/adm/inst-log/info'):
215 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000216 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000217 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000218 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000219 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100220 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000221 else:
222 continue
223 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000224 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000225 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000226 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000227 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100228 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000229
230 if os.path.exists('/etc/.installed'):
231 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000232 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000233 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000234 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
235 # XXX does Caldera support non Intel platforms ? If yes,
236 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100237 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000238
239 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300240 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000241 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000242 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000243 if verfiles[n][:14] != 'slack-version-':
244 del verfiles[n]
245 if verfiles:
246 verfiles.sort()
247 distname = 'slackware'
248 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100249 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000250
Victor Stinnerced39362013-12-09 00:14:52 +0100251 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000252
Antoine Pitroufd036452008-08-19 17:56:33 +0000253_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000254_lsb_release_version = re.compile(r'(.+)'
255 ' release '
256 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000257 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000258_release_version = re.compile(r'([^0-9]+)'
259 '(?: release )?'
260 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000261 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000262
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000263# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000264# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000265# and http://data.linux-ntfs.org/rpm/whichrpm
266# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000267
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000268_supported_dists = (
269 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
270 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200271 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000272
273def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000274
Benjamin Peterson25001472010-01-25 03:37:42 +0000275 # Default to empty 'version' and 'id' strings. Both defaults are used
276 # when 'firstline' is empty. 'id' defaults to empty when an id can not
277 # be deduced.
278 version = ''
279 id = ''
280
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000281 # Parse the first line
282 m = _lsb_release_version.match(firstline)
283 if m is not None:
284 # LSB format: "distro release x.x (codename)"
285 return tuple(m.groups())
286
287 # Pre-LSB format: "distro x.x (codename)"
288 m = _release_version.match(firstline)
289 if m is not None:
290 return tuple(m.groups())
291
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300292 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000293 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000294 if l:
295 version = l[0]
296 if len(l) > 1:
297 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000298 return '', version, id
299
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000300def linux_distribution(distname='', version='', id='',
301
302 supported_dists=_supported_dists,
303 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300304 import warnings
305 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300306 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300307 return _linux_distribution(distname, version, id, supported_dists,
308 full_distribution_name)
309
310def _linux_distribution(distname, version, id, supported_dists,
311 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000312
313 """ Tries to determine the name of the Linux OS distribution name.
314
315 The function first looks for a distribution release file in
316 /etc and then reverts to _dist_try_harder() in case no
317 suitable files are found.
318
319 supported_dists may be given to define the set of Linux
320 distributions to look for. It defaults to a list of currently
321 supported Linux distributions identified by their release file
322 name.
323
324 If full_distribution_name is true (default), the full
325 distribution read from the OS is returned. Otherwise the short
326 name taken from supported_dists is used.
327
Victor Stinnerced39362013-12-09 00:14:52 +0100328 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000329 args given as parameters.
330
331 """
332 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100333 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200334 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000335 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100336 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000337 etc.sort()
338 for file in etc:
339 m = _release_filename.match(file)
340 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100341 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000342 if _distname in supported_dists:
343 distname = _distname
344 break
345 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100346 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000347
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000348 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100349 with open(os.path.join(_UNIXCONFDIR, file), 'r',
350 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000351 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000352 _distname, _version, _id = _parse_release_file(firstline)
353
354 if _distname and full_distribution_name:
355 distname = _distname
356 if _version:
357 version = _version
358 if _id:
359 id = _id
360 return distname, version, id
361
362# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000363
Victor Stinnerced39362013-12-09 00:14:52 +0100364def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000365
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000366 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000367
Brett Cannon8ab27df2003-08-05 03:52:04 +0000368 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000369
370 The function first looks for a distribution release file in
371 /etc and then reverts to _dist_try_harder() in case no
372 suitable files are found.
373
Victor Stinnerced39362013-12-09 00:14:52 +0100374 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000375 args given as parameters.
376
377 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300378 import warnings
379 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300380 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300381 return _linux_distribution(distname, version, id,
382 supported_dists=supported_dists,
383 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000384
Antoine Pitrou877766d2011-03-19 17:00:37 +0100385def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000386
387 """ Portable popen() interface.
388 """
Victor Stinner25000d42011-05-24 00:16:16 +0200389 import warnings
390 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000391 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000392
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000393def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000394
Brett Cannon8ab27df2003-08-05 03:52:04 +0000395 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000396 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000397 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000398 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000399 if build:
400 l.append(build)
401 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100402 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000403 except ValueError:
404 strings = l
405 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100406 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000407 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000408 return version
409
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000410_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
411 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000412 '\[.* ([\d.]+)\])')
413
414# Examples of VER command output:
415#
416# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
417# Windows XP: Microsoft Windows XP [Version 5.1.2600]
418# Windows Vista: Microsoft Windows [Version 6.0.6002]
419#
420# Note that the "Version" string gets localized on different
421# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000422
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000423def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000424
Victor Stinnerced39362013-12-09 00:14:52 +0100425 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000426
427 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100428 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000429
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000430 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200431 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000432
433 In case this fails, the given parameters are used as
434 defaults.
435
436 """
437 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100438 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000439
440 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100441 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000442 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700443 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000444 info = pipe.read()
445 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200446 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200447 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000448 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200449 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100450 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000451 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452 else:
453 break
454 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100455 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
457 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000458 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000459 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000460 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100461 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 # Strip trailing dots from version and release
463 if release[-1] == '.':
464 release = release[:-1]
465 if version[-1] == '.':
466 version = version[:-1]
467 # Normalize the version and build strings (eliminating additional
468 # zeros)
469 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100470 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000471
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700472_WIN32_CLIENT_RELEASES = {
473 (5, 0): "2000",
474 (5, 1): "XP",
475 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
476 # has always called it 2003 Server
477 (5, 2): "2003Server",
478 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000479
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700480 (6, 0): "Vista",
481 (6, 1): "7",
482 (6, 2): "8",
483 (6, 3): "8.1",
484 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700486 (10, 0): "10",
487 (10, None): "post10",
488}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000489
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700490# Server release name lookup will default to client names if necessary
491_WIN32_SERVER_RELEASES = {
492 (5, 2): "2003Server",
493
494 (6, 0): "2008Server",
495 (6, 1): "2008ServerR2",
496 (6, 2): "2012Server",
497 (6, 3): "2012ServerR2",
498 (6, None): "post2012ServerR2",
499}
500
501def _get_real_winver(maj, min, build):
502 if maj < 6 or (maj == 6 and min < 2):
503 return maj, min, build
504
505 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
506 Structure, WinDLL)
507 from ctypes.wintypes import DWORD, HANDLE
508
509 class VS_FIXEDFILEINFO(Structure):
510 _fields_ = [
511 ("dwSignature", DWORD),
512 ("dwStrucVersion", DWORD),
513 ("dwFileVersionMS", DWORD),
514 ("dwFileVersionLS", DWORD),
515 ("dwProductVersionMS", DWORD),
516 ("dwProductVersionLS", DWORD),
517 ("dwFileFlagsMask", DWORD),
518 ("dwFileFlags", DWORD),
519 ("dwFileOS", DWORD),
520 ("dwFileType", DWORD),
521 ("dwFileSubtype", DWORD),
522 ("dwFileDateMS", DWORD),
523 ("dwFileDateLS", DWORD),
524 ]
525
526 kernel32 = WinDLL('kernel32')
527 version = WinDLL('version')
528
529 # We will immediately double the length up to MAX_PATH, but the
530 # path may be longer, so we retry until the returned string is
531 # shorter than our buffer.
532 name_len = actual_len = 130
533 while actual_len == name_len:
534 name_len *= 2
535 name = create_unicode_buffer(name_len)
536 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
537 name, len(name))
538 if not actual_len:
539 return maj, min, build
540
541 size = version.GetFileVersionInfoSizeW(name, None)
542 if not size:
543 return maj, min, build
544
545 ver_block = c_buffer(size)
546 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
547 not ver_block):
548 return maj, min, build
549
550 pvi = POINTER(VS_FIXEDFILEINFO)()
551 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
552 return maj, min, build
553
554 maj = pvi.contents.dwProductVersionMS >> 16
555 min = pvi.contents.dwProductVersionMS & 0xFFFF
556 build = pvi.contents.dwProductVersionLS >> 16
557
558 return maj, min, build
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000559
Victor Stinnerced39362013-12-09 00:14:52 +0100560def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700561 try:
562 from sys import getwindowsversion
563 except ImportError:
564 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000565 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700566 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400567 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700568 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
569
570 winver = getwindowsversion()
571 maj, min, build = _get_real_winver(*winver[:3])
572 version = '{0}.{1}.{2}'.format(maj, min, build)
573
574 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
575 _WIN32_CLIENT_RELEASES.get((maj, None)) or
576 release)
577
578 # getwindowsversion() reflect the compatibility mode Python is
579 # running under, and so the service pack value is only going to be
580 # valid if the versions match.
581 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000582 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700583 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000584 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700585 if csd[:13] == 'Service Pack ':
586 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000587
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700588 # VER_NT_SERVER = 3
Steve Dower126c9c12016-03-12 08:06:23 -0800589 if getattr(winver, 'product', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700590 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
591 _WIN32_SERVER_RELEASES.get((maj, None)) or
592 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000593
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700594 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000595 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700596 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
597 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
598 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000599 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700600 pass
601 finally:
602 if key:
603 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000604
Victor Stinnerced39362013-12-09 00:14:52 +0100605 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700607
Ronald Oussorene186e382010-07-23 11:54:59 +0000608def _mac_ver_xml():
609 fn = '/System/Library/CoreServices/SystemVersion.plist'
610 if not os.path.exists(fn):
611 return None
612
613 try:
614 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400615 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000616 return None
617
Ned Deily936dfae2014-01-13 11:34:19 -0800618 with open(fn, 'rb') as f:
619 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000620 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100621 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700622 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000623 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300624 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000625 machine = 'PowerPC'
626
Victor Stinnerced39362013-12-09 00:14:52 +0100627 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000628
629
Victor Stinnerced39362013-12-09 00:14:52 +0100630def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000631
632 """ Get MacOS version information and return it as tuple (release,
633 versioninfo, machine) with versioninfo being a tuple (version,
634 dev_stage, non_release_version).
635
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300636 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000637 which default to ''. All tuple entries are strings.
638 """
639
640 # First try reading the information from an XML file which should
641 # always be present
642 info = _mac_ver_xml()
643 if info is not None:
644 return info
645
Ronald Oussorene186e382010-07-23 11:54:59 +0000646 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100647 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000648
Victor Stinnerced39362013-12-09 00:14:52 +0100649def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650
651 from java.lang import System
652 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000653 value = System.getProperty(name)
654 if value is None:
655 return default
656 return value
657 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000658 return default
659
Victor Stinnerced39362013-12-09 00:14:52 +0100660def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000661
Brett Cannon8ab27df2003-08-05 03:52:04 +0000662 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000663
Victor Stinnerced39362013-12-09 00:14:52 +0100664 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
665 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
666 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667
668 Values which cannot be determined are set to the defaults
669 given as parameters (which all default to '').
670
671 """
672 # Import the needed APIs
673 try:
674 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400675 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100676 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000677
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000678 vendor = _java_getprop('java.vendor', vendor)
679 release = _java_getprop('java.version', release)
680 vm_name, vm_release, vm_vendor = vminfo
681 vm_name = _java_getprop('java.vm.name', vm_name)
682 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
683 vm_release = _java_getprop('java.vm.version', vm_release)
684 vminfo = vm_name, vm_release, vm_vendor
685 os_name, os_version, os_arch = osinfo
686 os_arch = _java_getprop('java.os.arch', os_arch)
687 os_name = _java_getprop('java.os.name', os_name)
688 os_version = _java_getprop('java.os.version', os_version)
689 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000690
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000691 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000692
693### System name aliasing
694
Victor Stinnerced39362013-12-09 00:14:52 +0100695def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000696
Victor Stinnerced39362013-12-09 00:14:52 +0100697 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698 marketing names used for some systems.
699
700 It also does some reordering of the information in some cases
701 where it would otherwise cause confusion.
702
703 """
704 if system == 'Rhapsody':
705 # Apple's BSD derivative
706 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100707 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000708
709 elif system == 'SunOS':
710 # Sun's OS
711 if release < '5':
712 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100713 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000714 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000715 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000716 if l:
717 try:
718 major = int(l[0])
719 except ValueError:
720 pass
721 else:
722 major = major - 3
723 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000724 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000725 if release < '6':
726 system = 'Solaris'
727 else:
728 # XXX Whatever the new SunOS marketing name is...
729 system = 'Solaris'
730
731 elif system == 'IRIX64':
732 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
733 # is really a version and not a different platform, since 32-bit
734 # apps are also supported..
735 system = 'IRIX'
736 if version:
737 version = version + ' (64bit)'
738 else:
739 version = '64bit'
740
Victor Stinnerced39362013-12-09 00:14:52 +0100741 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000742 # In case one of the other tricks
743 system = 'Windows'
744
Victor Stinnerced39362013-12-09 00:14:52 +0100745 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746
747### Various internal helpers
748
749def _platform(*args):
750
751 """ Helper to format the platform string in a filename
752 compatible format e.g. "system-version-machine".
753 """
754 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000755 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000756
757 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100758 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('(', '-')
765 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000766
767 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100768 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000769
770 # Fold '--'s and remove trailing '-'
771 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100772 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000773 if cleaned == platform:
774 break
775 platform = cleaned
776 while platform[-1] == '-':
777 platform = platform[:-1]
778
779 return platform
780
781def _node(default=''):
782
783 """ Helper to determine the node name of this machine.
784 """
785 try:
786 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400787 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000788 # No sockets...
789 return default
790 try:
791 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200792 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000793 # Still not working...
794 return default
795
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000796def _follow_symlinks(filepath):
797
798 """ In case filepath is a symlink, follow it until a
799 real file is reached.
800 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000801 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000802 while os.path.islink(filepath):
803 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100804 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805 return filepath
806
Victor Stinnerced39362013-12-09 00:14:52 +0100807def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000808
809 """ Interface to the system's uname command.
810 """
Victor Stinnerced39362013-12-09 00:14:52 +0100811 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000812 # XXX Others too ?
813 return default
814 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000815 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200816 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000817 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000818 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000819 rc = f.close()
820 if not output or rc:
821 return default
822 else:
823 return output
824
Victor Stinnerced39362013-12-09 00:14:52 +0100825def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000826
827 """ Interface to the system's file command.
828
829 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000830 omit the filename in its output. Follow the symlinks. It returns
831 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000832
833 """
Victor Stinnerced39362013-12-09 00:14:52 +0100834 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000835 # XXX Others too ?
836 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200837 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000838 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200839 proc = subprocess.Popen(['file', target],
840 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200841
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200842 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000843 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200844 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200845 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000846 if not output or rc:
847 return default
848 else:
849 return output
850
851### Information about the used architecture
852
853# Default values for architecture; non-empty strings override the
854# defaults given as parameters
855_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100856 'win32': ('', 'WindowsPE'),
857 'win16': ('', 'Windows'),
858 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000859}
860
Victor Stinnerced39362013-12-09 00:14:52 +0100861def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000862
863 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000864 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000865
Victor Stinnerced39362013-12-09 00:14:52 +0100866 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000867 the bit architecture and the linkage format used for the
868 executable. Both values are returned as strings.
869
870 Values that cannot be determined are returned as given by the
871 parameter presets. If bits is given as '', the sizeof(pointer)
872 (or sizeof(long) on Python version < 1.5.2) is used as
873 indicator for the supported pointer size.
874
875 The function relies on the system's "file" command to do the
876 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000877 platforms. On some non-Unix platforms where the "file" command
878 does not exist and the executable is set to the Python interpreter
879 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000880
881 """
882 # Use the sizeof(pointer) as default number of bits if nothing
883 # else is given as default.
884 if not bits:
885 import struct
886 try:
887 size = struct.calcsize('P')
888 except struct.error:
889 # Older installations can only query longs
890 size = struct.calcsize('l')
891 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000892
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000893 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000894 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000895 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000896 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000897 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000898
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000899 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000900 executable == sys.executable:
901 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000902 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000903 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100904 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000905 if b:
906 bits = b
907 if l:
908 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100909 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000910
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000911 if 'executable' not in fileout:
912 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100913 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000914
915 # Bits
916 if '32-bit' in fileout:
917 bits = '32bit'
918 elif 'N32' in fileout:
919 # On Irix only
920 bits = 'n32bit'
921 elif '64-bit' in fileout:
922 bits = '64bit'
923
924 # Linkage
925 if 'ELF' in fileout:
926 linkage = 'ELF'
927 elif 'PE' in fileout:
928 # E.g. Windows uses this format
929 if 'Windows' in fileout:
930 linkage = 'WindowsPE'
931 else:
932 linkage = 'PE'
933 elif 'COFF' in fileout:
934 linkage = 'COFF'
935 elif 'MS-DOS' in fileout:
936 linkage = 'MSDOS'
937 else:
938 # XXX the A.OUT format also falls under this class...
939 pass
940
Victor Stinnerced39362013-12-09 00:14:52 +0100941 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000942
943### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000944
Larry Hastings68386bc2012-06-24 14:30:41 -0700945uname_result = collections.namedtuple("uname_result",
946 "system node release version machine processor")
947
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000948_uname_cache = None
949
950def uname():
951
952 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100953 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000954 identifying the underlying platform.
955
956 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000957 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958
959 Entries which cannot be determined are set to ''.
960
961 """
962 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000963 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000964
965 if _uname_cache is not None:
966 return _uname_cache
967
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000968 processor = ''
969
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000970 # Get some infos from the builtin os.uname API...
971 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100972 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000973 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000974 no_os_uname = 1
975
Georg Brandl62e2ca22010-07-31 21:54:24 +0000976 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000977 # Hmm, no there is either no uname or uname has returned
978 #'unknowns'... we'll have to poke around the system then.
979 if no_os_uname:
980 system = sys.platform
981 release = ''
982 version = ''
983 node = _node()
984 machine = ''
985
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000986 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000987
988 # Try win32_ver() on win32 platforms
989 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100990 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000991 if release and version:
992 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000993 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000994 # available on Win XP and later; see
995 # http://support.microsoft.com/kb/888731 and
996 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000997 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000998 # WOW64 processes mask the native architecture
999 if "PROCESSOR_ARCHITEW6432" in os.environ:
1000 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1001 else:
1002 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001003 if not processor:
1004 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001005
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001006 # Try the 'ver' system command available on some
1007 # platforms
1008 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +01001009 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001010 # Normalize system to what win32_ver() normally returns
1011 # (_syscmd_ver() tends to return the vendor name as well)
1012 if system == 'Microsoft Windows':
1013 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001014 elif system == 'Microsoft' and release == 'Windows':
1015 # Under Windows Vista and Windows Server 2008,
1016 # Microsoft changed the output of the ver command. The
1017 # release is no longer printed. This causes the
1018 # system and release to be misidentified.
1019 system = 'Windows'
1020 if '6.0' == version[:3]:
1021 release = 'Vista'
1022 else:
1023 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001024
1025 # In case we still don't know anything useful, we'll try to
1026 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001027 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001028 if not version:
1029 if system == 'win32':
1030 version = '32bit'
1031 else:
1032 version = '16bit'
1033 system = 'Windows'
1034
1035 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001036 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001037 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001038 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001039 if not version:
1040 version = vendor
1041
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001042 # System specific extensions
1043 if system == 'OpenVMS':
1044 # OpenVMS seems to have release and version mixed up
1045 if not release or release == '0':
1046 release = version
1047 version = ''
1048 # Get processor information
1049 try:
1050 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001051 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001052 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001053 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001054 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001055 if (cpu_number >= 128):
1056 processor = 'Alpha'
1057 else:
1058 processor = 'VAX'
1059 if not processor:
1060 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001061 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001062
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001063 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064 if system == 'unknown':
1065 system = ''
1066 if node == 'unknown':
1067 node = ''
1068 if release == 'unknown':
1069 release = ''
1070 if version == 'unknown':
1071 version = ''
1072 if machine == 'unknown':
1073 machine = ''
1074 if processor == 'unknown':
1075 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001076
1077 # normalize name
1078 if system == 'Microsoft' and release == 'Windows':
1079 system = 'Windows'
1080 release = 'Vista'
1081
Victor Stinnerced39362013-12-09 00:14:52 +01001082 _uname_cache = uname_result(system, node, release, version,
1083 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001084 return _uname_cache
1085
1086### Direct interfaces to some of the uname() return values
1087
1088def system():
1089
1090 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1091
1092 An empty string is returned if the value cannot be determined.
1093
1094 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001095 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001096
1097def node():
1098
Brett Cannon8ab27df2003-08-05 03:52:04 +00001099 """ Returns the computer's network name (which may not be fully
1100 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001101
1102 An empty string is returned if the value cannot be determined.
1103
1104 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001105 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001106
1107def release():
1108
1109 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1110
1111 An empty string is returned if the value cannot be determined.
1112
1113 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001114 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001115
1116def version():
1117
1118 """ Returns the system's release version, e.g. '#3 on degas'
1119
1120 An empty string is returned if the value cannot be determined.
1121
1122 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001123 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001124
1125def machine():
1126
1127 """ Returns the machine type, e.g. 'i386'
1128
1129 An empty string is returned if the value cannot be determined.
1130
1131 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001132 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001133
1134def processor():
1135
1136 """ Returns the (true) processor name, e.g. 'amdk6'
1137
1138 An empty string is returned if the value cannot be
1139 determined. Note that many platforms do not provide this
1140 information or simply return the same value as for machine(),
1141 e.g. NetBSD does this.
1142
1143 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001144 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001145
1146### Various APIs for extracting information from sys.version
1147
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001148_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001149 r'([\w.+]+)\s*' # "version<space>"
1150 r'\(#?([^,]+)' # "(#buildno"
1151 r'(?:,\s*([\w ]*)' # ", builddate"
1152 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1153 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001154
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001155_ironpython_sys_version_parser = re.compile(
1156 r'IronPython\s*'
1157 '([\d\.]+)'
1158 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001159 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001160
Ezio Melottif076f532013-10-21 03:03:32 +03001161# IronPython covering 2.6 and 2.7
1162_ironpython26_sys_version_parser = re.compile(
1163 r'([\d.]+)\s*'
1164 '\(IronPython\s*'
1165 '[\d.]+\s*'
1166 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1167)
1168
Benjamin Petersone549ead2009-03-28 21:42:05 +00001169_pypy_sys_version_parser = re.compile(
1170 r'([\w.+]+)\s*'
1171 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1172 '\[PyPy [^\]]+\]?')
1173
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001174_sys_version_cache = {}
1175
1176def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177
1178 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001179 (name, version, branch, revision, buildno, builddate, compiler)
1180 referring to the Python implementation name, version, branch,
1181 revision, build number, build date/time as string and the compiler
1182 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001183
1184 Note that unlike the Python sys.version, the returned value
1185 for the Python version will always include the patchlevel (it
1186 defaults to '.0').
1187
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001188 The function returns empty strings for tuple entries that
1189 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001190
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001191 sys_version may be given to parse an alternative version
1192 string, e.g. if the version was read from a different Python
1193 interpreter.
1194
1195 """
1196 # Get the Python version
1197 if sys_version is None:
1198 sys_version = sys.version
1199
1200 # Try the cache first
1201 result = _sys_version_cache.get(sys_version, None)
1202 if result is not None:
1203 return result
1204
1205 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001206 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001207 # IronPython
1208 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001209 if sys_version.startswith('IronPython'):
1210 match = _ironpython_sys_version_parser.match(sys_version)
1211 else:
1212 match = _ironpython26_sys_version_parser.match(sys_version)
1213
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001214 if match is None:
1215 raise ValueError(
1216 'failed to parse IronPython sys.version: %s' %
1217 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001218
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001219 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001220 buildno = ''
1221 builddate = ''
1222
Ezio Melottif076f532013-10-21 03:03:32 +03001223 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001224 # Jython
1225 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001226 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001227 if match is None:
1228 raise ValueError(
1229 'failed to parse Jython sys.version: %s' %
1230 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001231 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001232 if builddate is None:
1233 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001234 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001235
1236 elif "PyPy" in sys_version:
1237 # PyPy
1238 name = "PyPy"
1239 match = _pypy_sys_version_parser.match(sys_version)
1240 if match is None:
1241 raise ValueError("failed to parse PyPy sys.version: %s" %
1242 repr(sys_version))
1243 version, buildno, builddate, buildtime = match.groups()
1244 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001245
1246 else:
1247 # CPython
1248 match = _sys_version_parser.match(sys_version)
1249 if match is None:
1250 raise ValueError(
1251 'failed to parse CPython sys.version: %s' %
1252 repr(sys_version))
1253 version, buildno, builddate, buildtime, compiler = \
1254 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001255 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001256 if builddate is None:
1257 builddate = ''
1258 elif buildtime:
1259 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001260
Georg Brandl82562422011-03-05 21:09:22 +01001261 if hasattr(sys, '_mercurial'):
1262 _, branch, revision = sys._mercurial
1263 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001264 # sys.subversion was added in Python 2.5
1265 _, branch, revision = sys.subversion
1266 else:
1267 branch = ''
1268 revision = ''
1269
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001270 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001271 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001272 if len(l) == 2:
1273 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001274 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001275
1276 # Build and cache the result
1277 result = (name, version, branch, revision, buildno, builddate, compiler)
1278 _sys_version_cache[sys_version] = result
1279 return result
1280
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001281def python_implementation():
1282
1283 """ Returns a string identifying the Python implementation.
1284
1285 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001286 'CPython' (C implementation of Python),
1287 'IronPython' (.NET implementation of Python),
1288 'Jython' (Java implementation of Python),
1289 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001290
1291 """
1292 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001293
1294def python_version():
1295
1296 """ Returns the Python version as string 'major.minor.patchlevel'
1297
1298 Note that unlike the Python sys.version, the returned value
1299 will always include the patchlevel (it defaults to 0).
1300
1301 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001302 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001303
1304def python_version_tuple():
1305
1306 """ Returns the Python version as tuple (major, minor, patchlevel)
1307 of strings.
1308
1309 Note that unlike the Python sys.version, the returned value
1310 will always include the patchlevel (it defaults to 0).
1311
1312 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001313 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001314
1315def python_branch():
1316
1317 """ Returns a string identifying the Python implementation
1318 branch.
1319
1320 For CPython this is the Subversion branch from which the
1321 Python binary was built.
1322
1323 If not available, an empty string is returned.
1324
1325 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001326
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001327 return _sys_version()[2]
1328
1329def python_revision():
1330
1331 """ Returns a string identifying the Python implementation
1332 revision.
1333
1334 For CPython this is the Subversion revision from which the
1335 Python binary was built.
1336
1337 If not available, an empty string is returned.
1338
1339 """
1340 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001341
1342def python_build():
1343
1344 """ Returns a tuple (buildno, builddate) stating the Python
1345 build number and date as strings.
1346
1347 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001348 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001349
1350def python_compiler():
1351
1352 """ Returns a string identifying the compiler used for compiling
1353 Python.
1354
1355 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001356 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001357
1358### The Opus Magnum of platform strings :-)
1359
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001360_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001361
1362def platform(aliased=0, terse=0):
1363
1364 """ Returns a single string identifying the underlying platform
1365 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001366
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001367 The output is intended to be human readable rather than
1368 machine parseable. It may look different on different
1369 platforms and this is intended.
1370
1371 If "aliased" is true, the function will use aliases for
1372 various platforms that report system names which differ from
1373 their common names, e.g. SunOS will be reported as
1374 Solaris. The system_alias() function is used to implement
1375 this.
1376
1377 Setting terse to true causes the function to return only the
1378 absolute minimum information needed to identify the platform.
1379
1380 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001381 result = _platform_cache.get((aliased, terse), None)
1382 if result is not None:
1383 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001384
1385 # Get uname information and then apply platform specific cosmetics
1386 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001387 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001388 if machine == processor:
1389 processor = ''
1390 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001391 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001392
1393 if system == 'Windows':
1394 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001395 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001396 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001397 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001398 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001399 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001400
1401 elif system in ('Linux',):
1402 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001403 with warnings.catch_warnings():
1404 # see issue #1322 for more information
1405 warnings.filterwarnings(
1406 'ignore',
1407 'dist\(\) and linux_distribution\(\) '
1408 'functions are deprecated .*',
1409 PendingDeprecationWarning,
1410 )
1411 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001412 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001413 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001414 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001415 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001416 else:
1417 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001418 libcname, libcversion = libc_ver(sys.executable)
1419 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001420 'with',
1421 libcname+libcversion)
1422 elif system == 'Java':
1423 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001424 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001425 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001426 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001427 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001428 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001429 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001430 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001431
1432 elif system == 'MacOS':
1433 # MacOS platforms
1434 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001435 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001436 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001437 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001438
1439 else:
1440 # Generic handler
1441 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001442 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001443 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001444 bits, linkage = architecture(sys.executable)
1445 platform = _platform(system, release, machine,
1446 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001447
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001448 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001449 return platform
1450
1451### Command line interface
1452
1453if __name__ == '__main__':
1454 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001455 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001456 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001457 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001458 sys.exit(0)