blob: cc2db9870d84b693d140d63c4d769fc48cbda3c5 [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
Berker Peksagbb59d892017-02-27 19:14:11 +0300113__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
Victor Stinnerced39362013-12-09 00:14:52 +0100147def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000148
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200149 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000150
Brett Cannon8ab27df2003-08-05 03:52:04 +0000151 """ Tries to determine the libc version that the file executable
152 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000153
154 Returns a tuple of strings (lib,version) which default to the
155 given parameters in case the lookup fails.
156
157 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000158 libc versions add symbols to the executable and thus is probably
159 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000160
161 The file is read and scanned in chunks of chunksize bytes.
162
163 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000164 if hasattr(os.path, 'realpath'):
165 # Python 2.2 introduced os.path.realpath(); it is used
166 # here to work around problems with Cygwin not being
167 # able to open symlinks for reading
168 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300169 with open(executable, 'rb') as f:
170 binary = f.read(chunksize)
171 pos = 0
172 while 1:
173 if b'libc' in binary or b'GLIBC' in binary:
174 m = _libc_search.search(binary, pos)
175 else:
176 m = None
177 if not m:
178 binary = f.read(chunksize)
179 if not binary:
180 break
181 pos = 0
182 continue
183 libcinit, glibc, glibcversion, so, threads, soversion = [
184 s.decode('latin1') if s is not None else s
185 for s in m.groups()]
186 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000187 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300188 elif glibc:
189 if lib != 'glibc':
190 lib = 'glibc'
191 version = glibcversion
192 elif glibcversion > version:
193 version = glibcversion
194 elif so:
195 if lib != 'glibc':
196 lib = 'libc'
197 if soversion and soversion > version:
198 version = soversion
199 if threads and version[-len(threads):] != threads:
200 version = version + threads
201 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100202 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000203
Victor Stinnerced39362013-12-09 00:14:52 +0100204def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000205
Tim Peters0eadaac2003-04-24 16:02:54 +0000206 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 information in case the default method fails.
208
209 Currently supports older SuSE Linux, Caldera OpenLinux and
210 Slackware Linux distributions.
211
212 """
213 if os.path.exists('/var/adm/inst-log/info'):
214 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000216 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000217 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000218 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100219 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000220 else:
221 continue
222 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000223 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000224 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000225 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000226 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100227 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000228
229 if os.path.exists('/etc/.installed'):
230 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000231 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000232 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000233 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
234 # XXX does Caldera support non Intel platforms ? If yes,
235 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100236 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000237
238 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300239 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000240 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000241 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000242 if verfiles[n][:14] != 'slack-version-':
243 del verfiles[n]
244 if verfiles:
245 verfiles.sort()
246 distname = 'slackware'
247 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100248 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000249
Victor Stinnerced39362013-12-09 00:14:52 +0100250 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000251
Antoine Pitroufd036452008-08-19 17:56:33 +0000252_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000253_lsb_release_version = re.compile(r'(.+)'
R David Murray44b548d2016-09-08 13:59:53 -0400254 r' release '
255 r'([\d.]+)'
256 r'[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000257_release_version = re.compile(r'([^0-9]+)'
R David Murray44b548d2016-09-08 13:59:53 -0400258 r'(?: release )?'
259 r'([\d.]+)'
260 r'[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000261
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000262# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000263# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000264# and http://data.linux-ntfs.org/rpm/whichrpm
265# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000266
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000267_supported_dists = (
268 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
269 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200270 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000271
272def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000273
Benjamin Peterson25001472010-01-25 03:37:42 +0000274 # Default to empty 'version' and 'id' strings. Both defaults are used
275 # when 'firstline' is empty. 'id' defaults to empty when an id can not
276 # be deduced.
277 version = ''
278 id = ''
279
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000280 # Parse the first line
281 m = _lsb_release_version.match(firstline)
282 if m is not None:
283 # LSB format: "distro release x.x (codename)"
284 return tuple(m.groups())
285
286 # Pre-LSB format: "distro x.x (codename)"
287 m = _release_version.match(firstline)
288 if m is not None:
289 return tuple(m.groups())
290
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300291 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000292 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000293 if l:
294 version = l[0]
295 if len(l) > 1:
296 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000297 return '', version, id
298
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000299def linux_distribution(distname='', version='', id='',
300
301 supported_dists=_supported_dists,
302 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300303 import warnings
304 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300305 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300306 return _linux_distribution(distname, version, id, supported_dists,
307 full_distribution_name)
308
309def _linux_distribution(distname, version, id, supported_dists,
310 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000311
312 """ Tries to determine the name of the Linux OS distribution name.
313
314 The function first looks for a distribution release file in
315 /etc and then reverts to _dist_try_harder() in case no
316 suitable files are found.
317
318 supported_dists may be given to define the set of Linux
319 distributions to look for. It defaults to a list of currently
320 supported Linux distributions identified by their release file
321 name.
322
323 If full_distribution_name is true (default), the full
324 distribution read from the OS is returned. Otherwise the short
325 name taken from supported_dists is used.
326
Victor Stinnerced39362013-12-09 00:14:52 +0100327 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000328 args given as parameters.
329
330 """
331 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100332 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200333 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000334 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100335 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000336 etc.sort()
337 for file in etc:
338 m = _release_filename.match(file)
339 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100340 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000341 if _distname in supported_dists:
342 distname = _distname
343 break
344 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100345 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000346
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000347 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100348 with open(os.path.join(_UNIXCONFDIR, file), 'r',
349 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000350 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000351 _distname, _version, _id = _parse_release_file(firstline)
352
353 if _distname and full_distribution_name:
354 distname = _distname
355 if _version:
356 version = _version
357 if _id:
358 id = _id
359 return distname, version, id
360
361# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000362
Victor Stinnerced39362013-12-09 00:14:52 +0100363def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000364
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000365 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000366
Brett Cannon8ab27df2003-08-05 03:52:04 +0000367 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000368
369 The function first looks for a distribution release file in
370 /etc and then reverts to _dist_try_harder() in case no
371 suitable files are found.
372
Victor Stinnerced39362013-12-09 00:14:52 +0100373 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000374 args given as parameters.
375
376 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300377 import warnings
378 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300379 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300380 return _linux_distribution(distname, version, id,
381 supported_dists=supported_dists,
382 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383
Antoine Pitrou877766d2011-03-19 17:00:37 +0100384def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000385
386 """ Portable popen() interface.
387 """
Victor Stinner25000d42011-05-24 00:16:16 +0200388 import warnings
389 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000390 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000391
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000392def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000393
Brett Cannon8ab27df2003-08-05 03:52:04 +0000394 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000395 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000396 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000397 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000398 if build:
399 l.append(build)
400 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100401 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000402 except ValueError:
403 strings = l
404 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100405 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000406 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000407 return version
408
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000409_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400410 r'.*'
411 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000412
413# Examples of VER command output:
414#
415# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
416# Windows XP: Microsoft Windows XP [Version 5.1.2600]
417# Windows Vista: Microsoft Windows [Version 6.0.6002]
418#
419# Note that the "Version" string gets localized on different
420# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000421
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000422def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000423
Victor Stinnerced39362013-12-09 00:14:52 +0100424 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000425
426 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100427 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000428
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000429 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200430 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000431
432 In case this fails, the given parameters are used as
433 defaults.
434
435 """
436 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100437 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000438
439 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100440 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700442 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000443 info = pipe.read()
444 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200445 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200446 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000447 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200448 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100449 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000450 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000451 else:
452 break
453 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100454 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000455
456 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000457 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000458 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000459 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100460 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000461 # Strip trailing dots from version and release
462 if release[-1] == '.':
463 release = release[:-1]
464 if version[-1] == '.':
465 version = version[:-1]
466 # Normalize the version and build strings (eliminating additional
467 # zeros)
468 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100469 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000470
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700471_WIN32_CLIENT_RELEASES = {
472 (5, 0): "2000",
473 (5, 1): "XP",
474 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
475 # has always called it 2003 Server
476 (5, 2): "2003Server",
477 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000478
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700479 (6, 0): "Vista",
480 (6, 1): "7",
481 (6, 2): "8",
482 (6, 3): "8.1",
483 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000484
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700485 (10, 0): "10",
486 (10, None): "post10",
487}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700489# Server release name lookup will default to client names if necessary
490_WIN32_SERVER_RELEASES = {
491 (5, 2): "2003Server",
492
493 (6, 0): "2008Server",
494 (6, 1): "2008ServerR2",
495 (6, 2): "2012Server",
496 (6, 3): "2012ServerR2",
497 (6, None): "post2012ServerR2",
498}
499
Victor Stinnerced39362013-12-09 00:14:52 +0100500def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700501 try:
502 from sys import getwindowsversion
503 except ImportError:
504 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000505 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700506 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400507 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700508 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
509
510 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700511 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700512 version = '{0}.{1}.{2}'.format(maj, min, build)
513
514 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
515 _WIN32_CLIENT_RELEASES.get((maj, None)) or
516 release)
517
518 # getwindowsversion() reflect the compatibility mode Python is
519 # running under, and so the service pack value is only going to be
520 # valid if the versions match.
521 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000522 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700523 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000524 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700525 if csd[:13] == 'Service Pack ':
526 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000527
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700528 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700529 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700530 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
531 _WIN32_SERVER_RELEASES.get((maj, None)) or
532 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000533
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700534 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000535 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700536 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
537 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
538 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000539 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700540 pass
541 finally:
542 if key:
543 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000544
Victor Stinnerced39362013-12-09 00:14:52 +0100545 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000546
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700547
Ronald Oussorene186e382010-07-23 11:54:59 +0000548def _mac_ver_xml():
549 fn = '/System/Library/CoreServices/SystemVersion.plist'
550 if not os.path.exists(fn):
551 return None
552
553 try:
554 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400555 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000556 return None
557
Ned Deily936dfae2014-01-13 11:34:19 -0800558 with open(fn, 'rb') as f:
559 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000560 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100561 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700562 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000563 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300564 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000565 machine = 'PowerPC'
566
Victor Stinnerced39362013-12-09 00:14:52 +0100567 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000568
569
Victor Stinnerced39362013-12-09 00:14:52 +0100570def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000571
572 """ Get MacOS version information and return it as tuple (release,
573 versioninfo, machine) with versioninfo being a tuple (version,
574 dev_stage, non_release_version).
575
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300576 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000577 which default to ''. All tuple entries are strings.
578 """
579
580 # First try reading the information from an XML file which should
581 # always be present
582 info = _mac_ver_xml()
583 if info is not None:
584 return info
585
Ronald Oussorene186e382010-07-23 11:54:59 +0000586 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100587 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000588
Victor Stinnerced39362013-12-09 00:14:52 +0100589def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000590
591 from java.lang import System
592 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000593 value = System.getProperty(name)
594 if value is None:
595 return default
596 return value
597 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000598 return default
599
Victor Stinnerced39362013-12-09 00:14:52 +0100600def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000601
Brett Cannon8ab27df2003-08-05 03:52:04 +0000602 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000603
Victor Stinnerced39362013-12-09 00:14:52 +0100604 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
605 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
606 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000607
608 Values which cannot be determined are set to the defaults
609 given as parameters (which all default to '').
610
611 """
612 # Import the needed APIs
613 try:
614 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400615 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100616 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000617
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000618 vendor = _java_getprop('java.vendor', vendor)
619 release = _java_getprop('java.version', release)
620 vm_name, vm_release, vm_vendor = vminfo
621 vm_name = _java_getprop('java.vm.name', vm_name)
622 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
623 vm_release = _java_getprop('java.vm.version', vm_release)
624 vminfo = vm_name, vm_release, vm_vendor
625 os_name, os_version, os_arch = osinfo
626 os_arch = _java_getprop('java.os.arch', os_arch)
627 os_name = _java_getprop('java.os.name', os_name)
628 os_version = _java_getprop('java.os.version', os_version)
629 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000630
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000631 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000632
633### System name aliasing
634
Victor Stinnerced39362013-12-09 00:14:52 +0100635def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636
Victor Stinnerced39362013-12-09 00:14:52 +0100637 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638 marketing names used for some systems.
639
640 It also does some reordering of the information in some cases
641 where it would otherwise cause confusion.
642
643 """
644 if system == 'Rhapsody':
645 # Apple's BSD derivative
646 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100647 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000648
649 elif system == 'SunOS':
650 # Sun's OS
651 if release < '5':
652 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100653 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000655 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000656 if l:
657 try:
658 major = int(l[0])
659 except ValueError:
660 pass
661 else:
662 major = major - 3
663 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000664 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665 if release < '6':
666 system = 'Solaris'
667 else:
668 # XXX Whatever the new SunOS marketing name is...
669 system = 'Solaris'
670
671 elif system == 'IRIX64':
672 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
673 # is really a version and not a different platform, since 32-bit
674 # apps are also supported..
675 system = 'IRIX'
676 if version:
677 version = version + ' (64bit)'
678 else:
679 version = '64bit'
680
Victor Stinnerced39362013-12-09 00:14:52 +0100681 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000682 # In case one of the other tricks
683 system = 'Windows'
684
Victor Stinnerced39362013-12-09 00:14:52 +0100685 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686
687### Various internal helpers
688
689def _platform(*args):
690
691 """ Helper to format the platform string in a filename
692 compatible format e.g. "system-version-machine".
693 """
694 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000695 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000696
697 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100698 platform = platform.replace(' ', '_')
699 platform = platform.replace('/', '-')
700 platform = platform.replace('\\', '-')
701 platform = platform.replace(':', '-')
702 platform = platform.replace(';', '-')
703 platform = platform.replace('"', '-')
704 platform = platform.replace('(', '-')
705 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000706
707 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100708 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000709
710 # Fold '--'s and remove trailing '-'
711 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100712 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000713 if cleaned == platform:
714 break
715 platform = cleaned
716 while platform[-1] == '-':
717 platform = platform[:-1]
718
719 return platform
720
721def _node(default=''):
722
723 """ Helper to determine the node name of this machine.
724 """
725 try:
726 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400727 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000728 # No sockets...
729 return default
730 try:
731 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200732 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000733 # Still not working...
734 return default
735
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000736def _follow_symlinks(filepath):
737
738 """ In case filepath is a symlink, follow it until a
739 real file is reached.
740 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000741 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000742 while os.path.islink(filepath):
743 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100744 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000745 return filepath
746
Victor Stinnerced39362013-12-09 00:14:52 +0100747def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000748
749 """ Interface to the system's uname command.
750 """
Victor Stinnerced39362013-12-09 00:14:52 +0100751 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000752 # XXX Others too ?
753 return default
754 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000755 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200756 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000757 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000758 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000759 rc = f.close()
760 if not output or rc:
761 return default
762 else:
763 return output
764
Victor Stinnerced39362013-12-09 00:14:52 +0100765def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000766
767 """ Interface to the system's file command.
768
769 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000770 omit the filename in its output. Follow the symlinks. It returns
771 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000772
773 """
Victor Stinnerced39362013-12-09 00:14:52 +0100774 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000775 # XXX Others too ?
776 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200777 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000778 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200779 proc = subprocess.Popen(['file', target],
780 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200781
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200782 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000783 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200784 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200785 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000786 if not output or rc:
787 return default
788 else:
789 return output
790
791### Information about the used architecture
792
793# Default values for architecture; non-empty strings override the
794# defaults given as parameters
795_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100796 'win32': ('', 'WindowsPE'),
797 'win16': ('', 'Windows'),
798 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000799}
800
Victor Stinnerced39362013-12-09 00:14:52 +0100801def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000802
803 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000804 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805
Victor Stinnerced39362013-12-09 00:14:52 +0100806 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000807 the bit architecture and the linkage format used for the
808 executable. Both values are returned as strings.
809
810 Values that cannot be determined are returned as given by the
811 parameter presets. If bits is given as '', the sizeof(pointer)
812 (or sizeof(long) on Python version < 1.5.2) is used as
813 indicator for the supported pointer size.
814
815 The function relies on the system's "file" command to do the
816 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000817 platforms. On some non-Unix platforms where the "file" command
818 does not exist and the executable is set to the Python interpreter
819 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000820
821 """
822 # Use the sizeof(pointer) as default number of bits if nothing
823 # else is given as default.
824 if not bits:
825 import struct
826 try:
827 size = struct.calcsize('P')
828 except struct.error:
829 # Older installations can only query longs
830 size = struct.calcsize('l')
831 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000832
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000833 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000834 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000835 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000836 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000837 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000838
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000839 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840 executable == sys.executable:
841 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000842 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000843 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100844 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000845 if b:
846 bits = b
847 if l:
848 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100849 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000850
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000851 if 'executable' not in fileout:
852 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100853 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000854
855 # Bits
856 if '32-bit' in fileout:
857 bits = '32bit'
858 elif 'N32' in fileout:
859 # On Irix only
860 bits = 'n32bit'
861 elif '64-bit' in fileout:
862 bits = '64bit'
863
864 # Linkage
865 if 'ELF' in fileout:
866 linkage = 'ELF'
867 elif 'PE' in fileout:
868 # E.g. Windows uses this format
869 if 'Windows' in fileout:
870 linkage = 'WindowsPE'
871 else:
872 linkage = 'PE'
873 elif 'COFF' in fileout:
874 linkage = 'COFF'
875 elif 'MS-DOS' in fileout:
876 linkage = 'MSDOS'
877 else:
878 # XXX the A.OUT format also falls under this class...
879 pass
880
Victor Stinnerced39362013-12-09 00:14:52 +0100881 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000882
883### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000884
Larry Hastings68386bc2012-06-24 14:30:41 -0700885uname_result = collections.namedtuple("uname_result",
886 "system node release version machine processor")
887
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000888_uname_cache = None
889
890def uname():
891
892 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100893 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000894 identifying the underlying platform.
895
896 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000897 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000898
899 Entries which cannot be determined are set to ''.
900
901 """
902 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000903 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000904
905 if _uname_cache is not None:
906 return _uname_cache
907
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000908 processor = ''
909
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000910 # Get some infos from the builtin os.uname API...
911 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100912 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000913 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000914 no_os_uname = 1
915
Georg Brandl62e2ca22010-07-31 21:54:24 +0000916 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000917 # Hmm, no there is either no uname or uname has returned
918 #'unknowns'... we'll have to poke around the system then.
919 if no_os_uname:
920 system = sys.platform
921 release = ''
922 version = ''
923 node = _node()
924 machine = ''
925
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000926 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000927
928 # Try win32_ver() on win32 platforms
929 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100930 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000931 if release and version:
932 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000933 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000934 # available on Win XP and later; see
935 # http://support.microsoft.com/kb/888731 and
936 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000937 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000938 # WOW64 processes mask the native architecture
939 if "PROCESSOR_ARCHITEW6432" in os.environ:
940 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
941 else:
942 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000943 if not processor:
944 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000945
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000946 # Try the 'ver' system command available on some
947 # platforms
948 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100949 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000950 # Normalize system to what win32_ver() normally returns
951 # (_syscmd_ver() tends to return the vendor name as well)
952 if system == 'Microsoft Windows':
953 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000954 elif system == 'Microsoft' and release == 'Windows':
955 # Under Windows Vista and Windows Server 2008,
956 # Microsoft changed the output of the ver command. The
957 # release is no longer printed. This causes the
958 # system and release to be misidentified.
959 system = 'Windows'
960 if '6.0' == version[:3]:
961 release = 'Vista'
962 else:
963 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000964
965 # In case we still don't know anything useful, we'll try to
966 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100967 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000968 if not version:
969 if system == 'win32':
970 version = '32bit'
971 else:
972 version = '16bit'
973 system = 'Windows'
974
975 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100976 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000977 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000978 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000979 if not version:
980 version = vendor
981
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000982 # System specific extensions
983 if system == 'OpenVMS':
984 # OpenVMS seems to have release and version mixed up
985 if not release or release == '0':
986 release = version
987 version = ''
988 # Get processor information
989 try:
990 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400991 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000992 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000993 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100994 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000995 if (cpu_number >= 128):
996 processor = 'Alpha'
997 else:
998 processor = 'VAX'
999 if not processor:
1000 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001001 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001002
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001003 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001004 if system == 'unknown':
1005 system = ''
1006 if node == 'unknown':
1007 node = ''
1008 if release == 'unknown':
1009 release = ''
1010 if version == 'unknown':
1011 version = ''
1012 if machine == 'unknown':
1013 machine = ''
1014 if processor == 'unknown':
1015 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001016
1017 # normalize name
1018 if system == 'Microsoft' and release == 'Windows':
1019 system = 'Windows'
1020 release = 'Vista'
1021
Victor Stinnerced39362013-12-09 00:14:52 +01001022 _uname_cache = uname_result(system, node, release, version,
1023 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001024 return _uname_cache
1025
1026### Direct interfaces to some of the uname() return values
1027
1028def system():
1029
1030 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1031
1032 An empty string is returned if the value cannot be determined.
1033
1034 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001035 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001036
1037def node():
1038
Brett Cannon8ab27df2003-08-05 03:52:04 +00001039 """ Returns the computer's network name (which may not be fully
1040 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001041
1042 An empty string is returned if the value cannot be determined.
1043
1044 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001045 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001046
1047def release():
1048
1049 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1050
1051 An empty string is returned if the value cannot be determined.
1052
1053 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001054 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001055
1056def version():
1057
1058 """ Returns the system's release version, e.g. '#3 on degas'
1059
1060 An empty string is returned if the value cannot be determined.
1061
1062 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001063 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064
1065def machine():
1066
1067 """ Returns the machine type, e.g. 'i386'
1068
1069 An empty string is returned if the value cannot be determined.
1070
1071 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001072 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001073
1074def processor():
1075
1076 """ Returns the (true) processor name, e.g. 'amdk6'
1077
1078 An empty string is returned if the value cannot be
1079 determined. Note that many platforms do not provide this
1080 information or simply return the same value as for machine(),
1081 e.g. NetBSD does this.
1082
1083 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001084 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001085
1086### Various APIs for extracting information from sys.version
1087
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001088_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001089 r'([\w.+]+)\s*' # "version<space>"
1090 r'\(#?([^,]+)' # "(#buildno"
1091 r'(?:,\s*([\w ]*)' # ", builddate"
1092 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1093 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001094
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001095_ironpython_sys_version_parser = re.compile(
1096 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001097 r'([\d\.]+)'
1098 r'(?: \(([\d\.]+)\))?'
1099 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001100
Ezio Melottif076f532013-10-21 03:03:32 +03001101# IronPython covering 2.6 and 2.7
1102_ironpython26_sys_version_parser = re.compile(
1103 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001104 r'\(IronPython\s*'
1105 r'[\d.]+\s*'
1106 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +03001107)
1108
Benjamin Petersone549ead2009-03-28 21:42:05 +00001109_pypy_sys_version_parser = re.compile(
1110 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001111 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1112 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +00001113
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001114_sys_version_cache = {}
1115
1116def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001117
1118 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001119 (name, version, branch, revision, buildno, builddate, compiler)
1120 referring to the Python implementation name, version, branch,
1121 revision, build number, build date/time as string and the compiler
1122 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001123
1124 Note that unlike the Python sys.version, the returned value
1125 for the Python version will always include the patchlevel (it
1126 defaults to '.0').
1127
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001128 The function returns empty strings for tuple entries that
1129 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001130
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001131 sys_version may be given to parse an alternative version
1132 string, e.g. if the version was read from a different Python
1133 interpreter.
1134
1135 """
1136 # Get the Python version
1137 if sys_version is None:
1138 sys_version = sys.version
1139
1140 # Try the cache first
1141 result = _sys_version_cache.get(sys_version, None)
1142 if result is not None:
1143 return result
1144
1145 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001146 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001147 # IronPython
1148 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001149 if sys_version.startswith('IronPython'):
1150 match = _ironpython_sys_version_parser.match(sys_version)
1151 else:
1152 match = _ironpython26_sys_version_parser.match(sys_version)
1153
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001154 if match is None:
1155 raise ValueError(
1156 'failed to parse IronPython sys.version: %s' %
1157 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001158
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001159 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001160 buildno = ''
1161 builddate = ''
1162
Ezio Melottif076f532013-10-21 03:03:32 +03001163 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001164 # Jython
1165 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001166 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001167 if match is None:
1168 raise ValueError(
1169 'failed to parse Jython sys.version: %s' %
1170 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001171 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001172 if builddate is None:
1173 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001174 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001175
1176 elif "PyPy" in sys_version:
1177 # PyPy
1178 name = "PyPy"
1179 match = _pypy_sys_version_parser.match(sys_version)
1180 if match is None:
1181 raise ValueError("failed to parse PyPy sys.version: %s" %
1182 repr(sys_version))
1183 version, buildno, builddate, buildtime = match.groups()
1184 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001185
1186 else:
1187 # CPython
1188 match = _sys_version_parser.match(sys_version)
1189 if match is None:
1190 raise ValueError(
1191 'failed to parse CPython sys.version: %s' %
1192 repr(sys_version))
1193 version, buildno, builddate, buildtime, compiler = \
1194 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001195 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001196 if builddate is None:
1197 builddate = ''
1198 elif buildtime:
1199 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001200
Ned Deily95c50e52017-03-04 01:05:06 -05001201 if hasattr(sys, '_git'):
1202 _, branch, revision = sys._git
1203 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001204 _, branch, revision = sys._mercurial
1205 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001206 # sys.subversion was added in Python 2.5
1207 _, branch, revision = sys.subversion
1208 else:
1209 branch = ''
1210 revision = ''
1211
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001212 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001213 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001214 if len(l) == 2:
1215 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001216 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001217
1218 # Build and cache the result
1219 result = (name, version, branch, revision, buildno, builddate, compiler)
1220 _sys_version_cache[sys_version] = result
1221 return result
1222
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001223def python_implementation():
1224
1225 """ Returns a string identifying the Python implementation.
1226
1227 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001228 'CPython' (C implementation of Python),
1229 'IronPython' (.NET implementation of Python),
1230 'Jython' (Java implementation of Python),
1231 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001232
1233 """
1234 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001235
1236def python_version():
1237
1238 """ Returns the Python version as string 'major.minor.patchlevel'
1239
1240 Note that unlike the Python sys.version, the returned value
1241 will always include the patchlevel (it defaults to 0).
1242
1243 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001244 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001245
1246def python_version_tuple():
1247
1248 """ Returns the Python version as tuple (major, minor, patchlevel)
1249 of strings.
1250
1251 Note that unlike the Python sys.version, the returned value
1252 will always include the patchlevel (it defaults to 0).
1253
1254 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001255 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001256
1257def python_branch():
1258
1259 """ Returns a string identifying the Python implementation
1260 branch.
1261
1262 For CPython this is the Subversion branch from which the
1263 Python binary was built.
1264
1265 If not available, an empty string is returned.
1266
1267 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001268
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001269 return _sys_version()[2]
1270
1271def python_revision():
1272
1273 """ Returns a string identifying the Python implementation
1274 revision.
1275
1276 For CPython this is the Subversion revision from which the
1277 Python binary was built.
1278
1279 If not available, an empty string is returned.
1280
1281 """
1282 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001283
1284def python_build():
1285
1286 """ Returns a tuple (buildno, builddate) stating the Python
1287 build number and date as strings.
1288
1289 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001290 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001291
1292def python_compiler():
1293
1294 """ Returns a string identifying the compiler used for compiling
1295 Python.
1296
1297 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001298 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001299
1300### The Opus Magnum of platform strings :-)
1301
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001302_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001303
1304def platform(aliased=0, terse=0):
1305
1306 """ Returns a single string identifying the underlying platform
1307 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001308
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001309 The output is intended to be human readable rather than
1310 machine parseable. It may look different on different
1311 platforms and this is intended.
1312
1313 If "aliased" is true, the function will use aliases for
1314 various platforms that report system names which differ from
1315 their common names, e.g. SunOS will be reported as
1316 Solaris. The system_alias() function is used to implement
1317 this.
1318
1319 Setting terse to true causes the function to return only the
1320 absolute minimum information needed to identify the platform.
1321
1322 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001323 result = _platform_cache.get((aliased, terse), None)
1324 if result is not None:
1325 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001326
1327 # Get uname information and then apply platform specific cosmetics
1328 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001329 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001330 if machine == processor:
1331 processor = ''
1332 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001333 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001334
1335 if system == 'Windows':
1336 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001337 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001338 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001339 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001340 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001341 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001342
1343 elif system in ('Linux',):
1344 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001345 with warnings.catch_warnings():
1346 # see issue #1322 for more information
1347 warnings.filterwarnings(
1348 'ignore',
R David Murray44b548d2016-09-08 13:59:53 -04001349 r'dist\(\) and linux_distribution\(\) '
Berker Peksag1392f712015-05-16 20:24:28 +03001350 'functions are deprecated .*',
1351 PendingDeprecationWarning,
1352 )
1353 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001354 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001355 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001356 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001357 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001358 else:
1359 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001360 libcname, libcversion = libc_ver(sys.executable)
1361 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001362 'with',
1363 libcname+libcversion)
1364 elif system == 'Java':
1365 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001366 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001367 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001368 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001369 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001370 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001371 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001372 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001373
1374 elif system == 'MacOS':
1375 # MacOS platforms
1376 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001377 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001378 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001379 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001380
1381 else:
1382 # Generic handler
1383 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001384 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001385 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001386 bits, linkage = architecture(sys.executable)
1387 platform = _platform(system, release, machine,
1388 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001389
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001390 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001391 return platform
1392
1393### Command line interface
1394
1395if __name__ == '__main__':
1396 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001397 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001398 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001399 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001400 sys.exit(0)