blob: 6051f2b590195f4c50c906b018ce6ac208bfadf4 [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
Victor Stinnerced39362013-12-09 00:14:52 +0100143def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000144
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200145 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000146
Brett Cannon8ab27df2003-08-05 03:52:04 +0000147 """ Tries to determine the libc version that the file executable
148 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000149
150 Returns a tuple of strings (lib,version) which default to the
151 given parameters in case the lookup fails.
152
153 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000154 libc versions add symbols to the executable and thus is probably
155 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000156
157 The file is read and scanned in chunks of chunksize bytes.
158
159 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000160 if hasattr(os.path, 'realpath'):
161 # Python 2.2 introduced os.path.realpath(); it is used
162 # here to work around problems with Cygwin not being
163 # able to open symlinks for reading
164 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300165 with open(executable, 'rb') as f:
166 binary = f.read(chunksize)
167 pos = 0
168 while 1:
169 if b'libc' in binary or b'GLIBC' in binary:
170 m = _libc_search.search(binary, pos)
171 else:
172 m = None
173 if not m:
174 binary = f.read(chunksize)
175 if not binary:
176 break
177 pos = 0
178 continue
179 libcinit, glibc, glibcversion, so, threads, soversion = [
180 s.decode('latin1') if s is not None else s
181 for s in m.groups()]
182 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000183 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300184 elif glibc:
185 if lib != 'glibc':
186 lib = 'glibc'
187 version = glibcversion
188 elif glibcversion > version:
189 version = glibcversion
190 elif so:
191 if lib != 'glibc':
192 lib = 'libc'
193 if soversion and soversion > version:
194 version = soversion
195 if threads and version[-len(threads):] != threads:
196 version = version + threads
197 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100198 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000199
Victor Stinnerced39362013-12-09 00:14:52 +0100200def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000201
Tim Peters0eadaac2003-04-24 16:02:54 +0000202 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000203 information in case the default method fails.
204
205 Currently supports older SuSE Linux, Caldera OpenLinux and
206 Slackware Linux distributions.
207
208 """
209 if os.path.exists('/var/adm/inst-log/info'):
210 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000211 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000212 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000213 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000214 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100215 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000216 else:
217 continue
218 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000219 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000220 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000221 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000222 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100223 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000224
225 if os.path.exists('/etc/.installed'):
226 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000227 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000228 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000229 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
230 # XXX does Caldera support non Intel platforms ? If yes,
231 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100232 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000233
234 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300235 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000236 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000237 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000238 if verfiles[n][:14] != 'slack-version-':
239 del verfiles[n]
240 if verfiles:
241 verfiles.sort()
242 distname = 'slackware'
243 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100244 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000245
Victor Stinnerced39362013-12-09 00:14:52 +0100246 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000247
Antoine Pitrou877766d2011-03-19 17:00:37 +0100248def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000249
250 """ Portable popen() interface.
251 """
Victor Stinner25000d42011-05-24 00:16:16 +0200252 import warnings
253 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000254 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000255
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000256def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000257
Brett Cannon8ab27df2003-08-05 03:52:04 +0000258 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000259 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000260 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000261 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000262 if build:
263 l.append(build)
264 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100265 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000266 except ValueError:
267 strings = l
268 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100269 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000270 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000271 return version
272
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000273_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400274 r'.*'
275 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000276
277# Examples of VER command output:
278#
279# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
280# Windows XP: Microsoft Windows XP [Version 5.1.2600]
281# Windows Vista: Microsoft Windows [Version 6.0.6002]
282#
283# Note that the "Version" string gets localized on different
284# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000285
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000286def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000287
Victor Stinnerced39362013-12-09 00:14:52 +0100288 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000289
290 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100291 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000292
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000293 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200294 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000295
296 In case this fails, the given parameters are used as
297 defaults.
298
299 """
300 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100301 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000302
303 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100304 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000305 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700306 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000307 info = pipe.read()
308 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200309 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200310 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000311 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200312 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100313 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000314 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000315 else:
316 break
317 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100318 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000319
320 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000321 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000322 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000323 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100324 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000325 # Strip trailing dots from version and release
326 if release[-1] == '.':
327 release = release[:-1]
328 if version[-1] == '.':
329 version = version[:-1]
330 # Normalize the version and build strings (eliminating additional
331 # zeros)
332 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100333 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000334
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700335_WIN32_CLIENT_RELEASES = {
336 (5, 0): "2000",
337 (5, 1): "XP",
338 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
339 # has always called it 2003 Server
340 (5, 2): "2003Server",
341 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000342
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700343 (6, 0): "Vista",
344 (6, 1): "7",
345 (6, 2): "8",
346 (6, 3): "8.1",
347 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000348
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700349 (10, 0): "10",
350 (10, None): "post10",
351}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000352
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700353# Server release name lookup will default to client names if necessary
354_WIN32_SERVER_RELEASES = {
355 (5, 2): "2003Server",
356
357 (6, 0): "2008Server",
358 (6, 1): "2008ServerR2",
359 (6, 2): "2012Server",
360 (6, 3): "2012ServerR2",
361 (6, None): "post2012ServerR2",
362}
363
Victor Stinnerced39362013-12-09 00:14:52 +0100364def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700365 try:
366 from sys import getwindowsversion
367 except ImportError:
368 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000369 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700370 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400371 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700372 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
373
374 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700375 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700376 version = '{0}.{1}.{2}'.format(maj, min, build)
377
378 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
379 _WIN32_CLIENT_RELEASES.get((maj, None)) or
380 release)
381
382 # getwindowsversion() reflect the compatibility mode Python is
383 # running under, and so the service pack value is only going to be
384 # valid if the versions match.
385 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000386 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700387 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000388 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700389 if csd[:13] == 'Service Pack ':
390 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000391
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700392 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700393 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700394 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
395 _WIN32_SERVER_RELEASES.get((maj, None)) or
396 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000397
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700398 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000399 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700400 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
401 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
402 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000403 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700404 pass
405 finally:
406 if key:
407 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000408
Victor Stinnerced39362013-12-09 00:14:52 +0100409 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000410
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700411
Ronald Oussorene186e382010-07-23 11:54:59 +0000412def _mac_ver_xml():
413 fn = '/System/Library/CoreServices/SystemVersion.plist'
414 if not os.path.exists(fn):
415 return None
416
417 try:
418 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400419 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000420 return None
421
Ned Deily936dfae2014-01-13 11:34:19 -0800422 with open(fn, 'rb') as f:
423 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000424 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100425 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700426 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000427 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300428 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000429 machine = 'PowerPC'
430
Victor Stinnerced39362013-12-09 00:14:52 +0100431 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000432
433
Victor Stinnerced39362013-12-09 00:14:52 +0100434def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000435
436 """ Get MacOS version information and return it as tuple (release,
437 versioninfo, machine) with versioninfo being a tuple (version,
438 dev_stage, non_release_version).
439
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300440 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000441 which default to ''. All tuple entries are strings.
442 """
443
444 # First try reading the information from an XML file which should
445 # always be present
446 info = _mac_ver_xml()
447 if info is not None:
448 return info
449
Ronald Oussorene186e382010-07-23 11:54:59 +0000450 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100451 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452
Victor Stinnerced39362013-12-09 00:14:52 +0100453def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454
455 from java.lang import System
456 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000457 value = System.getProperty(name)
458 if value is None:
459 return default
460 return value
461 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 return default
463
Victor Stinnerced39362013-12-09 00:14:52 +0100464def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000465
Brett Cannon8ab27df2003-08-05 03:52:04 +0000466 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000467
Victor Stinnerced39362013-12-09 00:14:52 +0100468 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
469 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
470 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000471
472 Values which cannot be determined are set to the defaults
473 given as parameters (which all default to '').
474
475 """
476 # Import the needed APIs
477 try:
478 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400479 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100480 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000481
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000482 vendor = _java_getprop('java.vendor', vendor)
483 release = _java_getprop('java.version', release)
484 vm_name, vm_release, vm_vendor = vminfo
485 vm_name = _java_getprop('java.vm.name', vm_name)
486 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
487 vm_release = _java_getprop('java.vm.version', vm_release)
488 vminfo = vm_name, vm_release, vm_vendor
489 os_name, os_version, os_arch = osinfo
490 os_arch = _java_getprop('java.os.arch', os_arch)
491 os_name = _java_getprop('java.os.name', os_name)
492 os_version = _java_getprop('java.os.version', os_version)
493 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000494
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000495 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000496
497### System name aliasing
498
Victor Stinnerced39362013-12-09 00:14:52 +0100499def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000500
Victor Stinnerced39362013-12-09 00:14:52 +0100501 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000502 marketing names used for some systems.
503
504 It also does some reordering of the information in some cases
505 where it would otherwise cause confusion.
506
507 """
508 if system == 'Rhapsody':
509 # Apple's BSD derivative
510 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100511 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000512
513 elif system == 'SunOS':
514 # Sun's OS
515 if release < '5':
516 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100517 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000518 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000519 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000520 if l:
521 try:
522 major = int(l[0])
523 except ValueError:
524 pass
525 else:
526 major = major - 3
527 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000528 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000529 if release < '6':
530 system = 'Solaris'
531 else:
532 # XXX Whatever the new SunOS marketing name is...
533 system = 'Solaris'
534
535 elif system == 'IRIX64':
536 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
537 # is really a version and not a different platform, since 32-bit
538 # apps are also supported..
539 system = 'IRIX'
540 if version:
541 version = version + ' (64bit)'
542 else:
543 version = '64bit'
544
Victor Stinnerced39362013-12-09 00:14:52 +0100545 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000546 # In case one of the other tricks
547 system = 'Windows'
548
Victor Stinnerced39362013-12-09 00:14:52 +0100549 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000550
551### Various internal helpers
552
553def _platform(*args):
554
555 """ Helper to format the platform string in a filename
556 compatible format e.g. "system-version-machine".
557 """
558 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000559 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000560
561 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100562 platform = platform.replace(' ', '_')
563 platform = platform.replace('/', '-')
564 platform = platform.replace('\\', '-')
565 platform = platform.replace(':', '-')
566 platform = platform.replace(';', '-')
567 platform = platform.replace('"', '-')
568 platform = platform.replace('(', '-')
569 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000570
571 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100572 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000573
574 # Fold '--'s and remove trailing '-'
575 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100576 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000577 if cleaned == platform:
578 break
579 platform = cleaned
580 while platform[-1] == '-':
581 platform = platform[:-1]
582
583 return platform
584
585def _node(default=''):
586
587 """ Helper to determine the node name of this machine.
588 """
589 try:
590 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400591 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000592 # No sockets...
593 return default
594 try:
595 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200596 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000597 # Still not working...
598 return default
599
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000600def _follow_symlinks(filepath):
601
602 """ In case filepath is a symlink, follow it until a
603 real file is reached.
604 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000605 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606 while os.path.islink(filepath):
607 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100608 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000609 return filepath
610
Victor Stinnerced39362013-12-09 00:14:52 +0100611def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000612
613 """ Interface to the system's uname command.
614 """
Victor Stinnerced39362013-12-09 00:14:52 +0100615 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000616 # XXX Others too ?
617 return default
618 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000619 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200620 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000621 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000622 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000623 rc = f.close()
624 if not output or rc:
625 return default
626 else:
627 return output
628
Victor Stinnerced39362013-12-09 00:14:52 +0100629def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000630
631 """ Interface to the system's file command.
632
633 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000634 omit the filename in its output. Follow the symlinks. It returns
635 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636
637 """
Victor Stinnerced39362013-12-09 00:14:52 +0100638 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000639 # XXX Others too ?
640 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200641 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000642 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200643 proc = subprocess.Popen(['file', target],
644 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200645
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200646 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000647 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200648 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200649 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650 if not output or rc:
651 return default
652 else:
653 return output
654
655### Information about the used architecture
656
657# Default values for architecture; non-empty strings override the
658# defaults given as parameters
659_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100660 'win32': ('', 'WindowsPE'),
661 'win16': ('', 'Windows'),
662 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000663}
664
Victor Stinnerced39362013-12-09 00:14:52 +0100665def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000666
667 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000668 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000669
Victor Stinnerced39362013-12-09 00:14:52 +0100670 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000671 the bit architecture and the linkage format used for the
672 executable. Both values are returned as strings.
673
674 Values that cannot be determined are returned as given by the
675 parameter presets. If bits is given as '', the sizeof(pointer)
676 (or sizeof(long) on Python version < 1.5.2) is used as
677 indicator for the supported pointer size.
678
679 The function relies on the system's "file" command to do the
680 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000681 platforms. On some non-Unix platforms where the "file" command
682 does not exist and the executable is set to the Python interpreter
683 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000684
685 """
686 # Use the sizeof(pointer) as default number of bits if nothing
687 # else is given as default.
688 if not bits:
689 import struct
690 try:
691 size = struct.calcsize('P')
692 except struct.error:
693 # Older installations can only query longs
694 size = struct.calcsize('l')
695 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000696
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000697 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000698 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000699 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000700 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000701 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000703 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000704 executable == sys.executable:
705 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000706 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000707 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100708 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000709 if b:
710 bits = b
711 if l:
712 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100713 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000714
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000715 if 'executable' not in fileout:
716 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100717 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000718
719 # Bits
720 if '32-bit' in fileout:
721 bits = '32bit'
722 elif 'N32' in fileout:
723 # On Irix only
724 bits = 'n32bit'
725 elif '64-bit' in fileout:
726 bits = '64bit'
727
728 # Linkage
729 if 'ELF' in fileout:
730 linkage = 'ELF'
731 elif 'PE' in fileout:
732 # E.g. Windows uses this format
733 if 'Windows' in fileout:
734 linkage = 'WindowsPE'
735 else:
736 linkage = 'PE'
737 elif 'COFF' in fileout:
738 linkage = 'COFF'
739 elif 'MS-DOS' in fileout:
740 linkage = 'MSDOS'
741 else:
742 # XXX the A.OUT format also falls under this class...
743 pass
744
Victor Stinnerced39362013-12-09 00:14:52 +0100745 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746
747### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000748
Larry Hastings68386bc2012-06-24 14:30:41 -0700749uname_result = collections.namedtuple("uname_result",
750 "system node release version machine processor")
751
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000752_uname_cache = None
753
754def uname():
755
756 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100757 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000758 identifying the underlying platform.
759
760 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000761 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000762
763 Entries which cannot be determined are set to ''.
764
765 """
766 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000767 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000768
769 if _uname_cache is not None:
770 return _uname_cache
771
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000772 processor = ''
773
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000774 # Get some infos from the builtin os.uname API...
775 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100776 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000777 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000778 no_os_uname = 1
779
Georg Brandl62e2ca22010-07-31 21:54:24 +0000780 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000781 # Hmm, no there is either no uname or uname has returned
782 #'unknowns'... we'll have to poke around the system then.
783 if no_os_uname:
784 system = sys.platform
785 release = ''
786 version = ''
787 node = _node()
788 machine = ''
789
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000790 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000791
792 # Try win32_ver() on win32 platforms
793 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100794 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000795 if release and version:
796 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000797 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000798 # available on Win XP and later; see
799 # http://support.microsoft.com/kb/888731 and
800 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000801 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000802 # WOW64 processes mask the native architecture
803 if "PROCESSOR_ARCHITEW6432" in os.environ:
804 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
805 else:
806 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000807 if not processor:
808 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000809
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000810 # Try the 'ver' system command available on some
811 # platforms
812 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100813 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000814 # Normalize system to what win32_ver() normally returns
815 # (_syscmd_ver() tends to return the vendor name as well)
816 if system == 'Microsoft Windows':
817 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000818 elif system == 'Microsoft' and release == 'Windows':
819 # Under Windows Vista and Windows Server 2008,
820 # Microsoft changed the output of the ver command. The
821 # release is no longer printed. This causes the
822 # system and release to be misidentified.
823 system = 'Windows'
824 if '6.0' == version[:3]:
825 release = 'Vista'
826 else:
827 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000828
829 # In case we still don't know anything useful, we'll try to
830 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100831 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000832 if not version:
833 if system == 'win32':
834 version = '32bit'
835 else:
836 version = '16bit'
837 system = 'Windows'
838
839 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100840 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000841 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000842 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000843 if not version:
844 version = vendor
845
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000846 # System specific extensions
847 if system == 'OpenVMS':
848 # OpenVMS seems to have release and version mixed up
849 if not release or release == '0':
850 release = version
851 version = ''
852 # Get processor information
853 try:
854 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400855 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000856 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000857 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100858 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000859 if (cpu_number >= 128):
860 processor = 'Alpha'
861 else:
862 processor = 'VAX'
863 if not processor:
864 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +0100865 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000866
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000867 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000868 if system == 'unknown':
869 system = ''
870 if node == 'unknown':
871 node = ''
872 if release == 'unknown':
873 release = ''
874 if version == 'unknown':
875 version = ''
876 if machine == 'unknown':
877 machine = ''
878 if processor == 'unknown':
879 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000880
881 # normalize name
882 if system == 'Microsoft' and release == 'Windows':
883 system = 'Windows'
884 release = 'Vista'
885
Victor Stinnerced39362013-12-09 00:14:52 +0100886 _uname_cache = uname_result(system, node, release, version,
887 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000888 return _uname_cache
889
890### Direct interfaces to some of the uname() return values
891
892def system():
893
894 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
895
896 An empty string is returned if the value cannot be determined.
897
898 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700899 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000900
901def node():
902
Brett Cannon8ab27df2003-08-05 03:52:04 +0000903 """ Returns the computer's network name (which may not be fully
904 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000905
906 An empty string is returned if the value cannot be determined.
907
908 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700909 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000910
911def release():
912
913 """ Returns the system's release, e.g. '2.2.0' or 'NT'
914
915 An empty string is returned if the value cannot be determined.
916
917 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700918 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000919
920def version():
921
922 """ Returns the system's release version, e.g. '#3 on degas'
923
924 An empty string is returned if the value cannot be determined.
925
926 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700927 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000928
929def machine():
930
931 """ Returns the machine type, e.g. 'i386'
932
933 An empty string is returned if the value cannot be determined.
934
935 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700936 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000937
938def processor():
939
940 """ Returns the (true) processor name, e.g. 'amdk6'
941
942 An empty string is returned if the value cannot be
943 determined. Note that many platforms do not provide this
944 information or simply return the same value as for machine(),
945 e.g. NetBSD does this.
946
947 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700948 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000949
950### Various APIs for extracting information from sys.version
951
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000952_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +0000953 r'([\w.+]+)\s*' # "version<space>"
954 r'\(#?([^,]+)' # "(#buildno"
955 r'(?:,\s*([\w ]*)' # ", builddate"
956 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
957 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000959_ironpython_sys_version_parser = re.compile(
960 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400961 r'([\d\.]+)'
962 r'(?: \(([\d\.]+)\))?'
963 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000964
Ezio Melottif076f532013-10-21 03:03:32 +0300965# IronPython covering 2.6 and 2.7
966_ironpython26_sys_version_parser = re.compile(
967 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400968 r'\(IronPython\s*'
969 r'[\d.]+\s*'
970 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +0300971)
972
Benjamin Petersone549ead2009-03-28 21:42:05 +0000973_pypy_sys_version_parser = re.compile(
974 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400975 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
976 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +0000977
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000978_sys_version_cache = {}
979
980def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000981
982 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +0000983 (name, version, branch, revision, buildno, builddate, compiler)
984 referring to the Python implementation name, version, branch,
985 revision, build number, build date/time as string and the compiler
986 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000987
988 Note that unlike the Python sys.version, the returned value
989 for the Python version will always include the patchlevel (it
990 defaults to '.0').
991
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000992 The function returns empty strings for tuple entries that
993 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000994
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000995 sys_version may be given to parse an alternative version
996 string, e.g. if the version was read from a different Python
997 interpreter.
998
999 """
1000 # Get the Python version
1001 if sys_version is None:
1002 sys_version = sys.version
1003
1004 # Try the cache first
1005 result = _sys_version_cache.get(sys_version, None)
1006 if result is not None:
1007 return result
1008
1009 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001010 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001011 # IronPython
1012 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001013 if sys_version.startswith('IronPython'):
1014 match = _ironpython_sys_version_parser.match(sys_version)
1015 else:
1016 match = _ironpython26_sys_version_parser.match(sys_version)
1017
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001018 if match is None:
1019 raise ValueError(
1020 'failed to parse IronPython sys.version: %s' %
1021 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001022
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001023 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001024 buildno = ''
1025 builddate = ''
1026
Ezio Melottif076f532013-10-21 03:03:32 +03001027 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001028 # Jython
1029 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001030 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001031 if match is None:
1032 raise ValueError(
1033 'failed to parse Jython sys.version: %s' %
1034 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001035 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001036 if builddate is None:
1037 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001038 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001039
1040 elif "PyPy" in sys_version:
1041 # PyPy
1042 name = "PyPy"
1043 match = _pypy_sys_version_parser.match(sys_version)
1044 if match is None:
1045 raise ValueError("failed to parse PyPy sys.version: %s" %
1046 repr(sys_version))
1047 version, buildno, builddate, buildtime = match.groups()
1048 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001049
1050 else:
1051 # CPython
1052 match = _sys_version_parser.match(sys_version)
1053 if match is None:
1054 raise ValueError(
1055 'failed to parse CPython sys.version: %s' %
1056 repr(sys_version))
1057 version, buildno, builddate, buildtime, compiler = \
1058 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001059 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001060 if builddate is None:
1061 builddate = ''
1062 elif buildtime:
1063 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001064
Ned Deily5c4b0d02017-03-04 00:19:55 -05001065 if hasattr(sys, '_git'):
1066 _, branch, revision = sys._git
1067 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001068 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001069 else:
1070 branch = ''
1071 revision = ''
1072
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001073 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001074 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001075 if len(l) == 2:
1076 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001077 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001078
1079 # Build and cache the result
1080 result = (name, version, branch, revision, buildno, builddate, compiler)
1081 _sys_version_cache[sys_version] = result
1082 return result
1083
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001084def python_implementation():
1085
1086 """ Returns a string identifying the Python implementation.
1087
1088 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001089 'CPython' (C implementation of Python),
1090 'IronPython' (.NET implementation of Python),
1091 'Jython' (Java implementation of Python),
1092 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001093
1094 """
1095 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001096
1097def python_version():
1098
1099 """ Returns the Python version as string 'major.minor.patchlevel'
1100
1101 Note that unlike the Python sys.version, the returned value
1102 will always include the patchlevel (it defaults to 0).
1103
1104 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001105 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001106
1107def python_version_tuple():
1108
1109 """ Returns the Python version as tuple (major, minor, patchlevel)
1110 of strings.
1111
1112 Note that unlike the Python sys.version, the returned value
1113 will always include the patchlevel (it defaults to 0).
1114
1115 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001116 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001117
1118def python_branch():
1119
1120 """ Returns a string identifying the Python implementation
1121 branch.
1122
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001123 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001124 Python binary was built.
1125
1126 If not available, an empty string is returned.
1127
1128 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001129
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001130 return _sys_version()[2]
1131
1132def python_revision():
1133
1134 """ Returns a string identifying the Python implementation
1135 revision.
1136
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001137 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001138 Python binary was built.
1139
1140 If not available, an empty string is returned.
1141
1142 """
1143 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001144
1145def python_build():
1146
1147 """ Returns a tuple (buildno, builddate) stating the Python
1148 build number and date as strings.
1149
1150 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001151 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001152
1153def python_compiler():
1154
1155 """ Returns a string identifying the compiler used for compiling
1156 Python.
1157
1158 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001159 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001160
1161### The Opus Magnum of platform strings :-)
1162
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001163_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001164
1165def platform(aliased=0, terse=0):
1166
1167 """ Returns a single string identifying the underlying platform
1168 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001169
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001170 The output is intended to be human readable rather than
1171 machine parseable. It may look different on different
1172 platforms and this is intended.
1173
1174 If "aliased" is true, the function will use aliases for
1175 various platforms that report system names which differ from
1176 their common names, e.g. SunOS will be reported as
1177 Solaris. The system_alias() function is used to implement
1178 this.
1179
1180 Setting terse to true causes the function to return only the
1181 absolute minimum information needed to identify the platform.
1182
1183 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001184 result = _platform_cache.get((aliased, terse), None)
1185 if result is not None:
1186 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001187
1188 # Get uname information and then apply platform specific cosmetics
1189 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001190 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001191 if machine == processor:
1192 processor = ''
1193 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001194 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001195
1196 if system == 'Windows':
1197 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001198 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001199 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001200 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001201 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001202 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001203
1204 elif system in ('Linux',):
Petr Viktorin8b94b412018-05-16 11:51:18 -04001205 # check for libc vs. glibc
1206 libcname, libcversion = libc_ver(sys.executable)
1207 platform = _platform(system, release, machine, processor,
1208 'with',
1209 libcname+libcversion)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001210 elif system == 'Java':
1211 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001212 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001213 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001214 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001215 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001216 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001217 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001218 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001219
1220 elif system == 'MacOS':
1221 # MacOS platforms
1222 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001223 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001224 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001225 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001226
1227 else:
1228 # Generic handler
1229 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001230 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001231 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001232 bits, linkage = architecture(sys.executable)
1233 platform = _platform(system, release, machine,
1234 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001235
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001236 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001237 return platform
1238
1239### Command line interface
1240
1241if __name__ == '__main__':
1242 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001243 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001244 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001245 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001246 sys.exit(0)