blob: f7e24d739c6d352e81680c7f7338360439fbdd69 [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
Serhiy Storchaka7d81e8f2018-08-27 13:29:51 +0300135# Helper for comparing two version number strings.
136# Based on the description of the PHP's version_compare():
137# http://php.net/manual/en/function.version-compare.php
138
139_ver_stages = {
140 # any string not found in this dict, will get 0 assigned
141 'dev': 10,
142 'alpha': 20, 'a': 20,
143 'beta': 30, 'b': 30,
144 'c': 40,
145 'RC': 50, 'rc': 50,
146 # number, will get 100 assigned
147 'pl': 200, 'p': 200,
148}
149
150_component_re = re.compile(r'([0-9]+|[._+-])')
151
152def _comparable_version(version):
153 result = []
154 for v in _component_re.split(version):
155 if v not in '._+-':
156 try:
157 v = int(v, 10)
158 t = 100
159 except ValueError:
160 t = _ver_stages.get(v, 0)
161 result.extend((t, v))
162 return result
163
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000164### Platform specific APIs
165
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200166_libc_search = re.compile(b'(__libc_init)'
167 b'|'
168 b'(GLIBC_([0-9.]+))'
169 b'|'
170 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000171
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300172def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000173
Brett Cannon8ab27df2003-08-05 03:52:04 +0000174 """ Tries to determine the libc version that the file executable
175 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000176
177 Returns a tuple of strings (lib,version) which default to the
178 given parameters in case the lookup fails.
179
180 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000181 libc versions add symbols to the executable and thus is probably
182 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000183
184 The file is read and scanned in chunks of chunksize bytes.
185
186 """
Serhiy Storchaka7d81e8f2018-08-27 13:29:51 +0300187 V = _comparable_version
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000188 if hasattr(os.path, 'realpath'):
189 # Python 2.2 introduced os.path.realpath(); it is used
190 # here to work around problems with Cygwin not being
191 # able to open symlinks for reading
192 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300193 with open(executable, 'rb') as f:
194 binary = f.read(chunksize)
195 pos = 0
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300196 while pos < len(binary):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300197 if b'libc' in binary or b'GLIBC' in binary:
198 m = _libc_search.search(binary, pos)
199 else:
200 m = None
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300201 if not m or m.end() == len(binary):
202 chunk = f.read(chunksize)
203 if chunk:
204 binary = binary[max(pos, len(binary) - 1000):] + chunk
205 pos = 0
206 continue
207 if not m:
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300208 break
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300209 libcinit, glibc, glibcversion, so, threads, soversion = [
210 s.decode('latin1') if s is not None else s
211 for s in m.groups()]
212 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000213 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300214 elif glibc:
215 if lib != 'glibc':
216 lib = 'glibc'
217 version = glibcversion
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300218 elif V(glibcversion) > V(version):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300219 version = glibcversion
220 elif so:
221 if lib != 'glibc':
222 lib = 'libc'
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300223 if soversion and (not version or V(soversion) > V(version)):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300224 version = soversion
225 if threads and version[-len(threads):] != threads:
226 version = version + threads
227 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100228 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000229
Victor Stinnerced39362013-12-09 00:14:52 +0100230def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000231
Tim Peters0eadaac2003-04-24 16:02:54 +0000232 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000233 information in case the default method fails.
234
235 Currently supports older SuSE Linux, Caldera OpenLinux and
236 Slackware Linux distributions.
237
238 """
239 if os.path.exists('/var/adm/inst-log/info'):
240 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000241 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000242 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000243 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000244 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100245 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000246 else:
247 continue
248 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000249 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000250 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000251 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000252 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100253 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000254
255 if os.path.exists('/etc/.installed'):
256 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000257 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000258 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000259 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
260 # XXX does Caldera support non Intel platforms ? If yes,
261 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100262 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000263
264 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300265 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000266 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000267 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000268 if verfiles[n][:14] != 'slack-version-':
269 del verfiles[n]
270 if verfiles:
271 verfiles.sort()
272 distname = 'slackware'
273 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100274 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000275
Victor Stinnerced39362013-12-09 00:14:52 +0100276 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000277
Antoine Pitrou877766d2011-03-19 17:00:37 +0100278def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000279
280 """ Portable popen() interface.
281 """
Victor Stinner25000d42011-05-24 00:16:16 +0200282 import warnings
283 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000284 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000285
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300286
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000287def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000288
Brett Cannon8ab27df2003-08-05 03:52:04 +0000289 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000290 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000291 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000292 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000293 if build:
294 l.append(build)
295 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100296 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000297 except ValueError:
298 strings = l
299 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100300 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000301 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000302 return version
303
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000304_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400305 r'.*'
306 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000307
308# Examples of VER command output:
309#
310# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
311# Windows XP: Microsoft Windows XP [Version 5.1.2600]
312# Windows Vista: Microsoft Windows [Version 6.0.6002]
313#
314# Note that the "Version" string gets localized on different
315# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000316
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000317def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000318
Victor Stinnerced39362013-12-09 00:14:52 +0100319 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000320
321 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100322 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000323
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000324 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200325 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000326
327 In case this fails, the given parameters are used as
328 defaults.
329
330 """
331 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100332 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000333
334 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100335 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000336 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700337 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000338 info = pipe.read()
339 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200340 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200341 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000342 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200343 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100344 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000345 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000346 else:
347 break
348 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100349 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000350
351 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000352 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000353 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000354 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100355 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000356 # Strip trailing dots from version and release
357 if release[-1] == '.':
358 release = release[:-1]
359 if version[-1] == '.':
360 version = version[:-1]
361 # Normalize the version and build strings (eliminating additional
362 # zeros)
363 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100364 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000365
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700366_WIN32_CLIENT_RELEASES = {
367 (5, 0): "2000",
368 (5, 1): "XP",
369 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
370 # has always called it 2003 Server
371 (5, 2): "2003Server",
372 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000373
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700374 (6, 0): "Vista",
375 (6, 1): "7",
376 (6, 2): "8",
377 (6, 3): "8.1",
378 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000379
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700380 (10, 0): "10",
381 (10, None): "post10",
382}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700384# Server release name lookup will default to client names if necessary
385_WIN32_SERVER_RELEASES = {
386 (5, 2): "2003Server",
387
388 (6, 0): "2008Server",
389 (6, 1): "2008ServerR2",
390 (6, 2): "2012Server",
391 (6, 3): "2012ServerR2",
392 (6, None): "post2012ServerR2",
393}
394
Victor Stinnerced39362013-12-09 00:14:52 +0100395def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700396 try:
397 from sys import getwindowsversion
398 except ImportError:
399 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000400 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700401 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400402 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700403 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
404
405 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700406 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700407 version = '{0}.{1}.{2}'.format(maj, min, build)
408
409 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
410 _WIN32_CLIENT_RELEASES.get((maj, None)) or
411 release)
412
413 # getwindowsversion() reflect the compatibility mode Python is
414 # running under, and so the service pack value is only going to be
415 # valid if the versions match.
416 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000417 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700418 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000419 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700420 if csd[:13] == 'Service Pack ':
421 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000422
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700423 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700424 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700425 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
426 _WIN32_SERVER_RELEASES.get((maj, None)) or
427 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000428
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700429 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000430 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700431 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
432 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
433 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000434 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700435 pass
436 finally:
437 if key:
438 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000439
Victor Stinnerced39362013-12-09 00:14:52 +0100440 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700442
Ronald Oussorene186e382010-07-23 11:54:59 +0000443def _mac_ver_xml():
444 fn = '/System/Library/CoreServices/SystemVersion.plist'
445 if not os.path.exists(fn):
446 return None
447
448 try:
449 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400450 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000451 return None
452
Ned Deily936dfae2014-01-13 11:34:19 -0800453 with open(fn, 'rb') as f:
454 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000455 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100456 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700457 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000458 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300459 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000460 machine = 'PowerPC'
461
Victor Stinnerced39362013-12-09 00:14:52 +0100462 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000463
464
Victor Stinnerced39362013-12-09 00:14:52 +0100465def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000466
467 """ Get MacOS version information and return it as tuple (release,
468 versioninfo, machine) with versioninfo being a tuple (version,
469 dev_stage, non_release_version).
470
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300471 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000472 which default to ''. All tuple entries are strings.
473 """
474
475 # First try reading the information from an XML file which should
476 # always be present
477 info = _mac_ver_xml()
478 if info is not None:
479 return info
480
Ronald Oussorene186e382010-07-23 11:54:59 +0000481 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100482 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000483
Victor Stinnerced39362013-12-09 00:14:52 +0100484def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485
486 from java.lang import System
487 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000488 value = System.getProperty(name)
489 if value is None:
490 return default
491 return value
492 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000493 return default
494
Victor Stinnerced39362013-12-09 00:14:52 +0100495def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000496
Brett Cannon8ab27df2003-08-05 03:52:04 +0000497 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000498
Victor Stinnerced39362013-12-09 00:14:52 +0100499 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
500 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
501 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000502
503 Values which cannot be determined are set to the defaults
504 given as parameters (which all default to '').
505
506 """
507 # Import the needed APIs
508 try:
509 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400510 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100511 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000512
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000513 vendor = _java_getprop('java.vendor', vendor)
514 release = _java_getprop('java.version', release)
515 vm_name, vm_release, vm_vendor = vminfo
516 vm_name = _java_getprop('java.vm.name', vm_name)
517 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
518 vm_release = _java_getprop('java.vm.version', vm_release)
519 vminfo = vm_name, vm_release, vm_vendor
520 os_name, os_version, os_arch = osinfo
521 os_arch = _java_getprop('java.os.arch', os_arch)
522 os_name = _java_getprop('java.os.name', os_name)
523 os_version = _java_getprop('java.os.version', os_version)
524 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000525
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000526 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000527
528### System name aliasing
529
Victor Stinnerced39362013-12-09 00:14:52 +0100530def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000531
Victor Stinnerced39362013-12-09 00:14:52 +0100532 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000533 marketing names used for some systems.
534
535 It also does some reordering of the information in some cases
536 where it would otherwise cause confusion.
537
538 """
539 if system == 'Rhapsody':
540 # Apple's BSD derivative
541 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100542 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000543
544 elif system == 'SunOS':
545 # Sun's OS
546 if release < '5':
547 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100548 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000549 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000550 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000551 if l:
552 try:
553 major = int(l[0])
554 except ValueError:
555 pass
556 else:
557 major = major - 3
558 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000559 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000560 if release < '6':
561 system = 'Solaris'
562 else:
563 # XXX Whatever the new SunOS marketing name is...
564 system = 'Solaris'
565
566 elif system == 'IRIX64':
567 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
568 # is really a version and not a different platform, since 32-bit
569 # apps are also supported..
570 system = 'IRIX'
571 if version:
572 version = version + ' (64bit)'
573 else:
574 version = '64bit'
575
Victor Stinnerced39362013-12-09 00:14:52 +0100576 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000577 # In case one of the other tricks
578 system = 'Windows'
579
Victor Stinnerced39362013-12-09 00:14:52 +0100580 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000581
582### Various internal helpers
583
584def _platform(*args):
585
586 """ Helper to format the platform string in a filename
587 compatible format e.g. "system-version-machine".
588 """
589 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000590 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000591
592 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100593 platform = platform.replace(' ', '_')
594 platform = platform.replace('/', '-')
595 platform = platform.replace('\\', '-')
596 platform = platform.replace(':', '-')
597 platform = platform.replace(';', '-')
598 platform = platform.replace('"', '-')
599 platform = platform.replace('(', '-')
600 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000601
602 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100603 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000604
605 # Fold '--'s and remove trailing '-'
606 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100607 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000608 if cleaned == platform:
609 break
610 platform = cleaned
611 while platform[-1] == '-':
612 platform = platform[:-1]
613
614 return platform
615
616def _node(default=''):
617
618 """ Helper to determine the node name of this machine.
619 """
620 try:
621 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400622 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000623 # No sockets...
624 return default
625 try:
626 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200627 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000628 # Still not working...
629 return default
630
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000631def _follow_symlinks(filepath):
632
633 """ In case filepath is a symlink, follow it until a
634 real file is reached.
635 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000636 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000637 while os.path.islink(filepath):
638 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100639 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000640 return filepath
641
Victor Stinnerced39362013-12-09 00:14:52 +0100642def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000643
644 """ Interface to the system's uname command.
645 """
Victor Stinnerced39362013-12-09 00:14:52 +0100646 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000647 # XXX Others too ?
648 return default
649 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000650 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200651 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000653 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654 rc = f.close()
655 if not output or rc:
656 return default
657 else:
658 return output
659
Victor Stinnerced39362013-12-09 00:14:52 +0100660def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000661
662 """ Interface to the system's file command.
663
664 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000665 omit the filename in its output. Follow the symlinks. It returns
666 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667
668 """
Victor Stinnerced39362013-12-09 00:14:52 +0100669 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000670 # XXX Others too ?
671 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200672 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000673 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200674 proc = subprocess.Popen(['file', target],
675 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200676
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200677 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000678 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200679 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200680 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000681 if not output or rc:
682 return default
683 else:
684 return output
685
686### Information about the used architecture
687
688# Default values for architecture; non-empty strings override the
689# defaults given as parameters
690_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100691 'win32': ('', 'WindowsPE'),
692 'win16': ('', 'Windows'),
693 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000694}
695
Victor Stinnerced39362013-12-09 00:14:52 +0100696def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000697
698 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000699 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000700
Victor Stinnerced39362013-12-09 00:14:52 +0100701 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702 the bit architecture and the linkage format used for the
703 executable. Both values are returned as strings.
704
705 Values that cannot be determined are returned as given by the
706 parameter presets. If bits is given as '', the sizeof(pointer)
707 (or sizeof(long) on Python version < 1.5.2) is used as
708 indicator for the supported pointer size.
709
710 The function relies on the system's "file" command to do the
711 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000712 platforms. On some non-Unix platforms where the "file" command
713 does not exist and the executable is set to the Python interpreter
714 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000715
716 """
717 # Use the sizeof(pointer) as default number of bits if nothing
718 # else is given as default.
719 if not bits:
720 import struct
721 try:
722 size = struct.calcsize('P')
723 except struct.error:
724 # Older installations can only query longs
725 size = struct.calcsize('l')
726 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000727
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000728 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000729 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000730 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000731 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000732 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000733
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000734 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000735 executable == sys.executable:
736 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000737 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000738 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100739 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000740 if b:
741 bits = b
742 if l:
743 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100744 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000745
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746 if 'executable' not in fileout:
747 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100748 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000749
750 # Bits
751 if '32-bit' in fileout:
752 bits = '32bit'
753 elif 'N32' in fileout:
754 # On Irix only
755 bits = 'n32bit'
756 elif '64-bit' in fileout:
757 bits = '64bit'
758
759 # Linkage
760 if 'ELF' in fileout:
761 linkage = 'ELF'
762 elif 'PE' in fileout:
763 # E.g. Windows uses this format
764 if 'Windows' in fileout:
765 linkage = 'WindowsPE'
766 else:
767 linkage = 'PE'
768 elif 'COFF' in fileout:
769 linkage = 'COFF'
770 elif 'MS-DOS' in fileout:
771 linkage = 'MSDOS'
772 else:
773 # XXX the A.OUT format also falls under this class...
774 pass
775
Victor Stinnerced39362013-12-09 00:14:52 +0100776 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000777
778### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000779
Larry Hastings68386bc2012-06-24 14:30:41 -0700780uname_result = collections.namedtuple("uname_result",
781 "system node release version machine processor")
782
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000783_uname_cache = None
784
785def uname():
786
787 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100788 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000789 identifying the underlying platform.
790
791 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000792 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000793
794 Entries which cannot be determined are set to ''.
795
796 """
797 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000798 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000799
800 if _uname_cache is not None:
801 return _uname_cache
802
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000803 processor = ''
804
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805 # Get some infos from the builtin os.uname API...
806 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100807 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000808 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000809 no_os_uname = 1
810
Georg Brandl62e2ca22010-07-31 21:54:24 +0000811 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000812 # Hmm, no there is either no uname or uname has returned
813 #'unknowns'... we'll have to poke around the system then.
814 if no_os_uname:
815 system = sys.platform
816 release = ''
817 version = ''
818 node = _node()
819 machine = ''
820
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000821 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000822
823 # Try win32_ver() on win32 platforms
824 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100825 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000826 if release and version:
827 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000828 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000829 # available on Win XP and later; see
830 # http://support.microsoft.com/kb/888731 and
831 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000832 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000833 # WOW64 processes mask the native architecture
834 if "PROCESSOR_ARCHITEW6432" in os.environ:
835 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
836 else:
837 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000838 if not processor:
839 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000840
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000841 # Try the 'ver' system command available on some
842 # platforms
843 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100844 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000845 # Normalize system to what win32_ver() normally returns
846 # (_syscmd_ver() tends to return the vendor name as well)
847 if system == 'Microsoft Windows':
848 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000849 elif system == 'Microsoft' and release == 'Windows':
850 # Under Windows Vista and Windows Server 2008,
851 # Microsoft changed the output of the ver command. The
852 # release is no longer printed. This causes the
853 # system and release to be misidentified.
854 system = 'Windows'
855 if '6.0' == version[:3]:
856 release = 'Vista'
857 else:
858 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000859
860 # In case we still don't know anything useful, we'll try to
861 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100862 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000863 if not version:
864 if system == 'win32':
865 version = '32bit'
866 else:
867 version = '16bit'
868 system = 'Windows'
869
870 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100871 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000872 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000873 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000874 if not version:
875 version = vendor
876
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000877 # System specific extensions
878 if system == 'OpenVMS':
879 # OpenVMS seems to have release and version mixed up
880 if not release or release == '0':
881 release = version
882 version = ''
883 # Get processor information
884 try:
885 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400886 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000887 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000888 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100889 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000890 if (cpu_number >= 128):
891 processor = 'Alpha'
892 else:
893 processor = 'VAX'
894 if not processor:
895 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +0100896 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000897
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000898 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899 if system == 'unknown':
900 system = ''
901 if node == 'unknown':
902 node = ''
903 if release == 'unknown':
904 release = ''
905 if version == 'unknown':
906 version = ''
907 if machine == 'unknown':
908 machine = ''
909 if processor == 'unknown':
910 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000911
912 # normalize name
913 if system == 'Microsoft' and release == 'Windows':
914 system = 'Windows'
915 release = 'Vista'
916
Victor Stinnerced39362013-12-09 00:14:52 +0100917 _uname_cache = uname_result(system, node, release, version,
918 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000919 return _uname_cache
920
921### Direct interfaces to some of the uname() return values
922
923def system():
924
925 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
926
927 An empty string is returned if the value cannot be determined.
928
929 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700930 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000931
932def node():
933
Brett Cannon8ab27df2003-08-05 03:52:04 +0000934 """ Returns the computer's network name (which may not be fully
935 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000936
937 An empty string is returned if the value cannot be determined.
938
939 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700940 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000941
942def release():
943
944 """ Returns the system's release, e.g. '2.2.0' or 'NT'
945
946 An empty string is returned if the value cannot be determined.
947
948 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700949 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000950
951def version():
952
953 """ Returns the system's release version, e.g. '#3 on degas'
954
955 An empty string is returned if the value cannot be determined.
956
957 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700958 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000959
960def machine():
961
962 """ Returns the machine type, e.g. 'i386'
963
964 An empty string is returned if the value cannot be determined.
965
966 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700967 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000968
969def processor():
970
971 """ Returns the (true) processor name, e.g. 'amdk6'
972
973 An empty string is returned if the value cannot be
974 determined. Note that many platforms do not provide this
975 information or simply return the same value as for machine(),
976 e.g. NetBSD does this.
977
978 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700979 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000980
981### Various APIs for extracting information from sys.version
982
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000983_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +0000984 r'([\w.+]+)\s*' # "version<space>"
985 r'\(#?([^,]+)' # "(#buildno"
986 r'(?:,\s*([\w ]*)' # ", builddate"
987 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
988 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000989
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000990_ironpython_sys_version_parser = re.compile(
991 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400992 r'([\d\.]+)'
993 r'(?: \(([\d\.]+)\))?'
994 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000995
Ezio Melottif076f532013-10-21 03:03:32 +0300996# IronPython covering 2.6 and 2.7
997_ironpython26_sys_version_parser = re.compile(
998 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400999 r'\(IronPython\s*'
1000 r'[\d.]+\s*'
1001 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +03001002)
1003
Benjamin Petersone549ead2009-03-28 21:42:05 +00001004_pypy_sys_version_parser = re.compile(
1005 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -04001006 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1007 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +00001008
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001009_sys_version_cache = {}
1010
1011def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001012
1013 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001014 (name, version, branch, revision, buildno, builddate, compiler)
1015 referring to the Python implementation name, version, branch,
1016 revision, build number, build date/time as string and the compiler
1017 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001018
1019 Note that unlike the Python sys.version, the returned value
1020 for the Python version will always include the patchlevel (it
1021 defaults to '.0').
1022
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001023 The function returns empty strings for tuple entries that
1024 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001025
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001026 sys_version may be given to parse an alternative version
1027 string, e.g. if the version was read from a different Python
1028 interpreter.
1029
1030 """
1031 # Get the Python version
1032 if sys_version is None:
1033 sys_version = sys.version
1034
1035 # Try the cache first
1036 result = _sys_version_cache.get(sys_version, None)
1037 if result is not None:
1038 return result
1039
1040 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001041 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001042 # IronPython
1043 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001044 if sys_version.startswith('IronPython'):
1045 match = _ironpython_sys_version_parser.match(sys_version)
1046 else:
1047 match = _ironpython26_sys_version_parser.match(sys_version)
1048
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001049 if match is None:
1050 raise ValueError(
1051 'failed to parse IronPython sys.version: %s' %
1052 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001053
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001054 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001055 buildno = ''
1056 builddate = ''
1057
Ezio Melottif076f532013-10-21 03:03:32 +03001058 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001059 # Jython
1060 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001061 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001062 if match is None:
1063 raise ValueError(
1064 'failed to parse Jython sys.version: %s' %
1065 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001066 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001067 if builddate is None:
1068 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001069 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001070
1071 elif "PyPy" in sys_version:
1072 # PyPy
1073 name = "PyPy"
1074 match = _pypy_sys_version_parser.match(sys_version)
1075 if match is None:
1076 raise ValueError("failed to parse PyPy sys.version: %s" %
1077 repr(sys_version))
1078 version, buildno, builddate, buildtime = match.groups()
1079 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001080
1081 else:
1082 # CPython
1083 match = _sys_version_parser.match(sys_version)
1084 if match is None:
1085 raise ValueError(
1086 'failed to parse CPython sys.version: %s' %
1087 repr(sys_version))
1088 version, buildno, builddate, buildtime, compiler = \
1089 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001090 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001091 if builddate is None:
1092 builddate = ''
1093 elif buildtime:
1094 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001095
Ned Deily5c4b0d02017-03-04 00:19:55 -05001096 if hasattr(sys, '_git'):
1097 _, branch, revision = sys._git
1098 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001099 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001100 else:
1101 branch = ''
1102 revision = ''
1103
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001104 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001105 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001106 if len(l) == 2:
1107 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001108 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001109
1110 # Build and cache the result
1111 result = (name, version, branch, revision, buildno, builddate, compiler)
1112 _sys_version_cache[sys_version] = result
1113 return result
1114
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001115def python_implementation():
1116
1117 """ Returns a string identifying the Python implementation.
1118
1119 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001120 'CPython' (C implementation of Python),
1121 'IronPython' (.NET implementation of Python),
1122 'Jython' (Java implementation of Python),
1123 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001124
1125 """
1126 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001127
1128def python_version():
1129
1130 """ Returns the Python version as string 'major.minor.patchlevel'
1131
1132 Note that unlike the Python sys.version, the returned value
1133 will always include the patchlevel (it defaults to 0).
1134
1135 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001136 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001137
1138def python_version_tuple():
1139
1140 """ Returns the Python version as tuple (major, minor, patchlevel)
1141 of strings.
1142
1143 Note that unlike the Python sys.version, the returned value
1144 will always include the patchlevel (it defaults to 0).
1145
1146 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001147 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001148
1149def python_branch():
1150
1151 """ Returns a string identifying the Python implementation
1152 branch.
1153
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001154 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001155 Python binary was built.
1156
1157 If not available, an empty string is returned.
1158
1159 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001160
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001161 return _sys_version()[2]
1162
1163def python_revision():
1164
1165 """ Returns a string identifying the Python implementation
1166 revision.
1167
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001168 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001169 Python binary was built.
1170
1171 If not available, an empty string is returned.
1172
1173 """
1174 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001175
1176def python_build():
1177
1178 """ Returns a tuple (buildno, builddate) stating the Python
1179 build number and date as strings.
1180
1181 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001182 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001183
1184def python_compiler():
1185
1186 """ Returns a string identifying the compiler used for compiling
1187 Python.
1188
1189 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001190 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001191
1192### The Opus Magnum of platform strings :-)
1193
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001194_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001195
1196def platform(aliased=0, terse=0):
1197
1198 """ Returns a single string identifying the underlying platform
1199 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001200
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001201 The output is intended to be human readable rather than
1202 machine parseable. It may look different on different
1203 platforms and this is intended.
1204
1205 If "aliased" is true, the function will use aliases for
1206 various platforms that report system names which differ from
1207 their common names, e.g. SunOS will be reported as
1208 Solaris. The system_alias() function is used to implement
1209 this.
1210
1211 Setting terse to true causes the function to return only the
1212 absolute minimum information needed to identify the platform.
1213
1214 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001215 result = _platform_cache.get((aliased, terse), None)
1216 if result is not None:
1217 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001218
1219 # Get uname information and then apply platform specific cosmetics
1220 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001221 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001222 if machine == processor:
1223 processor = ''
1224 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001225 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001226
1227 if system == 'Windows':
1228 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001229 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001230 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001231 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001232 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001233 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001234
1235 elif system in ('Linux',):
Petr Viktorin8b94b412018-05-16 11:51:18 -04001236 # check for libc vs. glibc
1237 libcname, libcversion = libc_ver(sys.executable)
1238 platform = _platform(system, release, machine, processor,
1239 'with',
1240 libcname+libcversion)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001241 elif system == 'Java':
1242 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001243 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001244 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001245 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001246 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001247 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001248 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001249 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001250
1251 elif system == 'MacOS':
1252 # MacOS platforms
1253 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001254 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001255 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001256 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001257
1258 else:
1259 # Generic handler
1260 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001261 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001262 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001263 bits, linkage = architecture(sys.executable)
1264 platform = _platform(system, release, machine,
1265 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001266
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001267 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001268 return platform
1269
1270### Command line interface
1271
1272if __name__ == '__main__':
1273 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001274 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001275 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001276 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001277 sys.exit(0)