blob: e219326087de49fcf845c281095ba9d6f8855c8f [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
Martin Pantereb995702016-07-28 01:11:04 +000064# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000065# 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
Steve Dower6a294a52016-09-09 18:01:25 -0700501if sys.platform == 'win32':
502 import ctypes
503 import ctypes.wintypes
504
505 class VS_FIXEDFILEINFO(ctypes.Structure):
506 _fields_ = [
507 ("dwSignature", ctypes.wintypes.DWORD),
508 ("dwStrucVersion", ctypes.wintypes.DWORD),
509 ("dwFileVersionMS", ctypes.wintypes.DWORD),
510 ("dwFileVersionLS", ctypes.wintypes.DWORD),
511 ("dwProductVersionMS", ctypes.wintypes.DWORD),
512 ("dwProductVersionLS", ctypes.wintypes.DWORD),
513 ("dwFileFlagsMask", ctypes.wintypes.DWORD),
514 ("dwFileFlags", ctypes.wintypes.DWORD),
515 ("dwFileOS", ctypes.wintypes.DWORD),
516 ("dwFileType", ctypes.wintypes.DWORD),
517 ("dwFileSubtype", ctypes.wintypes.DWORD),
518 ("dwFileDateMS", ctypes.wintypes.DWORD),
519 ("dwFileDateLS", ctypes.wintypes.DWORD),
520 ]
521
522 P_VS_FIXEDFILEINFO = ctypes.POINTER(VS_FIXEDFILEINFO)
523
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700524def _get_real_winver(maj, min, build):
525 if maj < 6 or (maj == 6 and min < 2):
526 return maj, min, build
527
Steve Dower6a294a52016-09-09 18:01:25 -0700528 kernel32 = ctypes.WinDLL('kernel32')
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700529 # 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
Steve Dower6a294a52016-09-09 18:01:25 -0700535 name = ctypes.create_unicode_buffer(name_len)
536 actual_len = kernel32.GetModuleFileNameW(
537 ctypes.wintypes.HANDLE(kernel32._handle),
538 name, len(name)
539 )
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700540 if not actual_len:
541 return maj, min, build
542
Steve Dower6a294a52016-09-09 18:01:25 -0700543 version = ctypes.WinDLL('version')
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700544 size = version.GetFileVersionInfoSizeW(name, None)
545 if not size:
546 return maj, min, build
547
Steve Dower6a294a52016-09-09 18:01:25 -0700548 ver_block = ctypes.c_buffer(size)
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700549 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
550 not ver_block):
551 return maj, min, build
552
Steve Dower6a294a52016-09-09 18:01:25 -0700553 pvi = P_VS_FIXEDFILEINFO()
554 if not version.VerQueryValueW(ver_block, "",
555 ctypes.byref(pvi), ctypes.byref(ctypes.wintypes.DWORD())):
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700556 return maj, min, build
557
558 maj = pvi.contents.dwProductVersionMS >> 16
559 min = pvi.contents.dwProductVersionMS & 0xFFFF
560 build = pvi.contents.dwProductVersionLS >> 16
561
562 return maj, min, build
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000563
Victor Stinnerced39362013-12-09 00:14:52 +0100564def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700565 try:
566 from sys import getwindowsversion
567 except ImportError:
568 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000569 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700570 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400571 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700572 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
573
574 winver = getwindowsversion()
575 maj, min, build = _get_real_winver(*winver[:3])
576 version = '{0}.{1}.{2}'.format(maj, min, build)
577
578 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
579 _WIN32_CLIENT_RELEASES.get((maj, None)) or
580 release)
581
582 # getwindowsversion() reflect the compatibility mode Python is
583 # running under, and so the service pack value is only going to be
584 # valid if the versions match.
585 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000586 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700587 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000588 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700589 if csd[:13] == 'Service Pack ':
590 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000591
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700592 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700593 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700594 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
595 _WIN32_SERVER_RELEASES.get((maj, None)) or
596 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000597
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700598 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000599 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700600 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
601 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
602 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000603 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700604 pass
605 finally:
606 if key:
607 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000608
Victor Stinnerced39362013-12-09 00:14:52 +0100609 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000610
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700611
Ronald Oussorene186e382010-07-23 11:54:59 +0000612def _mac_ver_xml():
613 fn = '/System/Library/CoreServices/SystemVersion.plist'
614 if not os.path.exists(fn):
615 return None
616
617 try:
618 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400619 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000620 return None
621
Ned Deily936dfae2014-01-13 11:34:19 -0800622 with open(fn, 'rb') as f:
623 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000624 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100625 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700626 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000627 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300628 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000629 machine = 'PowerPC'
630
Victor Stinnerced39362013-12-09 00:14:52 +0100631 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000632
633
Victor Stinnerced39362013-12-09 00:14:52 +0100634def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000635
636 """ Get MacOS version information and return it as tuple (release,
637 versioninfo, machine) with versioninfo being a tuple (version,
638 dev_stage, non_release_version).
639
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300640 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000641 which default to ''. All tuple entries are strings.
642 """
643
644 # First try reading the information from an XML file which should
645 # always be present
646 info = _mac_ver_xml()
647 if info is not None:
648 return info
649
Ronald Oussorene186e382010-07-23 11:54:59 +0000650 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100651 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652
Victor Stinnerced39362013-12-09 00:14:52 +0100653def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654
655 from java.lang import System
656 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000657 value = System.getProperty(name)
658 if value is None:
659 return default
660 return value
661 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000662 return default
663
Victor Stinnerced39362013-12-09 00:14:52 +0100664def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000665
Brett Cannon8ab27df2003-08-05 03:52:04 +0000666 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667
Victor Stinnerced39362013-12-09 00:14:52 +0100668 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
669 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
670 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000671
672 Values which cannot be determined are set to the defaults
673 given as parameters (which all default to '').
674
675 """
676 # Import the needed APIs
677 try:
678 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400679 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100680 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000681
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000682 vendor = _java_getprop('java.vendor', vendor)
683 release = _java_getprop('java.version', release)
684 vm_name, vm_release, vm_vendor = vminfo
685 vm_name = _java_getprop('java.vm.name', vm_name)
686 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
687 vm_release = _java_getprop('java.vm.version', vm_release)
688 vminfo = vm_name, vm_release, vm_vendor
689 os_name, os_version, os_arch = osinfo
690 os_arch = _java_getprop('java.os.arch', os_arch)
691 os_name = _java_getprop('java.os.name', os_name)
692 os_version = _java_getprop('java.os.version', os_version)
693 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000694
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000695 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000696
697### System name aliasing
698
Victor Stinnerced39362013-12-09 00:14:52 +0100699def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000700
Victor Stinnerced39362013-12-09 00:14:52 +0100701 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702 marketing names used for some systems.
703
704 It also does some reordering of the information in some cases
705 where it would otherwise cause confusion.
706
707 """
708 if system == 'Rhapsody':
709 # Apple's BSD derivative
710 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100711 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000712
713 elif system == 'SunOS':
714 # Sun's OS
715 if release < '5':
716 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100717 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000718 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000719 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000720 if l:
721 try:
722 major = int(l[0])
723 except ValueError:
724 pass
725 else:
726 major = major - 3
727 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000728 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000729 if release < '6':
730 system = 'Solaris'
731 else:
732 # XXX Whatever the new SunOS marketing name is...
733 system = 'Solaris'
734
735 elif system == 'IRIX64':
736 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
737 # is really a version and not a different platform, since 32-bit
738 # apps are also supported..
739 system = 'IRIX'
740 if version:
741 version = version + ' (64bit)'
742 else:
743 version = '64bit'
744
Victor Stinnerced39362013-12-09 00:14:52 +0100745 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746 # In case one of the other tricks
747 system = 'Windows'
748
Victor Stinnerced39362013-12-09 00:14:52 +0100749 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000750
751### Various internal helpers
752
753def _platform(*args):
754
755 """ Helper to format the platform string in a filename
756 compatible format e.g. "system-version-machine".
757 """
758 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000759 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000760
761 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100762 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('(', '-')
769 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000770
771 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100772 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000773
774 # Fold '--'s and remove trailing '-'
775 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100776 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000777 if cleaned == platform:
778 break
779 platform = cleaned
780 while platform[-1] == '-':
781 platform = platform[:-1]
782
783 return platform
784
785def _node(default=''):
786
787 """ Helper to determine the node name of this machine.
788 """
789 try:
790 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400791 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000792 # No sockets...
793 return default
794 try:
795 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200796 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000797 # Still not working...
798 return default
799
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000800def _follow_symlinks(filepath):
801
802 """ In case filepath is a symlink, follow it until a
803 real file is reached.
804 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000805 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000806 while os.path.islink(filepath):
807 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100808 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000809 return filepath
810
Victor Stinnerced39362013-12-09 00:14:52 +0100811def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000812
813 """ Interface to the system's uname command.
814 """
Victor Stinnerced39362013-12-09 00:14:52 +0100815 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000816 # XXX Others too ?
817 return default
818 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000819 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200820 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000822 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000823 rc = f.close()
824 if not output or rc:
825 return default
826 else:
827 return output
828
Victor Stinnerced39362013-12-09 00:14:52 +0100829def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000830
831 """ Interface to the system's file command.
832
833 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000834 omit the filename in its output. Follow the symlinks. It returns
835 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000836
837 """
Victor Stinnerced39362013-12-09 00:14:52 +0100838 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000839 # XXX Others too ?
840 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200841 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000842 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200843 proc = subprocess.Popen(['file', target],
844 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200845
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200846 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000847 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200848 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200849 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000850 if not output or rc:
851 return default
852 else:
853 return output
854
855### Information about the used architecture
856
857# Default values for architecture; non-empty strings override the
858# defaults given as parameters
859_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100860 'win32': ('', 'WindowsPE'),
861 'win16': ('', 'Windows'),
862 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000863}
864
Victor Stinnerced39362013-12-09 00:14:52 +0100865def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000866
867 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000868 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000869
Victor Stinnerced39362013-12-09 00:14:52 +0100870 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000871 the bit architecture and the linkage format used for the
872 executable. Both values are returned as strings.
873
874 Values that cannot be determined are returned as given by the
875 parameter presets. If bits is given as '', the sizeof(pointer)
876 (or sizeof(long) on Python version < 1.5.2) is used as
877 indicator for the supported pointer size.
878
879 The function relies on the system's "file" command to do the
880 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000881 platforms. On some non-Unix platforms where the "file" command
882 does not exist and the executable is set to the Python interpreter
883 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000884
885 """
886 # Use the sizeof(pointer) as default number of bits if nothing
887 # else is given as default.
888 if not bits:
889 import struct
890 try:
891 size = struct.calcsize('P')
892 except struct.error:
893 # Older installations can only query longs
894 size = struct.calcsize('l')
895 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000896
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000897 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000898 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000899 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000900 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000901 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000902
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000903 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000904 executable == sys.executable:
905 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000906 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000907 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100908 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000909 if b:
910 bits = b
911 if l:
912 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100913 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000914
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000915 if 'executable' not in fileout:
916 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100917 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000918
919 # Bits
920 if '32-bit' in fileout:
921 bits = '32bit'
922 elif 'N32' in fileout:
923 # On Irix only
924 bits = 'n32bit'
925 elif '64-bit' in fileout:
926 bits = '64bit'
927
928 # Linkage
929 if 'ELF' in fileout:
930 linkage = 'ELF'
931 elif 'PE' in fileout:
932 # E.g. Windows uses this format
933 if 'Windows' in fileout:
934 linkage = 'WindowsPE'
935 else:
936 linkage = 'PE'
937 elif 'COFF' in fileout:
938 linkage = 'COFF'
939 elif 'MS-DOS' in fileout:
940 linkage = 'MSDOS'
941 else:
942 # XXX the A.OUT format also falls under this class...
943 pass
944
Victor Stinnerced39362013-12-09 00:14:52 +0100945 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000946
947### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000948
Larry Hastings68386bc2012-06-24 14:30:41 -0700949uname_result = collections.namedtuple("uname_result",
950 "system node release version machine processor")
951
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000952_uname_cache = None
953
954def uname():
955
956 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100957 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958 identifying the underlying platform.
959
960 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000961 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000962
963 Entries which cannot be determined are set to ''.
964
965 """
966 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000967 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000968
969 if _uname_cache is not None:
970 return _uname_cache
971
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000972 processor = ''
973
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000974 # Get some infos from the builtin os.uname API...
975 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100976 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000977 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000978 no_os_uname = 1
979
Georg Brandl62e2ca22010-07-31 21:54:24 +0000980 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000981 # Hmm, no there is either no uname or uname has returned
982 #'unknowns'... we'll have to poke around the system then.
983 if no_os_uname:
984 system = sys.platform
985 release = ''
986 version = ''
987 node = _node()
988 machine = ''
989
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000990 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000991
992 # Try win32_ver() on win32 platforms
993 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100994 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000995 if release and version:
996 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000997 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000998 # available on Win XP and later; see
999 # http://support.microsoft.com/kb/888731 and
1000 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001001 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001002 # WOW64 processes mask the native architecture
1003 if "PROCESSOR_ARCHITEW6432" in os.environ:
1004 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1005 else:
1006 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001007 if not processor:
1008 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001009
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001010 # Try the 'ver' system command available on some
1011 # platforms
1012 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +01001013 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001014 # Normalize system to what win32_ver() normally returns
1015 # (_syscmd_ver() tends to return the vendor name as well)
1016 if system == 'Microsoft Windows':
1017 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001018 elif system == 'Microsoft' and release == 'Windows':
1019 # Under Windows Vista and Windows Server 2008,
1020 # Microsoft changed the output of the ver command. The
1021 # release is no longer printed. This causes the
1022 # system and release to be misidentified.
1023 system = 'Windows'
1024 if '6.0' == version[:3]:
1025 release = 'Vista'
1026 else:
1027 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001028
1029 # In case we still don't know anything useful, we'll try to
1030 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001031 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001032 if not version:
1033 if system == 'win32':
1034 version = '32bit'
1035 else:
1036 version = '16bit'
1037 system = 'Windows'
1038
1039 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001040 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001041 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001042 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001043 if not version:
1044 version = vendor
1045
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001046 # System specific extensions
1047 if system == 'OpenVMS':
1048 # OpenVMS seems to have release and version mixed up
1049 if not release or release == '0':
1050 release = version
1051 version = ''
1052 # Get processor information
1053 try:
1054 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001055 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001056 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001057 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001058 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001059 if (cpu_number >= 128):
1060 processor = 'Alpha'
1061 else:
1062 processor = 'VAX'
1063 if not processor:
1064 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001065 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001066
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001067 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001068 if system == 'unknown':
1069 system = ''
1070 if node == 'unknown':
1071 node = ''
1072 if release == 'unknown':
1073 release = ''
1074 if version == 'unknown':
1075 version = ''
1076 if machine == 'unknown':
1077 machine = ''
1078 if processor == 'unknown':
1079 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001080
1081 # normalize name
1082 if system == 'Microsoft' and release == 'Windows':
1083 system = 'Windows'
1084 release = 'Vista'
1085
Victor Stinnerced39362013-12-09 00:14:52 +01001086 _uname_cache = uname_result(system, node, release, version,
1087 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001088 return _uname_cache
1089
1090### Direct interfaces to some of the uname() return values
1091
1092def system():
1093
1094 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1095
1096 An empty string is returned if the value cannot be determined.
1097
1098 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001099 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001100
1101def node():
1102
Brett Cannon8ab27df2003-08-05 03:52:04 +00001103 """ Returns the computer's network name (which may not be fully
1104 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001105
1106 An empty string is returned if the value cannot be determined.
1107
1108 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001109 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001110
1111def release():
1112
1113 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1114
1115 An empty string is returned if the value cannot be determined.
1116
1117 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001118 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001119
1120def version():
1121
1122 """ Returns the system's release version, e.g. '#3 on degas'
1123
1124 An empty string is returned if the value cannot be determined.
1125
1126 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001127 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001128
1129def machine():
1130
1131 """ Returns the machine type, e.g. 'i386'
1132
1133 An empty string is returned if the value cannot be determined.
1134
1135 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001136 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001137
1138def processor():
1139
1140 """ Returns the (true) processor name, e.g. 'amdk6'
1141
1142 An empty string is returned if the value cannot be
1143 determined. Note that many platforms do not provide this
1144 information or simply return the same value as for machine(),
1145 e.g. NetBSD does this.
1146
1147 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001148 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001149
1150### Various APIs for extracting information from sys.version
1151
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001152_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001153 r'([\w.+]+)\s*' # "version<space>"
1154 r'\(#?([^,]+)' # "(#buildno"
1155 r'(?:,\s*([\w ]*)' # ", builddate"
1156 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1157 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001158
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001159_ironpython_sys_version_parser = re.compile(
1160 r'IronPython\s*'
1161 '([\d\.]+)'
1162 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001163 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001164
Ezio Melottif076f532013-10-21 03:03:32 +03001165# IronPython covering 2.6 and 2.7
1166_ironpython26_sys_version_parser = re.compile(
1167 r'([\d.]+)\s*'
1168 '\(IronPython\s*'
1169 '[\d.]+\s*'
1170 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1171)
1172
Benjamin Petersone549ead2009-03-28 21:42:05 +00001173_pypy_sys_version_parser = re.compile(
1174 r'([\w.+]+)\s*'
1175 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1176 '\[PyPy [^\]]+\]?')
1177
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001178_sys_version_cache = {}
1179
1180def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001181
1182 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001183 (name, version, branch, revision, buildno, builddate, compiler)
1184 referring to the Python implementation name, version, branch,
1185 revision, build number, build date/time as string and the compiler
1186 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001187
1188 Note that unlike the Python sys.version, the returned value
1189 for the Python version will always include the patchlevel (it
1190 defaults to '.0').
1191
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001192 The function returns empty strings for tuple entries that
1193 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001194
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001195 sys_version may be given to parse an alternative version
1196 string, e.g. if the version was read from a different Python
1197 interpreter.
1198
1199 """
1200 # Get the Python version
1201 if sys_version is None:
1202 sys_version = sys.version
1203
1204 # Try the cache first
1205 result = _sys_version_cache.get(sys_version, None)
1206 if result is not None:
1207 return result
1208
1209 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001210 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001211 # IronPython
1212 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001213 if sys_version.startswith('IronPython'):
1214 match = _ironpython_sys_version_parser.match(sys_version)
1215 else:
1216 match = _ironpython26_sys_version_parser.match(sys_version)
1217
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001218 if match is None:
1219 raise ValueError(
1220 'failed to parse IronPython sys.version: %s' %
1221 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001222
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001223 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001224 buildno = ''
1225 builddate = ''
1226
Ezio Melottif076f532013-10-21 03:03:32 +03001227 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001228 # Jython
1229 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001230 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001231 if match is None:
1232 raise ValueError(
1233 'failed to parse Jython sys.version: %s' %
1234 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001235 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001236 if builddate is None:
1237 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001238 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001239
1240 elif "PyPy" in sys_version:
1241 # PyPy
1242 name = "PyPy"
1243 match = _pypy_sys_version_parser.match(sys_version)
1244 if match is None:
1245 raise ValueError("failed to parse PyPy sys.version: %s" %
1246 repr(sys_version))
1247 version, buildno, builddate, buildtime = match.groups()
1248 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001249
1250 else:
1251 # CPython
1252 match = _sys_version_parser.match(sys_version)
1253 if match is None:
1254 raise ValueError(
1255 'failed to parse CPython sys.version: %s' %
1256 repr(sys_version))
1257 version, buildno, builddate, buildtime, compiler = \
1258 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001259 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001260 if builddate is None:
1261 builddate = ''
1262 elif buildtime:
1263 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001264
Georg Brandl82562422011-03-05 21:09:22 +01001265 if hasattr(sys, '_mercurial'):
1266 _, branch, revision = sys._mercurial
1267 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001268 # sys.subversion was added in Python 2.5
1269 _, branch, revision = sys.subversion
1270 else:
1271 branch = ''
1272 revision = ''
1273
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001274 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001275 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001276 if len(l) == 2:
1277 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001278 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001279
1280 # Build and cache the result
1281 result = (name, version, branch, revision, buildno, builddate, compiler)
1282 _sys_version_cache[sys_version] = result
1283 return result
1284
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001285def python_implementation():
1286
1287 """ Returns a string identifying the Python implementation.
1288
1289 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001290 'CPython' (C implementation of Python),
1291 'IronPython' (.NET implementation of Python),
1292 'Jython' (Java implementation of Python),
1293 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001294
1295 """
1296 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001297
1298def python_version():
1299
1300 """ Returns the Python version as string 'major.minor.patchlevel'
1301
1302 Note that unlike the Python sys.version, the returned value
1303 will always include the patchlevel (it defaults to 0).
1304
1305 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001306 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001307
1308def python_version_tuple():
1309
1310 """ Returns the Python version as tuple (major, minor, patchlevel)
1311 of strings.
1312
1313 Note that unlike the Python sys.version, the returned value
1314 will always include the patchlevel (it defaults to 0).
1315
1316 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001317 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001318
1319def python_branch():
1320
1321 """ Returns a string identifying the Python implementation
1322 branch.
1323
1324 For CPython this is the Subversion branch from which the
1325 Python binary was built.
1326
1327 If not available, an empty string is returned.
1328
1329 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001330
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001331 return _sys_version()[2]
1332
1333def python_revision():
1334
1335 """ Returns a string identifying the Python implementation
1336 revision.
1337
1338 For CPython this is the Subversion revision from which the
1339 Python binary was built.
1340
1341 If not available, an empty string is returned.
1342
1343 """
1344 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001345
1346def python_build():
1347
1348 """ Returns a tuple (buildno, builddate) stating the Python
1349 build number and date as strings.
1350
1351 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001352 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001353
1354def python_compiler():
1355
1356 """ Returns a string identifying the compiler used for compiling
1357 Python.
1358
1359 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001360 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001361
1362### The Opus Magnum of platform strings :-)
1363
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001364_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001365
1366def platform(aliased=0, terse=0):
1367
1368 """ Returns a single string identifying the underlying platform
1369 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001370
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001371 The output is intended to be human readable rather than
1372 machine parseable. It may look different on different
1373 platforms and this is intended.
1374
1375 If "aliased" is true, the function will use aliases for
1376 various platforms that report system names which differ from
1377 their common names, e.g. SunOS will be reported as
1378 Solaris. The system_alias() function is used to implement
1379 this.
1380
1381 Setting terse to true causes the function to return only the
1382 absolute minimum information needed to identify the platform.
1383
1384 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001385 result = _platform_cache.get((aliased, terse), None)
1386 if result is not None:
1387 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001388
1389 # Get uname information and then apply platform specific cosmetics
1390 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001391 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001392 if machine == processor:
1393 processor = ''
1394 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001395 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001396
1397 if system == 'Windows':
1398 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001399 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001400 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001401 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001402 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001403 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001404
1405 elif system in ('Linux',):
1406 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001407 with warnings.catch_warnings():
1408 # see issue #1322 for more information
1409 warnings.filterwarnings(
1410 'ignore',
1411 'dist\(\) and linux_distribution\(\) '
1412 'functions are deprecated .*',
1413 PendingDeprecationWarning,
1414 )
1415 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001416 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001417 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001418 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001419 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001420 else:
1421 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001422 libcname, libcversion = libc_ver(sys.executable)
1423 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001424 'with',
1425 libcname+libcversion)
1426 elif system == 'Java':
1427 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001428 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001429 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001430 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001431 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001432 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001433 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001434 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001435
1436 elif system == 'MacOS':
1437 # MacOS platforms
1438 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001439 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001440 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001441 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001442
1443 else:
1444 # Generic handler
1445 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001446 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001447 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001448 bits, linkage = architecture(sys.executable)
1449 platform = _platform(system, release, machine,
1450 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001451
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001452 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001453 return platform
1454
1455### Command line interface
1456
1457if __name__ == '__main__':
1458 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001459 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001460 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001461 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001462 sys.exit(0)