blob: f6394ab401445c3f25160168597f6cdf04552325 [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
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000360def popen(cmd, mode='r', bufsize=None):
361
362 """ Portable popen() interface.
363 """
Victor Stinner1dfd3802011-03-03 12:54:07 +0000364 return os.popen(cmd, mode, bufsize)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000365
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000366def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000367
Brett Cannon8ab27df2003-08-05 03:52:04 +0000368 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000369 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000370 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000371 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000372 if build:
373 l.append(build)
374 try:
375 ints = map(int,l)
376 except ValueError:
377 strings = l
378 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000379 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000380 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000381 return version
382
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000383_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
384 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000385 '\[.* ([\d.]+)\])')
386
387# Examples of VER command output:
388#
389# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
390# Windows XP: Microsoft Windows XP [Version 5.1.2600]
391# Windows Vista: Microsoft Windows [Version 6.0.6002]
392#
393# Note that the "Version" string gets localized on different
394# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000395
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000396def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000397
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000398 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000399
400 """ Tries to figure out the OS version used and returns
401 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000402
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000403 It uses the "ver" shell command for this which is known
404 to exists on Windows, DOS and OS/2. XXX Others too ?
405
406 In case this fails, the given parameters are used as
407 defaults.
408
409 """
410 if sys.platform not in supported_platforms:
411 return system,release,version
412
413 # Try some common cmd strings
414 for cmd in ('ver','command /c ver','cmd /c ver'):
415 try:
416 pipe = popen(cmd)
417 info = pipe.read()
418 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000419 raise os.error('command failed')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000420 # XXX How can I supress shell errors from being written
421 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000422 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000423 #print 'Command %s failed: %s' % (cmd,why)
424 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000425 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000426 #print 'Command %s failed: %s' % (cmd,why)
427 continue
428 else:
429 break
430 else:
431 return system,release,version
432
433 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000434 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000435 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000436 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000437 system,release,version = m.groups()
438 # Strip trailing dots from version and release
439 if release[-1] == '.':
440 release = release[:-1]
441 if version[-1] == '.':
442 version = version[:-1]
443 # Normalize the version and build strings (eliminating additional
444 # zeros)
445 version = _norm_version(version)
446 return system,release,version
447
448def _win32_getvalue(key,name,default=''):
449
450 """ Read a value for name from the registry key.
451
452 In case this fails, default is returned.
453
454 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000455 try:
456 # Use win32api if available
457 from win32api import RegQueryValueEx
458 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000459 # On Python 2.0 and later, emulate using winreg
460 import winreg
461 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 try:
463 return RegQueryValueEx(key,name)
464 except:
465 return default
466
467def win32_ver(release='',version='',csd='',ptype=''):
468
469 """ Get additional version information from the Windows Registry
470 and return a tuple (version,csd,ptype) referring to version
471 number, CSD level and OS type (multi/single
472 processor).
473
474 As a hint: ptype returns 'Uniprocessor Free' on single
475 processor NT machines and 'Multiprocessor Free' on multi
476 processor machines. The 'Free' refers to the OS version being
477 free of debugging code. It could also state 'Checked' which
478 means the OS version uses debugging code, i.e. code that
479 checks arguments, ranges, etc. (Thomas Heller).
480
Christian Heimes02781dc2008-03-21 01:11:52 +0000481 Note: this function works best with Mark Hammond's win32
482 package installed, but also on Python 2.3 and later. It
483 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000484
485 """
486 # XXX Is there any way to find out the processor type on WinXX ?
487 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000488 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000489 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000490 #
491 # The mappings between reg. values and release names can be found
492 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000493
494 # Import the needed APIs
495 try:
496 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000497 from win32api import RegQueryValueEx, RegOpenKeyEx, \
498 RegCloseKey, GetVersionEx
499 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
500 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000501 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000502 # Emulate the win32api module using Python APIs
503 try:
504 sys.getwindowsversion
505 except AttributeError:
506 # No emulation possible, so return the defaults...
507 return release,version,csd,ptype
508 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000509 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000510 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000511 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000512 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000513 RegQueryValueEx = winreg.QueryValueEx
514 RegOpenKeyEx = winreg.OpenKeyEx
515 RegCloseKey = winreg.CloseKey
516 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000517 VER_PLATFORM_WIN32_WINDOWS = 1
518 VER_PLATFORM_WIN32_NT = 2
519 VER_NT_WORKSTATION = 1
Brian Curtin6e2824d2010-05-06 03:05:50 +0000520 VER_NT_SERVER = 3
521 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000522
523 # Find out the registry key and some general version infos
Brian Curtin6e2824d2010-05-06 03:05:50 +0000524 winver = GetVersionEx()
525 maj,min,buildno,plat,csd = winver
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000526 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
Brian Curtin6e2824d2010-05-06 03:05:50 +0000527 if hasattr(winver, "service_pack"):
528 if winver.service_pack != "":
529 csd = 'SP%s' % winver.service_pack_major
530 else:
531 if csd[:13] == 'Service Pack ':
532 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000533
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000534 if plat == VER_PLATFORM_WIN32_WINDOWS:
535 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
536 # Try to guess the release name
537 if maj == 4:
538 if min == 0:
539 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000540 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000541 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000542 elif min == 90:
543 release = 'Me'
544 else:
545 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000546 elif maj == 5:
547 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000548
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000549 elif plat == VER_PLATFORM_WIN32_NT:
550 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
551 if maj <= 4:
552 release = 'NT'
553 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000554 if min == 0:
555 release = '2000'
556 elif min == 1:
557 release = 'XP'
558 elif min == 2:
559 release = '2003Server'
560 else:
561 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000562 elif maj == 6:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000563 if hasattr(winver, "product_type"):
564 product_type = winver.product_type
565 else:
566 product_type = VER_NT_WORKSTATION
567 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
568 # or help from the registry, we cannot properly identify
569 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000570 try:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000571 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
572 name, type = RegQueryValueEx(key, "ProductName")
573 # Discard any type that isn't REG_SZ
574 if type == REG_SZ and name.find("Server") != -1:
575 product_type = VER_NT_SERVER
576 except WindowsError:
577 # Use default of VER_NT_WORKSTATION
578 pass
579
580 if min == 0:
581 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000582 release = 'Vista'
583 else:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000584 release = '2008Server'
585 elif min == 1:
586 if product_type == VER_NT_WORKSTATION:
587 release = '7'
588 else:
589 release = '2008ServerR2'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000590 else:
591 release = 'post2008Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000592
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000593 else:
594 if not release:
595 # E.g. Win3.1 with win32s
596 release = '%i.%i' % (maj,min)
597 return release,version,csd,ptype
598
599 # Open the registry key
600 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000601 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000602 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000603 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000604 except:
605 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000606
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000607 # Parse values
608 #subversion = _win32_getvalue(keyCurVer,
609 # 'SubVersionNumber',
610 # ('',1))[0]
611 #if subversion:
612 # release = release + subversion # 95a, 95b, etc.
613 build = _win32_getvalue(keyCurVer,
614 'CurrentBuildNumber',
615 ('',1))[0]
616 ptype = _win32_getvalue(keyCurVer,
617 'CurrentType',
618 (ptype,1))[0]
619
620 # Normalize version
621 version = _norm_version(version,build)
622
623 # Close key
624 RegCloseKey(keyCurVer)
625 return release,version,csd,ptype
626
627def _mac_ver_lookup(selectors,default=None):
628
Benjamin Petersonebacd262008-05-29 21:09:51 +0000629 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000630 l = []
631 append = l.append
632 for selector in selectors:
633 try:
634 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000635 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000636 append(default)
637 return l
638
639def _bcd2str(bcd):
640
641 return hex(bcd)[2:]
642
Ronald Oussorene186e382010-07-23 11:54:59 +0000643def _mac_ver_gestalt():
644 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000645 Thanks to Mark R. Levinson for mailing documentation links and
646 code examples for this function. Documentation for the
647 gestalt() API is available online at:
648
649 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000650 """
651 # Check whether the version info module is available
652 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000653 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000654 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000655 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000656 # Get the infos
Ronald Oussoren19258d52010-02-07 11:33:33 +0000657 sysv, sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000658 # Decode the infos
659 if sysv:
660 major = (sysv & 0xFF00) >> 8
661 minor = (sysv & 0x00F0) >> 4
662 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000663
664 if (major, minor) >= (10, 4):
665 # the 'sysv' gestald cannot return patchlevels
666 # higher than 9. Apple introduced 3 new
667 # gestalt codes in 10.4 to deal with this
668 # issue (needed because patch levels can
669 # run higher than 9, such as 10.4.11)
670 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
671 release = '%i.%i.%i' %(major, minor, patch)
672 else:
673 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000674
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000675 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000676 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000677 0x2: 'PowerPC',
678 0xa: 'i386'}.get(sysa,'')
Ronald Oussorene186e382010-07-23 11:54:59 +0000679
680 return release,versioninfo,machine
681
682def _mac_ver_xml():
683 fn = '/System/Library/CoreServices/SystemVersion.plist'
684 if not os.path.exists(fn):
685 return None
686
687 try:
688 import plistlib
689 except ImportError:
690 return None
691
692 pl = plistlib.readPlist(fn)
693 release = pl['ProductVersion']
694 versioninfo=('', '', '')
695 machine = os.uname()[4]
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000696 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussorene186e382010-07-23 11:54:59 +0000697 # for compatibility with the gestalt based code
698 machine = 'PowerPC'
699
700 return release,versioninfo,machine
701
702
703def mac_ver(release='',versioninfo=('','',''),machine=''):
704
705 """ Get MacOS version information and return it as tuple (release,
706 versioninfo, machine) with versioninfo being a tuple (version,
707 dev_stage, non_release_version).
708
709 Entries which cannot be determined are set to the paramter values
710 which default to ''. All tuple entries are strings.
711 """
712
713 # First try reading the information from an XML file which should
714 # always be present
715 info = _mac_ver_xml()
716 if info is not None:
717 return info
718
719 # If that doesn't work for some reason fall back to reading the
720 # information using gestalt calls.
721 info = _mac_ver_gestalt()
722 if info is not None:
723 return info
724
725 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000726 return release,versioninfo,machine
727
Neal Norwitz9b924c62003-06-29 04:17:45 +0000728def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000729
730 from java.lang import System
731 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000732 value = System.getProperty(name)
733 if value is None:
734 return default
735 return value
736 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000737 return default
738
739def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000740
Brett Cannon8ab27df2003-08-05 03:52:04 +0000741 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000742
743 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
744 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
745 tuple (os_name,os_version,os_arch).
746
747 Values which cannot be determined are set to the defaults
748 given as parameters (which all default to '').
749
750 """
751 # Import the needed APIs
752 try:
753 import java.lang
754 except ImportError:
755 return release,vendor,vminfo,osinfo
756
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000757 vendor = _java_getprop('java.vendor', vendor)
758 release = _java_getprop('java.version', release)
759 vm_name, vm_release, vm_vendor = vminfo
760 vm_name = _java_getprop('java.vm.name', vm_name)
761 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
762 vm_release = _java_getprop('java.vm.version', vm_release)
763 vminfo = vm_name, vm_release, vm_vendor
764 os_name, os_version, os_arch = osinfo
765 os_arch = _java_getprop('java.os.arch', os_arch)
766 os_name = _java_getprop('java.os.name', os_name)
767 os_version = _java_getprop('java.os.version', os_version)
768 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000769
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000770 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000771
772### System name aliasing
773
774def system_alias(system,release,version):
775
776 """ Returns (system,release,version) aliased to common
777 marketing names used for some systems.
778
779 It also does some reordering of the information in some cases
780 where it would otherwise cause confusion.
781
782 """
783 if system == 'Rhapsody':
784 # Apple's BSD derivative
785 # XXX How can we determine the marketing release number ?
786 return 'MacOS X Server',system+release,version
787
788 elif system == 'SunOS':
789 # Sun's OS
790 if release < '5':
791 # These releases use the old name SunOS
792 return system,release,version
793 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000794 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000795 if l:
796 try:
797 major = int(l[0])
798 except ValueError:
799 pass
800 else:
801 major = major - 3
802 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000803 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000804 if release < '6':
805 system = 'Solaris'
806 else:
807 # XXX Whatever the new SunOS marketing name is...
808 system = 'Solaris'
809
810 elif system == 'IRIX64':
811 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
812 # is really a version and not a different platform, since 32-bit
813 # apps are also supported..
814 system = 'IRIX'
815 if version:
816 version = version + ' (64bit)'
817 else:
818 version = '64bit'
819
820 elif system in ('win32','win16'):
821 # In case one of the other tricks
822 system = 'Windows'
823
824 return system,release,version
825
826### Various internal helpers
827
828def _platform(*args):
829
830 """ Helper to format the platform string in a filename
831 compatible format e.g. "system-version-machine".
832 """
833 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000834 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000835
836 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000837 platform = platform.replace(' ','_')
838 platform = platform.replace('/','-')
839 platform = platform.replace('\\','-')
840 platform = platform.replace(':','-')
841 platform = platform.replace(';','-')
842 platform = platform.replace('"','-')
843 platform = platform.replace('(','-')
844 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000845
846 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000847 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000848
849 # Fold '--'s and remove trailing '-'
850 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000851 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000852 if cleaned == platform:
853 break
854 platform = cleaned
855 while platform[-1] == '-':
856 platform = platform[:-1]
857
858 return platform
859
860def _node(default=''):
861
862 """ Helper to determine the node name of this machine.
863 """
864 try:
865 import socket
866 except ImportError:
867 # No sockets...
868 return default
869 try:
870 return socket.gethostname()
871 except socket.error:
872 # Still not working...
873 return default
874
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000875def _follow_symlinks(filepath):
876
877 """ In case filepath is a symlink, follow it until a
878 real file is reached.
879 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000880 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000881 while os.path.islink(filepath):
882 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000883 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000884 return filepath
885
886def _syscmd_uname(option,default=''):
887
888 """ Interface to the system's uname command.
889 """
890 if sys.platform in ('dos','win32','win16','os2'):
891 # XXX Others too ?
892 return default
893 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000894 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000895 except (AttributeError,os.error):
896 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000897 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000898 rc = f.close()
899 if not output or rc:
900 return default
901 else:
902 return output
903
904def _syscmd_file(target,default=''):
905
906 """ Interface to the system's file command.
907
908 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000909 omit the filename in its output. Follow the symlinks. It returns
910 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000911
912 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +0000913 if sys.platform in ('dos','win32','win16','os2'):
914 # XXX Others too ?
915 return default
Victor Stinnerb27ee202010-04-18 18:28:09 +0000916 target = _follow_symlinks(target).replace('"', '\\"')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000917 try:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000918 f = os.popen('file -b "%s" 2> %s' % (target, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000919 except (AttributeError,os.error):
920 return default
Victor Stinnerb27ee202010-04-18 18:28:09 +0000921 output = f.read().strip()
922 rc = f.close()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000923 if not output or rc:
924 return default
925 else:
926 return output
927
928### Information about the used architecture
929
930# Default values for architecture; non-empty strings override the
931# defaults given as parameters
932_default_architecture = {
933 'win32': ('','WindowsPE'),
934 'win16': ('','Windows'),
935 'dos': ('','MSDOS'),
936}
937
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000938def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000939
940 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +0000941 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000942
Brett Cannon8ab27df2003-08-05 03:52:04 +0000943 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000944 the bit architecture and the linkage format used for the
945 executable. Both values are returned as strings.
946
947 Values that cannot be determined are returned as given by the
948 parameter presets. If bits is given as '', the sizeof(pointer)
949 (or sizeof(long) on Python version < 1.5.2) is used as
950 indicator for the supported pointer size.
951
952 The function relies on the system's "file" command to do the
953 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +0000954 platforms. On some non-Unix platforms where the "file" command
955 does not exist and the executable is set to the Python interpreter
956 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000957
958 """
959 # Use the sizeof(pointer) as default number of bits if nothing
960 # else is given as default.
961 if not bits:
962 import struct
963 try:
964 size = struct.calcsize('P')
965 except struct.error:
966 # Older installations can only query longs
967 size = struct.calcsize('l')
968 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +0000969
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000970 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000971 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000972 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000973 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000974 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000975
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000976 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000977 executable == sys.executable:
978 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +0000979 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000980 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000981 b,l = _default_architecture[sys.platform]
982 if b:
983 bits = b
984 if l:
985 linkage = l
986 return bits,linkage
987
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000988 if 'executable' not in fileout:
989 # Format not supported
990 return bits,linkage
991
992 # Bits
993 if '32-bit' in fileout:
994 bits = '32bit'
995 elif 'N32' in fileout:
996 # On Irix only
997 bits = 'n32bit'
998 elif '64-bit' in fileout:
999 bits = '64bit'
1000
1001 # Linkage
1002 if 'ELF' in fileout:
1003 linkage = 'ELF'
1004 elif 'PE' in fileout:
1005 # E.g. Windows uses this format
1006 if 'Windows' in fileout:
1007 linkage = 'WindowsPE'
1008 else:
1009 linkage = 'PE'
1010 elif 'COFF' in fileout:
1011 linkage = 'COFF'
1012 elif 'MS-DOS' in fileout:
1013 linkage = 'MSDOS'
1014 else:
1015 # XXX the A.OUT format also falls under this class...
1016 pass
1017
1018 return bits,linkage
1019
1020### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001021
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001022_uname_cache = None
1023
1024def uname():
1025
1026 """ Fairly portable uname interface. Returns a tuple
1027 of strings (system,node,release,version,machine,processor)
1028 identifying the underlying platform.
1029
1030 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001031 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001032
1033 Entries which cannot be determined are set to ''.
1034
1035 """
1036 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001037 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001038
1039 if _uname_cache is not None:
1040 return _uname_cache
1041
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001042 processor = ''
1043
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001044 # Get some infos from the builtin os.uname API...
1045 try:
1046 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001047 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001048 no_os_uname = 1
1049
Georg Brandl62e2ca22010-07-31 21:54:24 +00001050 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001051 # Hmm, no there is either no uname or uname has returned
1052 #'unknowns'... we'll have to poke around the system then.
1053 if no_os_uname:
1054 system = sys.platform
1055 release = ''
1056 version = ''
1057 node = _node()
1058 machine = ''
1059
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001060 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001061
1062 # Try win32_ver() on win32 platforms
1063 if system == 'win32':
1064 release,version,csd,ptype = win32_ver()
1065 if release and version:
1066 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001067 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001068 # available on Win XP and later; see
1069 # http://support.microsoft.com/kb/888731 and
1070 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001071 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001072 # WOW64 processes mask the native architecture
1073 if "PROCESSOR_ARCHITEW6432" in os.environ:
1074 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1075 else:
1076 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001077 if not processor:
1078 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001079
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001080 # Try the 'ver' system command available on some
1081 # platforms
1082 if use_syscmd_ver:
1083 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001084 # Normalize system to what win32_ver() normally returns
1085 # (_syscmd_ver() tends to return the vendor name as well)
1086 if system == 'Microsoft Windows':
1087 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001088 elif system == 'Microsoft' and release == 'Windows':
1089 # Under Windows Vista and Windows Server 2008,
1090 # Microsoft changed the output of the ver command. The
1091 # release is no longer printed. This causes the
1092 # system and release to be misidentified.
1093 system = 'Windows'
1094 if '6.0' == version[:3]:
1095 release = 'Vista'
1096 else:
1097 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001098
1099 # In case we still don't know anything useful, we'll try to
1100 # help ourselves
1101 if system in ('win32','win16'):
1102 if not version:
1103 if system == 'win32':
1104 version = '32bit'
1105 else:
1106 version = '16bit'
1107 system = 'Windows'
1108
1109 elif system[:4] == 'java':
1110 release,vendor,vminfo,osinfo = java_ver()
1111 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001112 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001113 if not version:
1114 version = vendor
1115
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001116 # System specific extensions
1117 if system == 'OpenVMS':
1118 # OpenVMS seems to have release and version mixed up
1119 if not release or release == '0':
1120 release = version
1121 version = ''
1122 # Get processor information
1123 try:
1124 import vms_lib
1125 except ImportError:
1126 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001127 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001128 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1129 if (cpu_number >= 128):
1130 processor = 'Alpha'
1131 else:
1132 processor = 'VAX'
1133 if not processor:
1134 # Get processor information from the uname system command
1135 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001136
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001137 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001138 if system == 'unknown':
1139 system = ''
1140 if node == 'unknown':
1141 node = ''
1142 if release == 'unknown':
1143 release = ''
1144 if version == 'unknown':
1145 version = ''
1146 if machine == 'unknown':
1147 machine = ''
1148 if processor == 'unknown':
1149 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001150
1151 # normalize name
1152 if system == 'Microsoft' and release == 'Windows':
1153 system = 'Windows'
1154 release = 'Vista'
1155
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001156 _uname_cache = system,node,release,version,machine,processor
1157 return _uname_cache
1158
1159### Direct interfaces to some of the uname() return values
1160
1161def system():
1162
1163 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1164
1165 An empty string is returned if the value cannot be determined.
1166
1167 """
1168 return uname()[0]
1169
1170def node():
1171
Brett Cannon8ab27df2003-08-05 03:52:04 +00001172 """ Returns the computer's network name (which may not be fully
1173 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001174
1175 An empty string is returned if the value cannot be determined.
1176
1177 """
1178 return uname()[1]
1179
1180def release():
1181
1182 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1183
1184 An empty string is returned if the value cannot be determined.
1185
1186 """
1187 return uname()[2]
1188
1189def version():
1190
1191 """ Returns the system's release version, e.g. '#3 on degas'
1192
1193 An empty string is returned if the value cannot be determined.
1194
1195 """
1196 return uname()[3]
1197
1198def machine():
1199
1200 """ Returns the machine type, e.g. 'i386'
1201
1202 An empty string is returned if the value cannot be determined.
1203
1204 """
1205 return uname()[4]
1206
1207def processor():
1208
1209 """ Returns the (true) processor name, e.g. 'amdk6'
1210
1211 An empty string is returned if the value cannot be
1212 determined. Note that many platforms do not provide this
1213 information or simply return the same value as for machine(),
1214 e.g. NetBSD does this.
1215
1216 """
1217 return uname()[5]
1218
1219### Various APIs for extracting information from sys.version
1220
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001221_sys_version_parser = re.compile(
1222 r'([\w.+]+)\s*'
1223 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001224 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001225
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001226_ironpython_sys_version_parser = re.compile(
1227 r'IronPython\s*'
1228 '([\d\.]+)'
1229 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001230 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001231
Benjamin Petersone549ead2009-03-28 21:42:05 +00001232_pypy_sys_version_parser = re.compile(
1233 r'([\w.+]+)\s*'
1234 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1235 '\[PyPy [^\]]+\]?')
1236
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001237_sys_version_cache = {}
1238
1239def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001240
1241 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001242 (name, version, branch, revision, buildno, builddate, compiler)
1243 referring to the Python implementation name, version, branch,
1244 revision, build number, build date/time as string and the compiler
1245 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001246
1247 Note that unlike the Python sys.version, the returned value
1248 for the Python version will always include the patchlevel (it
1249 defaults to '.0').
1250
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001251 The function returns empty strings for tuple entries that
1252 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001253
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001254 sys_version may be given to parse an alternative version
1255 string, e.g. if the version was read from a different Python
1256 interpreter.
1257
1258 """
1259 # Get the Python version
1260 if sys_version is None:
1261 sys_version = sys.version
1262
1263 # Try the cache first
1264 result = _sys_version_cache.get(sys_version, None)
1265 if result is not None:
1266 return result
1267
1268 # Parse it
1269 if sys_version[:10] == 'IronPython':
1270 # IronPython
1271 name = 'IronPython'
1272 match = _ironpython_sys_version_parser.match(sys_version)
1273 if match is None:
1274 raise ValueError(
1275 'failed to parse IronPython sys.version: %s' %
1276 repr(sys_version))
1277 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001278 buildno = ''
1279 builddate = ''
1280
1281 elif sys.platform[:4] == 'java':
1282 # Jython
1283 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001284 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001285 if match is None:
1286 raise ValueError(
1287 'failed to parse Jython sys.version: %s' %
1288 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001289 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001290 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001291
1292 elif "PyPy" in sys_version:
1293 # PyPy
1294 name = "PyPy"
1295 match = _pypy_sys_version_parser.match(sys_version)
1296 if match is None:
1297 raise ValueError("failed to parse PyPy sys.version: %s" %
1298 repr(sys_version))
1299 version, buildno, builddate, buildtime = match.groups()
1300 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001301
1302 else:
1303 # CPython
1304 match = _sys_version_parser.match(sys_version)
1305 if match is None:
1306 raise ValueError(
1307 'failed to parse CPython sys.version: %s' %
1308 repr(sys_version))
1309 version, buildno, builddate, buildtime, compiler = \
1310 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001311 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001312 builddate = builddate + ' ' + buildtime
1313
Georg Brandl82562422011-03-05 21:09:22 +01001314 if hasattr(sys, '_mercurial'):
1315 _, branch, revision = sys._mercurial
1316 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001317 # sys.subversion was added in Python 2.5
1318 _, branch, revision = sys.subversion
1319 else:
1320 branch = ''
1321 revision = ''
1322
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001323 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001324 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001325 if len(l) == 2:
1326 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001327 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001328
1329 # Build and cache the result
1330 result = (name, version, branch, revision, buildno, builddate, compiler)
1331 _sys_version_cache[sys_version] = result
1332 return result
1333
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001334def python_implementation():
1335
1336 """ Returns a string identifying the Python implementation.
1337
1338 Currently, the following implementations are identified:
1339 'CPython' (C implementation of Python),
1340 'IronPython' (.NET implementation of Python),
1341 'Jython' (Java implementation of Python).
1342
1343 """
1344 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001345
1346def python_version():
1347
1348 """ Returns the Python version as string 'major.minor.patchlevel'
1349
1350 Note that unlike the Python sys.version, the returned value
1351 will always include the patchlevel (it defaults to 0).
1352
1353 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001354 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001355
1356def python_version_tuple():
1357
1358 """ Returns the Python version as tuple (major, minor, patchlevel)
1359 of strings.
1360
1361 Note that unlike the Python sys.version, the returned value
1362 will always include the patchlevel (it defaults to 0).
1363
1364 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001365 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001366
1367def python_branch():
1368
1369 """ Returns a string identifying the Python implementation
1370 branch.
1371
1372 For CPython this is the Subversion branch from which the
1373 Python binary was built.
1374
1375 If not available, an empty string is returned.
1376
1377 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001378
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001379 return _sys_version()[2]
1380
1381def python_revision():
1382
1383 """ Returns a string identifying the Python implementation
1384 revision.
1385
1386 For CPython this is the Subversion revision from which the
1387 Python binary was built.
1388
1389 If not available, an empty string is returned.
1390
1391 """
1392 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001393
1394def python_build():
1395
1396 """ Returns a tuple (buildno, builddate) stating the Python
1397 build number and date as strings.
1398
1399 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001400 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001401
1402def python_compiler():
1403
1404 """ Returns a string identifying the compiler used for compiling
1405 Python.
1406
1407 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001408 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001409
1410### The Opus Magnum of platform strings :-)
1411
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001412_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001413
1414def platform(aliased=0, terse=0):
1415
1416 """ Returns a single string identifying the underlying platform
1417 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001418
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001419 The output is intended to be human readable rather than
1420 machine parseable. It may look different on different
1421 platforms and this is intended.
1422
1423 If "aliased" is true, the function will use aliases for
1424 various platforms that report system names which differ from
1425 their common names, e.g. SunOS will be reported as
1426 Solaris. The system_alias() function is used to implement
1427 this.
1428
1429 Setting terse to true causes the function to return only the
1430 absolute minimum information needed to identify the platform.
1431
1432 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001433 result = _platform_cache.get((aliased, terse), None)
1434 if result is not None:
1435 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001436
1437 # Get uname information and then apply platform specific cosmetics
1438 # to it...
1439 system,node,release,version,machine,processor = uname()
1440 if machine == processor:
1441 processor = ''
1442 if aliased:
1443 system,release,version = system_alias(system,release,version)
1444
1445 if system == 'Windows':
1446 # MS platforms
1447 rel,vers,csd,ptype = win32_ver(version)
1448 if terse:
1449 platform = _platform(system,release)
1450 else:
1451 platform = _platform(system,release,version,csd)
1452
1453 elif system in ('Linux',):
1454 # Linux based systems
1455 distname,distversion,distid = dist('')
1456 if distname and not terse:
1457 platform = _platform(system,release,machine,processor,
1458 'with',
1459 distname,distversion,distid)
1460 else:
1461 # If the distribution name is unknown check for libc vs. glibc
1462 libcname,libcversion = libc_ver(sys.executable)
1463 platform = _platform(system,release,machine,processor,
1464 'with',
1465 libcname+libcversion)
1466 elif system == 'Java':
1467 # Java platforms
1468 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001469 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001470 platform = _platform(system,release,version)
1471 else:
1472 platform = _platform(system,release,version,
1473 'on',
1474 os_name,os_version,os_arch)
1475
1476 elif system == 'MacOS':
1477 # MacOS platforms
1478 if terse:
1479 platform = _platform(system,release)
1480 else:
1481 platform = _platform(system,release,machine)
1482
1483 else:
1484 # Generic handler
1485 if terse:
1486 platform = _platform(system,release)
1487 else:
1488 bits,linkage = architecture(sys.executable)
1489 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001490
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001491 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001492 return platform
1493
1494### Command line interface
1495
1496if __name__ == '__main__':
1497 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001498 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001499 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001500 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001501 sys.exit(0)