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