blob: 3e726a7856ff98b266df11ff000f03cf84625158 [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
Martin Pantereb995702016-07-28 01:11:04 +000064# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000065# 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 "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300306 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300307 return _linux_distribution(distname, version, id, supported_dists,
308 full_distribution_name)
309
310def _linux_distribution(distname, version, id, supported_dists,
311 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000312
313 """ Tries to determine the name of the Linux OS distribution name.
314
315 The function first looks for a distribution release file in
316 /etc and then reverts to _dist_try_harder() in case no
317 suitable files are found.
318
319 supported_dists may be given to define the set of Linux
320 distributions to look for. It defaults to a list of currently
321 supported Linux distributions identified by their release file
322 name.
323
324 If full_distribution_name is true (default), the full
325 distribution read from the OS is returned. Otherwise the short
326 name taken from supported_dists is used.
327
Victor Stinnerced39362013-12-09 00:14:52 +0100328 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000329 args given as parameters.
330
331 """
332 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100333 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200334 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000335 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100336 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000337 etc.sort()
338 for file in etc:
339 m = _release_filename.match(file)
340 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100341 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000342 if _distname in supported_dists:
343 distname = _distname
344 break
345 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100346 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000347
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000348 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100349 with open(os.path.join(_UNIXCONFDIR, file), 'r',
350 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000351 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000352 _distname, _version, _id = _parse_release_file(firstline)
353
354 if _distname and full_distribution_name:
355 distname = _distname
356 if _version:
357 version = _version
358 if _id:
359 id = _id
360 return distname, version, id
361
362# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000363
Victor Stinnerced39362013-12-09 00:14:52 +0100364def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000365
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000366 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000367
Brett Cannon8ab27df2003-08-05 03:52:04 +0000368 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000369
370 The function first looks for a distribution release file in
371 /etc and then reverts to _dist_try_harder() in case no
372 suitable files are found.
373
Victor Stinnerced39362013-12-09 00:14:52 +0100374 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000375 args given as parameters.
376
377 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300378 import warnings
379 warnings.warn("dist() and linux_distribution() functions are deprecated "
Berker Peksag8d8221f2016-04-24 03:32:24 +0300380 "in Python 3.5", PendingDeprecationWarning, stacklevel=2)
Berker Peksag2f3742b2015-05-13 12:32:20 +0300381 return _linux_distribution(distname, version, id,
382 supported_dists=supported_dists,
383 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000384
Antoine Pitrou877766d2011-03-19 17:00:37 +0100385def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000386
387 """ Portable popen() interface.
388 """
Victor Stinner25000d42011-05-24 00:16:16 +0200389 import warnings
390 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000391 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000392
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000393def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000394
Brett Cannon8ab27df2003-08-05 03:52:04 +0000395 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000396 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000397 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000398 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000399 if build:
400 l.append(build)
401 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100402 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000403 except ValueError:
404 strings = l
405 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100406 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000407 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000408 return version
409
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000410_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
411 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000412 '\[.* ([\d.]+)\])')
413
414# Examples of VER command output:
415#
416# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
417# Windows XP: Microsoft Windows XP [Version 5.1.2600]
418# Windows Vista: Microsoft Windows [Version 6.0.6002]
419#
420# Note that the "Version" string gets localized on different
421# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000422
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000423def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000424
Victor Stinnerced39362013-12-09 00:14:52 +0100425 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000426
427 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100428 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000429
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000430 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200431 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000432
433 In case this fails, the given parameters are used as
434 defaults.
435
436 """
437 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100438 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000439
440 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100441 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000442 try:
Steve Dowercae101f2015-08-10 20:57:37 -0700443 pipe = os.popen(cmd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000444 info = pipe.read()
445 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200446 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200447 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000448 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200449 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100450 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000451 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000452 else:
453 break
454 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100455 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
457 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000458 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000459 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000460 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100461 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 # Strip trailing dots from version and release
463 if release[-1] == '.':
464 release = release[:-1]
465 if version[-1] == '.':
466 version = version[:-1]
467 # Normalize the version and build strings (eliminating additional
468 # zeros)
469 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100470 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000471
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700472_WIN32_CLIENT_RELEASES = {
473 (5, 0): "2000",
474 (5, 1): "XP",
475 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
476 # has always called it 2003 Server
477 (5, 2): "2003Server",
478 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000479
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700480 (6, 0): "Vista",
481 (6, 1): "7",
482 (6, 2): "8",
483 (6, 3): "8.1",
484 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700486 (10, 0): "10",
487 (10, None): "post10",
488}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000489
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700490# Server release name lookup will default to client names if necessary
491_WIN32_SERVER_RELEASES = {
492 (5, 2): "2003Server",
493
494 (6, 0): "2008Server",
495 (6, 1): "2008ServerR2",
496 (6, 2): "2012Server",
497 (6, 3): "2012ServerR2",
498 (6, None): "post2012ServerR2",
499}
500
Victor Stinnerced39362013-12-09 00:14:52 +0100501def win32_ver(release='', version='', csd='', ptype=''):
Steve Dower8f278f12015-09-22 17:35:24 -0700502 try:
503 from sys import getwindowsversion
504 except ImportError:
505 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000506 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700507 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Brett Cannoncd171c82013-07-04 17:43:24 -0400508 except ImportError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700509 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
510
511 winver = getwindowsversion()
Steve Dower1ec262b2016-09-17 17:25:42 -0700512 maj, min, build = winver._platform_version or winver[:3]
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700513 version = '{0}.{1}.{2}'.format(maj, min, build)
514
515 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
516 _WIN32_CLIENT_RELEASES.get((maj, None)) or
517 release)
518
519 # getwindowsversion() reflect the compatibility mode Python is
520 # running under, and so the service pack value is only going to be
521 # valid if the versions match.
522 if winver[:2] == (maj, min):
Christian Heimes02781dc2008-03-21 01:11:52 +0000523 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700524 csd = 'SP{}'.format(winver.service_pack_major)
Christian Heimes02781dc2008-03-21 01:11:52 +0000525 except AttributeError:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700526 if csd[:13] == 'Service Pack ':
527 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000528
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700529 # VER_NT_SERVER = 3
Steve Dower41519b22016-09-09 09:46:56 -0700530 if getattr(winver, 'product_type', None) == 3:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700531 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
532 _WIN32_SERVER_RELEASES.get((maj, None)) or
533 release)
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000534
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700535 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000536 try:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700537 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
538 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
539 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000540 except:
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700541 pass
542 finally:
543 if key:
544 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000545
Victor Stinnerced39362013-12-09 00:14:52 +0100546 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000547
Steve Dowerb9f4fea2015-09-22 17:23:39 -0700548
Ronald Oussorene186e382010-07-23 11:54:59 +0000549def _mac_ver_xml():
550 fn = '/System/Library/CoreServices/SystemVersion.plist'
551 if not os.path.exists(fn):
552 return None
553
554 try:
555 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400556 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000557 return None
558
Ned Deily936dfae2014-01-13 11:34:19 -0800559 with open(fn, 'rb') as f:
560 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000561 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100562 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700563 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000564 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300565 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000566 machine = 'PowerPC'
567
Victor Stinnerced39362013-12-09 00:14:52 +0100568 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000569
570
Victor Stinnerced39362013-12-09 00:14:52 +0100571def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000572
573 """ Get MacOS version information and return it as tuple (release,
574 versioninfo, machine) with versioninfo being a tuple (version,
575 dev_stage, non_release_version).
576
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300577 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000578 which default to ''. All tuple entries are strings.
579 """
580
581 # First try reading the information from an XML file which should
582 # always be present
583 info = _mac_ver_xml()
584 if info is not None:
585 return info
586
Ronald Oussorene186e382010-07-23 11:54:59 +0000587 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100588 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000589
Victor Stinnerced39362013-12-09 00:14:52 +0100590def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000591
592 from java.lang import System
593 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000594 value = System.getProperty(name)
595 if value is None:
596 return default
597 return value
598 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000599 return default
600
Victor Stinnerced39362013-12-09 00:14:52 +0100601def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000602
Brett Cannon8ab27df2003-08-05 03:52:04 +0000603 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000604
Victor Stinnerced39362013-12-09 00:14:52 +0100605 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
606 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
607 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000608
609 Values which cannot be determined are set to the defaults
610 given as parameters (which all default to '').
611
612 """
613 # Import the needed APIs
614 try:
615 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400616 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100617 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000618
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000619 vendor = _java_getprop('java.vendor', vendor)
620 release = _java_getprop('java.version', release)
621 vm_name, vm_release, vm_vendor = vminfo
622 vm_name = _java_getprop('java.vm.name', vm_name)
623 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
624 vm_release = _java_getprop('java.vm.version', vm_release)
625 vminfo = vm_name, vm_release, vm_vendor
626 os_name, os_version, os_arch = osinfo
627 os_arch = _java_getprop('java.os.arch', os_arch)
628 os_name = _java_getprop('java.os.name', os_name)
629 os_version = _java_getprop('java.os.version', os_version)
630 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000631
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000632 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000633
634### System name aliasing
635
Victor Stinnerced39362013-12-09 00:14:52 +0100636def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000637
Victor Stinnerced39362013-12-09 00:14:52 +0100638 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000639 marketing names used for some systems.
640
641 It also does some reordering of the information in some cases
642 where it would otherwise cause confusion.
643
644 """
645 if system == 'Rhapsody':
646 # Apple's BSD derivative
647 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100648 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000649
650 elif system == 'SunOS':
651 # Sun's OS
652 if release < '5':
653 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100654 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000655 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000656 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000657 if l:
658 try:
659 major = int(l[0])
660 except ValueError:
661 pass
662 else:
663 major = major - 3
664 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000665 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000666 if release < '6':
667 system = 'Solaris'
668 else:
669 # XXX Whatever the new SunOS marketing name is...
670 system = 'Solaris'
671
672 elif system == 'IRIX64':
673 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
674 # is really a version and not a different platform, since 32-bit
675 # apps are also supported..
676 system = 'IRIX'
677 if version:
678 version = version + ' (64bit)'
679 else:
680 version = '64bit'
681
Victor Stinnerced39362013-12-09 00:14:52 +0100682 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000683 # In case one of the other tricks
684 system = 'Windows'
685
Victor Stinnerced39362013-12-09 00:14:52 +0100686 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000687
688### Various internal helpers
689
690def _platform(*args):
691
692 """ Helper to format the platform string in a filename
693 compatible format e.g. "system-version-machine".
694 """
695 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000696 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000697
698 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100699 platform = platform.replace(' ', '_')
700 platform = platform.replace('/', '-')
701 platform = platform.replace('\\', '-')
702 platform = platform.replace(':', '-')
703 platform = platform.replace(';', '-')
704 platform = platform.replace('"', '-')
705 platform = platform.replace('(', '-')
706 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000707
708 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100709 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000710
711 # Fold '--'s and remove trailing '-'
712 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100713 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000714 if cleaned == platform:
715 break
716 platform = cleaned
717 while platform[-1] == '-':
718 platform = platform[:-1]
719
720 return platform
721
722def _node(default=''):
723
724 """ Helper to determine the node name of this machine.
725 """
726 try:
727 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400728 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000729 # No sockets...
730 return default
731 try:
732 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200733 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000734 # Still not working...
735 return default
736
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000737def _follow_symlinks(filepath):
738
739 """ In case filepath is a symlink, follow it until a
740 real file is reached.
741 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000742 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000743 while os.path.islink(filepath):
744 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100745 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746 return filepath
747
Victor Stinnerced39362013-12-09 00:14:52 +0100748def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000749
750 """ Interface to the system's uname command.
751 """
Victor Stinnerced39362013-12-09 00:14:52 +0100752 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000753 # XXX Others too ?
754 return default
755 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000756 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200757 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000758 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000759 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000760 rc = f.close()
761 if not output or rc:
762 return default
763 else:
764 return output
765
Victor Stinnerced39362013-12-09 00:14:52 +0100766def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000767
768 """ Interface to the system's file command.
769
770 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000771 omit the filename in its output. Follow the symlinks. It returns
772 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000773
774 """
Victor Stinnerced39362013-12-09 00:14:52 +0100775 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000776 # XXX Others too ?
777 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200778 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000779 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200780 proc = subprocess.Popen(['file', target],
781 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200782
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200783 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000784 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200785 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200786 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000787 if not output or rc:
788 return default
789 else:
790 return output
791
792### Information about the used architecture
793
794# Default values for architecture; non-empty strings override the
795# defaults given as parameters
796_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100797 'win32': ('', 'WindowsPE'),
798 'win16': ('', 'Windows'),
799 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000800}
801
Victor Stinnerced39362013-12-09 00:14:52 +0100802def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000803
804 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000805 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000806
Victor Stinnerced39362013-12-09 00:14:52 +0100807 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000808 the bit architecture and the linkage format used for the
809 executable. Both values are returned as strings.
810
811 Values that cannot be determined are returned as given by the
812 parameter presets. If bits is given as '', the sizeof(pointer)
813 (or sizeof(long) on Python version < 1.5.2) is used as
814 indicator for the supported pointer size.
815
816 The function relies on the system's "file" command to do the
817 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000818 platforms. On some non-Unix platforms where the "file" command
819 does not exist and the executable is set to the Python interpreter
820 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821
822 """
823 # Use the sizeof(pointer) as default number of bits if nothing
824 # else is given as default.
825 if not bits:
826 import struct
827 try:
828 size = struct.calcsize('P')
829 except struct.error:
830 # Older installations can only query longs
831 size = struct.calcsize('l')
832 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000833
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000834 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000835 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000836 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000837 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000838 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000839
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000840 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000841 executable == sys.executable:
842 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000843 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000844 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100845 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000846 if b:
847 bits = b
848 if l:
849 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100850 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000851
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000852 if 'executable' not in fileout:
853 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100854 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000855
856 # Bits
857 if '32-bit' in fileout:
858 bits = '32bit'
859 elif 'N32' in fileout:
860 # On Irix only
861 bits = 'n32bit'
862 elif '64-bit' in fileout:
863 bits = '64bit'
864
865 # Linkage
866 if 'ELF' in fileout:
867 linkage = 'ELF'
868 elif 'PE' in fileout:
869 # E.g. Windows uses this format
870 if 'Windows' in fileout:
871 linkage = 'WindowsPE'
872 else:
873 linkage = 'PE'
874 elif 'COFF' in fileout:
875 linkage = 'COFF'
876 elif 'MS-DOS' in fileout:
877 linkage = 'MSDOS'
878 else:
879 # XXX the A.OUT format also falls under this class...
880 pass
881
Victor Stinnerced39362013-12-09 00:14:52 +0100882 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000883
884### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000885
Larry Hastings68386bc2012-06-24 14:30:41 -0700886uname_result = collections.namedtuple("uname_result",
887 "system node release version machine processor")
888
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000889_uname_cache = None
890
891def uname():
892
893 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100894 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000895 identifying the underlying platform.
896
897 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000898 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899
900 Entries which cannot be determined are set to ''.
901
902 """
903 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000904 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000905
906 if _uname_cache is not None:
907 return _uname_cache
908
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000909 processor = ''
910
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000911 # Get some infos from the builtin os.uname API...
912 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100913 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000914 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000915 no_os_uname = 1
916
Georg Brandl62e2ca22010-07-31 21:54:24 +0000917 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000918 # Hmm, no there is either no uname or uname has returned
919 #'unknowns'... we'll have to poke around the system then.
920 if no_os_uname:
921 system = sys.platform
922 release = ''
923 version = ''
924 node = _node()
925 machine = ''
926
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +0000927 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000928
929 # Try win32_ver() on win32 platforms
930 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +0100931 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000932 if release and version:
933 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +0000934 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000935 # available on Win XP and later; see
936 # http://support.microsoft.com/kb/888731 and
937 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000938 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +0000939 # WOW64 processes mask the native architecture
940 if "PROCESSOR_ARCHITEW6432" in os.environ:
941 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
942 else:
943 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000944 if not processor:
945 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +0000946
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000947 # Try the 'ver' system command available on some
948 # platforms
949 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +0100950 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +0000951 # Normalize system to what win32_ver() normally returns
952 # (_syscmd_ver() tends to return the vendor name as well)
953 if system == 'Microsoft Windows':
954 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000955 elif system == 'Microsoft' and release == 'Windows':
956 # Under Windows Vista and Windows Server 2008,
957 # Microsoft changed the output of the ver command. The
958 # release is no longer printed. This causes the
959 # system and release to be misidentified.
960 system = 'Windows'
961 if '6.0' == version[:3]:
962 release = 'Vista'
963 else:
964 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000965
966 # In case we still don't know anything useful, we'll try to
967 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +0100968 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000969 if not version:
970 if system == 'win32':
971 version = '32bit'
972 else:
973 version = '16bit'
974 system = 'Windows'
975
976 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +0100977 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000978 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000979 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000980 if not version:
981 version = vendor
982
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000983 # System specific extensions
984 if system == 'OpenVMS':
985 # OpenVMS seems to have release and version mixed up
986 if not release or release == '0':
987 release = version
988 version = ''
989 # Get processor information
990 try:
991 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -0400992 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000993 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000994 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100995 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000996 if (cpu_number >= 128):
997 processor = 'Alpha'
998 else:
999 processor = 'VAX'
1000 if not processor:
1001 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001002 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001003
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001004 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001005 if system == 'unknown':
1006 system = ''
1007 if node == 'unknown':
1008 node = ''
1009 if release == 'unknown':
1010 release = ''
1011 if version == 'unknown':
1012 version = ''
1013 if machine == 'unknown':
1014 machine = ''
1015 if processor == 'unknown':
1016 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001017
1018 # normalize name
1019 if system == 'Microsoft' and release == 'Windows':
1020 system = 'Windows'
1021 release = 'Vista'
1022
Victor Stinnerced39362013-12-09 00:14:52 +01001023 _uname_cache = uname_result(system, node, release, version,
1024 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001025 return _uname_cache
1026
1027### Direct interfaces to some of the uname() return values
1028
1029def system():
1030
1031 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1032
1033 An empty string is returned if the value cannot be determined.
1034
1035 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001036 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001037
1038def node():
1039
Brett Cannon8ab27df2003-08-05 03:52:04 +00001040 """ Returns the computer's network name (which may not be fully
1041 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001042
1043 An empty string is returned if the value cannot be determined.
1044
1045 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001046 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001047
1048def release():
1049
1050 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1051
1052 An empty string is returned if the value cannot be determined.
1053
1054 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001055 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001056
1057def version():
1058
1059 """ Returns the system's release version, e.g. '#3 on degas'
1060
1061 An empty string is returned if the value cannot be determined.
1062
1063 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001064 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001065
1066def machine():
1067
1068 """ Returns the machine type, e.g. 'i386'
1069
1070 An empty string is returned if the value cannot be determined.
1071
1072 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001073 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001074
1075def processor():
1076
1077 """ Returns the (true) processor name, e.g. 'amdk6'
1078
1079 An empty string is returned if the value cannot be
1080 determined. Note that many platforms do not provide this
1081 information or simply return the same value as for machine(),
1082 e.g. NetBSD does this.
1083
1084 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001085 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001086
1087### Various APIs for extracting information from sys.version
1088
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001089_sys_version_parser = re.compile(
Martin Panter4e505532016-06-08 06:12:22 +00001090 r'([\w.+]+)\s*' # "version<space>"
1091 r'\(#?([^,]+)' # "(#buildno"
1092 r'(?:,\s*([\w ]*)' # ", builddate"
1093 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1094 r'\[([^\]]+)\]?', re.ASCII) # "[compiler]"
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001095
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001096_ironpython_sys_version_parser = re.compile(
1097 r'IronPython\s*'
1098 '([\d\.]+)'
1099 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001100 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001101
Ezio Melottif076f532013-10-21 03:03:32 +03001102# IronPython covering 2.6 and 2.7
1103_ironpython26_sys_version_parser = re.compile(
1104 r'([\d.]+)\s*'
1105 '\(IronPython\s*'
1106 '[\d.]+\s*'
1107 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1108)
1109
Benjamin Petersone549ead2009-03-28 21:42:05 +00001110_pypy_sys_version_parser = re.compile(
1111 r'([\w.+]+)\s*'
1112 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1113 '\[PyPy [^\]]+\]?')
1114
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001115_sys_version_cache = {}
1116
1117def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001118
1119 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001120 (name, version, branch, revision, buildno, builddate, compiler)
1121 referring to the Python implementation name, version, branch,
1122 revision, build number, build date/time as string and the compiler
1123 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001124
1125 Note that unlike the Python sys.version, the returned value
1126 for the Python version will always include the patchlevel (it
1127 defaults to '.0').
1128
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001129 The function returns empty strings for tuple entries that
1130 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001131
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001132 sys_version may be given to parse an alternative version
1133 string, e.g. if the version was read from a different Python
1134 interpreter.
1135
1136 """
1137 # Get the Python version
1138 if sys_version is None:
1139 sys_version = sys.version
1140
1141 # Try the cache first
1142 result = _sys_version_cache.get(sys_version, None)
1143 if result is not None:
1144 return result
1145
1146 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001147 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001148 # IronPython
1149 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001150 if sys_version.startswith('IronPython'):
1151 match = _ironpython_sys_version_parser.match(sys_version)
1152 else:
1153 match = _ironpython26_sys_version_parser.match(sys_version)
1154
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001155 if match is None:
1156 raise ValueError(
1157 'failed to parse IronPython sys.version: %s' %
1158 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001159
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001160 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001161 buildno = ''
1162 builddate = ''
1163
Ezio Melottif076f532013-10-21 03:03:32 +03001164 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001165 # Jython
1166 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001167 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001168 if match is None:
1169 raise ValueError(
1170 'failed to parse Jython sys.version: %s' %
1171 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001172 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panter4e505532016-06-08 06:12:22 +00001173 if builddate is None:
1174 builddate = ''
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001175 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001176
1177 elif "PyPy" in sys_version:
1178 # PyPy
1179 name = "PyPy"
1180 match = _pypy_sys_version_parser.match(sys_version)
1181 if match is None:
1182 raise ValueError("failed to parse PyPy sys.version: %s" %
1183 repr(sys_version))
1184 version, buildno, builddate, buildtime = match.groups()
1185 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001186
1187 else:
1188 # CPython
1189 match = _sys_version_parser.match(sys_version)
1190 if match is None:
1191 raise ValueError(
1192 'failed to parse CPython sys.version: %s' %
1193 repr(sys_version))
1194 version, buildno, builddate, buildtime, compiler = \
1195 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001196 name = 'CPython'
Martin Panter4e505532016-06-08 06:12:22 +00001197 if builddate is None:
1198 builddate = ''
1199 elif buildtime:
1200 builddate = builddate + ' ' + buildtime
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001201
Georg Brandl82562422011-03-05 21:09:22 +01001202 if hasattr(sys, '_mercurial'):
1203 _, branch, revision = sys._mercurial
1204 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001205 # sys.subversion was added in Python 2.5
1206 _, branch, revision = sys.subversion
1207 else:
1208 branch = ''
1209 revision = ''
1210
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001211 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001212 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001213 if len(l) == 2:
1214 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001215 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001216
1217 # Build and cache the result
1218 result = (name, version, branch, revision, buildno, builddate, compiler)
1219 _sys_version_cache[sys_version] = result
1220 return result
1221
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001222def python_implementation():
1223
1224 """ Returns a string identifying the Python implementation.
1225
1226 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001227 'CPython' (C implementation of Python),
1228 'IronPython' (.NET implementation of Python),
1229 'Jython' (Java implementation of Python),
1230 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001231
1232 """
1233 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001234
1235def python_version():
1236
1237 """ Returns the Python version as string 'major.minor.patchlevel'
1238
1239 Note that unlike the Python sys.version, the returned value
1240 will always include the patchlevel (it defaults to 0).
1241
1242 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001243 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001244
1245def python_version_tuple():
1246
1247 """ Returns the Python version as tuple (major, minor, patchlevel)
1248 of strings.
1249
1250 Note that unlike the Python sys.version, the returned value
1251 will always include the patchlevel (it defaults to 0).
1252
1253 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001254 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001255
1256def python_branch():
1257
1258 """ Returns a string identifying the Python implementation
1259 branch.
1260
1261 For CPython this is the Subversion branch from which the
1262 Python binary was built.
1263
1264 If not available, an empty string is returned.
1265
1266 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001267
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001268 return _sys_version()[2]
1269
1270def python_revision():
1271
1272 """ Returns a string identifying the Python implementation
1273 revision.
1274
1275 For CPython this is the Subversion revision from which the
1276 Python binary was built.
1277
1278 If not available, an empty string is returned.
1279
1280 """
1281 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001282
1283def python_build():
1284
1285 """ Returns a tuple (buildno, builddate) stating the Python
1286 build number and date as strings.
1287
1288 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001289 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001290
1291def python_compiler():
1292
1293 """ Returns a string identifying the compiler used for compiling
1294 Python.
1295
1296 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001297 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001298
1299### The Opus Magnum of platform strings :-)
1300
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001301_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001302
1303def platform(aliased=0, terse=0):
1304
1305 """ Returns a single string identifying the underlying platform
1306 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001307
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001308 The output is intended to be human readable rather than
1309 machine parseable. It may look different on different
1310 platforms and this is intended.
1311
1312 If "aliased" is true, the function will use aliases for
1313 various platforms that report system names which differ from
1314 their common names, e.g. SunOS will be reported as
1315 Solaris. The system_alias() function is used to implement
1316 this.
1317
1318 Setting terse to true causes the function to return only the
1319 absolute minimum information needed to identify the platform.
1320
1321 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001322 result = _platform_cache.get((aliased, terse), None)
1323 if result is not None:
1324 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001325
1326 # Get uname information and then apply platform specific cosmetics
1327 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001328 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001329 if machine == processor:
1330 processor = ''
1331 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001332 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001333
1334 if system == 'Windows':
1335 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001336 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001337 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001338 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001339 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001340 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001341
1342 elif system in ('Linux',):
1343 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001344 with warnings.catch_warnings():
1345 # see issue #1322 for more information
1346 warnings.filterwarnings(
1347 'ignore',
1348 'dist\(\) and linux_distribution\(\) '
1349 'functions are deprecated .*',
1350 PendingDeprecationWarning,
1351 )
1352 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001353 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001354 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001355 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001356 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001357 else:
1358 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001359 libcname, libcversion = libc_ver(sys.executable)
1360 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001361 'with',
1362 libcname+libcversion)
1363 elif system == 'Java':
1364 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001365 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001366 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001367 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001368 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001369 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001370 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001371 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001372
1373 elif system == 'MacOS':
1374 # MacOS platforms
1375 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001376 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001377 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001378 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001379
1380 else:
1381 # Generic handler
1382 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001383 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001384 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001385 bits, linkage = architecture(sys.executable)
1386 platform = _platform(system, release, machine,
1387 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001388
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001389 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001390 return platform
1391
1392### Command line interface
1393
1394if __name__ == '__main__':
1395 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001396 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001397 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001398 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001399 sys.exit(0)