blob: 0cb0a4fc436a1f1e195e20207d7f98fd2e1e4e03 [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
Victor Stinnerb27ee202010-04-18 18:28:09 +0000114import sys, os, re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000115
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000116### Globals & Constants
117
118# Determine the platform's /dev/null device
119try:
120 DEV_NULL = os.devnull
121except AttributeError:
122 # os.devnull was added in Python 2.4, so emulate it for earlier
123 # Python versions
124 if sys.platform in ('dos','win32','win16','os2'):
125 # Use the old CP/M NUL as device name
126 DEV_NULL = 'NUL'
127 else:
128 # Standard Unix uses /dev/null
129 DEV_NULL = '/dev/null'
130
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000131### Platform specific APIs
132
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000133_libc_search = re.compile(r'(__libc_init)'
134 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000135 '(GLIBC_([0-9.]+))'
136 '|'
Antoine Pitroufd036452008-08-19 17:56:33 +0000137 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000138
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000139def libc_ver(executable=sys.executable,lib='',version='',
140
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000141 chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000142
Brett Cannon8ab27df2003-08-05 03:52:04 +0000143 """ Tries to determine the libc version that the file executable
144 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000145
146 Returns a tuple of strings (lib,version) which default to the
147 given parameters in case the lookup fails.
148
149 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000150 libc versions add symbols to the executable and thus is probably
151 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000152
153 The file is read and scanned in chunks of chunksize bytes.
154
155 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000156 if hasattr(os.path, 'realpath'):
157 # Python 2.2 introduced os.path.realpath(); it is used
158 # here to work around problems with Cygwin not being
159 # able to open symlinks for reading
160 executable = os.path.realpath(executable)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000161 f = open(executable,'rb')
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000162 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000163 pos = 0
164 while 1:
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000165 m = _libc_search.search(binary,pos)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000166 if not m:
Walter Dörwaldc3b6ac72007-06-07 19:26:24 +0000167 binary = f.read(chunksize).decode('latin-1')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000168 if not binary:
169 break
170 pos = 0
171 continue
172 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
173 if libcinit and not lib:
174 lib = 'libc'
175 elif glibc:
176 if lib != 'glibc':
177 lib = 'glibc'
178 version = glibcversion
179 elif glibcversion > version:
180 version = glibcversion
181 elif so:
182 if lib != 'glibc':
183 lib = 'libc'
184 if soversion > version:
185 version = soversion
186 if threads and version[-len(threads):] != threads:
187 version = version + threads
188 pos = m.end()
189 f.close()
190 return lib,version
191
192def _dist_try_harder(distname,version,id):
193
Tim Peters0eadaac2003-04-24 16:02:54 +0000194 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000195 information in case the default method fails.
196
197 Currently supports older SuSE Linux, Caldera OpenLinux and
198 Slackware Linux distributions.
199
200 """
201 if os.path.exists('/var/adm/inst-log/info'):
202 # SuSE Linux stores distribution information in that file
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000203 distname = 'SuSE'
Florent Xicluna7dde7922010-09-03 19:52:03 +0000204 for line in open('/var/adm/inst-log/info'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000205 tv = line.split()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000206 if len(tv) == 2:
207 tag,value = tv
208 else:
209 continue
210 if tag == 'MIN_DIST_VERSION':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000211 version = value.strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000212 elif tag == 'DIST_IDENT':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000213 values = value.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000214 id = values[2]
215 return distname,version,id
216
217 if os.path.exists('/etc/.installed'):
218 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
Florent Xicluna7dde7922010-09-03 19:52:03 +0000219 for line in open('/etc/.installed'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000220 pkg = line.split('-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000221 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
222 # XXX does Caldera support non Intel platforms ? If yes,
223 # where can we find the needed id ?
224 return 'OpenLinux',pkg[1],id
225
226 if os.path.isdir('/usr/lib/setup'):
227 # Check for slackware verson tag file (thanks to Greg Andruk)
228 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000229 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000230 if verfiles[n][:14] != 'slack-version-':
231 del verfiles[n]
232 if verfiles:
233 verfiles.sort()
234 distname = 'slackware'
235 version = verfiles[-1][14:]
236 return distname,version,id
237
238 return distname,version,id
239
Antoine Pitroufd036452008-08-19 17:56:33 +0000240_release_filename = re.compile(r'(\w+)[-_](release|version)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000241_lsb_release_version = re.compile(r'(.+)'
242 ' release '
243 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000244 '[^(]*(?:\((.+)\))?', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000245_release_version = re.compile(r'([^0-9]+)'
246 '(?: release )?'
247 '([\d.]+)'
Antoine Pitroufd036452008-08-19 17:56:33 +0000248 '[^(]*(?:\((.+)\))?', re.ASCII)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000249
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000250# See also http://www.novell.com/coolsolutions/feature/11251.html
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000251# and http://linuxmafia.com/faq/Admin/release-files.html
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000252# and http://data.linux-ntfs.org/rpm/whichrpm
253# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000254
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000255_supported_dists = (
256 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
257 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
258 'UnitedLinux', 'turbolinux')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000259
260def _parse_release_file(firstline):
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000261
Benjamin Peterson25001472010-01-25 03:37:42 +0000262 # Default to empty 'version' and 'id' strings. Both defaults are used
263 # when 'firstline' is empty. 'id' defaults to empty when an id can not
264 # be deduced.
265 version = ''
266 id = ''
267
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000268 # Parse the first line
269 m = _lsb_release_version.match(firstline)
270 if m is not None:
271 # LSB format: "distro release x.x (codename)"
272 return tuple(m.groups())
273
274 # Pre-LSB format: "distro x.x (codename)"
275 m = _release_version.match(firstline)
276 if m is not None:
277 return tuple(m.groups())
278
279 # Unkown format... take the first two words
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000280 l = firstline.strip().split()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000281 if l:
282 version = l[0]
283 if len(l) > 1:
284 id = l[1]
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000285 return '', version, id
286
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000287def linux_distribution(distname='', version='', id='',
288
289 supported_dists=_supported_dists,
290 full_distribution_name=1):
291
292 """ Tries to determine the name of the Linux OS distribution name.
293
294 The function first looks for a distribution release file in
295 /etc and then reverts to _dist_try_harder() in case no
296 suitable files are found.
297
298 supported_dists may be given to define the set of Linux
299 distributions to look for. It defaults to a list of currently
300 supported Linux distributions identified by their release file
301 name.
302
303 If full_distribution_name is true (default), the full
304 distribution read from the OS is returned. Otherwise the short
305 name taken from supported_dists is used.
306
307 Returns a tuple (distname,version,id) which default to the
308 args given as parameters.
309
310 """
311 try:
312 etc = os.listdir('/etc')
313 except os.error:
314 # Probably not a Unix system
315 return distname,version,id
316 etc.sort()
317 for file in etc:
318 m = _release_filename.match(file)
319 if m is not None:
320 _distname,dummy = m.groups()
321 if _distname in supported_dists:
322 distname = _distname
323 break
324 else:
325 return _dist_try_harder(distname,version,id)
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000326
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000327 # Read the first line
Florent Xicluna7dde7922010-09-03 19:52:03 +0000328 with open('/etc/'+file, 'r') as f:
329 firstline = f.readline()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000330 _distname, _version, _id = _parse_release_file(firstline)
331
332 if _distname and full_distribution_name:
333 distname = _distname
334 if _version:
335 version = _version
336 if _id:
337 id = _id
338 return distname, version, id
339
340# To maintain backwards compatibility:
Thomas Wouters9fe394c2007-02-05 01:24:16 +0000341
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000342def dist(distname='',version='',id='',
343
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000344 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000345
Brett Cannon8ab27df2003-08-05 03:52:04 +0000346 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000347
348 The function first looks for a distribution release file in
349 /etc and then reverts to _dist_try_harder() in case no
350 suitable files are found.
351
Brett Cannon8ab27df2003-08-05 03:52:04 +0000352 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000353 args given as parameters.
354
355 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000356 return linux_distribution(distname, version, id,
357 supported_dists=supported_dists,
358 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000359
Antoine Pitrou877766d2011-03-19 17:00:37 +0100360def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000361
362 """ Portable popen() interface.
363 """
Victor Stinner25000d42011-05-24 00:16:16 +0200364 import warnings
365 warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2)
Victor Stinner1dfd3802011-03-03 12:54:07 +0000366 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000367
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000368def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000369
Brett Cannon8ab27df2003-08-05 03:52:04 +0000370 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000371 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000372 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000373 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000374 if build:
375 l.append(build)
376 try:
377 ints = map(int,l)
378 except ValueError:
379 strings = l
380 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000381 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000382 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383 return version
384
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000385_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
386 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000387 '\[.* ([\d.]+)\])')
388
389# Examples of VER command output:
390#
391# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
392# Windows XP: Microsoft Windows XP [Version 5.1.2600]
393# Windows Vista: Microsoft Windows [Version 6.0.6002]
394#
395# Note that the "Version" string gets localized on different
396# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000397
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000398def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000399
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000400 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000401
402 """ Tries to figure out the OS version used and returns
403 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000404
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000405 It uses the "ver" shell command for this which is known
406 to exists on Windows, DOS and OS/2. XXX Others too ?
407
408 In case this fails, the given parameters are used as
409 defaults.
410
411 """
412 if sys.platform not in supported_platforms:
413 return system,release,version
414
415 # Try some common cmd strings
416 for cmd in ('ver','command /c ver','cmd /c ver'):
417 try:
418 pipe = popen(cmd)
419 info = pipe.read()
420 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000421 raise os.error('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200422 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000423 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000424 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000425 #print 'Command %s failed: %s' % (cmd,why)
426 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000427 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000428 #print 'Command %s failed: %s' % (cmd,why)
429 continue
430 else:
431 break
432 else:
433 return system,release,version
434
435 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000436 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000437 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000438 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000439 system,release,version = m.groups()
440 # Strip trailing dots from version and release
441 if release[-1] == '.':
442 release = release[:-1]
443 if version[-1] == '.':
444 version = version[:-1]
445 # Normalize the version and build strings (eliminating additional
446 # zeros)
447 version = _norm_version(version)
448 return system,release,version
449
450def _win32_getvalue(key,name,default=''):
451
452 """ Read a value for name from the registry key.
453
454 In case this fails, default is returned.
455
456 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000457 try:
458 # Use win32api if available
459 from win32api import RegQueryValueEx
460 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000461 # On Python 2.0 and later, emulate using winreg
462 import winreg
463 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000464 try:
465 return RegQueryValueEx(key,name)
466 except:
467 return default
468
469def win32_ver(release='',version='',csd='',ptype=''):
470
471 """ Get additional version information from the Windows Registry
472 and return a tuple (version,csd,ptype) referring to version
473 number, CSD level and OS type (multi/single
474 processor).
475
476 As a hint: ptype returns 'Uniprocessor Free' on single
477 processor NT machines and 'Multiprocessor Free' on multi
478 processor machines. The 'Free' refers to the OS version being
479 free of debugging code. It could also state 'Checked' which
480 means the OS version uses debugging code, i.e. code that
481 checks arguments, ranges, etc. (Thomas Heller).
482
Christian Heimes02781dc2008-03-21 01:11:52 +0000483 Note: this function works best with Mark Hammond's win32
484 package installed, but also on Python 2.3 and later. It
485 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000486
487 """
488 # XXX Is there any way to find out the processor type on WinXX ?
489 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000490 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000491 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000492 #
493 # The mappings between reg. values and release names can be found
494 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000495
496 # Import the needed APIs
497 try:
498 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000499 from win32api import RegQueryValueEx, RegOpenKeyEx, \
500 RegCloseKey, GetVersionEx
501 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
502 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000503 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000504 # Emulate the win32api module using Python APIs
505 try:
506 sys.getwindowsversion
507 except AttributeError:
508 # No emulation possible, so return the defaults...
509 return release,version,csd,ptype
510 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000511 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000512 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000513 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000514 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000515 RegQueryValueEx = winreg.QueryValueEx
516 RegOpenKeyEx = winreg.OpenKeyEx
517 RegCloseKey = winreg.CloseKey
518 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000519 VER_PLATFORM_WIN32_WINDOWS = 1
520 VER_PLATFORM_WIN32_NT = 2
521 VER_NT_WORKSTATION = 1
Brian Curtin6e2824d2010-05-06 03:05:50 +0000522 VER_NT_SERVER = 3
523 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000524
525 # Find out the registry key and some general version infos
Brian Curtin6e2824d2010-05-06 03:05:50 +0000526 winver = GetVersionEx()
527 maj,min,buildno,plat,csd = winver
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000528 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
Brian Curtin6e2824d2010-05-06 03:05:50 +0000529 if hasattr(winver, "service_pack"):
530 if winver.service_pack != "":
531 csd = 'SP%s' % winver.service_pack_major
532 else:
533 if csd[:13] == 'Service Pack ':
534 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000535
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000536 if plat == VER_PLATFORM_WIN32_WINDOWS:
537 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
538 # Try to guess the release name
539 if maj == 4:
540 if min == 0:
541 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000542 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000543 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000544 elif min == 90:
545 release = 'Me'
546 else:
547 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000548 elif maj == 5:
549 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000550
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000551 elif plat == VER_PLATFORM_WIN32_NT:
552 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
553 if maj <= 4:
554 release = 'NT'
555 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000556 if min == 0:
557 release = '2000'
558 elif min == 1:
559 release = 'XP'
560 elif min == 2:
561 release = '2003Server'
562 else:
563 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000564 elif maj == 6:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000565 if hasattr(winver, "product_type"):
566 product_type = winver.product_type
567 else:
568 product_type = VER_NT_WORKSTATION
569 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
570 # or help from the registry, we cannot properly identify
571 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000572 try:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000573 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
574 name, type = RegQueryValueEx(key, "ProductName")
575 # Discard any type that isn't REG_SZ
576 if type == REG_SZ and name.find("Server") != -1:
577 product_type = VER_NT_SERVER
578 except WindowsError:
579 # Use default of VER_NT_WORKSTATION
580 pass
581
582 if min == 0:
583 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000584 release = 'Vista'
585 else:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000586 release = '2008Server'
587 elif min == 1:
588 if product_type == VER_NT_WORKSTATION:
589 release = '7'
590 else:
591 release = '2008ServerR2'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000592 else:
593 release = 'post2008Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000594
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000595 else:
596 if not release:
597 # E.g. Win3.1 with win32s
598 release = '%i.%i' % (maj,min)
599 return release,version,csd,ptype
600
601 # Open the registry key
602 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000603 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000604 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000605 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000606 except:
607 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000608
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000609 # Parse values
610 #subversion = _win32_getvalue(keyCurVer,
611 # 'SubVersionNumber',
612 # ('',1))[0]
613 #if subversion:
614 # release = release + subversion # 95a, 95b, etc.
615 build = _win32_getvalue(keyCurVer,
616 'CurrentBuildNumber',
617 ('',1))[0]
618 ptype = _win32_getvalue(keyCurVer,
619 'CurrentType',
620 (ptype,1))[0]
621
622 # Normalize version
623 version = _norm_version(version,build)
624
625 # Close key
626 RegCloseKey(keyCurVer)
627 return release,version,csd,ptype
628
629def _mac_ver_lookup(selectors,default=None):
630
Benjamin Petersonebacd262008-05-29 21:09:51 +0000631 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000632 l = []
633 append = l.append
634 for selector in selectors:
635 try:
636 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000637 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000638 append(default)
639 return l
640
641def _bcd2str(bcd):
642
643 return hex(bcd)[2:]
644
Ronald Oussorene186e382010-07-23 11:54:59 +0000645def _mac_ver_gestalt():
646 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000647 Thanks to Mark R. Levinson for mailing documentation links and
648 code examples for this function. Documentation for the
649 gestalt() API is available online at:
650
651 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000652 """
653 # Check whether the version info module is available
654 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000655 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000656 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000657 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000658 # Get the infos
Ronald Oussoren19258d52010-02-07 11:33:33 +0000659 sysv, sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000660 # Decode the infos
661 if sysv:
662 major = (sysv & 0xFF00) >> 8
663 minor = (sysv & 0x00F0) >> 4
664 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000665
666 if (major, minor) >= (10, 4):
667 # the 'sysv' gestald cannot return patchlevels
668 # higher than 9. Apple introduced 3 new
669 # gestalt codes in 10.4 to deal with this
670 # issue (needed because patch levels can
671 # run higher than 9, such as 10.4.11)
672 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
673 release = '%i.%i.%i' %(major, minor, patch)
674 else:
675 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000676
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000677 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000678 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000679 0x2: 'PowerPC',
680 0xa: 'i386'}.get(sysa,'')
Ronald Oussorene186e382010-07-23 11:54:59 +0000681
Ned Deily58e33502011-07-13 15:07:04 -0700682 versioninfo=('', '', '')
Ronald Oussorene186e382010-07-23 11:54:59 +0000683 return release,versioninfo,machine
684
685def _mac_ver_xml():
686 fn = '/System/Library/CoreServices/SystemVersion.plist'
687 if not os.path.exists(fn):
688 return None
689
690 try:
691 import plistlib
692 except ImportError:
693 return None
694
695 pl = plistlib.readPlist(fn)
696 release = pl['ProductVersion']
697 versioninfo=('', '', '')
698 machine = os.uname()[4]
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000699 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussorene186e382010-07-23 11:54:59 +0000700 # for compatibility with the gestalt based code
701 machine = 'PowerPC'
702
703 return release,versioninfo,machine
704
705
706def mac_ver(release='',versioninfo=('','',''),machine=''):
707
708 """ Get MacOS version information and return it as tuple (release,
709 versioninfo, machine) with versioninfo being a tuple (version,
710 dev_stage, non_release_version).
711
712 Entries which cannot be determined are set to the paramter values
713 which default to ''. All tuple entries are strings.
714 """
715
716 # First try reading the information from an XML file which should
717 # always be present
718 info = _mac_ver_xml()
719 if info is not None:
720 return info
721
722 # If that doesn't work for some reason fall back to reading the
723 # information using gestalt calls.
724 info = _mac_ver_gestalt()
725 if info is not None:
726 return info
727
728 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000729 return release,versioninfo,machine
730
Neal Norwitz9b924c62003-06-29 04:17:45 +0000731def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000732
733 from java.lang import System
734 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000735 value = System.getProperty(name)
736 if value is None:
737 return default
738 return value
739 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000740 return default
741
742def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000743
Brett Cannon8ab27df2003-08-05 03:52:04 +0000744 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000745
746 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
747 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
748 tuple (os_name,os_version,os_arch).
749
750 Values which cannot be determined are set to the defaults
751 given as parameters (which all default to '').
752
753 """
754 # Import the needed APIs
755 try:
756 import java.lang
757 except ImportError:
758 return release,vendor,vminfo,osinfo
759
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000760 vendor = _java_getprop('java.vendor', vendor)
761 release = _java_getprop('java.version', release)
762 vm_name, vm_release, vm_vendor = vminfo
763 vm_name = _java_getprop('java.vm.name', vm_name)
764 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
765 vm_release = _java_getprop('java.vm.version', vm_release)
766 vminfo = vm_name, vm_release, vm_vendor
767 os_name, os_version, os_arch = osinfo
768 os_arch = _java_getprop('java.os.arch', os_arch)
769 os_name = _java_getprop('java.os.name', os_name)
770 os_version = _java_getprop('java.os.version', os_version)
771 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000772
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000773 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000774
775### System name aliasing
776
777def system_alias(system,release,version):
778
779 """ Returns (system,release,version) aliased to common
780 marketing names used for some systems.
781
782 It also does some reordering of the information in some cases
783 where it would otherwise cause confusion.
784
785 """
786 if system == 'Rhapsody':
787 # Apple's BSD derivative
788 # XXX How can we determine the marketing release number ?
789 return 'MacOS X Server',system+release,version
790
791 elif system == 'SunOS':
792 # Sun's OS
793 if release < '5':
794 # These releases use the old name SunOS
795 return system,release,version
796 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000797 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000798 if l:
799 try:
800 major = int(l[0])
801 except ValueError:
802 pass
803 else:
804 major = major - 3
805 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000806 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000807 if release < '6':
808 system = 'Solaris'
809 else:
810 # XXX Whatever the new SunOS marketing name is...
811 system = 'Solaris'
812
813 elif system == 'IRIX64':
814 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
815 # is really a version and not a different platform, since 32-bit
816 # apps are also supported..
817 system = 'IRIX'
818 if version:
819 version = version + ' (64bit)'
820 else:
821 version = '64bit'
822
823 elif system in ('win32','win16'):
824 # In case one of the other tricks
825 system = 'Windows'
826
827 return system,release,version
828
829### Various internal helpers
830
831def _platform(*args):
832
833 """ Helper to format the platform string in a filename
834 compatible format e.g. "system-version-machine".
835 """
836 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000837 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000838
839 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000840 platform = platform.replace(' ','_')
841 platform = platform.replace('/','-')
842 platform = platform.replace('\\','-')
843 platform = platform.replace(':','-')
844 platform = platform.replace(';','-')
845 platform = platform.replace('"','-')
846 platform = platform.replace('(','-')
847 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000848
849 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000850 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000851
852 # Fold '--'s and remove trailing '-'
853 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000854 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000855 if cleaned == platform:
856 break
857 platform = cleaned
858 while platform[-1] == '-':
859 platform = platform[:-1]
860
861 return platform
862
863def _node(default=''):
864
865 """ Helper to determine the node name of this machine.
866 """
867 try:
868 import socket
869 except ImportError:
870 # No sockets...
871 return default
872 try:
873 return socket.gethostname()
874 except socket.error:
875 # Still not working...
876 return default
877
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000878def _follow_symlinks(filepath):
879
880 """ In case filepath is a symlink, follow it until a
881 real file is reached.
882 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000883 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000884 while os.path.islink(filepath):
885 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000886 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000887 return filepath
888
889def _syscmd_uname(option,default=''):
890
891 """ Interface to the system's uname command.
892 """
893 if sys.platform in ('dos','win32','win16','os2'):
894 # XXX Others too ?
895 return default
896 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000897 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000898 except (AttributeError,os.error):
899 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000900 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000901 rc = f.close()
902 if not output or rc:
903 return default
904 else:
905 return output
906
907def _syscmd_file(target,default=''):
908
909 """ Interface to the system's file command.
910
911 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000912 omit the filename in its output. Follow the symlinks. It returns
913 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000914
915 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000916 if sys.platform in ('dos','win32','win16','os2'):
917 # XXX Others too ?
918 return default
Victor Stinnerb27ee202010-04-18 18:28:09 +0000919 target = _follow_symlinks(target).replace('"', '\\"')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000920 try:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000921 f = os.popen('file -b "%s" 2> %s' % (target, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000922 except (AttributeError,os.error):
923 return default
Victor Stinnerb27ee202010-04-18 18:28:09 +0000924 output = f.read().strip()
925 rc = f.close()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000926 if not output or rc:
927 return default
928 else:
929 return output
930
931### Information about the used architecture
932
933# Default values for architecture; non-empty strings override the
934# defaults given as parameters
935_default_architecture = {
936 'win32': ('','WindowsPE'),
937 'win16': ('','Windows'),
938 'dos': ('','MSDOS'),
939}
940
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000941def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000942
943 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000944 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000945
Brett Cannon8ab27df2003-08-05 03:52:04 +0000946 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000947 the bit architecture and the linkage format used for the
948 executable. Both values are returned as strings.
949
950 Values that cannot be determined are returned as given by the
951 parameter presets. If bits is given as '', the sizeof(pointer)
952 (or sizeof(long) on Python version < 1.5.2) is used as
953 indicator for the supported pointer size.
954
955 The function relies on the system's "file" command to do the
956 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000957 platforms. On some non-Unix platforms where the "file" command
958 does not exist and the executable is set to the Python interpreter
959 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000960
961 """
962 # Use the sizeof(pointer) as default number of bits if nothing
963 # else is given as default.
964 if not bits:
965 import struct
966 try:
967 size = struct.calcsize('P')
968 except struct.error:
969 # Older installations can only query longs
970 size = struct.calcsize('l')
971 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000972
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000973 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000974 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000975 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000976 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000977 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000978
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000979 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000980 executable == sys.executable:
981 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000982 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000983 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000984 b,l = _default_architecture[sys.platform]
985 if b:
986 bits = b
987 if l:
988 linkage = l
989 return bits,linkage
990
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000991 if 'executable' not in fileout:
992 # Format not supported
993 return bits,linkage
994
995 # Bits
996 if '32-bit' in fileout:
997 bits = '32bit'
998 elif 'N32' in fileout:
999 # On Irix only
1000 bits = 'n32bit'
1001 elif '64-bit' in fileout:
1002 bits = '64bit'
1003
1004 # Linkage
1005 if 'ELF' in fileout:
1006 linkage = 'ELF'
1007 elif 'PE' in fileout:
1008 # E.g. Windows uses this format
1009 if 'Windows' in fileout:
1010 linkage = 'WindowsPE'
1011 else:
1012 linkage = 'PE'
1013 elif 'COFF' in fileout:
1014 linkage = 'COFF'
1015 elif 'MS-DOS' in fileout:
1016 linkage = 'MSDOS'
1017 else:
1018 # XXX the A.OUT format also falls under this class...
1019 pass
1020
1021 return bits,linkage
1022
1023### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001024
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001025_uname_cache = None
1026
1027def uname():
1028
1029 """ Fairly portable uname interface. Returns a tuple
1030 of strings (system,node,release,version,machine,processor)
1031 identifying the underlying platform.
1032
1033 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001034 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001035
1036 Entries which cannot be determined are set to ''.
1037
1038 """
1039 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001040 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001041
1042 if _uname_cache is not None:
1043 return _uname_cache
1044
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001045 processor = ''
1046
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001047 # Get some infos from the builtin os.uname API...
1048 try:
1049 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001050 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001051 no_os_uname = 1
1052
Georg Brandl62e2ca22010-07-31 21:54:24 +00001053 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001054 # Hmm, no there is either no uname or uname has returned
1055 #'unknowns'... we'll have to poke around the system then.
1056 if no_os_uname:
1057 system = sys.platform
1058 release = ''
1059 version = ''
1060 node = _node()
1061 machine = ''
1062
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001063 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001064
1065 # Try win32_ver() on win32 platforms
1066 if system == 'win32':
1067 release,version,csd,ptype = win32_ver()
1068 if release and version:
1069 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001070 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001071 # available on Win XP and later; see
1072 # http://support.microsoft.com/kb/888731 and
1073 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001074 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001075 # WOW64 processes mask the native architecture
1076 if "PROCESSOR_ARCHITEW6432" in os.environ:
1077 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1078 else:
1079 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001080 if not processor:
1081 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001082
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001083 # Try the 'ver' system command available on some
1084 # platforms
1085 if use_syscmd_ver:
1086 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001087 # Normalize system to what win32_ver() normally returns
1088 # (_syscmd_ver() tends to return the vendor name as well)
1089 if system == 'Microsoft Windows':
1090 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001091 elif system == 'Microsoft' and release == 'Windows':
1092 # Under Windows Vista and Windows Server 2008,
1093 # Microsoft changed the output of the ver command. The
1094 # release is no longer printed. This causes the
1095 # system and release to be misidentified.
1096 system = 'Windows'
1097 if '6.0' == version[:3]:
1098 release = 'Vista'
1099 else:
1100 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001101
1102 # In case we still don't know anything useful, we'll try to
1103 # help ourselves
1104 if system in ('win32','win16'):
1105 if not version:
1106 if system == 'win32':
1107 version = '32bit'
1108 else:
1109 version = '16bit'
1110 system = 'Windows'
1111
1112 elif system[:4] == 'java':
1113 release,vendor,vminfo,osinfo = java_ver()
1114 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001115 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001116 if not version:
1117 version = vendor
1118
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001119 # System specific extensions
1120 if system == 'OpenVMS':
1121 # OpenVMS seems to have release and version mixed up
1122 if not release or release == '0':
1123 release = version
1124 version = ''
1125 # Get processor information
1126 try:
1127 import vms_lib
1128 except ImportError:
1129 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001130 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001131 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1132 if (cpu_number >= 128):
1133 processor = 'Alpha'
1134 else:
1135 processor = 'VAX'
1136 if not processor:
1137 # Get processor information from the uname system command
1138 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001139
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001140 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001141 if system == 'unknown':
1142 system = ''
1143 if node == 'unknown':
1144 node = ''
1145 if release == 'unknown':
1146 release = ''
1147 if version == 'unknown':
1148 version = ''
1149 if machine == 'unknown':
1150 machine = ''
1151 if processor == 'unknown':
1152 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001153
1154 # normalize name
1155 if system == 'Microsoft' and release == 'Windows':
1156 system = 'Windows'
1157 release = 'Vista'
1158
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001159 _uname_cache = system,node,release,version,machine,processor
1160 return _uname_cache
1161
1162### Direct interfaces to some of the uname() return values
1163
1164def system():
1165
1166 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1167
1168 An empty string is returned if the value cannot be determined.
1169
1170 """
1171 return uname()[0]
1172
1173def node():
1174
Brett Cannon8ab27df2003-08-05 03:52:04 +00001175 """ Returns the computer's network name (which may not be fully
1176 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001177
1178 An empty string is returned if the value cannot be determined.
1179
1180 """
1181 return uname()[1]
1182
1183def release():
1184
1185 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1186
1187 An empty string is returned if the value cannot be determined.
1188
1189 """
1190 return uname()[2]
1191
1192def version():
1193
1194 """ Returns the system's release version, e.g. '#3 on degas'
1195
1196 An empty string is returned if the value cannot be determined.
1197
1198 """
1199 return uname()[3]
1200
1201def machine():
1202
1203 """ Returns the machine type, e.g. 'i386'
1204
1205 An empty string is returned if the value cannot be determined.
1206
1207 """
1208 return uname()[4]
1209
1210def processor():
1211
1212 """ Returns the (true) processor name, e.g. 'amdk6'
1213
1214 An empty string is returned if the value cannot be
1215 determined. Note that many platforms do not provide this
1216 information or simply return the same value as for machine(),
1217 e.g. NetBSD does this.
1218
1219 """
1220 return uname()[5]
1221
1222### Various APIs for extracting information from sys.version
1223
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001224_sys_version_parser = re.compile(
1225 r'([\w.+]+)\s*'
1226 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001227 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001228
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001229_ironpython_sys_version_parser = re.compile(
1230 r'IronPython\s*'
1231 '([\d\.]+)'
1232 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001233 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001234
Benjamin Petersone549ead2009-03-28 21:42:05 +00001235_pypy_sys_version_parser = re.compile(
1236 r'([\w.+]+)\s*'
1237 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1238 '\[PyPy [^\]]+\]?')
1239
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001240_sys_version_cache = {}
1241
1242def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001243
1244 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001245 (name, version, branch, revision, buildno, builddate, compiler)
1246 referring to the Python implementation name, version, branch,
1247 revision, build number, build date/time as string and the compiler
1248 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001249
1250 Note that unlike the Python sys.version, the returned value
1251 for the Python version will always include the patchlevel (it
1252 defaults to '.0').
1253
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001254 The function returns empty strings for tuple entries that
1255 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001256
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001257 sys_version may be given to parse an alternative version
1258 string, e.g. if the version was read from a different Python
1259 interpreter.
1260
1261 """
1262 # Get the Python version
1263 if sys_version is None:
1264 sys_version = sys.version
1265
1266 # Try the cache first
1267 result = _sys_version_cache.get(sys_version, None)
1268 if result is not None:
1269 return result
1270
1271 # Parse it
1272 if sys_version[:10] == 'IronPython':
1273 # IronPython
1274 name = 'IronPython'
1275 match = _ironpython_sys_version_parser.match(sys_version)
1276 if match is None:
1277 raise ValueError(
1278 'failed to parse IronPython sys.version: %s' %
1279 repr(sys_version))
1280 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001281 buildno = ''
1282 builddate = ''
1283
1284 elif sys.platform[:4] == 'java':
1285 # Jython
1286 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001287 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001288 if match is None:
1289 raise ValueError(
1290 'failed to parse Jython sys.version: %s' %
1291 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001292 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001293 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001294
1295 elif "PyPy" in sys_version:
1296 # PyPy
1297 name = "PyPy"
1298 match = _pypy_sys_version_parser.match(sys_version)
1299 if match is None:
1300 raise ValueError("failed to parse PyPy sys.version: %s" %
1301 repr(sys_version))
1302 version, buildno, builddate, buildtime = match.groups()
1303 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001304
1305 else:
1306 # CPython
1307 match = _sys_version_parser.match(sys_version)
1308 if match is None:
1309 raise ValueError(
1310 'failed to parse CPython sys.version: %s' %
1311 repr(sys_version))
1312 version, buildno, builddate, buildtime, compiler = \
1313 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001314 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001315 builddate = builddate + ' ' + buildtime
1316
Georg Brandl82562422011-03-05 21:09:22 +01001317 if hasattr(sys, '_mercurial'):
1318 _, branch, revision = sys._mercurial
1319 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001320 # sys.subversion was added in Python 2.5
1321 _, branch, revision = sys.subversion
1322 else:
1323 branch = ''
1324 revision = ''
1325
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001326 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001327 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001328 if len(l) == 2:
1329 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001330 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001331
1332 # Build and cache the result
1333 result = (name, version, branch, revision, buildno, builddate, compiler)
1334 _sys_version_cache[sys_version] = result
1335 return result
1336
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001337def python_implementation():
1338
1339 """ Returns a string identifying the Python implementation.
1340
1341 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001342 'CPython' (C implementation of Python),
1343 'IronPython' (.NET implementation of Python),
1344 'Jython' (Java implementation of Python),
1345 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001346
1347 """
1348 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001349
1350def python_version():
1351
1352 """ Returns the Python version as string 'major.minor.patchlevel'
1353
1354 Note that unlike the Python sys.version, the returned value
1355 will always include the patchlevel (it defaults to 0).
1356
1357 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001358 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001359
1360def python_version_tuple():
1361
1362 """ Returns the Python version as tuple (major, minor, patchlevel)
1363 of strings.
1364
1365 Note that unlike the Python sys.version, the returned value
1366 will always include the patchlevel (it defaults to 0).
1367
1368 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001369 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001370
1371def python_branch():
1372
1373 """ Returns a string identifying the Python implementation
1374 branch.
1375
1376 For CPython this is the Subversion branch from which the
1377 Python binary was built.
1378
1379 If not available, an empty string is returned.
1380
1381 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001382
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001383 return _sys_version()[2]
1384
1385def python_revision():
1386
1387 """ Returns a string identifying the Python implementation
1388 revision.
1389
1390 For CPython this is the Subversion revision from which the
1391 Python binary was built.
1392
1393 If not available, an empty string is returned.
1394
1395 """
1396 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001397
1398def python_build():
1399
1400 """ Returns a tuple (buildno, builddate) stating the Python
1401 build number and date as strings.
1402
1403 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001404 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001405
1406def python_compiler():
1407
1408 """ Returns a string identifying the compiler used for compiling
1409 Python.
1410
1411 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001412 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001413
1414### The Opus Magnum of platform strings :-)
1415
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001416_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001417
1418def platform(aliased=0, terse=0):
1419
1420 """ Returns a single string identifying the underlying platform
1421 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001422
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001423 The output is intended to be human readable rather than
1424 machine parseable. It may look different on different
1425 platforms and this is intended.
1426
1427 If "aliased" is true, the function will use aliases for
1428 various platforms that report system names which differ from
1429 their common names, e.g. SunOS will be reported as
1430 Solaris. The system_alias() function is used to implement
1431 this.
1432
1433 Setting terse to true causes the function to return only the
1434 absolute minimum information needed to identify the platform.
1435
1436 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001437 result = _platform_cache.get((aliased, terse), None)
1438 if result is not None:
1439 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001440
1441 # Get uname information and then apply platform specific cosmetics
1442 # to it...
1443 system,node,release,version,machine,processor = uname()
1444 if machine == processor:
1445 processor = ''
1446 if aliased:
1447 system,release,version = system_alias(system,release,version)
1448
1449 if system == 'Windows':
1450 # MS platforms
1451 rel,vers,csd,ptype = win32_ver(version)
1452 if terse:
1453 platform = _platform(system,release)
1454 else:
1455 platform = _platform(system,release,version,csd)
1456
1457 elif system in ('Linux',):
1458 # Linux based systems
1459 distname,distversion,distid = dist('')
1460 if distname and not terse:
1461 platform = _platform(system,release,machine,processor,
1462 'with',
1463 distname,distversion,distid)
1464 else:
1465 # If the distribution name is unknown check for libc vs. glibc
1466 libcname,libcversion = libc_ver(sys.executable)
1467 platform = _platform(system,release,machine,processor,
1468 'with',
1469 libcname+libcversion)
1470 elif system == 'Java':
1471 # Java platforms
1472 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001473 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001474 platform = _platform(system,release,version)
1475 else:
1476 platform = _platform(system,release,version,
1477 'on',
1478 os_name,os_version,os_arch)
1479
1480 elif system == 'MacOS':
1481 # MacOS platforms
1482 if terse:
1483 platform = _platform(system,release)
1484 else:
1485 platform = _platform(system,release,machine)
1486
1487 else:
1488 # Generic handler
1489 if terse:
1490 platform = _platform(system,release)
1491 else:
1492 bits,linkage = architecture(sys.executable)
1493 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001494
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001495 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001496 return platform
1497
1498### Command line interface
1499
1500if __name__ == '__main__':
1501 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001502 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001503 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001504 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001505 sys.exit(0)