blob: 98ee06f85ef1579fe653acac55ef7c68b802975b [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Marc-André Lemburg246d8472003-04-24 11:36:11 +00002
Brett Cannon8ab27df2003-08-05 03:52:04 +00003""" This module tries to retrieve as much platform-identifying data as
Marc-André Lemburg246d8472003-04-24 11:36:11 +00004 possible. It makes this information available via function APIs.
5
6 If called from the command line, it prints the platform
7 information concatenated as single string to stdout. The output
8 format is useable as part of a filename.
9
10"""
11# This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
12# If you find problems, please submit bug reports/patches via the
Benjamin Peterson4ac9ce42009-10-04 14:49:41 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
Marc-André Lemburg246d8472003-04-24 11:36:11 +000015# Still needed:
Marc-André Lemburg246d8472003-04-24 11:36:11 +000016# * support for MS-DOS (PythonDX ?)
17# * support for Amiga and other still unsupported platforms running Python
18# * support for additional Linux distributions
19#
Brett Cannon8ab27df2003-08-05 03:52:04 +000020# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000021# checks (in no particular order):
22#
23# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
24# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
25# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
26# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
27# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Steve Dowerb9f4fea2015-09-22 17:23:39 -070028# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
29# Dower
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
Steve Dowerb9f4fea2015-09-22 17:23:39 -070035# 1.0.8 - changed Windows support to read version from kernel32.dll
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000036# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000037# 1.0.6 - added linux_distribution()
38# 1.0.5 - fixed Java support to allow running the module on Jython
39# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000040# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000041# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000042# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000043# 1.0.0 - reformatted a bit and checked into Python CVS
44# 0.8.0 - added sys.version parser and various new access
45# APIs (python_version(), python_compiler(), etc.)
46# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
47# 0.7.1 - added support for Caldera OpenLinux
48# 0.7.0 - some fixes for WinCE; untabified the source file
49# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
50# vms_lib.getsyi() configured
51# 0.6.1 - added code to prevent 'uname -p' on platforms which are
52# known not to support it
53# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
54# did some cleanup of the interfaces - some APIs have changed
55# 0.5.5 - fixed another type in the MacOS code... should have
56# used more coffee today ;-)
57# 0.5.4 - fixed a few typos in the MacOS code
58# 0.5.3 - added experimental MacOS support; added better popen()
59# workarounds in _syscmd_ver() -- still not 100% elegant
60# though
61# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
62# return values (the system uname command tends to return
Martin Pantereb995702016-07-28 01:11:04 +000063# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000064# 0.5.1 - included code for slackware dist; added exception handlers
65# to cover up situations where platforms don't have os.popen
66# (e.g. Mac) or fail on socket.gethostname(); fixed libc
67# detection RE
68# 0.5.0 - changed the API names referring to system commands to *syscmd*;
69# added java_ver(); made syscmd_ver() a private
70# API (was system_ver() in previous versions) -- use uname()
71# instead; extended the win32_ver() to also return processor
72# type information
73# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
74# 0.3.4 - fixed a bug in _follow_symlinks()
75# 0.3.3 - fixed popen() and "file" command invokation bugs
76# 0.3.2 - added architecture() API and support for it in platform()
77# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
78# 0.3.0 - added system alias support
79# 0.2.3 - removed 'wince' again... oh well.
80# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
81# 0.2.1 - added cache logic and changed the platform string format
82# 0.2.0 - changed the API to use functions instead of module globals
83# since some action take too long to be run on module import
84# 0.1.0 - first release
85#
86# You can always get the latest version of this module at:
87#
88# http://www.egenix.com/files/python/platform.py
89#
90# If that URL should fail, try contacting the author.
91
92__copyright__ = """
93 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Peterson46a99002010-01-09 18:45:30 +000094 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000095
96 Permission to use, copy, modify, and distribute this software and its
97 documentation for any purpose and without fee or royalty is hereby granted,
98 provided that the above copyright notice appear in all copies and that
99 both that copyright notice and this permission notice appear in
100 supporting documentation or portions thereof, including modifications,
101 that you make.
102
103 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
104 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
105 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
106 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
107 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
108 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
109 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
110
111"""
112
Matthias Bussonnier6059ce42017-02-24 02:47:34 -0800113__version__ = '1.0.8'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000114
Larry Hastings68386bc2012-06-24 14:30:41 -0700115import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200116import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000117
Berker Peksag1392f712015-05-16 20:24:28 +0300118import warnings
119
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000120### Globals & Constants
121
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100128 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
Serhiy Storchaka7d81e8f2018-08-27 13:29:51 +0300135# Helper for comparing two version number strings.
136# Based on the description of the PHP's version_compare():
137# http://php.net/manual/en/function.version-compare.php
138
139_ver_stages = {
140 # any string not found in this dict, will get 0 assigned
141 'dev': 10,
142 'alpha': 20, 'a': 20,
143 'beta': 30, 'b': 30,
144 'c': 40,
145 'RC': 50, 'rc': 50,
146 # number, will get 100 assigned
147 'pl': 200, 'p': 200,
148}
149
150_component_re = re.compile(r'([0-9]+|[._+-])')
151
152def _comparable_version(version):
153 result = []
154 for v in _component_re.split(version):
155 if v not in '._+-':
156 try:
157 v = int(v, 10)
158 t = 100
159 except ValueError:
160 t = _ver_stages.get(v, 0)
161 result.extend((t, v))
162 return result
163
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000164### Platform specific APIs
165
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200166_libc_search = re.compile(b'(__libc_init)'
167 b'|'
168 b'(GLIBC_([0-9.]+))'
169 b'|'
170 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000171
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300172def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000173
Brett Cannon8ab27df2003-08-05 03:52:04 +0000174 """ Tries to determine the libc version that the file executable
175 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000176
177 Returns a tuple of strings (lib,version) which default to the
178 given parameters in case the lookup fails.
179
180 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000181 libc versions add symbols to the executable and thus is probably
182 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000183
184 The file is read and scanned in chunks of chunksize bytes.
185
186 """
Serhiy Storchaka7d81e8f2018-08-27 13:29:51 +0300187 V = _comparable_version
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000188 if hasattr(os.path, 'realpath'):
189 # Python 2.2 introduced os.path.realpath(); it is used
190 # here to work around problems with Cygwin not being
191 # able to open symlinks for reading
192 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300193 with open(executable, 'rb') as f:
194 binary = f.read(chunksize)
195 pos = 0
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300196 while pos < len(binary):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300197 if b'libc' in binary or b'GLIBC' in binary:
198 m = _libc_search.search(binary, pos)
199 else:
200 m = None
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300201 if not m or m.end() == len(binary):
202 chunk = f.read(chunksize)
203 if chunk:
204 binary = binary[max(pos, len(binary) - 1000):] + chunk
205 pos = 0
206 continue
207 if not m:
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300208 break
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300209 libcinit, glibc, glibcversion, so, threads, soversion = [
210 s.decode('latin1') if s is not None else s
211 for s in m.groups()]
212 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000213 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300214 elif glibc:
215 if lib != 'glibc':
216 lib = 'glibc'
217 version = glibcversion
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300218 elif V(glibcversion) > V(version):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300219 version = glibcversion
220 elif so:
221 if lib != 'glibc':
222 lib = 'libc'
Serhiy Storchaka2a9b8ba2018-07-09 11:47:45 +0300223 if soversion and (not version or V(soversion) > V(version)):
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300224 version = soversion
225 if threads and version[-len(threads):] != threads:
226 version = version + threads
227 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100228 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000229
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 Stinnerced39362013-12-09 00:14:52 +0100278 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000279 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700280 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000281 info = pipe.read()
282 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200283 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200284 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000285 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200286 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100287 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000288 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000289 else:
290 break
291 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100292 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000293
294 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000295 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000296 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000297 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100298 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000299 # Strip trailing dots from version and release
300 if release[-1] == '.':
301 release = release[:-1]
302 if version[-1] == '.':
303 version = version[:-1]
304 # Normalize the version and build strings (eliminating additional
305 # zeros)
306 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100307 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000308
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700309_WIN32_CLIENT_RELEASES = {
310 (5, 0): "2000",
311 (5, 1): "XP",
312 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
313 # has always called it 2003 Server
314 (5, 2): "2003Server",
315 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000316
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700317 (6, 0): "Vista",
318 (6, 1): "7",
319 (6, 2): "8",
320 (6, 3): "8.1",
321 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000322
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700323 (10, 0): "10",
324 (10, None): "post10",
325}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000326
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700327# Server release name lookup will default to client names if necessary
328_WIN32_SERVER_RELEASES = {
329 (5, 2): "2003Server",
330
331 (6, 0): "2008Server",
332 (6, 1): "2008ServerR2",
333 (6, 2): "2012Server",
334 (6, 3): "2012ServerR2",
335 (6, None): "post2012ServerR2",
336}
337
Victor Stinnerced39362013-12-09 00:14:52 +0100338def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700339 try:
340 from sys import getwindowsversion
341 except ImportError:
342 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000343 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700344 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400345 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700346 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
347
348 winver = getwindowsversion()
Steve Dower74f4af72016-09-17 17:27:48 -0700349 maj, min, build = winver.platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700350 version = '{0}.{1}.{2}'.format(maj, min, build)
351
352 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
353 _WIN32_CLIENT_RELEASES.get((maj, None)) or
354 release)
355
356 # getwindowsversion() reflect the compatibility mode Python is
357 # running under, and so the service pack value is only going to be
358 # valid if the versions match.
359 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000360 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700361 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000362 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700363 if csd[:13] == 'Service Pack ':
364 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000365
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700366 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700367 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700368 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
369 _WIN32_SERVER_RELEASES.get((maj, None)) or
370 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000371
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700372 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000373 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700374 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
375 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
376 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000377 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700378 pass
379 finally:
380 if key:
381 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000382
Victor Stinnerced39362013-12-09 00:14:52 +0100383 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000384
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700385
Ronald Oussorene186e382010-07-23 11:54:59 +0000386def _mac_ver_xml():
387 fn = '/System/Library/CoreServices/SystemVersion.plist'
388 if not os.path.exists(fn):
389 return None
390
391 try:
392 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400393 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000394 return None
395
Ned Deily936dfae2014-01-13 11:34:19 -0800396 with open(fn, 'rb') as f:
397 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000398 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100399 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700400 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000401 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300402 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000403 machine = 'PowerPC'
404
Victor Stinnerced39362013-12-09 00:14:52 +0100405 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000406
407
Victor Stinnerced39362013-12-09 00:14:52 +0100408def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000409
410 """ Get MacOS version information and return it as tuple (release,
411 versioninfo, machine) with versioninfo being a tuple (version,
412 dev_stage, non_release_version).
413
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300414 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000415 which default to ''. All tuple entries are strings.
416 """
417
418 # First try reading the information from an XML file which should
419 # always be present
420 info = _mac_ver_xml()
421 if info is not None:
422 return info
423
Ronald Oussorene186e382010-07-23 11:54:59 +0000424 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100425 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000426
Victor Stinnerced39362013-12-09 00:14:52 +0100427def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000428
429 from java.lang import System
430 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000431 value = System.getProperty(name)
432 if value is None:
433 return default
434 return value
435 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000436 return default
437
Victor Stinnerced39362013-12-09 00:14:52 +0100438def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000439
Brett Cannon8ab27df2003-08-05 03:52:04 +0000440 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441
Victor Stinnerced39362013-12-09 00:14:52 +0100442 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
443 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
444 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000445
446 Values which cannot be determined are set to the defaults
447 given as parameters (which all default to '').
448
449 """
450 # Import the needed APIs
451 try:
452 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400453 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100454 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000455
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000456 vendor = _java_getprop('java.vendor', vendor)
457 release = _java_getprop('java.version', release)
458 vm_name, vm_release, vm_vendor = vminfo
459 vm_name = _java_getprop('java.vm.name', vm_name)
460 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
461 vm_release = _java_getprop('java.vm.version', vm_release)
462 vminfo = vm_name, vm_release, vm_vendor
463 os_name, os_version, os_arch = osinfo
464 os_arch = _java_getprop('java.os.arch', os_arch)
465 os_name = _java_getprop('java.os.name', os_name)
466 os_version = _java_getprop('java.os.version', os_version)
467 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000468
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000469 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000470
471### System name aliasing
472
Victor Stinnerced39362013-12-09 00:14:52 +0100473def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000474
Victor Stinnerced39362013-12-09 00:14:52 +0100475 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000476 marketing names used for some systems.
477
478 It also does some reordering of the information in some cases
479 where it would otherwise cause confusion.
480
481 """
482 if system == 'Rhapsody':
483 # Apple's BSD derivative
484 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100485 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000486
487 elif system == 'SunOS':
488 # Sun's OS
489 if release < '5':
490 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100491 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000492 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000493 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000494 if l:
495 try:
496 major = int(l[0])
497 except ValueError:
498 pass
499 else:
500 major = major - 3
501 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000502 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000503 if release < '6':
504 system = 'Solaris'
505 else:
506 # XXX Whatever the new SunOS marketing name is...
507 system = 'Solaris'
508
509 elif system == 'IRIX64':
510 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
511 # is really a version and not a different platform, since 32-bit
512 # apps are also supported..
513 system = 'IRIX'
514 if version:
515 version = version + ' (64bit)'
516 else:
517 version = '64bit'
518
Victor Stinnerced39362013-12-09 00:14:52 +0100519 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000520 # In case one of the other tricks
521 system = 'Windows'
522
Victor Stinnerced39362013-12-09 00:14:52 +0100523 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000524
525### Various internal helpers
526
527def _platform(*args):
528
529 """ Helper to format the platform string in a filename
530 compatible format e.g. "system-version-machine".
531 """
532 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000533 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000534
535 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100536 platform = platform.replace(' ', '_')
537 platform = platform.replace('/', '-')
538 platform = platform.replace('\\', '-')
539 platform = platform.replace(':', '-')
540 platform = platform.replace(';', '-')
541 platform = platform.replace('"', '-')
542 platform = platform.replace('(', '-')
543 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000544
545 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100546 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000547
548 # Fold '--'s and remove trailing '-'
549 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100550 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000551 if cleaned == platform:
552 break
553 platform = cleaned
554 while platform[-1] == '-':
555 platform = platform[:-1]
556
557 return platform
558
559def _node(default=''):
560
561 """ Helper to determine the node name of this machine.
562 """
563 try:
564 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400565 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000566 # No sockets...
567 return default
568 try:
569 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200570 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000571 # Still not working...
572 return default
573
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000574def _follow_symlinks(filepath):
575
576 """ In case filepath is a symlink, follow it until a
577 real file is reached.
578 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000579 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000580 while os.path.islink(filepath):
581 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100582 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000583 return filepath
584
Victor Stinnerced39362013-12-09 00:14:52 +0100585def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000586
587 """ Interface to the system's uname command.
588 """
Victor Stinnerced39362013-12-09 00:14:52 +0100589 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000590 # XXX Others too ?
591 return default
592 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000593 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200594 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000595 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000596 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000597 rc = f.close()
598 if not output or rc:
599 return default
600 else:
601 return output
602
Victor Stinnerced39362013-12-09 00:14:52 +0100603def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000604
605 """ Interface to the system's file command.
606
607 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000608 omit the filename in its output. Follow the symlinks. It returns
609 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000610
611 """
Victor Stinnerced39362013-12-09 00:14:52 +0100612 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000613 # XXX Others too ?
614 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200615 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000616 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200617 proc = subprocess.Popen(['file', target],
618 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200619
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200620 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000621 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200622 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200623 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000624 if not output or rc:
625 return default
626 else:
627 return output
628
629### Information about the used architecture
630
631# Default values for architecture; non-empty strings override the
632# defaults given as parameters
633_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100634 'win32': ('', 'WindowsPE'),
635 'win16': ('', 'Windows'),
636 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000637}
638
Victor Stinnerced39362013-12-09 00:14:52 +0100639def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000640
641 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000642 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000643
Victor Stinnerced39362013-12-09 00:14:52 +0100644 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000645 the bit architecture and the linkage format used for the
646 executable. Both values are returned as strings.
647
648 Values that cannot be determined are returned as given by the
649 parameter presets. If bits is given as '', the sizeof(pointer)
650 (or sizeof(long) on Python version < 1.5.2) is used as
651 indicator for the supported pointer size.
652
653 The function relies on the system's "file" command to do the
654 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000655 platforms. On some non-Unix platforms where the "file" command
656 does not exist and the executable is set to the Python interpreter
657 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000658
659 """
660 # Use the sizeof(pointer) as default number of bits if nothing
661 # else is given as default.
662 if not bits:
663 import struct
664 try:
665 size = struct.calcsize('P')
666 except struct.error:
667 # Older installations can only query longs
668 size = struct.calcsize('l')
669 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000670
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000671 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000672 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000673 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000674 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000675 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000676
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000677 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000678 executable == sys.executable:
679 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000680 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000681 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100682 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000683 if b:
684 bits = b
685 if l:
686 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100687 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000688
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000689 if 'executable' not in fileout:
690 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100691 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000692
693 # Bits
694 if '32-bit' in fileout:
695 bits = '32bit'
696 elif 'N32' in fileout:
697 # On Irix only
698 bits = 'n32bit'
699 elif '64-bit' in fileout:
700 bits = '64bit'
701
702 # Linkage
703 if 'ELF' in fileout:
704 linkage = 'ELF'
705 elif 'PE' in fileout:
706 # E.g. Windows uses this format
707 if 'Windows' in fileout:
708 linkage = 'WindowsPE'
709 else:
710 linkage = 'PE'
711 elif 'COFF' in fileout:
712 linkage = 'COFF'
713 elif 'MS-DOS' in fileout:
714 linkage = 'MSDOS'
715 else:
716 # XXX the A.OUT format also falls under this class...
717 pass
718
Victor Stinnerced39362013-12-09 00:14:52 +0100719 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000720
721### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000722
Larry Hastings68386bc2012-06-24 14:30:41 -0700723uname_result = collections.namedtuple("uname_result",
724 "system node release version machine processor")
725
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000726_uname_cache = None
727
728def uname():
729
730 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100731 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000732 identifying the underlying platform.
733
734 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000735 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000736
737 Entries which cannot be determined are set to ''.
738
739 """
740 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000741 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000742
743 if _uname_cache is not None:
744 return _uname_cache
745
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000746 processor = ''
747
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000748 # Get some infos from the builtin os.uname API...
749 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100750 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000751 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000752 no_os_uname = 1
753
Georg Brandl62e2ca22010-07-31 21:54:24 +0000754 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000755 # Hmm, no there is either no uname or uname has returned
756 #'unknowns'... we'll have to poke around the system then.
757 if no_os_uname:
758 system = sys.platform
759 release = ''
760 version = ''
761 node = _node()
762 machine = ''
763
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000764 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000765
766 # Try win32_ver() on win32 platforms
767 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100768 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000769 if release and version:
770 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000771 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000772 # available on Win XP and later; see
773 # http://support.microsoft.com/kb/888731 and
774 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000775 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000776 # WOW64 processes mask the native architecture
777 if "PROCESSOR_ARCHITEW6432" in os.environ:
778 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
779 else:
780 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000781 if not processor:
782 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000783
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000784 # Try the 'ver' system command available on some
785 # platforms
786 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100787 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000788 # Normalize system to what win32_ver() normally returns
789 # (_syscmd_ver() tends to return the vendor name as well)
790 if system == 'Microsoft Windows':
791 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000792 elif system == 'Microsoft' and release == 'Windows':
793 # Under Windows Vista and Windows Server 2008,
794 # Microsoft changed the output of the ver command. The
795 # release is no longer printed. This causes the
796 # system and release to be misidentified.
797 system = 'Windows'
798 if '6.0' == version[:3]:
799 release = 'Vista'
800 else:
801 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000802
803 # In case we still don't know anything useful, we'll try to
804 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100805 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000806 if not version:
807 if system == 'win32':
808 version = '32bit'
809 else:
810 version = '16bit'
811 system = 'Windows'
812
813 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100814 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000815 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000816 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000817 if not version:
818 version = vendor
819
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000820 # System specific extensions
821 if system == 'OpenVMS':
822 # OpenVMS seems to have release and version mixed up
823 if not release or release == '0':
824 release = version
825 version = ''
826 # Get processor information
827 try:
828 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400829 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000830 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000831 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100832 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000833 if (cpu_number >= 128):
834 processor = 'Alpha'
835 else:
836 processor = 'VAX'
837 if not processor:
838 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +0100839 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000841 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000842 if system == 'unknown':
843 system = ''
844 if node == 'unknown':
845 node = ''
846 if release == 'unknown':
847 release = ''
848 if version == 'unknown':
849 version = ''
850 if machine == 'unknown':
851 machine = ''
852 if processor == 'unknown':
853 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000854
855 # normalize name
856 if system == 'Microsoft' and release == 'Windows':
857 system = 'Windows'
858 release = 'Vista'
859
Victor Stinnerced39362013-12-09 00:14:52 +0100860 _uname_cache = uname_result(system, node, release, version,
861 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000862 return _uname_cache
863
864### Direct interfaces to some of the uname() return values
865
866def system():
867
868 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
869
870 An empty string is returned if the value cannot be determined.
871
872 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700873 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000874
875def node():
876
Brett Cannon8ab27df2003-08-05 03:52:04 +0000877 """ Returns the computer's network name (which may not be fully
878 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000879
880 An empty string is returned if the value cannot be determined.
881
882 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700883 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000884
885def release():
886
887 """ Returns the system's release, e.g. '2.2.0' or 'NT'
888
889 An empty string is returned if the value cannot be determined.
890
891 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700892 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000893
894def version():
895
896 """ Returns the system's release version, e.g. '#3 on degas'
897
898 An empty string is returned if the value cannot be determined.
899
900 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700901 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000902
903def machine():
904
905 """ Returns the machine type, e.g. 'i386'
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().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000911
912def processor():
913
914 """ Returns the (true) processor name, e.g. 'amdk6'
915
916 An empty string is returned if the value cannot be
917 determined. Note that many platforms do not provide this
918 information or simply return the same value as for machine(),
919 e.g. NetBSD does this.
920
921 """
Larry Hastings68386bc2012-06-24 14:30:41 -0700922 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000923
924### Various APIs for extracting information from sys.version
925
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000926_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +0000927 r'([\w.+]+)\s*' # "version<space>"
928 r'\(#?([^,]+)' # "(#buildno"
929 r'(?:,\s*([\w ]*)' # ", builddate"
930 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
931 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000932
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000933_ironpython_sys_version_parser = re.compile(
934 r'IronPython\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400935 r'([\d\.]+)'
936 r'(?: \(([\d\.]+)\))?'
937 r' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000938
Ezio Melottif076f532013-10-21 03:03:32 +0300939# IronPython covering 2.6 and 2.7
940_ironpython26_sys_version_parser = re.compile(
941 r'([\d.]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400942 r'\(IronPython\s*'
943 r'[\d.]+\s*'
944 r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
Ezio Melottif076f532013-10-21 03:03:32 +0300945)
946
Benjamin Petersone549ead2009-03-28 21:42:05 +0000947_pypy_sys_version_parser = re.compile(
948 r'([\w.+]+)\s*'
R David Murray44b548d2016-09-08 13:59:53 -0400949 r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
950 r'\[PyPy [^\]]+\]?')
Benjamin Petersone549ead2009-03-28 21:42:05 +0000951
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000952_sys_version_cache = {}
953
954def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000955
956 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +0000957 (name, version, branch, revision, buildno, builddate, compiler)
958 referring to the Python implementation name, version, branch,
959 revision, build number, build date/time as string and the compiler
960 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000961
962 Note that unlike the Python sys.version, the returned value
963 for the Python version will always include the patchlevel (it
964 defaults to '.0').
965
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000966 The function returns empty strings for tuple entries that
967 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000968
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000969 sys_version may be given to parse an alternative version
970 string, e.g. if the version was read from a different Python
971 interpreter.
972
973 """
974 # Get the Python version
975 if sys_version is None:
976 sys_version = sys.version
977
978 # Try the cache first
979 result = _sys_version_cache.get(sys_version, None)
980 if result is not None:
981 return result
982
983 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +0300984 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000985 # IronPython
986 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +0300987 if sys_version.startswith('IronPython'):
988 match = _ironpython_sys_version_parser.match(sys_version)
989 else:
990 match = _ironpython26_sys_version_parser.match(sys_version)
991
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000992 if match is None:
993 raise ValueError(
994 'failed to parse IronPython sys.version: %s' %
995 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +0300996
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000997 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000998 buildno = ''
999 builddate = ''
1000
Ezio Melottif076f532013-10-21 03:03:32 +03001001 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001002 # Jython
1003 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001004 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001005 if match is None:
1006 raise ValueError(
1007 'failed to parse Jython sys.version: %s' %
1008 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001009 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001010 if builddate is None:
1011 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001012 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001013
1014 elif "PyPy" in sys_version:
1015 # PyPy
1016 name = "PyPy"
1017 match = _pypy_sys_version_parser.match(sys_version)
1018 if match is None:
1019 raise ValueError("failed to parse PyPy sys.version: %s" %
1020 repr(sys_version))
1021 version, buildno, builddate, buildtime = match.groups()
1022 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001023
1024 else:
1025 # CPython
1026 match = _sys_version_parser.match(sys_version)
1027 if match is None:
1028 raise ValueError(
1029 'failed to parse CPython sys.version: %s' %
1030 repr(sys_version))
1031 version, buildno, builddate, buildtime, compiler = \
1032 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001033 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001034 if builddate is None:
1035 builddate = ''
1036 elif buildtime:
1037 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001038
Ned Deily5c4b0d02017-03-04 00:19:55 -05001039 if hasattr(sys, '_git'):
1040 _, branch, revision = sys._git
1041 elif hasattr(sys, '_mercurial'):
Georg Brandl82562422011-03-05 21:09:22 +01001042 _, branch, revision = sys._mercurial
Benjamin Petersone549ead2009-03-28 21:42:05 +00001043 else:
1044 branch = ''
1045 revision = ''
1046
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001047 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001048 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001049 if len(l) == 2:
1050 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001051 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001052
1053 # Build and cache the result
1054 result = (name, version, branch, revision, buildno, builddate, compiler)
1055 _sys_version_cache[sys_version] = result
1056 return result
1057
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001058def python_implementation():
1059
1060 """ Returns a string identifying the Python implementation.
1061
1062 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001063 'CPython' (C implementation of Python),
1064 'IronPython' (.NET implementation of Python),
1065 'Jython' (Java implementation of Python),
1066 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001067
1068 """
1069 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001070
1071def python_version():
1072
1073 """ Returns the Python version as string 'major.minor.patchlevel'
1074
1075 Note that unlike the Python sys.version, the returned value
1076 will always include the patchlevel (it defaults to 0).
1077
1078 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001079 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001080
1081def python_version_tuple():
1082
1083 """ Returns the Python version as tuple (major, minor, patchlevel)
1084 of strings.
1085
1086 Note that unlike the Python sys.version, the returned value
1087 will always include the patchlevel (it defaults to 0).
1088
1089 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001090 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001091
1092def python_branch():
1093
1094 """ Returns a string identifying the Python implementation
1095 branch.
1096
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001097 For CPython this is the SCM branch from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001098 Python binary was built.
1099
1100 If not available, an empty string is returned.
1101
1102 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001103
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001104 return _sys_version()[2]
1105
1106def python_revision():
1107
1108 """ Returns a string identifying the Python implementation
1109 revision.
1110
Victor Stinnerfe2d5ba2017-11-28 22:29:32 +01001111 For CPython this is the SCM revision from which the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001112 Python binary was built.
1113
1114 If not available, an empty string is returned.
1115
1116 """
1117 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001118
1119def python_build():
1120
1121 """ Returns a tuple (buildno, builddate) stating the Python
1122 build number and date as strings.
1123
1124 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001125 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001126
1127def python_compiler():
1128
1129 """ Returns a string identifying the compiler used for compiling
1130 Python.
1131
1132 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001133 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001134
1135### The Opus Magnum of platform strings :-)
1136
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001137_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001138
1139def platform(aliased=0, terse=0):
1140
1141 """ Returns a single string identifying the underlying platform
1142 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001143
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001144 The output is intended to be human readable rather than
1145 machine parseable. It may look different on different
1146 platforms and this is intended.
1147
1148 If "aliased" is true, the function will use aliases for
1149 various platforms that report system names which differ from
1150 their common names, e.g. SunOS will be reported as
1151 Solaris. The system_alias() function is used to implement
1152 this.
1153
1154 Setting terse to true causes the function to return only the
1155 absolute minimum information needed to identify the platform.
1156
1157 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001158 result = _platform_cache.get((aliased, terse), None)
1159 if result is not None:
1160 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001161
1162 # Get uname information and then apply platform specific cosmetics
1163 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001164 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001165 if machine == processor:
1166 processor = ''
1167 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001168 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001169
1170 if system == 'Windows':
1171 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001172 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001173 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001174 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001175 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001176 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177
1178 elif system in ('Linux',):
Petr Viktorin8b94b412018-05-16 11:51:18 -04001179 # check for libc vs. glibc
1180 libcname, libcversion = libc_ver(sys.executable)
1181 platform = _platform(system, release, machine, processor,
1182 'with',
1183 libcname+libcversion)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001184 elif system == 'Java':
1185 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001186 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001187 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001188 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001189 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001190 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001191 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001192 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001193
1194 elif system == 'MacOS':
1195 # MacOS platforms
1196 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001197 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001198 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001199 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001200
1201 else:
1202 # Generic handler
1203 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001204 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001205 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001206 bits, linkage = architecture(sys.executable)
1207 platform = _platform(system, release, machine,
1208 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001209
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001210 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001211 return platform
1212
1213### Command line interface
1214
1215if __name__ == '__main__':
1216 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001217 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001218 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001219 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001220 sys.exit(0)