blob: b1c659ebbf42abe1e229ecf30ea799c09aadbf31 [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),
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000029# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
Marc-André Lemburg246d8472003-04-24 11:36:11 +000030#
31# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000032#
33# <see CVS and SVN checkin messages for history>
34#
Alexandre Vassalottie52e3782009-07-17 09:18:18 +000035# 1.0.7 - added DEV_NULL
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +000036# 1.0.6 - added linux_distribution()
37# 1.0.5 - fixed Java support to allow running the module on Jython
38# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000039# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000040# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000041# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000042# 1.0.0 - reformatted a bit and checked into Python CVS
43# 0.8.0 - added sys.version parser and various new access
44# APIs (python_version(), python_compiler(), etc.)
45# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
46# 0.7.1 - added support for Caldera OpenLinux
47# 0.7.0 - some fixes for WinCE; untabified the source file
48# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
49# vms_lib.getsyi() configured
50# 0.6.1 - added code to prevent 'uname -p' on platforms which are
51# known not to support it
52# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
53# did some cleanup of the interfaces - some APIs have changed
54# 0.5.5 - fixed another type in the MacOS code... should have
55# used more coffee today ;-)
56# 0.5.4 - fixed a few typos in the MacOS code
57# 0.5.3 - added experimental MacOS support; added better popen()
58# workarounds in _syscmd_ver() -- still not 100% elegant
59# though
60# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
61# return values (the system uname command tends to return
62# 'unknown' instead of just leaving the field emtpy)
63# 0.5.1 - included code for slackware dist; added exception handlers
64# to cover up situations where platforms don't have os.popen
65# (e.g. Mac) or fail on socket.gethostname(); fixed libc
66# detection RE
67# 0.5.0 - changed the API names referring to system commands to *syscmd*;
68# added java_ver(); made syscmd_ver() a private
69# API (was system_ver() in previous versions) -- use uname()
70# instead; extended the win32_ver() to also return processor
71# type information
72# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
73# 0.3.4 - fixed a bug in _follow_symlinks()
74# 0.3.3 - fixed popen() and "file" command invokation bugs
75# 0.3.2 - added architecture() API and support for it in platform()
76# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
77# 0.3.0 - added system alias support
78# 0.2.3 - removed 'wince' again... oh well.
79# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
80# 0.2.1 - added cache logic and changed the platform string format
81# 0.2.0 - changed the API to use functions instead of module globals
82# since some action take too long to be run on module import
83# 0.1.0 - first release
84#
85# You can always get the latest version of this module at:
86#
87# http://www.egenix.com/files/python/platform.py
88#
89# If that URL should fail, try contacting the author.
90
91__copyright__ = """
92 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Benjamin Peterson46a99002010-01-09 18:45:30 +000093 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000094
95 Permission to use, copy, modify, and distribute this software and its
96 documentation for any purpose and without fee or royalty is hereby granted,
97 provided that the above copyright notice appear in all copies and that
98 both that copyright notice and this permission notice appear in
99 supporting documentation or portions thereof, including modifications,
100 that you make.
101
102 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
103 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
104 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
105 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
106 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
107 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
108 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
109
110"""
111
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000112__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000113
Larry Hastings68386bc2012-06-24 14:30:41 -0700114import collections
Jesus Ceafc990e92012-10-04 13:51:43 +0200115import sys, os, re, subprocess
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000116
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000117### Globals & Constants
118
119# Determine the platform's /dev/null device
120try:
121 DEV_NULL = os.devnull
122except AttributeError:
123 # os.devnull was added in Python 2.4, so emulate it for earlier
124 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100125 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000126 # Use the old CP/M NUL as device name
127 DEV_NULL = 'NUL'
128 else:
129 # Standard Unix uses /dev/null
130 DEV_NULL = '/dev/null'
131
Victor Stinner620c48b2013-12-09 00:01:27 +0100132# Directory to search for configuration information on Unix.
133# Constant used by test_platform to test linux_distribution().
134_UNIXCONFDIR = '/etc'
135
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000136### Platform specific APIs
137
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200138_libc_search = re.compile(b'(__libc_init)'
139 b'|'
140 b'(GLIBC_([0-9.]+))'
141 b'|'
142 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000143
Victor Stinnerced39362013-12-09 00:14:52 +0100144def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000145
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200146 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147
Brett Cannon8ab27df2003-08-05 03:52:04 +0000148 """ Tries to determine the libc version that the file executable
149 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000150
151 Returns a tuple of strings (lib,version) which default to the
152 given parameters in case the lookup fails.
153
154 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000155 libc versions add symbols to the executable and thus is probably
156 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000157
158 The file is read and scanned in chunks of chunksize bytes.
159
160 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000161 if hasattr(os.path, 'realpath'):
162 # Python 2.2 introduced os.path.realpath(); it is used
163 # here to work around problems with Cygwin not being
164 # able to open symlinks for reading
165 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300166 with open(executable, 'rb') as f:
167 binary = f.read(chunksize)
168 pos = 0
169 while 1:
170 if b'libc' in binary or b'GLIBC' in binary:
171 m = _libc_search.search(binary, pos)
172 else:
173 m = None
174 if not m:
175 binary = f.read(chunksize)
176 if not binary:
177 break
178 pos = 0
179 continue
180 libcinit, glibc, glibcversion, so, threads, soversion = [
181 s.decode('latin1') if s is not None else s
182 for s in m.groups()]
183 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000184 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300185 elif glibc:
186 if lib != 'glibc':
187 lib = 'glibc'
188 version = glibcversion
189 elif glibcversion > version:
190 version = glibcversion
191 elif so:
192 if lib != 'glibc':
193 lib = 'libc'
194 if soversion and soversion > version:
195 version = soversion
196 if threads and version[-len(threads):] != threads:
197 version = version + threads
198 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100199 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000200
Victor Stinnerced39362013-12-09 00:14:52 +0100201def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000202
Tim Peters0eadaac2003-04-24 16:02:54 +0000203 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000204 information in case the default method fails.
205
206 Currently supports older SuSE Linux, Caldera OpenLinux and
207 Slackware Linux distributions.
208
209 """
210 if os.path.exists('/var/adm/inst-log/info'):
211 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000212 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000213 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000214 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000215 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100216 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000217 else:
218 continue
219 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000220 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000221 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000222 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000223 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100224 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000225
226 if os.path.exists('/etc/.installed'):
227 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000228 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000229 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000230 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
231 # XXX does Caldera support non Intel platforms ? If yes,
232 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100233 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000234
235 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300236 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000237 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000238 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000239 if verfiles[n][:14] != 'slack-version-':
240 del verfiles[n]
241 if verfiles:
242 verfiles.sort()
243 distname = 'slackware'
244 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100245 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000246
Victor Stinnerced39362013-12-09 00:14:52 +0100247 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000248
Antoine Pitroufd036452008-08-19 17:56:33 +0000249_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000250_lsb_release_version = re.compile(r'(.+)'
251 ' release '
252 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000253 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000254_release_version = re.compile(r'([^0-9]+)'
255 '(?: release )?'
256 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000257 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000258
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000259# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000260# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000261# and http://data.linux-ntfs.org/rpm/whichrpm
262# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000263
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000264_supported_dists = (
265 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
266 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200267 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000268
269def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000270
Benjamin Peterson25001472010-01-25 03:37:42 +0000271 # Default to empty 'version' and 'id' strings. Both defaults are used
272 # when 'firstline' is empty. 'id' defaults to empty when an id can not
273 # be deduced.
274 version = ''
275 id = ''
276
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000277 # Parse the first line
278 m = _lsb_release_version.match(firstline)
279 if m is not None:
280 # LSB format: "distro release x.x (codename)"
281 return tuple(m.groups())
282
283 # Pre-LSB format: "distro x.x (codename)"
284 m = _release_version.match(firstline)
285 if m is not None:
286 return tuple(m.groups())
287
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300288 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000289 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000290 if l:
291 version = l[0]
292 if len(l) > 1:
293 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000294 return '', version, id
295
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000296def linux_distribution(distname='', version='', id='',
297
298 supported_dists=_supported_dists,
299 full_distribution_name=1):
300
301 """ Tries to determine the name of the Linux OS distribution name.
302
303 The function first looks for a distribution release file in
304 /etc and then reverts to _dist_try_harder() in case no
305 suitable files are found.
306
307 supported_dists may be given to define the set of Linux
308 distributions to look for. It defaults to a list of currently
309 supported Linux distributions identified by their release file
310 name.
311
312 If full_distribution_name is true (default), the full
313 distribution read from the OS is returned. Otherwise the short
314 name taken from supported_dists is used.
315
Victor Stinnerced39362013-12-09 00:14:52 +0100316 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000317 args given as parameters.
318
319 """
320 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100321 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200322 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000323 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100324 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000325 etc.sort()
326 for file in etc:
327 m = _release_filename.match(file)
328 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100329 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000330 if _distname in supported_dists:
331 distname = _distname
332 break
333 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100334 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000335
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000336 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100337 with open(os.path.join(_UNIXCONFDIR, file), 'r',
338 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000339 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000340 _distname, _version, _id = _parse_release_file(firstline)
341
342 if _distname and full_distribution_name:
343 distname = _distname
344 if _version:
345 version = _version
346 if _id:
347 id = _id
348 return distname, version, id
349
350# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000351
Victor Stinnerced39362013-12-09 00:14:52 +0100352def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000353
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000354 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000355
Brett Cannon8ab27df2003-08-05 03:52:04 +0000356 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000357
358 The function first looks for a distribution release file in
359 /etc and then reverts to _dist_try_harder() in case no
360 suitable files are found.
361
Victor Stinnerced39362013-12-09 00:14:52 +0100362 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000363 args given as parameters.
364
365 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000366 return linux_distribution(distname, version, id,
367 supported_dists=supported_dists,
368 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000369
Antoine Pitrou877766d2011-03-19 17:00:37 +0100370def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000371
372 """ Portable popen() interface.
373 """
Victor Stinner25000d42011-05-24 00:16:16 +0200374 import warnings
375 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000376 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000377
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000378def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000379
Brett Cannon8ab27df2003-08-05 03:52:04 +0000380 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000381 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000382 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000383 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000384 if build:
385 l.append(build)
386 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100387 ints = map(int, l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000388 except ValueError:
389 strings = l
390 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100391 strings = list(map(str, ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000392 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000393 return version
394
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000395_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
396 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000397 '\[.* ([\d.]+)\])')
398
399# Examples of VER command output:
400#
401# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
402# Windows XP: Microsoft Windows XP [Version 5.1.2600]
403# Windows Vista: Microsoft Windows [Version 6.0.6002]
404#
405# Note that the "Version" string gets localized on different
406# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000407
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000408def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000409
Victor Stinnerced39362013-12-09 00:14:52 +0100410 supported_platforms=('win32', 'win16', 'dos')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000411
412 """ Tries to figure out the OS version used and returns
Victor Stinnerced39362013-12-09 00:14:52 +0100413 a tuple (system, release, version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000414
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000415 It uses the "ver" shell command for this which is known
Jesus Ceaf1af7052012-10-05 02:48:46 +0200416 to exists on Windows, DOS. XXX Others too ?
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000417
418 In case this fails, the given parameters are used as
419 defaults.
420
421 """
422 if sys.platform not in supported_platforms:
Victor Stinnerced39362013-12-09 00:14:52 +0100423 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000424
425 # Try some common cmd strings
Victor Stinnerced39362013-12-09 00:14:52 +0100426 for cmd in ('ver', 'command /c ver', 'cmd /c ver'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000427 try:
428 pipe = popen(cmd)
429 info = pipe.read()
430 if pipe.close():
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200431 raise OSError('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200432 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000433 # to stderr ?
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200434 except OSError as why:
Victor Stinnerced39362013-12-09 00:14:52 +0100435 #print 'Command %s failed: %s' % (cmd, why)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000436 continue
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000437 else:
438 break
439 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100440 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000441
442 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000443 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000444 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000445 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100446 system, release, version = m.groups()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000447 # Strip trailing dots from version and release
448 if release[-1] == '.':
449 release = release[:-1]
450 if version[-1] == '.':
451 version = version[:-1]
452 # Normalize the version and build strings (eliminating additional
453 # zeros)
454 version = _norm_version(version)
Victor Stinnerced39362013-12-09 00:14:52 +0100455 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000456
Victor Stinnerced39362013-12-09 00:14:52 +0100457def _win32_getvalue(key, name, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000458
459 """ Read a value for name from the registry key.
460
461 In case this fails, default is returned.
462
463 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000464 try:
465 # Use win32api if available
466 from win32api import RegQueryValueEx
Brett Cannoncd171c82013-07-04 17:43:24 -0400467 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000468 # On Python 2.0 and later, emulate using winreg
469 import winreg
470 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000471 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100472 return RegQueryValueEx(key, name)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000473 except:
474 return default
475
Victor Stinnerced39362013-12-09 00:14:52 +0100476def win32_ver(release='', version='', csd='', ptype=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000477
478 """ Get additional version information from the Windows Registry
Victor Stinnerced39362013-12-09 00:14:52 +0100479 and return a tuple (version, csd, ptype) referring to version
Brian Curtin10dda6e2012-02-01 15:14:00 -0600480 number, CSD level (service pack), and OS type (multi/single
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000481 processor).
482
483 As a hint: ptype returns 'Uniprocessor Free' on single
484 processor NT machines and 'Multiprocessor Free' on multi
485 processor machines. The 'Free' refers to the OS version being
486 free of debugging code. It could also state 'Checked' which
487 means the OS version uses debugging code, i.e. code that
488 checks arguments, ranges, etc. (Thomas Heller).
489
Christian Heimes02781dc2008-03-21 01:11:52 +0000490 Note: this function works best with Mark Hammond's win32
491 package installed, but also on Python 2.3 and later. It
492 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000493
494 """
495 # XXX Is there any way to find out the processor type on WinXX ?
496 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000497 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000498 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000499 #
500 # The mappings between reg. values and release names can be found
501 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000502
503 # Import the needed APIs
504 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000505 from win32api import RegQueryValueEx, RegOpenKeyEx, \
506 RegCloseKey, GetVersionEx
507 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
508 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Brett Cannoncd171c82013-07-04 17:43:24 -0400509 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000510 # Emulate the win32api module using Python APIs
511 try:
512 sys.getwindowsversion
513 except AttributeError:
514 # No emulation possible, so return the defaults...
Victor Stinnerced39362013-12-09 00:14:52 +0100515 return release, version, csd, ptype
Christian Heimes02781dc2008-03-21 01:11:52 +0000516 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000517 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000518 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000519 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000520 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000521 RegQueryValueEx = winreg.QueryValueEx
522 RegOpenKeyEx = winreg.OpenKeyEx
523 RegCloseKey = winreg.CloseKey
524 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000525 VER_PLATFORM_WIN32_WINDOWS = 1
526 VER_PLATFORM_WIN32_NT = 2
527 VER_NT_WORKSTATION = 1
Brian Curtin6e2824d2010-05-06 03:05:50 +0000528 VER_NT_SERVER = 3
529 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000530
531 # Find out the registry key and some general version infos
Brian Curtin6e2824d2010-05-06 03:05:50 +0000532 winver = GetVersionEx()
Victor Stinnerced39362013-12-09 00:14:52 +0100533 maj, min, buildno, plat, csd = winver
534 version = '%i.%i.%i' % (maj, min, buildno & 0xFFFF)
Brian Curtin6e2824d2010-05-06 03:05:50 +0000535 if hasattr(winver, "service_pack"):
536 if winver.service_pack != "":
537 csd = 'SP%s' % winver.service_pack_major
538 else:
539 if csd[:13] == 'Service Pack ':
540 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000541
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000542 if plat == VER_PLATFORM_WIN32_WINDOWS:
543 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
544 # Try to guess the release name
545 if maj == 4:
546 if min == 0:
547 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000548 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000549 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000550 elif min == 90:
551 release = 'Me'
552 else:
553 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000554 elif maj == 5:
555 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000556
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000557 elif plat == VER_PLATFORM_WIN32_NT:
558 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
559 if maj <= 4:
560 release = 'NT'
561 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000562 if min == 0:
563 release = '2000'
564 elif min == 1:
565 release = 'XP'
566 elif min == 2:
567 release = '2003Server'
568 else:
569 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000570 elif maj == 6:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000571 if hasattr(winver, "product_type"):
572 product_type = winver.product_type
573 else:
574 product_type = VER_NT_WORKSTATION
575 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
576 # or help from the registry, we cannot properly identify
577 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000578 try:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000579 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
580 name, type = RegQueryValueEx(key, "ProductName")
581 # Discard any type that isn't REG_SZ
582 if type == REG_SZ and name.find("Server") != -1:
583 product_type = VER_NT_SERVER
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200584 except OSError:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000585 # Use default of VER_NT_WORKSTATION
586 pass
587
588 if min == 0:
589 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000590 release = 'Vista'
591 else:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000592 release = '2008Server'
593 elif min == 1:
594 if product_type == VER_NT_WORKSTATION:
595 release = '7'
596 else:
597 release = '2008ServerR2'
Brian Curtin0b960f52012-10-11 16:07:52 -0500598 elif min == 2:
599 if product_type == VER_NT_WORKSTATION:
600 release = '8'
601 else:
602 release = '2012Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000603 else:
Brian Curtin0b960f52012-10-11 16:07:52 -0500604 release = 'post2012Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000605
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606 else:
607 if not release:
608 # E.g. Win3.1 with win32s
Victor Stinnerced39362013-12-09 00:14:52 +0100609 release = '%i.%i' % (maj, min)
610 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000611
612 # Open the registry key
613 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000614 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000615 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000616 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000617 except:
Victor Stinnerced39362013-12-09 00:14:52 +0100618 return release, version, csd, ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000619
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000620 # Parse values
621 #subversion = _win32_getvalue(keyCurVer,
622 # 'SubVersionNumber',
623 # ('',1))[0]
624 #if subversion:
625 # release = release + subversion # 95a, 95b, etc.
626 build = _win32_getvalue(keyCurVer,
627 'CurrentBuildNumber',
Victor Stinnerced39362013-12-09 00:14:52 +0100628 ('', 1))[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000629 ptype = _win32_getvalue(keyCurVer,
630 'CurrentType',
Victor Stinnerced39362013-12-09 00:14:52 +0100631 (ptype, 1))[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000632
633 # Normalize version
Victor Stinnerced39362013-12-09 00:14:52 +0100634 version = _norm_version(version, build)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000635
636 # Close key
637 RegCloseKey(keyCurVer)
Victor Stinnerced39362013-12-09 00:14:52 +0100638 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000639
Ronald Oussorene186e382010-07-23 11:54:59 +0000640def _mac_ver_xml():
641 fn = '/System/Library/CoreServices/SystemVersion.plist'
642 if not os.path.exists(fn):
643 return None
644
645 try:
646 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400647 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000648 return None
649
Ned Deily936dfae2014-01-13 11:34:19 -0800650 with open(fn, 'rb') as f:
651 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000652 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100653 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700654 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000655 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300656 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000657 machine = 'PowerPC'
658
Victor Stinnerced39362013-12-09 00:14:52 +0100659 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000660
661
Victor Stinnerced39362013-12-09 00:14:52 +0100662def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000663
664 """ Get MacOS version information and return it as tuple (release,
665 versioninfo, machine) with versioninfo being a tuple (version,
666 dev_stage, non_release_version).
667
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300668 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000669 which default to ''. All tuple entries are strings.
670 """
671
672 # First try reading the information from an XML file which should
673 # always be present
674 info = _mac_ver_xml()
675 if info is not None:
676 return info
677
Ronald Oussorene186e382010-07-23 11:54:59 +0000678 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100679 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000680
Victor Stinnerced39362013-12-09 00:14:52 +0100681def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000682
683 from java.lang import System
684 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000685 value = System.getProperty(name)
686 if value is None:
687 return default
688 return value
689 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000690 return default
691
Victor Stinnerced39362013-12-09 00:14:52 +0100692def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000693
Brett Cannon8ab27df2003-08-05 03:52:04 +0000694 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000695
Victor Stinnerced39362013-12-09 00:14:52 +0100696 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
697 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
698 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000699
700 Values which cannot be determined are set to the defaults
701 given as parameters (which all default to '').
702
703 """
704 # Import the needed APIs
705 try:
706 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400707 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100708 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000709
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000710 vendor = _java_getprop('java.vendor', vendor)
711 release = _java_getprop('java.version', release)
712 vm_name, vm_release, vm_vendor = vminfo
713 vm_name = _java_getprop('java.vm.name', vm_name)
714 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
715 vm_release = _java_getprop('java.vm.version', vm_release)
716 vminfo = vm_name, vm_release, vm_vendor
717 os_name, os_version, os_arch = osinfo
718 os_arch = _java_getprop('java.os.arch', os_arch)
719 os_name = _java_getprop('java.os.name', os_name)
720 os_version = _java_getprop('java.os.version', os_version)
721 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000722
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000723 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000724
725### System name aliasing
726
Victor Stinnerced39362013-12-09 00:14:52 +0100727def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000728
Victor Stinnerced39362013-12-09 00:14:52 +0100729 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000730 marketing names used for some systems.
731
732 It also does some reordering of the information in some cases
733 where it would otherwise cause confusion.
734
735 """
736 if system == 'Rhapsody':
737 # Apple's BSD derivative
738 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100739 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000740
741 elif system == 'SunOS':
742 # Sun's OS
743 if release < '5':
744 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100745 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000746 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000747 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000748 if l:
749 try:
750 major = int(l[0])
751 except ValueError:
752 pass
753 else:
754 major = major - 3
755 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000756 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000757 if release < '6':
758 system = 'Solaris'
759 else:
760 # XXX Whatever the new SunOS marketing name is...
761 system = 'Solaris'
762
763 elif system == 'IRIX64':
764 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
765 # is really a version and not a different platform, since 32-bit
766 # apps are also supported..
767 system = 'IRIX'
768 if version:
769 version = version + ' (64bit)'
770 else:
771 version = '64bit'
772
Victor Stinnerced39362013-12-09 00:14:52 +0100773 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000774 # In case one of the other tricks
775 system = 'Windows'
776
Victor Stinnerced39362013-12-09 00:14:52 +0100777 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000778
779### Various internal helpers
780
781def _platform(*args):
782
783 """ Helper to format the platform string in a filename
784 compatible format e.g. "system-version-machine".
785 """
786 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000787 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000788
789 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100790 platform = platform.replace(' ', '_')
791 platform = platform.replace('/', '-')
792 platform = platform.replace('\\', '-')
793 platform = platform.replace(':', '-')
794 platform = platform.replace(';', '-')
795 platform = platform.replace('"', '-')
796 platform = platform.replace('(', '-')
797 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000798
799 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100800 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000801
802 # Fold '--'s and remove trailing '-'
803 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100804 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805 if cleaned == platform:
806 break
807 platform = cleaned
808 while platform[-1] == '-':
809 platform = platform[:-1]
810
811 return platform
812
813def _node(default=''):
814
815 """ Helper to determine the node name of this machine.
816 """
817 try:
818 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400819 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000820 # No sockets...
821 return default
822 try:
823 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200824 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000825 # Still not working...
826 return default
827
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000828def _follow_symlinks(filepath):
829
830 """ In case filepath is a symlink, follow it until a
831 real file is reached.
832 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000833 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000834 while os.path.islink(filepath):
835 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100836 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000837 return filepath
838
Victor Stinnerced39362013-12-09 00:14:52 +0100839def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840
841 """ Interface to the system's uname command.
842 """
Victor Stinnerced39362013-12-09 00:14:52 +0100843 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000844 # XXX Others too ?
845 return default
846 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000847 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200848 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000849 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000850 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000851 rc = f.close()
852 if not output or rc:
853 return default
854 else:
855 return output
856
Victor Stinnerced39362013-12-09 00:14:52 +0100857def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000858
859 """ Interface to the system's file command.
860
861 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000862 omit the filename in its output. Follow the symlinks. It returns
863 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000864
865 """
Victor Stinnerced39362013-12-09 00:14:52 +0100866 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000867 # XXX Others too ?
868 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200869 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000870 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200871 proc = subprocess.Popen(['file', target],
872 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200873
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200874 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000875 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200876 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200877 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000878 if not output or rc:
879 return default
880 else:
881 return output
882
883### Information about the used architecture
884
885# Default values for architecture; non-empty strings override the
886# defaults given as parameters
887_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100888 'win32': ('', 'WindowsPE'),
889 'win16': ('', 'Windows'),
890 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000891}
892
Victor Stinnerced39362013-12-09 00:14:52 +0100893def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000894
895 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000896 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000897
Victor Stinnerced39362013-12-09 00:14:52 +0100898 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000899 the bit architecture and the linkage format used for the
900 executable. Both values are returned as strings.
901
902 Values that cannot be determined are returned as given by the
903 parameter presets. If bits is given as '', the sizeof(pointer)
904 (or sizeof(long) on Python version < 1.5.2) is used as
905 indicator for the supported pointer size.
906
907 The function relies on the system's "file" command to do the
908 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000909 platforms. On some non-Unix platforms where the "file" command
910 does not exist and the executable is set to the Python interpreter
911 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000912
913 """
914 # Use the sizeof(pointer) as default number of bits if nothing
915 # else is given as default.
916 if not bits:
917 import struct
918 try:
919 size = struct.calcsize('P')
920 except struct.error:
921 # Older installations can only query longs
922 size = struct.calcsize('l')
923 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000924
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000925 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000926 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000927 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000928 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000929 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000930
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000931 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000932 executable == sys.executable:
933 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000934 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000935 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100936 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000937 if b:
938 bits = b
939 if l:
940 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100941 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000942
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000943 if 'executable' not in fileout:
944 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100945 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000946
947 # Bits
948 if '32-bit' in fileout:
949 bits = '32bit'
950 elif 'N32' in fileout:
951 # On Irix only
952 bits = 'n32bit'
953 elif '64-bit' in fileout:
954 bits = '64bit'
955
956 # Linkage
957 if 'ELF' in fileout:
958 linkage = 'ELF'
959 elif 'PE' in fileout:
960 # E.g. Windows uses this format
961 if 'Windows' in fileout:
962 linkage = 'WindowsPE'
963 else:
964 linkage = 'PE'
965 elif 'COFF' in fileout:
966 linkage = 'COFF'
967 elif 'MS-DOS' in fileout:
968 linkage = 'MSDOS'
969 else:
970 # XXX the A.OUT format also falls under this class...
971 pass
972
Victor Stinnerced39362013-12-09 00:14:52 +0100973 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000974
975### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000976
Larry Hastings68386bc2012-06-24 14:30:41 -0700977uname_result = collections.namedtuple("uname_result",
978 "system node release version machine processor")
979
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000980_uname_cache = None
981
982def uname():
983
984 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +0100985 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000986 identifying the underlying platform.
987
988 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +0000989 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000990
991 Entries which cannot be determined are set to ''.
992
993 """
994 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +0000995 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000996
997 if _uname_cache is not None:
998 return _uname_cache
999
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001000 processor = ''
1001
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001002 # Get some infos from the builtin os.uname API...
1003 try:
Victor Stinnerced39362013-12-09 00:14:52 +01001004 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001005 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001006 no_os_uname = 1
1007
Georg Brandl62e2ca22010-07-31 21:54:24 +00001008 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001009 # Hmm, no there is either no uname or uname has returned
1010 #'unknowns'... we'll have to poke around the system then.
1011 if no_os_uname:
1012 system = sys.platform
1013 release = ''
1014 version = ''
1015 node = _node()
1016 machine = ''
1017
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001018 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001019
1020 # Try win32_ver() on win32 platforms
1021 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +01001022 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001023 if release and version:
1024 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001025 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001026 # available on Win XP and later; see
1027 # http://support.microsoft.com/kb/888731 and
1028 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001029 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001030 # WOW64 processes mask the native architecture
1031 if "PROCESSOR_ARCHITEW6432" in os.environ:
1032 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1033 else:
1034 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001035 if not processor:
1036 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001037
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001038 # Try the 'ver' system command available on some
1039 # platforms
1040 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +01001041 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001042 # Normalize system to what win32_ver() normally returns
1043 # (_syscmd_ver() tends to return the vendor name as well)
1044 if system == 'Microsoft Windows':
1045 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001046 elif system == 'Microsoft' and release == 'Windows':
1047 # Under Windows Vista and Windows Server 2008,
1048 # Microsoft changed the output of the ver command. The
1049 # release is no longer printed. This causes the
1050 # system and release to be misidentified.
1051 system = 'Windows'
1052 if '6.0' == version[:3]:
1053 release = 'Vista'
1054 else:
1055 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001056
1057 # In case we still don't know anything useful, we'll try to
1058 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001059 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001060 if not version:
1061 if system == 'win32':
1062 version = '32bit'
1063 else:
1064 version = '16bit'
1065 system = 'Windows'
1066
1067 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001068 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001069 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001070 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001071 if not version:
1072 version = vendor
1073
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001074 # System specific extensions
1075 if system == 'OpenVMS':
1076 # OpenVMS seems to have release and version mixed up
1077 if not release or release == '0':
1078 release = version
1079 version = ''
1080 # Get processor information
1081 try:
1082 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001083 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001084 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001085 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001086 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001087 if (cpu_number >= 128):
1088 processor = 'Alpha'
1089 else:
1090 processor = 'VAX'
1091 if not processor:
1092 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001093 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001094
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001095 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001096 if system == 'unknown':
1097 system = ''
1098 if node == 'unknown':
1099 node = ''
1100 if release == 'unknown':
1101 release = ''
1102 if version == 'unknown':
1103 version = ''
1104 if machine == 'unknown':
1105 machine = ''
1106 if processor == 'unknown':
1107 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001108
1109 # normalize name
1110 if system == 'Microsoft' and release == 'Windows':
1111 system = 'Windows'
1112 release = 'Vista'
1113
Victor Stinnerced39362013-12-09 00:14:52 +01001114 _uname_cache = uname_result(system, node, release, version,
1115 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001116 return _uname_cache
1117
1118### Direct interfaces to some of the uname() return values
1119
1120def system():
1121
1122 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1123
1124 An empty string is returned if the value cannot be determined.
1125
1126 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001127 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001128
1129def node():
1130
Brett Cannon8ab27df2003-08-05 03:52:04 +00001131 """ Returns the computer's network name (which may not be fully
1132 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001133
1134 An empty string is returned if the value cannot be determined.
1135
1136 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001137 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001138
1139def release():
1140
1141 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1142
1143 An empty string is returned if the value cannot be determined.
1144
1145 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001146 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001147
1148def version():
1149
1150 """ Returns the system's release version, e.g. '#3 on degas'
1151
1152 An empty string is returned if the value cannot be determined.
1153
1154 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001155 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001156
1157def machine():
1158
1159 """ Returns the machine type, e.g. 'i386'
1160
1161 An empty string is returned if the value cannot be determined.
1162
1163 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001164 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001165
1166def processor():
1167
1168 """ Returns the (true) processor name, e.g. 'amdk6'
1169
1170 An empty string is returned if the value cannot be
1171 determined. Note that many platforms do not provide this
1172 information or simply return the same value as for machine(),
1173 e.g. NetBSD does this.
1174
1175 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001176 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177
1178### Various APIs for extracting information from sys.version
1179
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001180_sys_version_parser = re.compile(
1181 r'([\w.+]+)\s*'
1182 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001183 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001184
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001185_ironpython_sys_version_parser = re.compile(
1186 r'IronPython\s*'
1187 '([\d\.]+)'
1188 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001189 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001190
Ezio Melottif076f532013-10-21 03:03:32 +03001191# IronPython covering 2.6 and 2.7
1192_ironpython26_sys_version_parser = re.compile(
1193 r'([\d.]+)\s*'
1194 '\(IronPython\s*'
1195 '[\d.]+\s*'
1196 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1197)
1198
Benjamin Petersone549ead2009-03-28 21:42:05 +00001199_pypy_sys_version_parser = re.compile(
1200 r'([\w.+]+)\s*'
1201 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1202 '\[PyPy [^\]]+\]?')
1203
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001204_sys_version_cache = {}
1205
1206def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001207
1208 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001209 (name, version, branch, revision, buildno, builddate, compiler)
1210 referring to the Python implementation name, version, branch,
1211 revision, build number, build date/time as string and the compiler
1212 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001213
1214 Note that unlike the Python sys.version, the returned value
1215 for the Python version will always include the patchlevel (it
1216 defaults to '.0').
1217
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001218 The function returns empty strings for tuple entries that
1219 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001220
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001221 sys_version may be given to parse an alternative version
1222 string, e.g. if the version was read from a different Python
1223 interpreter.
1224
1225 """
1226 # Get the Python version
1227 if sys_version is None:
1228 sys_version = sys.version
1229
1230 # Try the cache first
1231 result = _sys_version_cache.get(sys_version, None)
1232 if result is not None:
1233 return result
1234
1235 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001236 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001237 # IronPython
1238 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001239 if sys_version.startswith('IronPython'):
1240 match = _ironpython_sys_version_parser.match(sys_version)
1241 else:
1242 match = _ironpython26_sys_version_parser.match(sys_version)
1243
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001244 if match is None:
1245 raise ValueError(
1246 'failed to parse IronPython sys.version: %s' %
1247 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001248
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001249 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001250 buildno = ''
1251 builddate = ''
1252
Ezio Melottif076f532013-10-21 03:03:32 +03001253 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001254 # Jython
1255 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001256 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001257 if match is None:
1258 raise ValueError(
1259 'failed to parse Jython sys.version: %s' %
1260 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001261 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001262 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001263
1264 elif "PyPy" in sys_version:
1265 # PyPy
1266 name = "PyPy"
1267 match = _pypy_sys_version_parser.match(sys_version)
1268 if match is None:
1269 raise ValueError("failed to parse PyPy sys.version: %s" %
1270 repr(sys_version))
1271 version, buildno, builddate, buildtime = match.groups()
1272 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001273
1274 else:
1275 # CPython
1276 match = _sys_version_parser.match(sys_version)
1277 if match is None:
1278 raise ValueError(
1279 'failed to parse CPython sys.version: %s' %
1280 repr(sys_version))
1281 version, buildno, builddate, buildtime, compiler = \
1282 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001283 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001284 builddate = builddate + ' ' + buildtime
1285
Georg Brandl82562422011-03-05 21:09:22 +01001286 if hasattr(sys, '_mercurial'):
1287 _, branch, revision = sys._mercurial
1288 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001289 # sys.subversion was added in Python 2.5
1290 _, branch, revision = sys.subversion
1291 else:
1292 branch = ''
1293 revision = ''
1294
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001295 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001296 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001297 if len(l) == 2:
1298 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001299 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001300
1301 # Build and cache the result
1302 result = (name, version, branch, revision, buildno, builddate, compiler)
1303 _sys_version_cache[sys_version] = result
1304 return result
1305
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001306def python_implementation():
1307
1308 """ Returns a string identifying the Python implementation.
1309
1310 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001311 'CPython' (C implementation of Python),
1312 'IronPython' (.NET implementation of Python),
1313 'Jython' (Java implementation of Python),
1314 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001315
1316 """
1317 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001318
1319def python_version():
1320
1321 """ Returns the Python version as string 'major.minor.patchlevel'
1322
1323 Note that unlike the Python sys.version, the returned value
1324 will always include the patchlevel (it defaults to 0).
1325
1326 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001327 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001328
1329def python_version_tuple():
1330
1331 """ Returns the Python version as tuple (major, minor, patchlevel)
1332 of strings.
1333
1334 Note that unlike the Python sys.version, the returned value
1335 will always include the patchlevel (it defaults to 0).
1336
1337 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001338 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001339
1340def python_branch():
1341
1342 """ Returns a string identifying the Python implementation
1343 branch.
1344
1345 For CPython this is the Subversion branch from which the
1346 Python binary was built.
1347
1348 If not available, an empty string is returned.
1349
1350 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001351
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001352 return _sys_version()[2]
1353
1354def python_revision():
1355
1356 """ Returns a string identifying the Python implementation
1357 revision.
1358
1359 For CPython this is the Subversion revision from which the
1360 Python binary was built.
1361
1362 If not available, an empty string is returned.
1363
1364 """
1365 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001366
1367def python_build():
1368
1369 """ Returns a tuple (buildno, builddate) stating the Python
1370 build number and date as strings.
1371
1372 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001373 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001374
1375def python_compiler():
1376
1377 """ Returns a string identifying the compiler used for compiling
1378 Python.
1379
1380 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001381 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001382
1383### The Opus Magnum of platform strings :-)
1384
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001385_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001386
1387def platform(aliased=0, terse=0):
1388
1389 """ Returns a single string identifying the underlying platform
1390 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001391
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001392 The output is intended to be human readable rather than
1393 machine parseable. It may look different on different
1394 platforms and this is intended.
1395
1396 If "aliased" is true, the function will use aliases for
1397 various platforms that report system names which differ from
1398 their common names, e.g. SunOS will be reported as
1399 Solaris. The system_alias() function is used to implement
1400 this.
1401
1402 Setting terse to true causes the function to return only the
1403 absolute minimum information needed to identify the platform.
1404
1405 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001406 result = _platform_cache.get((aliased, terse), None)
1407 if result is not None:
1408 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001409
1410 # Get uname information and then apply platform specific cosmetics
1411 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001412 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001413 if machine == processor:
1414 processor = ''
1415 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001416 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001417
1418 if system == 'Windows':
1419 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001420 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001421 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001422 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001423 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001424 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001425
1426 elif system in ('Linux',):
1427 # Linux based systems
Victor Stinnerced39362013-12-09 00:14:52 +01001428 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001429 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001430 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001431 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001432 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001433 else:
1434 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001435 libcname, libcversion = libc_ver(sys.executable)
1436 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001437 'with',
1438 libcname+libcversion)
1439 elif system == 'Java':
1440 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001441 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001442 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001443 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001444 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001445 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001446 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001447 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001448
1449 elif system == 'MacOS':
1450 # MacOS platforms
1451 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001452 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001453 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001454 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001455
1456 else:
1457 # Generic handler
1458 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001459 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001460 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001461 bits, linkage = architecture(sys.executable)
1462 platform = _platform(system, release, machine,
1463 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001464
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001465 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001466 return platform
1467
1468### Command line interface
1469
1470if __name__ == '__main__':
1471 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001472 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001473 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001474 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001475 sys.exit(0)