blob: 6fbb7b08c598e3d1782479ab492e4d8c964604ef [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()
penguindustin96466302019-05-06 14:57:17 -040075# 0.3.3 - fixed popen() and "file" command invocation bugs
Marc-André Lemburg246d8472003-04-24 11:36:11 +000076# 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
Paul Monson62dfd7d2019-04-25 11:36:45 -0700337def win32_is_iot():
338 return win32_edition() in ('IoTUAP', 'NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS')
339
340def win32_edition():
341 try:
342 try:
343 import winreg
344 except ImportError:
345 import _winreg as winreg
346 except ImportError:
347 pass
348 else:
349 try:
350 cvkey = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
351 with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, cvkey) as key:
352 return winreg.QueryValueEx(key, 'EditionId')[0]
353 except OSError:
354 pass
355
356 return None
357
Victor Stinnerced39362013-12-09 00:14:52 +0100358def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700359 try:
360 from sys import getwindowsversion
361 except ImportError:
362 return release, version, csd, ptype
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700363
364 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700365 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700366 version = '{0}.{1}.{2}'.format(maj, min, build)
367
368 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
369 _WIN32_CLIENT_RELEASES.get((maj, None)) or
370 release)
371
372 # getwindowsversion() reflect the compatibility mode Python is
373 # running under, and so the service pack value is only going to be
374 # valid if the versions match.
375 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000376 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700377 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000378 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700379 if csd[:13] == 'Service Pack ':
380 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000381
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700382 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700383 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700384 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
385 _WIN32_SERVER_RELEASES.get((maj, None)) or
386 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000387
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000388 try:
Steve Dowerd307d052019-04-22 11:40:12 -0700389 try:
390 import winreg
391 except ImportError:
392 import _winreg as winreg
393 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700394 pass
Steve Dowerd307d052019-04-22 11:40:12 -0700395 else:
396 try:
397 cvkey = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
398 with winreg.OpenKeyEx(HKEY_LOCAL_MACHINE, cvkey) as key:
399 ptype = QueryValueEx(key, 'CurrentType')[0]
400 except:
401 pass
Tim Peters0eadaac2003-04-24 16:02:54 +0000402
Victor Stinnerced39362013-12-09 00:14:52 +0100403 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000404
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700405
Ronald Oussorene186e382010-07-23 11:54:59 +0000406def _mac_ver_xml():
407 fn = '/System/Library/CoreServices/SystemVersion.plist'
408 if not os.path.exists(fn):
409 return None
410
411 try:
412 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400413 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000414 return None
415
Ned Deily936dfae2014-01-13 11:34:19 -0800416 with open(fn, 'rb') as f:
417 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000418 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100419 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700420 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000421 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300422 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000423 machine = 'PowerPC'
424
Victor Stinnerced39362013-12-09 00:14:52 +0100425 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000426
427
Victor Stinnerced39362013-12-09 00:14:52 +0100428def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000429
Victor Stinnerb0e08772018-12-12 17:48:08 +0100430 """ Get macOS version information and return it as tuple (release,
Ronald Oussorene186e382010-07-23 11:54:59 +0000431 versioninfo, machine) with versioninfo being a tuple (version,
432 dev_stage, non_release_version).
433
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300434 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000435 which default to ''. All tuple entries are strings.
436 """
437
438 # First try reading the information from an XML file which should
439 # always be present
440 info = _mac_ver_xml()
441 if info is not None:
442 return info
443
Ronald Oussorene186e382010-07-23 11:54:59 +0000444 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100445 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000446
Victor Stinnerced39362013-12-09 00:14:52 +0100447def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000448
449 from java.lang import System
450 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000451 value = System.getProperty(name)
452 if value is None:
453 return default
454 return value
455 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456 return default
457
Victor Stinnerced39362013-12-09 00:14:52 +0100458def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000459
Brett Cannon8ab27df2003-08-05 03:52:04 +0000460 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000461
Victor Stinnerced39362013-12-09 00:14:52 +0100462 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
463 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
464 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000465
466 Values which cannot be determined are set to the defaults
467 given as parameters (which all default to '').
468
469 """
470 # Import the needed APIs
471 try:
472 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400473 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100474 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000475
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000476 vendor = _java_getprop('java.vendor', vendor)
477 release = _java_getprop('java.version', release)
478 vm_name, vm_release, vm_vendor = vminfo
479 vm_name = _java_getprop('java.vm.name', vm_name)
480 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
481 vm_release = _java_getprop('java.vm.version', vm_release)
482 vminfo = vm_name, vm_release, vm_vendor
483 os_name, os_version, os_arch = osinfo
484 os_arch = _java_getprop('java.os.arch', os_arch)
485 os_name = _java_getprop('java.os.name', os_name)
486 os_version = _java_getprop('java.os.version', os_version)
487 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000488
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000489 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000490
491### System name aliasing
492
Victor Stinnerced39362013-12-09 00:14:52 +0100493def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000494
Victor Stinnerced39362013-12-09 00:14:52 +0100495 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000496 marketing names used for some systems.
497
498 It also does some reordering of the information in some cases
499 where it would otherwise cause confusion.
500
501 """
Victor Stinnerb0e08772018-12-12 17:48:08 +0100502 if system == 'SunOS':
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000503 # Sun's OS
504 if release < '5':
505 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100506 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000507 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000508 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000509 if l:
510 try:
511 major = int(l[0])
512 except ValueError:
513 pass
514 else:
515 major = major - 3
516 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000517 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000518 if release < '6':
519 system = 'Solaris'
520 else:
521 # XXX Whatever the new SunOS marketing name is...
522 system = 'Solaris'
523
524 elif system == 'IRIX64':
525 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
526 # is really a version and not a different platform, since 32-bit
527 # apps are also supported..
528 system = 'IRIX'
529 if version:
530 version = version + ' (64bit)'
531 else:
532 version = '64bit'
533
Victor Stinnerced39362013-12-09 00:14:52 +0100534 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000535 # In case one of the other tricks
536 system = 'Windows'
537
Victor Stinner60875db2018-12-18 19:51:35 +0100538 # bpo-35516: Don't replace Darwin with macOS since input release and
539 # version arguments can be different than the currently running version.
540
Victor Stinnerced39362013-12-09 00:14:52 +0100541 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000542
543### Various internal helpers
544
545def _platform(*args):
546
547 """ Helper to format the platform string in a filename
548 compatible format e.g. "system-version-machine".
549 """
550 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000551 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000552
553 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100554 platform = platform.replace(' ', '_')
555 platform = platform.replace('/', '-')
556 platform = platform.replace('\\', '-')
557 platform = platform.replace(':', '-')
558 platform = platform.replace(';', '-')
559 platform = platform.replace('"', '-')
560 platform = platform.replace('(', '-')
561 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000562
563 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100564 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000565
566 # Fold '--'s and remove trailing '-'
567 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100568 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000569 if cleaned == platform:
570 break
571 platform = cleaned
572 while platform[-1] == '-':
573 platform = platform[:-1]
574
575 return platform
576
577def _node(default=''):
578
579 """ Helper to determine the node name of this machine.
580 """
581 try:
582 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400583 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000584 # No sockets...
585 return default
586 try:
587 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200588 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000589 # Still not working...
590 return default
591
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000592def _follow_symlinks(filepath):
593
594 """ In case filepath is a symlink, follow it until a
595 real file is reached.
596 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000597 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000598 while os.path.islink(filepath):
599 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100600 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000601 return filepath
602
Victor Stinnerced39362013-12-09 00:14:52 +0100603def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000604
605 """ Interface to the system's uname command.
606 """
Victor Stinnerced39362013-12-09 00:14:52 +0100607 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000608 # XXX Others too ?
609 return default
Victor Stinner3a521f02018-12-07 11:10:33 +0100610
611 import subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000612 try:
Victor Stinner3a521f02018-12-07 11:10:33 +0100613 output = subprocess.check_output(('uname', option),
614 stderr=subprocess.DEVNULL,
615 text=True)
616 except (OSError, subprocess.CalledProcessError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000617 return default
Victor Stinner3a521f02018-12-07 11:10:33 +0100618 return (output.strip() or default)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000619
Victor Stinnerced39362013-12-09 00:14:52 +0100620def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000621
622 """ Interface to the system's file command.
623
624 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000625 omit the filename in its output. Follow the symlinks. It returns
626 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000627
628 """
Victor Stinnerced39362013-12-09 00:14:52 +0100629 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000630 # XXX Others too ?
631 return default
Victor Stinnerb8e689a2018-12-04 17:18:12 +0100632
633 import subprocess
Jesus Ceafc990e92012-10-04 13:51:43 +0200634 target = _follow_symlinks(target)
Victor Stinner0af9c332018-12-17 18:47:24 +0100635 # "file" output is locale dependent: force the usage of the C locale
636 # to get deterministic behavior.
637 env = dict(os.environ, LC_ALL='C')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638 try:
Victor Stinner0af9c332018-12-17 18:47:24 +0100639 # -b: do not prepend filenames to output lines (brief mode)
640 output = subprocess.check_output(['file', '-b', target],
Victor Stinner3a521f02018-12-07 11:10:33 +0100641 stderr=subprocess.DEVNULL,
Victor Stinner0af9c332018-12-17 18:47:24 +0100642 env=env)
Victor Stinner3a521f02018-12-07 11:10:33 +0100643 except (OSError, subprocess.CalledProcessError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000644 return default
Victor Stinner0af9c332018-12-17 18:47:24 +0100645 if not output:
646 return default
647 # With the C locale, the output should be mostly ASCII-compatible.
648 # Decode from Latin-1 to prevent Unicode decode error.
649 return output.decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650
651### Information about the used architecture
652
653# Default values for architecture; non-empty strings override the
654# defaults given as parameters
655_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100656 'win32': ('', 'WindowsPE'),
657 'win16': ('', 'Windows'),
658 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000659}
660
Victor Stinnerced39362013-12-09 00:14:52 +0100661def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000662
663 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000664 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665
Victor Stinnerced39362013-12-09 00:14:52 +0100666 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000667 the bit architecture and the linkage format used for the
668 executable. Both values are returned as strings.
669
670 Values that cannot be determined are returned as given by the
671 parameter presets. If bits is given as '', the sizeof(pointer)
672 (or sizeof(long) on Python version < 1.5.2) is used as
673 indicator for the supported pointer size.
674
675 The function relies on the system's "file" command to do the
676 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000677 platforms. On some non-Unix platforms where the "file" command
678 does not exist and the executable is set to the Python interpreter
679 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000680
681 """
682 # Use the sizeof(pointer) as default number of bits if nothing
683 # else is given as default.
684 if not bits:
685 import struct
Victor Stinner4aa917c2018-12-14 13:14:10 +0100686 size = struct.calcsize('P')
687 bits = str(size * 8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000688
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000689 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000690 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000691 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000692 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000693 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000694
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000695 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000696 executable == sys.executable:
697 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000698 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000699 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100700 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000701 if b:
702 bits = b
703 if l:
704 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100705 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000706
Victor Stinner0af9c332018-12-17 18:47:24 +0100707 if 'executable' not in fileout and 'shared object' not in fileout:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000708 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100709 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000710
711 # Bits
712 if '32-bit' in fileout:
713 bits = '32bit'
714 elif 'N32' in fileout:
715 # On Irix only
716 bits = 'n32bit'
717 elif '64-bit' in fileout:
718 bits = '64bit'
719
720 # Linkage
721 if 'ELF' in fileout:
722 linkage = 'ELF'
723 elif 'PE' in fileout:
724 # E.g. Windows uses this format
725 if 'Windows' in fileout:
726 linkage = 'WindowsPE'
727 else:
728 linkage = 'PE'
729 elif 'COFF' in fileout:
730 linkage = 'COFF'
731 elif 'MS-DOS' in fileout:
732 linkage = 'MSDOS'
733 else:
734 # XXX the A.OUT format also falls under this class...
735 pass
736
Victor Stinnerced39362013-12-09 00:14:52 +0100737 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000738
739### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000740
Larry Hastings68386bc2012-06-24 14:30:41 -0700741uname_result = collections.namedtuple("uname_result",
742 "system node release version machine processor")
743
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744_uname_cache = None
745
746def uname():
747
748 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100749 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000750 identifying the underlying platform.
751
752 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000753 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000754
755 Entries which cannot be determined are set to ''.
756
757 """
758 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000759 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000760
761 if _uname_cache is not None:
762 return _uname_cache
763
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000764 processor = ''
765
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000766 # Get some infos from the builtin os.uname API...
767 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100768 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000769 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000770 no_os_uname = 1
771
Georg Brandl62e2ca22010-07-31 21:54:24 +0000772 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000773 # Hmm, no there is either no uname or uname has returned
774 #'unknowns'... we'll have to poke around the system then.
775 if no_os_uname:
776 system = sys.platform
777 release = ''
778 version = ''
779 node = _node()
780 machine = ''
781
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000782 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000783
784 # Try win32_ver() on win32 platforms
785 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100786 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000787 if release and version:
788 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000789 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000790 # available on Win XP and later; see
791 # http://support.microsoft.com/kb/888731 and
792 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000793 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000794 # WOW64 processes mask the native architecture
795 if "PROCESSOR_ARCHITEW6432" in os.environ:
796 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
797 else:
798 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000799 if not processor:
800 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000801
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000802 # Try the 'ver' system command available on some
803 # platforms
804 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100805 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000806 # Normalize system to what win32_ver() normally returns
807 # (_syscmd_ver() tends to return the vendor name as well)
808 if system == 'Microsoft Windows':
809 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000810 elif system == 'Microsoft' and release == 'Windows':
811 # Under Windows Vista and Windows Server 2008,
812 # Microsoft changed the output of the ver command. The
813 # release is no longer printed. This causes the
814 # system and release to be misidentified.
815 system = 'Windows'
816 if '6.0' == version[:3]:
817 release = 'Vista'
818 else:
819 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000820
821 # In case we still don't know anything useful, we'll try to
822 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100823 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000824 if not version:
825 if system == 'win32':
826 version = '32bit'
827 else:
828 version = '16bit'
829 system = 'Windows'
830
831 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100832 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000833 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000834 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000835 if not version:
836 version = vendor
837
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000838 # System specific extensions
839 if system == 'OpenVMS':
840 # OpenVMS seems to have release and version mixed up
841 if not release or release == '0':
842 release = version
843 version = ''
844 # Get processor information
845 try:
846 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400847 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000848 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000849 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100850 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000851 if (cpu_number >= 128):
852 processor = 'Alpha'
853 else:
854 processor = 'VAX'
855 if not processor:
856 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +0100857 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000858
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000859 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000860 if system == 'unknown':
861 system = ''
862 if node == 'unknown':
863 node = ''
864 if release == 'unknown':
865 release = ''
866 if version == 'unknown':
867 version = ''
868 if machine == 'unknown':
869 machine = ''
870 if processor == 'unknown':
871 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000872
873 # normalize name
874 if system == 'Microsoft' and release == 'Windows':
875 system = 'Windows'
876 release = 'Vista'
877
Victor Stinnerced39362013-12-09 00:14:52 +0100878 _uname_cache = uname_result(system, node, release, version,
879 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000880 return _uname_cache
881
882### Direct interfaces to some of the uname() return values
883
884def system():
885
886 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
887
888 An empty string is returned if the value cannot be determined.
889
890 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700891 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000892
893def node():
894
Brett Cannon8ab27df2003-08-05 03:52:04 +0000895 """ Returns the computer's network name (which may not be fully
896 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000897
898 An empty string is returned if the value cannot be determined.
899
900 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700901 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000902
903def release():
904
905 """ Returns the system's release, e.g. '2.2.0' or 'NT'
906
907 An empty string is returned if the value cannot be determined.
908
909 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700910 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000911
912def version():
913
914 """ Returns the system's release version, e.g. '#3 on degas'
915
916 An empty string is returned if the value cannot be determined.
917
918 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700919 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000920
921def machine():
922
923 """ Returns the machine type, e.g. 'i386'
924
925 An empty string is returned if the value cannot be determined.
926
927 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700928 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000929
930def processor():
931
932 """ Returns the (true) processor name, e.g. 'amdk6'
933
934 An empty string is returned if the value cannot be
935 determined. Note that many platforms do not provide this
936 information or simply return the same value as for machine(),
937 e.g. NetBSD does this.
938
939 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700940 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000941
942### Various APIs for extracting information from sys.version
943
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000944_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +0000945 r'([\w.+]+)\s*' # "version<space>"
946 r'\(#?([^,]+)' # "(#buildno"
947 r'(?:,\s*([\w ]*)' # ", builddate"
948 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
949 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000950
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000951_ironpython_sys_version_parser = re.compile(
952 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400953 r'([\d\.]+)'
954 r'(?: \(([\d\.]+)\))?'
955 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000956
Ezio Melottif076f532013-10-21 03:03:32 +0300957# IronPython covering 2.6 and 2.7
958_ironpython26_sys_version_parser = re.compile(
959 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400960 r'\(IronPython\s*'
961 r'[\d.]+\s*'
962 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +0300963)
964
Benjamin Petersone549ead2009-03-28 21:42:05 +0000965_pypy_sys_version_parser = re.compile(
966 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400967 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
968 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +0000969
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000970_sys_version_cache = {}
971
972def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000973
974 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +0000975 (name, version, branch, revision, buildno, builddate, compiler)
976 referring to the Python implementation name, version, branch,
977 revision, build number, build date/time as string and the compiler
978 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000979
980 Note that unlike the Python sys.version, the returned value
981 for the Python version will always include the patchlevel (it
982 defaults to '.0').
983
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000984 The function returns empty strings for tuple entries that
985 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000986
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000987 sys_version may be given to parse an alternative version
988 string, e.g. if the version was read from a different Python
989 interpreter.
990
991 """
992 # Get the Python version
993 if sys_version is None:
994 sys_version = sys.version
995
996 # Try the cache first
997 result = _sys_version_cache.get(sys_version, None)
998 if result is not None:
999 return result
1000
1001 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001002 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001003 # IronPython
1004 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001005 if sys_version.startswith('IronPython'):
1006 match = _ironpython_sys_version_parser.match(sys_version)
1007 else:
1008 match = _ironpython26_sys_version_parser.match(sys_version)
1009
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001010 if match is None:
1011 raise ValueError(
1012 'failed to parse IronPython sys.version: %s' %
1013 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001014
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001015 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001016 buildno = ''
1017 builddate = ''
1018
Ezio Melottif076f532013-10-21 03:03:32 +03001019 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001020 # Jython
1021 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001022 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001023 if match is None:
1024 raise ValueError(
1025 'failed to parse Jython sys.version: %s' %
1026 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001027 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001028 if builddate is None:
1029 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001030 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001031
1032 elif "PyPy" in sys_version:
1033 # PyPy
1034 name = "PyPy"
1035 match = _pypy_sys_version_parser.match(sys_version)
1036 if match is None:
1037 raise ValueError("failed to parse PyPy sys.version: %s" %
1038 repr(sys_version))
1039 version, buildno, builddate, buildtime = match.groups()
1040 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001041
1042 else:
1043 # CPython
1044 match = _sys_version_parser.match(sys_version)
1045 if match is None:
1046 raise ValueError(
1047 'failed to parse CPython sys.version: %s' %
1048 repr(sys_version))
1049 version, buildno, builddate, buildtime, compiler = \
1050 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001051 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001052 if builddate is None:
1053 builddate = ''
1054 elif buildtime:
1055 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001056
Ned Deily5c4b0d02017-03-04 00:19:55 -05001057 if hasattr(sys, '_git'):
1058 _, branch, revision = sys._git
1059 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001060 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001061 else:
1062 branch = ''
1063 revision = ''
1064
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001065 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001066 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001067 if len(l) == 2:
1068 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001069 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001070
1071 # Build and cache the result
1072 result = (name, version, branch, revision, buildno, builddate, compiler)
1073 _sys_version_cache[sys_version] = result
1074 return result
1075
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001076def python_implementation():
1077
1078 """ Returns a string identifying the Python implementation.
1079
1080 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001081 'CPython' (C implementation of Python),
1082 'IronPython' (.NET implementation of Python),
1083 'Jython' (Java implementation of Python),
1084 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001085
1086 """
1087 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001088
1089def python_version():
1090
1091 """ Returns the Python version as string 'major.minor.patchlevel'
1092
1093 Note that unlike the Python sys.version, the returned value
1094 will always include the patchlevel (it defaults to 0).
1095
1096 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001097 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001098
1099def python_version_tuple():
1100
1101 """ Returns the Python version as tuple (major, minor, patchlevel)
1102 of strings.
1103
1104 Note that unlike the Python sys.version, the returned value
1105 will always include the patchlevel (it defaults to 0).
1106
1107 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001108 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001109
1110def python_branch():
1111
1112 """ Returns a string identifying the Python implementation
1113 branch.
1114
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001115 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001116 Python binary was built.
1117
1118 If not available, an empty string is returned.
1119
1120 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001121
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001122 return _sys_version()[2]
1123
1124def python_revision():
1125
1126 """ Returns a string identifying the Python implementation
1127 revision.
1128
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001129 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001130 Python binary was built.
1131
1132 If not available, an empty string is returned.
1133
1134 """
1135 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001136
1137def python_build():
1138
1139 """ Returns a tuple (buildno, builddate) stating the Python
1140 build number and date as strings.
1141
1142 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001143 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001144
1145def python_compiler():
1146
1147 """ Returns a string identifying the compiler used for compiling
1148 Python.
1149
1150 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001151 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001152
1153### The Opus Magnum of platform strings :-)
1154
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001155_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001156
1157def platform(aliased=0, terse=0):
1158
1159 """ Returns a single string identifying the underlying platform
1160 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001161
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001162 The output is intended to be human readable rather than
1163 machine parseable. It may look different on different
1164 platforms and this is intended.
1165
1166 If "aliased" is true, the function will use aliases for
1167 various platforms that report system names which differ from
1168 their common names, e.g. SunOS will be reported as
1169 Solaris. The system_alias() function is used to implement
1170 this.
1171
1172 Setting terse to true causes the function to return only the
1173 absolute minimum information needed to identify the platform.
1174
1175 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001176 result = _platform_cache.get((aliased, terse), None)
1177 if result is not None:
1178 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001179
1180 # Get uname information and then apply platform specific cosmetics
1181 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001182 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001183 if machine == processor:
1184 processor = ''
1185 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001186 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001187
Victor Stinnerea0ca212018-12-05 22:41:52 +01001188 if system == 'Darwin':
1189 # macOS (darwin kernel)
1190 macos_release = mac_ver()[0]
1191 if macos_release:
Victor Stinnerea0ca212018-12-05 22:41:52 +01001192 system = 'macOS'
1193 release = macos_release
1194
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001195 if system == 'Windows':
1196 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001197 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001198 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001199 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001200 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001201 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001202
1203 elif system in ('Linux',):
Petr Viktorin8b94b412018-05-16 11:51:18 -04001204 # check for libc vs. glibc
1205 libcname, libcversion = libc_ver(sys.executable)
1206 platform = _platform(system, release, machine, processor,
1207 'with',
1208 libcname+libcversion)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001209 elif system == 'Java':
1210 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001211 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001212 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001213 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001214 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001215 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001216 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001217 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001218
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001219 else:
1220 # Generic handler
1221 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001222 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001223 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001224 bits, linkage = architecture(sys.executable)
1225 platform = _platform(system, release, machine,
1226 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001227
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001228 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001229 return platform
1230
1231### Command line interface
1232
1233if __name__ == '__main__':
1234 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001235 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001236 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001237 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001238 sys.exit(0)