blob: 62a5476a8f4d3039e3a7c08452fc4bdc9c9e99b5 [file] [log] [blame]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001#!/usr/bin/env python
2
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
Georg Brandl52c17942009-09-19 08:43:16 +000013# Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
Marc-André Lemburg246d8472003-04-24 11:36:11 +000014#
15# Note: Please keep this module compatible to Python 1.5.2.
16#
17# Still needed:
18# * more support for WinCE
19# * support for MS-DOS (PythonDX ?)
20# * support for Amiga and other still unsupported platforms running Python
21# * support for additional Linux distributions
22#
Brett Cannon8ab27df2003-08-05 03:52:04 +000023# Many thanks to all those who helped adding platform-specific
Marc-André Lemburg246d8472003-04-24 11:36:11 +000024# checks (in no particular order):
25#
26# Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
27# Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
28# Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
29# Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
30# Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
Steve Dower044cde52015-09-22 17:25:30 -070031# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve
32# Dower
Marc-André Lemburg246d8472003-04-24 11:36:11 +000033#
34# History:
Marc-André Lemburg380f4172005-11-07 16:11:02 +000035#
36# <see CVS and SVN checkin messages for history>
37#
Steve Dower044cde52015-09-22 17:25:30 -070038# 1.0.8 - changed Windows support to read version from kernel32.dll
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +000039# 1.0.7 - added DEV_NULL
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +000040# 1.0.6 - added linux_distribution()
41# 1.0.5 - fixed Java support to allow running the module on Jython
42# 1.0.4 - added IronPython support
Marc-André Lemburgcdc79232004-06-19 17:17:00 +000043# 1.0.3 - added normalization of Windows system name
Marc-André Lemburg91e83e22004-03-25 18:35:12 +000044# 1.0.2 - added more Windows support
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +000045# 1.0.1 - reformatted to make doc.py happy
Marc-André Lemburg246d8472003-04-24 11:36:11 +000046# 1.0.0 - reformatted a bit and checked into Python CVS
47# 0.8.0 - added sys.version parser and various new access
48# APIs (python_version(), python_compiler(), etc.)
49# 0.7.2 - fixed architecture() to use sizeof(pointer) where available
50# 0.7.1 - added support for Caldera OpenLinux
51# 0.7.0 - some fixes for WinCE; untabified the source file
52# 0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
53# vms_lib.getsyi() configured
54# 0.6.1 - added code to prevent 'uname -p' on platforms which are
55# known not to support it
56# 0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
57# did some cleanup of the interfaces - some APIs have changed
58# 0.5.5 - fixed another type in the MacOS code... should have
59# used more coffee today ;-)
60# 0.5.4 - fixed a few typos in the MacOS code
61# 0.5.3 - added experimental MacOS support; added better popen()
62# workarounds in _syscmd_ver() -- still not 100% elegant
63# though
64# 0.5.2 - fixed uname() to return '' instead of 'unknown' in all
65# return values (the system uname command tends to return
Martin Pantera850ef62016-07-28 01:11:04 +000066# 'unknown' instead of just leaving the field empty)
Marc-André Lemburg246d8472003-04-24 11:36:11 +000067# 0.5.1 - included code for slackware dist; added exception handlers
68# to cover up situations where platforms don't have os.popen
69# (e.g. Mac) or fail on socket.gethostname(); fixed libc
70# detection RE
71# 0.5.0 - changed the API names referring to system commands to *syscmd*;
72# added java_ver(); made syscmd_ver() a private
73# API (was system_ver() in previous versions) -- use uname()
74# instead; extended the win32_ver() to also return processor
75# type information
76# 0.4.0 - added win32_ver() and modified the platform() output for WinXX
77# 0.3.4 - fixed a bug in _follow_symlinks()
78# 0.3.3 - fixed popen() and "file" command invokation bugs
79# 0.3.2 - added architecture() API and support for it in platform()
80# 0.3.1 - fixed syscmd_ver() RE to support Windows NT
81# 0.3.0 - added system alias support
82# 0.2.3 - removed 'wince' again... oh well.
83# 0.2.2 - added 'wince' to syscmd_ver() supported platforms
84# 0.2.1 - added cache logic and changed the platform string format
85# 0.2.0 - changed the API to use functions instead of module globals
86# since some action take too long to be run on module import
87# 0.1.0 - first release
88#
89# You can always get the latest version of this module at:
90#
91# http://www.egenix.com/files/python/platform.py
92#
93# If that URL should fail, try contacting the author.
94
95__copyright__ = """
96 Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
Georg Brandl8cdc9bc2010-01-01 13:07:05 +000097 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com
Marc-André Lemburg246d8472003-04-24 11:36:11 +000098
99 Permission to use, copy, modify, and distribute this software and its
100 documentation for any purpose and without fee or royalty is hereby granted,
101 provided that the above copyright notice appear in all copies and that
102 both that copyright notice and this permission notice appear in
103 supporting documentation or portions thereof, including modifications,
104 that you make.
105
106 EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
107 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
108 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
109 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
110 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
111 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
112 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
113
114"""
115
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000116__version__ = '1.0.7'
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000117
Jesus Ceadebda5d2012-10-04 15:14:56 +0200118import sys,string,os,re
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000119
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000120### Globals & Constants
121
122# Determine the platform's /dev/null device
123try:
124 DEV_NULL = os.devnull
125except AttributeError:
126 # os.devnull was added in Python 2.4, so emulate it for earlier
127 # Python versions
128 if sys.platform in ('dos','win32','win16','os2'):
129 # Use the old CP/M NUL as device name
130 DEV_NULL = 'NUL'
131 else:
132 # Standard Unix uses /dev/null
133 DEV_NULL = '/dev/null'
134
Miss Islington (bot)97340242018-09-05 07:46:26 -0700135# Helper for comparing two version number strings.
136# Based on the description of the PHP's version_compare():
137# http://php.net/manual/en/function.version-compare.php
138
139_ver_stages = {
140 # any string not found in this dict, will get 0 assigned
141 'dev': 10,
142 'alpha': 20, 'a': 20,
143 'beta': 30, 'b': 30,
144 'c': 40,
145 'RC': 50, 'rc': 50,
146 # number, will get 100 assigned
147 'pl': 200, 'p': 200,
148}
149
150_component_re = re.compile(r'([0-9]+|[._+-])')
151
152def _comparable_version(version):
153 result = []
154 for v in _component_re.split(version):
155 if v not in '._+-':
156 try:
157 v = int(v, 10)
158 t = 100
159 except ValueError:
160 t = _ver_stages.get(v, 0)
161 result.extend((t, v))
162 return result
163
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000164### Platform specific APIs
165
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000166_libc_search = re.compile(r'(__libc_init)'
167 '|'
Tim Peters0eadaac2003-04-24 16:02:54 +0000168 '(GLIBC_([0-9.]+))'
169 '|'
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000170 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
171
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300172def libc_ver(executable=sys.executable,lib='',version='', chunksize=2048):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000173
Brett Cannon8ab27df2003-08-05 03:52:04 +0000174 """ Tries to determine the libc version that the file executable
175 (which defaults to the Python interpreter) is linked against.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000176
177 Returns a tuple of strings (lib,version) which default to the
178 given parameters in case the lookup fails.
179
180 Note that the function has intimate knowledge of how different
Brett Cannon8ab27df2003-08-05 03:52:04 +0000181 libc versions add symbols to the executable and thus is probably
182 only useable for executables compiled using gcc.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000183
184 The file is read and scanned in chunks of chunksize bytes.
185
186 """
Miss Islington (bot)97340242018-09-05 07:46:26 -0700187 V = _comparable_version
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000188 if hasattr(os.path, 'realpath'):
189 # Python 2.2 introduced os.path.realpath(); it is used
190 # here to work around problems with Cygwin not being
191 # able to open symlinks for reading
192 executable = os.path.realpath(executable)
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300193 with open(executable, 'rb') as f:
194 binary = f.read(chunksize)
195 pos = 0
196 while pos < len(binary):
197 m = _libc_search.search(binary,pos)
198 if not m or m.end() == len(binary):
199 chunk = f.read(chunksize)
200 if chunk:
201 binary = binary[max(pos, len(binary) - 1000):] + chunk
202 pos = 0
203 continue
204 if not m:
205 break
206 libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
207 if libcinit and not lib:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000208 lib = 'libc'
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300209 elif glibc:
210 if lib != 'glibc':
211 lib = 'glibc'
212 version = glibcversion
213 elif V(glibcversion) > V(version):
214 version = glibcversion
215 elif so:
216 if lib != 'glibc':
217 lib = 'libc'
218 if soversion and (not version or V(soversion) > V(version)):
219 version = soversion
220 if threads and version[-len(threads):] != threads:
221 version = version + threads
222 pos = m.end()
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000223 return lib,version
224
225def _dist_try_harder(distname,version,id):
226
Tim Peters0eadaac2003-04-24 16:02:54 +0000227 """ Tries some special tricks to get the distribution
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000228 information in case the default method fails.
229
230 Currently supports older SuSE Linux, Caldera OpenLinux and
231 Slackware Linux distributions.
232
233 """
234 if os.path.exists('/var/adm/inst-log/info'):
235 # SuSE Linux stores distribution information in that file
236 info = open('/var/adm/inst-log/info').readlines()
237 distname = 'SuSE'
238 for line in info:
239 tv = string.split(line)
240 if len(tv) == 2:
241 tag,value = tv
242 else:
243 continue
244 if tag == 'MIN_DIST_VERSION':
245 version = string.strip(value)
246 elif tag == 'DIST_IDENT':
247 values = string.split(value,'-')
248 id = values[2]
249 return distname,version,id
250
251 if os.path.exists('/etc/.installed'):
252 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
253 info = open('/etc/.installed').readlines()
254 for line in info:
255 pkg = string.split(line,'-')
256 if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
257 # XXX does Caldera support non Intel platforms ? If yes,
258 # where can we find the needed id ?
259 return 'OpenLinux',pkg[1],id
260
261 if os.path.isdir('/usr/lib/setup'):
Ezio Melottif5469cf2013-08-17 15:43:51 +0300262 # Check for slackware version tag file (thanks to Greg Andruk)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000263 verfiles = os.listdir('/usr/lib/setup')
Guido van Rossum843c7342004-05-04 18:18:59 +0000264 for n in range(len(verfiles)-1, -1, -1):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000265 if verfiles[n][:14] != 'slack-version-':
266 del verfiles[n]
267 if verfiles:
268 verfiles.sort()
269 distname = 'slackware'
270 version = verfiles[-1][14:]
271 return distname,version,id
272
273 return distname,version,id
274
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000275_release_filename = re.compile(r'(\w+)[-_](release|version)')
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000276_lsb_release_version = re.compile(r'(.+)'
277 ' release '
278 '([\d.]+)'
279 '[^(]*(?:\((.+)\))?')
280_release_version = re.compile(r'([^0-9]+)'
281 '(?: release )?'
282 '([\d.]+)'
283 '[^(]*(?:\((.+)\))?')
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000284
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000285# See also http://www.novell.com/coolsolutions/feature/11251.html
Tim Petersf733abb2007-01-30 03:03:46 +0000286# and http://linuxmafia.com/faq/Admin/release-files.html
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000287# and http://data.linux-ntfs.org/rpm/whichrpm
288# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
Marc-André Lemburg380f4172005-11-07 16:11:02 +0000289
Marc-André Lemburg50967bd2008-03-08 10:01:43 +0000290_supported_dists = (
291 'SuSE', 'debian', 'fedora', 'redhat', 'centos',
292 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
293 'UnitedLinux', 'turbolinux')
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000294
295def _parse_release_file(firstline):
Tim Petersf733abb2007-01-30 03:03:46 +0000296
Benjamin Petersona43f34c2010-01-25 03:31:13 +0000297 # Default to empty 'version' and 'id' strings. Both defaults are used
298 # when 'firstline' is empty. 'id' defaults to empty when an id can not
299 # be deduced.
300 version = ''
301 id = ''
302
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000303 # Parse the first line
304 m = _lsb_release_version.match(firstline)
305 if m is not None:
306 # LSB format: "distro release x.x (codename)"
307 return tuple(m.groups())
308
309 # Pre-LSB format: "distro x.x (codename)"
310 m = _release_version.match(firstline)
311 if m is not None:
312 return tuple(m.groups())
313
Ezio Melottif5469cf2013-08-17 15:43:51 +0300314 # Unknown format... take the first two words
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000315 l = string.split(string.strip(firstline))
316 if l:
317 version = l[0]
318 if len(l) > 1:
319 id = l[1]
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000320 return '', version, id
321
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000322def linux_distribution(distname='', version='', id='',
323
324 supported_dists=_supported_dists,
325 full_distribution_name=1):
326
327 """ Tries to determine the name of the Linux OS distribution name.
328
329 The function first looks for a distribution release file in
330 /etc and then reverts to _dist_try_harder() in case no
331 suitable files are found.
332
333 supported_dists may be given to define the set of Linux
334 distributions to look for. It defaults to a list of currently
335 supported Linux distributions identified by their release file
336 name.
337
338 If full_distribution_name is true (default), the full
339 distribution read from the OS is returned. Otherwise the short
340 name taken from supported_dists is used.
341
342 Returns a tuple (distname,version,id) which default to the
343 args given as parameters.
344
345 """
346 try:
347 etc = os.listdir('/etc')
348 except os.error:
349 # Probably not a Unix system
350 return distname,version,id
351 etc.sort()
352 for file in etc:
353 m = _release_filename.match(file)
354 if m is not None:
355 _distname,dummy = m.groups()
356 if _distname in supported_dists:
357 distname = _distname
358 break
359 else:
360 return _dist_try_harder(distname,version,id)
Tim Petersf733abb2007-01-30 03:03:46 +0000361
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000362 # Read the first line
363 f = open('/etc/'+file, 'r')
364 firstline = f.readline()
365 f.close()
366 _distname, _version, _id = _parse_release_file(firstline)
367
368 if _distname and full_distribution_name:
369 distname = _distname
370 if _version:
371 version = _version
372 if _id:
373 id = _id
374 return distname, version, id
375
376# To maintain backwards compatibility:
Tim Petersf733abb2007-01-30 03:03:46 +0000377
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000378def dist(distname='',version='',id='',
379
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000380 supported_dists=_supported_dists):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000381
Brett Cannon8ab27df2003-08-05 03:52:04 +0000382 """ Tries to determine the name of the Linux OS distribution name.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000383
384 The function first looks for a distribution release file in
385 /etc and then reverts to _dist_try_harder() in case no
386 suitable files are found.
387
Brett Cannon8ab27df2003-08-05 03:52:04 +0000388 Returns a tuple (distname,version,id) which default to the
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000389 args given as parameters.
390
391 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000392 return linux_distribution(distname, version, id,
393 supported_dists=supported_dists,
394 full_distribution_name=0)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000395
396class _popen:
397
398 """ Fairly portable (alternative) popen implementation.
399
400 This is mostly needed in case os.popen() is not available, or
401 doesn't work as advertised, e.g. in Win9X GUI programs like
402 PythonWin or IDLE.
403
404 Writing to the pipe is currently not supported.
405
406 """
407 tmpfile = ''
408 pipe = None
409 bufsize = None
410 mode = 'r'
411
412 def __init__(self,cmd,mode='r',bufsize=None):
413
414 if mode != 'r':
415 raise ValueError,'popen()-emulation only supports read mode'
416 import tempfile
417 self.tmpfile = tmpfile = tempfile.mktemp()
418 os.system(cmd + ' > %s' % tmpfile)
419 self.pipe = open(tmpfile,'rb')
420 self.bufsize = bufsize
421 self.mode = mode
422
423 def read(self):
424
425 return self.pipe.read()
426
427 def readlines(self):
428
429 if self.bufsize is not None:
430 return self.pipe.readlines()
431
432 def close(self,
433
434 remove=os.unlink,error=os.error):
435
436 if self.pipe:
437 rc = self.pipe.close()
438 else:
439 rc = 255
440 if self.tmpfile:
441 try:
442 remove(self.tmpfile)
443 except error:
444 pass
445 return rc
446
447 # Alias
448 __del__ = close
449
450def popen(cmd, mode='r', bufsize=None):
451
452 """ Portable popen() interface.
453 """
454 # Find a working popen implementation preferring win32pipe.popen
455 # over os.popen over _popen
456 popen = None
457 if os.environ.get('OS','') == 'Windows_NT':
458 # On NT win32pipe should work; on Win9x it hangs due to bugs
459 # in the MS C lib (see MS KnowledgeBase article Q150956)
460 try:
461 import win32pipe
462 except ImportError:
463 pass
464 else:
465 popen = win32pipe.popen
466 if popen is None:
467 if hasattr(os,'popen'):
468 popen = os.popen
469 # Check whether it works... it doesn't in GUI programs
470 # on Windows platforms
471 if sys.platform == 'win32': # XXX Others too ?
472 try:
473 popen('')
474 except os.error:
475 popen = _popen
476 else:
477 popen = _popen
478 if bufsize is None:
479 return popen(cmd,mode)
480 else:
481 return popen(cmd,mode,bufsize)
482
Serhiy Storchakab1e6e562018-07-09 14:39:06 +0300483
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000484def _norm_version(version, build=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000485
Brett Cannon8ab27df2003-08-05 03:52:04 +0000486 """ Normalize the version and build strings and return a single
Walter Dörwalde5a7fad2005-11-21 17:01:27 +0000487 version string using the format major.minor.build (or patchlevel).
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000488 """
489 l = string.split(version,'.')
490 if build:
491 l.append(build)
492 try:
493 ints = map(int,l)
494 except ValueError:
495 strings = l
496 else:
497 strings = map(str,ints)
498 version = string.join(strings[:3],'.')
499 return version
500
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000501_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
502 '.*'
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000503 '\[.* ([\d.]+)\])')
504
505# Examples of VER command output:
506#
507# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195]
508# Windows XP: Microsoft Windows XP [Version 5.1.2600]
509# Windows Vista: Microsoft Windows [Version 6.0.6002]
510#
511# Note that the "Version" string gets localized on different
512# Windows versions.
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000513
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000514def _syscmd_ver(system='', release='', version='',
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000515
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000516 supported_platforms=('win32','win16','dos','os2')):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000517
518 """ Tries to figure out the OS version used and returns
519 a tuple (system,release,version).
Tim Peters0eadaac2003-04-24 16:02:54 +0000520
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000521 It uses the "ver" shell command for this which is known
522 to exists on Windows, DOS and OS/2. XXX Others too ?
523
524 In case this fails, the given parameters are used as
525 defaults.
526
527 """
528 if sys.platform not in supported_platforms:
529 return system,release,version
530
531 # Try some common cmd strings
532 for cmd in ('ver','command /c ver','cmd /c ver'):
533 try:
534 pipe = popen(cmd)
535 info = pipe.read()
536 if pipe.close():
537 raise os.error,'command failed'
Ezio Melottic2077b02011-03-16 12:34:31 +0200538 # XXX How can I suppress shell errors from being written
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000539 # to stderr ?
540 except os.error,why:
541 #print 'Command %s failed: %s' % (cmd,why)
542 continue
543 except IOError,why:
544 #print 'Command %s failed: %s' % (cmd,why)
545 continue
546 else:
547 break
548 else:
549 return system,release,version
550
551 # Parse the output
552 info = string.strip(info)
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +0000553 m = _ver_output.match(info)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000554 if m is not None:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000555 system,release,version = m.groups()
556 # Strip trailing dots from version and release
557 if release[-1] == '.':
558 release = release[:-1]
559 if version[-1] == '.':
560 version = version[:-1]
561 # Normalize the version and build strings (eliminating additional
562 # zeros)
563 version = _norm_version(version)
564 return system,release,version
565
Steve Dower044cde52015-09-22 17:25:30 -0700566_WIN32_CLIENT_RELEASES = {
567 (5, 0): "2000",
568 (5, 1): "XP",
569 # Strictly, 5.2 client is XP 64-bit, but platform.py historically
570 # has always called it 2003 Server
571 (5, 2): "2003Server",
572 (5, None): "post2003",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000573
Steve Dower044cde52015-09-22 17:25:30 -0700574 (6, 0): "Vista",
575 (6, 1): "7",
576 (6, 2): "8",
577 (6, 3): "8.1",
578 (6, None): "post8.1",
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000579
Steve Dower044cde52015-09-22 17:25:30 -0700580 (10, 0): "10",
581 (10, None): "post10",
582}
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000583
Steve Dower044cde52015-09-22 17:25:30 -0700584# Server release name lookup will default to client names if necessary
585_WIN32_SERVER_RELEASES = {
586 (5, 2): "2003Server",
587
588 (6, 0): "2008Server",
589 (6, 1): "2008ServerR2",
590 (6, 2): "2012Server",
591 (6, 3): "2012ServerR2",
592 (6, None): "post2012ServerR2",
593}
594
595def _get_real_winver(maj, min, build):
596 if maj < 6 or (maj == 6 and min < 2):
597 return maj, min, build
598
599 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer,
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700600 Structure, WinDLL, _Pointer)
Steve Dower044cde52015-09-22 17:25:30 -0700601 from ctypes.wintypes import DWORD, HANDLE
602
603 class VS_FIXEDFILEINFO(Structure):
604 _fields_ = [
605 ("dwSignature", DWORD),
606 ("dwStrucVersion", DWORD),
607 ("dwFileVersionMS", DWORD),
608 ("dwFileVersionLS", DWORD),
609 ("dwProductVersionMS", DWORD),
610 ("dwProductVersionLS", DWORD),
611 ("dwFileFlagsMask", DWORD),
612 ("dwFileFlags", DWORD),
613 ("dwFileOS", DWORD),
614 ("dwFileType", DWORD),
615 ("dwFileSubtype", DWORD),
616 ("dwFileDateMS", DWORD),
617 ("dwFileDateLS", DWORD),
618 ]
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700619 class PVS_FIXEDFILEINFO(_Pointer):
620 _type_ = VS_FIXEDFILEINFO
Steve Dower044cde52015-09-22 17:25:30 -0700621
622 kernel32 = WinDLL('kernel32')
623 version = WinDLL('version')
624
625 # We will immediately double the length up to MAX_PATH, but the
626 # path may be longer, so we retry until the returned string is
627 # shorter than our buffer.
628 name_len = actual_len = 130
629 while actual_len == name_len:
630 name_len *= 2
631 name = create_unicode_buffer(name_len)
632 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle),
633 name, len(name))
634 if not actual_len:
635 return maj, min, build
636
637 size = version.GetFileVersionInfoSizeW(name, None)
638 if not size:
639 return maj, min, build
640
641 ver_block = c_buffer(size)
642 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or
643 not ver_block):
644 return maj, min, build
645
Steve Dowerdb01b3e2016-09-17 16:43:01 -0700646 pvi = PVS_FIXEDFILEINFO()
Steve Dower044cde52015-09-22 17:25:30 -0700647 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())):
648 return maj, min, build
649
650 maj = pvi.contents.dwProductVersionMS >> 16
651 min = pvi.contents.dwProductVersionMS & 0xFFFF
652 build = pvi.contents.dwProductVersionLS >> 16
653
654 return maj, min, build
655
656def win32_ver(release='', version='', csd='', ptype=''):
Steve Dowere20c2a62015-09-22 17:35:24 -0700657 try:
658 from sys import getwindowsversion
659 except ImportError:
660 return release, version, csd, ptype
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000661 try:
Steve Dower044cde52015-09-22 17:25:30 -0700662 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000663 except ImportError:
Steve Dower044cde52015-09-22 17:25:30 -0700664 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000665
Steve Dower044cde52015-09-22 17:25:30 -0700666 winver = getwindowsversion()
667 maj, min, build = _get_real_winver(*winver[:3])
668 version = '{0}.{1}.{2}'.format(maj, min, build)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000669
Steve Dower044cde52015-09-22 17:25:30 -0700670 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or
671 _WIN32_CLIENT_RELEASES.get((maj, None)) or
672 release)
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000673
Steve Dower044cde52015-09-22 17:25:30 -0700674 # getwindowsversion() reflect the compatibility mode Python is
675 # running under, and so the service pack value is only going to be
676 # valid if the versions match.
677 if winver[:2] == (maj, min):
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000678 try:
Steve Dower044cde52015-09-22 17:25:30 -0700679 csd = 'SP{}'.format(winver.service_pack_major)
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +0000680 except AttributeError:
Steve Dower044cde52015-09-22 17:25:30 -0700681 if csd[:13] == 'Service Pack ':
682 csd = 'SP' + csd[13:]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000683
Steve Dower044cde52015-09-22 17:25:30 -0700684 # VER_NT_SERVER = 3
Steve Dower1de99f72016-09-21 09:10:21 -0700685 if getattr(winver, 'product_type', None) == 3:
Steve Dower044cde52015-09-22 17:25:30 -0700686 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or
687 _WIN32_SERVER_RELEASES.get((maj, None)) or
688 release)
Marc-André Lemburgcecaa652009-07-13 21:28:33 +0000689
Steve Dower044cde52015-09-22 17:25:30 -0700690 key = None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000691 try:
Steve Dower044cde52015-09-22 17:25:30 -0700692 key = OpenKeyEx(HKEY_LOCAL_MACHINE,
693 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion')
694 ptype = QueryValueEx(key, 'CurrentType')[0]
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000695 except:
Steve Dower044cde52015-09-22 17:25:30 -0700696 pass
697 finally:
698 if key:
699 CloseKey(key)
Tim Peters0eadaac2003-04-24 16:02:54 +0000700
Steve Dower044cde52015-09-22 17:25:30 -0700701 return release, version, csd, ptype
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000702
703def _mac_ver_lookup(selectors,default=None):
704
705 from gestalt import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000706 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000707 l = []
708 append = l.append
709 for selector in selectors:
710 try:
711 append(gestalt(selector))
Jack Jansena290e3d2003-08-11 11:08:49 +0000712 except (RuntimeError, MacOS.Error):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000713 append(default)
714 return l
715
716def _bcd2str(bcd):
717
718 return hex(bcd)[2:]
719
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000720def _mac_ver_gestalt():
721 """
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000722 Thanks to Mark R. Levinson for mailing documentation links and
723 code examples for this function. Documentation for the
724 gestalt() API is available online at:
725
726 http://www.rgaros.nl/gestalt/
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000727 """
728 # Check whether the version info module is available
729 try:
730 import gestalt
Jack Jansena290e3d2003-08-11 11:08:49 +0000731 import MacOS
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000732 except ImportError:
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000733 return None
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000734 # Get the infos
Ronald Oussoren9341ad22010-02-07 11:29:31 +0000735 sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000736 # Decode the infos
737 if sysv:
738 major = (sysv & 0xFF00) >> 8
739 minor = (sysv & 0x00F0) >> 4
740 patch = (sysv & 0x000F)
Ronald Oussorenc27b8b82008-05-08 10:34:39 +0000741
742 if (major, minor) >= (10, 4):
743 # the 'sysv' gestald cannot return patchlevels
744 # higher than 9. Apple introduced 3 new
745 # gestalt codes in 10.4 to deal with this
746 # issue (needed because patch levels can
747 # run higher than 9, such as 10.4.11)
748 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
749 release = '%i.%i.%i' %(major, minor, patch)
750 else:
751 release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
Ronald Oussoren7a0f4c72008-05-18 20:54:47 +0000752
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000753 if sysa:
Tim Peters0eadaac2003-04-24 16:02:54 +0000754 machine = {0x1: '68k',
Ronald Oussoren749d0702006-04-17 13:37:15 +0000755 0x2: 'PowerPC',
756 0xa: 'i386'}.get(sysa,'')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000757
Ned Deily0ab67ee2011-07-13 15:05:31 -0700758 versioninfo=('', '', '')
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000759 return release,versioninfo,machine
760
761def _mac_ver_xml():
762 fn = '/System/Library/CoreServices/SystemVersion.plist'
763 if not os.path.exists(fn):
764 return None
765
766 try:
767 import plistlib
768 except ImportError:
769 return None
770
771 pl = plistlib.readPlist(fn)
772 release = pl['ProductVersion']
773 versioninfo=('', '', '')
774 machine = os.uname()[4]
Ronald Oussoren22e3e692010-08-03 07:44:35 +0000775 if machine in ('ppc', 'Power Macintosh'):
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000776 # for compatibility with the gestalt based code
777 machine = 'PowerPC'
778
779 return release,versioninfo,machine
780
781
782def mac_ver(release='',versioninfo=('','',''),machine=''):
783
784 """ Get MacOS version information and return it as tuple (release,
785 versioninfo, machine) with versioninfo being a tuple (version,
786 dev_stage, non_release_version).
787
Ezio Melottif5469cf2013-08-17 15:43:51 +0300788 Entries which cannot be determined are set to the parameter values
Ronald Oussoren3a04a252010-07-23 12:41:00 +0000789 which default to ''. All tuple entries are strings.
790 """
791
792 # First try reading the information from an XML file which should
793 # always be present
794 info = _mac_ver_xml()
795 if info is not None:
796 return info
797
798 # If that doesn't work for some reason fall back to reading the
799 # information using gestalt calls.
800 info = _mac_ver_gestalt()
801 if info is not None:
802 return info
803
804 # If that also doesn't work return the default values
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000805 return release,versioninfo,machine
806
Neal Norwitz9b924c62003-06-29 04:17:45 +0000807def _java_getprop(name,default):
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000808
809 from java.lang import System
810 try:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000811 value = System.getProperty(name)
812 if value is None:
813 return default
814 return value
815 except AttributeError:
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000816 return default
817
818def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
Tim Peters0eadaac2003-04-24 16:02:54 +0000819
Brett Cannon8ab27df2003-08-05 03:52:04 +0000820 """ Version interface for Jython.
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000821
822 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
823 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
824 tuple (os_name,os_version,os_arch).
825
826 Values which cannot be determined are set to the defaults
827 given as parameters (which all default to '').
828
829 """
830 # Import the needed APIs
831 try:
832 import java.lang
833 except ImportError:
834 return release,vendor,vminfo,osinfo
835
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000836 vendor = _java_getprop('java.vendor', vendor)
837 release = _java_getprop('java.version', release)
838 vm_name, vm_release, vm_vendor = vminfo
839 vm_name = _java_getprop('java.vm.name', vm_name)
840 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
841 vm_release = _java_getprop('java.vm.version', vm_release)
842 vminfo = vm_name, vm_release, vm_vendor
843 os_name, os_version, os_arch = osinfo
844 os_arch = _java_getprop('java.os.arch', os_arch)
845 os_name = _java_getprop('java.os.name', os_name)
846 os_version = _java_getprop('java.os.version', os_version)
847 osinfo = os_name, os_version, os_arch
Tim Peters0eadaac2003-04-24 16:02:54 +0000848
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000849 return release, vendor, vminfo, osinfo
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000850
851### System name aliasing
852
853def system_alias(system,release,version):
854
855 """ Returns (system,release,version) aliased to common
856 marketing names used for some systems.
857
858 It also does some reordering of the information in some cases
859 where it would otherwise cause confusion.
860
861 """
862 if system == 'Rhapsody':
863 # Apple's BSD derivative
864 # XXX How can we determine the marketing release number ?
865 return 'MacOS X Server',system+release,version
866
867 elif system == 'SunOS':
868 # Sun's OS
869 if release < '5':
870 # These releases use the old name SunOS
871 return system,release,version
872 # Modify release (marketing release = SunOS release - 3)
873 l = string.split(release,'.')
874 if l:
875 try:
876 major = int(l[0])
877 except ValueError:
878 pass
879 else:
880 major = major - 3
881 l[0] = str(major)
882 release = string.join(l,'.')
883 if release < '6':
884 system = 'Solaris'
885 else:
886 # XXX Whatever the new SunOS marketing name is...
887 system = 'Solaris'
888
889 elif system == 'IRIX64':
890 # IRIX reports IRIX64 on platforms with 64-bit support; yet it
891 # is really a version and not a different platform, since 32-bit
892 # apps are also supported..
893 system = 'IRIX'
894 if version:
895 version = version + ' (64bit)'
896 else:
897 version = '64bit'
898
899 elif system in ('win32','win16'):
900 # In case one of the other tricks
901 system = 'Windows'
902
903 return system,release,version
904
905### Various internal helpers
906
907def _platform(*args):
908
909 """ Helper to format the platform string in a filename
910 compatible format e.g. "system-version-machine".
911 """
912 # Format the platform string
913 platform = string.join(
914 map(string.strip,
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +0000915 filter(len, args)),
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000916 '-')
917
918 # Cleanup some possible filename obstacles...
919 replace = string.replace
920 platform = replace(platform,' ','_')
921 platform = replace(platform,'/','-')
922 platform = replace(platform,'\\','-')
923 platform = replace(platform,':','-')
924 platform = replace(platform,';','-')
925 platform = replace(platform,'"','-')
926 platform = replace(platform,'(','-')
927 platform = replace(platform,')','-')
928
929 # No need to report 'unknown' information...
930 platform = replace(platform,'unknown','')
931
932 # Fold '--'s and remove trailing '-'
933 while 1:
934 cleaned = replace(platform,'--','-')
935 if cleaned == platform:
936 break
937 platform = cleaned
938 while platform[-1] == '-':
939 platform = platform[:-1]
940
941 return platform
942
943def _node(default=''):
944
945 """ Helper to determine the node name of this machine.
946 """
947 try:
948 import socket
949 except ImportError:
950 # No sockets...
951 return default
952 try:
953 return socket.gethostname()
954 except socket.error:
955 # Still not working...
956 return default
957
958# os.path.abspath is new in Python 1.5.2:
959if not hasattr(os.path,'abspath'):
960
961 def _abspath(path,
962
963 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
964 normpath=os.path.normpath):
965
966 if not isabs(path):
967 path = join(getcwd(), path)
968 return normpath(path)
969
970else:
971
972 _abspath = os.path.abspath
973
974def _follow_symlinks(filepath):
975
976 """ In case filepath is a symlink, follow it until a
977 real file is reached.
978 """
979 filepath = _abspath(filepath)
980 while os.path.islink(filepath):
981 filepath = os.path.normpath(
Hirokazu Yamamoto171c4aa2008-09-04 11:15:14 +0000982 os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000983 return filepath
984
985def _syscmd_uname(option,default=''):
986
987 """ Interface to the system's uname command.
988 """
989 if sys.platform in ('dos','win32','win16','os2'):
990 # XXX Others too ?
991 return default
992 try:
Marc-André Lemburg19e5b3f2009-07-13 20:23:49 +0000993 f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
Marc-André Lemburg246d8472003-04-24 11:36:11 +0000994 except (AttributeError,os.error):
995 return default
996 output = string.strip(f.read())
997 rc = f.close()
998 if not output or rc:
999 return default
1000 else:
1001 return output
1002
1003def _syscmd_file(target,default=''):
1004
1005 """ Interface to the system's file command.
1006
1007 The function uses the -b option of the file command to have it
1008 ommit the filename in its output and if possible the -L option
1009 to have the command follow symlinks. It returns default in
1010 case the command should fail.
1011
1012 """
Jesus Ceadebda5d2012-10-04 15:14:56 +02001013
1014 # We do the import here to avoid a bootstrap issue.
1015 # See c73b90b6dadd changeset.
1016 #
1017 # [..]
1018 # ranlib libpython2.7.a
1019 # gcc -o python \
1020 # Modules/python.o \
1021 # libpython2.7.a -lsocket -lnsl -ldl -lm
1022 # Traceback (most recent call last):
1023 # File "./setup.py", line 8, in <module>
1024 # from platform import machine as platform_machine
1025 # File "[..]/build/Lib/platform.py", line 116, in <module>
1026 # import sys,string,os,re,subprocess
1027 # File "[..]/build/Lib/subprocess.py", line 429, in <module>
1028 # import select
1029 # ImportError: No module named select
1030
1031 import subprocess
1032
Hirokazu Yamamotoed8c6442008-09-01 14:32:58 +00001033 if sys.platform in ('dos','win32','win16','os2'):
1034 # XXX Others too ?
1035 return default
Jesus Cea3e94e142012-10-04 15:06:57 +02001036 target = _follow_symlinks(target)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001037 try:
Jesus Cea2699c9d2012-10-05 05:18:47 +02001038 proc = subprocess.Popen(['file', target],
1039 stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Jesus Cea3e94e142012-10-04 15:06:57 +02001040
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001041 except (AttributeError,os.error):
1042 return default
Jesus Cea69e7c9b2012-10-05 04:50:17 +02001043 output = proc.communicate()[0]
Jesus Cea3e94e142012-10-04 15:06:57 +02001044 rc = proc.wait()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001045 if not output or rc:
1046 return default
1047 else:
1048 return output
1049
1050### Information about the used architecture
1051
1052# Default values for architecture; non-empty strings override the
1053# defaults given as parameters
1054_default_architecture = {
1055 'win32': ('','WindowsPE'),
1056 'win16': ('','Windows'),
1057 'dos': ('','MSDOS'),
1058}
1059
Victor Stinner814b6c22010-04-18 18:22:25 +00001060_architecture_split = re.compile(r'[\s,]').split
1061
Marc-André Lemburg366a0fe2003-04-24 11:46:35 +00001062def architecture(executable=sys.executable,bits='',linkage=''):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001063
1064 """ Queries the given executable (defaults to the Python interpreter
Brett Cannon8ab27df2003-08-05 03:52:04 +00001065 binary) for various architecture information.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001066
Brett Cannon8ab27df2003-08-05 03:52:04 +00001067 Returns a tuple (bits,linkage) which contains information about
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001068 the bit architecture and the linkage format used for the
1069 executable. Both values are returned as strings.
1070
1071 Values that cannot be determined are returned as given by the
1072 parameter presets. If bits is given as '', the sizeof(pointer)
1073 (or sizeof(long) on Python version < 1.5.2) is used as
1074 indicator for the supported pointer size.
1075
1076 The function relies on the system's "file" command to do the
1077 actual work. This is available on most if not all Unix
Brett Cannon8ab27df2003-08-05 03:52:04 +00001078 platforms. On some non-Unix platforms where the "file" command
1079 does not exist and the executable is set to the Python interpreter
1080 binary defaults from _default_architecture are used.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001081
1082 """
1083 # Use the sizeof(pointer) as default number of bits if nothing
1084 # else is given as default.
1085 if not bits:
1086 import struct
1087 try:
1088 size = struct.calcsize('P')
1089 except struct.error:
1090 # Older installations can only query longs
1091 size = struct.calcsize('l')
1092 bits = str(size*8) + 'bit'
Tim Peters0eadaac2003-04-24 16:02:54 +00001093
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001094 # Get data from the 'file' system command
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001095 if executable:
Victor Stinner814b6c22010-04-18 18:22:25 +00001096 output = _syscmd_file(executable, '')
Marc-André Lemburg3b8f60b2007-01-13 23:13:54 +00001097 else:
Victor Stinner814b6c22010-04-18 18:22:25 +00001098 output = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001099
Victor Stinner814b6c22010-04-18 18:22:25 +00001100 if not output and \
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001101 executable == sys.executable:
1102 # "file" command did not return anything; we'll try to provide
Tim Peters0eadaac2003-04-24 16:02:54 +00001103 # some sensible defaults then...
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001104 if sys.platform in _default_architecture:
1105 b, l = _default_architecture[sys.platform]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001106 if b:
1107 bits = b
1108 if l:
1109 linkage = l
Florent Xicluna8d1da0f2010-04-01 18:17:09 +00001110 return bits, linkage
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001111
Victor Stinner814b6c22010-04-18 18:22:25 +00001112 # Split the output into a list of strings omitting the filename
1113 fileout = _architecture_split(output)[1:]
1114
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001115 if 'executable' not in fileout:
1116 # Format not supported
1117 return bits,linkage
1118
1119 # Bits
1120 if '32-bit' in fileout:
1121 bits = '32bit'
1122 elif 'N32' in fileout:
1123 # On Irix only
1124 bits = 'n32bit'
1125 elif '64-bit' in fileout:
1126 bits = '64bit'
1127
1128 # Linkage
1129 if 'ELF' in fileout:
1130 linkage = 'ELF'
1131 elif 'PE' in fileout:
1132 # E.g. Windows uses this format
1133 if 'Windows' in fileout:
1134 linkage = 'WindowsPE'
1135 else:
1136 linkage = 'PE'
1137 elif 'COFF' in fileout:
1138 linkage = 'COFF'
1139 elif 'MS-DOS' in fileout:
1140 linkage = 'MSDOS'
1141 else:
1142 # XXX the A.OUT format also falls under this class...
1143 pass
1144
1145 return bits,linkage
1146
1147### Portable uname() interface
Tim Peters0eadaac2003-04-24 16:02:54 +00001148
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001149_uname_cache = None
1150
1151def uname():
1152
1153 """ Fairly portable uname interface. Returns a tuple
1154 of strings (system,node,release,version,machine,processor)
1155 identifying the underlying platform.
1156
1157 Note that unlike the os.uname function this also returns
Brett Cannon8ab27df2003-08-05 03:52:04 +00001158 possible processor information as an additional tuple entry.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001159
1160 Entries which cannot be determined are set to ''.
1161
1162 """
1163 global _uname_cache
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001164 no_os_uname = 0
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001165
1166 if _uname_cache is not None:
1167 return _uname_cache
1168
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001169 processor = ''
1170
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001171 # Get some infos from the builtin os.uname API...
1172 try:
1173 system,node,release,version,machine = os.uname()
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001174 except AttributeError:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001175 no_os_uname = 1
1176
1177 if no_os_uname or not filter(None, (system, node, release, version, machine)):
1178 # Hmm, no there is either no uname or uname has returned
1179 #'unknowns'... we'll have to poke around the system then.
1180 if no_os_uname:
1181 system = sys.platform
1182 release = ''
1183 version = ''
1184 node = _node()
1185 machine = ''
1186
Marc-André Lemburgcecaa652009-07-13 21:28:33 +00001187 use_syscmd_ver = 1
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001188
1189 # Try win32_ver() on win32 platforms
1190 if system == 'win32':
1191 release,version,csd,ptype = win32_ver()
1192 if release and version:
1193 use_syscmd_ver = 0
Marc-André Lemburgdbd61a22008-03-20 17:31:36 +00001194 # Try to use the PROCESSOR_* environment variables
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001195 # available on Win XP and later; see
1196 # http://support.microsoft.com/kb/888731 and
1197 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001198 if not machine:
R. David Murrayc9d1a782010-03-22 15:55:09 +00001199 # WOW64 processes mask the native architecture
1200 if "PROCESSOR_ARCHITEW6432" in os.environ:
1201 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1202 else:
1203 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001204 if not processor:
1205 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
Tim Peters0eadaac2003-04-24 16:02:54 +00001206
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001207 # Try the 'ver' system command available on some
1208 # platforms
1209 if use_syscmd_ver:
1210 system,release,version = _syscmd_ver(system)
Marc-André Lemburgcdc79232004-06-19 17:17:00 +00001211 # Normalize system to what win32_ver() normally returns
1212 # (_syscmd_ver() tends to return the vendor name as well)
1213 if system == 'Microsoft Windows':
1214 system = 'Windows'
Marc-André Lemburgb24cd0f2007-06-12 09:26:49 +00001215 elif system == 'Microsoft' and release == 'Windows':
1216 # Under Windows Vista and Windows Server 2008,
1217 # Microsoft changed the output of the ver command. The
1218 # release is no longer printed. This causes the
1219 # system and release to be misidentified.
1220 system = 'Windows'
1221 if '6.0' == version[:3]:
1222 release = 'Vista'
1223 else:
1224 release = ''
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001225
1226 # In case we still don't know anything useful, we'll try to
1227 # help ourselves
1228 if system in ('win32','win16'):
1229 if not version:
1230 if system == 'win32':
1231 version = '32bit'
1232 else:
1233 version = '16bit'
1234 system = 'Windows'
1235
1236 elif system[:4] == 'java':
1237 release,vendor,vminfo,osinfo = java_ver()
1238 system = 'Java'
1239 version = string.join(vminfo,', ')
1240 if not version:
1241 version = vendor
1242
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001243 # System specific extensions
1244 if system == 'OpenVMS':
1245 # OpenVMS seems to have release and version mixed up
1246 if not release or release == '0':
1247 release = version
1248 version = ''
1249 # Get processor information
1250 try:
1251 import vms_lib
1252 except ImportError:
1253 pass
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001254 else:
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001255 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1256 if (cpu_number >= 128):
1257 processor = 'Alpha'
1258 else:
1259 processor = 'VAX'
1260 if not processor:
1261 # Get processor information from the uname system command
1262 processor = _syscmd_uname('-p','')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001263
Benjamin Peterson5c0be322008-06-13 15:11:50 +00001264 #If any unknowns still exist, replace them with ''s, which are more portable
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001265 if system == 'unknown':
1266 system = ''
1267 if node == 'unknown':
1268 node = ''
1269 if release == 'unknown':
1270 release = ''
1271 if version == 'unknown':
1272 version = ''
1273 if machine == 'unknown':
1274 machine = ''
1275 if processor == 'unknown':
1276 processor = ''
Sean Reifscheiderf09597c2007-09-17 20:53:21 +00001277
1278 # normalize name
1279 if system == 'Microsoft' and release == 'Windows':
1280 system = 'Windows'
1281 release = 'Vista'
1282
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001283 _uname_cache = system,node,release,version,machine,processor
1284 return _uname_cache
1285
1286### Direct interfaces to some of the uname() return values
1287
1288def system():
1289
1290 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1291
1292 An empty string is returned if the value cannot be determined.
1293
1294 """
1295 return uname()[0]
1296
1297def node():
1298
Brett Cannon8ab27df2003-08-05 03:52:04 +00001299 """ Returns the computer's network name (which may not be fully
1300 qualified)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001301
1302 An empty string is returned if the value cannot be determined.
1303
1304 """
1305 return uname()[1]
1306
1307def release():
1308
1309 """ Returns the system's release, e.g. '2.2.0' or 'NT'
1310
1311 An empty string is returned if the value cannot be determined.
1312
1313 """
1314 return uname()[2]
1315
1316def version():
1317
1318 """ Returns the system's release version, e.g. '#3 on degas'
1319
1320 An empty string is returned if the value cannot be determined.
1321
1322 """
1323 return uname()[3]
1324
1325def machine():
1326
1327 """ Returns the machine type, e.g. 'i386'
1328
1329 An empty string is returned if the value cannot be determined.
1330
1331 """
1332 return uname()[4]
1333
1334def processor():
1335
1336 """ Returns the (true) processor name, e.g. 'amdk6'
1337
1338 An empty string is returned if the value cannot be
1339 determined. Note that many platforms do not provide this
1340 information or simply return the same value as for machine(),
1341 e.g. NetBSD does this.
1342
1343 """
1344 return uname()[5]
1345
1346### Various APIs for extracting information from sys.version
1347
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001348_sys_version_parser = re.compile(
Martin Panterc3636442016-06-08 06:12:22 +00001349 r'([\w.+]+)\s*' # "version<space>"
1350 r'\(#?([^,]+)' # "(#buildno"
1351 r'(?:,\s*([\w ]*)' # ", builddate"
1352 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>"
1353 r'\[([^\]]+)\]?') # "[compiler]"
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001354
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001355_ironpython_sys_version_parser = re.compile(
1356 r'IronPython\s*'
1357 '([\d\.]+)'
1358 '(?: \(([\d\.]+)\))?'
1359 ' on (.NET [\d\.]+)')
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001360
Ezio Melottibc385482013-10-21 03:03:32 +03001361# IronPython covering 2.6 and 2.7
1362_ironpython26_sys_version_parser = re.compile(
1363 r'([\d.]+)\s*'
1364 '\(IronPython\s*'
1365 '[\d.]+\s*'
1366 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)'
1367)
1368
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001369_pypy_sys_version_parser = re.compile(
1370 r'([\w.+]+)\s*'
1371 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1372 '\[PyPy [^\]]+\]?')
1373
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001374_sys_version_cache = {}
1375
1376def _sys_version(sys_version=None):
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001377
1378 """ Returns a parsed version of Python's sys.version as tuple
Marc-André Lemburga519cfc2009-03-25 19:44:58 +00001379 (name, version, branch, revision, buildno, builddate, compiler)
1380 referring to the Python implementation name, version, branch,
1381 revision, build number, build date/time as string and the compiler
1382 identification string.
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001383
1384 Note that unlike the Python sys.version, the returned value
1385 for the Python version will always include the patchlevel (it
1386 defaults to '.0').
1387
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001388 The function returns empty strings for tuple entries that
1389 cannot be determined.
1390
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001391 sys_version may be given to parse an alternative version
1392 string, e.g. if the version was read from a different Python
1393 interpreter.
1394
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001395 """
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001396 # Get the Python version
1397 if sys_version is None:
1398 sys_version = sys.version
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001399
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001400 # Try the cache first
1401 result = _sys_version_cache.get(sys_version, None)
1402 if result is not None:
1403 return result
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001404
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001405 # Parse it
Ezio Melottibc385482013-10-21 03:03:32 +03001406 if 'IronPython' in sys_version:
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001407 # IronPython
1408 name = 'IronPython'
Ezio Melottibc385482013-10-21 03:03:32 +03001409 if sys_version.startswith('IronPython'):
1410 match = _ironpython_sys_version_parser.match(sys_version)
1411 else:
1412 match = _ironpython26_sys_version_parser.match(sys_version)
1413
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001414 if match is None:
1415 raise ValueError(
1416 'failed to parse IronPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001417 repr(sys_version))
Ezio Melottibc385482013-10-21 03:03:32 +03001418
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001419 version, alt_version, compiler = match.groups()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001420 buildno = ''
1421 builddate = ''
1422
Ezio Melottibc385482013-10-21 03:03:32 +03001423 elif sys.platform.startswith('java'):
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001424 # Jython
1425 name = 'Jython'
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001426 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001427 if match is None:
1428 raise ValueError(
1429 'failed to parse Jython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001430 repr(sys_version))
Benjamin Petersonf521b8c2009-03-26 18:35:37 +00001431 version, buildno, builddate, buildtime, _ = match.groups()
Martin Panterc3636442016-06-08 06:12:22 +00001432 if builddate is None:
1433 builddate = ''
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001434 compiler = sys.platform
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001435
Benjamin Peterson0ad9b772009-03-26 19:09:21 +00001436 elif "PyPy" in sys_version:
1437 # PyPy
1438 name = "PyPy"
1439 match = _pypy_sys_version_parser.match(sys_version)
1440 if match is None:
1441 raise ValueError("failed to parse PyPy sys.version: %s" %
1442 repr(sys_version))
1443 version, buildno, builddate, buildtime = match.groups()
1444 compiler = ""
1445
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001446 else:
1447 # CPython
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001448 match = _sys_version_parser.match(sys_version)
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001449 if match is None:
1450 raise ValueError(
1451 'failed to parse CPython sys.version: %s' %
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001452 repr(sys_version))
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001453 version, buildno, builddate, buildtime, compiler = \
1454 match.groups()
Benjamin Petersonb457b892009-03-26 18:55:48 +00001455 name = 'CPython'
Martin Panterc3636442016-06-08 06:12:22 +00001456 if builddate is None:
1457 builddate = ''
1458 elif buildtime:
1459 builddate = builddate + ' ' + buildtime
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001460
Benjamin Petersonb457b892009-03-26 18:55:48 +00001461 if hasattr(sys, 'subversion'):
1462 # sys.subversion was added in Python 2.5
1463 _, branch, revision = sys.subversion
1464 else:
1465 branch = ''
1466 revision = ''
1467
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001468 # Add the patchlevel version if missing
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001469 l = string.split(version, '.')
1470 if len(l) == 2:
1471 l.append('0')
1472 version = string.join(l, '.')
Marc-André Lemburg2be9d432007-01-13 22:32:21 +00001473
1474 # Build and cache the result
1475 result = (name, version, branch, revision, buildno, builddate, compiler)
1476 _sys_version_cache[sys_version] = result
1477 return result
1478
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001479def python_implementation():
1480
1481 """ Returns a string identifying the Python implementation.
1482
1483 Currently, the following implementations are identified:
Ezio Melotti6fa09472011-05-04 18:37:50 +03001484 'CPython' (C implementation of Python),
1485 'IronPython' (.NET implementation of Python),
1486 'Jython' (Java implementation of Python),
1487 'PyPy' (Python implementation of Python).
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001488
1489 """
1490 return _sys_version()[0]
1491
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001492def python_version():
1493
1494 """ Returns the Python version as string 'major.minor.patchlevel'
1495
1496 Note that unlike the Python sys.version, the returned value
1497 will always include the patchlevel (it defaults to 0).
1498
1499 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001500 return _sys_version()[1]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001501
1502def python_version_tuple():
1503
1504 """ Returns the Python version as tuple (major, minor, patchlevel)
1505 of strings.
1506
1507 Note that unlike the Python sys.version, the returned value
1508 will always include the patchlevel (it defaults to 0).
1509
1510 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001511 return tuple(string.split(_sys_version()[1], '.'))
1512
1513def python_branch():
1514
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001515 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001516 branch.
1517
1518 For CPython this is the Subversion branch from which the
1519 Python binary was built.
1520
1521 If not available, an empty string is returned.
1522
1523 """
Tim Petersf733abb2007-01-30 03:03:46 +00001524
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001525 return _sys_version()[2]
1526
1527def python_revision():
1528
Neal Norwitz4b86f8b2007-01-13 21:22:37 +00001529 """ Returns a string identifying the Python implementation
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001530 revision.
1531
1532 For CPython this is the Subversion revision from which the
1533 Python binary was built.
1534
1535 If not available, an empty string is returned.
1536
1537 """
1538 return _sys_version()[3]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001539
1540def python_build():
1541
1542 """ Returns a tuple (buildno, builddate) stating the Python
1543 build number and date as strings.
1544
1545 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001546 return _sys_version()[4:6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001547
1548def python_compiler():
1549
1550 """ Returns a string identifying the compiler used for compiling
1551 Python.
1552
1553 """
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001554 return _sys_version()[6]
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001555
1556### The Opus Magnum of platform strings :-)
1557
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001558_platform_cache = {}
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001559
1560def platform(aliased=0, terse=0):
1561
1562 """ Returns a single string identifying the underlying platform
1563 with as much useful information as possible (but no more :).
Tim Peters0eadaac2003-04-24 16:02:54 +00001564
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001565 The output is intended to be human readable rather than
1566 machine parseable. It may look different on different
1567 platforms and this is intended.
1568
1569 If "aliased" is true, the function will use aliases for
1570 various platforms that report system names which differ from
1571 their common names, e.g. SunOS will be reported as
1572 Solaris. The system_alias() function is used to implement
1573 this.
1574
1575 Setting terse to true causes the function to return only the
1576 absolute minimum information needed to identify the platform.
1577
1578 """
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001579 result = _platform_cache.get((aliased, terse), None)
1580 if result is not None:
1581 return result
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001582
1583 # Get uname information and then apply platform specific cosmetics
1584 # to it...
1585 system,node,release,version,machine,processor = uname()
1586 if machine == processor:
1587 processor = ''
1588 if aliased:
1589 system,release,version = system_alias(system,release,version)
1590
1591 if system == 'Windows':
1592 # MS platforms
1593 rel,vers,csd,ptype = win32_ver(version)
1594 if terse:
1595 platform = _platform(system,release)
1596 else:
1597 platform = _platform(system,release,version,csd)
1598
1599 elif system in ('Linux',):
1600 # Linux based systems
1601 distname,distversion,distid = dist('')
1602 if distname and not terse:
1603 platform = _platform(system,release,machine,processor,
1604 'with',
1605 distname,distversion,distid)
1606 else:
1607 # If the distribution name is unknown check for libc vs. glibc
1608 libcname,libcversion = libc_ver(sys.executable)
1609 platform = _platform(system,release,machine,processor,
1610 'with',
1611 libcname+libcversion)
1612 elif system == 'Java':
1613 # Java platforms
1614 r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
Marc-André Lemburg9e0dc962007-01-13 21:00:08 +00001615 if terse or not os_name:
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001616 platform = _platform(system,release,version)
1617 else:
1618 platform = _platform(system,release,version,
1619 'on',
1620 os_name,os_version,os_arch)
1621
1622 elif system == 'MacOS':
1623 # MacOS platforms
1624 if terse:
1625 platform = _platform(system,release)
1626 else:
1627 platform = _platform(system,release,machine)
1628
1629 else:
1630 # Generic handler
1631 if terse:
1632 platform = _platform(system,release)
1633 else:
1634 bits,linkage = architecture(sys.executable)
1635 platform = _platform(system,release,machine,processor,bits,linkage)
Tim Peters0eadaac2003-04-24 16:02:54 +00001636
Marc-André Lemburg91e83e22004-03-25 18:35:12 +00001637 _platform_cache[(aliased, terse)] = platform
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001638 return platform
1639
1640### Command line interface
1641
1642if __name__ == '__main__':
1643 # Default is to print the aliased verbose platform string
Tim Peters0eadaac2003-04-24 16:02:54 +00001644 terse = ('terse' in sys.argv or '--terse' in sys.argv)
Marc-André Lemburg246d8472003-04-24 11:36:11 +00001645 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1646 print platform(aliased,terse)
1647 sys.exit(0)