blob: e2273485078633432cdcbd79fbbfe2a61658e0aa [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
Matthias Bussonnier6059ce42017-02-24 02:47:34 -0800113__version__ = '1.0.8'
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
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300147def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000148
Brett Cannon8ab27df2003-08-05 03:52:04 +0000149 """ Tries to determine the libc version that the file executable
150 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000151
152 Returns a tuple of strings (lib,version) which default to the
153 given parameters in case the lookup fails.
154
155 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000156 libc versions add symbols to the executable and thus is probably
157 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000158
159 The file is read and scanned in chunks of chunksize bytes.
160
161 """
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300162 from distutils.version import LooseVersion as V
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000163 if hasattr(os.path, 'realpath'):
164 # Python 2.2 introduced os.path.realpath(); it is used
165 # here to work around problems with Cygwin not being
166 # able to open symlinks for reading
167 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300168 with open(executable, 'rb') as f:
169 binary = f.read(chunksize)
170 pos = 0
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300171 while pos < len(binary):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300172 if b'libc' in binary or b'GLIBC' in binary:
173 m = _libc_search.search(binary, pos)
174 else:
175 m = None
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300176 if not m or m.end() == len(binary):
177 chunk = f.read(chunksize)
178 if chunk:
179 binary = binary[max(pos, len(binary) - 1000):] + chunk
180 pos = 0
181 continue
182 if not m:
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300183 break
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300184 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
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300193 elif V(glibcversion) > V(version):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300194 version = glibcversion
195 elif so:
196 if lib != 'glibc':
197 lib = 'libc'
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300198 if soversion and (not version or V(soversion) > V(version)):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300199 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'(.+)'
R David Murray44b548d2016-09-08 13:59:53 -0400255 r' release '
256 r'([\d.]+)'
257 r'[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000258_release_version = re.compile(r'([^0-9]+)'
R David Murray44b548d2016-09-08 13:59:53 -0400259 r'(?: release )?'
260 r'([\d.]+)'
261 r'[^(]*(?:\((.+)\))?', 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 "
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -0700306 "in Python 3.5", DeprecationWarning, 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 "
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -0700380 "in Python 3.5", DeprecationWarning, 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
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300393
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000394def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000395
Brett Cannon8ab27df2003-08-05 03:52:04 +0000396 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000397 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000398 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000399 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000400 if build:
401 l.append(build)
402 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100403 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000404 except ValueError:
405 strings = l
406 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100407 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000408 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000409 return version
410
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000411_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400412 r'.*'
413 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000414
415# Examples of VER command output:
416#
417# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
418# Windows XP: Microsoft Windows XP [Version 5.1.2600]
419# Windows Vista: Microsoft Windows [Version 6.0.6002]
420#
421# Note that the "Version" string gets localized on different
422# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000423
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000424def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000425
Victor Stinnerced39362013-12-09 00:14:52 +0100426 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000427
428 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100429 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000430
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000431 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200432 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000433
434 In case this fails, the given parameters are used as
435 defaults.
436
437 """
438 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100439 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000440
441 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100442 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000443 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700444 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000445 info = pipe.read()
446 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200447 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200448 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000449 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200450 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100451 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000453 else:
454 break
455 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100456 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000457
458 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000459 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000460 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000461 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100462 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000463 # Strip trailing dots from version and release
464 if release[-1] == '.':
465 release = release[:-1]
466 if version[-1] == '.':
467 version = version[:-1]
468 # Normalize the version and build strings (eliminating additional
469 # zeros)
470 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100471 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000472
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700473_WIN32_CLIENT_RELEASES = {
474 (5, 0): "2000",
475 (5, 1): "XP",
476 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
477 # has always called it 2003 Server
478 (5, 2): "2003Server",
479 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000480
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700481 (6, 0): "Vista",
482 (6, 1): "7",
483 (6, 2): "8",
484 (6, 3): "8.1",
485 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000486
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700487 (10, 0): "10",
488 (10, None): "post10",
489}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000490
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700491# Server release name lookup will default to client names if necessary
492_WIN32_SERVER_RELEASES = {
493 (5, 2): "2003Server",
494
495 (6, 0): "2008Server",
496 (6, 1): "2008ServerR2",
497 (6, 2): "2012Server",
498 (6, 3): "2012ServerR2",
499 (6, None): "post2012ServerR2",
500}
501
Victor Stinnerced39362013-12-09 00:14:52 +0100502def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700503 try:
504 from sys import getwindowsversion
505 except ImportError:
506 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000507 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700508 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400509 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700510 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
511
512 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700513 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700514 version = '{0}.{1}.{2}'.format(maj, min, build)
515
516 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
517 _WIN32_CLIENT_RELEASES.get((maj, None)) or
518 release)
519
520 # getwindowsversion() reflect the compatibility mode Python is
521 # running under, and so the service pack value is only going to be
522 # valid if the versions match.
523 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000524 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700525 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000526 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700527 if csd[:13] == 'Service Pack ':
528 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000529
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700530 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700531 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700532 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
533 _WIN32_SERVER_RELEASES.get((maj, None)) or
534 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000535
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700536 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000537 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700538 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
539 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
540 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000541 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700542 pass
543 finally:
544 if key:
545 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000546
Victor Stinnerced39362013-12-09 00:14:52 +0100547 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700549
Ronald Oussorene186e382010-07-23 11:54:59 +0000550def _mac_ver_xml():
551 fn = '/System/Library/CoreServices/SystemVersion.plist'
552 if not os.path.exists(fn):
553 return None
554
555 try:
556 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400557 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000558 return None
559
Ned Deily936dfae2014-01-13 11:34:19 -0800560 with open(fn, 'rb') as f:
561 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000562 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100563 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700564 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000565 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300566 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000567 machine = 'PowerPC'
568
Victor Stinnerced39362013-12-09 00:14:52 +0100569 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000570
571
Victor Stinnerced39362013-12-09 00:14:52 +0100572def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000573
574 """ Get MacOS version information and return it as tuple (release,
575 versioninfo, machine) with versioninfo being a tuple (version,
576 dev_stage, non_release_version).
577
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300578 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000579 which default to ''. All tuple entries are strings.
580 """
581
582 # First try reading the information from an XML file which should
583 # always be present
584 info = _mac_ver_xml()
585 if info is not None:
586 return info
587
Ronald Oussorene186e382010-07-23 11:54:59 +0000588 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100589 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000590
Victor Stinnerced39362013-12-09 00:14:52 +0100591def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000592
593 from java.lang import System
594 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000595 value = System.getProperty(name)
596 if value is None:
597 return default
598 return value
599 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000600 return default
601
Victor Stinnerced39362013-12-09 00:14:52 +0100602def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000603
Brett Cannon8ab27df2003-08-05 03:52:04 +0000604 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000605
Victor Stinnerced39362013-12-09 00:14:52 +0100606 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
607 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
608 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000609
610 Values which cannot be determined are set to the defaults
611 given as parameters (which all default to '').
612
613 """
614 # Import the needed APIs
615 try:
616 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400617 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100618 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000619
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000620 vendor = _java_getprop('java.vendor', vendor)
621 release = _java_getprop('java.version', release)
622 vm_name, vm_release, vm_vendor = vminfo
623 vm_name = _java_getprop('java.vm.name', vm_name)
624 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
625 vm_release = _java_getprop('java.vm.version', vm_release)
626 vminfo = vm_name, vm_release, vm_vendor
627 os_name, os_version, os_arch = osinfo
628 os_arch = _java_getprop('java.os.arch', os_arch)
629 os_name = _java_getprop('java.os.name', os_name)
630 os_version = _java_getprop('java.os.version', os_version)
631 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000632
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000633 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000634
635### System name aliasing
636
Victor Stinnerced39362013-12-09 00:14:52 +0100637def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638
Victor Stinnerced39362013-12-09 00:14:52 +0100639 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000640 marketing names used for some systems.
641
642 It also does some reordering of the information in some cases
643 where it would otherwise cause confusion.
644
645 """
646 if system == 'Rhapsody':
647 # Apple's BSD derivative
648 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100649 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650
651 elif system == 'SunOS':
652 # Sun's OS
653 if release < '5':
654 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100655 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000656 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000657 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000658 if l:
659 try:
660 major = int(l[0])
661 except ValueError:
662 pass
663 else:
664 major = major - 3
665 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000666 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667 if release < '6':
668 system = 'Solaris'
669 else:
670 # XXX Whatever the new SunOS marketing name is...
671 system = 'Solaris'
672
673 elif system == 'IRIX64':
674 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
675 # is really a version and not a different platform, since 32-bit
676 # apps are also supported..
677 system = 'IRIX'
678 if version:
679 version = version + ' (64bit)'
680 else:
681 version = '64bit'
682
Victor Stinnerced39362013-12-09 00:14:52 +0100683 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000684 # In case one of the other tricks
685 system = 'Windows'
686
Victor Stinnerced39362013-12-09 00:14:52 +0100687 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000688
689### Various internal helpers
690
691def _platform(*args):
692
693 """ Helper to format the platform string in a filename
694 compatible format e.g. "system-version-machine".
695 """
696 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000697 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698
699 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100700 platform = platform.replace(' ', '_')
701 platform = platform.replace('/', '-')
702 platform = platform.replace('\\', '-')
703 platform = platform.replace(':', '-')
704 platform = platform.replace(';', '-')
705 platform = platform.replace('"', '-')
706 platform = platform.replace('(', '-')
707 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000708
709 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100710 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000711
712 # Fold '--'s and remove trailing '-'
713 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100714 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000715 if cleaned == platform:
716 break
717 platform = cleaned
718 while platform[-1] == '-':
719 platform = platform[:-1]
720
721 return platform
722
723def _node(default=''):
724
725 """ Helper to determine the node name of this machine.
726 """
727 try:
728 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400729 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000730 # No sockets...
731 return default
732 try:
733 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200734 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000735 # Still not working...
736 return default
737
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000738def _follow_symlinks(filepath):
739
740 """ In case filepath is a symlink, follow it until a
741 real file is reached.
742 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000743 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744 while os.path.islink(filepath):
745 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100746 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000747 return filepath
748
Victor Stinnerced39362013-12-09 00:14:52 +0100749def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000750
751 """ Interface to the system's uname command.
752 """
Victor Stinnerced39362013-12-09 00:14:52 +0100753 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000754 # XXX Others too ?
755 return default
756 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000757 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200758 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000759 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000760 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000761 rc = f.close()
762 if not output or rc:
763 return default
764 else:
765 return output
766
Victor Stinnerced39362013-12-09 00:14:52 +0100767def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000768
769 """ Interface to the system's file command.
770
771 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000772 omit the filename in its output. Follow the symlinks. It returns
773 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000774
775 """
Victor Stinnerced39362013-12-09 00:14:52 +0100776 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000777 # XXX Others too ?
778 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200779 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000780 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200781 proc = subprocess.Popen(['file', target],
782 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200783
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200784 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000785 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200786 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200787 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000788 if not output or rc:
789 return default
790 else:
791 return output
792
793### Information about the used architecture
794
795# Default values for architecture; non-empty strings override the
796# defaults given as parameters
797_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100798 'win32': ('', 'WindowsPE'),
799 'win16': ('', 'Windows'),
800 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000801}
802
Victor Stinnerced39362013-12-09 00:14:52 +0100803def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000804
805 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000806 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000807
Victor Stinnerced39362013-12-09 00:14:52 +0100808 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000809 the bit architecture and the linkage format used for the
810 executable. Both values are returned as strings.
811
812 Values that cannot be determined are returned as given by the
813 parameter presets. If bits is given as '', the sizeof(pointer)
814 (or sizeof(long) on Python version < 1.5.2) is used as
815 indicator for the supported pointer size.
816
817 The function relies on the system's "file" command to do the
818 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000819 platforms. On some non-Unix platforms where the "file" command
820 does not exist and the executable is set to the Python interpreter
821 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000822
823 """
824 # Use the sizeof(pointer) as default number of bits if nothing
825 # else is given as default.
826 if not bits:
827 import struct
828 try:
829 size = struct.calcsize('P')
830 except struct.error:
831 # Older installations can only query longs
832 size = struct.calcsize('l')
833 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000834
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000835 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000836 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000837 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000838 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000839 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000841 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000842 executable == sys.executable:
843 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000844 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000845 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100846 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000847 if b:
848 bits = b
849 if l:
850 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100851 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000852
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000853 if 'executable' not in fileout:
854 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100855 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000856
857 # Bits
858 if '32-bit' in fileout:
859 bits = '32bit'
860 elif 'N32' in fileout:
861 # On Irix only
862 bits = 'n32bit'
863 elif '64-bit' in fileout:
864 bits = '64bit'
865
866 # Linkage
867 if 'ELF' in fileout:
868 linkage = 'ELF'
869 elif 'PE' in fileout:
870 # E.g. Windows uses this format
871 if 'Windows' in fileout:
872 linkage = 'WindowsPE'
873 else:
874 linkage = 'PE'
875 elif 'COFF' in fileout:
876 linkage = 'COFF'
877 elif 'MS-DOS' in fileout:
878 linkage = 'MSDOS'
879 else:
880 # XXX the A.OUT format also falls under this class...
881 pass
882
Victor Stinnerced39362013-12-09 00:14:52 +0100883 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000884
885### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000886
Larry Hastings68386bc2012-06-24 14:30:41 -0700887uname_result = collections.namedtuple("uname_result",
888 "system node release version machine processor")
889
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000890_uname_cache = None
891
892def uname():
893
894 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100895 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000896 identifying the underlying platform.
897
898 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000899 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000900
901 Entries which cannot be determined are set to ''.
902
903 """
904 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000905 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000906
907 if _uname_cache is not None:
908 return _uname_cache
909
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000910 processor = ''
911
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000912 # Get some infos from the builtin os.uname API...
913 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100914 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000915 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000916 no_os_uname = 1
917
Georg Brandl62e2ca22010-07-31 21:54:24 +0000918 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000919 # Hmm, no there is either no uname or uname has returned
920 #'unknowns'... we'll have to poke around the system then.
921 if no_os_uname:
922 system = sys.platform
923 release = ''
924 version = ''
925 node = _node()
926 machine = ''
927
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000928 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000929
930 # Try win32_ver() on win32 platforms
931 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100932 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000933 if release and version:
934 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000935 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000936 # available on Win XP and later; see
937 # http://support.microsoft.com/kb/888731 and
938 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000939 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000940 # WOW64 processes mask the native architecture
941 if "PROCESSOR_ARCHITEW6432" in os.environ:
942 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
943 else:
944 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000945 if not processor:
946 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000947
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000948 # Try the 'ver' system command available on some
949 # platforms
950 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100951 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000952 # Normalize system to what win32_ver() normally returns
953 # (_syscmd_ver() tends to return the vendor name as well)
954 if system == 'Microsoft Windows':
955 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000956 elif system == 'Microsoft' and release == 'Windows':
957 # Under Windows Vista and Windows Server 2008,
958 # Microsoft changed the output of the ver command. The
959 # release is no longer printed. This causes the
960 # system and release to be misidentified.
961 system = 'Windows'
962 if '6.0' == version[:3]:
963 release = 'Vista'
964 else:
965 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000966
967 # In case we still don't know anything useful, we'll try to
968 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100969 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000970 if not version:
971 if system == 'win32':
972 version = '32bit'
973 else:
974 version = '16bit'
975 system = 'Windows'
976
977 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100978 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000979 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000980 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000981 if not version:
982 version = vendor
983
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000984 # System specific extensions
985 if system == 'OpenVMS':
986 # OpenVMS seems to have release and version mixed up
987 if not release or release == '0':
988 release = version
989 version = ''
990 # Get processor information
991 try:
992 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400993 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000994 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000995 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100996 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000997 if (cpu_number >= 128):
998 processor = 'Alpha'
999 else:
1000 processor = 'VAX'
1001 if not processor:
1002 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001003 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001004
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001005 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001006 if system == 'unknown':
1007 system = ''
1008 if node == 'unknown':
1009 node = ''
1010 if release == 'unknown':
1011 release = ''
1012 if version == 'unknown':
1013 version = ''
1014 if machine == 'unknown':
1015 machine = ''
1016 if processor == 'unknown':
1017 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001018
1019 # normalize name
1020 if system == 'Microsoft' and release == 'Windows':
1021 system = 'Windows'
1022 release = 'Vista'
1023
Victor Stinnerced39362013-12-09 00:14:52 +01001024 _uname_cache = uname_result(system, node, release, version,
1025 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001026 return _uname_cache
1027
1028### Direct interfaces to some of the uname() return values
1029
1030def system():
1031
1032 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1033
1034 An empty string is returned if the value cannot be determined.
1035
1036 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001037 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001038
1039def node():
1040
Brett Cannon8ab27df2003-08-05 03:52:04 +00001041 """ Returns the computer's network name (which may not be fully
1042 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001043
1044 An empty string is returned if the value cannot be determined.
1045
1046 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001047 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001048
1049def release():
1050
1051 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1052
1053 An empty string is returned if the value cannot be determined.
1054
1055 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001056 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001057
1058def version():
1059
1060 """ Returns the system's release version, e.g. '#3 on degas'
1061
1062 An empty string is returned if the value cannot be determined.
1063
1064 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001065 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001066
1067def machine():
1068
1069 """ Returns the machine type, e.g. 'i386'
1070
1071 An empty string is returned if the value cannot be determined.
1072
1073 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001074 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001075
1076def processor():
1077
1078 """ Returns the (true) processor name, e.g. 'amdk6'
1079
1080 An empty string is returned if the value cannot be
1081 determined. Note that many platforms do not provide this
1082 information or simply return the same value as for machine(),
1083 e.g. NetBSD does this.
1084
1085 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001086 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001087
1088### Various APIs for extracting information from sys.version
1089
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001090_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001091 r'([\w.+]+)\s*' # "version<space>"
1092 r'\(#?([^,]+)' # "(#buildno"
1093 r'(?:,\s*([\w ]*)' # ", builddate"
1094 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1095 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001096
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001097_ironpython_sys_version_parser = re.compile(
1098 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001099 r'([\d\.]+)'
1100 r'(?: \(([\d\.]+)\))?'
1101 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001102
Ezio Melottif076f532013-10-21 03:03:32 +03001103# IronPython covering 2.6 and 2.7
1104_ironpython26_sys_version_parser = re.compile(
1105 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001106 r'\(IronPython\s*'
1107 r'[\d.]+\s*'
1108 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +03001109)
1110
Benjamin Petersone549ead2009-03-28 21:42:05 +00001111_pypy_sys_version_parser = re.compile(
1112 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001113 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1114 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +00001115
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001116_sys_version_cache = {}
1117
1118def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001119
1120 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001121 (name, version, branch, revision, buildno, builddate, compiler)
1122 referring to the Python implementation name, version, branch,
1123 revision, build number, build date/time as string and the compiler
1124 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001125
1126 Note that unlike the Python sys.version, the returned value
1127 for the Python version will always include the patchlevel (it
1128 defaults to '.0').
1129
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001130 The function returns empty strings for tuple entries that
1131 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001132
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001133 sys_version may be given to parse an alternative version
1134 string, e.g. if the version was read from a different Python
1135 interpreter.
1136
1137 """
1138 # Get the Python version
1139 if sys_version is None:
1140 sys_version = sys.version
1141
1142 # Try the cache first
1143 result = _sys_version_cache.get(sys_version, None)
1144 if result is not None:
1145 return result
1146
1147 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001148 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001149 # IronPython
1150 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001151 if sys_version.startswith('IronPython'):
1152 match = _ironpython_sys_version_parser.match(sys_version)
1153 else:
1154 match = _ironpython26_sys_version_parser.match(sys_version)
1155
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001156 if match is None:
1157 raise ValueError(
1158 'failed to parse IronPython sys.version: %s' %
1159 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001160
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001161 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001162 buildno = ''
1163 builddate = ''
1164
Ezio Melottif076f532013-10-21 03:03:32 +03001165 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001166 # Jython
1167 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001168 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001169 if match is None:
1170 raise ValueError(
1171 'failed to parse Jython sys.version: %s' %
1172 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001173 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001174 if builddate is None:
1175 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001176 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001177
1178 elif "PyPy" in sys_version:
1179 # PyPy
1180 name = "PyPy"
1181 match = _pypy_sys_version_parser.match(sys_version)
1182 if match is None:
1183 raise ValueError("failed to parse PyPy sys.version: %s" %
1184 repr(sys_version))
1185 version, buildno, builddate, buildtime = match.groups()
1186 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001187
1188 else:
1189 # CPython
1190 match = _sys_version_parser.match(sys_version)
1191 if match is None:
1192 raise ValueError(
1193 'failed to parse CPython sys.version: %s' %
1194 repr(sys_version))
1195 version, buildno, builddate, buildtime, compiler = \
1196 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001197 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001198 if builddate is None:
1199 builddate = ''
1200 elif buildtime:
1201 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001202
Ned Deily5c4b0d02017-03-04 00:19:55 -05001203 if hasattr(sys, '_git'):
1204 _, branch, revision = sys._git
1205 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001206 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001207 else:
1208 branch = ''
1209 revision = ''
1210
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001211 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001212 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001213 if len(l) == 2:
1214 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001215 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001216
1217 # Build and cache the result
1218 result = (name, version, branch, revision, buildno, builddate, compiler)
1219 _sys_version_cache[sys_version] = result
1220 return result
1221
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001222def python_implementation():
1223
1224 """ Returns a string identifying the Python implementation.
1225
1226 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001227 'CPython' (C implementation of Python),
1228 'IronPython' (.NET implementation of Python),
1229 'Jython' (Java implementation of Python),
1230 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001231
1232 """
1233 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001234
1235def python_version():
1236
1237 """ Returns the Python version as string 'major.minor.patchlevel'
1238
1239 Note that unlike the Python sys.version, the returned value
1240 will always include the patchlevel (it defaults to 0).
1241
1242 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001243 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001244
1245def python_version_tuple():
1246
1247 """ Returns the Python version as tuple (major, minor, patchlevel)
1248 of strings.
1249
1250 Note that unlike the Python sys.version, the returned value
1251 will always include the patchlevel (it defaults to 0).
1252
1253 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001254 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001255
1256def python_branch():
1257
1258 """ Returns a string identifying the Python implementation
1259 branch.
1260
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001261 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001262 Python binary was built.
1263
1264 If not available, an empty string is returned.
1265
1266 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001267
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001268 return _sys_version()[2]
1269
1270def python_revision():
1271
1272 """ Returns a string identifying the Python implementation
1273 revision.
1274
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001275 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001276 Python binary was built.
1277
1278 If not available, an empty string is returned.
1279
1280 """
1281 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001282
1283def python_build():
1284
1285 """ Returns a tuple (buildno, builddate) stating the Python
1286 build number and date as strings.
1287
1288 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001289 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001290
1291def python_compiler():
1292
1293 """ Returns a string identifying the compiler used for compiling
1294 Python.
1295
1296 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001297 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001298
1299### The Opus Magnum of platform strings :-)
1300
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001301_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001302
1303def platform(aliased=0, terse=0):
1304
1305 """ Returns a single string identifying the underlying platform
1306 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001307
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001308 The output is intended to be human readable rather than
1309 machine parseable. It may look different on different
1310 platforms and this is intended.
1311
1312 If "aliased" is true, the function will use aliases for
1313 various platforms that report system names which differ from
1314 their common names, e.g. SunOS will be reported as
1315 Solaris. The system_alias() function is used to implement
1316 this.
1317
1318 Setting terse to true causes the function to return only the
1319 absolute minimum information needed to identify the platform.
1320
1321 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001322 result = _platform_cache.get((aliased, terse), None)
1323 if result is not None:
1324 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001325
1326 # Get uname information and then apply platform specific cosmetics
1327 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001328 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001329 if machine == processor:
1330 processor = ''
1331 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001332 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001333
1334 if system == 'Windows':
1335 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001336 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001337 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001338 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001339 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001340 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001341
1342 elif system in ('Linux',):
1343 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001344 with warnings.catch_warnings():
1345 # see issue #1322 for more information
1346 warnings.filterwarnings(
1347 'ignore',
R David Murray44b548d2016-09-08 13:59:53 -04001348 r'dist\(\) and linux_distribution\(\) '
Berker Peksag1392f712015-05-16 20:24:28 +03001349 'functions are deprecated .*',
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -07001350 DeprecationWarning,
Berker Peksag1392f712015-05-16 20:24:28 +03001351 )
1352 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001353 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001354 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001355 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001356 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001357 else:
1358 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001359 libcname, libcversion = libc_ver(sys.executable)
1360 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001361 'with',
1362 libcname+libcversion)
1363 elif system == 'Java':
1364 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001365 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001366 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001367 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001368 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001369 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001370 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001371 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001372
1373 elif system == 'MacOS':
1374 # MacOS platforms
1375 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001376 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001377 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001378 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001379
1380 else:
1381 # Generic handler
1382 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001383 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001384 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001385 bits, linkage = architecture(sys.executable)
1386 platform = _platform(system, release, machine,
1387 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001388
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001389 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001390 return platform
1391
1392### Command line interface
1393
1394if __name__ == '__main__':
1395 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001396 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001397 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001398 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001399 sys.exit(0)