blob: 6345184902bee46348cdeeb89f2f2b9452ea701e [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
Berker Peksag1392f712015-05-16 20:24:28 +0300117import warnings
118
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000119### Globals & Constants
120
121# Determine the platform's /dev/null device
122try:
123 DEV_NULL = os.devnull
124except AttributeError:
125 # os.devnull was added in Python 2.4, so emulate it for earlier
126 # Python versions
Victor Stinnerced39362013-12-09 00:14:52 +0100127 if sys.platform in ('dos', 'win32', 'win16'):
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000128 # Use the old CP/M NUL as device name
129 DEV_NULL = 'NUL'
130 else:
131 # Standard Unix uses /dev/null
132 DEV_NULL = '/dev/null'
133
Victor Stinner620c48b2013-12-09 00:01:27 +0100134# Directory to search for configuration information on Unix.
135# Constant used by test_platform to test linux_distribution().
136_UNIXCONFDIR = '/etc'
137
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000138### Platform specific APIs
139
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200140_libc_search = re.compile(b'(__libc_init)'
141 b'|'
142 b'(GLIBC_([0-9.]+))'
143 b'|'
144 br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000145
Victor Stinnerced39362013-12-09 00:14:52 +0100146def libc_ver(executable=sys.executable, lib='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000147
Antoine Pitrouba7c2262011-10-07 13:26:59 +0200148 chunksize=16384):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000149
Brett Cannon8ab27df2003-08-05 03:52:04 +0000150 """ Tries to determine the libc version that the file executable
151 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152
153 Returns a tuple of strings (lib,version) which default to the
154 given parameters in case the lookup fails.
155
156 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000157 libc versions add symbols to the executable and thus is probably
158 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000159
160 The file is read and scanned in chunks of chunksize bytes.
161
162 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000163 if hasattr(os.path, 'realpath'):
164 # Python 2.2 introduced os.path.realpath(); it is used
165 # here to work around problems with Cygwin not being
166 # able to open symlinks for reading
167 executable = os.path.realpath(executable)
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300168 with open(executable, 'rb') as f:
169 binary = f.read(chunksize)
170 pos = 0
171 while 1:
172 if b'libc' in binary or b'GLIBC' in binary:
173 m = _libc_search.search(binary, pos)
174 else:
175 m = None
176 if not m:
177 binary = f.read(chunksize)
178 if not binary:
179 break
180 pos = 0
181 continue
182 libcinit, glibc, glibcversion, so, threads, soversion = [
183 s.decode('latin1') if s is not None else s
184 for s in m.groups()]
185 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000186 lib = 'libc'
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +0300187 elif glibc:
188 if lib != 'glibc':
189 lib = 'glibc'
190 version = glibcversion
191 elif glibcversion > version:
192 version = glibcversion
193 elif so:
194 if lib != 'glibc':
195 lib = 'libc'
196 if soversion and soversion > version:
197 version = soversion
198 if threads and version[-len(threads):] != threads:
199 version = version + threads
200 pos = m.end()
Victor Stinnerced39362013-12-09 00:14:52 +0100201 return lib, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000202
Victor Stinnerced39362013-12-09 00:14:52 +0100203def _dist_try_harder(distname, version, id):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000204
Tim Peters0eadaac2003-04-24 16:02:54 +0000205 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000206 information in case the default method fails.
207
208 Currently supports older SuSE Linux, Caldera OpenLinux and
209 Slackware Linux distributions.
210
211 """
212 if os.path.exists('/var/adm/inst-log/info'):
213 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000214 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000215 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000216 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000217 if len(tv) == 2:
Victor Stinnerced39362013-12-09 00:14:52 +0100218 tag, value = tv
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000219 else:
220 continue
221 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000222 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000223 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000224 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000225 id = values[2]
Victor Stinnerced39362013-12-09 00:14:52 +0100226 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000227
228 if os.path.exists('/etc/.installed'):
229 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000230 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000231 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000232 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
233 # XXX does Caldera support non Intel platforms ? If yes,
234 # where can we find the needed id ?
Victor Stinnerced39362013-12-09 00:14:52 +0100235 return 'OpenLinux', pkg[1], id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000236
237 if os.path.isdir('/usr/lib/setup'):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300238 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000239 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000240 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000241 if verfiles[n][:14] != 'slack-version-':
242 del verfiles[n]
243 if verfiles:
244 verfiles.sort()
245 distname = 'slackware'
246 version = verfiles[-1][14:]
Victor Stinnerced39362013-12-09 00:14:52 +0100247 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000248
Victor Stinnerced39362013-12-09 00:14:52 +0100249 return distname, version, id
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000250
Antoine Pitroufd036452008-08-19 17:56:33 +0000251_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000252_lsb_release_version = re.compile(r'(.+)'
253 ' release '
254 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000255 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000256_release_version = re.compile(r'([^0-9]+)'
257 '(?: release )?'
258 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000259 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000260
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000261# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000262# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000263# and http://data.linux-ntfs.org/rpm/whichrpm
264# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000265
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000266_supported_dists = (
267 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
268 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
Antoine Pitrouab888032012-06-24 22:20:18 +0200269 'UnitedLinux', 'turbolinux', 'arch', 'mageia')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000270
271def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000272
Benjamin Peterson25001472010-01-25 03:37:42 +0000273 # Default to empty 'version' and 'id' strings. Both defaults are used
274 # when 'firstline' is empty. 'id' defaults to empty when an id can not
275 # be deduced.
276 version = ''
277 id = ''
278
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000279 # Parse the first line
280 m = _lsb_release_version.match(firstline)
281 if m is not None:
282 # LSB format: "distro release x.x (codename)"
283 return tuple(m.groups())
284
285 # Pre-LSB format: "distro x.x (codename)"
286 m = _release_version.match(firstline)
287 if m is not None:
288 return tuple(m.groups())
289
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300290 # Unknown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000291 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000292 if l:
293 version = l[0]
294 if len(l) > 1:
295 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000296 return '', version, id
297
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000298def linux_distribution(distname='', version='', id='',
299
300 supported_dists=_supported_dists,
301 full_distribution_name=1):
Berker Peksag2f3742b2015-05-13 12:32:20 +0300302 import warnings
303 warnings.warn("dist() and linux_distribution() functions are deprecated "
304 "in Python 3.5 and will be removed in Python 3.7",
305 PendingDeprecationWarning, stacklevel=2)
306 return _linux_distribution(distname, version, id, supported_dists,
307 full_distribution_name)
308
309def _linux_distribution(distname, version, id, supported_dists,
310 full_distribution_name):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000311
312 """ Tries to determine the name of the Linux OS distribution name.
313
314 The function first looks for a distribution release file in
315 /etc and then reverts to _dist_try_harder() in case no
316 suitable files are found.
317
318 supported_dists may be given to define the set of Linux
319 distributions to look for. It defaults to a list of currently
320 supported Linux distributions identified by their release file
321 name.
322
323 If full_distribution_name is true (default), the full
324 distribution read from the OS is returned. Otherwise the short
325 name taken from supported_dists is used.
326
Victor Stinnerced39362013-12-09 00:14:52 +0100327 Returns a tuple (distname, version, id) which default to the
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000328 args given as parameters.
329
330 """
331 try:
Victor Stinner620c48b2013-12-09 00:01:27 +0100332 etc = os.listdir(_UNIXCONFDIR)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200333 except OSError:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000334 # Probably not a Unix system
Victor Stinnerced39362013-12-09 00:14:52 +0100335 return distname, version, id
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000336 etc.sort()
337 for file in etc:
338 m = _release_filename.match(file)
339 if m is not None:
Victor Stinnerced39362013-12-09 00:14:52 +0100340 _distname, dummy = m.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000341 if _distname in supported_dists:
342 distname = _distname
343 break
344 else:
Victor Stinnerced39362013-12-09 00:14:52 +0100345 return _dist_try_harder(distname, version, id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000346
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000347 # Read the first line
Victor Stinner620c48b2013-12-09 00:01:27 +0100348 with open(os.path.join(_UNIXCONFDIR, file), 'r',
349 encoding='utf-8', errors='surrogateescape') as f:
Florent Xicluna7dde7922010-09-03 19:52:03 +0000350 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000351 _distname, _version, _id = _parse_release_file(firstline)
352
353 if _distname and full_distribution_name:
354 distname = _distname
355 if _version:
356 version = _version
357 if _id:
358 id = _id
359 return distname, version, id
360
361# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000362
Victor Stinnerced39362013-12-09 00:14:52 +0100363def dist(distname='', version='', id='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000364
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000365 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000366
Brett Cannon8ab27df2003-08-05 03:52:04 +0000367 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000368
369 The function first looks for a distribution release file in
370 /etc and then reverts to _dist_try_harder() in case no
371 suitable files are found.
372
Victor Stinnerced39362013-12-09 00:14:52 +0100373 Returns a tuple (distname, version, id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000374 args given as parameters.
375
376 """
Berker Peksag2f3742b2015-05-13 12:32:20 +0300377 import warnings
378 warnings.warn("dist() and linux_distribution() functions are deprecated "
379 "in Python 3.5 and will be removed in Python 3.7",
380 PendingDeprecationWarning, stacklevel=2)
381 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:
443 pipe = popen(cmd)
444 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
Victor Stinnerced39362013-12-09 00:14:52 +0100472def _win32_getvalue(key, name, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000473
474 """ Read a value for name from the registry key.
475
476 In case this fails, default is returned.
477
478 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000479 try:
480 # Use win32api if available
481 from win32api import RegQueryValueEx
Brett Cannoncd171c82013-07-04 17:43:24 -0400482 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000483 # On Python 2.0 and later, emulate using winreg
484 import winreg
485 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000486 try:
Victor Stinnerced39362013-12-09 00:14:52 +0100487 return RegQueryValueEx(key, name)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488 except:
489 return default
490
Victor Stinnerced39362013-12-09 00:14:52 +0100491def win32_ver(release='', version='', csd='', ptype=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000492
493 """ Get additional version information from the Windows Registry
Victor Stinnerced39362013-12-09 00:14:52 +0100494 and return a tuple (version, csd, ptype) referring to version
Brian Curtin10dda6e2012-02-01 15:14:00 -0600495 number, CSD level (service pack), and OS type (multi/single
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000496 processor).
497
498 As a hint: ptype returns 'Uniprocessor Free' on single
499 processor NT machines and 'Multiprocessor Free' on multi
500 processor machines. The 'Free' refers to the OS version being
501 free of debugging code. It could also state 'Checked' which
502 means the OS version uses debugging code, i.e. code that
503 checks arguments, ranges, etc. (Thomas Heller).
504
Christian Heimes02781dc2008-03-21 01:11:52 +0000505 Note: this function works best with Mark Hammond's win32
506 package installed, but also on Python 2.3 and later. It
507 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000508
509 """
510 # XXX Is there any way to find out the processor type on WinXX ?
511 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000512 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000513 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000514 #
515 # The mappings between reg. values and release names can be found
516 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000517
518 # Import the needed APIs
519 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000520 from win32api import RegQueryValueEx, RegOpenKeyEx, \
521 RegCloseKey, GetVersionEx
522 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
523 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Brett Cannoncd171c82013-07-04 17:43:24 -0400524 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000525 # Emulate the win32api module using Python APIs
526 try:
527 sys.getwindowsversion
528 except AttributeError:
529 # No emulation possible, so return the defaults...
Victor Stinnerced39362013-12-09 00:14:52 +0100530 return release, version, csd, ptype
Christian Heimes02781dc2008-03-21 01:11:52 +0000531 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000532 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000533 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000534 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000535 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000536 RegQueryValueEx = winreg.QueryValueEx
537 RegOpenKeyEx = winreg.OpenKeyEx
538 RegCloseKey = winreg.CloseKey
539 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000540 VER_PLATFORM_WIN32_WINDOWS = 1
541 VER_PLATFORM_WIN32_NT = 2
542 VER_NT_WORKSTATION = 1
Brian Curtin6e2824d2010-05-06 03:05:50 +0000543 VER_NT_SERVER = 3
544 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000545
546 # Find out the registry key and some general version infos
Brian Curtin6e2824d2010-05-06 03:05:50 +0000547 winver = GetVersionEx()
Victor Stinnerced39362013-12-09 00:14:52 +0100548 maj, min, buildno, plat, csd = winver
549 version = '%i.%i.%i' % (maj, min, buildno & 0xFFFF)
Brian Curtin6e2824d2010-05-06 03:05:50 +0000550 if hasattr(winver, "service_pack"):
551 if winver.service_pack != "":
552 csd = 'SP%s' % winver.service_pack_major
553 else:
554 if csd[:13] == 'Service Pack ':
555 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000556
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000557 if plat == VER_PLATFORM_WIN32_WINDOWS:
558 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
559 # Try to guess the release name
560 if maj == 4:
561 if min == 0:
562 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000563 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000564 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000565 elif min == 90:
566 release = 'Me'
567 else:
568 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000569 elif maj == 5:
570 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000571
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000572 elif plat == VER_PLATFORM_WIN32_NT:
573 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
574 if maj <= 4:
575 release = 'NT'
576 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000577 if min == 0:
578 release = '2000'
579 elif min == 1:
580 release = 'XP'
581 elif min == 2:
582 release = '2003Server'
583 else:
584 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000585 elif maj == 6:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000586 if hasattr(winver, "product_type"):
587 product_type = winver.product_type
588 else:
589 product_type = VER_NT_WORKSTATION
590 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
591 # or help from the registry, we cannot properly identify
592 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000593 try:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000594 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
595 name, type = RegQueryValueEx(key, "ProductName")
596 # Discard any type that isn't REG_SZ
597 if type == REG_SZ and name.find("Server") != -1:
598 product_type = VER_NT_SERVER
Andrew Svetlov2606a6f2012-12-19 14:33:35 +0200599 except OSError:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000600 # Use default of VER_NT_WORKSTATION
601 pass
602
603 if min == 0:
604 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000605 release = 'Vista'
606 else:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000607 release = '2008Server'
608 elif min == 1:
609 if product_type == VER_NT_WORKSTATION:
610 release = '7'
611 else:
612 release = '2008ServerR2'
Brian Curtin0b960f52012-10-11 16:07:52 -0500613 elif min == 2:
614 if product_type == VER_NT_WORKSTATION:
615 release = '8'
616 else:
617 release = '2012Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000618 else:
Brian Curtin0b960f52012-10-11 16:07:52 -0500619 release = 'post2012Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000620
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000621 else:
622 if not release:
623 # E.g. Win3.1 with win32s
Victor Stinnerced39362013-12-09 00:14:52 +0100624 release = '%i.%i' % (maj, min)
625 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000626
627 # Open the registry key
628 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000629 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000630 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000631 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000632 except:
Victor Stinnerced39362013-12-09 00:14:52 +0100633 return release, version, csd, ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000634
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000635 # Parse values
636 #subversion = _win32_getvalue(keyCurVer,
637 # 'SubVersionNumber',
638 # ('',1))[0]
639 #if subversion:
640 # release = release + subversion # 95a, 95b, etc.
641 build = _win32_getvalue(keyCurVer,
642 'CurrentBuildNumber',
Victor Stinnerced39362013-12-09 00:14:52 +0100643 ('', 1))[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000644 ptype = _win32_getvalue(keyCurVer,
645 'CurrentType',
Victor Stinnerced39362013-12-09 00:14:52 +0100646 (ptype, 1))[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000647
648 # Normalize version
Victor Stinnerced39362013-12-09 00:14:52 +0100649 version = _norm_version(version, build)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650
651 # Close key
652 RegCloseKey(keyCurVer)
Victor Stinnerced39362013-12-09 00:14:52 +0100653 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654
Ronald Oussorene186e382010-07-23 11:54:59 +0000655def _mac_ver_xml():
656 fn = '/System/Library/CoreServices/SystemVersion.plist'
657 if not os.path.exists(fn):
658 return None
659
660 try:
661 import plistlib
Brett Cannoncd171c82013-07-04 17:43:24 -0400662 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000663 return None
664
Ned Deily936dfae2014-01-13 11:34:19 -0800665 with open(fn, 'rb') as f:
666 pl = plistlib.load(f)
Ronald Oussorene186e382010-07-23 11:54:59 +0000667 release = pl['ProductVersion']
Victor Stinnerced39362013-12-09 00:14:52 +0100668 versioninfo = ('', '', '')
Larry Hastings605a62d2012-06-24 04:33:36 -0700669 machine = os.uname().machine
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000670 if machine in ('ppc', 'Power Macintosh'):
Ezio Melotti9a3777e2013-08-17 15:53:55 +0300671 # Canonical name
Ronald Oussorene186e382010-07-23 11:54:59 +0000672 machine = 'PowerPC'
673
Victor Stinnerced39362013-12-09 00:14:52 +0100674 return release, versioninfo, machine
Ronald Oussorene186e382010-07-23 11:54:59 +0000675
676
Victor Stinnerced39362013-12-09 00:14:52 +0100677def mac_ver(release='', versioninfo=('', '', ''), machine=''):
Ronald Oussorene186e382010-07-23 11:54:59 +0000678
679 """ Get MacOS version information and return it as tuple (release,
680 versioninfo, machine) with versioninfo being a tuple (version,
681 dev_stage, non_release_version).
682
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300683 Entries which cannot be determined are set to the parameter values
Ronald Oussorene186e382010-07-23 11:54:59 +0000684 which default to ''. All tuple entries are strings.
685 """
686
687 # First try reading the information from an XML file which should
688 # always be present
689 info = _mac_ver_xml()
690 if info is not None:
691 return info
692
Ronald Oussorene186e382010-07-23 11:54:59 +0000693 # If that also doesn't work return the default values
Victor Stinnerced39362013-12-09 00:14:52 +0100694 return release, versioninfo, machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000695
Victor Stinnerced39362013-12-09 00:14:52 +0100696def _java_getprop(name, default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000697
698 from java.lang import System
699 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000700 value = System.getProperty(name)
701 if value is None:
702 return default
703 return value
704 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000705 return default
706
Victor Stinnerced39362013-12-09 00:14:52 +0100707def java_ver(release='', vendor='', vminfo=('', '', ''), osinfo=('', '', '')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000708
Brett Cannon8ab27df2003-08-05 03:52:04 +0000709 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000710
Victor Stinnerced39362013-12-09 00:14:52 +0100711 Returns a tuple (release, vendor, vminfo, osinfo) with vminfo being
712 a tuple (vm_name, vm_release, vm_vendor) and osinfo being a
713 tuple (os_name, os_version, os_arch).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000714
715 Values which cannot be determined are set to the defaults
716 given as parameters (which all default to '').
717
718 """
719 # Import the needed APIs
720 try:
721 import java.lang
Brett Cannoncd171c82013-07-04 17:43:24 -0400722 except ImportError:
Victor Stinnerced39362013-12-09 00:14:52 +0100723 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000724
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000725 vendor = _java_getprop('java.vendor', vendor)
726 release = _java_getprop('java.version', release)
727 vm_name, vm_release, vm_vendor = vminfo
728 vm_name = _java_getprop('java.vm.name', vm_name)
729 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
730 vm_release = _java_getprop('java.vm.version', vm_release)
731 vminfo = vm_name, vm_release, vm_vendor
732 os_name, os_version, os_arch = osinfo
733 os_arch = _java_getprop('java.os.arch', os_arch)
734 os_name = _java_getprop('java.os.name', os_name)
735 os_version = _java_getprop('java.os.version', os_version)
736 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000737
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000738 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000739
740### System name aliasing
741
Victor Stinnerced39362013-12-09 00:14:52 +0100742def system_alias(system, release, version):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000743
Victor Stinnerced39362013-12-09 00:14:52 +0100744 """ Returns (system, release, version) aliased to common
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000745 marketing names used for some systems.
746
747 It also does some reordering of the information in some cases
748 where it would otherwise cause confusion.
749
750 """
751 if system == 'Rhapsody':
752 # Apple's BSD derivative
753 # XXX How can we determine the marketing release number ?
Victor Stinnerced39362013-12-09 00:14:52 +0100754 return 'MacOS X Server', system+release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000755
756 elif system == 'SunOS':
757 # Sun's OS
758 if release < '5':
759 # These releases use the old name SunOS
Victor Stinnerced39362013-12-09 00:14:52 +0100760 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000761 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000762 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000763 if l:
764 try:
765 major = int(l[0])
766 except ValueError:
767 pass
768 else:
769 major = major - 3
770 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000771 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000772 if release < '6':
773 system = 'Solaris'
774 else:
775 # XXX Whatever the new SunOS marketing name is...
776 system = 'Solaris'
777
778 elif system == 'IRIX64':
779 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
780 # is really a version and not a different platform, since 32-bit
781 # apps are also supported..
782 system = 'IRIX'
783 if version:
784 version = version + ' (64bit)'
785 else:
786 version = '64bit'
787
Victor Stinnerced39362013-12-09 00:14:52 +0100788 elif system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000789 # In case one of the other tricks
790 system = 'Windows'
791
Victor Stinnerced39362013-12-09 00:14:52 +0100792 return system, release, version
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000793
794### Various internal helpers
795
796def _platform(*args):
797
798 """ Helper to format the platform string in a filename
799 compatible format e.g. "system-version-machine".
800 """
801 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000802 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000803
804 # Cleanup some possible filename obstacles...
Victor Stinnerced39362013-12-09 00:14:52 +0100805 platform = platform.replace(' ', '_')
806 platform = platform.replace('/', '-')
807 platform = platform.replace('\\', '-')
808 platform = platform.replace(':', '-')
809 platform = platform.replace(';', '-')
810 platform = platform.replace('"', '-')
811 platform = platform.replace('(', '-')
812 platform = platform.replace(')', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000813
814 # No need to report 'unknown' information...
Victor Stinnerced39362013-12-09 00:14:52 +0100815 platform = platform.replace('unknown', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000816
817 # Fold '--'s and remove trailing '-'
818 while 1:
Victor Stinnerced39362013-12-09 00:14:52 +0100819 cleaned = platform.replace('--', '-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000820 if cleaned == platform:
821 break
822 platform = cleaned
823 while platform[-1] == '-':
824 platform = platform[:-1]
825
826 return platform
827
828def _node(default=''):
829
830 """ Helper to determine the node name of this machine.
831 """
832 try:
833 import socket
Brett Cannoncd171c82013-07-04 17:43:24 -0400834 except ImportError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000835 # No sockets...
836 return default
837 try:
838 return socket.gethostname()
Andrew Svetlov0832af62012-12-18 23:10:48 +0200839 except OSError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000840 # Still not working...
841 return default
842
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000843def _follow_symlinks(filepath):
844
845 """ In case filepath is a symlink, follow it until a
846 real file is reached.
847 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000848 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000849 while os.path.islink(filepath):
850 filepath = os.path.normpath(
Victor Stinnerced39362013-12-09 00:14:52 +0100851 os.path.join(os.path.dirname(filepath), os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000852 return filepath
853
Victor Stinnerced39362013-12-09 00:14:52 +0100854def _syscmd_uname(option, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000855
856 """ Interface to the system's uname command.
857 """
Victor Stinnerced39362013-12-09 00:14:52 +0100858 if sys.platform in ('dos', 'win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000859 # XXX Others too ?
860 return default
861 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000862 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200863 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000864 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000865 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000866 rc = f.close()
867 if not output or rc:
868 return default
869 else:
870 return output
871
Victor Stinnerced39362013-12-09 00:14:52 +0100872def _syscmd_file(target, default=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000873
874 """ Interface to the system's file command.
875
876 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000877 omit the filename in its output. Follow the symlinks. It returns
878 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000879
880 """
Victor Stinnerced39362013-12-09 00:14:52 +0100881 if sys.platform in ('dos', 'win32', 'win16'):
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000882 # XXX Others too ?
883 return default
Jesus Ceafc990e92012-10-04 13:51:43 +0200884 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000885 try:
Jesus Cea685fffa2012-10-05 05:21:42 +0200886 proc = subprocess.Popen(['file', target],
887 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Ceae8801e22012-10-04 13:56:23 +0200888
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200889 except (AttributeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000890 return default
Jesus Ceacb959962012-10-05 05:31:31 +0200891 output = proc.communicate()[0].decode('latin-1')
Jesus Ceafc990e92012-10-04 13:51:43 +0200892 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000893 if not output or rc:
894 return default
895 else:
896 return output
897
898### Information about the used architecture
899
900# Default values for architecture; non-empty strings override the
901# defaults given as parameters
902_default_architecture = {
Victor Stinnerced39362013-12-09 00:14:52 +0100903 'win32': ('', 'WindowsPE'),
904 'win16': ('', 'Windows'),
905 'dos': ('', 'MSDOS'),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000906}
907
Victor Stinnerced39362013-12-09 00:14:52 +0100908def architecture(executable=sys.executable, bits='', linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000909
910 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000911 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000912
Victor Stinnerced39362013-12-09 00:14:52 +0100913 Returns a tuple (bits, linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000914 the bit architecture and the linkage format used for the
915 executable. Both values are returned as strings.
916
917 Values that cannot be determined are returned as given by the
918 parameter presets. If bits is given as '', the sizeof(pointer)
919 (or sizeof(long) on Python version < 1.5.2) is used as
920 indicator for the supported pointer size.
921
922 The function relies on the system's "file" command to do the
923 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000924 platforms. On some non-Unix platforms where the "file" command
925 does not exist and the executable is set to the Python interpreter
926 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000927
928 """
929 # Use the sizeof(pointer) as default number of bits if nothing
930 # else is given as default.
931 if not bits:
932 import struct
933 try:
934 size = struct.calcsize('P')
935 except struct.error:
936 # Older installations can only query longs
937 size = struct.calcsize('l')
938 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000939
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000940 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000941 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000942 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000943 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000944 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000945
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000946 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000947 executable == sys.executable:
948 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000949 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000950 if sys.platform in _default_architecture:
Victor Stinnerced39362013-12-09 00:14:52 +0100951 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000952 if b:
953 bits = b
954 if l:
955 linkage = l
Victor Stinnerced39362013-12-09 00:14:52 +0100956 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000957
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000958 if 'executable' not in fileout:
959 # Format not supported
Victor Stinnerced39362013-12-09 00:14:52 +0100960 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000961
962 # Bits
963 if '32-bit' in fileout:
964 bits = '32bit'
965 elif 'N32' in fileout:
966 # On Irix only
967 bits = 'n32bit'
968 elif '64-bit' in fileout:
969 bits = '64bit'
970
971 # Linkage
972 if 'ELF' in fileout:
973 linkage = 'ELF'
974 elif 'PE' in fileout:
975 # E.g. Windows uses this format
976 if 'Windows' in fileout:
977 linkage = 'WindowsPE'
978 else:
979 linkage = 'PE'
980 elif 'COFF' in fileout:
981 linkage = 'COFF'
982 elif 'MS-DOS' in fileout:
983 linkage = 'MSDOS'
984 else:
985 # XXX the A.OUT format also falls under this class...
986 pass
987
Victor Stinnerced39362013-12-09 00:14:52 +0100988 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000989
990### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +0000991
Larry Hastings68386bc2012-06-24 14:30:41 -0700992uname_result = collections.namedtuple("uname_result",
993 "system node release version machine processor")
994
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000995_uname_cache = None
996
997def uname():
998
999 """ Fairly portable uname interface. Returns a tuple
Victor Stinnerced39362013-12-09 00:14:52 +01001000 of strings (system, node, release, version, machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001001 identifying the underlying platform.
1002
1003 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001004 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001005
1006 Entries which cannot be determined are set to ''.
1007
1008 """
1009 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001010 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001011
1012 if _uname_cache is not None:
1013 return _uname_cache
1014
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001015 processor = ''
1016
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001017 # Get some infos from the builtin os.uname API...
1018 try:
Victor Stinnerced39362013-12-09 00:14:52 +01001019 system, node, release, version, machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001020 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001021 no_os_uname = 1
1022
Georg Brandl62e2ca22010-07-31 21:54:24 +00001023 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001024 # Hmm, no there is either no uname or uname has returned
1025 #'unknowns'... we'll have to poke around the system then.
1026 if no_os_uname:
1027 system = sys.platform
1028 release = ''
1029 version = ''
1030 node = _node()
1031 machine = ''
1032
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001033 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001034
1035 # Try win32_ver() on win32 platforms
1036 if system == 'win32':
Victor Stinnerced39362013-12-09 00:14:52 +01001037 release, version, csd, ptype = win32_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001038 if release and version:
1039 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001040 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001041 # available on Win XP and later; see
1042 # http://support.microsoft.com/kb/888731 and
1043 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001044 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001045 # WOW64 processes mask the native architecture
1046 if "PROCESSOR_ARCHITEW6432" in os.environ:
1047 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1048 else:
1049 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001050 if not processor:
1051 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001052
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001053 # Try the 'ver' system command available on some
1054 # platforms
1055 if use_syscmd_ver:
Victor Stinnerced39362013-12-09 00:14:52 +01001056 system, release, version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001057 # Normalize system to what win32_ver() normally returns
1058 # (_syscmd_ver() tends to return the vendor name as well)
1059 if system == 'Microsoft Windows':
1060 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001061 elif system == 'Microsoft' and release == 'Windows':
1062 # Under Windows Vista and Windows Server 2008,
1063 # Microsoft changed the output of the ver command. The
1064 # release is no longer printed. This causes the
1065 # system and release to be misidentified.
1066 system = 'Windows'
1067 if '6.0' == version[:3]:
1068 release = 'Vista'
1069 else:
1070 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001071
1072 # In case we still don't know anything useful, we'll try to
1073 # help ourselves
Victor Stinnerced39362013-12-09 00:14:52 +01001074 if system in ('win32', 'win16'):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001075 if not version:
1076 if system == 'win32':
1077 version = '32bit'
1078 else:
1079 version = '16bit'
1080 system = 'Windows'
1081
1082 elif system[:4] == 'java':
Victor Stinnerced39362013-12-09 00:14:52 +01001083 release, vendor, vminfo, osinfo = java_ver()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001084 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001085 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001086 if not version:
1087 version = vendor
1088
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001089 # System specific extensions
1090 if system == 'OpenVMS':
1091 # OpenVMS seems to have release and version mixed up
1092 if not release or release == '0':
1093 release = version
1094 version = ''
1095 # Get processor information
1096 try:
1097 import vms_lib
Brett Cannoncd171c82013-07-04 17:43:24 -04001098 except ImportError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001099 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001100 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001101 csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001102 if (cpu_number >= 128):
1103 processor = 'Alpha'
1104 else:
1105 processor = 'VAX'
1106 if not processor:
1107 # Get processor information from the uname system command
Victor Stinnerced39362013-12-09 00:14:52 +01001108 processor = _syscmd_uname('-p', '')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001109
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001110 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001111 if system == 'unknown':
1112 system = ''
1113 if node == 'unknown':
1114 node = ''
1115 if release == 'unknown':
1116 release = ''
1117 if version == 'unknown':
1118 version = ''
1119 if machine == 'unknown':
1120 machine = ''
1121 if processor == 'unknown':
1122 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001123
1124 # normalize name
1125 if system == 'Microsoft' and release == 'Windows':
1126 system = 'Windows'
1127 release = 'Vista'
1128
Victor Stinnerced39362013-12-09 00:14:52 +01001129 _uname_cache = uname_result(system, node, release, version,
1130 machine, processor)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001131 return _uname_cache
1132
1133### Direct interfaces to some of the uname() return values
1134
1135def system():
1136
1137 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1138
1139 An empty string is returned if the value cannot be determined.
1140
1141 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001142 return uname().system
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001143
1144def node():
1145
Brett Cannon8ab27df2003-08-05 03:52:04 +00001146 """ Returns the computer's network name (which may not be fully
1147 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001148
1149 An empty string is returned if the value cannot be determined.
1150
1151 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001152 return uname().node
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001153
1154def release():
1155
1156 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1157
1158 An empty string is returned if the value cannot be determined.
1159
1160 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001161 return uname().release
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001162
1163def version():
1164
1165 """ Returns the system's release version, e.g. '#3 on degas'
1166
1167 An empty string is returned if the value cannot be determined.
1168
1169 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001170 return uname().version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001171
1172def machine():
1173
1174 """ Returns the machine type, e.g. 'i386'
1175
1176 An empty string is returned if the value cannot be determined.
1177
1178 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001179 return uname().machine
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001180
1181def processor():
1182
1183 """ Returns the (true) processor name, e.g. 'amdk6'
1184
1185 An empty string is returned if the value cannot be
1186 determined. Note that many platforms do not provide this
1187 information or simply return the same value as for machine(),
1188 e.g. NetBSD does this.
1189
1190 """
Larry Hastings68386bc2012-06-24 14:30:41 -07001191 return uname().processor
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001192
1193### Various APIs for extracting information from sys.version
1194
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001195_sys_version_parser = re.compile(
1196 r'([\w.+]+)\s*'
1197 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001198 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001199
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001200_ironpython_sys_version_parser = re.compile(
1201 r'IronPython\s*'
1202 '([\d\.]+)'
1203 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001204 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001205
Ezio Melottif076f532013-10-21 03:03:32 +03001206# IronPython covering 2.6 and 2.7
1207_ironpython26_sys_version_parser = re.compile(
1208 r'([\d.]+)\s*'
1209 '\(IronPython\s*'
1210 '[\d.]+\s*'
1211 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1212)
1213
Benjamin Petersone549ead2009-03-28 21:42:05 +00001214_pypy_sys_version_parser = re.compile(
1215 r'([\w.+]+)\s*'
1216 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1217 '\[PyPy [^\]]+\]?')
1218
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001219_sys_version_cache = {}
1220
1221def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001222
1223 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001224 (name, version, branch, revision, buildno, builddate, compiler)
1225 referring to the Python implementation name, version, branch,
1226 revision, build number, build date/time as string and the compiler
1227 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001228
1229 Note that unlike the Python sys.version, the returned value
1230 for the Python version will always include the patchlevel (it
1231 defaults to '.0').
1232
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001233 The function returns empty strings for tuple entries that
1234 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001235
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001236 sys_version may be given to parse an alternative version
1237 string, e.g. if the version was read from a different Python
1238 interpreter.
1239
1240 """
1241 # Get the Python version
1242 if sys_version is None:
1243 sys_version = sys.version
1244
1245 # Try the cache first
1246 result = _sys_version_cache.get(sys_version, None)
1247 if result is not None:
1248 return result
1249
1250 # Parse it
Ezio Melottif076f532013-10-21 03:03:32 +03001251 if 'IronPython' in sys_version:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001252 # IronPython
1253 name = 'IronPython'
Ezio Melottif076f532013-10-21 03:03:32 +03001254 if sys_version.startswith('IronPython'):
1255 match = _ironpython_sys_version_parser.match(sys_version)
1256 else:
1257 match = _ironpython26_sys_version_parser.match(sys_version)
1258
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001259 if match is None:
1260 raise ValueError(
1261 'failed to parse IronPython sys.version: %s' %
1262 repr(sys_version))
Ezio Melottif076f532013-10-21 03:03:32 +03001263
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001264 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001265 buildno = ''
1266 builddate = ''
1267
Ezio Melottif076f532013-10-21 03:03:32 +03001268 elif sys.platform.startswith('java'):
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001269 # Jython
1270 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001271 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001272 if match is None:
1273 raise ValueError(
1274 'failed to parse Jython sys.version: %s' %
1275 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001276 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001277 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001278
1279 elif "PyPy" in sys_version:
1280 # PyPy
1281 name = "PyPy"
1282 match = _pypy_sys_version_parser.match(sys_version)
1283 if match is None:
1284 raise ValueError("failed to parse PyPy sys.version: %s" %
1285 repr(sys_version))
1286 version, buildno, builddate, buildtime = match.groups()
1287 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001288
1289 else:
1290 # CPython
1291 match = _sys_version_parser.match(sys_version)
1292 if match is None:
1293 raise ValueError(
1294 'failed to parse CPython sys.version: %s' %
1295 repr(sys_version))
1296 version, buildno, builddate, buildtime, compiler = \
1297 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001298 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001299 builddate = builddate + ' ' + buildtime
1300
Georg Brandl82562422011-03-05 21:09:22 +01001301 if hasattr(sys, '_mercurial'):
1302 _, branch, revision = sys._mercurial
1303 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001304 # sys.subversion was added in Python 2.5
1305 _, branch, revision = sys.subversion
1306 else:
1307 branch = ''
1308 revision = ''
1309
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001310 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001311 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001312 if len(l) == 2:
1313 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001314 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001315
1316 # Build and cache the result
1317 result = (name, version, branch, revision, buildno, builddate, compiler)
1318 _sys_version_cache[sys_version] = result
1319 return result
1320
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001321def python_implementation():
1322
1323 """ Returns a string identifying the Python implementation.
1324
1325 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001326 'CPython' (C implementation of Python),
1327 'IronPython' (.NET implementation of Python),
1328 'Jython' (Java implementation of Python),
1329 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001330
1331 """
1332 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001333
1334def python_version():
1335
1336 """ Returns the Python version as string 'major.minor.patchlevel'
1337
1338 Note that unlike the Python sys.version, the returned value
1339 will always include the patchlevel (it defaults to 0).
1340
1341 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001342 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001343
1344def python_version_tuple():
1345
1346 """ Returns the Python version as tuple (major, minor, patchlevel)
1347 of strings.
1348
1349 Note that unlike the Python sys.version, the returned value
1350 will always include the patchlevel (it defaults to 0).
1351
1352 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001353 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001354
1355def python_branch():
1356
1357 """ Returns a string identifying the Python implementation
1358 branch.
1359
1360 For CPython this is the Subversion branch from which the
1361 Python binary was built.
1362
1363 If not available, an empty string is returned.
1364
1365 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001366
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001367 return _sys_version()[2]
1368
1369def python_revision():
1370
1371 """ Returns a string identifying the Python implementation
1372 revision.
1373
1374 For CPython this is the Subversion revision from which the
1375 Python binary was built.
1376
1377 If not available, an empty string is returned.
1378
1379 """
1380 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001381
1382def python_build():
1383
1384 """ Returns a tuple (buildno, builddate) stating the Python
1385 build number and date as strings.
1386
1387 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001388 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001389
1390def python_compiler():
1391
1392 """ Returns a string identifying the compiler used for compiling
1393 Python.
1394
1395 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001396 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001397
1398### The Opus Magnum of platform strings :-)
1399
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001400_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401
1402def platform(aliased=0, terse=0):
1403
1404 """ Returns a single string identifying the underlying platform
1405 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001406
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001407 The output is intended to be human readable rather than
1408 machine parseable. It may look different on different
1409 platforms and this is intended.
1410
1411 If "aliased" is true, the function will use aliases for
1412 various platforms that report system names which differ from
1413 their common names, e.g. SunOS will be reported as
1414 Solaris. The system_alias() function is used to implement
1415 this.
1416
1417 Setting terse to true causes the function to return only the
1418 absolute minimum information needed to identify the platform.
1419
1420 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001421 result = _platform_cache.get((aliased, terse), None)
1422 if result is not None:
1423 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001424
1425 # Get uname information and then apply platform specific cosmetics
1426 # to it...
Victor Stinnerced39362013-12-09 00:14:52 +01001427 system, node, release, version, machine, processor = uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001428 if machine == processor:
1429 processor = ''
1430 if aliased:
Victor Stinnerced39362013-12-09 00:14:52 +01001431 system, release, version = system_alias(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001432
1433 if system == 'Windows':
1434 # MS platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001435 rel, vers, csd, ptype = win32_ver(version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001436 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001437 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001438 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001439 platform = _platform(system, release, version, csd)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001440
1441 elif system in ('Linux',):
1442 # Linux based systems
Berker Peksag1392f712015-05-16 20:24:28 +03001443 with warnings.catch_warnings():
1444 # see issue #1322 for more information
1445 warnings.filterwarnings(
1446 'ignore',
1447 'dist\(\) and linux_distribution\(\) '
1448 'functions are deprecated .*',
1449 PendingDeprecationWarning,
1450 )
1451 distname, distversion, distid = dist('')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001452 if distname and not terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001453 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001454 'with',
Victor Stinnerced39362013-12-09 00:14:52 +01001455 distname, distversion, distid)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001456 else:
1457 # If the distribution name is unknown check for libc vs. glibc
Victor Stinnerced39362013-12-09 00:14:52 +01001458 libcname, libcversion = libc_ver(sys.executable)
1459 platform = _platform(system, release, machine, processor,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001460 'with',
1461 libcname+libcversion)
1462 elif system == 'Java':
1463 # Java platforms
Victor Stinnerced39362013-12-09 00:14:52 +01001464 r, v, vminfo, (os_name, os_version, os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001465 if terse or not os_name:
Victor Stinnerced39362013-12-09 00:14:52 +01001466 platform = _platform(system, release, version)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001467 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001468 platform = _platform(system, release, version,
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001469 'on',
Victor Stinnerced39362013-12-09 00:14:52 +01001470 os_name, os_version, os_arch)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001471
1472 elif system == 'MacOS':
1473 # MacOS platforms
1474 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001475 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001476 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001477 platform = _platform(system, release, machine)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001478
1479 else:
1480 # Generic handler
1481 if terse:
Victor Stinnerced39362013-12-09 00:14:52 +01001482 platform = _platform(system, release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001483 else:
Victor Stinnerced39362013-12-09 00:14:52 +01001484 bits, linkage = architecture(sys.executable)
1485 platform = _platform(system, release, machine,
1486 processor, bits, linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001487
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001488 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001489 return platform
1490
1491### Command line interface
1492
1493if __name__ == '__main__':
1494 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001495 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001496 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Victor Stinnerced39362013-12-09 00:14:52 +01001497 print(platform(aliased, terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001498 sys.exit(0)