blob: f089a463ef9fe1430d083f7e798441e14c55e945 [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
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100128 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
Serhiy Storchaka7d81e8f2018-08-27 13:29:51 +0300135# Helper for comparing two version number strings.
136# Based on the description of the PHP's version_compare():
137# http://php.net/manual/en/function.version-compare.php
138
139_ver_stages = {
140 # any string not found in this dict, will get 0 assigned
141 'dev': 10,
142 'alpha': 20, 'a': 20,
143 'beta': 30, 'b': 30,
144 'c': 40,
145 'RC': 50, 'rc': 50,
146 # number, will get 100 assigned
147 'pl': 200, 'p': 200,
148}
149
150_component_re = re.compile(r'([0-9]+|[._+-])')
151
152def _comparable_version(version):
153 result = []
154 for v in _component_re.split(version):
155 if v not in '._+-':
156 try:
157 v = int(v, 10)
158 t = 100
159 except ValueError:
160 t = _ver_stages.get(v, 0)
161 result.extend((t, v))
162 return result
163
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000164### Platform specific APIs
165
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200166_libc_search = re.compile(b'(__libc_init)'
167 b'|'
168 b'(GLIBC_([0-9.]+))'
169 b'|'
170 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000171
Victor Stinner476b1132018-12-05 14:04:52 +0100172def libc_ver(executable=None, lib='', version='', chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000173
Brett Cannon8ab27df2003-08-05 03:52:04 +0000174 """ Tries to determine the libc version that the file executable
175 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000176
177 Returns a tuple of strings (lib,version) which default to the
178 given parameters in case the lookup fails.
179
180 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000181 libc versions add symbols to the executable and thus is probably
182 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000183
184 The file is read and scanned in chunks of chunksize bytes.
185
186 """
Victor Stinner476b1132018-12-05 14:04:52 +0100187 if executable is None:
188 try:
189 ver = os.confstr('CS_GNU_LIBC_VERSION')
190 # parse 'glibc 2.28' as ('glibc', '2.28')
191 parts = ver.split(maxsplit=1)
192 if len(parts) == 2:
193 return tuple(parts)
194 except (AttributeError, ValueError, OSError):
195 # os.confstr() or CS_GNU_LIBC_VERSION value not available
196 pass
197
198 executable = sys.executable
199
Serhiy Storchaka7d81e8f2018-08-27 13:29:51 +0300200 V = _comparable_version
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000201 if hasattr(os.path, 'realpath'):
202 # Python 2.2 introduced os.path.realpath(); it is used
203 # here to work around problems with Cygwin not being
204 # able to open symlinks for reading
205 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300206 with open(executable, 'rb') as f:
207 binary = f.read(chunksize)
208 pos = 0
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300209 while pos < len(binary):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300210 if b'libc' in binary or b'GLIBC' in binary:
211 m = _libc_search.search(binary, pos)
212 else:
213 m = None
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300214 if not m or m.end() == len(binary):
215 chunk = f.read(chunksize)
216 if chunk:
217 binary = binary[max(pos, len(binary) - 1000):] + chunk
218 pos = 0
219 continue
220 if not m:
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300221 break
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300222 libcinit, glibc, glibcversion, so, threads, soversion = [
223 s.decode('latin1') if s is not None else s
224 for s in m.groups()]
225 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000226 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300227 elif glibc:
228 if lib != 'glibc':
229 lib = 'glibc'
230 version = glibcversion
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300231 elif V(glibcversion) > V(version):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300232 version = glibcversion
233 elif so:
234 if lib != 'glibc':
235 lib = 'libc'
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300236 if soversion and (not version or V(soversion) > V(version)):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300237 version = soversion
238 if threads and version[-len(threads):] != threads:
239 version = version + threads
240 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100241 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000242
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000243def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000244
Brett Cannon8ab27df2003-08-05 03:52:04 +0000245 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000246 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000247 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000248 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000249 if build:
250 l.append(build)
251 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100252 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000253 except ValueError:
254 strings = l
255 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100256 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000257 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000258 return version
259
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000260_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
R David Murray44b548d2016-09-08 13:59:53 -0400261 r'.*'
262 r'\[.* ([\d.]+)\])')
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000263
264# Examples of VER command output:
265#
266# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
267# Windows XP: Microsoft Windows XP [Version 5.1.2600]
268# Windows Vista: Microsoft Windows [Version 6.0.6002]
269#
270# Note that the "Version" string gets localized on different
271# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000272
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000273def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000274
Victor Stinnerced39362013-12-09 00:14:52 +0100275 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000276
277 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100278 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000279
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000280 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200281 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000282
283 In case this fails, the given parameters are used as
284 defaults.
285
286 """
287 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100288 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000289
290 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100291 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000292 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700293 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000294 info = pipe.read()
295 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200296 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200297 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000298 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200299 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100300 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000301 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000302 else:
303 break
304 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100305 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000306
307 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000308 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000309 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000310 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100311 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000312 # Strip trailing dots from version and release
313 if release[-1] == '.':
314 release = release[:-1]
315 if version[-1] == '.':
316 version = version[:-1]
317 # Normalize the version and build strings (eliminating additional
318 # zeros)
319 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100320 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000321
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700322_WIN32_CLIENT_RELEASES = {
323 (5, 0): "2000",
324 (5, 1): "XP",
325 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
326 # has always called it 2003 Server
327 (5, 2): "2003Server",
328 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000329
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700330 (6, 0): "Vista",
331 (6, 1): "7",
332 (6, 2): "8",
333 (6, 3): "8.1",
334 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000335
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700336 (10, 0): "10",
337 (10, None): "post10",
338}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000339
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700340# Server release name lookup will default to client names if necessary
341_WIN32_SERVER_RELEASES = {
342 (5, 2): "2003Server",
343
344 (6, 0): "2008Server",
345 (6, 1): "2008ServerR2",
346 (6, 2): "2012Server",
347 (6, 3): "2012ServerR2",
348 (6, None): "post2012ServerR2",
349}
350
Victor Stinnerced39362013-12-09 00:14:52 +0100351def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700352 try:
353 from sys import getwindowsversion
354 except ImportError:
355 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000356 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700357 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400358 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700359 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
360
361 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700362 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700363 version = '{0}.{1}.{2}'.format(maj, min, build)
364
365 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
366 _WIN32_CLIENT_RELEASES.get((maj, None)) or
367 release)
368
369 # getwindowsversion() reflect the compatibility mode Python is
370 # running under, and so the service pack value is only going to be
371 # valid if the versions match.
372 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000373 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700374 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000375 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700376 if csd[:13] == 'Service Pack ':
377 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000378
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700379 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700380 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700381 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
382 _WIN32_SERVER_RELEASES.get((maj, None)) or
383 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000384
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700385 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000386 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700387 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
388 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
389 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000390 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700391 pass
392 finally:
393 if key:
394 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000395
Victor Stinnerced39362013-12-09 00:14:52 +0100396 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000397
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700398
Ronald Oussorene186e382010-07-23 11:54:59 +0000399def _mac_ver_xml():
400 fn = '/System/Library/CoreServices/SystemVersion.plist'
401 if not os.path.exists(fn):
402 return None
403
404 try:
405 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400406 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000407 return None
408
Ned Deily936dfae2014-01-13 11:34:19 -0800409 with open(fn, 'rb') as f:
410 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000411 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100412 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700413 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000414 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300415 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000416 machine = 'PowerPC'
417
Victor Stinnerced39362013-12-09 00:14:52 +0100418 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000419
420
Victor Stinnerced39362013-12-09 00:14:52 +0100421def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000422
423 """ Get MacOS version information and return it as tuple (release,
424 versioninfo, machine) with versioninfo being a tuple (version,
425 dev_stage, non_release_version).
426
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300427 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000428 which default to ''. All tuple entries are strings.
429 """
430
431 # First try reading the information from an XML file which should
432 # always be present
433 info = _mac_ver_xml()
434 if info is not None:
435 return info
436
Ronald Oussorene186e382010-07-23 11:54:59 +0000437 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100438 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000439
Victor Stinnerced39362013-12-09 00:14:52 +0100440def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441
442 from java.lang import System
443 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000444 value = System.getProperty(name)
445 if value is None:
446 return default
447 return value
448 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000449 return default
450
Victor Stinnerced39362013-12-09 00:14:52 +0100451def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000452
Brett Cannon8ab27df2003-08-05 03:52:04 +0000453 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454
Victor Stinnerced39362013-12-09 00:14:52 +0100455 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
456 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
457 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458
459 Values which cannot be determined are set to the defaults
460 given as parameters (which all default to '').
461
462 """
463 # Import the needed APIs
464 try:
465 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400466 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100467 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000468
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000469 vendor = _java_getprop('java.vendor', vendor)
470 release = _java_getprop('java.version', release)
471 vm_name, vm_release, vm_vendor = vminfo
472 vm_name = _java_getprop('java.vm.name', vm_name)
473 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
474 vm_release = _java_getprop('java.vm.version', vm_release)
475 vminfo = vm_name, vm_release, vm_vendor
476 os_name, os_version, os_arch = osinfo
477 os_arch = _java_getprop('java.os.arch', os_arch)
478 os_name = _java_getprop('java.os.name', os_name)
479 os_version = _java_getprop('java.os.version', os_version)
480 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000481
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000482 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000483
484### System name aliasing
485
Victor Stinnerced39362013-12-09 00:14:52 +0100486def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000487
Victor Stinnerced39362013-12-09 00:14:52 +0100488 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000489 marketing names used for some systems.
490
491 It also does some reordering of the information in some cases
492 where it would otherwise cause confusion.
493
494 """
495 if system == 'Rhapsody':
496 # Apple's BSD derivative
497 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100498 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000499
500 elif system == 'SunOS':
501 # Sun's OS
502 if release < '5':
503 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100504 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000505 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000506 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000507 if l:
508 try:
509 major = int(l[0])
510 except ValueError:
511 pass
512 else:
513 major = major - 3
514 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000515 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000516 if release < '6':
517 system = 'Solaris'
518 else:
519 # XXX Whatever the new SunOS marketing name is...
520 system = 'Solaris'
521
522 elif system == 'IRIX64':
523 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
524 # is really a version and not a different platform, since 32-bit
525 # apps are also supported..
526 system = 'IRIX'
527 if version:
528 version = version + ' (64bit)'
529 else:
530 version = '64bit'
531
Victor Stinnerced39362013-12-09 00:14:52 +0100532 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000533 # In case one of the other tricks
534 system = 'Windows'
535
Victor Stinnerced39362013-12-09 00:14:52 +0100536 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000537
538### Various internal helpers
539
540def _platform(*args):
541
542 """ Helper to format the platform string in a filename
543 compatible format e.g. "system-version-machine".
544 """
545 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000546 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000547
548 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100549 platform = platform.replace(' ', '_')
550 platform = platform.replace('/', '-')
551 platform = platform.replace('\\', '-')
552 platform = platform.replace(':', '-')
553 platform = platform.replace(';', '-')
554 platform = platform.replace('"', '-')
555 platform = platform.replace('(', '-')
556 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000557
558 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100559 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000560
561 # Fold '--'s and remove trailing '-'
562 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100563 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000564 if cleaned == platform:
565 break
566 platform = cleaned
567 while platform[-1] == '-':
568 platform = platform[:-1]
569
570 return platform
571
572def _node(default=''):
573
574 """ Helper to determine the node name of this machine.
575 """
576 try:
577 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400578 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000579 # No sockets...
580 return default
581 try:
582 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200583 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000584 # Still not working...
585 return default
586
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000587def _follow_symlinks(filepath):
588
589 """ In case filepath is a symlink, follow it until a
590 real file is reached.
591 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000592 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000593 while os.path.islink(filepath):
594 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100595 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000596 return filepath
597
Victor Stinnerced39362013-12-09 00:14:52 +0100598def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000599
600 """ Interface to the system's uname command.
601 """
Victor Stinnerced39362013-12-09 00:14:52 +0100602 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000603 # XXX Others too ?
604 return default
605 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000606 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200607 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000608 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000609 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000610 rc = f.close()
611 if not output or rc:
612 return default
613 else:
614 return output
615
Victor Stinnerced39362013-12-09 00:14:52 +0100616def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000617
618 """ Interface to the system's file command.
619
620 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000621 omit the filename in its output. Follow the symlinks. It returns
622 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000623
624 """
Victor Stinnerced39362013-12-09 00:14:52 +0100625 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000626 # XXX Others too ?
627 return default
Victor Stinnerb8e689a2018-12-04 17:18:12 +0100628
629 import subprocess
Jesus Ceafc990e92012-10-04 13:51:43 +0200630 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000631 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200632 proc = subprocess.Popen(['file', target],
Victor Stinnerb8e689a2018-12-04 17:18:12 +0100633 stdout=subprocess.PIPE,
634 stderr=subprocess.STDOUT)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200635 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200637 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200638 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000639 if not output or rc:
640 return default
641 else:
642 return output
643
644### Information about the used architecture
645
646# Default values for architecture; non-empty strings override the
647# defaults given as parameters
648_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100649 'win32': ('', 'WindowsPE'),
650 'win16': ('', 'Windows'),
651 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652}
653
Victor Stinnerced39362013-12-09 00:14:52 +0100654def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000655
656 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000657 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000658
Victor Stinnerced39362013-12-09 00:14:52 +0100659 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000660 the bit architecture and the linkage format used for the
661 executable. Both values are returned as strings.
662
663 Values that cannot be determined are returned as given by the
664 parameter presets. If bits is given as '', the sizeof(pointer)
665 (or sizeof(long) on Python version < 1.5.2) is used as
666 indicator for the supported pointer size.
667
668 The function relies on the system's "file" command to do the
669 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000670 platforms. On some non-Unix platforms where the "file" command
671 does not exist and the executable is set to the Python interpreter
672 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000673
674 """
675 # Use the sizeof(pointer) as default number of bits if nothing
676 # else is given as default.
677 if not bits:
678 import struct
679 try:
680 size = struct.calcsize('P')
681 except struct.error:
682 # Older installations can only query longs
683 size = struct.calcsize('l')
684 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000685
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000687 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000688 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000689 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000690 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000691
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000692 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000693 executable == sys.executable:
694 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000695 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000696 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100697 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698 if b:
699 bits = b
700 if l:
701 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100702 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000703
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000704 if 'executable' not in fileout:
705 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100706 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000707
708 # Bits
709 if '32-bit' in fileout:
710 bits = '32bit'
711 elif 'N32' in fileout:
712 # On Irix only
713 bits = 'n32bit'
714 elif '64-bit' in fileout:
715 bits = '64bit'
716
717 # Linkage
718 if 'ELF' in fileout:
719 linkage = 'ELF'
720 elif 'PE' in fileout:
721 # E.g. Windows uses this format
722 if 'Windows' in fileout:
723 linkage = 'WindowsPE'
724 else:
725 linkage = 'PE'
726 elif 'COFF' in fileout:
727 linkage = 'COFF'
728 elif 'MS-DOS' in fileout:
729 linkage = 'MSDOS'
730 else:
731 # XXX the A.OUT format also falls under this class...
732 pass
733
Victor Stinnerced39362013-12-09 00:14:52 +0100734 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000735
736### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000737
Larry Hastings68386bc2012-06-24 14:30:41 -0700738uname_result = collections.namedtuple("uname_result",
739 "system node release version machine processor")
740
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000741_uname_cache = None
742
743def uname():
744
745 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100746 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000747 identifying the underlying platform.
748
749 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000750 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000751
752 Entries which cannot be determined are set to ''.
753
754 """
755 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000756 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000757
758 if _uname_cache is not None:
759 return _uname_cache
760
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000761 processor = ''
762
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000763 # Get some infos from the builtin os.uname API...
764 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100765 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000766 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000767 no_os_uname = 1
768
Georg Brandl62e2ca22010-07-31 21:54:24 +0000769 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000770 # Hmm, no there is either no uname or uname has returned
771 #'unknowns'... we'll have to poke around the system then.
772 if no_os_uname:
773 system = sys.platform
774 release = ''
775 version = ''
776 node = _node()
777 machine = ''
778
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000779 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000780
781 # Try win32_ver() on win32 platforms
782 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100783 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000784 if release and version:
785 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000786 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000787 # available on Win XP and later; see
788 # http://support.microsoft.com/kb/888731 and
789 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000790 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000791 # WOW64 processes mask the native architecture
792 if "PROCESSOR_ARCHITEW6432" in os.environ:
793 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
794 else:
795 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000796 if not processor:
797 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000798
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000799 # Try the 'ver' system command available on some
800 # platforms
801 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100802 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000803 # Normalize system to what win32_ver() normally returns
804 # (_syscmd_ver() tends to return the vendor name as well)
805 if system == 'Microsoft Windows':
806 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000807 elif system == 'Microsoft' and release == 'Windows':
808 # Under Windows Vista and Windows Server 2008,
809 # Microsoft changed the output of the ver command. The
810 # release is no longer printed. This causes the
811 # system and release to be misidentified.
812 system = 'Windows'
813 if '6.0' == version[:3]:
814 release = 'Vista'
815 else:
816 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000817
818 # In case we still don't know anything useful, we'll try to
819 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100820 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821 if not version:
822 if system == 'win32':
823 version = '32bit'
824 else:
825 version = '16bit'
826 system = 'Windows'
827
828 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100829 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000830 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000831 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000832 if not version:
833 version = vendor
834
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000835 # System specific extensions
836 if system == 'OpenVMS':
837 # OpenVMS seems to have release and version mixed up
838 if not release or release == '0':
839 release = version
840 version = ''
841 # Get processor information
842 try:
843 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400844 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000845 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000846 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100847 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000848 if (cpu_number >= 128):
849 processor = 'Alpha'
850 else:
851 processor = 'VAX'
852 if not processor:
853 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +0100854 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000855
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000856 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000857 if system == 'unknown':
858 system = ''
859 if node == 'unknown':
860 node = ''
861 if release == 'unknown':
862 release = ''
863 if version == 'unknown':
864 version = ''
865 if machine == 'unknown':
866 machine = ''
867 if processor == 'unknown':
868 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000869
870 # normalize name
871 if system == 'Microsoft' and release == 'Windows':
872 system = 'Windows'
873 release = 'Vista'
874
Victor Stinnerced39362013-12-09 00:14:52 +0100875 _uname_cache = uname_result(system, node, release, version,
876 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000877 return _uname_cache
878
879### Direct interfaces to some of the uname() return values
880
881def system():
882
883 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
884
885 An empty string is returned if the value cannot be determined.
886
887 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700888 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000889
890def node():
891
Brett Cannon8ab27df2003-08-05 03:52:04 +0000892 """ Returns the computer's network name (which may not be fully
893 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000894
895 An empty string is returned if the value cannot be determined.
896
897 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700898 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899
900def release():
901
902 """ Returns the system's release, e.g. '2.2.0' or 'NT'
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().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000908
909def version():
910
911 """ Returns the system's release version, e.g. '#3 on degas'
912
913 An empty string is returned if the value cannot be determined.
914
915 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700916 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000917
918def machine():
919
920 """ Returns the machine type, e.g. 'i386'
921
922 An empty string is returned if the value cannot be determined.
923
924 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700925 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000926
927def processor():
928
929 """ Returns the (true) processor name, e.g. 'amdk6'
930
931 An empty string is returned if the value cannot be
932 determined. Note that many platforms do not provide this
933 information or simply return the same value as for machine(),
934 e.g. NetBSD does this.
935
936 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700937 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000938
939### Various APIs for extracting information from sys.version
940
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000941_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +0000942 r'([\w.+]+)\s*' # "version<space>"
943 r'\(#?([^,]+)' # "(#buildno"
944 r'(?:,\s*([\w ]*)' # ", builddate"
945 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
946 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000947
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000948_ironpython_sys_version_parser = re.compile(
949 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400950 r'([\d\.]+)'
951 r'(?: \(([\d\.]+)\))?'
952 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000953
Ezio Melottif076f532013-10-21 03:03:32 +0300954# IronPython covering 2.6 and 2.7
955_ironpython26_sys_version_parser = re.compile(
956 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400957 r'\(IronPython\s*'
958 r'[\d.]+\s*'
959 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +0300960)
961
Benjamin Petersone549ead2009-03-28 21:42:05 +0000962_pypy_sys_version_parser = re.compile(
963 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400964 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
965 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +0000966
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000967_sys_version_cache = {}
968
969def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000970
971 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +0000972 (name, version, branch, revision, buildno, builddate, compiler)
973 referring to the Python implementation name, version, branch,
974 revision, build number, build date/time as string and the compiler
975 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000976
977 Note that unlike the Python sys.version, the returned value
978 for the Python version will always include the patchlevel (it
979 defaults to '.0').
980
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000981 The function returns empty strings for tuple entries that
982 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000983
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000984 sys_version may be given to parse an alternative version
985 string, e.g. if the version was read from a different Python
986 interpreter.
987
988 """
989 # Get the Python version
990 if sys_version is None:
991 sys_version = sys.version
992
993 # Try the cache first
994 result = _sys_version_cache.get(sys_version, None)
995 if result is not None:
996 return result
997
998 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +0300999 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001000 # IronPython
1001 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001002 if sys_version.startswith('IronPython'):
1003 match = _ironpython_sys_version_parser.match(sys_version)
1004 else:
1005 match = _ironpython26_sys_version_parser.match(sys_version)
1006
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001007 if match is None:
1008 raise ValueError(
1009 'failed to parse IronPython sys.version: %s' %
1010 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001011
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001012 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001013 buildno = ''
1014 builddate = ''
1015
Ezio Melottif076f532013-10-21 03:03:32 +03001016 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001017 # Jython
1018 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001019 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001020 if match is None:
1021 raise ValueError(
1022 'failed to parse Jython sys.version: %s' %
1023 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001024 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001025 if builddate is None:
1026 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001027 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001028
1029 elif "PyPy" in sys_version:
1030 # PyPy
1031 name = "PyPy"
1032 match = _pypy_sys_version_parser.match(sys_version)
1033 if match is None:
1034 raise ValueError("failed to parse PyPy sys.version: %s" %
1035 repr(sys_version))
1036 version, buildno, builddate, buildtime = match.groups()
1037 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001038
1039 else:
1040 # CPython
1041 match = _sys_version_parser.match(sys_version)
1042 if match is None:
1043 raise ValueError(
1044 'failed to parse CPython sys.version: %s' %
1045 repr(sys_version))
1046 version, buildno, builddate, buildtime, compiler = \
1047 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001048 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001049 if builddate is None:
1050 builddate = ''
1051 elif buildtime:
1052 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001053
Ned Deily5c4b0d02017-03-04 00:19:55 -05001054 if hasattr(sys, '_git'):
1055 _, branch, revision = sys._git
1056 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001057 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001058 else:
1059 branch = ''
1060 revision = ''
1061
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001062 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001063 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064 if len(l) == 2:
1065 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001066 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001067
1068 # Build and cache the result
1069 result = (name, version, branch, revision, buildno, builddate, compiler)
1070 _sys_version_cache[sys_version] = result
1071 return result
1072
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001073def python_implementation():
1074
1075 """ Returns a string identifying the Python implementation.
1076
1077 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001078 'CPython' (C implementation of Python),
1079 'IronPython' (.NET implementation of Python),
1080 'Jython' (Java implementation of Python),
1081 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001082
1083 """
1084 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001085
1086def python_version():
1087
1088 """ Returns the Python version as string 'major.minor.patchlevel'
1089
1090 Note that unlike the Python sys.version, the returned value
1091 will always include the patchlevel (it defaults to 0).
1092
1093 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001094 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001095
1096def python_version_tuple():
1097
1098 """ Returns the Python version as tuple (major, minor, patchlevel)
1099 of strings.
1100
1101 Note that unlike the Python sys.version, the returned value
1102 will always include the patchlevel (it defaults to 0).
1103
1104 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001105 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001106
1107def python_branch():
1108
1109 """ Returns a string identifying the Python implementation
1110 branch.
1111
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001112 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001113 Python binary was built.
1114
1115 If not available, an empty string is returned.
1116
1117 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001118
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001119 return _sys_version()[2]
1120
1121def python_revision():
1122
1123 """ Returns a string identifying the Python implementation
1124 revision.
1125
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001126 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001127 Python binary was built.
1128
1129 If not available, an empty string is returned.
1130
1131 """
1132 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001133
1134def python_build():
1135
1136 """ Returns a tuple (buildno, builddate) stating the Python
1137 build number and date as strings.
1138
1139 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001140 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001141
1142def python_compiler():
1143
1144 """ Returns a string identifying the compiler used for compiling
1145 Python.
1146
1147 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001148 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001149
1150### The Opus Magnum of platform strings :-)
1151
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001152_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001153
1154def platform(aliased=0, terse=0):
1155
1156 """ Returns a single string identifying the underlying platform
1157 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001158
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001159 The output is intended to be human readable rather than
1160 machine parseable. It may look different on different
1161 platforms and this is intended.
1162
1163 If "aliased" is true, the function will use aliases for
1164 various platforms that report system names which differ from
1165 their common names, e.g. SunOS will be reported as
1166 Solaris. The system_alias() function is used to implement
1167 this.
1168
1169 Setting terse to true causes the function to return only the
1170 absolute minimum information needed to identify the platform.
1171
1172 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001173 result = _platform_cache.get((aliased, terse), None)
1174 if result is not None:
1175 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001176
1177 # Get uname information and then apply platform specific cosmetics
1178 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001179 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001180 if machine == processor:
1181 processor = ''
1182 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001183 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001184
1185 if system == 'Windows':
1186 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001187 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001188 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001189 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001190 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001191 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001192
1193 elif system in ('Linux',):
Petr Viktorin8b94b412018-05-16 11:51:18 -04001194 # check for libc vs. glibc
1195 libcname, libcversion = libc_ver(sys.executable)
1196 platform = _platform(system, release, machine, processor,
1197 'with',
1198 libcname+libcversion)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001199 elif system == 'Java':
1200 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001201 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001202 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001203 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001204 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001205 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001206 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001207 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001208
1209 elif system == 'MacOS':
1210 # MacOS platforms
1211 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001212 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001213 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001214 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001215
1216 else:
1217 # Generic handler
1218 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001219 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001220 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001221 bits, linkage = architecture(sys.executable)
1222 platform = _platform(system, release, machine,
1223 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001224
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001225 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001226 return platform
1227
1228### Command line interface
1229
1230if __name__ == '__main__':
1231 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001232 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001233 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001234 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001235 sys.exit(0)