blob: a7785a22440ed257268438e7429188a4e26096be [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Marc-André Lemburg246d8472003-04-24 11:36:11 +00002
Brett Cannon8ab27df2003-08-05 03:52:04 +00003""" This module tries to retrieve as much platform-identifying data as
Marc-André Lemburg246d8472003-04-24 11:36:11 +00004 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
Marc-André Lemburg246d8472003-04-24 11:36:11 +000015# Still needed:
Marc-André Lemburg246d8472003-04-24 11:36:11 +000016# * support for MS-DOS (PythonDX ?)
17# * support for Amiga and other still unsupported platforms running Python
18# * support for additional Linux distributions
19#
Brett Cannon8ab27df2003-08-05 03:52:04 +000020# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000021# checks (in no particular order):
22#
23# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
24# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
25# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
26# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
27# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Steve Dowerb9f4fea2015-09-22 17:23:39 -070028# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
29# Dower
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
Steve Dowerb9f4fea2015-09-22 17:23:39 -070035# 1.0.8 - changed Windows support to read version from kernel32.dll
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000036# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000037# 1.0.6 - added linux_distribution()
38# 1.0.5 - fixed Java support to allow running the module on Jython
39# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000040# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000041# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000042# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000043# 1.0.0 - reformatted a bit and checked into Python CVS
44# 0.8.0 - added sys.version parser and various new access
45# APIs (python_version(), python_compiler(), etc.)
46# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
47# 0.7.1 - added support for Caldera OpenLinux
48# 0.7.0 - some fixes for WinCE; untabified the source file
49# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
50# vms_lib.getsyi() configured
51# 0.6.1 - added code to prevent 'uname -p' on platforms which are
52# known not to support it
53# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
54# did some cleanup of the interfaces - some APIs have changed
55# 0.5.5 - fixed another type in the MacOS code... should have
56# used more coffee today ;-)
57# 0.5.4 - fixed a few typos in the MacOS code
58# 0.5.3 - added experimental MacOS support; added better popen()
59# workarounds in _syscmd_ver() -- still not 100% elegant
60# though
61# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
62# return values (the system uname command tends to return
Martin Pantereb995702016-07-28 01:11:04 +000063# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000064# 0.5.1 - included code for slackware dist; added exception handlers
65# to cover up situations where platforms don't have os.popen
66# (e.g. Mac) or fail on socket.gethostname(); fixed libc
67# detection RE
68# 0.5.0 - changed the API names referring to system commands to *syscmd*;
69# added java_ver(); made syscmd_ver() a private
70# API (was system_ver() in previous versions) -- use uname()
71# instead; extended the win32_ver() to also return processor
72# type information
73# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
74# 0.3.4 - fixed a bug in _follow_symlinks()
75# 0.3.3 - fixed popen() and "file" command invokation bugs
76# 0.3.2 - added architecture() API and support for it in platform()
77# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
78# 0.3.0 - added system alias support
79# 0.2.3 - removed 'wince' again... oh well.
80# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
81# 0.2.1 - added cache logic and changed the platform string format
82# 0.2.0 - changed the API to use functions instead of module globals
83# since some action take too long to be run on module import
84# 0.1.0 - first release
85#
86# You can always get the latest version of this module at:
87#
88# http://www.egenix.com/files/python/platform.py
89#
90# If that URL should fail, try contacting the author.
91
92__copyright__ = """
93 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Peterson46a99002010-01-09 18:45:30 +000094 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000095
96 Permission to use, copy, modify, and distribute this software and its
97 documentation for any purpose and without fee or royalty is hereby granted,
98 provided that the above copyright notice appear in all copies and that
99 both that copyright notice and this permission notice appear in
100 supporting documentation or portions thereof, including modifications,
101 that you make.
102
103 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
104 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
105 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
106 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
107 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
108 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
109 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
110
111"""
112
Matthias Bussonnier6059ce42017-02-24 02:47:34 -0800113__version__ = '1.0.8'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000114
Larry Hastings68386bc2012-06-24 14:30:41 -0700115import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200116import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000117
Berker Peksag1392f712015-05-16 20:24:28 +0300118import warnings
119
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000120### Globals & Constants
121
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100128 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000135### Platform specific APIs
136
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200137_libc_search = re.compile(b'(__libc_init)'
138 b'|'
139 b'(GLIBC_([0-9.]+))'
140 b'|'
141 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000142
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300143def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000144
Brett Cannon8ab27df2003-08-05 03:52:04 +0000145 """ Tries to determine the libc version that the file executable
146 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147
148 Returns a tuple of strings (lib,version) which default to the
149 given parameters in case the lookup fails.
150
151 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000152 libc versions add symbols to the executable and thus is probably
153 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000154
155 The file is read and scanned in chunks of chunksize bytes.
156
157 """
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300158 from distutils.version import LooseVersion as V
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000159 if hasattr(os.path, 'realpath'):
160 # Python 2.2 introduced os.path.realpath(); it is used
161 # here to work around problems with Cygwin not being
162 # able to open symlinks for reading
163 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300164 with open(executable, 'rb') as f:
165 binary = f.read(chunksize)
166 pos = 0
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300167 while pos < len(binary):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300168 if b'libc' in binary or b'GLIBC' in binary:
169 m = _libc_search.search(binary, pos)
170 else:
171 m = None
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300172 if not m or m.end() == len(binary):
173 chunk = f.read(chunksize)
174 if chunk:
175 binary = binary[max(pos, len(binary) - 1000):] + chunk
176 pos = 0
177 continue
178 if not m:
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300179 break
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300180 libcinit, glibc, glibcversion, so, threads, soversion = [
181 s.decode('latin1') if s is not None else s
182 for s in m.groups()]
183 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000184 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300185 elif glibc:
186 if lib != 'glibc':
187 lib = 'glibc'
188 version = glibcversion
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300189 elif V(glibcversion) > V(version):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300190 version = glibcversion
191 elif so:
192 if lib != 'glibc':
193 lib = 'libc'
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300194 if soversion and (not version or V(soversion) > V(version)):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300195 version = soversion
196 if threads and version[-len(threads):] != threads:
197 version = version + threads
198 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100199 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000200
Victor Stinnerced39362013-12-09 00:14:52 +0100201def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000202
Tim Peters0eadaac2003-04-24 16:02:54 +0000203 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000204 information in case the default method fails.
205
206 Currently supports older SuSE Linux, Caldera OpenLinux and
207 Slackware Linux distributions.
208
209 """
210 if os.path.exists('/var/adm/inst-log/info'):
211 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000212 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000213 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000214 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100216 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000217 else:
218 continue
219 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000220 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000221 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000222 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000223 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100224 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000225
226 if os.path.exists('/etc/.installed'):
227 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000228 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000229 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000230 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
231 # XXX does Caldera support non Intel platforms ? If yes,
232 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100233 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000234
235 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300236 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000237 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000238 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000239 if verfiles[n][:14] != 'slack-version-':
240 del verfiles[n]
241 if verfiles:
242 verfiles.sort()
243 distname = 'slackware'
244 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100245 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000246
Victor Stinnerced39362013-12-09 00:14:52 +0100247 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000248
Antoine Pitrou877766d2011-03-19 17:00:37 +0100249def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000250
251 """ Portable popen() interface.
252 """
Victor Stinner25000d42011-05-24 00:16:16 +0200253 import warnings
254 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000255 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000256
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300257
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000258def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000259
Brett Cannon8ab27df2003-08-05 03:52:04 +0000260 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000261 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000262 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000263 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000264 if build:
265 l.append(build)
266 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100267 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000268 except ValueError:
269 strings = l
270 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100271 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000272 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000273 return version
274
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000275_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400276 r'.*'
277 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000278
279# Examples of VER command output:
280#
281# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
282# Windows XP: Microsoft Windows XP [Version 5.1.2600]
283# Windows Vista: Microsoft Windows [Version 6.0.6002]
284#
285# Note that the "Version" string gets localized on different
286# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000287
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000288def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000289
Victor Stinnerced39362013-12-09 00:14:52 +0100290 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000291
292 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100293 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000294
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000295 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200296 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000297
298 In case this fails, the given parameters are used as
299 defaults.
300
301 """
302 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100303 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000304
305 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100306 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000307 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700308 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000309 info = pipe.read()
310 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200311 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200312 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000313 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200314 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100315 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000316 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000317 else:
318 break
319 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100320 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000321
322 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000323 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000324 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000325 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100326 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000327 # Strip trailing dots from version and release
328 if release[-1] == '.':
329 release = release[:-1]
330 if version[-1] == '.':
331 version = version[:-1]
332 # Normalize the version and build strings (eliminating additional
333 # zeros)
334 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100335 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000336
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700337_WIN32_CLIENT_RELEASES = {
338 (5, 0): "2000",
339 (5, 1): "XP",
340 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
341 # has always called it 2003 Server
342 (5, 2): "2003Server",
343 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000344
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700345 (6, 0): "Vista",
346 (6, 1): "7",
347 (6, 2): "8",
348 (6, 3): "8.1",
349 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000350
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700351 (10, 0): "10",
352 (10, None): "post10",
353}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000354
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700355# Server release name lookup will default to client names if necessary
356_WIN32_SERVER_RELEASES = {
357 (5, 2): "2003Server",
358
359 (6, 0): "2008Server",
360 (6, 1): "2008ServerR2",
361 (6, 2): "2012Server",
362 (6, 3): "2012ServerR2",
363 (6, None): "post2012ServerR2",
364}
365
Victor Stinnerced39362013-12-09 00:14:52 +0100366def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700367 try:
368 from sys import getwindowsversion
369 except ImportError:
370 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000371 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700372 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400373 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700374 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
375
376 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700377 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700378 version = '{0}.{1}.{2}'.format(maj, min, build)
379
380 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
381 _WIN32_CLIENT_RELEASES.get((maj, None)) or
382 release)
383
384 # getwindowsversion() reflect the compatibility mode Python is
385 # running under, and so the service pack value is only going to be
386 # valid if the versions match.
387 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000388 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700389 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000390 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700391 if csd[:13] == 'Service Pack ':
392 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000393
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700394 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700395 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700396 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
397 _WIN32_SERVER_RELEASES.get((maj, None)) or
398 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000399
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700400 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000401 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700402 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
403 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
404 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000405 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700406 pass
407 finally:
408 if key:
409 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000410
Victor Stinnerced39362013-12-09 00:14:52 +0100411 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000412
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700413
Ronald Oussorene186e382010-07-23 11:54:59 +0000414def _mac_ver_xml():
415 fn = '/System/Library/CoreServices/SystemVersion.plist'
416 if not os.path.exists(fn):
417 return None
418
419 try:
420 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400421 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000422 return None
423
Ned Deily936dfae2014-01-13 11:34:19 -0800424 with open(fn, 'rb') as f:
425 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000426 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100427 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700428 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000429 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300430 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000431 machine = 'PowerPC'
432
Victor Stinnerced39362013-12-09 00:14:52 +0100433 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000434
435
Victor Stinnerced39362013-12-09 00:14:52 +0100436def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000437
438 """ Get MacOS version information and return it as tuple (release,
439 versioninfo, machine) with versioninfo being a tuple (version,
440 dev_stage, non_release_version).
441
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300442 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000443 which default to ''. All tuple entries are strings.
444 """
445
446 # First try reading the information from an XML file which should
447 # always be present
448 info = _mac_ver_xml()
449 if info is not None:
450 return info
451
Ronald Oussorene186e382010-07-23 11:54:59 +0000452 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100453 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454
Victor Stinnerced39362013-12-09 00:14:52 +0100455def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
457 from java.lang import System
458 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000459 value = System.getProperty(name)
460 if value is None:
461 return default
462 return value
463 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000464 return default
465
Victor Stinnerced39362013-12-09 00:14:52 +0100466def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000467
Brett Cannon8ab27df2003-08-05 03:52:04 +0000468 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000469
Victor Stinnerced39362013-12-09 00:14:52 +0100470 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
471 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
472 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000473
474 Values which cannot be determined are set to the defaults
475 given as parameters (which all default to '').
476
477 """
478 # Import the needed APIs
479 try:
480 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400481 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100482 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000483
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000484 vendor = _java_getprop('java.vendor', vendor)
485 release = _java_getprop('java.version', release)
486 vm_name, vm_release, vm_vendor = vminfo
487 vm_name = _java_getprop('java.vm.name', vm_name)
488 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
489 vm_release = _java_getprop('java.vm.version', vm_release)
490 vminfo = vm_name, vm_release, vm_vendor
491 os_name, os_version, os_arch = osinfo
492 os_arch = _java_getprop('java.os.arch', os_arch)
493 os_name = _java_getprop('java.os.name', os_name)
494 os_version = _java_getprop('java.os.version', os_version)
495 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000496
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000497 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000498
499### System name aliasing
500
Victor Stinnerced39362013-12-09 00:14:52 +0100501def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000502
Victor Stinnerced39362013-12-09 00:14:52 +0100503 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000504 marketing names used for some systems.
505
506 It also does some reordering of the information in some cases
507 where it would otherwise cause confusion.
508
509 """
510 if system == 'Rhapsody':
511 # Apple's BSD derivative
512 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100513 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000514
515 elif system == 'SunOS':
516 # Sun's OS
517 if release < '5':
518 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100519 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000520 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000521 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000522 if l:
523 try:
524 major = int(l[0])
525 except ValueError:
526 pass
527 else:
528 major = major - 3
529 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000530 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000531 if release < '6':
532 system = 'Solaris'
533 else:
534 # XXX Whatever the new SunOS marketing name is...
535 system = 'Solaris'
536
537 elif system == 'IRIX64':
538 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
539 # is really a version and not a different platform, since 32-bit
540 # apps are also supported..
541 system = 'IRIX'
542 if version:
543 version = version + ' (64bit)'
544 else:
545 version = '64bit'
546
Victor Stinnerced39362013-12-09 00:14:52 +0100547 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548 # In case one of the other tricks
549 system = 'Windows'
550
Victor Stinnerced39362013-12-09 00:14:52 +0100551 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000552
553### Various internal helpers
554
555def _platform(*args):
556
557 """ Helper to format the platform string in a filename
558 compatible format e.g. "system-version-machine".
559 """
560 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000561 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000562
563 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100564 platform = platform.replace(' ', '_')
565 platform = platform.replace('/', '-')
566 platform = platform.replace('\\', '-')
567 platform = platform.replace(':', '-')
568 platform = platform.replace(';', '-')
569 platform = platform.replace('"', '-')
570 platform = platform.replace('(', '-')
571 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000572
573 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100574 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000575
576 # Fold '--'s and remove trailing '-'
577 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100578 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000579 if cleaned == platform:
580 break
581 platform = cleaned
582 while platform[-1] == '-':
583 platform = platform[:-1]
584
585 return platform
586
587def _node(default=''):
588
589 """ Helper to determine the node name of this machine.
590 """
591 try:
592 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400593 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000594 # No sockets...
595 return default
596 try:
597 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200598 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000599 # Still not working...
600 return default
601
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000602def _follow_symlinks(filepath):
603
604 """ In case filepath is a symlink, follow it until a
605 real file is reached.
606 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000607 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000608 while os.path.islink(filepath):
609 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100610 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000611 return filepath
612
Victor Stinnerced39362013-12-09 00:14:52 +0100613def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000614
615 """ Interface to the system's uname command.
616 """
Victor Stinnerced39362013-12-09 00:14:52 +0100617 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000618 # XXX Others too ?
619 return default
620 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000621 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200622 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000623 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000624 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000625 rc = f.close()
626 if not output or rc:
627 return default
628 else:
629 return output
630
Victor Stinnerced39362013-12-09 00:14:52 +0100631def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000632
633 """ Interface to the system's file command.
634
635 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000636 omit the filename in its output. Follow the symlinks. It returns
637 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638
639 """
Victor Stinnerced39362013-12-09 00:14:52 +0100640 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000641 # XXX Others too ?
642 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200643 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000644 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200645 proc = subprocess.Popen(['file', target],
646 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200647
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200648 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000649 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200650 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200651 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652 if not output or rc:
653 return default
654 else:
655 return output
656
657### Information about the used architecture
658
659# Default values for architecture; non-empty strings override the
660# defaults given as parameters
661_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100662 'win32': ('', 'WindowsPE'),
663 'win16': ('', 'Windows'),
664 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665}
666
Victor Stinnerced39362013-12-09 00:14:52 +0100667def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000668
669 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000670 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000671
Victor Stinnerced39362013-12-09 00:14:52 +0100672 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000673 the bit architecture and the linkage format used for the
674 executable. Both values are returned as strings.
675
676 Values that cannot be determined are returned as given by the
677 parameter presets. If bits is given as '', the sizeof(pointer)
678 (or sizeof(long) on Python version < 1.5.2) is used as
679 indicator for the supported pointer size.
680
681 The function relies on the system's "file" command to do the
682 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000683 platforms. On some non-Unix platforms where the "file" command
684 does not exist and the executable is set to the Python interpreter
685 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686
687 """
688 # Use the sizeof(pointer) as default number of bits if nothing
689 # else is given as default.
690 if not bits:
691 import struct
692 try:
693 size = struct.calcsize('P')
694 except struct.error:
695 # Older installations can only query longs
696 size = struct.calcsize('l')
697 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000698
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000699 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000700 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000701 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000702 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000703 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000704
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000705 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000706 executable == sys.executable:
707 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000708 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000709 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100710 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000711 if b:
712 bits = b
713 if l:
714 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100715 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000716
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000717 if 'executable' not in fileout:
718 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100719 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000720
721 # Bits
722 if '32-bit' in fileout:
723 bits = '32bit'
724 elif 'N32' in fileout:
725 # On Irix only
726 bits = 'n32bit'
727 elif '64-bit' in fileout:
728 bits = '64bit'
729
730 # Linkage
731 if 'ELF' in fileout:
732 linkage = 'ELF'
733 elif 'PE' in fileout:
734 # E.g. Windows uses this format
735 if 'Windows' in fileout:
736 linkage = 'WindowsPE'
737 else:
738 linkage = 'PE'
739 elif 'COFF' in fileout:
740 linkage = 'COFF'
741 elif 'MS-DOS' in fileout:
742 linkage = 'MSDOS'
743 else:
744 # XXX the A.OUT format also falls under this class...
745 pass
746
Victor Stinnerced39362013-12-09 00:14:52 +0100747 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000748
749### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000750
Larry Hastings68386bc2012-06-24 14:30:41 -0700751uname_result = collections.namedtuple("uname_result",
752 "system node release version machine processor")
753
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000754_uname_cache = None
755
756def uname():
757
758 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100759 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000760 identifying the underlying platform.
761
762 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000763 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000764
765 Entries which cannot be determined are set to ''.
766
767 """
768 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000769 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000770
771 if _uname_cache is not None:
772 return _uname_cache
773
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000774 processor = ''
775
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000776 # Get some infos from the builtin os.uname API...
777 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100778 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000779 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000780 no_os_uname = 1
781
Georg Brandl62e2ca22010-07-31 21:54:24 +0000782 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000783 # Hmm, no there is either no uname or uname has returned
784 #'unknowns'... we'll have to poke around the system then.
785 if no_os_uname:
786 system = sys.platform
787 release = ''
788 version = ''
789 node = _node()
790 machine = ''
791
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000792 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000793
794 # Try win32_ver() on win32 platforms
795 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100796 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000797 if release and version:
798 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000799 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000800 # available on Win XP and later; see
801 # http://support.microsoft.com/kb/888731 and
802 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000803 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000804 # WOW64 processes mask the native architecture
805 if "PROCESSOR_ARCHITEW6432" in os.environ:
806 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
807 else:
808 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000809 if not processor:
810 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000811
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000812 # Try the 'ver' system command available on some
813 # platforms
814 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100815 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000816 # Normalize system to what win32_ver() normally returns
817 # (_syscmd_ver() tends to return the vendor name as well)
818 if system == 'Microsoft Windows':
819 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000820 elif system == 'Microsoft' and release == 'Windows':
821 # Under Windows Vista and Windows Server 2008,
822 # Microsoft changed the output of the ver command. The
823 # release is no longer printed. This causes the
824 # system and release to be misidentified.
825 system = 'Windows'
826 if '6.0' == version[:3]:
827 release = 'Vista'
828 else:
829 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000830
831 # In case we still don't know anything useful, we'll try to
832 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100833 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000834 if not version:
835 if system == 'win32':
836 version = '32bit'
837 else:
838 version = '16bit'
839 system = 'Windows'
840
841 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100842 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000843 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000844 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000845 if not version:
846 version = vendor
847
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000848 # System specific extensions
849 if system == 'OpenVMS':
850 # OpenVMS seems to have release and version mixed up
851 if not release or release == '0':
852 release = version
853 version = ''
854 # Get processor information
855 try:
856 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400857 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000858 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000859 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100860 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000861 if (cpu_number >= 128):
862 processor = 'Alpha'
863 else:
864 processor = 'VAX'
865 if not processor:
866 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +0100867 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000868
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000869 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000870 if system == 'unknown':
871 system = ''
872 if node == 'unknown':
873 node = ''
874 if release == 'unknown':
875 release = ''
876 if version == 'unknown':
877 version = ''
878 if machine == 'unknown':
879 machine = ''
880 if processor == 'unknown':
881 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000882
883 # normalize name
884 if system == 'Microsoft' and release == 'Windows':
885 system = 'Windows'
886 release = 'Vista'
887
Victor Stinnerced39362013-12-09 00:14:52 +0100888 _uname_cache = uname_result(system, node, release, version,
889 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000890 return _uname_cache
891
892### Direct interfaces to some of the uname() return values
893
894def system():
895
896 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
897
898 An empty string is returned if the value cannot be determined.
899
900 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700901 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000902
903def node():
904
Brett Cannon8ab27df2003-08-05 03:52:04 +0000905 """ Returns the computer's network name (which may not be fully
906 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000907
908 An empty string is returned if the value cannot be determined.
909
910 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700911 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000912
913def release():
914
915 """ Returns the system's release, e.g. '2.2.0' or 'NT'
916
917 An empty string is returned if the value cannot be determined.
918
919 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700920 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000921
922def version():
923
924 """ Returns the system's release version, e.g. '#3 on degas'
925
926 An empty string is returned if the value cannot be determined.
927
928 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700929 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000930
931def machine():
932
933 """ Returns the machine type, e.g. 'i386'
934
935 An empty string is returned if the value cannot be determined.
936
937 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700938 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000939
940def processor():
941
942 """ Returns the (true) processor name, e.g. 'amdk6'
943
944 An empty string is returned if the value cannot be
945 determined. Note that many platforms do not provide this
946 information or simply return the same value as for machine(),
947 e.g. NetBSD does this.
948
949 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700950 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000951
952### Various APIs for extracting information from sys.version
953
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000954_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +0000955 r'([\w.+]+)\s*' # "version<space>"
956 r'\(#?([^,]+)' # "(#buildno"
957 r'(?:,\s*([\w ]*)' # ", builddate"
958 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
959 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000960
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000961_ironpython_sys_version_parser = re.compile(
962 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400963 r'([\d\.]+)'
964 r'(?: \(([\d\.]+)\))?'
965 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000966
Ezio Melottif076f532013-10-21 03:03:32 +0300967# IronPython covering 2.6 and 2.7
968_ironpython26_sys_version_parser = re.compile(
969 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400970 r'\(IronPython\s*'
971 r'[\d.]+\s*'
972 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +0300973)
974
Benjamin Petersone549ead2009-03-28 21:42:05 +0000975_pypy_sys_version_parser = re.compile(
976 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400977 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
978 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +0000979
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000980_sys_version_cache = {}
981
982def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000983
984 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +0000985 (name, version, branch, revision, buildno, builddate, compiler)
986 referring to the Python implementation name, version, branch,
987 revision, build number, build date/time as string and the compiler
988 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000989
990 Note that unlike the Python sys.version, the returned value
991 for the Python version will always include the patchlevel (it
992 defaults to '.0').
993
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000994 The function returns empty strings for tuple entries that
995 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000996
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000997 sys_version may be given to parse an alternative version
998 string, e.g. if the version was read from a different Python
999 interpreter.
1000
1001 """
1002 # Get the Python version
1003 if sys_version is None:
1004 sys_version = sys.version
1005
1006 # Try the cache first
1007 result = _sys_version_cache.get(sys_version, None)
1008 if result is not None:
1009 return result
1010
1011 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001012 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001013 # IronPython
1014 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001015 if sys_version.startswith('IronPython'):
1016 match = _ironpython_sys_version_parser.match(sys_version)
1017 else:
1018 match = _ironpython26_sys_version_parser.match(sys_version)
1019
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001020 if match is None:
1021 raise ValueError(
1022 'failed to parse IronPython sys.version: %s' %
1023 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001024
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001025 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001026 buildno = ''
1027 builddate = ''
1028
Ezio Melottif076f532013-10-21 03:03:32 +03001029 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001030 # Jython
1031 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001032 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001033 if match is None:
1034 raise ValueError(
1035 'failed to parse Jython sys.version: %s' %
1036 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001037 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001038 if builddate is None:
1039 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001040 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001041
1042 elif "PyPy" in sys_version:
1043 # PyPy
1044 name = "PyPy"
1045 match = _pypy_sys_version_parser.match(sys_version)
1046 if match is None:
1047 raise ValueError("failed to parse PyPy sys.version: %s" %
1048 repr(sys_version))
1049 version, buildno, builddate, buildtime = match.groups()
1050 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001051
1052 else:
1053 # CPython
1054 match = _sys_version_parser.match(sys_version)
1055 if match is None:
1056 raise ValueError(
1057 'failed to parse CPython sys.version: %s' %
1058 repr(sys_version))
1059 version, buildno, builddate, buildtime, compiler = \
1060 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001061 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001062 if builddate is None:
1063 builddate = ''
1064 elif buildtime:
1065 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001066
Ned Deily5c4b0d02017-03-04 00:19:55 -05001067 if hasattr(sys, '_git'):
1068 _, branch, revision = sys._git
1069 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001070 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001071 else:
1072 branch = ''
1073 revision = ''
1074
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001075 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001076 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001077 if len(l) == 2:
1078 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001079 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001080
1081 # Build and cache the result
1082 result = (name, version, branch, revision, buildno, builddate, compiler)
1083 _sys_version_cache[sys_version] = result
1084 return result
1085
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001086def python_implementation():
1087
1088 """ Returns a string identifying the Python implementation.
1089
1090 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001091 'CPython' (C implementation of Python),
1092 'IronPython' (.NET implementation of Python),
1093 'Jython' (Java implementation of Python),
1094 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001095
1096 """
1097 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001098
1099def python_version():
1100
1101 """ Returns the Python version as string 'major.minor.patchlevel'
1102
1103 Note that unlike the Python sys.version, the returned value
1104 will always include the patchlevel (it defaults to 0).
1105
1106 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001107 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001108
1109def python_version_tuple():
1110
1111 """ Returns the Python version as tuple (major, minor, patchlevel)
1112 of strings.
1113
1114 Note that unlike the Python sys.version, the returned value
1115 will always include the patchlevel (it defaults to 0).
1116
1117 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001118 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001119
1120def python_branch():
1121
1122 """ Returns a string identifying the Python implementation
1123 branch.
1124
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001125 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001126 Python binary was built.
1127
1128 If not available, an empty string is returned.
1129
1130 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001131
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001132 return _sys_version()[2]
1133
1134def python_revision():
1135
1136 """ Returns a string identifying the Python implementation
1137 revision.
1138
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001139 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001140 Python binary was built.
1141
1142 If not available, an empty string is returned.
1143
1144 """
1145 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001146
1147def python_build():
1148
1149 """ Returns a tuple (buildno, builddate) stating the Python
1150 build number and date as strings.
1151
1152 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001153 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001154
1155def python_compiler():
1156
1157 """ Returns a string identifying the compiler used for compiling
1158 Python.
1159
1160 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001161 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001162
1163### The Opus Magnum of platform strings :-)
1164
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001165_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001166
1167def platform(aliased=0, terse=0):
1168
1169 """ Returns a single string identifying the underlying platform
1170 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001171
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001172 The output is intended to be human readable rather than
1173 machine parseable. It may look different on different
1174 platforms and this is intended.
1175
1176 If "aliased" is true, the function will use aliases for
1177 various platforms that report system names which differ from
1178 their common names, e.g. SunOS will be reported as
1179 Solaris. The system_alias() function is used to implement
1180 this.
1181
1182 Setting terse to true causes the function to return only the
1183 absolute minimum information needed to identify the platform.
1184
1185 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001186 result = _platform_cache.get((aliased, terse), None)
1187 if result is not None:
1188 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001189
1190 # Get uname information and then apply platform specific cosmetics
1191 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001192 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001193 if machine == processor:
1194 processor = ''
1195 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001196 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001197
1198 if system == 'Windows':
1199 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001200 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001201 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001202 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001203 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001204 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001205
1206 elif system in ('Linux',):
Petr Viktorin8b94b412018-05-16 11:51:18 -04001207 # check for libc vs. glibc
1208 libcname, libcversion = libc_ver(sys.executable)
1209 platform = _platform(system, release, machine, processor,
1210 'with',
1211 libcname+libcversion)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001212 elif system == 'Java':
1213 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001214 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001215 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001216 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001217 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001218 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001219 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001220 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001221
1222 elif system == 'MacOS':
1223 # MacOS platforms
1224 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001225 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001226 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001227 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001228
1229 else:
1230 # Generic handler
1231 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001232 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001233 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001234 bits, linkage = architecture(sys.executable)
1235 platform = _platform(system, release, machine,
1236 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001237
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001238 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001239 return platform
1240
1241### Command line interface
1242
1243if __name__ == '__main__':
1244 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001245 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001246 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001247 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001248 sys.exit(0)