blob: ad425a16c1e873cb82ae67d46ec9c0340b630e84 [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:
16# * more support for WinCE
17# * support for MS-DOS (PythonDX ?)
18# * support for Amiga and other still unsupported platforms running Python
19# * support for additional Linux distributions
20#
Brett Cannon8ab27df2003-08-05 03:52:04 +000021# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000022# checks (in no particular order):
23#
24# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
25# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
26# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
27# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
28# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Steve Dower64a33872015-09-22 17:29:51 -070029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
30# Dower
Marc-André Lemburg246d8472003-04-24 11:36:11 +000031#
32# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000033#
34# <see CVS and SVN checkin messages for history>
35#
Steve Dower64a33872015-09-22 17:29:51 -070036# 1.0.8 - changed Windows support to read version from kernel32.dll
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000037# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000038# 1.0.6 - added linux_distribution()
39# 1.0.5 - fixed Java support to allow running the module on Jython
40# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000041# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000042# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000043# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000044# 1.0.0 - reformatted a bit and checked into Python CVS
45# 0.8.0 - added sys.version parser and various new access
46# APIs (python_version(), python_compiler(), etc.)
47# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
48# 0.7.1 - added support for Caldera OpenLinux
49# 0.7.0 - some fixes for WinCE; untabified the source file
50# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
51# vms_lib.getsyi() configured
52# 0.6.1 - added code to prevent 'uname -p' on platforms which are
53# known not to support it
54# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
55# did some cleanup of the interfaces - some APIs have changed
56# 0.5.5 - fixed another type in the MacOS code... should have
57# used more coffee today ;-)
58# 0.5.4 - fixed a few typos in the MacOS code
59# 0.5.3 - added experimental MacOS support; added better popen()
60# workarounds in _syscmd_ver() -- still not 100% elegant
61# though
62# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
63# return values (the system uname command tends to return
64# 'unknown' instead of just leaving the field emtpy)
65# 0.5.1 - included code for slackware dist; added exception handlers
66# to cover up situations where platforms don't have os.popen
67# (e.g. Mac) or fail on socket.gethostname(); fixed libc
68# detection RE
69# 0.5.0 - changed the API names referring to system commands to *syscmd*;
70# added java_ver(); made syscmd_ver() a private
71# API (was system_ver() in previous versions) -- use uname()
72# instead; extended the win32_ver() to also return processor
73# type information
74# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
75# 0.3.4 - fixed a bug in _follow_symlinks()
76# 0.3.3 - fixed popen() and "file" command invokation bugs
77# 0.3.2 - added architecture() API and support for it in platform()
78# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
79# 0.3.0 - added system alias support
80# 0.2.3 - removed 'wince' again... oh well.
81# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
82# 0.2.1 - added cache logic and changed the platform string format
83# 0.2.0 - changed the API to use functions instead of module globals
84# since some action take too long to be run on module import
85# 0.1.0 - first release
86#
87# You can always get the latest version of this module at:
88#
89# http://www.egenix.com/files/python/platform.py
90#
91# If that URL should fail, try contacting the author.
92
93__copyright__ = """
94 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Peterson46a99002010-01-09 18:45:30 +000095 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000096
97 Permission to use, copy, modify, and distribute this software and its
98 documentation for any purpose and without fee or royalty is hereby granted,
99 provided that the above copyright notice appear in all copies and that
100 both that copyright notice and this permission notice appear in
101 supporting documentation or portions thereof, including modifications,
102 that you make.
103
104 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
105 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
106 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
107 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
108 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
109 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
110 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
111
112"""
113
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000114__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000115
Larry Hastings68386bc2012-06-24 14:30:41 -0700116import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200117import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000118
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000119### Globals & Constants
120
121# Determine the platform's /dev/null device
122try:
123 DEV_NULL = os.devnull
124except AttributeError:
125 # os.devnull was added in Python 2.4, so emulate it for earlier
126 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100127 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000128 # Use the old CP/M NUL as device name
129 DEV_NULL = 'NUL'
130 else:
131 # Standard Unix uses /dev/null
132 DEV_NULL = '/dev/null'
133
Victor Stinner620c48b2013-12-09 00:01:27 +0100134# Directory to search for configuration information on Unix.
135# Constant used by test_platform to test linux_distribution().
136_UNIXCONFDIR = '/etc'
137
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000138### Platform specific APIs
139
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200140_libc_search = re.compile(b'(__libc_init)'
141 b'|'
142 b'(GLIBC_([0-9.]+))'
143 b'|'
144 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000145
Victor Stinnerced39362013-12-09 00:14:52 +0100146def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200148 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000149
Brett Cannon8ab27df2003-08-05 03:52:04 +0000150 """ Tries to determine the libc version that the file executable
151 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152
153 Returns a tuple of strings (lib,version) which default to the
154 given parameters in case the lookup fails.
155
156 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000157 libc versions add symbols to the executable and thus is probably
158 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000159
160 The file is read and scanned in chunks of chunksize bytes.
161
162 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000163 if hasattr(os.path, 'realpath'):
164 # Python 2.2 introduced os.path.realpath(); it is used
165 # here to work around problems with Cygwin not being
166 # able to open symlinks for reading
167 executable = os.path.realpath(executable)
Victor Stinnerced39362013-12-09 00:14:52 +0100168 f = open(executable, 'rb')
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200169 binary = f.read(chunksize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000170 pos = 0
171 while 1:
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200172 if b'libc' in binary or b'GLIBC' in binary:
Victor Stinnerced39362013-12-09 00:14:52 +0100173 m = _libc_search.search(binary, pos)
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200174 else:
175 m = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000176 if not m:
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200177 binary = f.read(chunksize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000178 if not binary:
179 break
180 pos = 0
181 continue
Victor Stinnerced39362013-12-09 00:14:52 +0100182 libcinit, glibc, glibcversion, so, threads, soversion = [
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200183 s.decode('latin1') if s is not None else s
184 for s in m.groups()]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000185 if libcinit and not lib:
186 lib = 'libc'
187 elif glibc:
188 if lib != 'glibc':
189 lib = 'glibc'
190 version = glibcversion
191 elif glibcversion > version:
192 version = glibcversion
193 elif so:
194 if lib != 'glibc':
195 lib = 'libc'
Victor Stinner87448812011-12-15 21:42:03 +0100196 if soversion and soversion > version:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000197 version = soversion
198 if threads and version[-len(threads):] != threads:
199 version = version + threads
200 pos = m.end()
201 f.close()
Victor Stinnerced39362013-12-09 00:14:52 +0100202 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000203
Victor Stinnerced39362013-12-09 00:14:52 +0100204def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000205
Tim Peters0eadaac2003-04-24 16:02:54 +0000206 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000207 information in case the default method fails.
208
209 Currently supports older SuSE Linux, Caldera OpenLinux and
210 Slackware Linux distributions.
211
212 """
213 if os.path.exists('/var/adm/inst-log/info'):
214 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000216 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000217 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000218 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100219 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000220 else:
221 continue
222 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000223 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000224 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000225 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000226 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100227 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000228
229 if os.path.exists('/etc/.installed'):
230 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000231 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000232 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000233 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
234 # XXX does Caldera support non Intel platforms ? If yes,
235 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100236 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000237
238 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300239 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000240 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000241 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000242 if verfiles[n][:14] != 'slack-version-':
243 del verfiles[n]
244 if verfiles:
245 verfiles.sort()
246 distname = 'slackware'
247 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100248 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000249
Victor Stinnerced39362013-12-09 00:14:52 +0100250 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000251
Antoine Pitroufd036452008-08-19 17:56:33 +0000252_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000253_lsb_release_version = re.compile(r'(.+)'
254 ' release '
255 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000256 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000257_release_version = re.compile(r'([^0-9]+)'
258 '(?: release )?'
259 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000260 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000261
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000262# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000263# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000264# and http://data.linux-ntfs.org/rpm/whichrpm
265# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000266
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000267_supported_dists = (
268 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
269 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200270 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000271
272def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000273
Benjamin Peterson25001472010-01-25 03:37:42 +0000274 # Default to empty 'version' and 'id' strings. Both defaults are used
275 # when 'firstline' is empty. 'id' defaults to empty when an id can not
276 # be deduced.
277 version = ''
278 id = ''
279
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000280 # Parse the first line
281 m = _lsb_release_version.match(firstline)
282 if m is not None:
283 # LSB format: "distro release x.x (codename)"
284 return tuple(m.groups())
285
286 # Pre-LSB format: "distro x.x (codename)"
287 m = _release_version.match(firstline)
288 if m is not None:
289 return tuple(m.groups())
290
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300291 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000292 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000293 if l:
294 version = l[0]
295 if len(l) > 1:
296 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000297 return '', version, id
298
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000299def linux_distribution(distname='', version='', id='',
300
301 supported_dists=_supported_dists,
302 full_distribution_name=1):
303
304 """ Tries to determine the name of the Linux OS distribution name.
305
306 The function first looks for a distribution release file in
307 /etc and then reverts to _dist_try_harder() in case no
308 suitable files are found.
309
310 supported_dists may be given to define the set of Linux
311 distributions to look for. It defaults to a list of currently
312 supported Linux distributions identified by their release file
313 name.
314
315 If full_distribution_name is true (default), the full
316 distribution read from the OS is returned. Otherwise the short
317 name taken from supported_dists is used.
318
Victor Stinnerced39362013-12-09 00:14:52 +0100319 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000320 args given as parameters.
321
322 """
323 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100324 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200325 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000326 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100327 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000328 etc.sort()
329 for file in etc:
330 m = _release_filename.match(file)
331 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100332 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000333 if _distname in supported_dists:
334 distname = _distname
335 break
336 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100337 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000338
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000339 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100340 with open(os.path.join(_UNIXCONFDIR, file), 'r',
341 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000342 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000343 _distname, _version, _id = _parse_release_file(firstline)
344
345 if _distname and full_distribution_name:
346 distname = _distname
347 if _version:
348 version = _version
349 if _id:
350 id = _id
351 return distname, version, id
352
353# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000354
Victor Stinnerced39362013-12-09 00:14:52 +0100355def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000356
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000357 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000358
Brett Cannon8ab27df2003-08-05 03:52:04 +0000359 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000360
361 The function first looks for a distribution release file in
362 /etc and then reverts to _dist_try_harder() in case no
363 suitable files are found.
364
Victor Stinnerced39362013-12-09 00:14:52 +0100365 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000366 args given as parameters.
367
368 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000369 return linux_distribution(distname, version, id,
370 supported_dists=supported_dists,
371 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000372
Antoine Pitrou877766d2011-03-19 17:00:37 +0100373def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000374
375 """ Portable popen() interface.
376 """
Victor Stinner25000d42011-05-24 00:16:16 +0200377 import warnings
378 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000379 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000380
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000381def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000382
Brett Cannon8ab27df2003-08-05 03:52:04 +0000383 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000384 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000385 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000386 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000387 if build:
388 l.append(build)
389 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100390 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000391 except ValueError:
392 strings = l
393 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100394 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000395 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000396 return version
397
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000398_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
399 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000400 '\[.* ([\d.]+)\])')
401
402# Examples of VER command output:
403#
404# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
405# Windows XP: Microsoft Windows XP [Version 5.1.2600]
406# Windows Vista: Microsoft Windows [Version 6.0.6002]
407#
408# Note that the "Version" string gets localized on different
409# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000410
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000411def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000412
Victor Stinnerced39362013-12-09 00:14:52 +0100413 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000414
415 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100416 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000417
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000418 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200419 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000420
421 In case this fails, the given parameters are used as
422 defaults.
423
424 """
425 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100426 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000427
428 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100429 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000430 try:
431 pipe = popen(cmd)
432 info = pipe.read()
433 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200434 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200435 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000436 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200437 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100438 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000439 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000440 else:
441 break
442 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100443 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000444
445 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000446 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000447 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000448 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100449 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000450 # Strip trailing dots from version and release
451 if release[-1] == '.':
452 release = release[:-1]
453 if version[-1] == '.':
454 version = version[:-1]
455 # Normalize the version and build strings (eliminating additional
456 # zeros)
457 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100458 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000459
Steve Dower64a33872015-09-22 17:29:51 -0700460_WIN32_CLIENT_RELEASES = {
461 (5, 0): "2000",
462 (5, 1): "XP",
463 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
464 # has always called it 2003 Server
465 (5, 2): "2003Server",
466 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000467
Steve Dower64a33872015-09-22 17:29:51 -0700468 (6, 0): "Vista",
469 (6, 1): "7",
470 (6, 2): "8",
471 (6, 3): "8.1",
472 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000473
Steve Dower64a33872015-09-22 17:29:51 -0700474 (10, 0): "10",
475 (10, None): "post10",
476}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000477
Steve Dower64a33872015-09-22 17:29:51 -0700478# Server release name lookup will default to client names if necessary
479_WIN32_SERVER_RELEASES = {
480 (5, 2): "2003Server",
481
482 (6, 0): "2008Server",
483 (6, 1): "2008ServerR2",
484 (6, 2): "2012Server",
485 (6, 3): "2012ServerR2",
486 (6, None): "post2012ServerR2",
487}
488
489def _get_real_winver(maj, min, build):
490 if maj < 6 or (maj == 6 and min < 2):
491 return maj, min, build
492
493 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
494 Structure, WinDLL)
495 from ctypes.wintypes import DWORD, HANDLE
496
497 class VS_FIXEDFILEINFO(Structure):
498 _fields_ = [
499 ("dwSignature", DWORD),
500 ("dwStrucVersion", DWORD),
501 ("dwFileVersionMS", DWORD),
502 ("dwFileVersionLS", DWORD),
503 ("dwProductVersionMS", DWORD),
504 ("dwProductVersionLS", DWORD),
505 ("dwFileFlagsMask", DWORD),
506 ("dwFileFlags", DWORD),
507 ("dwFileOS", DWORD),
508 ("dwFileType", DWORD),
509 ("dwFileSubtype", DWORD),
510 ("dwFileDateMS", DWORD),
511 ("dwFileDateLS", DWORD),
512 ]
513
514 kernel32 = WinDLL('kernel32')
515 version = WinDLL('version')
516
517 # We will immediately double the length up to MAX_PATH, but the
518 # path may be longer, so we retry until the returned string is
519 # shorter than our buffer.
520 name_len = actual_len = 130
521 while actual_len == name_len:
522 name_len *= 2
523 name = create_unicode_buffer(name_len)
524 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
525 name, len(name))
526 if not actual_len:
527 return maj, min, build
528
529 size = version.GetFileVersionInfoSizeW(name, None)
530 if not size:
531 return maj, min, build
532
533 ver_block = c_buffer(size)
534 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
535 not ver_block):
536 return maj, min, build
537
538 pvi = POINTER(VS_FIXEDFILEINFO)()
539 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
540 return maj, min, build
541
542 maj = pvi.contents.dwProductVersionMS >> 16
543 min = pvi.contents.dwProductVersionMS & 0xFFFF
544 build = pvi.contents.dwProductVersionLS >> 16
545
546 return maj, min, build
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000547
Victor Stinnerced39362013-12-09 00:14:52 +0100548def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700549 try:
550 from sys import getwindowsversion
551 except ImportError:
552 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000553 try:
Steve Dower64a33872015-09-22 17:29:51 -0700554 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400555 except ImportError:
Steve Dower64a33872015-09-22 17:29:51 -0700556 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
557
558 winver = getwindowsversion()
559 maj, min, build = _get_real_winver(*winver[:3])
560 version = '{0}.{1}.{2}'.format(maj, min, build)
561
562 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
563 _WIN32_CLIENT_RELEASES.get((maj, None)) or
564 release)
565
566 # getwindowsversion() reflect the compatibility mode Python is
567 # running under, and so the service pack value is only going to be
568 # valid if the versions match.
569 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000570 try:
Steve Dower64a33872015-09-22 17:29:51 -0700571 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000572 except AttributeError:
Steve Dower64a33872015-09-22 17:29:51 -0700573 if csd[:13] == 'Service Pack ':
574 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000575
Steve Dower64a33872015-09-22 17:29:51 -0700576 # VER_NT_SERVER = 3
577 if getattr(winver, 'product_type', None) == 3:
578 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
579 _WIN32_SERVER_RELEASES.get((maj, None)) or
580 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000581
Steve Dower64a33872015-09-22 17:29:51 -0700582 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000583 try:
Steve Dower64a33872015-09-22 17:29:51 -0700584 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
585 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
586 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000587 except:
Steve Dower64a33872015-09-22 17:29:51 -0700588 pass
589 finally:
590 if key:
591 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000592
Victor Stinnerced39362013-12-09 00:14:52 +0100593 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000594
Steve Dower64a33872015-09-22 17:29:51 -0700595
Ronald Oussorene186e382010-07-23 11:54:59 +0000596def _mac_ver_xml():
597 fn = '/System/Library/CoreServices/SystemVersion.plist'
598 if not os.path.exists(fn):
599 return None
600
601 try:
602 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400603 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000604 return None
605
Ned Deily936dfae2014-01-13 11:34:19 -0800606 with open(fn, 'rb') as f:
607 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000608 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100609 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700610 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000611 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300612 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000613 machine = 'PowerPC'
614
Victor Stinnerced39362013-12-09 00:14:52 +0100615 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000616
617
Victor Stinnerced39362013-12-09 00:14:52 +0100618def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000619
620 """ Get MacOS version information and return it as tuple (release,
621 versioninfo, machine) with versioninfo being a tuple (version,
622 dev_stage, non_release_version).
623
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300624 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000625 which default to ''. All tuple entries are strings.
626 """
627
628 # First try reading the information from an XML file which should
629 # always be present
630 info = _mac_ver_xml()
631 if info is not None:
632 return info
633
Ronald Oussorene186e382010-07-23 11:54:59 +0000634 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100635 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636
Victor Stinnerced39362013-12-09 00:14:52 +0100637def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638
639 from java.lang import System
640 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000641 value = System.getProperty(name)
642 if value is None:
643 return default
644 return value
645 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000646 return default
647
Victor Stinnerced39362013-12-09 00:14:52 +0100648def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000649
Brett Cannon8ab27df2003-08-05 03:52:04 +0000650 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000651
Victor Stinnerced39362013-12-09 00:14:52 +0100652 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
653 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
654 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000655
656 Values which cannot be determined are set to the defaults
657 given as parameters (which all default to '').
658
659 """
660 # Import the needed APIs
661 try:
662 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400663 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100664 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000666 vendor = _java_getprop('java.vendor', vendor)
667 release = _java_getprop('java.version', release)
668 vm_name, vm_release, vm_vendor = vminfo
669 vm_name = _java_getprop('java.vm.name', vm_name)
670 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
671 vm_release = _java_getprop('java.vm.version', vm_release)
672 vminfo = vm_name, vm_release, vm_vendor
673 os_name, os_version, os_arch = osinfo
674 os_arch = _java_getprop('java.os.arch', os_arch)
675 os_name = _java_getprop('java.os.name', os_name)
676 os_version = _java_getprop('java.os.version', os_version)
677 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000678
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000679 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000680
681### System name aliasing
682
Victor Stinnerced39362013-12-09 00:14:52 +0100683def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000684
Victor Stinnerced39362013-12-09 00:14:52 +0100685 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000686 marketing names used for some systems.
687
688 It also does some reordering of the information in some cases
689 where it would otherwise cause confusion.
690
691 """
692 if system == 'Rhapsody':
693 # Apple's BSD derivative
694 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100695 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000696
697 elif system == 'SunOS':
698 # Sun's OS
699 if release < '5':
700 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100701 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000703 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000704 if l:
705 try:
706 major = int(l[0])
707 except ValueError:
708 pass
709 else:
710 major = major - 3
711 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000712 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000713 if release < '6':
714 system = 'Solaris'
715 else:
716 # XXX Whatever the new SunOS marketing name is...
717 system = 'Solaris'
718
719 elif system == 'IRIX64':
720 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
721 # is really a version and not a different platform, since 32-bit
722 # apps are also supported..
723 system = 'IRIX'
724 if version:
725 version = version + ' (64bit)'
726 else:
727 version = '64bit'
728
Victor Stinnerced39362013-12-09 00:14:52 +0100729 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000730 # In case one of the other tricks
731 system = 'Windows'
732
Victor Stinnerced39362013-12-09 00:14:52 +0100733 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000734
735### Various internal helpers
736
737def _platform(*args):
738
739 """ Helper to format the platform string in a filename
740 compatible format e.g. "system-version-machine".
741 """
742 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000743 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744
745 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100746 platform = platform.replace(' ', '_')
747 platform = platform.replace('/', '-')
748 platform = platform.replace('\\', '-')
749 platform = platform.replace(':', '-')
750 platform = platform.replace(';', '-')
751 platform = platform.replace('"', '-')
752 platform = platform.replace('(', '-')
753 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000754
755 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100756 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000757
758 # Fold '--'s and remove trailing '-'
759 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100760 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000761 if cleaned == platform:
762 break
763 platform = cleaned
764 while platform[-1] == '-':
765 platform = platform[:-1]
766
767 return platform
768
769def _node(default=''):
770
771 """ Helper to determine the node name of this machine.
772 """
773 try:
774 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400775 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000776 # No sockets...
777 return default
778 try:
779 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200780 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000781 # Still not working...
782 return default
783
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000784def _follow_symlinks(filepath):
785
786 """ In case filepath is a symlink, follow it until a
787 real file is reached.
788 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000789 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000790 while os.path.islink(filepath):
791 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100792 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000793 return filepath
794
Victor Stinnerced39362013-12-09 00:14:52 +0100795def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000796
797 """ Interface to the system's uname command.
798 """
Victor Stinnerced39362013-12-09 00:14:52 +0100799 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000800 # XXX Others too ?
801 return default
802 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000803 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200804 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000806 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000807 rc = f.close()
808 if not output or rc:
809 return default
810 else:
811 return output
812
Victor Stinnerced39362013-12-09 00:14:52 +0100813def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000814
815 """ Interface to the system's file command.
816
817 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000818 omit the filename in its output. Follow the symlinks. It returns
819 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000820
821 """
Victor Stinnerced39362013-12-09 00:14:52 +0100822 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000823 # XXX Others too ?
824 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200825 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000826 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200827 proc = subprocess.Popen(['file', target],
828 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200829
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200830 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000831 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200832 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200833 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000834 if not output or rc:
835 return default
836 else:
837 return output
838
839### Information about the used architecture
840
841# Default values for architecture; non-empty strings override the
842# defaults given as parameters
843_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100844 'win32': ('', 'WindowsPE'),
845 'win16': ('', 'Windows'),
846 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000847}
848
Victor Stinnerced39362013-12-09 00:14:52 +0100849def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000850
851 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000852 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000853
Victor Stinnerced39362013-12-09 00:14:52 +0100854 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000855 the bit architecture and the linkage format used for the
856 executable. Both values are returned as strings.
857
858 Values that cannot be determined are returned as given by the
859 parameter presets. If bits is given as '', the sizeof(pointer)
860 (or sizeof(long) on Python version < 1.5.2) is used as
861 indicator for the supported pointer size.
862
863 The function relies on the system's "file" command to do the
864 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000865 platforms. On some non-Unix platforms where the "file" command
866 does not exist and the executable is set to the Python interpreter
867 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000868
869 """
870 # Use the sizeof(pointer) as default number of bits if nothing
871 # else is given as default.
872 if not bits:
873 import struct
874 try:
875 size = struct.calcsize('P')
876 except struct.error:
877 # Older installations can only query longs
878 size = struct.calcsize('l')
879 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000880
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000881 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000882 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000883 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000884 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000885 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000886
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000887 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000888 executable == sys.executable:
889 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000890 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000891 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100892 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000893 if b:
894 bits = b
895 if l:
896 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100897 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000898
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899 if 'executable' not in fileout:
900 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100901 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000902
903 # Bits
904 if '32-bit' in fileout:
905 bits = '32bit'
906 elif 'N32' in fileout:
907 # On Irix only
908 bits = 'n32bit'
909 elif '64-bit' in fileout:
910 bits = '64bit'
911
912 # Linkage
913 if 'ELF' in fileout:
914 linkage = 'ELF'
915 elif 'PE' in fileout:
916 # E.g. Windows uses this format
917 if 'Windows' in fileout:
918 linkage = 'WindowsPE'
919 else:
920 linkage = 'PE'
921 elif 'COFF' in fileout:
922 linkage = 'COFF'
923 elif 'MS-DOS' in fileout:
924 linkage = 'MSDOS'
925 else:
926 # XXX the A.OUT format also falls under this class...
927 pass
928
Victor Stinnerced39362013-12-09 00:14:52 +0100929 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000930
931### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000932
Larry Hastings68386bc2012-06-24 14:30:41 -0700933uname_result = collections.namedtuple("uname_result",
934 "system node release version machine processor")
935
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000936_uname_cache = None
937
938def uname():
939
940 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100941 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000942 identifying the underlying platform.
943
944 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000945 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000946
947 Entries which cannot be determined are set to ''.
948
949 """
950 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000951 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000952
953 if _uname_cache is not None:
954 return _uname_cache
955
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000956 processor = ''
957
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958 # Get some infos from the builtin os.uname API...
959 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100960 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000961 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000962 no_os_uname = 1
963
Georg Brandl62e2ca22010-07-31 21:54:24 +0000964 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000965 # Hmm, no there is either no uname or uname has returned
966 #'unknowns'... we'll have to poke around the system then.
967 if no_os_uname:
968 system = sys.platform
969 release = ''
970 version = ''
971 node = _node()
972 machine = ''
973
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000974 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000975
976 # Try win32_ver() on win32 platforms
977 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100978 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000979 if release and version:
980 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000981 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000982 # available on Win XP and later; see
983 # http://support.microsoft.com/kb/888731 and
984 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000985 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000986 # WOW64 processes mask the native architecture
987 if "PROCESSOR_ARCHITEW6432" in os.environ:
988 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
989 else:
990 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000991 if not processor:
992 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000993
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000994 # Try the 'ver' system command available on some
995 # platforms
996 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100997 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000998 # Normalize system to what win32_ver() normally returns
999 # (_syscmd_ver() tends to return the vendor name as well)
1000 if system == 'Microsoft Windows':
1001 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001002 elif system == 'Microsoft' and release == 'Windows':
1003 # Under Windows Vista and Windows Server 2008,
1004 # Microsoft changed the output of the ver command. The
1005 # release is no longer printed. This causes the
1006 # system and release to be misidentified.
1007 system = 'Windows'
1008 if '6.0' == version[:3]:
1009 release = 'Vista'
1010 else:
1011 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001012
1013 # In case we still don't know anything useful, we'll try to
1014 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001015 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001016 if not version:
1017 if system == 'win32':
1018 version = '32bit'
1019 else:
1020 version = '16bit'
1021 system = 'Windows'
1022
1023 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001024 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001025 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001026 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001027 if not version:
1028 version = vendor
1029
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001030 # System specific extensions
1031 if system == 'OpenVMS':
1032 # OpenVMS seems to have release and version mixed up
1033 if not release or release == '0':
1034 release = version
1035 version = ''
1036 # Get processor information
1037 try:
1038 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001039 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001040 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001041 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001042 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001043 if (cpu_number >= 128):
1044 processor = 'Alpha'
1045 else:
1046 processor = 'VAX'
1047 if not processor:
1048 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001049 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001050
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001051 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001052 if system == 'unknown':
1053 system = ''
1054 if node == 'unknown':
1055 node = ''
1056 if release == 'unknown':
1057 release = ''
1058 if version == 'unknown':
1059 version = ''
1060 if machine == 'unknown':
1061 machine = ''
1062 if processor == 'unknown':
1063 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001064
1065 # normalize name
1066 if system == 'Microsoft' and release == 'Windows':
1067 system = 'Windows'
1068 release = 'Vista'
1069
Victor Stinnerced39362013-12-09 00:14:52 +01001070 _uname_cache = uname_result(system, node, release, version,
1071 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001072 return _uname_cache
1073
1074### Direct interfaces to some of the uname() return values
1075
1076def system():
1077
1078 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1079
1080 An empty string is returned if the value cannot be determined.
1081
1082 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001083 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001084
1085def node():
1086
Brett Cannon8ab27df2003-08-05 03:52:04 +00001087 """ Returns the computer's network name (which may not be fully
1088 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001089
1090 An empty string is returned if the value cannot be determined.
1091
1092 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001093 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001094
1095def release():
1096
1097 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1098
1099 An empty string is returned if the value cannot be determined.
1100
1101 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001102 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001103
1104def version():
1105
1106 """ Returns the system's release version, e.g. '#3 on degas'
1107
1108 An empty string is returned if the value cannot be determined.
1109
1110 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001111 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001112
1113def machine():
1114
1115 """ Returns the machine type, e.g. 'i386'
1116
1117 An empty string is returned if the value cannot be determined.
1118
1119 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001120 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001121
1122def processor():
1123
1124 """ Returns the (true) processor name, e.g. 'amdk6'
1125
1126 An empty string is returned if the value cannot be
1127 determined. Note that many platforms do not provide this
1128 information or simply return the same value as for machine(),
1129 e.g. NetBSD does this.
1130
1131 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001132 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001133
1134### Various APIs for extracting information from sys.version
1135
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001136_sys_version_parser = re.compile(
1137 r'([\w.+]+)\s*'
1138 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001139 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001140
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001141_ironpython_sys_version_parser = re.compile(
1142 r'IronPython\s*'
1143 '([\d\.]+)'
1144 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001145 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001146
Ezio Melottif076f532013-10-21 03:03:32 +03001147# IronPython covering 2.6 and 2.7
1148_ironpython26_sys_version_parser = re.compile(
1149 r'([\d.]+)\s*'
1150 '\(IronPython\s*'
1151 '[\d.]+\s*'
1152 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1153)
1154
Benjamin Petersone549ead2009-03-28 21:42:05 +00001155_pypy_sys_version_parser = re.compile(
1156 r'([\w.+]+)\s*'
1157 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1158 '\[PyPy [^\]]+\]?')
1159
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001160_sys_version_cache = {}
1161
1162def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001163
1164 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001165 (name, version, branch, revision, buildno, builddate, compiler)
1166 referring to the Python implementation name, version, branch,
1167 revision, build number, build date/time as string and the compiler
1168 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001169
1170 Note that unlike the Python sys.version, the returned value
1171 for the Python version will always include the patchlevel (it
1172 defaults to '.0').
1173
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001174 The function returns empty strings for tuple entries that
1175 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001176
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001177 sys_version may be given to parse an alternative version
1178 string, e.g. if the version was read from a different Python
1179 interpreter.
1180
1181 """
1182 # Get the Python version
1183 if sys_version is None:
1184 sys_version = sys.version
1185
1186 # Try the cache first
1187 result = _sys_version_cache.get(sys_version, None)
1188 if result is not None:
1189 return result
1190
1191 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001192 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001193 # IronPython
1194 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001195 if sys_version.startswith('IronPython'):
1196 match = _ironpython_sys_version_parser.match(sys_version)
1197 else:
1198 match = _ironpython26_sys_version_parser.match(sys_version)
1199
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001200 if match is None:
1201 raise ValueError(
1202 'failed to parse IronPython sys.version: %s' %
1203 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001204
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001205 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001206 buildno = ''
1207 builddate = ''
1208
Ezio Melottif076f532013-10-21 03:03:32 +03001209 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001210 # Jython
1211 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001212 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001213 if match is None:
1214 raise ValueError(
1215 'failed to parse Jython sys.version: %s' %
1216 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001217 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001218 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001219
1220 elif "PyPy" in sys_version:
1221 # PyPy
1222 name = "PyPy"
1223 match = _pypy_sys_version_parser.match(sys_version)
1224 if match is None:
1225 raise ValueError("failed to parse PyPy sys.version: %s" %
1226 repr(sys_version))
1227 version, buildno, builddate, buildtime = match.groups()
1228 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001229
1230 else:
1231 # CPython
1232 match = _sys_version_parser.match(sys_version)
1233 if match is None:
1234 raise ValueError(
1235 'failed to parse CPython sys.version: %s' %
1236 repr(sys_version))
1237 version, buildno, builddate, buildtime, compiler = \
1238 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001239 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001240 builddate = builddate + ' ' + buildtime
1241
Georg Brandl82562422011-03-05 21:09:22 +01001242 if hasattr(sys, '_mercurial'):
1243 _, branch, revision = sys._mercurial
1244 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001245 # sys.subversion was added in Python 2.5
1246 _, branch, revision = sys.subversion
1247 else:
1248 branch = ''
1249 revision = ''
1250
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001251 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001252 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001253 if len(l) == 2:
1254 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001255 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001256
1257 # Build and cache the result
1258 result = (name, version, branch, revision, buildno, builddate, compiler)
1259 _sys_version_cache[sys_version] = result
1260 return result
1261
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001262def python_implementation():
1263
1264 """ Returns a string identifying the Python implementation.
1265
1266 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001267 'CPython' (C implementation of Python),
1268 'IronPython' (.NET implementation of Python),
1269 'Jython' (Java implementation of Python),
1270 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001271
1272 """
1273 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001274
1275def python_version():
1276
1277 """ Returns the Python version as string 'major.minor.patchlevel'
1278
1279 Note that unlike the Python sys.version, the returned value
1280 will always include the patchlevel (it defaults to 0).
1281
1282 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001283 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001284
1285def python_version_tuple():
1286
1287 """ Returns the Python version as tuple (major, minor, patchlevel)
1288 of strings.
1289
1290 Note that unlike the Python sys.version, the returned value
1291 will always include the patchlevel (it defaults to 0).
1292
1293 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001294 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001295
1296def python_branch():
1297
1298 """ Returns a string identifying the Python implementation
1299 branch.
1300
1301 For CPython this is the Subversion branch from which the
1302 Python binary was built.
1303
1304 If not available, an empty string is returned.
1305
1306 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001307
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001308 return _sys_version()[2]
1309
1310def python_revision():
1311
1312 """ Returns a string identifying the Python implementation
1313 revision.
1314
1315 For CPython this is the Subversion revision from which the
1316 Python binary was built.
1317
1318 If not available, an empty string is returned.
1319
1320 """
1321 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001322
1323def python_build():
1324
1325 """ Returns a tuple (buildno, builddate) stating the Python
1326 build number and date as strings.
1327
1328 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001329 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001330
1331def python_compiler():
1332
1333 """ Returns a string identifying the compiler used for compiling
1334 Python.
1335
1336 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001337 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001338
1339### The Opus Magnum of platform strings :-)
1340
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001341_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001342
1343def platform(aliased=0, terse=0):
1344
1345 """ Returns a single string identifying the underlying platform
1346 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001347
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001348 The output is intended to be human readable rather than
1349 machine parseable. It may look different on different
1350 platforms and this is intended.
1351
1352 If "aliased" is true, the function will use aliases for
1353 various platforms that report system names which differ from
1354 their common names, e.g. SunOS will be reported as
1355 Solaris. The system_alias() function is used to implement
1356 this.
1357
1358 Setting terse to true causes the function to return only the
1359 absolute minimum information needed to identify the platform.
1360
1361 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001362 result = _platform_cache.get((aliased, terse), None)
1363 if result is not None:
1364 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001365
1366 # Get uname information and then apply platform specific cosmetics
1367 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001368 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001369 if machine == processor:
1370 processor = ''
1371 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001372 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001373
1374 if system == 'Windows':
1375 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001376 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001377 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001378 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001379 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001380 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001381
1382 elif system in ('Linux',):
1383 # Linux based systems
Victor Stinnerced39362013-12-09 00:14:52 +01001384 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001385 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001386 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001387 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001388 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001389 else:
1390 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001391 libcname, libcversion = libc_ver(sys.executable)
1392 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001393 'with',
1394 libcname+libcversion)
1395 elif system == 'Java':
1396 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001397 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001398 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001399 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001400 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001401 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001402 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001403 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001404
1405 elif system == 'MacOS':
1406 # MacOS platforms
1407 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001408 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001409 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001410 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001411
1412 else:
1413 # Generic handler
1414 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001415 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001416 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001417 bits, linkage = architecture(sys.executable)
1418 platform = _platform(system, release, machine,
1419 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001420
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001421 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001422 return platform
1423
1424### Command line interface
1425
1426if __name__ == '__main__':
1427 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001428 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001429 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001430 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001431 sys.exit(0)