blob: 686a04584538940b5cee319096d551813300c4bc [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
Jesus Ceafc990e92012-10-04 13:51:43 +0200114import sys, os, re, subprocess
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'
Victor Stinner87448812011-12-15 21:42:03 +0100184 if soversion and soversion > version:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000185 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
360class _popen:
361
362 """ Fairly portable (alternative) popen implementation.
363
364 This is mostly needed in case os.popen() is not available, or
365 doesn't work as advertised, e.g. in Win9X GUI programs like
366 PythonWin or IDLE.
367
368 Writing to the pipe is currently not supported.
369
370 """
371 tmpfile = ''
372 pipe = None
373 bufsize = None
374 mode = 'r'
375
376 def __init__(self,cmd,mode='r',bufsize=None):
377
378 if mode != 'r':
Collin Winterce36ad82007-08-30 01:19:48 +0000379 raise ValueError('popen()-emulation only supports read mode')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000380 import tempfile
381 self.tmpfile = tmpfile = tempfile.mktemp()
382 os.system(cmd + ' > %s' % tmpfile)
383 self.pipe = open(tmpfile,'rb')
384 self.bufsize = bufsize
385 self.mode = mode
386
387 def read(self):
388
389 return self.pipe.read()
390
391 def readlines(self):
392
393 if self.bufsize is not None:
394 return self.pipe.readlines()
395
396 def close(self,
397
398 remove=os.unlink,error=os.error):
399
400 if self.pipe:
401 rc = self.pipe.close()
402 else:
403 rc = 255
404 if self.tmpfile:
405 try:
406 remove(self.tmpfile)
407 except error:
408 pass
409 return rc
410
411 # Alias
412 __del__ = close
413
Antoine Pitrou877766d2011-03-19 17:00:37 +0100414def popen(cmd, mode='r', bufsize=-1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000415
416 """ Portable popen() interface.
417 """
418 # Find a working popen implementation preferring win32pipe.popen
419 # over os.popen over _popen
420 popen = None
421 if os.environ.get('OS','') == 'Windows_NT':
422 # On NT win32pipe should work; on Win9x it hangs due to bugs
423 # in the MS C lib (see MS KnowledgeBase article Q150956)
424 try:
425 import win32pipe
426 except ImportError:
427 pass
428 else:
429 popen = win32pipe.popen
430 if popen is None:
431 if hasattr(os,'popen'):
432 popen = os.popen
433 # Check whether it works... it doesn't in GUI programs
434 # on Windows platforms
435 if sys.platform == 'win32': # XXX Others too ?
436 try:
437 popen('')
438 except os.error:
439 popen = _popen
440 else:
441 popen = _popen
442 if bufsize is None:
443 return popen(cmd,mode)
444 else:
445 return popen(cmd,mode,bufsize)
446
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000447def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000448
Brett Cannon8ab27df2003-08-05 03:52:04 +0000449 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000450 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000451 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000452 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000453 if build:
454 l.append(build)
455 try:
456 ints = map(int,l)
457 except ValueError:
458 strings = l
459 else:
Neal Norwitz78a70bd2007-08-30 06:16:26 +0000460 strings = list(map(str,ints))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000461 version = '.'.join(strings[:3])
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000462 return version
463
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000464_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
465 '.*'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000466 '\[.* ([\d.]+)\])')
467
468# Examples of VER command output:
469#
470# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
471# Windows XP: Microsoft Windows XP [Version 5.1.2600]
472# Windows Vista: Microsoft Windows [Version 6.0.6002]
473#
474# Note that the "Version" string gets localized on different
475# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000476
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000477def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000478
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000479 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000480
481 """ Tries to figure out the OS version used and returns
482 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000483
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000484 It uses the "ver" shell command for this which is known
485 to exists on Windows, DOS and OS/2. XXX Others too ?
486
487 In case this fails, the given parameters are used as
488 defaults.
489
490 """
491 if sys.platform not in supported_platforms:
492 return system,release,version
493
494 # Try some common cmd strings
495 for cmd in ('ver','command /c ver','cmd /c ver'):
496 try:
497 pipe = popen(cmd)
498 info = pipe.read()
499 if pipe.close():
Collin Winterce36ad82007-08-30 01:19:48 +0000500 raise os.error('command failed')
Ezio Melotti13925002011-03-16 11:05:33 +0200501 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000502 # to stderr ?
Guido van Rossumb940e112007-01-10 16:19:56 +0000503 except os.error as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000504 #print 'Command %s failed: %s' % (cmd,why)
505 continue
Guido van Rossumb940e112007-01-10 16:19:56 +0000506 except IOError as why:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000507 #print 'Command %s failed: %s' % (cmd,why)
508 continue
509 else:
510 break
511 else:
512 return system,release,version
513
514 # Parse the output
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000515 info = info.strip()
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000516 m = _ver_output.match(info)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000517 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000518 system,release,version = m.groups()
519 # Strip trailing dots from version and release
520 if release[-1] == '.':
521 release = release[:-1]
522 if version[-1] == '.':
523 version = version[:-1]
524 # Normalize the version and build strings (eliminating additional
525 # zeros)
526 version = _norm_version(version)
527 return system,release,version
528
529def _win32_getvalue(key,name,default=''):
530
531 """ Read a value for name from the registry key.
532
533 In case this fails, default is returned.
534
535 """
Christian Heimes02781dc2008-03-21 01:11:52 +0000536 try:
537 # Use win32api if available
538 from win32api import RegQueryValueEx
539 except ImportError:
Georg Brandl38feaf02008-05-25 07:45:51 +0000540 # On Python 2.0 and later, emulate using winreg
541 import winreg
542 RegQueryValueEx = winreg.QueryValueEx
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000543 try:
544 return RegQueryValueEx(key,name)
545 except:
546 return default
547
548def win32_ver(release='',version='',csd='',ptype=''):
549
550 """ Get additional version information from the Windows Registry
551 and return a tuple (version,csd,ptype) referring to version
Brian Curtin10dda6e2012-02-01 15:14:00 -0600552 number, CSD level (service pack), and OS type (multi/single
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000553 processor).
554
555 As a hint: ptype returns 'Uniprocessor Free' on single
556 processor NT machines and 'Multiprocessor Free' on multi
557 processor machines. The 'Free' refers to the OS version being
558 free of debugging code. It could also state 'Checked' which
559 means the OS version uses debugging code, i.e. code that
560 checks arguments, ranges, etc. (Thomas Heller).
561
Christian Heimes02781dc2008-03-21 01:11:52 +0000562 Note: this function works best with Mark Hammond's win32
563 package installed, but also on Python 2.3 and later. It
564 obviously only runs on Win32 compatible platforms.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000565
566 """
567 # XXX Is there any way to find out the processor type on WinXX ?
568 # XXX Is win32 available on Windows CE ?
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000569 #
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000570 # Adapted from code posted by Karl Putland to comp.lang.python.
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000571 #
572 # The mappings between reg. values and release names can be found
573 # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000574
575 # Import the needed APIs
576 try:
577 import win32api
Christian Heimes02781dc2008-03-21 01:11:52 +0000578 from win32api import RegQueryValueEx, RegOpenKeyEx, \
579 RegCloseKey, GetVersionEx
580 from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
581 VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000582 except ImportError:
Christian Heimes02781dc2008-03-21 01:11:52 +0000583 # Emulate the win32api module using Python APIs
584 try:
585 sys.getwindowsversion
586 except AttributeError:
587 # No emulation possible, so return the defaults...
588 return release,version,csd,ptype
589 else:
Georg Brandl38feaf02008-05-25 07:45:51 +0000590 # Emulation using winreg (added in Python 2.0) and
Christian Heimes02781dc2008-03-21 01:11:52 +0000591 # sys.getwindowsversion() (added in Python 2.3)
Georg Brandl38feaf02008-05-25 07:45:51 +0000592 import winreg
Christian Heimes02781dc2008-03-21 01:11:52 +0000593 GetVersionEx = sys.getwindowsversion
Georg Brandl38feaf02008-05-25 07:45:51 +0000594 RegQueryValueEx = winreg.QueryValueEx
595 RegOpenKeyEx = winreg.OpenKeyEx
596 RegCloseKey = winreg.CloseKey
597 HKEY_LOCAL_MACHINE = winreg.HKEY_LOCAL_MACHINE
Christian Heimes02781dc2008-03-21 01:11:52 +0000598 VER_PLATFORM_WIN32_WINDOWS = 1
599 VER_PLATFORM_WIN32_NT = 2
600 VER_NT_WORKSTATION = 1
Brian Curtin6e2824d2010-05-06 03:05:50 +0000601 VER_NT_SERVER = 3
602 REG_SZ = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000603
604 # Find out the registry key and some general version infos
Brian Curtin6e2824d2010-05-06 03:05:50 +0000605 winver = GetVersionEx()
606 maj,min,buildno,plat,csd = winver
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000607 version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
Brian Curtin6e2824d2010-05-06 03:05:50 +0000608 if hasattr(winver, "service_pack"):
609 if winver.service_pack != "":
610 csd = 'SP%s' % winver.service_pack_major
611 else:
612 if csd[:13] == 'Service Pack ':
613 csd = 'SP' + csd[13:]
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000614
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000615 if plat == VER_PLATFORM_WIN32_WINDOWS:
616 regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
617 # Try to guess the release name
618 if maj == 4:
619 if min == 0:
620 release = '95'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000621 elif min == 10:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000622 release = '98'
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000623 elif min == 90:
624 release = 'Me'
625 else:
626 release = 'postMe'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000627 elif maj == 5:
628 release = '2000'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000629
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000630 elif plat == VER_PLATFORM_WIN32_NT:
631 regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
632 if maj <= 4:
633 release = 'NT'
634 elif maj == 5:
Marc-André Lemburg91e83e22004-03-25 18:35:12 +0000635 if min == 0:
636 release = '2000'
637 elif min == 1:
638 release = 'XP'
639 elif min == 2:
640 release = '2003Server'
641 else:
642 release = 'post2003'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000643 elif maj == 6:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000644 if hasattr(winver, "product_type"):
645 product_type = winver.product_type
646 else:
647 product_type = VER_NT_WORKSTATION
648 # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
649 # or help from the registry, we cannot properly identify
650 # non-workstation versions.
Christian Heimes02781dc2008-03-21 01:11:52 +0000651 try:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000652 key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
653 name, type = RegQueryValueEx(key, "ProductName")
654 # Discard any type that isn't REG_SZ
655 if type == REG_SZ and name.find("Server") != -1:
656 product_type = VER_NT_SERVER
657 except WindowsError:
658 # Use default of VER_NT_WORKSTATION
659 pass
660
661 if min == 0:
662 if product_type == VER_NT_WORKSTATION:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000663 release = 'Vista'
664 else:
Brian Curtin6e2824d2010-05-06 03:05:50 +0000665 release = '2008Server'
666 elif min == 1:
667 if product_type == VER_NT_WORKSTATION:
668 release = '7'
669 else:
670 release = '2008ServerR2'
Brian Curtin0b960f52012-10-11 16:07:52 -0500671 elif min == 2:
672 if product_type == VER_NT_WORKSTATION:
673 release = '8'
674 else:
675 release = '2012Server'
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000676 else:
Brian Curtin0b960f52012-10-11 16:07:52 -0500677 release = 'post2012Server'
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000678
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000679 else:
680 if not release:
681 # E.g. Win3.1 with win32s
682 release = '%i.%i' % (maj,min)
683 return release,version,csd,ptype
684
685 # Open the registry key
686 try:
Christian Heimes02781dc2008-03-21 01:11:52 +0000687 keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000688 # Get a value to make sure the key exists...
Christian Heimes02781dc2008-03-21 01:11:52 +0000689 RegQueryValueEx(keyCurVer, 'SystemRoot')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000690 except:
691 return release,version,csd,ptype
Tim Peters0eadaac2003-04-24 16:02:54 +0000692
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000693 # Parse values
694 #subversion = _win32_getvalue(keyCurVer,
695 # 'SubVersionNumber',
696 # ('',1))[0]
697 #if subversion:
698 # release = release + subversion # 95a, 95b, etc.
699 build = _win32_getvalue(keyCurVer,
700 'CurrentBuildNumber',
701 ('',1))[0]
702 ptype = _win32_getvalue(keyCurVer,
703 'CurrentType',
704 (ptype,1))[0]
705
706 # Normalize version
707 version = _norm_version(version,build)
708
709 # Close key
710 RegCloseKey(keyCurVer)
711 return release,version,csd,ptype
712
713def _mac_ver_lookup(selectors,default=None):
714
Benjamin Petersonebacd262008-05-29 21:09:51 +0000715 from _gestalt import gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000716 l = []
717 append = l.append
718 for selector in selectors:
719 try:
720 append(gestalt(selector))
Benjamin Petersonebacd262008-05-29 21:09:51 +0000721 except (RuntimeError, OSError):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000722 append(default)
723 return l
724
725def _bcd2str(bcd):
726
727 return hex(bcd)[2:]
728
Ronald Oussorene186e382010-07-23 11:54:59 +0000729def _mac_ver_gestalt():
730 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000731 Thanks to Mark R. Levinson for mailing documentation links and
732 code examples for this function. Documentation for the
733 gestalt() API is available online at:
734
735 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000736 """
737 # Check whether the version info module is available
738 try:
Benjamin Petersonebacd262008-05-29 21:09:51 +0000739 import _gestalt
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000740 except ImportError:
Ronald Oussorene186e382010-07-23 11:54:59 +0000741 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000742 # Get the infos
Ronald Oussoren19258d52010-02-07 11:33:33 +0000743 sysv, sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000744 # Decode the infos
745 if sysv:
746 major = (sysv & 0xFF00) >> 8
747 minor = (sysv & 0x00F0) >> 4
748 patch = (sysv & 0x000F)
Christian Heimese4ca8152008-05-08 17:18:53 +0000749
750 if (major, minor) >= (10, 4):
751 # the 'sysv' gestald cannot return patchlevels
752 # higher than 9. Apple introduced 3 new
753 # gestalt codes in 10.4 to deal with this
754 # issue (needed because patch levels can
755 # run higher than 9, such as 10.4.11)
756 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
757 release = '%i.%i.%i' %(major, minor, patch)
758 else:
759 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Benjamin Peterson856ff5f2008-05-29 21:22:40 +0000760
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000761 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000762 machine = {0x1: '68k',
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000763 0x2: 'PowerPC',
764 0xa: 'i386'}.get(sysa,'')
Ronald Oussorene186e382010-07-23 11:54:59 +0000765
Ned Deily58e33502011-07-13 15:07:04 -0700766 versioninfo=('', '', '')
Ronald Oussorene186e382010-07-23 11:54:59 +0000767 return release,versioninfo,machine
768
769def _mac_ver_xml():
770 fn = '/System/Library/CoreServices/SystemVersion.plist'
771 if not os.path.exists(fn):
772 return None
773
774 try:
775 import plistlib
776 except ImportError:
777 return None
778
779 pl = plistlib.readPlist(fn)
780 release = pl['ProductVersion']
781 versioninfo=('', '', '')
782 machine = os.uname()[4]
Ronald Oussorenfcd77012010-08-03 07:42:42 +0000783 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussorene186e382010-07-23 11:54:59 +0000784 # for compatibility with the gestalt based code
785 machine = 'PowerPC'
786
787 return release,versioninfo,machine
788
789
790def mac_ver(release='',versioninfo=('','',''),machine=''):
791
792 """ Get MacOS version information and return it as tuple (release,
793 versioninfo, machine) with versioninfo being a tuple (version,
794 dev_stage, non_release_version).
795
796 Entries which cannot be determined are set to the paramter values
797 which default to ''. All tuple entries are strings.
798 """
799
800 # First try reading the information from an XML file which should
801 # always be present
802 info = _mac_ver_xml()
803 if info is not None:
804 return info
805
806 # If that doesn't work for some reason fall back to reading the
807 # information using gestalt calls.
808 info = _mac_ver_gestalt()
809 if info is not None:
810 return info
811
812 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000813 return release,versioninfo,machine
814
Neal Norwitz9b924c62003-06-29 04:17:45 +0000815def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000816
817 from java.lang import System
818 try:
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000819 value = System.getProperty(name)
820 if value is None:
821 return default
822 return value
823 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000824 return default
825
826def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000827
Brett Cannon8ab27df2003-08-05 03:52:04 +0000828 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000829
830 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
831 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
832 tuple (os_name,os_version,os_arch).
833
834 Values which cannot be determined are set to the defaults
835 given as parameters (which all default to '').
836
837 """
838 # Import the needed APIs
839 try:
840 import java.lang
841 except ImportError:
842 return release,vendor,vminfo,osinfo
843
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000844 vendor = _java_getprop('java.vendor', vendor)
845 release = _java_getprop('java.version', release)
846 vm_name, vm_release, vm_vendor = vminfo
847 vm_name = _java_getprop('java.vm.name', vm_name)
848 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
849 vm_release = _java_getprop('java.vm.version', vm_release)
850 vminfo = vm_name, vm_release, vm_vendor
851 os_name, os_version, os_arch = osinfo
852 os_arch = _java_getprop('java.os.arch', os_arch)
853 os_name = _java_getprop('java.os.name', os_name)
854 os_version = _java_getprop('java.os.version', os_version)
855 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000856
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000857 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000858
859### System name aliasing
860
861def system_alias(system,release,version):
862
863 """ Returns (system,release,version) aliased to common
864 marketing names used for some systems.
865
866 It also does some reordering of the information in some cases
867 where it would otherwise cause confusion.
868
869 """
870 if system == 'Rhapsody':
871 # Apple's BSD derivative
872 # XXX How can we determine the marketing release number ?
873 return 'MacOS X Server',system+release,version
874
875 elif system == 'SunOS':
876 # Sun's OS
877 if release < '5':
878 # These releases use the old name SunOS
879 return system,release,version
880 # Modify release (marketing release = SunOS release - 3)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000881 l = release.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000882 if l:
883 try:
884 major = int(l[0])
885 except ValueError:
886 pass
887 else:
888 major = major - 3
889 l[0] = str(major)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000890 release = '.'.join(l)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000891 if release < '6':
892 system = 'Solaris'
893 else:
894 # XXX Whatever the new SunOS marketing name is...
895 system = 'Solaris'
896
897 elif system == 'IRIX64':
898 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
899 # is really a version and not a different platform, since 32-bit
900 # apps are also supported..
901 system = 'IRIX'
902 if version:
903 version = version + ' (64bit)'
904 else:
905 version = '64bit'
906
907 elif system in ('win32','win16'):
908 # In case one of the other tricks
909 system = 'Windows'
910
911 return system,release,version
912
913### Various internal helpers
914
915def _platform(*args):
916
917 """ Helper to format the platform string in a filename
918 compatible format e.g. "system-version-machine".
919 """
920 # Format the platform string
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000921 platform = '-'.join(x.strip() for x in filter(len, args))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000922
923 # Cleanup some possible filename obstacles...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000924 platform = platform.replace(' ','_')
925 platform = platform.replace('/','-')
926 platform = platform.replace('\\','-')
927 platform = platform.replace(':','-')
928 platform = platform.replace(';','-')
929 platform = platform.replace('"','-')
930 platform = platform.replace('(','-')
931 platform = platform.replace(')','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000932
933 # No need to report 'unknown' information...
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000934 platform = platform.replace('unknown','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000935
936 # Fold '--'s and remove trailing '-'
937 while 1:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000938 cleaned = platform.replace('--','-')
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000939 if cleaned == platform:
940 break
941 platform = cleaned
942 while platform[-1] == '-':
943 platform = platform[:-1]
944
945 return platform
946
947def _node(default=''):
948
949 """ Helper to determine the node name of this machine.
950 """
951 try:
952 import socket
953 except ImportError:
954 # No sockets...
955 return default
956 try:
957 return socket.gethostname()
958 except socket.error:
959 # Still not working...
960 return default
961
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000962def _follow_symlinks(filepath):
963
964 """ In case filepath is a symlink, follow it until a
965 real file is reached.
966 """
Georg Brandl673f7ef2008-01-05 21:20:19 +0000967 filepath = os.path.abspath(filepath)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000968 while os.path.islink(filepath):
969 filepath = os.path.normpath(
Hirokazu Yamamotob12716b2008-09-04 11:24:53 +0000970 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000971 return filepath
972
973def _syscmd_uname(option,default=''):
974
975 """ Interface to the system's uname command.
976 """
977 if sys.platform in ('dos','win32','win16','os2'):
978 # XXX Others too ?
979 return default
980 try:
Alexandre Vassalottie52e3782009-07-17 09:18:18 +0000981 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000982 except (AttributeError,os.error):
983 return default
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000984 output = f.read().strip()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000985 rc = f.close()
986 if not output or rc:
987 return default
988 else:
989 return output
990
991def _syscmd_file(target,default=''):
992
993 """ Interface to the system's file command.
994
995 The function uses the -b option of the file command to have it
Victor Stinnerddfb2c32010-08-13 16:30:15 +0000996 omit the filename in its output. Follow the symlinks. It returns
997 default in case the command should fail.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000998
999 """
Hirokazu Yamamotod26782e2008-09-01 14:35:47 +00001000 if sys.platform in ('dos','win32','win16','os2'):
1001 # XXX Others too ?
1002 return default
Jesus Ceafc990e92012-10-04 13:51:43 +02001003 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001004 try:
Jesus Cea685fffa2012-10-05 05:21:42 +02001005 proc = subprocess.Popen(['file', target],
1006 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001007 except (AttributeError,os.error):
1008 return default
Jesus Ceaadc82112012-10-05 04:58:38 +02001009 output = proc.communicate()[0].decode("latin-1")
Jesus Ceafc990e92012-10-04 13:51:43 +02001010 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001011 if not output or rc:
1012 return default
1013 else:
1014 return output
1015
1016### Information about the used architecture
1017
1018# Default values for architecture; non-empty strings override the
1019# defaults given as parameters
1020_default_architecture = {
1021 'win32': ('','WindowsPE'),
1022 'win16': ('','Windows'),
1023 'dos': ('','MSDOS'),
1024}
1025
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001026def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001027
1028 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001029 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001030
Brett Cannon8ab27df2003-08-05 03:52:04 +00001031 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001032 the bit architecture and the linkage format used for the
1033 executable. Both values are returned as strings.
1034
1035 Values that cannot be determined are returned as given by the
1036 parameter presets. If bits is given as '', the sizeof(pointer)
1037 (or sizeof(long) on Python version < 1.5.2) is used as
1038 indicator for the supported pointer size.
1039
1040 The function relies on the system's "file" command to do the
1041 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001042 platforms. On some non-Unix platforms where the "file" command
1043 does not exist and the executable is set to the Python interpreter
1044 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001045
1046 """
1047 # Use the sizeof(pointer) as default number of bits if nothing
1048 # else is given as default.
1049 if not bits:
1050 import struct
1051 try:
1052 size = struct.calcsize('P')
1053 except struct.error:
1054 # Older installations can only query longs
1055 size = struct.calcsize('l')
1056 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001057
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001058 # Get data from the 'file' system command
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001059 if executable:
Victor Stinnerddfb2c32010-08-13 16:30:15 +00001060 fileout = _syscmd_file(executable, '')
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001061 else:
Victor Stinnerddfb2c32010-08-13 16:30:15 +00001062 fileout = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001063
Victor Stinnerddfb2c32010-08-13 16:30:15 +00001064 if not fileout and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001065 executable == sys.executable:
1066 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001067 # some sensible defaults then...
Guido van Rossume2b70bc2006-08-18 22:13:04 +00001068 if sys.platform in _default_architecture:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001069 b,l = _default_architecture[sys.platform]
1070 if b:
1071 bits = b
1072 if l:
1073 linkage = l
1074 return bits,linkage
1075
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001076 if 'executable' not in fileout:
1077 # Format not supported
1078 return bits,linkage
1079
1080 # Bits
1081 if '32-bit' in fileout:
1082 bits = '32bit'
1083 elif 'N32' in fileout:
1084 # On Irix only
1085 bits = 'n32bit'
1086 elif '64-bit' in fileout:
1087 bits = '64bit'
1088
1089 # Linkage
1090 if 'ELF' in fileout:
1091 linkage = 'ELF'
1092 elif 'PE' in fileout:
1093 # E.g. Windows uses this format
1094 if 'Windows' in fileout:
1095 linkage = 'WindowsPE'
1096 else:
1097 linkage = 'PE'
1098 elif 'COFF' in fileout:
1099 linkage = 'COFF'
1100 elif 'MS-DOS' in fileout:
1101 linkage = 'MSDOS'
1102 else:
1103 # XXX the A.OUT format also falls under this class...
1104 pass
1105
1106 return bits,linkage
1107
1108### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001109
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001110_uname_cache = None
1111
1112def uname():
1113
1114 """ Fairly portable uname interface. Returns a tuple
1115 of strings (system,node,release,version,machine,processor)
1116 identifying the underlying platform.
1117
1118 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001119 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001120
1121 Entries which cannot be determined are set to ''.
1122
1123 """
1124 global _uname_cache
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001125 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001126
1127 if _uname_cache is not None:
1128 return _uname_cache
1129
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001130 processor = ''
1131
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001132 # Get some infos from the builtin os.uname API...
1133 try:
1134 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001135 except AttributeError:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001136 no_os_uname = 1
1137
Georg Brandl62e2ca22010-07-31 21:54:24 +00001138 if no_os_uname or not list(filter(None, (system, node, release, version, machine))):
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001139 # Hmm, no there is either no uname or uname has returned
1140 #'unknowns'... we'll have to poke around the system then.
1141 if no_os_uname:
1142 system = sys.platform
1143 release = ''
1144 version = ''
1145 node = _node()
1146 machine = ''
1147
Amaury Forgeot d'Arc7a019842008-06-17 21:42:46 +00001148 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001149
1150 # Try win32_ver() on win32 platforms
1151 if system == 'win32':
1152 release,version,csd,ptype = win32_ver()
1153 if release and version:
1154 use_syscmd_ver = 0
Christian Heimes02781dc2008-03-21 01:11:52 +00001155 # Try to use the PROCESSOR_* environment variables
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001156 # available on Win XP and later; see
1157 # http://support.microsoft.com/kb/888731 and
1158 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001159 if not machine:
R. David Murrayca2edce2010-03-22 17:48:48 +00001160 # WOW64 processes mask the native architecture
1161 if "PROCESSOR_ARCHITEW6432" in os.environ:
1162 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1163 else:
1164 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001165 if not processor:
1166 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001167
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001168 # Try the 'ver' system command available on some
1169 # platforms
1170 if use_syscmd_ver:
1171 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001172 # Normalize system to what win32_ver() normally returns
1173 # (_syscmd_ver() tends to return the vendor name as well)
1174 if system == 'Microsoft Windows':
1175 system = 'Windows'
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001176 elif system == 'Microsoft' and release == 'Windows':
1177 # Under Windows Vista and Windows Server 2008,
1178 # Microsoft changed the output of the ver command. The
1179 # release is no longer printed. This causes the
1180 # system and release to be misidentified.
1181 system = 'Windows'
1182 if '6.0' == version[:3]:
1183 release = 'Vista'
1184 else:
1185 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001186
1187 # In case we still don't know anything useful, we'll try to
1188 # help ourselves
1189 if system in ('win32','win16'):
1190 if not version:
1191 if system == 'win32':
1192 version = '32bit'
1193 else:
1194 version = '16bit'
1195 system = 'Windows'
1196
1197 elif system[:4] == 'java':
1198 release,vendor,vminfo,osinfo = java_ver()
1199 system = 'Java'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001200 version = ', '.join(vminfo)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001201 if not version:
1202 version = vendor
1203
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001204 # System specific extensions
1205 if system == 'OpenVMS':
1206 # OpenVMS seems to have release and version mixed up
1207 if not release or release == '0':
1208 release = version
1209 version = ''
1210 # Get processor information
1211 try:
1212 import vms_lib
1213 except ImportError:
1214 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001215 else:
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001216 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1217 if (cpu_number >= 128):
1218 processor = 'Alpha'
1219 else:
1220 processor = 'VAX'
1221 if not processor:
1222 # Get processor information from the uname system command
1223 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001224
Amaury Forgeot d'Arc35c86582008-06-17 21:11:29 +00001225 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001226 if system == 'unknown':
1227 system = ''
1228 if node == 'unknown':
1229 node = ''
1230 if release == 'unknown':
1231 release = ''
1232 if version == 'unknown':
1233 version = ''
1234 if machine == 'unknown':
1235 machine = ''
1236 if processor == 'unknown':
1237 processor = ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001238
1239 # normalize name
1240 if system == 'Microsoft' and release == 'Windows':
1241 system = 'Windows'
1242 release = 'Vista'
1243
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001244 _uname_cache = system,node,release,version,machine,processor
1245 return _uname_cache
1246
1247### Direct interfaces to some of the uname() return values
1248
1249def system():
1250
1251 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1252
1253 An empty string is returned if the value cannot be determined.
1254
1255 """
1256 return uname()[0]
1257
1258def node():
1259
Brett Cannon8ab27df2003-08-05 03:52:04 +00001260 """ Returns the computer's network name (which may not be fully
1261 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001262
1263 An empty string is returned if the value cannot be determined.
1264
1265 """
1266 return uname()[1]
1267
1268def release():
1269
1270 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1271
1272 An empty string is returned if the value cannot be determined.
1273
1274 """
1275 return uname()[2]
1276
1277def version():
1278
1279 """ Returns the system's release version, e.g. '#3 on degas'
1280
1281 An empty string is returned if the value cannot be determined.
1282
1283 """
1284 return uname()[3]
1285
1286def machine():
1287
1288 """ Returns the machine type, e.g. 'i386'
1289
1290 An empty string is returned if the value cannot be determined.
1291
1292 """
1293 return uname()[4]
1294
1295def processor():
1296
1297 """ Returns the (true) processor name, e.g. 'amdk6'
1298
1299 An empty string is returned if the value cannot be
1300 determined. Note that many platforms do not provide this
1301 information or simply return the same value as for machine(),
1302 e.g. NetBSD does this.
1303
1304 """
1305 return uname()[5]
1306
1307### Various APIs for extracting information from sys.version
1308
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001309_sys_version_parser = re.compile(
1310 r'([\w.+]+)\s*'
1311 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
Antoine Pitroufd036452008-08-19 17:56:33 +00001312 '\[([^\]]+)\]?', re.ASCII)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001313
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001314_ironpython_sys_version_parser = re.compile(
1315 r'IronPython\s*'
1316 '([\d\.]+)'
1317 '(?: \(([\d\.]+)\))?'
Antoine Pitroufd036452008-08-19 17:56:33 +00001318 ' on (.NET [\d\.]+)', re.ASCII)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001319
Benjamin Petersone549ead2009-03-28 21:42:05 +00001320_pypy_sys_version_parser = re.compile(
1321 r'([\w.+]+)\s*'
1322 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1323 '\[PyPy [^\]]+\]?')
1324
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001325_sys_version_cache = {}
1326
1327def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001328
1329 """ Returns a parsed version of Python's sys.version as tuple
Benjamin Peterson5f28b7b2009-03-26 21:49:58 +00001330 (name, version, branch, revision, buildno, builddate, compiler)
1331 referring to the Python implementation name, version, branch,
1332 revision, build number, build date/time as string and the compiler
1333 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001334
1335 Note that unlike the Python sys.version, the returned value
1336 for the Python version will always include the patchlevel (it
1337 defaults to '.0').
1338
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001339 The function returns empty strings for tuple entries that
1340 cannot be determined.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001341
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001342 sys_version may be given to parse an alternative version
1343 string, e.g. if the version was read from a different Python
1344 interpreter.
1345
1346 """
1347 # Get the Python version
1348 if sys_version is None:
1349 sys_version = sys.version
1350
1351 # Try the cache first
1352 result = _sys_version_cache.get(sys_version, None)
1353 if result is not None:
1354 return result
1355
1356 # Parse it
1357 if sys_version[:10] == 'IronPython':
1358 # IronPython
1359 name = 'IronPython'
1360 match = _ironpython_sys_version_parser.match(sys_version)
1361 if match is None:
1362 raise ValueError(
1363 'failed to parse IronPython sys.version: %s' %
1364 repr(sys_version))
1365 version, alt_version, compiler = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001366 buildno = ''
1367 builddate = ''
1368
1369 elif sys.platform[:4] == 'java':
1370 # Jython
1371 name = 'Jython'
Benjamin Petersone549ead2009-03-28 21:42:05 +00001372 match = _sys_version_parser.match(sys_version)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001373 if match is None:
1374 raise ValueError(
1375 'failed to parse Jython sys.version: %s' %
1376 repr(sys_version))
Benjamin Petersone549ead2009-03-28 21:42:05 +00001377 version, buildno, builddate, buildtime, _ = match.groups()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001378 compiler = sys.platform
Benjamin Petersone549ead2009-03-28 21:42:05 +00001379
1380 elif "PyPy" in sys_version:
1381 # PyPy
1382 name = "PyPy"
1383 match = _pypy_sys_version_parser.match(sys_version)
1384 if match is None:
1385 raise ValueError("failed to parse PyPy sys.version: %s" %
1386 repr(sys_version))
1387 version, buildno, builddate, buildtime = match.groups()
1388 compiler = ""
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001389
1390 else:
1391 # CPython
1392 match = _sys_version_parser.match(sys_version)
1393 if match is None:
1394 raise ValueError(
1395 'failed to parse CPython sys.version: %s' %
1396 repr(sys_version))
1397 version, buildno, builddate, buildtime, compiler = \
1398 match.groups()
Benjamin Petersone549ead2009-03-28 21:42:05 +00001399 name = 'CPython'
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001400 builddate = builddate + ' ' + buildtime
1401
Georg Brandl82562422011-03-05 21:09:22 +01001402 if hasattr(sys, '_mercurial'):
1403 _, branch, revision = sys._mercurial
1404 elif hasattr(sys, 'subversion'):
Benjamin Petersone549ead2009-03-28 21:42:05 +00001405 # sys.subversion was added in Python 2.5
1406 _, branch, revision = sys.subversion
1407 else:
1408 branch = ''
1409 revision = ''
1410
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001411 # Add the patchlevel version if missing
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001412 l = version.split('.')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001413 if len(l) == 2:
1414 l.append('0')
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001415 version = '.'.join(l)
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001416
1417 # Build and cache the result
1418 result = (name, version, branch, revision, buildno, builddate, compiler)
1419 _sys_version_cache[sys_version] = result
1420 return result
1421
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001422def python_implementation():
1423
1424 """ Returns a string identifying the Python implementation.
1425
1426 Currently, the following implementations are identified:
Ezio Melottif16898b2011-05-04 18:37:50 +03001427 'CPython' (C implementation of Python),
1428 'IronPython' (.NET implementation of Python),
1429 'Jython' (Java implementation of Python),
1430 'PyPy' (Python implementation of Python).
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001431
1432 """
1433 return _sys_version()[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001434
1435def python_version():
1436
1437 """ Returns the Python version as string 'major.minor.patchlevel'
1438
1439 Note that unlike the Python sys.version, the returned value
1440 will always include the patchlevel (it defaults to 0).
1441
1442 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001443 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001444
1445def python_version_tuple():
1446
1447 """ Returns the Python version as tuple (major, minor, patchlevel)
1448 of strings.
1449
1450 Note that unlike the Python sys.version, the returned value
1451 will always include the patchlevel (it defaults to 0).
1452
1453 """
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001454 return tuple(_sys_version()[1].split('.'))
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001455
1456def python_branch():
1457
1458 """ Returns a string identifying the Python implementation
1459 branch.
1460
1461 For CPython this is the Subversion branch from which the
1462 Python binary was built.
1463
1464 If not available, an empty string is returned.
1465
1466 """
Thomas Wouters9fe394c2007-02-05 01:24:16 +00001467
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001468 return _sys_version()[2]
1469
1470def python_revision():
1471
1472 """ Returns a string identifying the Python implementation
1473 revision.
1474
1475 For CPython this is the Subversion revision from which the
1476 Python binary was built.
1477
1478 If not available, an empty string is returned.
1479
1480 """
1481 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001482
1483def python_build():
1484
1485 """ Returns a tuple (buildno, builddate) stating the Python
1486 build number and date as strings.
1487
1488 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001489 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001490
1491def python_compiler():
1492
1493 """ Returns a string identifying the compiler used for compiling
1494 Python.
1495
1496 """
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001497 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001498
1499### The Opus Magnum of platform strings :-)
1500
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001501_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001502
1503def platform(aliased=0, terse=0):
1504
1505 """ Returns a single string identifying the underlying platform
1506 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001507
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001508 The output is intended to be human readable rather than
1509 machine parseable. It may look different on different
1510 platforms and this is intended.
1511
1512 If "aliased" is true, the function will use aliases for
1513 various platforms that report system names which differ from
1514 their common names, e.g. SunOS will be reported as
1515 Solaris. The system_alias() function is used to implement
1516 this.
1517
1518 Setting terse to true causes the function to return only the
1519 absolute minimum information needed to identify the platform.
1520
1521 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001522 result = _platform_cache.get((aliased, terse), None)
1523 if result is not None:
1524 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001525
1526 # Get uname information and then apply platform specific cosmetics
1527 # to it...
1528 system,node,release,version,machine,processor = uname()
1529 if machine == processor:
1530 processor = ''
1531 if aliased:
1532 system,release,version = system_alias(system,release,version)
1533
1534 if system == 'Windows':
1535 # MS platforms
1536 rel,vers,csd,ptype = win32_ver(version)
1537 if terse:
1538 platform = _platform(system,release)
1539 else:
1540 platform = _platform(system,release,version,csd)
1541
1542 elif system in ('Linux',):
1543 # Linux based systems
1544 distname,distversion,distid = dist('')
1545 if distname and not terse:
1546 platform = _platform(system,release,machine,processor,
1547 'with',
1548 distname,distversion,distid)
1549 else:
1550 # If the distribution name is unknown check for libc vs. glibc
1551 libcname,libcversion = libc_ver(sys.executable)
1552 platform = _platform(system,release,machine,processor,
1553 'with',
1554 libcname+libcversion)
1555 elif system == 'Java':
1556 # Java platforms
1557 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +00001558 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001559 platform = _platform(system,release,version)
1560 else:
1561 platform = _platform(system,release,version,
1562 'on',
1563 os_name,os_version,os_arch)
1564
1565 elif system == 'MacOS':
1566 # MacOS platforms
1567 if terse:
1568 platform = _platform(system,release)
1569 else:
1570 platform = _platform(system,release,machine)
1571
1572 else:
1573 # Generic handler
1574 if terse:
1575 platform = _platform(system,release)
1576 else:
1577 bits,linkage = architecture(sys.executable)
1578 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001579
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001580 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001581 return platform
1582
1583### Command line interface
1584
1585if __name__ == '__main__':
1586 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001587 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001588 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001589 print(platform(aliased,terse))
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001590 sys.exit(0)