blob: ff25f511af1a3f16f43d8cd6cd4b1abad52e5fbc [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
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000113__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000114
Larry Hastings68386bc2012-06-24 14:30:41 -0700115import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200116import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000117
Berker Peksag1392f712015-05-16 20:24:28 +0300118import warnings
119
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000120### Globals & Constants
121
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100128 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
Victor Stinner620c48b2013-12-09 00:01:27 +0100135# Directory to search for configuration information on Unix.
136# Constant used by test_platform to test linux_distribution().
137_UNIXCONFDIR = '/etc'
138
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000139### Platform specific APIs
140
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200141_libc_search = re.compile(b'(__libc_init)'
142 b'|'
143 b'(GLIBC_([0-9.]+))'
144 b'|'
145 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000146
Victor Stinnerced39362013-12-09 00:14:52 +0100147def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000148
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200149 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000150
Brett Cannon8ab27df2003-08-05 03:52:04 +0000151 """ Tries to determine the libc version that the file executable
152 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000153
154 Returns a tuple of strings (lib,version) which default to the
155 given parameters in case the lookup fails.
156
157 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000158 libc versions add symbols to the executable and thus is probably
159 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000160
161 The file is read and scanned in chunks of chunksize bytes.
162
163 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000164 if hasattr(os.path, 'realpath'):
165 # Python 2.2 introduced os.path.realpath(); it is used
166 # here to work around problems with Cygwin not being
167 # able to open symlinks for reading
168 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300169 with open(executable, 'rb') as f:
170 binary = f.read(chunksize)
171 pos = 0
172 while 1:
173 if b'libc' in binary or b'GLIBC' in binary:
174 m = _libc_search.search(binary, pos)
175 else:
176 m = None
177 if not m:
178 binary = f.read(chunksize)
179 if not binary:
180 break
181 pos = 0
182 continue
183 libcinit, glibc, glibcversion, so, threads, soversion = [
184 s.decode('latin1') if s is not None else s
185 for s in m.groups()]
186 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000187 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300188 elif glibc:
189 if lib != 'glibc':
190 lib = 'glibc'
191 version = glibcversion
192 elif glibcversion > version:
193 version = glibcversion
194 elif so:
195 if lib != 'glibc':
196 lib = 'libc'
197 if soversion and soversion > version:
198 version = soversion
199 if threads and version[-len(threads):] != threads:
200 version = version + threads
201 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100202 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000203
Victor Stinnerced39362013-12-09 00:14:52 +0100204def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000205
Tim Peters0eadaac2003-04-24 16:02:54 +0000206 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 information in case the default method fails.
208
209 Currently supports older SuSE Linux, Caldera OpenLinux and
210 Slackware Linux distributions.
211
212 """
213 if os.path.exists('/var/adm/inst-log/info'):
214 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000216 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000217 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000218 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100219 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000220 else:
221 continue
222 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000223 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000224 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000225 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000226 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100227 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000228
229 if os.path.exists('/etc/.installed'):
230 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000231 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000232 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000233 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
234 # XXX does Caldera support non Intel platforms ? If yes,
235 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100236 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000237
238 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300239 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000240 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000241 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000242 if verfiles[n][:14] != 'slack-version-':
243 del verfiles[n]
244 if verfiles:
245 verfiles.sort()
246 distname = 'slackware'
247 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100248 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000249
Victor Stinnerced39362013-12-09 00:14:52 +0100250 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000251
Antoine Pitroufd036452008-08-19 17:56:33 +0000252_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000253_lsb_release_version = re.compile(r'(.+)'
R David Murray44b548d2016-09-08 13:59:53 -0400254 r' release '
255 r'([\d.]+)'
256 r'[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000257_release_version = re.compile(r'([^0-9]+)'
R David Murray44b548d2016-09-08 13:59:53 -0400258 r'(?: release )?'
259 r'([\d.]+)'
260 r'[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000261
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000262# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000263# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000264# and http://data.linux-ntfs.org/rpm/whichrpm
265# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000266
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000267_supported_dists = (
268 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
269 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200270 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000271
272def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000273
Benjamin Peterson25001472010-01-25 03:37:42 +0000274 # Default to empty 'version' and 'id' strings. Both defaults are used
275 # when 'firstline' is empty. 'id' defaults to empty when an id can not
276 # be deduced.
277 version = ''
278 id = ''
279
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000280 # Parse the first line
281 m = _lsb_release_version.match(firstline)
282 if m is not None:
283 # LSB format: "distro release x.x (codename)"
284 return tuple(m.groups())
285
286 # Pre-LSB format: "distro x.x (codename)"
287 m = _release_version.match(firstline)
288 if m is not None:
289 return tuple(m.groups())
290
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300291 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000292 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000293 if l:
294 version = l[0]
295 if len(l) > 1:
296 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000297 return '', version, id
298
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000299def linux_distribution(distname='', version='', id='',
300
301 supported_dists=_supported_dists,
302 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300303 import warnings
304 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300305 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300306 return _linux_distribution(distname, version, id, supported_dists,
307 full_distribution_name)
308
309def _linux_distribution(distname, version, id, supported_dists,
310 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000311
312 """ Tries to determine the name of the Linux OS distribution name.
313
314 The function first looks for a distribution release file in
315 /etc and then reverts to _dist_try_harder() in case no
316 suitable files are found.
317
318 supported_dists may be given to define the set of Linux
319 distributions to look for. It defaults to a list of currently
320 supported Linux distributions identified by their release file
321 name.
322
323 If full_distribution_name is true (default), the full
324 distribution read from the OS is returned. Otherwise the short
325 name taken from supported_dists is used.
326
Victor Stinnerced39362013-12-09 00:14:52 +0100327 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000328 args given as parameters.
329
330 """
331 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100332 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200333 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000334 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100335 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000336 etc.sort()
337 for file in etc:
338 m = _release_filename.match(file)
339 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100340 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000341 if _distname in supported_dists:
342 distname = _distname
343 break
344 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100345 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000346
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000347 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100348 with open(os.path.join(_UNIXCONFDIR, file), 'r',
349 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000350 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000351 _distname, _version, _id = _parse_release_file(firstline)
352
353 if _distname and full_distribution_name:
354 distname = _distname
355 if _version:
356 version = _version
357 if _id:
358 id = _id
359 return distname, version, id
360
361# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000362
Victor Stinnerced39362013-12-09 00:14:52 +0100363def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000364
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000365 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000366
Brett Cannon8ab27df2003-08-05 03:52:04 +0000367 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000368
369 The function first looks for a distribution release file in
370 /etc and then reverts to _dist_try_harder() in case no
371 suitable files are found.
372
Victor Stinnerced39362013-12-09 00:14:52 +0100373 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000374 args given as parameters.
375
376 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300377 import warnings
378 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300379 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300380 return _linux_distribution(distname, version, id,
381 supported_dists=supported_dists,
382 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383
Antoine Pitrou877766d2011-03-19 17:00:37 +0100384def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000385
386 """ Portable popen() interface.
387 """
Victor Stinner25000d42011-05-24 00:16:16 +0200388 import warnings
389 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000390 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000391
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000392def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000393
Brett Cannon8ab27df2003-08-05 03:52:04 +0000394 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000395 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000396 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000397 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000398 if build:
399 l.append(build)
400 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100401 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000402 except ValueError:
403 strings = l
404 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100405 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000406 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000407 return version
408
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000409_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400410 r'.*'
411 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000412
413# Examples of VER command output:
414#
415# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
416# Windows XP: Microsoft Windows XP [Version 5.1.2600]
417# Windows Vista: Microsoft Windows [Version 6.0.6002]
418#
419# Note that the "Version" string gets localized on different
420# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000421
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000422def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000423
Victor Stinnerced39362013-12-09 00:14:52 +0100424 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000425
426 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100427 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000428
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000429 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200430 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000431
432 In case this fails, the given parameters are used as
433 defaults.
434
435 """
436 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100437 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000438
439 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100440 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700442 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000443 info = pipe.read()
444 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200445 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200446 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000447 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200448 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100449 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000450 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000451 else:
452 break
453 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100454 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000455
456 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000457 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000458 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000459 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100460 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000461 # Strip trailing dots from version and release
462 if release[-1] == '.':
463 release = release[:-1]
464 if version[-1] == '.':
465 version = version[:-1]
466 # Normalize the version and build strings (eliminating additional
467 # zeros)
468 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100469 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000470
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700471_WIN32_CLIENT_RELEASES = {
472 (5, 0): "2000",
473 (5, 1): "XP",
474 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
475 # has always called it 2003 Server
476 (5, 2): "2003Server",
477 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000478
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700479 (6, 0): "Vista",
480 (6, 1): "7",
481 (6, 2): "8",
482 (6, 3): "8.1",
483 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000484
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700485 (10, 0): "10",
486 (10, None): "post10",
487}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700489# Server release name lookup will default to client names if necessary
490_WIN32_SERVER_RELEASES = {
491 (5, 2): "2003Server",
492
493 (6, 0): "2008Server",
494 (6, 1): "2008ServerR2",
495 (6, 2): "2012Server",
496 (6, 3): "2012ServerR2",
497 (6, None): "post2012ServerR2",
498}
499
Steve Dower6a294a52016-09-09 18:01:25 -0700500if sys.platform == 'win32':
501 import ctypes
502 import ctypes.wintypes
503
504 class VS_FIXEDFILEINFO(ctypes.Structure):
505 _fields_ = [
506 ("dwSignature", ctypes.wintypes.DWORD),
507 ("dwStrucVersion", ctypes.wintypes.DWORD),
508 ("dwFileVersionMS", ctypes.wintypes.DWORD),
509 ("dwFileVersionLS", ctypes.wintypes.DWORD),
510 ("dwProductVersionMS", ctypes.wintypes.DWORD),
511 ("dwProductVersionLS", ctypes.wintypes.DWORD),
512 ("dwFileFlagsMask", ctypes.wintypes.DWORD),
513 ("dwFileFlags", ctypes.wintypes.DWORD),
514 ("dwFileOS", ctypes.wintypes.DWORD),
515 ("dwFileType", ctypes.wintypes.DWORD),
516 ("dwFileSubtype", ctypes.wintypes.DWORD),
517 ("dwFileDateMS", ctypes.wintypes.DWORD),
518 ("dwFileDateLS", ctypes.wintypes.DWORD),
519 ]
520
521 P_VS_FIXEDFILEINFO = ctypes.POINTER(VS_FIXEDFILEINFO)
522
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700523def _get_real_winver(maj, min, build):
524 if maj < 6 or (maj == 6 and min < 2):
525 return maj, min, build
526
Steve Dower6a294a52016-09-09 18:01:25 -0700527 kernel32 = ctypes.WinDLL('kernel32')
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700528 # We will immediately double the length up to MAX_PATH, but the
529 # path may be longer, so we retry until the returned string is
530 # shorter than our buffer.
531 name_len = actual_len = 130
532 while actual_len == name_len:
533 name_len *= 2
Steve Dower6a294a52016-09-09 18:01:25 -0700534 name = ctypes.create_unicode_buffer(name_len)
535 actual_len = kernel32.GetModuleFileNameW(
536 ctypes.wintypes.HANDLE(kernel32._handle),
537 name, len(name)
538 )
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700539 if not actual_len:
540 return maj, min, build
541
Steve Dower6a294a52016-09-09 18:01:25 -0700542 version = ctypes.WinDLL('version')
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700543 size = version.GetFileVersionInfoSizeW(name, None)
544 if not size:
545 return maj, min, build
546
Steve Dower6a294a52016-09-09 18:01:25 -0700547 ver_block = ctypes.c_buffer(size)
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700548 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
549 not ver_block):
550 return maj, min, build
551
Steve Dower6a294a52016-09-09 18:01:25 -0700552 pvi = P_VS_FIXEDFILEINFO()
553 if not version.VerQueryValueW(ver_block, "",
554 ctypes.byref(pvi), ctypes.byref(ctypes.wintypes.DWORD())):
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700555 return maj, min, build
556
557 maj = pvi.contents.dwProductVersionMS >> 16
558 min = pvi.contents.dwProductVersionMS & 0xFFFF
559 build = pvi.contents.dwProductVersionLS >> 16
560
561 return maj, min, build
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000562
Victor Stinnerced39362013-12-09 00:14:52 +0100563def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700564 try:
565 from sys import getwindowsversion
566 except ImportError:
567 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000568 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700569 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400570 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700571 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
572
573 winver = getwindowsversion()
574 maj, min, build = _get_real_winver(*winver[:3])
575 version = '{0}.{1}.{2}'.format(maj, min, build)
576
577 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
578 _WIN32_CLIENT_RELEASES.get((maj, None)) or
579 release)
580
581 # getwindowsversion() reflect the compatibility mode Python is
582 # running under, and so the service pack value is only going to be
583 # valid if the versions match.
584 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000585 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700586 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000587 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700588 if csd[:13] == 'Service Pack ':
589 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000590
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700591 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700592 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700593 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
594 _WIN32_SERVER_RELEASES.get((maj, None)) or
595 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000596
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700597 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000598 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700599 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
600 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
601 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000602 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700603 pass
604 finally:
605 if key:
606 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000607
Victor Stinnerced39362013-12-09 00:14:52 +0100608 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000609
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700610
Ronald Oussorene186e382010-07-23 11:54:59 +0000611def _mac_ver_xml():
612 fn = '/System/Library/CoreServices/SystemVersion.plist'
613 if not os.path.exists(fn):
614 return None
615
616 try:
617 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400618 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000619 return None
620
Ned Deily936dfae2014-01-13 11:34:19 -0800621 with open(fn, 'rb') as f:
622 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000623 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100624 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700625 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000626 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300627 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000628 machine = 'PowerPC'
629
Victor Stinnerced39362013-12-09 00:14:52 +0100630 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000631
632
Victor Stinnerced39362013-12-09 00:14:52 +0100633def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000634
635 """ Get MacOS version information and return it as tuple (release,
636 versioninfo, machine) with versioninfo being a tuple (version,
637 dev_stage, non_release_version).
638
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300639 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000640 which default to ''. All tuple entries are strings.
641 """
642
643 # First try reading the information from an XML file which should
644 # always be present
645 info = _mac_ver_xml()
646 if info is not None:
647 return info
648
Ronald Oussorene186e382010-07-23 11:54:59 +0000649 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100650 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000651
Victor Stinnerced39362013-12-09 00:14:52 +0100652def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000653
654 from java.lang import System
655 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000656 value = System.getProperty(name)
657 if value is None:
658 return default
659 return value
660 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000661 return default
662
Victor Stinnerced39362013-12-09 00:14:52 +0100663def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000664
Brett Cannon8ab27df2003-08-05 03:52:04 +0000665 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000666
Victor Stinnerced39362013-12-09 00:14:52 +0100667 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
668 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
669 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000670
671 Values which cannot be determined are set to the defaults
672 given as parameters (which all default to '').
673
674 """
675 # Import the needed APIs
676 try:
677 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400678 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100679 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000680
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000681 vendor = _java_getprop('java.vendor', vendor)
682 release = _java_getprop('java.version', release)
683 vm_name, vm_release, vm_vendor = vminfo
684 vm_name = _java_getprop('java.vm.name', vm_name)
685 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
686 vm_release = _java_getprop('java.vm.version', vm_release)
687 vminfo = vm_name, vm_release, vm_vendor
688 os_name, os_version, os_arch = osinfo
689 os_arch = _java_getprop('java.os.arch', os_arch)
690 os_name = _java_getprop('java.os.name', os_name)
691 os_version = _java_getprop('java.os.version', os_version)
692 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000693
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000694 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000695
696### System name aliasing
697
Victor Stinnerced39362013-12-09 00:14:52 +0100698def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000699
Victor Stinnerced39362013-12-09 00:14:52 +0100700 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000701 marketing names used for some systems.
702
703 It also does some reordering of the information in some cases
704 where it would otherwise cause confusion.
705
706 """
707 if system == 'Rhapsody':
708 # Apple's BSD derivative
709 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100710 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000711
712 elif system == 'SunOS':
713 # Sun's OS
714 if release < '5':
715 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100716 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000717 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000718 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000719 if l:
720 try:
721 major = int(l[0])
722 except ValueError:
723 pass
724 else:
725 major = major - 3
726 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000727 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000728 if release < '6':
729 system = 'Solaris'
730 else:
731 # XXX Whatever the new SunOS marketing name is...
732 system = 'Solaris'
733
734 elif system == 'IRIX64':
735 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
736 # is really a version and not a different platform, since 32-bit
737 # apps are also supported..
738 system = 'IRIX'
739 if version:
740 version = version + ' (64bit)'
741 else:
742 version = '64bit'
743
Victor Stinnerced39362013-12-09 00:14:52 +0100744 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000745 # In case one of the other tricks
746 system = 'Windows'
747
Victor Stinnerced39362013-12-09 00:14:52 +0100748 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000749
750### Various internal helpers
751
752def _platform(*args):
753
754 """ Helper to format the platform string in a filename
755 compatible format e.g. "system-version-machine".
756 """
757 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000758 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000759
760 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100761 platform = platform.replace(' ', '_')
762 platform = platform.replace('/', '-')
763 platform = platform.replace('\\', '-')
764 platform = platform.replace(':', '-')
765 platform = platform.replace(';', '-')
766 platform = platform.replace('"', '-')
767 platform = platform.replace('(', '-')
768 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000769
770 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100771 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000772
773 # Fold '--'s and remove trailing '-'
774 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100775 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000776 if cleaned == platform:
777 break
778 platform = cleaned
779 while platform[-1] == '-':
780 platform = platform[:-1]
781
782 return platform
783
784def _node(default=''):
785
786 """ Helper to determine the node name of this machine.
787 """
788 try:
789 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400790 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000791 # No sockets...
792 return default
793 try:
794 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200795 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000796 # Still not working...
797 return default
798
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000799def _follow_symlinks(filepath):
800
801 """ In case filepath is a symlink, follow it until a
802 real file is reached.
803 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000804 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805 while os.path.islink(filepath):
806 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100807 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000808 return filepath
809
Victor Stinnerced39362013-12-09 00:14:52 +0100810def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000811
812 """ Interface to the system's uname command.
813 """
Victor Stinnerced39362013-12-09 00:14:52 +0100814 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000815 # XXX Others too ?
816 return default
817 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000818 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200819 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000820 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000821 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000822 rc = f.close()
823 if not output or rc:
824 return default
825 else:
826 return output
827
Victor Stinnerced39362013-12-09 00:14:52 +0100828def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000829
830 """ Interface to the system's file command.
831
832 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000833 omit the filename in its output. Follow the symlinks. It returns
834 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000835
836 """
Victor Stinnerced39362013-12-09 00:14:52 +0100837 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000838 # XXX Others too ?
839 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200840 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000841 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200842 proc = subprocess.Popen(['file', target],
843 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200844
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200845 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000846 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200847 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200848 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000849 if not output or rc:
850 return default
851 else:
852 return output
853
854### Information about the used architecture
855
856# Default values for architecture; non-empty strings override the
857# defaults given as parameters
858_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100859 'win32': ('', 'WindowsPE'),
860 'win16': ('', 'Windows'),
861 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000862}
863
Victor Stinnerced39362013-12-09 00:14:52 +0100864def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000865
866 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000867 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000868
Victor Stinnerced39362013-12-09 00:14:52 +0100869 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000870 the bit architecture and the linkage format used for the
871 executable. Both values are returned as strings.
872
873 Values that cannot be determined are returned as given by the
874 parameter presets. If bits is given as '', the sizeof(pointer)
875 (or sizeof(long) on Python version < 1.5.2) is used as
876 indicator for the supported pointer size.
877
878 The function relies on the system's "file" command to do the
879 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000880 platforms. On some non-Unix platforms where the "file" command
881 does not exist and the executable is set to the Python interpreter
882 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000883
884 """
885 # Use the sizeof(pointer) as default number of bits if nothing
886 # else is given as default.
887 if not bits:
888 import struct
889 try:
890 size = struct.calcsize('P')
891 except struct.error:
892 # Older installations can only query longs
893 size = struct.calcsize('l')
894 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000895
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000896 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000897 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000898 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000899 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000900 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000901
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000902 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000903 executable == sys.executable:
904 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000905 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000906 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100907 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000908 if b:
909 bits = b
910 if l:
911 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100912 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000913
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000914 if 'executable' not in fileout:
915 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100916 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000917
918 # Bits
919 if '32-bit' in fileout:
920 bits = '32bit'
921 elif 'N32' in fileout:
922 # On Irix only
923 bits = 'n32bit'
924 elif '64-bit' in fileout:
925 bits = '64bit'
926
927 # Linkage
928 if 'ELF' in fileout:
929 linkage = 'ELF'
930 elif 'PE' in fileout:
931 # E.g. Windows uses this format
932 if 'Windows' in fileout:
933 linkage = 'WindowsPE'
934 else:
935 linkage = 'PE'
936 elif 'COFF' in fileout:
937 linkage = 'COFF'
938 elif 'MS-DOS' in fileout:
939 linkage = 'MSDOS'
940 else:
941 # XXX the A.OUT format also falls under this class...
942 pass
943
Victor Stinnerced39362013-12-09 00:14:52 +0100944 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000945
946### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000947
Larry Hastings68386bc2012-06-24 14:30:41 -0700948uname_result = collections.namedtuple("uname_result",
949 "system node release version machine processor")
950
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000951_uname_cache = None
952
953def uname():
954
955 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100956 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000957 identifying the underlying platform.
958
959 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000960 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000961
962 Entries which cannot be determined are set to ''.
963
964 """
965 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000966 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000967
968 if _uname_cache is not None:
969 return _uname_cache
970
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000971 processor = ''
972
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000973 # Get some infos from the builtin os.uname API...
974 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100975 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000976 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000977 no_os_uname = 1
978
Georg Brandl62e2ca22010-07-31 21:54:24 +0000979 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000980 # Hmm, no there is either no uname or uname has returned
981 #'unknowns'... we'll have to poke around the system then.
982 if no_os_uname:
983 system = sys.platform
984 release = ''
985 version = ''
986 node = _node()
987 machine = ''
988
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000989 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000990
991 # Try win32_ver() on win32 platforms
992 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100993 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000994 if release and version:
995 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000996 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000997 # available on Win XP and later; see
998 # http://support.microsoft.com/kb/888731 and
999 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001000 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001001 # WOW64 processes mask the native architecture
1002 if "PROCESSOR_ARCHITEW6432" in os.environ:
1003 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1004 else:
1005 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001006 if not processor:
1007 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001008
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001009 # Try the 'ver' system command available on some
1010 # platforms
1011 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +01001012 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001013 # Normalize system to what win32_ver() normally returns
1014 # (_syscmd_ver() tends to return the vendor name as well)
1015 if system == 'Microsoft Windows':
1016 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001017 elif system == 'Microsoft' and release == 'Windows':
1018 # Under Windows Vista and Windows Server 2008,
1019 # Microsoft changed the output of the ver command. The
1020 # release is no longer printed. This causes the
1021 # system and release to be misidentified.
1022 system = 'Windows'
1023 if '6.0' == version[:3]:
1024 release = 'Vista'
1025 else:
1026 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001027
1028 # In case we still don't know anything useful, we'll try to
1029 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001030 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001031 if not version:
1032 if system == 'win32':
1033 version = '32bit'
1034 else:
1035 version = '16bit'
1036 system = 'Windows'
1037
1038 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001039 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001040 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001041 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001042 if not version:
1043 version = vendor
1044
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001045 # System specific extensions
1046 if system == 'OpenVMS':
1047 # OpenVMS seems to have release and version mixed up
1048 if not release or release == '0':
1049 release = version
1050 version = ''
1051 # Get processor information
1052 try:
1053 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001054 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001055 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001056 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001057 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001058 if (cpu_number >= 128):
1059 processor = 'Alpha'
1060 else:
1061 processor = 'VAX'
1062 if not processor:
1063 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001064 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001065
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001066 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067 if system == 'unknown':
1068 system = ''
1069 if node == 'unknown':
1070 node = ''
1071 if release == 'unknown':
1072 release = ''
1073 if version == 'unknown':
1074 version = ''
1075 if machine == 'unknown':
1076 machine = ''
1077 if processor == 'unknown':
1078 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001079
1080 # normalize name
1081 if system == 'Microsoft' and release == 'Windows':
1082 system = 'Windows'
1083 release = 'Vista'
1084
Victor Stinnerced39362013-12-09 00:14:52 +01001085 _uname_cache = uname_result(system, node, release, version,
1086 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001087 return _uname_cache
1088
1089### Direct interfaces to some of the uname() return values
1090
1091def system():
1092
1093 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1094
1095 An empty string is returned if the value cannot be determined.
1096
1097 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001098 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001099
1100def node():
1101
Brett Cannon8ab27df2003-08-05 03:52:04 +00001102 """ Returns the computer's network name (which may not be fully
1103 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001104
1105 An empty string is returned if the value cannot be determined.
1106
1107 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001108 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001109
1110def release():
1111
1112 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1113
1114 An empty string is returned if the value cannot be determined.
1115
1116 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001117 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001118
1119def version():
1120
1121 """ Returns the system's release version, e.g. '#3 on degas'
1122
1123 An empty string is returned if the value cannot be determined.
1124
1125 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001126 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001127
1128def machine():
1129
1130 """ Returns the machine type, e.g. 'i386'
1131
1132 An empty string is returned if the value cannot be determined.
1133
1134 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001135 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001136
1137def processor():
1138
1139 """ Returns the (true) processor name, e.g. 'amdk6'
1140
1141 An empty string is returned if the value cannot be
1142 determined. Note that many platforms do not provide this
1143 information or simply return the same value as for machine(),
1144 e.g. NetBSD does this.
1145
1146 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001147 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001148
1149### Various APIs for extracting information from sys.version
1150
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001151_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001152 r'([\w.+]+)\s*' # "version<space>"
1153 r'\(#?([^,]+)' # "(#buildno"
1154 r'(?:,\s*([\w ]*)' # ", builddate"
1155 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1156 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001157
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001158_ironpython_sys_version_parser = re.compile(
1159 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001160 r'([\d\.]+)'
1161 r'(?: \(([\d\.]+)\))?'
1162 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001163
Ezio Melottif076f532013-10-21 03:03:32 +03001164# IronPython covering 2.6 and 2.7
1165_ironpython26_sys_version_parser = re.compile(
1166 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001167 r'\(IronPython\s*'
1168 r'[\d.]+\s*'
1169 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +03001170)
1171
Benjamin Petersone549ead2009-03-28 21:42:05 +00001172_pypy_sys_version_parser = re.compile(
1173 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001174 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1175 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +00001176
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001177_sys_version_cache = {}
1178
1179def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001180
1181 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001182 (name, version, branch, revision, buildno, builddate, compiler)
1183 referring to the Python implementation name, version, branch,
1184 revision, build number, build date/time as string and the compiler
1185 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001186
1187 Note that unlike the Python sys.version, the returned value
1188 for the Python version will always include the patchlevel (it
1189 defaults to '.0').
1190
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001191 The function returns empty strings for tuple entries that
1192 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001193
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001194 sys_version may be given to parse an alternative version
1195 string, e.g. if the version was read from a different Python
1196 interpreter.
1197
1198 """
1199 # Get the Python version
1200 if sys_version is None:
1201 sys_version = sys.version
1202
1203 # Try the cache first
1204 result = _sys_version_cache.get(sys_version, None)
1205 if result is not None:
1206 return result
1207
1208 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001209 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001210 # IronPython
1211 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001212 if sys_version.startswith('IronPython'):
1213 match = _ironpython_sys_version_parser.match(sys_version)
1214 else:
1215 match = _ironpython26_sys_version_parser.match(sys_version)
1216
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001217 if match is None:
1218 raise ValueError(
1219 'failed to parse IronPython sys.version: %s' %
1220 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001221
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001222 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001223 buildno = ''
1224 builddate = ''
1225
Ezio Melottif076f532013-10-21 03:03:32 +03001226 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001227 # Jython
1228 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001229 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001230 if match is None:
1231 raise ValueError(
1232 'failed to parse Jython sys.version: %s' %
1233 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001234 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001235 if builddate is None:
1236 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001237 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001238
1239 elif "PyPy" in sys_version:
1240 # PyPy
1241 name = "PyPy"
1242 match = _pypy_sys_version_parser.match(sys_version)
1243 if match is None:
1244 raise ValueError("failed to parse PyPy sys.version: %s" %
1245 repr(sys_version))
1246 version, buildno, builddate, buildtime = match.groups()
1247 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001248
1249 else:
1250 # CPython
1251 match = _sys_version_parser.match(sys_version)
1252 if match is None:
1253 raise ValueError(
1254 'failed to parse CPython sys.version: %s' %
1255 repr(sys_version))
1256 version, buildno, builddate, buildtime, compiler = \
1257 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001258 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001259 if builddate is None:
1260 builddate = ''
1261 elif buildtime:
1262 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001263
Georg Brandl82562422011-03-05 21:09:22 +01001264 if hasattr(sys, '_mercurial'):
1265 _, branch, revision = sys._mercurial
1266 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001267 # sys.subversion was added in Python 2.5
1268 _, branch, revision = sys.subversion
1269 else:
1270 branch = ''
1271 revision = ''
1272
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001273 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001274 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001275 if len(l) == 2:
1276 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001277 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001278
1279 # Build and cache the result
1280 result = (name, version, branch, revision, buildno, builddate, compiler)
1281 _sys_version_cache[sys_version] = result
1282 return result
1283
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001284def python_implementation():
1285
1286 """ Returns a string identifying the Python implementation.
1287
1288 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001289 'CPython' (C implementation of Python),
1290 'IronPython' (.NET implementation of Python),
1291 'Jython' (Java implementation of Python),
1292 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001293
1294 """
1295 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001296
1297def python_version():
1298
1299 """ Returns the Python version as string 'major.minor.patchlevel'
1300
1301 Note that unlike the Python sys.version, the returned value
1302 will always include the patchlevel (it defaults to 0).
1303
1304 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001305 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001306
1307def python_version_tuple():
1308
1309 """ Returns the Python version as tuple (major, minor, patchlevel)
1310 of strings.
1311
1312 Note that unlike the Python sys.version, the returned value
1313 will always include the patchlevel (it defaults to 0).
1314
1315 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001316 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001317
1318def python_branch():
1319
1320 """ Returns a string identifying the Python implementation
1321 branch.
1322
1323 For CPython this is the Subversion branch from which the
1324 Python binary was built.
1325
1326 If not available, an empty string is returned.
1327
1328 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001329
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001330 return _sys_version()[2]
1331
1332def python_revision():
1333
1334 """ Returns a string identifying the Python implementation
1335 revision.
1336
1337 For CPython this is the Subversion revision from which the
1338 Python binary was built.
1339
1340 If not available, an empty string is returned.
1341
1342 """
1343 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001344
1345def python_build():
1346
1347 """ Returns a tuple (buildno, builddate) stating the Python
1348 build number and date as strings.
1349
1350 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001351 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001352
1353def python_compiler():
1354
1355 """ Returns a string identifying the compiler used for compiling
1356 Python.
1357
1358 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001359 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001360
1361### The Opus Magnum of platform strings :-)
1362
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001363_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001364
1365def platform(aliased=0, terse=0):
1366
1367 """ Returns a single string identifying the underlying platform
1368 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001369
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001370 The output is intended to be human readable rather than
1371 machine parseable. It may look different on different
1372 platforms and this is intended.
1373
1374 If "aliased" is true, the function will use aliases for
1375 various platforms that report system names which differ from
1376 their common names, e.g. SunOS will be reported as
1377 Solaris. The system_alias() function is used to implement
1378 this.
1379
1380 Setting terse to true causes the function to return only the
1381 absolute minimum information needed to identify the platform.
1382
1383 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001384 result = _platform_cache.get((aliased, terse), None)
1385 if result is not None:
1386 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001387
1388 # Get uname information and then apply platform specific cosmetics
1389 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001390 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001391 if machine == processor:
1392 processor = ''
1393 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001394 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001395
1396 if system == 'Windows':
1397 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001398 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001399 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001400 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001402 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001403
1404 elif system in ('Linux',):
1405 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001406 with warnings.catch_warnings():
1407 # see issue #1322 for more information
1408 warnings.filterwarnings(
1409 'ignore',
R David Murray44b548d2016-09-08 13:59:53 -04001410 r'dist\(\) and linux_distribution\(\) '
Berker Peksag1392f712015-05-16 20:24:28 +03001411 'functions are deprecated .*',
1412 PendingDeprecationWarning,
1413 )
1414 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001415 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001416 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001417 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001418 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001419 else:
1420 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001421 libcname, libcversion = libc_ver(sys.executable)
1422 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001423 'with',
1424 libcname+libcversion)
1425 elif system == 'Java':
1426 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001427 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001428 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001429 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001430 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001431 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001432 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001433 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001434
1435 elif system == 'MacOS':
1436 # MacOS platforms
1437 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001438 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001439 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001440 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001441
1442 else:
1443 # Generic handler
1444 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001445 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001446 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001447 bits, linkage = architecture(sys.executable)
1448 platform = _platform(system, release, machine,
1449 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001450
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001451 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001452 return platform
1453
1454### Command line interface
1455
1456if __name__ == '__main__':
1457 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001458 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001459 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001460 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001461 sys.exit(0)