blob: 0c6fc03efa9f815e5a927a289adf912ce8050dec [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
Serhiy Storchaka20a83922018-09-04 17:31:18 +0300139# Helper for comparing two version number strings.
140# Based on the description of the PHP's version_compare():
141# http://php.net/manual/en/function.version-compare.php
142
143_ver_stages = {
144 # any string not found in this dict, will get 0 assigned
145 'dev': 10,
146 'alpha': 20, 'a': 20,
147 'beta': 30, 'b': 30,
148 'c': 40,
149 'RC': 50, 'rc': 50,
150 # number, will get 100 assigned
151 'pl': 200, 'p': 200,
152}
153
154_component_re = re.compile(r'([0-9]+|[._+-])')
155
156def _comparable_version(version):
157 result = []
158 for v in _component_re.split(version):
159 if v not in '._+-':
160 try:
161 v = int(v, 10)
162 t = 100
163 except ValueError:
164 t = _ver_stages.get(v, 0)
165 result.extend((t, v))
166 return result
167
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000168### Platform specific APIs
169
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200170_libc_search = re.compile(b'(__libc_init)'
171 b'|'
172 b'(GLIBC_([0-9.]+))'
173 b'|'
174 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000175
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300176def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000177
Brett Cannon8ab27df2003-08-05 03:52:04 +0000178 """ Tries to determine the libc version that the file executable
179 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000180
181 Returns a tuple of strings (lib,version) which default to the
182 given parameters in case the lookup fails.
183
184 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000185 libc versions add symbols to the executable and thus is probably
186 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000187
188 The file is read and scanned in chunks of chunksize bytes.
189
190 """
Serhiy Storchaka20a83922018-09-04 17:31:18 +0300191 V = _comparable_version
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000192 if hasattr(os.path, 'realpath'):
193 # Python 2.2 introduced os.path.realpath(); it is used
194 # here to work around problems with Cygwin not being
195 # able to open symlinks for reading
196 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300197 with open(executable, 'rb') as f:
198 binary = f.read(chunksize)
199 pos = 0
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300200 while pos < len(binary):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300201 if b'libc' in binary or b'GLIBC' in binary:
202 m = _libc_search.search(binary, pos)
203 else:
204 m = None
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300205 if not m or m.end() == len(binary):
206 chunk = f.read(chunksize)
207 if chunk:
208 binary = binary[max(pos, len(binary) - 1000):] + chunk
209 pos = 0
210 continue
211 if not m:
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300212 break
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300213 libcinit, glibc, glibcversion, so, threads, soversion = [
214 s.decode('latin1') if s is not None else s
215 for s in m.groups()]
216 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000217 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300218 elif glibc:
219 if lib != 'glibc':
220 lib = 'glibc'
221 version = glibcversion
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300222 elif V(glibcversion) > V(version):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300223 version = glibcversion
224 elif so:
225 if lib != 'glibc':
226 lib = 'libc'
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300227 if soversion and (not version or V(soversion) > V(version)):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300228 version = soversion
229 if threads and version[-len(threads):] != threads:
230 version = version + threads
231 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100232 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000233
Victor Stinnerced39362013-12-09 00:14:52 +0100234def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000235
Tim Peters0eadaac2003-04-24 16:02:54 +0000236 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000237 information in case the default method fails.
238
239 Currently supports older SuSE Linux, Caldera OpenLinux and
240 Slackware Linux distributions.
241
242 """
243 if os.path.exists('/var/adm/inst-log/info'):
244 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000245 distname = 'SuSE'
Victor Stinner7eeab872018-11-29 12:31:08 +0100246 with open('/var/adm/inst-log/info') as f:
247 for line in f:
248 tv = line.split()
249 if len(tv) == 2:
250 tag, value = tv
251 else:
252 continue
253 if tag == 'MIN_DIST_VERSION':
254 version = value.strip()
255 elif tag == 'DIST_IDENT':
256 values = value.split('-')
257 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100258 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000259
260 if os.path.exists('/etc/.installed'):
261 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Victor Stinner7eeab872018-11-29 12:31:08 +0100262 with open('/etc/.installed') as f:
263 for line in f:
264 pkg = line.split('-')
265 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
266 # XXX does Caldera support non Intel platforms ? If yes,
267 # where can we find the needed id ?
268 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000269
270 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300271 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000272 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000273 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000274 if verfiles[n][:14] != 'slack-version-':
275 del verfiles[n]
276 if verfiles:
277 verfiles.sort()
278 distname = 'slackware'
279 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100280 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000281
Victor Stinnerced39362013-12-09 00:14:52 +0100282 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000283
Antoine Pitroufd036452008-08-19 17:56:33 +0000284_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000285_lsb_release_version = re.compile(r'(.+)'
R David Murray44b548d2016-09-08 13:59:53 -0400286 r' release '
287 r'([\d.]+)'
288 r'[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000289_release_version = re.compile(r'([^0-9]+)'
R David Murray44b548d2016-09-08 13:59:53 -0400290 r'(?: release )?'
291 r'([\d.]+)'
292 r'[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000293
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000294# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000295# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000296# and http://data.linux-ntfs.org/rpm/whichrpm
297# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000298
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000299_supported_dists = (
300 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
301 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200302 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000303
304def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000305
Benjamin Peterson25001472010-01-25 03:37:42 +0000306 # Default to empty 'version' and 'id' strings. Both defaults are used
307 # when 'firstline' is empty. 'id' defaults to empty when an id can not
308 # be deduced.
309 version = ''
310 id = ''
311
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000312 # Parse the first line
313 m = _lsb_release_version.match(firstline)
314 if m is not None:
315 # LSB format: "distro release x.x (codename)"
316 return tuple(m.groups())
317
318 # Pre-LSB format: "distro x.x (codename)"
319 m = _release_version.match(firstline)
320 if m is not None:
321 return tuple(m.groups())
322
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300323 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000324 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000325 if l:
326 version = l[0]
327 if len(l) > 1:
328 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000329 return '', version, id
330
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000331def linux_distribution(distname='', version='', id='',
332
333 supported_dists=_supported_dists,
334 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300335 import warnings
336 warnings.warn("dist() and linux_distribution() functions are deprecated "
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -0700337 "in Python 3.5", DeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300338 return _linux_distribution(distname, version, id, supported_dists,
339 full_distribution_name)
340
341def _linux_distribution(distname, version, id, supported_dists,
342 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000343
344 """ Tries to determine the name of the Linux OS distribution name.
345
346 The function first looks for a distribution release file in
347 /etc and then reverts to _dist_try_harder() in case no
348 suitable files are found.
349
350 supported_dists may be given to define the set of Linux
351 distributions to look for. It defaults to a list of currently
352 supported Linux distributions identified by their release file
353 name.
354
355 If full_distribution_name is true (default), the full
356 distribution read from the OS is returned. Otherwise the short
357 name taken from supported_dists is used.
358
Victor Stinnerced39362013-12-09 00:14:52 +0100359 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000360 args given as parameters.
361
362 """
363 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100364 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200365 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000366 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100367 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000368 etc.sort()
369 for file in etc:
370 m = _release_filename.match(file)
371 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100372 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000373 if _distname in supported_dists:
374 distname = _distname
375 break
376 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100377 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000378
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000379 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100380 with open(os.path.join(_UNIXCONFDIR, file), 'r',
381 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000382 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000383 _distname, _version, _id = _parse_release_file(firstline)
384
385 if _distname and full_distribution_name:
386 distname = _distname
387 if _version:
388 version = _version
389 if _id:
390 id = _id
391 return distname, version, id
392
393# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000394
Victor Stinnerced39362013-12-09 00:14:52 +0100395def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000396
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000397 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000398
Brett Cannon8ab27df2003-08-05 03:52:04 +0000399 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000400
401 The function first looks for a distribution release file in
402 /etc and then reverts to _dist_try_harder() in case no
403 suitable files are found.
404
Victor Stinnerced39362013-12-09 00:14:52 +0100405 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000406 args given as parameters.
407
408 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300409 import warnings
410 warnings.warn("dist() and linux_distribution() functions are deprecated "
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -0700411 "in Python 3.5", DeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300412 return _linux_distribution(distname, version, id,
413 supported_dists=supported_dists,
414 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000415
Antoine Pitrou877766d2011-03-19 17:00:37 +0100416def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000417
418 """ Portable popen() interface.
419 """
Victor Stinner25000d42011-05-24 00:16:16 +0200420 import warnings
421 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000422 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000423
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300424
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000425def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000426
Brett Cannon8ab27df2003-08-05 03:52:04 +0000427 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000428 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000429 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000430 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000431 if build:
432 l.append(build)
433 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100434 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000435 except ValueError:
436 strings = l
437 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100438 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000439 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000440 return version
441
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000442_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400443 r'.*'
444 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000445
446# Examples of VER command output:
447#
448# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
449# Windows XP: Microsoft Windows XP [Version 5.1.2600]
450# Windows Vista: Microsoft Windows [Version 6.0.6002]
451#
452# Note that the "Version" string gets localized on different
453# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000454
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000455def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
Victor Stinnerced39362013-12-09 00:14:52 +0100457 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458
459 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100460 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000461
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200463 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000464
465 In case this fails, the given parameters are used as
466 defaults.
467
468 """
469 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100470 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000471
472 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100473 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000474 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700475 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000476 info = pipe.read()
477 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200478 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200479 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000480 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200481 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100482 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000483 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000484 else:
485 break
486 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100487 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488
489 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000490 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000491 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000492 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100493 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000494 # Strip trailing dots from version and release
495 if release[-1] == '.':
496 release = release[:-1]
497 if version[-1] == '.':
498 version = version[:-1]
499 # Normalize the version and build strings (eliminating additional
500 # zeros)
501 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100502 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000503
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700504_WIN32_CLIENT_RELEASES = {
505 (5, 0): "2000",
506 (5, 1): "XP",
507 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
508 # has always called it 2003 Server
509 (5, 2): "2003Server",
510 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000511
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700512 (6, 0): "Vista",
513 (6, 1): "7",
514 (6, 2): "8",
515 (6, 3): "8.1",
516 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000517
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700518 (10, 0): "10",
519 (10, None): "post10",
520}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000521
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700522# Server release name lookup will default to client names if necessary
523_WIN32_SERVER_RELEASES = {
524 (5, 2): "2003Server",
525
526 (6, 0): "2008Server",
527 (6, 1): "2008ServerR2",
528 (6, 2): "2012Server",
529 (6, 3): "2012ServerR2",
530 (6, None): "post2012ServerR2",
531}
532
Victor Stinnerced39362013-12-09 00:14:52 +0100533def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700534 try:
535 from sys import getwindowsversion
536 except ImportError:
537 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000538 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700539 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400540 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700541 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
542
543 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700544 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700545 version = '{0}.{1}.{2}'.format(maj, min, build)
546
547 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
548 _WIN32_CLIENT_RELEASES.get((maj, None)) or
549 release)
550
551 # getwindowsversion() reflect the compatibility mode Python is
552 # running under, and so the service pack value is only going to be
553 # valid if the versions match.
554 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000555 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700556 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000557 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700558 if csd[:13] == 'Service Pack ':
559 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000560
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700561 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700562 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700563 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
564 _WIN32_SERVER_RELEASES.get((maj, None)) or
565 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000566
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700567 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000568 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700569 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
570 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
571 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000572 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700573 pass
574 finally:
575 if key:
576 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000577
Victor Stinnerced39362013-12-09 00:14:52 +0100578 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000579
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700580
Ronald Oussorene186e382010-07-23 11:54:59 +0000581def _mac_ver_xml():
582 fn = '/System/Library/CoreServices/SystemVersion.plist'
583 if not os.path.exists(fn):
584 return None
585
586 try:
587 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400588 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000589 return None
590
Ned Deily936dfae2014-01-13 11:34:19 -0800591 with open(fn, 'rb') as f:
592 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000593 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100594 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700595 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000596 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300597 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000598 machine = 'PowerPC'
599
Victor Stinnerced39362013-12-09 00:14:52 +0100600 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000601
602
Victor Stinnerced39362013-12-09 00:14:52 +0100603def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000604
605 """ Get MacOS version information and return it as tuple (release,
606 versioninfo, machine) with versioninfo being a tuple (version,
607 dev_stage, non_release_version).
608
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300609 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000610 which default to ''. All tuple entries are strings.
611 """
612
613 # First try reading the information from an XML file which should
614 # always be present
615 info = _mac_ver_xml()
616 if info is not None:
617 return info
618
Ronald Oussorene186e382010-07-23 11:54:59 +0000619 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100620 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000621
Victor Stinnerced39362013-12-09 00:14:52 +0100622def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000623
624 from java.lang import System
625 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000626 value = System.getProperty(name)
627 if value is None:
628 return default
629 return value
630 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000631 return default
632
Victor Stinnerced39362013-12-09 00:14:52 +0100633def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000634
Brett Cannon8ab27df2003-08-05 03:52:04 +0000635 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636
Victor Stinnerced39362013-12-09 00:14:52 +0100637 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
638 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
639 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000640
641 Values which cannot be determined are set to the defaults
642 given as parameters (which all default to '').
643
644 """
645 # Import the needed APIs
646 try:
647 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400648 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100649 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000651 vendor = _java_getprop('java.vendor', vendor)
652 release = _java_getprop('java.version', release)
653 vm_name, vm_release, vm_vendor = vminfo
654 vm_name = _java_getprop('java.vm.name', vm_name)
655 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
656 vm_release = _java_getprop('java.vm.version', vm_release)
657 vminfo = vm_name, vm_release, vm_vendor
658 os_name, os_version, os_arch = osinfo
659 os_arch = _java_getprop('java.os.arch', os_arch)
660 os_name = _java_getprop('java.os.name', os_name)
661 os_version = _java_getprop('java.os.version', os_version)
662 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000663
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000664 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665
666### System name aliasing
667
Victor Stinnerced39362013-12-09 00:14:52 +0100668def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000669
Victor Stinnerced39362013-12-09 00:14:52 +0100670 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000671 marketing names used for some systems.
672
673 It also does some reordering of the information in some cases
674 where it would otherwise cause confusion.
675
676 """
677 if system == 'Rhapsody':
678 # Apple's BSD derivative
679 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100680 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000681
682 elif system == 'SunOS':
683 # Sun's OS
684 if release < '5':
685 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100686 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000688 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000689 if l:
690 try:
691 major = int(l[0])
692 except ValueError:
693 pass
694 else:
695 major = major - 3
696 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000697 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698 if release < '6':
699 system = 'Solaris'
700 else:
701 # XXX Whatever the new SunOS marketing name is...
702 system = 'Solaris'
703
704 elif system == 'IRIX64':
705 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
706 # is really a version and not a different platform, since 32-bit
707 # apps are also supported..
708 system = 'IRIX'
709 if version:
710 version = version + ' (64bit)'
711 else:
712 version = '64bit'
713
Victor Stinnerced39362013-12-09 00:14:52 +0100714 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000715 # In case one of the other tricks
716 system = 'Windows'
717
Victor Stinnerced39362013-12-09 00:14:52 +0100718 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000719
720### Various internal helpers
721
722def _platform(*args):
723
724 """ Helper to format the platform string in a filename
725 compatible format e.g. "system-version-machine".
726 """
727 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000728 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000729
730 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100731 platform = platform.replace(' ', '_')
732 platform = platform.replace('/', '-')
733 platform = platform.replace('\\', '-')
734 platform = platform.replace(':', '-')
735 platform = platform.replace(';', '-')
736 platform = platform.replace('"', '-')
737 platform = platform.replace('(', '-')
738 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000739
740 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100741 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000742
743 # Fold '--'s and remove trailing '-'
744 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100745 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746 if cleaned == platform:
747 break
748 platform = cleaned
749 while platform[-1] == '-':
750 platform = platform[:-1]
751
752 return platform
753
754def _node(default=''):
755
756 """ Helper to determine the node name of this machine.
757 """
758 try:
759 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400760 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000761 # No sockets...
762 return default
763 try:
764 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200765 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000766 # Still not working...
767 return default
768
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000769def _follow_symlinks(filepath):
770
771 """ In case filepath is a symlink, follow it until a
772 real file is reached.
773 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000774 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000775 while os.path.islink(filepath):
776 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100777 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000778 return filepath
779
Victor Stinnerced39362013-12-09 00:14:52 +0100780def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000781
782 """ Interface to the system's uname command.
783 """
Victor Stinnerced39362013-12-09 00:14:52 +0100784 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000785 # XXX Others too ?
786 return default
787 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000788 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200789 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000790 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000791 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000792 rc = f.close()
793 if not output or rc:
794 return default
795 else:
796 return output
797
Victor Stinnerced39362013-12-09 00:14:52 +0100798def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000799
800 """ Interface to the system's file command.
801
802 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000803 omit the filename in its output. Follow the symlinks. It returns
804 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805
806 """
Victor Stinnerced39362013-12-09 00:14:52 +0100807 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000808 # XXX Others too ?
809 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200810 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000811 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200812 proc = subprocess.Popen(['file', target],
813 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200814
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200815 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000816 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200817 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200818 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000819 if not output or rc:
820 return default
821 else:
822 return output
823
824### Information about the used architecture
825
826# Default values for architecture; non-empty strings override the
827# defaults given as parameters
828_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100829 'win32': ('', 'WindowsPE'),
830 'win16': ('', 'Windows'),
831 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000832}
833
Victor Stinnerced39362013-12-09 00:14:52 +0100834def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000835
836 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000837 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000838
Victor Stinnerced39362013-12-09 00:14:52 +0100839 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840 the bit architecture and the linkage format used for the
841 executable. Both values are returned as strings.
842
843 Values that cannot be determined are returned as given by the
844 parameter presets. If bits is given as '', the sizeof(pointer)
845 (or sizeof(long) on Python version < 1.5.2) is used as
846 indicator for the supported pointer size.
847
848 The function relies on the system's "file" command to do the
849 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000850 platforms. On some non-Unix platforms where the "file" command
851 does not exist and the executable is set to the Python interpreter
852 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000853
854 """
855 # Use the sizeof(pointer) as default number of bits if nothing
856 # else is given as default.
857 if not bits:
858 import struct
859 try:
860 size = struct.calcsize('P')
861 except struct.error:
862 # Older installations can only query longs
863 size = struct.calcsize('l')
864 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000865
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000866 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000867 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000868 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000869 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000870 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000871
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000872 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000873 executable == sys.executable:
874 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000875 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000876 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100877 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000878 if b:
879 bits = b
880 if l:
881 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100882 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000883
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000884 if 'executable' not in fileout:
885 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100886 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000887
888 # Bits
889 if '32-bit' in fileout:
890 bits = '32bit'
891 elif 'N32' in fileout:
892 # On Irix only
893 bits = 'n32bit'
894 elif '64-bit' in fileout:
895 bits = '64bit'
896
897 # Linkage
898 if 'ELF' in fileout:
899 linkage = 'ELF'
900 elif 'PE' in fileout:
901 # E.g. Windows uses this format
902 if 'Windows' in fileout:
903 linkage = 'WindowsPE'
904 else:
905 linkage = 'PE'
906 elif 'COFF' in fileout:
907 linkage = 'COFF'
908 elif 'MS-DOS' in fileout:
909 linkage = 'MSDOS'
910 else:
911 # XXX the A.OUT format also falls under this class...
912 pass
913
Victor Stinnerced39362013-12-09 00:14:52 +0100914 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000915
916### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000917
Larry Hastings68386bc2012-06-24 14:30:41 -0700918uname_result = collections.namedtuple("uname_result",
919 "system node release version machine processor")
920
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000921_uname_cache = None
922
923def uname():
924
925 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100926 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000927 identifying the underlying platform.
928
929 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000930 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000931
932 Entries which cannot be determined are set to ''.
933
934 """
935 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000936 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000937
938 if _uname_cache is not None:
939 return _uname_cache
940
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000941 processor = ''
942
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000943 # Get some infos from the builtin os.uname API...
944 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100945 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000946 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000947 no_os_uname = 1
948
Georg Brandl62e2ca22010-07-31 21:54:24 +0000949 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000950 # Hmm, no there is either no uname or uname has returned
951 #'unknowns'... we'll have to poke around the system then.
952 if no_os_uname:
953 system = sys.platform
954 release = ''
955 version = ''
956 node = _node()
957 machine = ''
958
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000959 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000960
961 # Try win32_ver() on win32 platforms
962 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100963 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000964 if release and version:
965 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000966 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000967 # available on Win XP and later; see
968 # http://support.microsoft.com/kb/888731 and
969 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000970 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000971 # WOW64 processes mask the native architecture
972 if "PROCESSOR_ARCHITEW6432" in os.environ:
973 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
974 else:
975 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000976 if not processor:
977 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000978
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000979 # Try the 'ver' system command available on some
980 # platforms
981 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100982 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000983 # Normalize system to what win32_ver() normally returns
984 # (_syscmd_ver() tends to return the vendor name as well)
985 if system == 'Microsoft Windows':
986 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000987 elif system == 'Microsoft' and release == 'Windows':
988 # Under Windows Vista and Windows Server 2008,
989 # Microsoft changed the output of the ver command. The
990 # release is no longer printed. This causes the
991 # system and release to be misidentified.
992 system = 'Windows'
993 if '6.0' == version[:3]:
994 release = 'Vista'
995 else:
996 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000997
998 # In case we still don't know anything useful, we'll try to
999 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001000 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001001 if not version:
1002 if system == 'win32':
1003 version = '32bit'
1004 else:
1005 version = '16bit'
1006 system = 'Windows'
1007
1008 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001009 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001010 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001011 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001012 if not version:
1013 version = vendor
1014
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001015 # System specific extensions
1016 if system == 'OpenVMS':
1017 # OpenVMS seems to have release and version mixed up
1018 if not release or release == '0':
1019 release = version
1020 version = ''
1021 # Get processor information
1022 try:
1023 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001024 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001025 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001026 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001027 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001028 if (cpu_number >= 128):
1029 processor = 'Alpha'
1030 else:
1031 processor = 'VAX'
1032 if not processor:
1033 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001034 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001035
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001036 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001037 if system == 'unknown':
1038 system = ''
1039 if node == 'unknown':
1040 node = ''
1041 if release == 'unknown':
1042 release = ''
1043 if version == 'unknown':
1044 version = ''
1045 if machine == 'unknown':
1046 machine = ''
1047 if processor == 'unknown':
1048 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001049
1050 # normalize name
1051 if system == 'Microsoft' and release == 'Windows':
1052 system = 'Windows'
1053 release = 'Vista'
1054
Victor Stinnerced39362013-12-09 00:14:52 +01001055 _uname_cache = uname_result(system, node, release, version,
1056 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001057 return _uname_cache
1058
1059### Direct interfaces to some of the uname() return values
1060
1061def system():
1062
1063 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1064
1065 An empty string is returned if the value cannot be determined.
1066
1067 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001068 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001069
1070def node():
1071
Brett Cannon8ab27df2003-08-05 03:52:04 +00001072 """ Returns the computer's network name (which may not be fully
1073 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001074
1075 An empty string is returned if the value cannot be determined.
1076
1077 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001078 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001079
1080def release():
1081
1082 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1083
1084 An empty string is returned if the value cannot be determined.
1085
1086 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001087 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001088
1089def version():
1090
1091 """ Returns the system's release version, e.g. '#3 on degas'
1092
1093 An empty string is returned if the value cannot be determined.
1094
1095 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001096 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001097
1098def machine():
1099
1100 """ Returns the machine type, e.g. 'i386'
1101
1102 An empty string is returned if the value cannot be determined.
1103
1104 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001105 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001106
1107def processor():
1108
1109 """ Returns the (true) processor name, e.g. 'amdk6'
1110
1111 An empty string is returned if the value cannot be
1112 determined. Note that many platforms do not provide this
1113 information or simply return the same value as for machine(),
1114 e.g. NetBSD does this.
1115
1116 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001117 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001118
1119### Various APIs for extracting information from sys.version
1120
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001121_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001122 r'([\w.+]+)\s*' # "version<space>"
1123 r'\(#?([^,]+)' # "(#buildno"
1124 r'(?:,\s*([\w ]*)' # ", builddate"
1125 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1126 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001127
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001128_ironpython_sys_version_parser = re.compile(
1129 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001130 r'([\d\.]+)'
1131 r'(?: \(([\d\.]+)\))?'
1132 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001133
Ezio Melottif076f532013-10-21 03:03:32 +03001134# IronPython covering 2.6 and 2.7
1135_ironpython26_sys_version_parser = re.compile(
1136 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001137 r'\(IronPython\s*'
1138 r'[\d.]+\s*'
1139 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +03001140)
1141
Benjamin Petersone549ead2009-03-28 21:42:05 +00001142_pypy_sys_version_parser = re.compile(
1143 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001144 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1145 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +00001146
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001147_sys_version_cache = {}
1148
1149def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001150
1151 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001152 (name, version, branch, revision, buildno, builddate, compiler)
1153 referring to the Python implementation name, version, branch,
1154 revision, build number, build date/time as string and the compiler
1155 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001156
1157 Note that unlike the Python sys.version, the returned value
1158 for the Python version will always include the patchlevel (it
1159 defaults to '.0').
1160
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001161 The function returns empty strings for tuple entries that
1162 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001163
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001164 sys_version may be given to parse an alternative version
1165 string, e.g. if the version was read from a different Python
1166 interpreter.
1167
1168 """
1169 # Get the Python version
1170 if sys_version is None:
1171 sys_version = sys.version
1172
1173 # Try the cache first
1174 result = _sys_version_cache.get(sys_version, None)
1175 if result is not None:
1176 return result
1177
1178 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001179 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001180 # IronPython
1181 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001182 if sys_version.startswith('IronPython'):
1183 match = _ironpython_sys_version_parser.match(sys_version)
1184 else:
1185 match = _ironpython26_sys_version_parser.match(sys_version)
1186
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001187 if match is None:
1188 raise ValueError(
1189 'failed to parse IronPython sys.version: %s' %
1190 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001191
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001192 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001193 buildno = ''
1194 builddate = ''
1195
Ezio Melottif076f532013-10-21 03:03:32 +03001196 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001197 # Jython
1198 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001199 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001200 if match is None:
1201 raise ValueError(
1202 'failed to parse Jython sys.version: %s' %
1203 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001204 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001205 if builddate is None:
1206 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001207 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001208
1209 elif "PyPy" in sys_version:
1210 # PyPy
1211 name = "PyPy"
1212 match = _pypy_sys_version_parser.match(sys_version)
1213 if match is None:
1214 raise ValueError("failed to parse PyPy sys.version: %s" %
1215 repr(sys_version))
1216 version, buildno, builddate, buildtime = match.groups()
1217 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001218
1219 else:
1220 # CPython
1221 match = _sys_version_parser.match(sys_version)
1222 if match is None:
1223 raise ValueError(
1224 'failed to parse CPython sys.version: %s' %
1225 repr(sys_version))
1226 version, buildno, builddate, buildtime, compiler = \
1227 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001228 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001229 if builddate is None:
1230 builddate = ''
1231 elif buildtime:
1232 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001233
Ned Deily5c4b0d02017-03-04 00:19:55 -05001234 if hasattr(sys, '_git'):
1235 _, branch, revision = sys._git
1236 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001237 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001238 else:
1239 branch = ''
1240 revision = ''
1241
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001242 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001243 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001244 if len(l) == 2:
1245 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001246 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001247
1248 # Build and cache the result
1249 result = (name, version, branch, revision, buildno, builddate, compiler)
1250 _sys_version_cache[sys_version] = result
1251 return result
1252
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001253def python_implementation():
1254
1255 """ Returns a string identifying the Python implementation.
1256
1257 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001258 'CPython' (C implementation of Python),
1259 'IronPython' (.NET implementation of Python),
1260 'Jython' (Java implementation of Python),
1261 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001262
1263 """
1264 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001265
1266def python_version():
1267
1268 """ Returns the Python version as string 'major.minor.patchlevel'
1269
1270 Note that unlike the Python sys.version, the returned value
1271 will always include the patchlevel (it defaults to 0).
1272
1273 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001274 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001275
1276def python_version_tuple():
1277
1278 """ Returns the Python version as tuple (major, minor, patchlevel)
1279 of strings.
1280
1281 Note that unlike the Python sys.version, the returned value
1282 will always include the patchlevel (it defaults to 0).
1283
1284 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001285 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001286
1287def python_branch():
1288
1289 """ Returns a string identifying the Python implementation
1290 branch.
1291
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001292 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001293 Python binary was built.
1294
1295 If not available, an empty string is returned.
1296
1297 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001298
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001299 return _sys_version()[2]
1300
1301def python_revision():
1302
1303 """ Returns a string identifying the Python implementation
1304 revision.
1305
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001306 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001307 Python binary was built.
1308
1309 If not available, an empty string is returned.
1310
1311 """
1312 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001313
1314def python_build():
1315
1316 """ Returns a tuple (buildno, builddate) stating the Python
1317 build number and date as strings.
1318
1319 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001320 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001321
1322def python_compiler():
1323
1324 """ Returns a string identifying the compiler used for compiling
1325 Python.
1326
1327 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001328 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001329
1330### The Opus Magnum of platform strings :-)
1331
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001332_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001333
1334def platform(aliased=0, terse=0):
1335
1336 """ Returns a single string identifying the underlying platform
1337 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001338
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001339 The output is intended to be human readable rather than
1340 machine parseable. It may look different on different
1341 platforms and this is intended.
1342
1343 If "aliased" is true, the function will use aliases for
1344 various platforms that report system names which differ from
1345 their common names, e.g. SunOS will be reported as
1346 Solaris. The system_alias() function is used to implement
1347 this.
1348
1349 Setting terse to true causes the function to return only the
1350 absolute minimum information needed to identify the platform.
1351
1352 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001353 result = _platform_cache.get((aliased, terse), None)
1354 if result is not None:
1355 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001356
1357 # Get uname information and then apply platform specific cosmetics
1358 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001359 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001360 if machine == processor:
1361 processor = ''
1362 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001363 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001364
1365 if system == 'Windows':
1366 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001367 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001368 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001369 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001370 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001371 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001372
1373 elif system in ('Linux',):
1374 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001375 with warnings.catch_warnings():
1376 # see issue #1322 for more information
1377 warnings.filterwarnings(
1378 'ignore',
R David Murray44b548d2016-09-08 13:59:53 -04001379 r'dist\(\) and linux_distribution\(\) '
Berker Peksag1392f712015-05-16 20:24:28 +03001380 'functions are deprecated .*',
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -07001381 DeprecationWarning,
Berker Peksag1392f712015-05-16 20:24:28 +03001382 )
1383 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001384 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001385 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001386 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001387 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001388 else:
1389 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001390 libcname, libcversion = libc_ver(sys.executable)
1391 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001392 'with',
1393 libcname+libcversion)
1394 elif system == 'Java':
1395 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001396 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001397 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001398 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001399 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001400 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001402 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001403
1404 elif system == 'MacOS':
1405 # MacOS platforms
1406 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001407 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001408 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001409 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001410
1411 else:
1412 # Generic handler
1413 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001414 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001415 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001416 bits, linkage = architecture(sys.executable)
1417 platform = _platform(system, release, machine,
1418 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001419
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001420 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001421 return platform
1422
1423### Command line interface
1424
1425if __name__ == '__main__':
1426 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001427 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001428 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001429 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001430 sys.exit(0)