blob: 4482f479bfdecd704844aa916ce06de666515aec [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'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000246 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000247 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000248 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100249 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000250 else:
251 continue
252 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000253 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000254 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000255 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000256 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100257 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000258
259 if os.path.exists('/etc/.installed'):
260 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000261 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000262 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000263 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
264 # XXX does Caldera support non Intel platforms ? If yes,
265 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100266 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000267
268 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300269 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000270 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000271 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000272 if verfiles[n][:14] != 'slack-version-':
273 del verfiles[n]
274 if verfiles:
275 verfiles.sort()
276 distname = 'slackware'
277 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100278 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000279
Victor Stinnerced39362013-12-09 00:14:52 +0100280 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000281
Antoine Pitroufd036452008-08-19 17:56:33 +0000282_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000283_lsb_release_version = re.compile(r'(.+)'
R David Murray44b548d2016-09-08 13:59:53 -0400284 r' release '
285 r'([\d.]+)'
286 r'[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000287_release_version = re.compile(r'([^0-9]+)'
R David Murray44b548d2016-09-08 13:59:53 -0400288 r'(?: release )?'
289 r'([\d.]+)'
290 r'[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000291
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000292# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000293# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000294# and http://data.linux-ntfs.org/rpm/whichrpm
295# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000296
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000297_supported_dists = (
298 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
299 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200300 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000301
302def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000303
Benjamin Peterson25001472010-01-25 03:37:42 +0000304 # Default to empty 'version' and 'id' strings. Both defaults are used
305 # when 'firstline' is empty. 'id' defaults to empty when an id can not
306 # be deduced.
307 version = ''
308 id = ''
309
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000310 # Parse the first line
311 m = _lsb_release_version.match(firstline)
312 if m is not None:
313 # LSB format: "distro release x.x (codename)"
314 return tuple(m.groups())
315
316 # Pre-LSB format: "distro x.x (codename)"
317 m = _release_version.match(firstline)
318 if m is not None:
319 return tuple(m.groups())
320
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300321 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000322 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000323 if l:
324 version = l[0]
325 if len(l) > 1:
326 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000327 return '', version, id
328
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000329def linux_distribution(distname='', version='', id='',
330
331 supported_dists=_supported_dists,
332 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300333 import warnings
334 warnings.warn("dist() and linux_distribution() functions are deprecated "
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -0700335 "in Python 3.5", DeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300336 return _linux_distribution(distname, version, id, supported_dists,
337 full_distribution_name)
338
339def _linux_distribution(distname, version, id, supported_dists,
340 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000341
342 """ Tries to determine the name of the Linux OS distribution name.
343
344 The function first looks for a distribution release file in
345 /etc and then reverts to _dist_try_harder() in case no
346 suitable files are found.
347
348 supported_dists may be given to define the set of Linux
349 distributions to look for. It defaults to a list of currently
350 supported Linux distributions identified by their release file
351 name.
352
353 If full_distribution_name is true (default), the full
354 distribution read from the OS is returned. Otherwise the short
355 name taken from supported_dists is used.
356
Victor Stinnerced39362013-12-09 00:14:52 +0100357 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000358 args given as parameters.
359
360 """
361 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100362 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200363 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000364 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100365 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000366 etc.sort()
367 for file in etc:
368 m = _release_filename.match(file)
369 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100370 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000371 if _distname in supported_dists:
372 distname = _distname
373 break
374 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100375 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000376
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000377 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100378 with open(os.path.join(_UNIXCONFDIR, file), 'r',
379 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000380 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000381 _distname, _version, _id = _parse_release_file(firstline)
382
383 if _distname and full_distribution_name:
384 distname = _distname
385 if _version:
386 version = _version
387 if _id:
388 id = _id
389 return distname, version, id
390
391# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000392
Victor Stinnerced39362013-12-09 00:14:52 +0100393def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000394
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000395 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000396
Brett Cannon8ab27df2003-08-05 03:52:04 +0000397 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000398
399 The function first looks for a distribution release file in
400 /etc and then reverts to _dist_try_harder() in case no
401 suitable files are found.
402
Victor Stinnerced39362013-12-09 00:14:52 +0100403 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000404 args given as parameters.
405
406 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300407 import warnings
408 warnings.warn("dist() and linux_distribution() functions are deprecated "
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -0700409 "in Python 3.5", DeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300410 return _linux_distribution(distname, version, id,
411 supported_dists=supported_dists,
412 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000413
Antoine Pitrou877766d2011-03-19 17:00:37 +0100414def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000415
416 """ Portable popen() interface.
417 """
Victor Stinner25000d42011-05-24 00:16:16 +0200418 import warnings
419 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000420 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000421
Serhiy Storchaka7c43b802018-07-09 12:55:35 +0300422
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000423def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000424
Brett Cannon8ab27df2003-08-05 03:52:04 +0000425 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000426 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000427 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000428 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000429 if build:
430 l.append(build)
431 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100432 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000433 except ValueError:
434 strings = l
435 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100436 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000437 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000438 return version
439
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000440_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400441 r'.*'
442 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000443
444# Examples of VER command output:
445#
446# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
447# Windows XP: Microsoft Windows XP [Version 5.1.2600]
448# Windows Vista: Microsoft Windows [Version 6.0.6002]
449#
450# Note that the "Version" string gets localized on different
451# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000452
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000453def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454
Victor Stinnerced39362013-12-09 00:14:52 +0100455 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
457 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100458 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000459
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000460 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200461 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462
463 In case this fails, the given parameters are used as
464 defaults.
465
466 """
467 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100468 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000469
470 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100471 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000472 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700473 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000474 info = pipe.read()
475 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200476 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200477 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000478 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200479 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100480 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000481 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000482 else:
483 break
484 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100485 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000486
487 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000488 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000489 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000490 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100491 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000492 # Strip trailing dots from version and release
493 if release[-1] == '.':
494 release = release[:-1]
495 if version[-1] == '.':
496 version = version[:-1]
497 # Normalize the version and build strings (eliminating additional
498 # zeros)
499 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100500 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000501
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700502_WIN32_CLIENT_RELEASES = {
503 (5, 0): "2000",
504 (5, 1): "XP",
505 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
506 # has always called it 2003 Server
507 (5, 2): "2003Server",
508 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000509
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700510 (6, 0): "Vista",
511 (6, 1): "7",
512 (6, 2): "8",
513 (6, 3): "8.1",
514 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000515
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700516 (10, 0): "10",
517 (10, None): "post10",
518}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000519
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700520# Server release name lookup will default to client names if necessary
521_WIN32_SERVER_RELEASES = {
522 (5, 2): "2003Server",
523
524 (6, 0): "2008Server",
525 (6, 1): "2008ServerR2",
526 (6, 2): "2012Server",
527 (6, 3): "2012ServerR2",
528 (6, None): "post2012ServerR2",
529}
530
Victor Stinnerced39362013-12-09 00:14:52 +0100531def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700532 try:
533 from sys import getwindowsversion
534 except ImportError:
535 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000536 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700537 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400538 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700539 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
540
541 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700542 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700543 version = '{0}.{1}.{2}'.format(maj, min, build)
544
545 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
546 _WIN32_CLIENT_RELEASES.get((maj, None)) or
547 release)
548
549 # getwindowsversion() reflect the compatibility mode Python is
550 # running under, and so the service pack value is only going to be
551 # valid if the versions match.
552 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000553 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700554 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000555 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700556 if csd[:13] == 'Service Pack ':
557 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000558
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700559 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700560 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700561 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
562 _WIN32_SERVER_RELEASES.get((maj, None)) or
563 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000564
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700565 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000566 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700567 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
568 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
569 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000570 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700571 pass
572 finally:
573 if key:
574 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000575
Victor Stinnerced39362013-12-09 00:14:52 +0100576 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000577
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700578
Ronald Oussorene186e382010-07-23 11:54:59 +0000579def _mac_ver_xml():
580 fn = '/System/Library/CoreServices/SystemVersion.plist'
581 if not os.path.exists(fn):
582 return None
583
584 try:
585 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400586 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000587 return None
588
Ned Deily936dfae2014-01-13 11:34:19 -0800589 with open(fn, 'rb') as f:
590 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000591 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100592 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700593 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000594 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300595 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000596 machine = 'PowerPC'
597
Victor Stinnerced39362013-12-09 00:14:52 +0100598 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000599
600
Victor Stinnerced39362013-12-09 00:14:52 +0100601def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000602
603 """ Get MacOS version information and return it as tuple (release,
604 versioninfo, machine) with versioninfo being a tuple (version,
605 dev_stage, non_release_version).
606
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300607 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000608 which default to ''. All tuple entries are strings.
609 """
610
611 # First try reading the information from an XML file which should
612 # always be present
613 info = _mac_ver_xml()
614 if info is not None:
615 return info
616
Ronald Oussorene186e382010-07-23 11:54:59 +0000617 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100618 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000619
Victor Stinnerced39362013-12-09 00:14:52 +0100620def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000621
622 from java.lang import System
623 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000624 value = System.getProperty(name)
625 if value is None:
626 return default
627 return value
628 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000629 return default
630
Victor Stinnerced39362013-12-09 00:14:52 +0100631def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000632
Brett Cannon8ab27df2003-08-05 03:52:04 +0000633 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000634
Victor Stinnerced39362013-12-09 00:14:52 +0100635 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
636 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
637 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638
639 Values which cannot be determined are set to the defaults
640 given as parameters (which all default to '').
641
642 """
643 # Import the needed APIs
644 try:
645 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400646 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100647 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000648
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000649 vendor = _java_getprop('java.vendor', vendor)
650 release = _java_getprop('java.version', release)
651 vm_name, vm_release, vm_vendor = vminfo
652 vm_name = _java_getprop('java.vm.name', vm_name)
653 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
654 vm_release = _java_getprop('java.vm.version', vm_release)
655 vminfo = vm_name, vm_release, vm_vendor
656 os_name, os_version, os_arch = osinfo
657 os_arch = _java_getprop('java.os.arch', os_arch)
658 os_name = _java_getprop('java.os.name', os_name)
659 os_version = _java_getprop('java.os.version', os_version)
660 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000661
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000662 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000663
664### System name aliasing
665
Victor Stinnerced39362013-12-09 00:14:52 +0100666def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667
Victor Stinnerced39362013-12-09 00:14:52 +0100668 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000669 marketing names used for some systems.
670
671 It also does some reordering of the information in some cases
672 where it would otherwise cause confusion.
673
674 """
675 if system == 'Rhapsody':
676 # Apple's BSD derivative
677 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100678 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000679
680 elif system == 'SunOS':
681 # Sun's OS
682 if release < '5':
683 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100684 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000685 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000686 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687 if l:
688 try:
689 major = int(l[0])
690 except ValueError:
691 pass
692 else:
693 major = major - 3
694 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000695 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000696 if release < '6':
697 system = 'Solaris'
698 else:
699 # XXX Whatever the new SunOS marketing name is...
700 system = 'Solaris'
701
702 elif system == 'IRIX64':
703 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
704 # is really a version and not a different platform, since 32-bit
705 # apps are also supported..
706 system = 'IRIX'
707 if version:
708 version = version + ' (64bit)'
709 else:
710 version = '64bit'
711
Victor Stinnerced39362013-12-09 00:14:52 +0100712 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000713 # In case one of the other tricks
714 system = 'Windows'
715
Victor Stinnerced39362013-12-09 00:14:52 +0100716 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000717
718### Various internal helpers
719
720def _platform(*args):
721
722 """ Helper to format the platform string in a filename
723 compatible format e.g. "system-version-machine".
724 """
725 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000726 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000727
728 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100729 platform = platform.replace(' ', '_')
730 platform = platform.replace('/', '-')
731 platform = platform.replace('\\', '-')
732 platform = platform.replace(':', '-')
733 platform = platform.replace(';', '-')
734 platform = platform.replace('"', '-')
735 platform = platform.replace('(', '-')
736 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000737
738 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100739 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000740
741 # Fold '--'s and remove trailing '-'
742 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100743 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744 if cleaned == platform:
745 break
746 platform = cleaned
747 while platform[-1] == '-':
748 platform = platform[:-1]
749
750 return platform
751
752def _node(default=''):
753
754 """ Helper to determine the node name of this machine.
755 """
756 try:
757 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400758 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000759 # No sockets...
760 return default
761 try:
762 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200763 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000764 # Still not working...
765 return default
766
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000767def _follow_symlinks(filepath):
768
769 """ In case filepath is a symlink, follow it until a
770 real file is reached.
771 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000772 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000773 while os.path.islink(filepath):
774 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100775 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000776 return filepath
777
Victor Stinnerced39362013-12-09 00:14:52 +0100778def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000779
780 """ Interface to the system's uname command.
781 """
Victor Stinnerced39362013-12-09 00:14:52 +0100782 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000783 # XXX Others too ?
784 return default
785 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000786 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200787 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000788 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000789 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000790 rc = f.close()
791 if not output or rc:
792 return default
793 else:
794 return output
795
Victor Stinnerced39362013-12-09 00:14:52 +0100796def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000797
798 """ Interface to the system's file command.
799
800 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000801 omit the filename in its output. Follow the symlinks. It returns
802 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000803
804 """
Victor Stinnerced39362013-12-09 00:14:52 +0100805 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000806 # XXX Others too ?
807 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200808 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000809 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200810 proc = subprocess.Popen(['file', target],
811 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200812
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200813 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000814 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200815 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200816 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000817 if not output or rc:
818 return default
819 else:
820 return output
821
822### Information about the used architecture
823
824# Default values for architecture; non-empty strings override the
825# defaults given as parameters
826_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100827 'win32': ('', 'WindowsPE'),
828 'win16': ('', 'Windows'),
829 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000830}
831
Victor Stinnerced39362013-12-09 00:14:52 +0100832def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000833
834 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000835 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000836
Victor Stinnerced39362013-12-09 00:14:52 +0100837 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000838 the bit architecture and the linkage format used for the
839 executable. Both values are returned as strings.
840
841 Values that cannot be determined are returned as given by the
842 parameter presets. If bits is given as '', the sizeof(pointer)
843 (or sizeof(long) on Python version < 1.5.2) is used as
844 indicator for the supported pointer size.
845
846 The function relies on the system's "file" command to do the
847 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000848 platforms. On some non-Unix platforms where the "file" command
849 does not exist and the executable is set to the Python interpreter
850 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000851
852 """
853 # Use the sizeof(pointer) as default number of bits if nothing
854 # else is given as default.
855 if not bits:
856 import struct
857 try:
858 size = struct.calcsize('P')
859 except struct.error:
860 # Older installations can only query longs
861 size = struct.calcsize('l')
862 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000863
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000864 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000865 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000866 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000867 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000868 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000869
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000870 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000871 executable == sys.executable:
872 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000873 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000874 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100875 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000876 if b:
877 bits = b
878 if l:
879 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100880 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000881
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000882 if 'executable' not in fileout:
883 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100884 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000885
886 # Bits
887 if '32-bit' in fileout:
888 bits = '32bit'
889 elif 'N32' in fileout:
890 # On Irix only
891 bits = 'n32bit'
892 elif '64-bit' in fileout:
893 bits = '64bit'
894
895 # Linkage
896 if 'ELF' in fileout:
897 linkage = 'ELF'
898 elif 'PE' in fileout:
899 # E.g. Windows uses this format
900 if 'Windows' in fileout:
901 linkage = 'WindowsPE'
902 else:
903 linkage = 'PE'
904 elif 'COFF' in fileout:
905 linkage = 'COFF'
906 elif 'MS-DOS' in fileout:
907 linkage = 'MSDOS'
908 else:
909 # XXX the A.OUT format also falls under this class...
910 pass
911
Victor Stinnerced39362013-12-09 00:14:52 +0100912 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000913
914### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000915
Larry Hastings68386bc2012-06-24 14:30:41 -0700916uname_result = collections.namedtuple("uname_result",
917 "system node release version machine processor")
918
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000919_uname_cache = None
920
921def uname():
922
923 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100924 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000925 identifying the underlying platform.
926
927 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000928 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000929
930 Entries which cannot be determined are set to ''.
931
932 """
933 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000934 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000935
936 if _uname_cache is not None:
937 return _uname_cache
938
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000939 processor = ''
940
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000941 # Get some infos from the builtin os.uname API...
942 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100943 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000944 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000945 no_os_uname = 1
946
Georg Brandl62e2ca22010-07-31 21:54:24 +0000947 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000948 # Hmm, no there is either no uname or uname has returned
949 #'unknowns'... we'll have to poke around the system then.
950 if no_os_uname:
951 system = sys.platform
952 release = ''
953 version = ''
954 node = _node()
955 machine = ''
956
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000957 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958
959 # Try win32_ver() on win32 platforms
960 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100961 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000962 if release and version:
963 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000964 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000965 # available on Win XP and later; see
966 # http://support.microsoft.com/kb/888731 and
967 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000968 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000969 # WOW64 processes mask the native architecture
970 if "PROCESSOR_ARCHITEW6432" in os.environ:
971 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
972 else:
973 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000974 if not processor:
975 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000976
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000977 # Try the 'ver' system command available on some
978 # platforms
979 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100980 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000981 # Normalize system to what win32_ver() normally returns
982 # (_syscmd_ver() tends to return the vendor name as well)
983 if system == 'Microsoft Windows':
984 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000985 elif system == 'Microsoft' and release == 'Windows':
986 # Under Windows Vista and Windows Server 2008,
987 # Microsoft changed the output of the ver command. The
988 # release is no longer printed. This causes the
989 # system and release to be misidentified.
990 system = 'Windows'
991 if '6.0' == version[:3]:
992 release = 'Vista'
993 else:
994 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000995
996 # In case we still don't know anything useful, we'll try to
997 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100998 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000999 if not version:
1000 if system == 'win32':
1001 version = '32bit'
1002 else:
1003 version = '16bit'
1004 system = 'Windows'
1005
1006 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001007 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001008 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001009 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001010 if not version:
1011 version = vendor
1012
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001013 # System specific extensions
1014 if system == 'OpenVMS':
1015 # OpenVMS seems to have release and version mixed up
1016 if not release or release == '0':
1017 release = version
1018 version = ''
1019 # Get processor information
1020 try:
1021 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001022 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001023 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001024 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001025 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001026 if (cpu_number >= 128):
1027 processor = 'Alpha'
1028 else:
1029 processor = 'VAX'
1030 if not processor:
1031 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001032 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001033
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001034 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001035 if system == 'unknown':
1036 system = ''
1037 if node == 'unknown':
1038 node = ''
1039 if release == 'unknown':
1040 release = ''
1041 if version == 'unknown':
1042 version = ''
1043 if machine == 'unknown':
1044 machine = ''
1045 if processor == 'unknown':
1046 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001047
1048 # normalize name
1049 if system == 'Microsoft' and release == 'Windows':
1050 system = 'Windows'
1051 release = 'Vista'
1052
Victor Stinnerced39362013-12-09 00:14:52 +01001053 _uname_cache = uname_result(system, node, release, version,
1054 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001055 return _uname_cache
1056
1057### Direct interfaces to some of the uname() return values
1058
1059def system():
1060
1061 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1062
1063 An empty string is returned if the value cannot be determined.
1064
1065 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001066 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067
1068def node():
1069
Brett Cannon8ab27df2003-08-05 03:52:04 +00001070 """ Returns the computer's network name (which may not be fully
1071 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001072
1073 An empty string is returned if the value cannot be determined.
1074
1075 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001076 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001077
1078def release():
1079
1080 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1081
1082 An empty string is returned if the value cannot be determined.
1083
1084 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001085 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001086
1087def version():
1088
1089 """ Returns the system's release version, e.g. '#3 on degas'
1090
1091 An empty string is returned if the value cannot be determined.
1092
1093 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001094 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001095
1096def machine():
1097
1098 """ Returns the machine type, e.g. 'i386'
1099
1100 An empty string is returned if the value cannot be determined.
1101
1102 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001103 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001104
1105def processor():
1106
1107 """ Returns the (true) processor name, e.g. 'amdk6'
1108
1109 An empty string is returned if the value cannot be
1110 determined. Note that many platforms do not provide this
1111 information or simply return the same value as for machine(),
1112 e.g. NetBSD does this.
1113
1114 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001115 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001116
1117### Various APIs for extracting information from sys.version
1118
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001119_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001120 r'([\w.+]+)\s*' # "version<space>"
1121 r'\(#?([^,]+)' # "(#buildno"
1122 r'(?:,\s*([\w ]*)' # ", builddate"
1123 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1124 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001125
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001126_ironpython_sys_version_parser = re.compile(
1127 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001128 r'([\d\.]+)'
1129 r'(?: \(([\d\.]+)\))?'
1130 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001131
Ezio Melottif076f532013-10-21 03:03:32 +03001132# IronPython covering 2.6 and 2.7
1133_ironpython26_sys_version_parser = re.compile(
1134 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001135 r'\(IronPython\s*'
1136 r'[\d.]+\s*'
1137 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +03001138)
1139
Benjamin Petersone549ead2009-03-28 21:42:05 +00001140_pypy_sys_version_parser = re.compile(
1141 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001142 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1143 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +00001144
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001145_sys_version_cache = {}
1146
1147def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001148
1149 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001150 (name, version, branch, revision, buildno, builddate, compiler)
1151 referring to the Python implementation name, version, branch,
1152 revision, build number, build date/time as string and the compiler
1153 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001154
1155 Note that unlike the Python sys.version, the returned value
1156 for the Python version will always include the patchlevel (it
1157 defaults to '.0').
1158
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001159 The function returns empty strings for tuple entries that
1160 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001161
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001162 sys_version may be given to parse an alternative version
1163 string, e.g. if the version was read from a different Python
1164 interpreter.
1165
1166 """
1167 # Get the Python version
1168 if sys_version is None:
1169 sys_version = sys.version
1170
1171 # Try the cache first
1172 result = _sys_version_cache.get(sys_version, None)
1173 if result is not None:
1174 return result
1175
1176 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001177 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001178 # IronPython
1179 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001180 if sys_version.startswith('IronPython'):
1181 match = _ironpython_sys_version_parser.match(sys_version)
1182 else:
1183 match = _ironpython26_sys_version_parser.match(sys_version)
1184
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001185 if match is None:
1186 raise ValueError(
1187 'failed to parse IronPython sys.version: %s' %
1188 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001189
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001190 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001191 buildno = ''
1192 builddate = ''
1193
Ezio Melottif076f532013-10-21 03:03:32 +03001194 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001195 # Jython
1196 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001197 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001198 if match is None:
1199 raise ValueError(
1200 'failed to parse Jython sys.version: %s' %
1201 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001202 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001203 if builddate is None:
1204 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001205 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001206
1207 elif "PyPy" in sys_version:
1208 # PyPy
1209 name = "PyPy"
1210 match = _pypy_sys_version_parser.match(sys_version)
1211 if match is None:
1212 raise ValueError("failed to parse PyPy sys.version: %s" %
1213 repr(sys_version))
1214 version, buildno, builddate, buildtime = match.groups()
1215 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001216
1217 else:
1218 # CPython
1219 match = _sys_version_parser.match(sys_version)
1220 if match is None:
1221 raise ValueError(
1222 'failed to parse CPython sys.version: %s' %
1223 repr(sys_version))
1224 version, buildno, builddate, buildtime, compiler = \
1225 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001226 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001227 if builddate is None:
1228 builddate = ''
1229 elif buildtime:
1230 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001231
Ned Deily5c4b0d02017-03-04 00:19:55 -05001232 if hasattr(sys, '_git'):
1233 _, branch, revision = sys._git
1234 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001235 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001236 else:
1237 branch = ''
1238 revision = ''
1239
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001240 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001241 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001242 if len(l) == 2:
1243 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001244 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001245
1246 # Build and cache the result
1247 result = (name, version, branch, revision, buildno, builddate, compiler)
1248 _sys_version_cache[sys_version] = result
1249 return result
1250
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001251def python_implementation():
1252
1253 """ Returns a string identifying the Python implementation.
1254
1255 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001256 'CPython' (C implementation of Python),
1257 'IronPython' (.NET implementation of Python),
1258 'Jython' (Java implementation of Python),
1259 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001260
1261 """
1262 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001263
1264def python_version():
1265
1266 """ Returns the Python version as string 'major.minor.patchlevel'
1267
1268 Note that unlike the Python sys.version, the returned value
1269 will always include the patchlevel (it defaults to 0).
1270
1271 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001272 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001273
1274def python_version_tuple():
1275
1276 """ Returns the Python version as tuple (major, minor, patchlevel)
1277 of strings.
1278
1279 Note that unlike the Python sys.version, the returned value
1280 will always include the patchlevel (it defaults to 0).
1281
1282 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001283 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001284
1285def python_branch():
1286
1287 """ Returns a string identifying the Python implementation
1288 branch.
1289
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001290 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001291 Python binary was built.
1292
1293 If not available, an empty string is returned.
1294
1295 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001296
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001297 return _sys_version()[2]
1298
1299def python_revision():
1300
1301 """ Returns a string identifying the Python implementation
1302 revision.
1303
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001304 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001305 Python binary was built.
1306
1307 If not available, an empty string is returned.
1308
1309 """
1310 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001311
1312def python_build():
1313
1314 """ Returns a tuple (buildno, builddate) stating the Python
1315 build number and date as strings.
1316
1317 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001318 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001319
1320def python_compiler():
1321
1322 """ Returns a string identifying the compiler used for compiling
1323 Python.
1324
1325 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001326 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001327
1328### The Opus Magnum of platform strings :-)
1329
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001330_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001331
1332def platform(aliased=0, terse=0):
1333
1334 """ Returns a single string identifying the underlying platform
1335 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001336
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001337 The output is intended to be human readable rather than
1338 machine parseable. It may look different on different
1339 platforms and this is intended.
1340
1341 If "aliased" is true, the function will use aliases for
1342 various platforms that report system names which differ from
1343 their common names, e.g. SunOS will be reported as
1344 Solaris. The system_alias() function is used to implement
1345 this.
1346
1347 Setting terse to true causes the function to return only the
1348 absolute minimum information needed to identify the platform.
1349
1350 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001351 result = _platform_cache.get((aliased, terse), None)
1352 if result is not None:
1353 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001354
1355 # Get uname information and then apply platform specific cosmetics
1356 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001357 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001358 if machine == processor:
1359 processor = ''
1360 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001361 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001362
1363 if system == 'Windows':
1364 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001365 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001366 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001367 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001368 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001369 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001370
1371 elif system in ('Linux',):
1372 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001373 with warnings.catch_warnings():
1374 # see issue #1322 for more information
1375 warnings.filterwarnings(
1376 'ignore',
R David Murray44b548d2016-09-08 13:59:53 -04001377 r'dist\(\) and linux_distribution\(\) '
Berker Peksag1392f712015-05-16 20:24:28 +03001378 'functions are deprecated .*',
Miss Islington (bot)f4fdb612018-05-15 10:30:06 -07001379 DeprecationWarning,
Berker Peksag1392f712015-05-16 20:24:28 +03001380 )
1381 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001382 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001383 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001384 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001385 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001386 else:
1387 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001388 libcname, libcversion = libc_ver(sys.executable)
1389 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001390 'with',
1391 libcname+libcversion)
1392 elif system == 'Java':
1393 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001394 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001395 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001396 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001397 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001398 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001399 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001400 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401
1402 elif system == 'MacOS':
1403 # MacOS platforms
1404 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001405 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001406 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001407 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001408
1409 else:
1410 # Generic handler
1411 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001412 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001413 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001414 bits, linkage = architecture(sys.executable)
1415 platform = _platform(system, release, machine,
1416 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001417
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001418 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001419 return platform
1420
1421### Command line interface
1422
1423if __name__ == '__main__':
1424 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001425 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001426 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001427 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001428 sys.exit(0)