blob: 2ab68aed7861380a302ebde4970069a7bd45ca4d [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
Victor Stinnerb8e689a2018-12-04 17:18:12 +0100116import os
117import re
118import sys
Berker Peksag1392f712015-05-16 20:24:28 +0300119
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000120### Globals & Constants
121
Serhiy Storchaka7d81e8f2018-08-27 13:29:51 +0300122# Helper for comparing two version number strings.
123# Based on the description of the PHP's version_compare():
124# http://php.net/manual/en/function.version-compare.php
125
126_ver_stages = {
127 # any string not found in this dict, will get 0 assigned
128 'dev': 10,
129 'alpha': 20, 'a': 20,
130 'beta': 30, 'b': 30,
131 'c': 40,
132 'RC': 50, 'rc': 50,
133 # number, will get 100 assigned
134 'pl': 200, 'p': 200,
135}
136
137_component_re = re.compile(r'([0-9]+|[._+-])')
138
139def _comparable_version(version):
140 result = []
141 for v in _component_re.split(version):
142 if v not in '._+-':
143 try:
144 v = int(v, 10)
145 t = 100
146 except ValueError:
147 t = _ver_stages.get(v, 0)
148 result.extend((t, v))
149 return result
150
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000151### Platform specific APIs
152
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200153_libc_search = re.compile(b'(__libc_init)'
154 b'|'
155 b'(GLIBC_([0-9.]+))'
156 b'|'
157 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000158
Victor Stinner476b1132018-12-05 14:04:52 +0100159def libc_ver(executable=None, lib='', version='', chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000160
Brett Cannon8ab27df2003-08-05 03:52:04 +0000161 """ Tries to determine the libc version that the file executable
162 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000163
164 Returns a tuple of strings (lib,version) which default to the
165 given parameters in case the lookup fails.
166
167 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000168 libc versions add symbols to the executable and thus is probably
169 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000170
171 The file is read and scanned in chunks of chunksize bytes.
172
173 """
Victor Stinner476b1132018-12-05 14:04:52 +0100174 if executable is None:
175 try:
176 ver = os.confstr('CS_GNU_LIBC_VERSION')
177 # parse 'glibc 2.28' as ('glibc', '2.28')
178 parts = ver.split(maxsplit=1)
179 if len(parts) == 2:
180 return tuple(parts)
181 except (AttributeError, ValueError, OSError):
182 # os.confstr() or CS_GNU_LIBC_VERSION value not available
183 pass
184
185 executable = sys.executable
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
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000230def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000231
Brett Cannon8ab27df2003-08-05 03:52:04 +0000232 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000233 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000234 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000235 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000236 if build:
237 l.append(build)
238 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100239 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000240 except ValueError:
241 strings = l
242 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100243 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000244 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000245 return version
246
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000247_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400248 r'.*'
249 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000250
251# Examples of VER command output:
252#
253# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
254# Windows XP: Microsoft Windows XP [Version 5.1.2600]
255# Windows Vista: Microsoft Windows [Version 6.0.6002]
256#
257# Note that the "Version" string gets localized on different
258# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000259
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000260def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000261
Victor Stinnerced39362013-12-09 00:14:52 +0100262 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000263
264 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100265 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000266
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000267 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200268 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000269
270 In case this fails, the given parameters are used as
271 defaults.
272
273 """
274 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100275 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000276
277 # Try some common cmd strings
Victor Stinner3a521f02018-12-07 11:10:33 +0100278 import subprocess
Victor Stinnerced39362013-12-09 00:14:52 +0100279 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000280 try:
Victor Stinner3a521f02018-12-07 11:10:33 +0100281 info = subprocess.check_output(cmd,
282 stderr=subprocess.DEVNULL,
283 text=True,
284 shell=True)
285 except (OSError, subprocess.CalledProcessError) as why:
286 #print('Command %s failed: %s' % (cmd, why))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000287 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000288 else:
289 break
290 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100291 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000292
293 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000294 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000295 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000296 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100297 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000298 # Strip trailing dots from version and release
299 if release[-1] == '.':
300 release = release[:-1]
301 if version[-1] == '.':
302 version = version[:-1]
303 # Normalize the version and build strings (eliminating additional
304 # zeros)
305 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100306 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000307
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700308_WIN32_CLIENT_RELEASES = {
309 (5, 0): "2000",
310 (5, 1): "XP",
311 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
312 # has always called it 2003 Server
313 (5, 2): "2003Server",
314 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000315
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700316 (6, 0): "Vista",
317 (6, 1): "7",
318 (6, 2): "8",
319 (6, 3): "8.1",
320 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000321
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700322 (10, 0): "10",
323 (10, None): "post10",
324}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000325
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700326# Server release name lookup will default to client names if necessary
327_WIN32_SERVER_RELEASES = {
328 (5, 2): "2003Server",
329
330 (6, 0): "2008Server",
331 (6, 1): "2008ServerR2",
332 (6, 2): "2012Server",
333 (6, 3): "2012ServerR2",
334 (6, None): "post2012ServerR2",
335}
336
Victor Stinnerced39362013-12-09 00:14:52 +0100337def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700338 try:
339 from sys import getwindowsversion
340 except ImportError:
341 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000342 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700343 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400344 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700345 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
346
347 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700348 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700349 version = '{0}.{1}.{2}'.format(maj, min, build)
350
351 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
352 _WIN32_CLIENT_RELEASES.get((maj, None)) or
353 release)
354
355 # getwindowsversion() reflect the compatibility mode Python is
356 # running under, and so the service pack value is only going to be
357 # valid if the versions match.
358 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000359 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700360 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000361 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700362 if csd[:13] == 'Service Pack ':
363 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000364
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700365 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700366 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700367 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
368 _WIN32_SERVER_RELEASES.get((maj, None)) or
369 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000370
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700371 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000372 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700373 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
374 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
375 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000376 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700377 pass
378 finally:
379 if key:
380 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000381
Victor Stinnerced39362013-12-09 00:14:52 +0100382 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700384
Ronald Oussorene186e382010-07-23 11:54:59 +0000385def _mac_ver_xml():
386 fn = '/System/Library/CoreServices/SystemVersion.plist'
387 if not os.path.exists(fn):
388 return None
389
390 try:
391 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400392 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000393 return None
394
Ned Deily936dfae2014-01-13 11:34:19 -0800395 with open(fn, 'rb') as f:
396 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000397 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100398 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700399 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000400 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300401 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000402 machine = 'PowerPC'
403
Victor Stinnerced39362013-12-09 00:14:52 +0100404 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000405
406
Victor Stinnerced39362013-12-09 00:14:52 +0100407def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000408
Victor Stinnerb0e08772018-12-12 17:48:08 +0100409 """ Get macOS version information and return it as tuple (release,
Ronald Oussorene186e382010-07-23 11:54:59 +0000410 versioninfo, machine) with versioninfo being a tuple (version,
411 dev_stage, non_release_version).
412
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300413 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000414 which default to ''. All tuple entries are strings.
415 """
416
417 # First try reading the information from an XML file which should
418 # always be present
419 info = _mac_ver_xml()
420 if info is not None:
421 return info
422
Ronald Oussorene186e382010-07-23 11:54:59 +0000423 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100424 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000425
Victor Stinnerced39362013-12-09 00:14:52 +0100426def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000427
428 from java.lang import System
429 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000430 value = System.getProperty(name)
431 if value is None:
432 return default
433 return value
434 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000435 return default
436
Victor Stinnerced39362013-12-09 00:14:52 +0100437def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000438
Brett Cannon8ab27df2003-08-05 03:52:04 +0000439 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000440
Victor Stinnerced39362013-12-09 00:14:52 +0100441 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
442 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
443 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000444
445 Values which cannot be determined are set to the defaults
446 given as parameters (which all default to '').
447
448 """
449 # Import the needed APIs
450 try:
451 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400452 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100453 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000455 vendor = _java_getprop('java.vendor', vendor)
456 release = _java_getprop('java.version', release)
457 vm_name, vm_release, vm_vendor = vminfo
458 vm_name = _java_getprop('java.vm.name', vm_name)
459 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
460 vm_release = _java_getprop('java.vm.version', vm_release)
461 vminfo = vm_name, vm_release, vm_vendor
462 os_name, os_version, os_arch = osinfo
463 os_arch = _java_getprop('java.os.arch', os_arch)
464 os_name = _java_getprop('java.os.name', os_name)
465 os_version = _java_getprop('java.os.version', os_version)
466 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000467
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000468 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000469
470### System name aliasing
471
Victor Stinnerced39362013-12-09 00:14:52 +0100472def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000473
Victor Stinnerced39362013-12-09 00:14:52 +0100474 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000475 marketing names used for some systems.
476
477 It also does some reordering of the information in some cases
478 where it would otherwise cause confusion.
479
480 """
Victor Stinnerb0e08772018-12-12 17:48:08 +0100481 if system == 'SunOS':
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000482 # Sun's OS
483 if release < '5':
484 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100485 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000486 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000487 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488 if l:
489 try:
490 major = int(l[0])
491 except ValueError:
492 pass
493 else:
494 major = major - 3
495 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000496 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000497 if release < '6':
498 system = 'Solaris'
499 else:
500 # XXX Whatever the new SunOS marketing name is...
501 system = 'Solaris'
502
503 elif system == 'IRIX64':
504 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
505 # is really a version and not a different platform, since 32-bit
506 # apps are also supported..
507 system = 'IRIX'
508 if version:
509 version = version + ' (64bit)'
510 else:
511 version = '64bit'
512
Victor Stinnerced39362013-12-09 00:14:52 +0100513 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000514 # In case one of the other tricks
515 system = 'Windows'
516
Victor Stinner60875db2018-12-18 19:51:35 +0100517 # bpo-35516: Don't replace Darwin with macOS since input release and
518 # version arguments can be different than the currently running version.
519
Victor Stinnerced39362013-12-09 00:14:52 +0100520 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000521
522### Various internal helpers
523
524def _platform(*args):
525
526 """ Helper to format the platform string in a filename
527 compatible format e.g. "system-version-machine".
528 """
529 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000530 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000531
532 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100533 platform = platform.replace(' ', '_')
534 platform = platform.replace('/', '-')
535 platform = platform.replace('\\', '-')
536 platform = platform.replace(':', '-')
537 platform = platform.replace(';', '-')
538 platform = platform.replace('"', '-')
539 platform = platform.replace('(', '-')
540 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000541
542 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100543 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000544
545 # Fold '--'s and remove trailing '-'
546 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100547 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548 if cleaned == platform:
549 break
550 platform = cleaned
551 while platform[-1] == '-':
552 platform = platform[:-1]
553
554 return platform
555
556def _node(default=''):
557
558 """ Helper to determine the node name of this machine.
559 """
560 try:
561 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400562 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000563 # No sockets...
564 return default
565 try:
566 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200567 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000568 # Still not working...
569 return default
570
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000571def _follow_symlinks(filepath):
572
573 """ In case filepath is a symlink, follow it until a
574 real file is reached.
575 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000576 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000577 while os.path.islink(filepath):
578 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100579 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000580 return filepath
581
Victor Stinnerced39362013-12-09 00:14:52 +0100582def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000583
584 """ Interface to the system's uname command.
585 """
Victor Stinnerced39362013-12-09 00:14:52 +0100586 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000587 # XXX Others too ?
588 return default
Victor Stinner3a521f02018-12-07 11:10:33 +0100589
590 import subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000591 try:
Victor Stinner3a521f02018-12-07 11:10:33 +0100592 output = subprocess.check_output(('uname', option),
593 stderr=subprocess.DEVNULL,
594 text=True)
595 except (OSError, subprocess.CalledProcessError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000596 return default
Victor Stinner3a521f02018-12-07 11:10:33 +0100597 return (output.strip() or default)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000598
Victor Stinnerced39362013-12-09 00:14:52 +0100599def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000600
601 """ Interface to the system's file command.
602
603 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000604 omit the filename in its output. Follow the symlinks. It returns
605 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606
607 """
Victor Stinnerced39362013-12-09 00:14:52 +0100608 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000609 # XXX Others too ?
610 return default
Victor Stinnerb8e689a2018-12-04 17:18:12 +0100611
612 import subprocess
Jesus Ceafc990e92012-10-04 13:51:43 +0200613 target = _follow_symlinks(target)
Victor Stinner0af9c332018-12-17 18:47:24 +0100614 # "file" output is locale dependent: force the usage of the C locale
615 # to get deterministic behavior.
616 env = dict(os.environ, LC_ALL='C')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000617 try:
Victor Stinner0af9c332018-12-17 18:47:24 +0100618 # -b: do not prepend filenames to output lines (brief mode)
619 output = subprocess.check_output(['file', '-b', target],
Victor Stinner3a521f02018-12-07 11:10:33 +0100620 stderr=subprocess.DEVNULL,
Victor Stinner0af9c332018-12-17 18:47:24 +0100621 env=env)
Victor Stinner3a521f02018-12-07 11:10:33 +0100622 except (OSError, subprocess.CalledProcessError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000623 return default
Victor Stinner0af9c332018-12-17 18:47:24 +0100624 if not output:
625 return default
626 # With the C locale, the output should be mostly ASCII-compatible.
627 # Decode from Latin-1 to prevent Unicode decode error.
628 return output.decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000629
630### Information about the used architecture
631
632# Default values for architecture; non-empty strings override the
633# defaults given as parameters
634_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100635 'win32': ('', 'WindowsPE'),
636 'win16': ('', 'Windows'),
637 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638}
639
Victor Stinnerced39362013-12-09 00:14:52 +0100640def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000641
642 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000643 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000644
Victor Stinnerced39362013-12-09 00:14:52 +0100645 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000646 the bit architecture and the linkage format used for the
647 executable. Both values are returned as strings.
648
649 Values that cannot be determined are returned as given by the
650 parameter presets. If bits is given as '', the sizeof(pointer)
651 (or sizeof(long) on Python version < 1.5.2) is used as
652 indicator for the supported pointer size.
653
654 The function relies on the system's "file" command to do the
655 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000656 platforms. On some non-Unix platforms where the "file" command
657 does not exist and the executable is set to the Python interpreter
658 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000659
660 """
661 # Use the sizeof(pointer) as default number of bits if nothing
662 # else is given as default.
663 if not bits:
664 import struct
Victor Stinner4aa917c2018-12-14 13:14:10 +0100665 size = struct.calcsize('P')
666 bits = str(size * 8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000667
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000668 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000669 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000670 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000671 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000672 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000673
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000674 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000675 executable == sys.executable:
676 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000677 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000678 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100679 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000680 if b:
681 bits = b
682 if l:
683 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100684 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000685
Victor Stinner0af9c332018-12-17 18:47:24 +0100686 if 'executable' not in fileout and 'shared object' not in fileout:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100688 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000689
690 # Bits
691 if '32-bit' in fileout:
692 bits = '32bit'
693 elif 'N32' in fileout:
694 # On Irix only
695 bits = 'n32bit'
696 elif '64-bit' in fileout:
697 bits = '64bit'
698
699 # Linkage
700 if 'ELF' in fileout:
701 linkage = 'ELF'
702 elif 'PE' in fileout:
703 # E.g. Windows uses this format
704 if 'Windows' in fileout:
705 linkage = 'WindowsPE'
706 else:
707 linkage = 'PE'
708 elif 'COFF' in fileout:
709 linkage = 'COFF'
710 elif 'MS-DOS' in fileout:
711 linkage = 'MSDOS'
712 else:
713 # XXX the A.OUT format also falls under this class...
714 pass
715
Victor Stinnerced39362013-12-09 00:14:52 +0100716 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000717
718### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000719
Larry Hastings68386bc2012-06-24 14:30:41 -0700720uname_result = collections.namedtuple("uname_result",
721 "system node release version machine processor")
722
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000723_uname_cache = None
724
725def uname():
726
727 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100728 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000729 identifying the underlying platform.
730
731 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000732 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000733
734 Entries which cannot be determined are set to ''.
735
736 """
737 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000738 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000739
740 if _uname_cache is not None:
741 return _uname_cache
742
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000743 processor = ''
744
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000745 # Get some infos from the builtin os.uname API...
746 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100747 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000748 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000749 no_os_uname = 1
750
Georg Brandl62e2ca22010-07-31 21:54:24 +0000751 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000752 # Hmm, no there is either no uname or uname has returned
753 #'unknowns'... we'll have to poke around the system then.
754 if no_os_uname:
755 system = sys.platform
756 release = ''
757 version = ''
758 node = _node()
759 machine = ''
760
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000761 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000762
763 # Try win32_ver() on win32 platforms
764 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100765 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000766 if release and version:
767 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000768 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000769 # available on Win XP and later; see
770 # http://support.microsoft.com/kb/888731 and
771 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000772 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000773 # WOW64 processes mask the native architecture
774 if "PROCESSOR_ARCHITEW6432" in os.environ:
775 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
776 else:
777 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000778 if not processor:
779 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000780
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000781 # Try the 'ver' system command available on some
782 # platforms
783 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100784 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000785 # Normalize system to what win32_ver() normally returns
786 # (_syscmd_ver() tends to return the vendor name as well)
787 if system == 'Microsoft Windows':
788 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000789 elif system == 'Microsoft' and release == 'Windows':
790 # Under Windows Vista and Windows Server 2008,
791 # Microsoft changed the output of the ver command. The
792 # release is no longer printed. This causes the
793 # system and release to be misidentified.
794 system = 'Windows'
795 if '6.0' == version[:3]:
796 release = 'Vista'
797 else:
798 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000799
800 # In case we still don't know anything useful, we'll try to
801 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100802 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000803 if not version:
804 if system == 'win32':
805 version = '32bit'
806 else:
807 version = '16bit'
808 system = 'Windows'
809
810 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100811 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000812 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000813 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000814 if not version:
815 version = vendor
816
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000817 # System specific extensions
818 if system == 'OpenVMS':
819 # OpenVMS seems to have release and version mixed up
820 if not release or release == '0':
821 release = version
822 version = ''
823 # Get processor information
824 try:
825 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400826 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000827 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000828 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100829 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000830 if (cpu_number >= 128):
831 processor = 'Alpha'
832 else:
833 processor = 'VAX'
834 if not processor:
835 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +0100836 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000837
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000838 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000839 if system == 'unknown':
840 system = ''
841 if node == 'unknown':
842 node = ''
843 if release == 'unknown':
844 release = ''
845 if version == 'unknown':
846 version = ''
847 if machine == 'unknown':
848 machine = ''
849 if processor == 'unknown':
850 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000851
852 # normalize name
853 if system == 'Microsoft' and release == 'Windows':
854 system = 'Windows'
855 release = 'Vista'
856
Victor Stinnerced39362013-12-09 00:14:52 +0100857 _uname_cache = uname_result(system, node, release, version,
858 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000859 return _uname_cache
860
861### Direct interfaces to some of the uname() return values
862
863def system():
864
865 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
866
867 An empty string is returned if the value cannot be determined.
868
869 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700870 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000871
872def node():
873
Brett Cannon8ab27df2003-08-05 03:52:04 +0000874 """ Returns the computer's network name (which may not be fully
875 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000876
877 An empty string is returned if the value cannot be determined.
878
879 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700880 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000881
882def release():
883
884 """ Returns the system's release, e.g. '2.2.0' or 'NT'
885
886 An empty string is returned if the value cannot be determined.
887
888 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700889 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000890
891def version():
892
893 """ Returns the system's release version, e.g. '#3 on degas'
894
895 An empty string is returned if the value cannot be determined.
896
897 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700898 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899
900def machine():
901
902 """ Returns the machine type, e.g. 'i386'
903
904 An empty string is returned if the value cannot be determined.
905
906 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700907 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000908
909def processor():
910
911 """ Returns the (true) processor name, e.g. 'amdk6'
912
913 An empty string is returned if the value cannot be
914 determined. Note that many platforms do not provide this
915 information or simply return the same value as for machine(),
916 e.g. NetBSD does this.
917
918 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700919 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000920
921### Various APIs for extracting information from sys.version
922
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000923_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +0000924 r'([\w.+]+)\s*' # "version<space>"
925 r'\(#?([^,]+)' # "(#buildno"
926 r'(?:,\s*([\w ]*)' # ", builddate"
927 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
928 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000929
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000930_ironpython_sys_version_parser = re.compile(
931 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400932 r'([\d\.]+)'
933 r'(?: \(([\d\.]+)\))?'
934 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000935
Ezio Melottif076f532013-10-21 03:03:32 +0300936# IronPython covering 2.6 and 2.7
937_ironpython26_sys_version_parser = re.compile(
938 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400939 r'\(IronPython\s*'
940 r'[\d.]+\s*'
941 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +0300942)
943
Benjamin Petersone549ead2009-03-28 21:42:05 +0000944_pypy_sys_version_parser = re.compile(
945 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400946 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
947 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +0000948
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000949_sys_version_cache = {}
950
951def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000952
953 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +0000954 (name, version, branch, revision, buildno, builddate, compiler)
955 referring to the Python implementation name, version, branch,
956 revision, build number, build date/time as string and the compiler
957 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958
959 Note that unlike the Python sys.version, the returned value
960 for the Python version will always include the patchlevel (it
961 defaults to '.0').
962
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000963 The function returns empty strings for tuple entries that
964 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000965
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000966 sys_version may be given to parse an alternative version
967 string, e.g. if the version was read from a different Python
968 interpreter.
969
970 """
971 # Get the Python version
972 if sys_version is None:
973 sys_version = sys.version
974
975 # Try the cache first
976 result = _sys_version_cache.get(sys_version, None)
977 if result is not None:
978 return result
979
980 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +0300981 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000982 # IronPython
983 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +0300984 if sys_version.startswith('IronPython'):
985 match = _ironpython_sys_version_parser.match(sys_version)
986 else:
987 match = _ironpython26_sys_version_parser.match(sys_version)
988
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000989 if match is None:
990 raise ValueError(
991 'failed to parse IronPython sys.version: %s' %
992 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +0300993
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000994 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000995 buildno = ''
996 builddate = ''
997
Ezio Melottif076f532013-10-21 03:03:32 +0300998 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000999 # Jython
1000 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001001 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001002 if match is None:
1003 raise ValueError(
1004 'failed to parse Jython sys.version: %s' %
1005 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001006 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001007 if builddate is None:
1008 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001009 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001010
1011 elif "PyPy" in sys_version:
1012 # PyPy
1013 name = "PyPy"
1014 match = _pypy_sys_version_parser.match(sys_version)
1015 if match is None:
1016 raise ValueError("failed to parse PyPy sys.version: %s" %
1017 repr(sys_version))
1018 version, buildno, builddate, buildtime = match.groups()
1019 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001020
1021 else:
1022 # CPython
1023 match = _sys_version_parser.match(sys_version)
1024 if match is None:
1025 raise ValueError(
1026 'failed to parse CPython sys.version: %s' %
1027 repr(sys_version))
1028 version, buildno, builddate, buildtime, compiler = \
1029 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001030 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001031 if builddate is None:
1032 builddate = ''
1033 elif buildtime:
1034 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001035
Ned Deily5c4b0d02017-03-04 00:19:55 -05001036 if hasattr(sys, '_git'):
1037 _, branch, revision = sys._git
1038 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001039 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001040 else:
1041 branch = ''
1042 revision = ''
1043
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001044 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001045 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001046 if len(l) == 2:
1047 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001048 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001049
1050 # Build and cache the result
1051 result = (name, version, branch, revision, buildno, builddate, compiler)
1052 _sys_version_cache[sys_version] = result
1053 return result
1054
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001055def python_implementation():
1056
1057 """ Returns a string identifying the Python implementation.
1058
1059 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001060 'CPython' (C implementation of Python),
1061 'IronPython' (.NET implementation of Python),
1062 'Jython' (Java implementation of Python),
1063 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001064
1065 """
1066 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067
1068def python_version():
1069
1070 """ Returns the Python version as string 'major.minor.patchlevel'
1071
1072 Note that unlike the Python sys.version, the returned value
1073 will always include the patchlevel (it defaults to 0).
1074
1075 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001076 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001077
1078def python_version_tuple():
1079
1080 """ Returns the Python version as tuple (major, minor, patchlevel)
1081 of strings.
1082
1083 Note that unlike the Python sys.version, the returned value
1084 will always include the patchlevel (it defaults to 0).
1085
1086 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001087 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001088
1089def python_branch():
1090
1091 """ Returns a string identifying the Python implementation
1092 branch.
1093
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001094 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001095 Python binary was built.
1096
1097 If not available, an empty string is returned.
1098
1099 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001100
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001101 return _sys_version()[2]
1102
1103def python_revision():
1104
1105 """ Returns a string identifying the Python implementation
1106 revision.
1107
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001108 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001109 Python binary was built.
1110
1111 If not available, an empty string is returned.
1112
1113 """
1114 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001115
1116def python_build():
1117
1118 """ Returns a tuple (buildno, builddate) stating the Python
1119 build number and date as strings.
1120
1121 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001122 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001123
1124def python_compiler():
1125
1126 """ Returns a string identifying the compiler used for compiling
1127 Python.
1128
1129 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001130 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001131
1132### The Opus Magnum of platform strings :-)
1133
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001134_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001135
1136def platform(aliased=0, terse=0):
1137
1138 """ Returns a single string identifying the underlying platform
1139 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001140
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001141 The output is intended to be human readable rather than
1142 machine parseable. It may look different on different
1143 platforms and this is intended.
1144
1145 If "aliased" is true, the function will use aliases for
1146 various platforms that report system names which differ from
1147 their common names, e.g. SunOS will be reported as
1148 Solaris. The system_alias() function is used to implement
1149 this.
1150
1151 Setting terse to true causes the function to return only the
1152 absolute minimum information needed to identify the platform.
1153
1154 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001155 result = _platform_cache.get((aliased, terse), None)
1156 if result is not None:
1157 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001158
1159 # Get uname information and then apply platform specific cosmetics
1160 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001161 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001162 if machine == processor:
1163 processor = ''
1164 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001165 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001166
Victor Stinnerea0ca212018-12-05 22:41:52 +01001167 if system == 'Darwin':
1168 # macOS (darwin kernel)
1169 macos_release = mac_ver()[0]
1170 if macos_release:
Victor Stinnerea0ca212018-12-05 22:41:52 +01001171 system = 'macOS'
1172 release = macos_release
1173
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001174 if system == 'Windows':
1175 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001176 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001178 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001179 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001180 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001181
1182 elif system in ('Linux',):
Petr Viktorin8b94b412018-05-16 11:51:18 -04001183 # check for libc vs. glibc
1184 libcname, libcversion = libc_ver(sys.executable)
1185 platform = _platform(system, release, machine, processor,
1186 'with',
1187 libcname+libcversion)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001188 elif system == 'Java':
1189 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001190 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001191 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001192 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001193 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001194 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001195 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001196 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001197
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001198 else:
1199 # Generic handler
1200 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001201 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001202 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001203 bits, linkage = architecture(sys.executable)
1204 platform = _platform(system, release, machine,
1205 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001206
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001207 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001208 return platform
1209
1210### Command line interface
1211
1212if __name__ == '__main__':
1213 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001214 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001215 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001216 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001217 sys.exit(0)