blob: f3d2c423875a53c024dd00759da2f69097be8467 [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 Dowerb9f4fea2015-09-22 17:23:39 -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 Dowerb9f4fea2015-09-22 17:23:39 -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
Berker Peksag1392f712015-05-16 20:24:28 +0300119import warnings
120
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000121### Globals & Constants
122
123# Determine the platform's /dev/null device
124try:
125 DEV_NULL = os.devnull
126except AttributeError:
127 # os.devnull was added in Python 2.4, so emulate it for earlier
128 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100129 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000130 # Use the old CP/M NUL as device name
131 DEV_NULL = 'NUL'
132 else:
133 # Standard Unix uses /dev/null
134 DEV_NULL = '/dev/null'
135
Victor Stinner620c48b2013-12-09 00:01:27 +0100136# Directory to search for configuration information on Unix.
137# Constant used by test_platform to test linux_distribution().
138_UNIXCONFDIR = '/etc'
139
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000140### Platform specific APIs
141
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200142_libc_search = re.compile(b'(__libc_init)'
143 b'|'
144 b'(GLIBC_([0-9.]+))'
145 b'|'
146 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000147
Victor Stinnerced39362013-12-09 00:14:52 +0100148def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000149
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200150 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000151
Brett Cannon8ab27df2003-08-05 03:52:04 +0000152 """ Tries to determine the libc version that the file executable
153 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000154
155 Returns a tuple of strings (lib,version) which default to the
156 given parameters in case the lookup fails.
157
158 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000159 libc versions add symbols to the executable and thus is probably
160 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000161
162 The file is read and scanned in chunks of chunksize bytes.
163
164 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000165 if hasattr(os.path, 'realpath'):
166 # Python 2.2 introduced os.path.realpath(); it is used
167 # here to work around problems with Cygwin not being
168 # able to open symlinks for reading
169 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300170 with open(executable, 'rb') as f:
171 binary = f.read(chunksize)
172 pos = 0
173 while 1:
174 if b'libc' in binary or b'GLIBC' in binary:
175 m = _libc_search.search(binary, pos)
176 else:
177 m = None
178 if not m:
179 binary = f.read(chunksize)
180 if not binary:
181 break
182 pos = 0
183 continue
184 libcinit, glibc, glibcversion, so, threads, soversion = [
185 s.decode('latin1') if s is not None else s
186 for s in m.groups()]
187 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000188 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300189 elif glibc:
190 if lib != 'glibc':
191 lib = 'glibc'
192 version = glibcversion
193 elif glibcversion > version:
194 version = glibcversion
195 elif so:
196 if lib != 'glibc':
197 lib = 'libc'
198 if soversion and soversion > version:
199 version = soversion
200 if threads and version[-len(threads):] != threads:
201 version = version + threads
202 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100203 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000204
Victor Stinnerced39362013-12-09 00:14:52 +0100205def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000206
Tim Peters0eadaac2003-04-24 16:02:54 +0000207 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000208 information in case the default method fails.
209
210 Currently supports older SuSE Linux, Caldera OpenLinux and
211 Slackware Linux distributions.
212
213 """
214 if os.path.exists('/var/adm/inst-log/info'):
215 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000216 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000217 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000218 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000219 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100220 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000221 else:
222 continue
223 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000224 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000225 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000226 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000227 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100228 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000229
230 if os.path.exists('/etc/.installed'):
231 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000232 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000233 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000234 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
235 # XXX does Caldera support non Intel platforms ? If yes,
236 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100237 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000238
239 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300240 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000241 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000242 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000243 if verfiles[n][:14] != 'slack-version-':
244 del verfiles[n]
245 if verfiles:
246 verfiles.sort()
247 distname = 'slackware'
248 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100249 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000250
Victor Stinnerced39362013-12-09 00:14:52 +0100251 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000252
Antoine Pitroufd036452008-08-19 17:56:33 +0000253_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000254_lsb_release_version = re.compile(r'(.+)'
255 ' release '
256 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000257 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000258_release_version = re.compile(r'([^0-9]+)'
259 '(?: release )?'
260 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000261 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000262
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000263# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000264# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000265# and http://data.linux-ntfs.org/rpm/whichrpm
266# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000267
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000268_supported_dists = (
269 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
270 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200271 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000272
273def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000274
Benjamin Peterson25001472010-01-25 03:37:42 +0000275 # Default to empty 'version' and 'id' strings. Both defaults are used
276 # when 'firstline' is empty. 'id' defaults to empty when an id can not
277 # be deduced.
278 version = ''
279 id = ''
280
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000281 # Parse the first line
282 m = _lsb_release_version.match(firstline)
283 if m is not None:
284 # LSB format: "distro release x.x (codename)"
285 return tuple(m.groups())
286
287 # Pre-LSB format: "distro x.x (codename)"
288 m = _release_version.match(firstline)
289 if m is not None:
290 return tuple(m.groups())
291
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300292 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000293 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000294 if l:
295 version = l[0]
296 if len(l) > 1:
297 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000298 return '', version, id
299
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000300def linux_distribution(distname='', version='', id='',
301
302 supported_dists=_supported_dists,
303 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300304 import warnings
305 warnings.warn("dist() and linux_distribution() functions are deprecated "
306 "in Python 3.5 and will be removed in Python 3.7",
307 PendingDeprecationWarning, stacklevel=2)
308 return _linux_distribution(distname, version, id, supported_dists,
309 full_distribution_name)
310
311def _linux_distribution(distname, version, id, supported_dists,
312 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000313
314 """ Tries to determine the name of the Linux OS distribution name.
315
316 The function first looks for a distribution release file in
317 /etc and then reverts to _dist_try_harder() in case no
318 suitable files are found.
319
320 supported_dists may be given to define the set of Linux
321 distributions to look for. It defaults to a list of currently
322 supported Linux distributions identified by their release file
323 name.
324
325 If full_distribution_name is true (default), the full
326 distribution read from the OS is returned. Otherwise the short
327 name taken from supported_dists is used.
328
Victor Stinnerced39362013-12-09 00:14:52 +0100329 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000330 args given as parameters.
331
332 """
333 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100334 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200335 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000336 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100337 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000338 etc.sort()
339 for file in etc:
340 m = _release_filename.match(file)
341 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100342 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000343 if _distname in supported_dists:
344 distname = _distname
345 break
346 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100347 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000348
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000349 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100350 with open(os.path.join(_UNIXCONFDIR, file), 'r',
351 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000352 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000353 _distname, _version, _id = _parse_release_file(firstline)
354
355 if _distname and full_distribution_name:
356 distname = _distname
357 if _version:
358 version = _version
359 if _id:
360 id = _id
361 return distname, version, id
362
363# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000364
Victor Stinnerced39362013-12-09 00:14:52 +0100365def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000366
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000367 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000368
Brett Cannon8ab27df2003-08-05 03:52:04 +0000369 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000370
371 The function first looks for a distribution release file in
372 /etc and then reverts to _dist_try_harder() in case no
373 suitable files are found.
374
Victor Stinnerced39362013-12-09 00:14:52 +0100375 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000376 args given as parameters.
377
378 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300379 import warnings
380 warnings.warn("dist() and linux_distribution() functions are deprecated "
381 "in Python 3.5 and will be removed in Python 3.7",
382 PendingDeprecationWarning, stacklevel=2)
383 return _linux_distribution(distname, version, id,
384 supported_dists=supported_dists,
385 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000386
Antoine Pitrou877766d2011-03-19 17:00:37 +0100387def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000388
389 """ Portable popen() interface.
390 """
Victor Stinner25000d42011-05-24 00:16:16 +0200391 import warnings
392 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000393 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000394
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000395def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000396
Brett Cannon8ab27df2003-08-05 03:52:04 +0000397 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000398 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000399 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000400 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000401 if build:
402 l.append(build)
403 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100404 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000405 except ValueError:
406 strings = l
407 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100408 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000409 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000410 return version
411
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000412_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
413 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000414 '\[.* ([\d.]+)\])')
415
416# Examples of VER command output:
417#
418# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
419# Windows XP: Microsoft Windows XP [Version 5.1.2600]
420# Windows Vista: Microsoft Windows [Version 6.0.6002]
421#
422# Note that the "Version" string gets localized on different
423# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000424
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000425def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000426
Victor Stinnerced39362013-12-09 00:14:52 +0100427 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000428
429 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100430 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000431
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000432 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200433 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000434
435 In case this fails, the given parameters are used as
436 defaults.
437
438 """
439 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100440 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441
442 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100443 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000444 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700445 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000446 info = pipe.read()
447 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200448 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200449 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000450 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200451 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100452 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000453 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000454 else:
455 break
456 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100457 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458
459 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000460 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000461 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000462 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100463 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000464 # Strip trailing dots from version and release
465 if release[-1] == '.':
466 release = release[:-1]
467 if version[-1] == '.':
468 version = version[:-1]
469 # Normalize the version and build strings (eliminating additional
470 # zeros)
471 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100472 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000473
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700474_WIN32_CLIENT_RELEASES = {
475 (5, 0): "2000",
476 (5, 1): "XP",
477 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
478 # has always called it 2003 Server
479 (5, 2): "2003Server",
480 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000481
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700482 (6, 0): "Vista",
483 (6, 1): "7",
484 (6, 2): "8",
485 (6, 3): "8.1",
486 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000487
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700488 (10, 0): "10",
489 (10, None): "post10",
490}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000491
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700492# Server release name lookup will default to client names if necessary
493_WIN32_SERVER_RELEASES = {
494 (5, 2): "2003Server",
495
496 (6, 0): "2008Server",
497 (6, 1): "2008ServerR2",
498 (6, 2): "2012Server",
499 (6, 3): "2012ServerR2",
500 (6, None): "post2012ServerR2",
501}
502
503def _get_real_winver(maj, min, build):
504 if maj < 6 or (maj == 6 and min < 2):
505 return maj, min, build
506
507 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
508 Structure, WinDLL)
509 from ctypes.wintypes import DWORD, HANDLE
510
511 class VS_FIXEDFILEINFO(Structure):
512 _fields_ = [
513 ("dwSignature", DWORD),
514 ("dwStrucVersion", DWORD),
515 ("dwFileVersionMS", DWORD),
516 ("dwFileVersionLS", DWORD),
517 ("dwProductVersionMS", DWORD),
518 ("dwProductVersionLS", DWORD),
519 ("dwFileFlagsMask", DWORD),
520 ("dwFileFlags", DWORD),
521 ("dwFileOS", DWORD),
522 ("dwFileType", DWORD),
523 ("dwFileSubtype", DWORD),
524 ("dwFileDateMS", DWORD),
525 ("dwFileDateLS", DWORD),
526 ]
527
528 kernel32 = WinDLL('kernel32')
529 version = WinDLL('version')
530
531 # We will immediately double the length up to MAX_PATH, but the
532 # path may be longer, so we retry until the returned string is
533 # shorter than our buffer.
534 name_len = actual_len = 130
535 while actual_len == name_len:
536 name_len *= 2
537 name = create_unicode_buffer(name_len)
538 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
539 name, len(name))
540 if not actual_len:
541 return maj, min, build
542
543 size = version.GetFileVersionInfoSizeW(name, None)
544 if not size:
545 return maj, min, build
546
547 ver_block = c_buffer(size)
548 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
549 not ver_block):
550 return maj, min, build
551
552 pvi = POINTER(VS_FIXEDFILEINFO)()
553 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
554 return maj, min, build
555
556 maj = pvi.contents.dwProductVersionMS >> 16
557 min = pvi.contents.dwProductVersionMS & 0xFFFF
558 build = pvi.contents.dwProductVersionLS >> 16
559
560 return maj, min, build
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000561
Victor Stinnerced39362013-12-09 00:14:52 +0100562def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700563 try:
564 from sys import getwindowsversion
565 except ImportError:
566 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000567 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700568 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400569 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700570 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
571
572 winver = getwindowsversion()
573 maj, min, build = _get_real_winver(*winver[:3])
574 version = '{0}.{1}.{2}'.format(maj, min, build)
575
576 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
577 _WIN32_CLIENT_RELEASES.get((maj, None)) or
578 release)
579
580 # getwindowsversion() reflect the compatibility mode Python is
581 # running under, and so the service pack value is only going to be
582 # valid if the versions match.
583 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000584 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700585 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000586 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700587 if csd[:13] == 'Service Pack ':
588 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000589
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700590 # VER_NT_SERVER = 3
591 if getattr(winver, 'product_type', None) == 3:
592 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
593 _WIN32_SERVER_RELEASES.get((maj, None)) or
594 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000595
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700596 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000597 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700598 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
599 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
600 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000601 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700602 pass
603 finally:
604 if key:
605 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000606
Victor Stinnerced39362013-12-09 00:14:52 +0100607 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000608
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700609
Ronald Oussorene186e382010-07-23 11:54:59 +0000610def _mac_ver_xml():
611 fn = '/System/Library/CoreServices/SystemVersion.plist'
612 if not os.path.exists(fn):
613 return None
614
615 try:
616 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400617 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000618 return None
619
Ned Deily936dfae2014-01-13 11:34:19 -0800620 with open(fn, 'rb') as f:
621 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000622 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100623 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700624 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000625 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300626 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000627 machine = 'PowerPC'
628
Victor Stinnerced39362013-12-09 00:14:52 +0100629 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000630
631
Victor Stinnerced39362013-12-09 00:14:52 +0100632def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000633
634 """ Get MacOS version information and return it as tuple (release,
635 versioninfo, machine) with versioninfo being a tuple (version,
636 dev_stage, non_release_version).
637
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300638 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000639 which default to ''. All tuple entries are strings.
640 """
641
642 # First try reading the information from an XML file which should
643 # always be present
644 info = _mac_ver_xml()
645 if info is not None:
646 return info
647
Ronald Oussorene186e382010-07-23 11:54:59 +0000648 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100649 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650
Victor Stinnerced39362013-12-09 00:14:52 +0100651def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652
653 from java.lang import System
654 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000655 value = System.getProperty(name)
656 if value is None:
657 return default
658 return value
659 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000660 return default
661
Victor Stinnerced39362013-12-09 00:14:52 +0100662def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000663
Brett Cannon8ab27df2003-08-05 03:52:04 +0000664 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665
Victor Stinnerced39362013-12-09 00:14:52 +0100666 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
667 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
668 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000669
670 Values which cannot be determined are set to the defaults
671 given as parameters (which all default to '').
672
673 """
674 # Import the needed APIs
675 try:
676 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400677 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100678 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000679
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000680 vendor = _java_getprop('java.vendor', vendor)
681 release = _java_getprop('java.version', release)
682 vm_name, vm_release, vm_vendor = vminfo
683 vm_name = _java_getprop('java.vm.name', vm_name)
684 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
685 vm_release = _java_getprop('java.vm.version', vm_release)
686 vminfo = vm_name, vm_release, vm_vendor
687 os_name, os_version, os_arch = osinfo
688 os_arch = _java_getprop('java.os.arch', os_arch)
689 os_name = _java_getprop('java.os.name', os_name)
690 os_version = _java_getprop('java.os.version', os_version)
691 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000692
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000693 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000694
695### System name aliasing
696
Victor Stinnerced39362013-12-09 00:14:52 +0100697def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000698
Victor Stinnerced39362013-12-09 00:14:52 +0100699 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000700 marketing names used for some systems.
701
702 It also does some reordering of the information in some cases
703 where it would otherwise cause confusion.
704
705 """
706 if system == 'Rhapsody':
707 # Apple's BSD derivative
708 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100709 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000710
711 elif system == 'SunOS':
712 # Sun's OS
713 if release < '5':
714 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100715 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000716 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000717 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000718 if l:
719 try:
720 major = int(l[0])
721 except ValueError:
722 pass
723 else:
724 major = major - 3
725 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000726 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000727 if release < '6':
728 system = 'Solaris'
729 else:
730 # XXX Whatever the new SunOS marketing name is...
731 system = 'Solaris'
732
733 elif system == 'IRIX64':
734 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
735 # is really a version and not a different platform, since 32-bit
736 # apps are also supported..
737 system = 'IRIX'
738 if version:
739 version = version + ' (64bit)'
740 else:
741 version = '64bit'
742
Victor Stinnerced39362013-12-09 00:14:52 +0100743 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744 # In case one of the other tricks
745 system = 'Windows'
746
Victor Stinnerced39362013-12-09 00:14:52 +0100747 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000748
749### Various internal helpers
750
751def _platform(*args):
752
753 """ Helper to format the platform string in a filename
754 compatible format e.g. "system-version-machine".
755 """
756 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000757 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000758
759 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100760 platform = platform.replace(' ', '_')
761 platform = platform.replace('/', '-')
762 platform = platform.replace('\\', '-')
763 platform = platform.replace(':', '-')
764 platform = platform.replace(';', '-')
765 platform = platform.replace('"', '-')
766 platform = platform.replace('(', '-')
767 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000768
769 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100770 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000771
772 # Fold '--'s and remove trailing '-'
773 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100774 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000775 if cleaned == platform:
776 break
777 platform = cleaned
778 while platform[-1] == '-':
779 platform = platform[:-1]
780
781 return platform
782
783def _node(default=''):
784
785 """ Helper to determine the node name of this machine.
786 """
787 try:
788 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400789 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000790 # No sockets...
791 return default
792 try:
793 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200794 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000795 # Still not working...
796 return default
797
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000798def _follow_symlinks(filepath):
799
800 """ In case filepath is a symlink, follow it until a
801 real file is reached.
802 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000803 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000804 while os.path.islink(filepath):
805 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100806 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000807 return filepath
808
Victor Stinnerced39362013-12-09 00:14:52 +0100809def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000810
811 """ Interface to the system's uname command.
812 """
Victor Stinnerced39362013-12-09 00:14:52 +0100813 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000814 # XXX Others too ?
815 return default
816 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000817 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200818 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000819 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000820 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821 rc = f.close()
822 if not output or rc:
823 return default
824 else:
825 return output
826
Victor Stinnerced39362013-12-09 00:14:52 +0100827def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000828
829 """ Interface to the system's file command.
830
831 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000832 omit the filename in its output. Follow the symlinks. It returns
833 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000834
835 """
Victor Stinnerced39362013-12-09 00:14:52 +0100836 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000837 # XXX Others too ?
838 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200839 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200841 proc = subprocess.Popen(['file', target],
842 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200843
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200844 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000845 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200846 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200847 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000848 if not output or rc:
849 return default
850 else:
851 return output
852
853### Information about the used architecture
854
855# Default values for architecture; non-empty strings override the
856# defaults given as parameters
857_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100858 'win32': ('', 'WindowsPE'),
859 'win16': ('', 'Windows'),
860 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000861}
862
Victor Stinnerced39362013-12-09 00:14:52 +0100863def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000864
865 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000866 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000867
Victor Stinnerced39362013-12-09 00:14:52 +0100868 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000869 the bit architecture and the linkage format used for the
870 executable. Both values are returned as strings.
871
872 Values that cannot be determined are returned as given by the
873 parameter presets. If bits is given as '', the sizeof(pointer)
874 (or sizeof(long) on Python version < 1.5.2) is used as
875 indicator for the supported pointer size.
876
877 The function relies on the system's "file" command to do the
878 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000879 platforms. On some non-Unix platforms where the "file" command
880 does not exist and the executable is set to the Python interpreter
881 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000882
883 """
884 # Use the sizeof(pointer) as default number of bits if nothing
885 # else is given as default.
886 if not bits:
887 import struct
888 try:
889 size = struct.calcsize('P')
890 except struct.error:
891 # Older installations can only query longs
892 size = struct.calcsize('l')
893 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000894
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000895 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000896 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000897 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000898 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000899 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000900
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000901 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000902 executable == sys.executable:
903 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000904 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000905 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100906 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000907 if b:
908 bits = b
909 if l:
910 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100911 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000912
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000913 if 'executable' not in fileout:
914 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100915 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000916
917 # Bits
918 if '32-bit' in fileout:
919 bits = '32bit'
920 elif 'N32' in fileout:
921 # On Irix only
922 bits = 'n32bit'
923 elif '64-bit' in fileout:
924 bits = '64bit'
925
926 # Linkage
927 if 'ELF' in fileout:
928 linkage = 'ELF'
929 elif 'PE' in fileout:
930 # E.g. Windows uses this format
931 if 'Windows' in fileout:
932 linkage = 'WindowsPE'
933 else:
934 linkage = 'PE'
935 elif 'COFF' in fileout:
936 linkage = 'COFF'
937 elif 'MS-DOS' in fileout:
938 linkage = 'MSDOS'
939 else:
940 # XXX the A.OUT format also falls under this class...
941 pass
942
Victor Stinnerced39362013-12-09 00:14:52 +0100943 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000944
945### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000946
Larry Hastings68386bc2012-06-24 14:30:41 -0700947uname_result = collections.namedtuple("uname_result",
948 "system node release version machine processor")
949
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000950_uname_cache = None
951
952def uname():
953
954 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100955 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000956 identifying the underlying platform.
957
958 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000959 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000960
961 Entries which cannot be determined are set to ''.
962
963 """
964 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000965 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000966
967 if _uname_cache is not None:
968 return _uname_cache
969
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000970 processor = ''
971
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000972 # Get some infos from the builtin os.uname API...
973 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100974 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000975 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000976 no_os_uname = 1
977
Georg Brandl62e2ca22010-07-31 21:54:24 +0000978 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000979 # Hmm, no there is either no uname or uname has returned
980 #'unknowns'... we'll have to poke around the system then.
981 if no_os_uname:
982 system = sys.platform
983 release = ''
984 version = ''
985 node = _node()
986 machine = ''
987
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000988 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000989
990 # Try win32_ver() on win32 platforms
991 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100992 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000993 if release and version:
994 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000995 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000996 # available on Win XP and later; see
997 # http://support.microsoft.com/kb/888731 and
998 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000999 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001000 # WOW64 processes mask the native architecture
1001 if "PROCESSOR_ARCHITEW6432" in os.environ:
1002 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1003 else:
1004 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001005 if not processor:
1006 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001007
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001008 # Try the 'ver' system command available on some
1009 # platforms
1010 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +01001011 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001012 # Normalize system to what win32_ver() normally returns
1013 # (_syscmd_ver() tends to return the vendor name as well)
1014 if system == 'Microsoft Windows':
1015 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001016 elif system == 'Microsoft' and release == 'Windows':
1017 # Under Windows Vista and Windows Server 2008,
1018 # Microsoft changed the output of the ver command. The
1019 # release is no longer printed. This causes the
1020 # system and release to be misidentified.
1021 system = 'Windows'
1022 if '6.0' == version[:3]:
1023 release = 'Vista'
1024 else:
1025 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001026
1027 # In case we still don't know anything useful, we'll try to
1028 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001029 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001030 if not version:
1031 if system == 'win32':
1032 version = '32bit'
1033 else:
1034 version = '16bit'
1035 system = 'Windows'
1036
1037 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001038 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001039 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001040 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001041 if not version:
1042 version = vendor
1043
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001044 # System specific extensions
1045 if system == 'OpenVMS':
1046 # OpenVMS seems to have release and version mixed up
1047 if not release or release == '0':
1048 release = version
1049 version = ''
1050 # Get processor information
1051 try:
1052 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001053 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001054 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001055 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001056 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001057 if (cpu_number >= 128):
1058 processor = 'Alpha'
1059 else:
1060 processor = 'VAX'
1061 if not processor:
1062 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001063 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001065 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001066 if system == 'unknown':
1067 system = ''
1068 if node == 'unknown':
1069 node = ''
1070 if release == 'unknown':
1071 release = ''
1072 if version == 'unknown':
1073 version = ''
1074 if machine == 'unknown':
1075 machine = ''
1076 if processor == 'unknown':
1077 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001078
1079 # normalize name
1080 if system == 'Microsoft' and release == 'Windows':
1081 system = 'Windows'
1082 release = 'Vista'
1083
Victor Stinnerced39362013-12-09 00:14:52 +01001084 _uname_cache = uname_result(system, node, release, version,
1085 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001086 return _uname_cache
1087
1088### Direct interfaces to some of the uname() return values
1089
1090def system():
1091
1092 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1093
1094 An empty string is returned if the value cannot be determined.
1095
1096 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001097 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001098
1099def node():
1100
Brett Cannon8ab27df2003-08-05 03:52:04 +00001101 """ Returns the computer's network name (which may not be fully
1102 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001103
1104 An empty string is returned if the value cannot be determined.
1105
1106 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001107 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001108
1109def release():
1110
1111 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1112
1113 An empty string is returned if the value cannot be determined.
1114
1115 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001116 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001117
1118def version():
1119
1120 """ Returns the system's release version, e.g. '#3 on degas'
1121
1122 An empty string is returned if the value cannot be determined.
1123
1124 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001125 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001126
1127def machine():
1128
1129 """ Returns the machine type, e.g. 'i386'
1130
1131 An empty string is returned if the value cannot be determined.
1132
1133 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001134 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001135
1136def processor():
1137
1138 """ Returns the (true) processor name, e.g. 'amdk6'
1139
1140 An empty string is returned if the value cannot be
1141 determined. Note that many platforms do not provide this
1142 information or simply return the same value as for machine(),
1143 e.g. NetBSD does this.
1144
1145 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001146 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001147
1148### Various APIs for extracting information from sys.version
1149
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001150_sys_version_parser = re.compile(
1151 r'([\w.+]+)\s*'
1152 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001153 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001154
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001155_ironpython_sys_version_parser = re.compile(
1156 r'IronPython\s*'
1157 '([\d\.]+)'
1158 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001159 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001160
Ezio Melottif076f532013-10-21 03:03:32 +03001161# IronPython covering 2.6 and 2.7
1162_ironpython26_sys_version_parser = re.compile(
1163 r'([\d.]+)\s*'
1164 '\(IronPython\s*'
1165 '[\d.]+\s*'
1166 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1167)
1168
Benjamin Petersone549ead2009-03-28 21:42:05 +00001169_pypy_sys_version_parser = re.compile(
1170 r'([\w.+]+)\s*'
1171 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1172 '\[PyPy [^\]]+\]?')
1173
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001174_sys_version_cache = {}
1175
1176def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177
1178 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001179 (name, version, branch, revision, buildno, builddate, compiler)
1180 referring to the Python implementation name, version, branch,
1181 revision, build number, build date/time as string and the compiler
1182 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001183
1184 Note that unlike the Python sys.version, the returned value
1185 for the Python version will always include the patchlevel (it
1186 defaults to '.0').
1187
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001188 The function returns empty strings for tuple entries that
1189 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001190
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001191 sys_version may be given to parse an alternative version
1192 string, e.g. if the version was read from a different Python
1193 interpreter.
1194
1195 """
1196 # Get the Python version
1197 if sys_version is None:
1198 sys_version = sys.version
1199
1200 # Try the cache first
1201 result = _sys_version_cache.get(sys_version, None)
1202 if result is not None:
1203 return result
1204
1205 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001206 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001207 # IronPython
1208 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001209 if sys_version.startswith('IronPython'):
1210 match = _ironpython_sys_version_parser.match(sys_version)
1211 else:
1212 match = _ironpython26_sys_version_parser.match(sys_version)
1213
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001214 if match is None:
1215 raise ValueError(
1216 'failed to parse IronPython sys.version: %s' %
1217 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001218
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001219 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001220 buildno = ''
1221 builddate = ''
1222
Ezio Melottif076f532013-10-21 03:03:32 +03001223 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001224 # Jython
1225 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001226 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001227 if match is None:
1228 raise ValueError(
1229 'failed to parse Jython sys.version: %s' %
1230 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001231 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001232 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001233
1234 elif "PyPy" in sys_version:
1235 # PyPy
1236 name = "PyPy"
1237 match = _pypy_sys_version_parser.match(sys_version)
1238 if match is None:
1239 raise ValueError("failed to parse PyPy sys.version: %s" %
1240 repr(sys_version))
1241 version, buildno, builddate, buildtime = match.groups()
1242 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001243
1244 else:
1245 # CPython
1246 match = _sys_version_parser.match(sys_version)
1247 if match is None:
1248 raise ValueError(
1249 'failed to parse CPython sys.version: %s' %
1250 repr(sys_version))
1251 version, buildno, builddate, buildtime, compiler = \
1252 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001253 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001254 builddate = builddate + ' ' + buildtime
1255
Georg Brandl82562422011-03-05 21:09:22 +01001256 if hasattr(sys, '_mercurial'):
1257 _, branch, revision = sys._mercurial
1258 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001259 # sys.subversion was added in Python 2.5
1260 _, branch, revision = sys.subversion
1261 else:
1262 branch = ''
1263 revision = ''
1264
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001265 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001266 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001267 if len(l) == 2:
1268 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001269 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001270
1271 # Build and cache the result
1272 result = (name, version, branch, revision, buildno, builddate, compiler)
1273 _sys_version_cache[sys_version] = result
1274 return result
1275
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001276def python_implementation():
1277
1278 """ Returns a string identifying the Python implementation.
1279
1280 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001281 'CPython' (C implementation of Python),
1282 'IronPython' (.NET implementation of Python),
1283 'Jython' (Java implementation of Python),
1284 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001285
1286 """
1287 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001288
1289def python_version():
1290
1291 """ Returns the Python version as string 'major.minor.patchlevel'
1292
1293 Note that unlike the Python sys.version, the returned value
1294 will always include the patchlevel (it defaults to 0).
1295
1296 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001297 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001298
1299def python_version_tuple():
1300
1301 """ Returns the Python version as tuple (major, minor, patchlevel)
1302 of strings.
1303
1304 Note that unlike the Python sys.version, the returned value
1305 will always include the patchlevel (it defaults to 0).
1306
1307 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001308 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001309
1310def python_branch():
1311
1312 """ Returns a string identifying the Python implementation
1313 branch.
1314
1315 For CPython this is the Subversion branch from which the
1316 Python binary was built.
1317
1318 If not available, an empty string is returned.
1319
1320 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001321
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001322 return _sys_version()[2]
1323
1324def python_revision():
1325
1326 """ Returns a string identifying the Python implementation
1327 revision.
1328
1329 For CPython this is the Subversion revision from which the
1330 Python binary was built.
1331
1332 If not available, an empty string is returned.
1333
1334 """
1335 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001336
1337def python_build():
1338
1339 """ Returns a tuple (buildno, builddate) stating the Python
1340 build number and date as strings.
1341
1342 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001343 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001344
1345def python_compiler():
1346
1347 """ Returns a string identifying the compiler used for compiling
1348 Python.
1349
1350 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001351 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001352
1353### The Opus Magnum of platform strings :-)
1354
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001355_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001356
1357def platform(aliased=0, terse=0):
1358
1359 """ Returns a single string identifying the underlying platform
1360 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001361
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001362 The output is intended to be human readable rather than
1363 machine parseable. It may look different on different
1364 platforms and this is intended.
1365
1366 If "aliased" is true, the function will use aliases for
1367 various platforms that report system names which differ from
1368 their common names, e.g. SunOS will be reported as
1369 Solaris. The system_alias() function is used to implement
1370 this.
1371
1372 Setting terse to true causes the function to return only the
1373 absolute minimum information needed to identify the platform.
1374
1375 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001376 result = _platform_cache.get((aliased, terse), None)
1377 if result is not None:
1378 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001379
1380 # Get uname information and then apply platform specific cosmetics
1381 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001382 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001383 if machine == processor:
1384 processor = ''
1385 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001386 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001387
1388 if system == 'Windows':
1389 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001390 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001391 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001392 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001393 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001394 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001395
1396 elif system in ('Linux',):
1397 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001398 with warnings.catch_warnings():
1399 # see issue #1322 for more information
1400 warnings.filterwarnings(
1401 'ignore',
1402 'dist\(\) and linux_distribution\(\) '
1403 'functions are deprecated .*',
1404 PendingDeprecationWarning,
1405 )
1406 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001407 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001408 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001409 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001410 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001411 else:
1412 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001413 libcname, libcversion = libc_ver(sys.executable)
1414 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001415 'with',
1416 libcname+libcversion)
1417 elif system == 'Java':
1418 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001419 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001420 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001421 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001422 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001423 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001424 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001425 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001426
1427 elif system == 'MacOS':
1428 # MacOS platforms
1429 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001430 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001431 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001432 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001433
1434 else:
1435 # Generic handler
1436 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001437 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001438 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001439 bits, linkage = architecture(sys.executable)
1440 platform = _platform(system, release, machine,
1441 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001442
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001443 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001444 return platform
1445
1446### Command line interface
1447
1448if __name__ == '__main__':
1449 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001450 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001451 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001452 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001453 sys.exit(0)