1#!/usr/bin/env python 2 3""" This module tries to retrieve as much platform-identifying data as 4 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 13# Python bug tracker (http://bugs.python.org) and assign them to "lemburg". 14# 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# 23# Many thanks to all those who helped adding platform-specific 24# 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), 31# Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter, Steve 32# Dower 33# 34# History: 35# 36# <see CVS and SVN checkin messages for history> 37# 38# 1.0.8 - changed Windows support to read version from kernel32.dll 39# 1.0.7 - added DEV_NULL 40# 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 43# 1.0.3 - added normalization of Windows system name 44# 1.0.2 - added more Windows support 45# 1.0.1 - reformatted to make doc.py happy 46# 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 66# 'unknown' instead of just leaving the field empty) 67# 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 97 Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:info@egenix.com 98 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 116__version__ = '1.0.7' 117 118import sys,string,os,re 119 120### 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 135### Platform specific APIs 136 137_libc_search = re.compile(r'(__libc_init)' 138 '|' 139 '(GLIBC_([0-9.]+))' 140 '|' 141 '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)') 142 143def libc_ver(executable=sys.executable,lib='',version='', 144 145 chunksize=2048): 146 147 """ Tries to determine the libc version that the file executable 148 (which defaults to the Python interpreter) is linked against. 149 150 Returns a tuple of strings (lib,version) which default to the 151 given parameters in case the lookup fails. 152 153 Note that the function has intimate knowledge of how different 154 libc versions add symbols to the executable and thus is probably 155 only useable for executables compiled using gcc. 156 157 The file is read and scanned in chunks of chunksize bytes. 158 159 """ 160 if hasattr(os.path, 'realpath'): 161 # Python 2.2 introduced os.path.realpath(); it is used 162 # here to work around problems with Cygwin not being 163 # able to open symlinks for reading 164 executable = os.path.realpath(executable) 165 f = open(executable,'rb') 166 binary = f.read(chunksize) 167 pos = 0 168 while 1: 169 m = _libc_search.search(binary,pos) 170 if not m: 171 binary = f.read(chunksize) 172 if not binary: 173 break 174 pos = 0 175 continue 176 libcinit,glibc,glibcversion,so,threads,soversion = m.groups() 177 if libcinit and not lib: 178 lib = 'libc' 179 elif glibc: 180 if lib != 'glibc': 181 lib = 'glibc' 182 version = glibcversion 183 elif glibcversion > version: 184 version = glibcversion 185 elif so: 186 if lib != 'glibc': 187 lib = 'libc' 188 if soversion and soversion > version: 189 version = soversion 190 if threads and version[-len(threads):] != threads: 191 version = version + threads 192 pos = m.end() 193 f.close() 194 return lib,version 195 196def _dist_try_harder(distname,version,id): 197 198 """ Tries some special tricks to get the distribution 199 information in case the default method fails. 200 201 Currently supports older SuSE Linux, Caldera OpenLinux and 202 Slackware Linux distributions. 203 204 """ 205 if os.path.exists('/var/adm/inst-log/info'): 206 # SuSE Linux stores distribution information in that file 207 info = open('/var/adm/inst-log/info').readlines() 208 distname = 'SuSE' 209 for line in info: 210 tv = string.split(line) 211 if len(tv) == 2: 212 tag,value = tv 213 else: 214 continue 215 if tag == 'MIN_DIST_VERSION': 216 version = string.strip(value) 217 elif tag == 'DIST_IDENT': 218 values = string.split(value,'-') 219 id = values[2] 220 return distname,version,id 221 222 if os.path.exists('/etc/.installed'): 223 # Caldera OpenLinux has some infos in that file (thanks to Colin Kong) 224 info = open('/etc/.installed').readlines() 225 for line in info: 226 pkg = string.split(line,'-') 227 if len(pkg) >= 2 and pkg[0] == 'OpenLinux': 228 # XXX does Caldera support non Intel platforms ? If yes, 229 # where can we find the needed id ? 230 return 'OpenLinux',pkg[1],id 231 232 if os.path.isdir('/usr/lib/setup'): 233 # Check for slackware version tag file (thanks to Greg Andruk) 234 verfiles = os.listdir('/usr/lib/setup') 235 for n in range(len(verfiles)-1, -1, -1): 236 if verfiles[n][:14] != 'slack-version-': 237 del verfiles[n] 238 if verfiles: 239 verfiles.sort() 240 distname = 'slackware' 241 version = verfiles[-1][14:] 242 return distname,version,id 243 244 return distname,version,id 245 246_release_filename = re.compile(r'(\w+)[-_](release|version)') 247_lsb_release_version = re.compile(r'(.+)' 248 ' release ' 249 '([\d.]+)' 250 '[^(]*(?:\((.+)\))?') 251_release_version = re.compile(r'([^0-9]+)' 252 '(?: release )?' 253 '([\d.]+)' 254 '[^(]*(?:\((.+)\))?') 255 256# See also http://www.novell.com/coolsolutions/feature/11251.html 257# and http://linuxmafia.com/faq/Admin/release-files.html 258# and http://data.linux-ntfs.org/rpm/whichrpm 259# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html 260 261_supported_dists = ( 262 'SuSE', 'debian', 'fedora', 'redhat', 'centos', 263 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo', 264 'UnitedLinux', 'turbolinux') 265 266def _parse_release_file(firstline): 267 268 # Default to empty 'version' and 'id' strings. Both defaults are used 269 # when 'firstline' is empty. 'id' defaults to empty when an id can not 270 # be deduced. 271 version = '' 272 id = '' 273 274 # Parse the first line 275 m = _lsb_release_version.match(firstline) 276 if m is not None: 277 # LSB format: "distro release x.x (codename)" 278 return tuple(m.groups()) 279 280 # Pre-LSB format: "distro x.x (codename)" 281 m = _release_version.match(firstline) 282 if m is not None: 283 return tuple(m.groups()) 284 285 # Unknown format... take the first two words 286 l = string.split(string.strip(firstline)) 287 if l: 288 version = l[0] 289 if len(l) > 1: 290 id = l[1] 291 return '', version, id 292 293def linux_distribution(distname='', version='', id='', 294 295 supported_dists=_supported_dists, 296 full_distribution_name=1): 297 298 """ Tries to determine the name of the Linux OS distribution name. 299 300 The function first looks for a distribution release file in 301 /etc and then reverts to _dist_try_harder() in case no 302 suitable files are found. 303 304 supported_dists may be given to define the set of Linux 305 distributions to look for. It defaults to a list of currently 306 supported Linux distributions identified by their release file 307 name. 308 309 If full_distribution_name is true (default), the full 310 distribution read from the OS is returned. Otherwise the short 311 name taken from supported_dists is used. 312 313 Returns a tuple (distname,version,id) which default to the 314 args given as parameters. 315 316 """ 317 try: 318 etc = os.listdir('/etc') 319 except os.error: 320 # Probably not a Unix system 321 return distname,version,id 322 etc.sort() 323 for file in etc: 324 m = _release_filename.match(file) 325 if m is not None: 326 _distname,dummy = m.groups() 327 if _distname in supported_dists: 328 distname = _distname 329 break 330 else: 331 return _dist_try_harder(distname,version,id) 332 333 # Read the first line 334 f = open('/etc/'+file, 'r') 335 firstline = f.readline() 336 f.close() 337 _distname, _version, _id = _parse_release_file(firstline) 338 339 if _distname and full_distribution_name: 340 distname = _distname 341 if _version: 342 version = _version 343 if _id: 344 id = _id 345 return distname, version, id 346 347# To maintain backwards compatibility: 348 349def dist(distname='',version='',id='', 350 351 supported_dists=_supported_dists): 352 353 """ Tries to determine the name of the Linux OS distribution name. 354 355 The function first looks for a distribution release file in 356 /etc and then reverts to _dist_try_harder() in case no 357 suitable files are found. 358 359 Returns a tuple (distname,version,id) which default to the 360 args given as parameters. 361 362 """ 363 return linux_distribution(distname, version, id, 364 supported_dists=supported_dists, 365 full_distribution_name=0) 366 367class _popen: 368 369 """ Fairly portable (alternative) popen implementation. 370 371 This is mostly needed in case os.popen() is not available, or 372 doesn't work as advertised, e.g. in Win9X GUI programs like 373 PythonWin or IDLE. 374 375 Writing to the pipe is currently not supported. 376 377 """ 378 tmpfile = '' 379 pipe = None 380 bufsize = None 381 mode = 'r' 382 383 def __init__(self,cmd,mode='r',bufsize=None): 384 385 if mode != 'r': 386 raise ValueError,'popen()-emulation only supports read mode' 387 import tempfile 388 self.tmpfile = tmpfile = tempfile.mktemp() 389 os.system(cmd + ' > %s' % tmpfile) 390 self.pipe = open(tmpfile,'rb') 391 self.bufsize = bufsize 392 self.mode = mode 393 394 def read(self): 395 396 return self.pipe.read() 397 398 def readlines(self): 399 400 if self.bufsize is not None: 401 return self.pipe.readlines() 402 403 def close(self, 404 405 remove=os.unlink,error=os.error): 406 407 if self.pipe: 408 rc = self.pipe.close() 409 else: 410 rc = 255 411 if self.tmpfile: 412 try: 413 remove(self.tmpfile) 414 except error: 415 pass 416 return rc 417 418 # Alias 419 __del__ = close 420 421def popen(cmd, mode='r', bufsize=None): 422 423 """ Portable popen() interface. 424 """ 425 # Find a working popen implementation preferring win32pipe.popen 426 # over os.popen over _popen 427 popen = None 428 if os.environ.get('OS','') == 'Windows_NT': 429 # On NT win32pipe should work; on Win9x it hangs due to bugs 430 # in the MS C lib (see MS KnowledgeBase article Q150956) 431 try: 432 import win32pipe 433 except ImportError: 434 pass 435 else: 436 popen = win32pipe.popen 437 if popen is None: 438 if hasattr(os,'popen'): 439 popen = os.popen 440 # Check whether it works... it doesn't in GUI programs 441 # on Windows platforms 442 if sys.platform == 'win32': # XXX Others too ? 443 try: 444 popen('') 445 except os.error: 446 popen = _popen 447 else: 448 popen = _popen 449 if bufsize is None: 450 return popen(cmd,mode) 451 else: 452 return popen(cmd,mode,bufsize) 453 454def _norm_version(version, build=''): 455 456 """ Normalize the version and build strings and return a single 457 version string using the format major.minor.build (or patchlevel). 458 """ 459 l = string.split(version,'.') 460 if build: 461 l.append(build) 462 try: 463 ints = map(int,l) 464 except ValueError: 465 strings = l 466 else: 467 strings = map(str,ints) 468 version = string.join(strings[:3],'.') 469 return version 470 471_ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) ' 472 '.*' 473 '\[.* ([\d.]+)\])') 474 475# Examples of VER command output: 476# 477# Windows 2000: Microsoft Windows 2000 [Version 5.00.2195] 478# Windows XP: Microsoft Windows XP [Version 5.1.2600] 479# Windows Vista: Microsoft Windows [Version 6.0.6002] 480# 481# Note that the "Version" string gets localized on different 482# Windows versions. 483 484def _syscmd_ver(system='', release='', version='', 485 486 supported_platforms=('win32','win16','dos','os2')): 487 488 """ Tries to figure out the OS version used and returns 489 a tuple (system,release,version). 490 491 It uses the "ver" shell command for this which is known 492 to exists on Windows, DOS and OS/2. XXX Others too ? 493 494 In case this fails, the given parameters are used as 495 defaults. 496 497 """ 498 if sys.platform not in supported_platforms: 499 return system,release,version 500 501 # Try some common cmd strings 502 for cmd in ('ver','command /c ver','cmd /c ver'): 503 try: 504 pipe = popen(cmd) 505 info = pipe.read() 506 if pipe.close(): 507 raise os.error,'command failed' 508 # XXX How can I suppress shell errors from being written 509 # to stderr ? 510 except os.error,why: 511 #print 'Command %s failed: %s' % (cmd,why) 512 continue 513 except IOError,why: 514 #print 'Command %s failed: %s' % (cmd,why) 515 continue 516 else: 517 break 518 else: 519 return system,release,version 520 521 # Parse the output 522 info = string.strip(info) 523 m = _ver_output.match(info) 524 if m is not None: 525 system,release,version = m.groups() 526 # Strip trailing dots from version and release 527 if release[-1] == '.': 528 release = release[:-1] 529 if version[-1] == '.': 530 version = version[:-1] 531 # Normalize the version and build strings (eliminating additional 532 # zeros) 533 version = _norm_version(version) 534 return system,release,version 535 536_WIN32_CLIENT_RELEASES = { 537 (5, 0): "2000", 538 (5, 1): "XP", 539 # Strictly, 5.2 client is XP 64-bit, but platform.py historically 540 # has always called it 2003 Server 541 (5, 2): "2003Server", 542 (5, None): "post2003", 543 544 (6, 0): "Vista", 545 (6, 1): "7", 546 (6, 2): "8", 547 (6, 3): "8.1", 548 (6, None): "post8.1", 549 550 (10, 0): "10", 551 (10, None): "post10", 552} 553 554# Server release name lookup will default to client names if necessary 555_WIN32_SERVER_RELEASES = { 556 (5, 2): "2003Server", 557 558 (6, 0): "2008Server", 559 (6, 1): "2008ServerR2", 560 (6, 2): "2012Server", 561 (6, 3): "2012ServerR2", 562 (6, None): "post2012ServerR2", 563} 564 565def _get_real_winver(maj, min, build): 566 if maj < 6 or (maj == 6 and min < 2): 567 return maj, min, build 568 569 from ctypes import (c_buffer, POINTER, byref, create_unicode_buffer, 570 Structure, WinDLL, _Pointer) 571 from ctypes.wintypes import DWORD, HANDLE 572 573 class VS_FIXEDFILEINFO(Structure): 574 _fields_ = [ 575 ("dwSignature", DWORD), 576 ("dwStrucVersion", DWORD), 577 ("dwFileVersionMS", DWORD), 578 ("dwFileVersionLS", DWORD), 579 ("dwProductVersionMS", DWORD), 580 ("dwProductVersionLS", DWORD), 581 ("dwFileFlagsMask", DWORD), 582 ("dwFileFlags", DWORD), 583 ("dwFileOS", DWORD), 584 ("dwFileType", DWORD), 585 ("dwFileSubtype", DWORD), 586 ("dwFileDateMS", DWORD), 587 ("dwFileDateLS", DWORD), 588 ] 589 class PVS_FIXEDFILEINFO(_Pointer): 590 _type_ = VS_FIXEDFILEINFO 591 592 kernel32 = WinDLL('kernel32') 593 version = WinDLL('version') 594 595 # We will immediately double the length up to MAX_PATH, but the 596 # path may be longer, so we retry until the returned string is 597 # shorter than our buffer. 598 name_len = actual_len = 130 599 while actual_len == name_len: 600 name_len *= 2 601 name = create_unicode_buffer(name_len) 602 actual_len = kernel32.GetModuleFileNameW(HANDLE(kernel32._handle), 603 name, len(name)) 604 if not actual_len: 605 return maj, min, build 606 607 size = version.GetFileVersionInfoSizeW(name, None) 608 if not size: 609 return maj, min, build 610 611 ver_block = c_buffer(size) 612 if (not version.GetFileVersionInfoW(name, None, size, ver_block) or 613 not ver_block): 614 return maj, min, build 615 616 pvi = PVS_FIXEDFILEINFO() 617 if not version.VerQueryValueW(ver_block, "", byref(pvi), byref(DWORD())): 618 return maj, min, build 619 620 maj = pvi.contents.dwProductVersionMS >> 16 621 min = pvi.contents.dwProductVersionMS & 0xFFFF 622 build = pvi.contents.dwProductVersionLS >> 16 623 624 return maj, min, build 625 626def win32_ver(release='', version='', csd='', ptype=''): 627 try: 628 from sys import getwindowsversion 629 except ImportError: 630 return release, version, csd, ptype 631 try: 632 from winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE 633 except ImportError: 634 from _winreg import OpenKeyEx, QueryValueEx, CloseKey, HKEY_LOCAL_MACHINE 635 636 winver = getwindowsversion() 637 maj, min, build = _get_real_winver(*winver[:3]) 638 version = '{0}.{1}.{2}'.format(maj, min, build) 639 640 release = (_WIN32_CLIENT_RELEASES.get((maj, min)) or 641 _WIN32_CLIENT_RELEASES.get((maj, None)) or 642 release) 643 644 # getwindowsversion() reflect the compatibility mode Python is 645 # running under, and so the service pack value is only going to be 646 # valid if the versions match. 647 if winver[:2] == (maj, min): 648 try: 649 csd = 'SP{}'.format(winver.service_pack_major) 650 except AttributeError: 651 if csd[:13] == 'Service Pack ': 652 csd = 'SP' + csd[13:] 653 654 # VER_NT_SERVER = 3 655 if getattr(winver, 'product_type', None) == 3: 656 release = (_WIN32_SERVER_RELEASES.get((maj, min)) or 657 _WIN32_SERVER_RELEASES.get((maj, None)) or 658 release) 659 660 key = None 661 try: 662 key = OpenKeyEx(HKEY_LOCAL_MACHINE, 663 r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') 664 ptype = QueryValueEx(key, 'CurrentType')[0] 665 except: 666 pass 667 finally: 668 if key: 669 CloseKey(key) 670 671 return release, version, csd, ptype 672 673def _mac_ver_lookup(selectors,default=None): 674 675 from gestalt import gestalt 676 import MacOS 677 l = [] 678 append = l.append 679 for selector in selectors: 680 try: 681 append(gestalt(selector)) 682 except (RuntimeError, MacOS.Error): 683 append(default) 684 return l 685 686def _bcd2str(bcd): 687 688 return hex(bcd)[2:] 689 690def _mac_ver_gestalt(): 691 """ 692 Thanks to Mark R. Levinson for mailing documentation links and 693 code examples for this function. Documentation for the 694 gestalt() API is available online at: 695 696 http://www.rgaros.nl/gestalt/ 697 """ 698 # Check whether the version info module is available 699 try: 700 import gestalt 701 import MacOS 702 except ImportError: 703 return None 704 # Get the infos 705 sysv,sysa = _mac_ver_lookup(('sysv','sysa')) 706 # Decode the infos 707 if sysv: 708 major = (sysv & 0xFF00) >> 8 709 minor = (sysv & 0x00F0) >> 4 710 patch = (sysv & 0x000F) 711 712 if (major, minor) >= (10, 4): 713 # the 'sysv' gestald cannot return patchlevels 714 # higher than 9. Apple introduced 3 new 715 # gestalt codes in 10.4 to deal with this 716 # issue (needed because patch levels can 717 # run higher than 9, such as 10.4.11) 718 major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3')) 719 release = '%i.%i.%i' %(major, minor, patch) 720 else: 721 release = '%s.%i.%i' % (_bcd2str(major),minor,patch) 722 723 if sysa: 724 machine = {0x1: '68k', 725 0x2: 'PowerPC', 726 0xa: 'i386'}.get(sysa,'') 727 728 versioninfo=('', '', '') 729 return release,versioninfo,machine 730 731def _mac_ver_xml(): 732 fn = '/System/Library/CoreServices/SystemVersion.plist' 733 if not os.path.exists(fn): 734 return None 735 736 try: 737 import plistlib 738 except ImportError: 739 return None 740 741 pl = plistlib.readPlist(fn) 742 release = pl['ProductVersion'] 743 versioninfo=('', '', '') 744 machine = os.uname()[4] 745 if machine in ('ppc', 'Power Macintosh'): 746 # for compatibility with the gestalt based code 747 machine = 'PowerPC' 748 749 return release,versioninfo,machine 750 751 752def mac_ver(release='',versioninfo=('','',''),machine=''): 753 754 """ Get MacOS version information and return it as tuple (release, 755 versioninfo, machine) with versioninfo being a tuple (version, 756 dev_stage, non_release_version). 757 758 Entries which cannot be determined are set to the parameter values 759 which default to ''. All tuple entries are strings. 760 """ 761 762 # First try reading the information from an XML file which should 763 # always be present 764 info = _mac_ver_xml() 765 if info is not None: 766 return info 767 768 # If that doesn't work for some reason fall back to reading the 769 # information using gestalt calls. 770 info = _mac_ver_gestalt() 771 if info is not None: 772 return info 773 774 # If that also doesn't work return the default values 775 return release,versioninfo,machine 776 777def _java_getprop(name,default): 778 779 from java.lang import System 780 try: 781 value = System.getProperty(name) 782 if value is None: 783 return default 784 return value 785 except AttributeError: 786 return default 787 788def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')): 789 790 """ Version interface for Jython. 791 792 Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being 793 a tuple (vm_name,vm_release,vm_vendor) and osinfo being a 794 tuple (os_name,os_version,os_arch). 795 796 Values which cannot be determined are set to the defaults 797 given as parameters (which all default to ''). 798 799 """ 800 # Import the needed APIs 801 try: 802 import java.lang 803 except ImportError: 804 return release,vendor,vminfo,osinfo 805 806 vendor = _java_getprop('java.vendor', vendor) 807 release = _java_getprop('java.version', release) 808 vm_name, vm_release, vm_vendor = vminfo 809 vm_name = _java_getprop('java.vm.name', vm_name) 810 vm_vendor = _java_getprop('java.vm.vendor', vm_vendor) 811 vm_release = _java_getprop('java.vm.version', vm_release) 812 vminfo = vm_name, vm_release, vm_vendor 813 os_name, os_version, os_arch = osinfo 814 os_arch = _java_getprop('java.os.arch', os_arch) 815 os_name = _java_getprop('java.os.name', os_name) 816 os_version = _java_getprop('java.os.version', os_version) 817 osinfo = os_name, os_version, os_arch 818 819 return release, vendor, vminfo, osinfo 820 821### System name aliasing 822 823def system_alias(system,release,version): 824 825 """ Returns (system,release,version) aliased to common 826 marketing names used for some systems. 827 828 It also does some reordering of the information in some cases 829 where it would otherwise cause confusion. 830 831 """ 832 if system == 'Rhapsody': 833 # Apple's BSD derivative 834 # XXX How can we determine the marketing release number ? 835 return 'MacOS X Server',system+release,version 836 837 elif system == 'SunOS': 838 # Sun's OS 839 if release < '5': 840 # These releases use the old name SunOS 841 return system,release,version 842 # Modify release (marketing release = SunOS release - 3) 843 l = string.split(release,'.') 844 if l: 845 try: 846 major = int(l[0]) 847 except ValueError: 848 pass 849 else: 850 major = major - 3 851 l[0] = str(major) 852 release = string.join(l,'.') 853 if release < '6': 854 system = 'Solaris' 855 else: 856 # XXX Whatever the new SunOS marketing name is... 857 system = 'Solaris' 858 859 elif system == 'IRIX64': 860 # IRIX reports IRIX64 on platforms with 64-bit support; yet it 861 # is really a version and not a different platform, since 32-bit 862 # apps are also supported.. 863 system = 'IRIX' 864 if version: 865 version = version + ' (64bit)' 866 else: 867 version = '64bit' 868 869 elif system in ('win32','win16'): 870 # In case one of the other tricks 871 system = 'Windows' 872 873 return system,release,version 874 875### Various internal helpers 876 877def _platform(*args): 878 879 """ Helper to format the platform string in a filename 880 compatible format e.g. "system-version-machine". 881 """ 882 # Format the platform string 883 platform = string.join( 884 map(string.strip, 885 filter(len, args)), 886 '-') 887 888 # Cleanup some possible filename obstacles... 889 replace = string.replace 890 platform = replace(platform,' ','_') 891 platform = replace(platform,'/','-') 892 platform = replace(platform,'\\','-') 893 platform = replace(platform,':','-') 894 platform = replace(platform,';','-') 895 platform = replace(platform,'"','-') 896 platform = replace(platform,'(','-') 897 platform = replace(platform,')','-') 898 899 # No need to report 'unknown' information... 900 platform = replace(platform,'unknown','') 901 902 # Fold '--'s and remove trailing '-' 903 while 1: 904 cleaned = replace(platform,'--','-') 905 if cleaned == platform: 906 break 907 platform = cleaned 908 while platform[-1] == '-': 909 platform = platform[:-1] 910 911 return platform 912 913def _node(default=''): 914 915 """ Helper to determine the node name of this machine. 916 """ 917 try: 918 import socket 919 except ImportError: 920 # No sockets... 921 return default 922 try: 923 return socket.gethostname() 924 except socket.error: 925 # Still not working... 926 return default 927 928# os.path.abspath is new in Python 1.5.2: 929if not hasattr(os.path,'abspath'): 930 931 def _abspath(path, 932 933 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd, 934 normpath=os.path.normpath): 935 936 if not isabs(path): 937 path = join(getcwd(), path) 938 return normpath(path) 939 940else: 941 942 _abspath = os.path.abspath 943 944def _follow_symlinks(filepath): 945 946 """ In case filepath is a symlink, follow it until a 947 real file is reached. 948 """ 949 filepath = _abspath(filepath) 950 while os.path.islink(filepath): 951 filepath = os.path.normpath( 952 os.path.join(os.path.dirname(filepath),os.readlink(filepath))) 953 return filepath 954 955def _syscmd_uname(option,default=''): 956 957 """ Interface to the system's uname command. 958 """ 959 if sys.platform in ('dos','win32','win16','os2'): 960 # XXX Others too ? 961 return default 962 try: 963 f = os.popen('uname %s 2> %s' % (option, DEV_NULL)) 964 except (AttributeError,os.error): 965 return default 966 output = string.strip(f.read()) 967 rc = f.close() 968 if not output or rc: 969 return default 970 else: 971 return output 972 973def _syscmd_file(target,default=''): 974 975 """ Interface to the system's file command. 976 977 The function uses the -b option of the file command to have it 978 ommit the filename in its output and if possible the -L option 979 to have the command follow symlinks. It returns default in 980 case the command should fail. 981 982 """ 983 984 # We do the import here to avoid a bootstrap issue. 985 # See c73b90b6dadd changeset. 986 # 987 # [..] 988 # ranlib libpython2.7.a 989 # gcc -o python \ 990 # Modules/python.o \ 991 # libpython2.7.a -lsocket -lnsl -ldl -lm 992 # Traceback (most recent call last): 993 # File "./setup.py", line 8, in <module> 994 # from platform import machine as platform_machine 995 # File "[..]/build/Lib/platform.py", line 116, in <module> 996 # import sys,string,os,re,subprocess 997 # File "[..]/build/Lib/subprocess.py", line 429, in <module> 998 # import select 999 # ImportError: No module named select 1000 1001 import subprocess 1002 1003 if sys.platform in ('dos','win32','win16','os2'): 1004 # XXX Others too ? 1005 return default 1006 target = _follow_symlinks(target) 1007 try: 1008 proc = subprocess.Popen(['file', target], 1009 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 1010 1011 except (AttributeError,os.error): 1012 return default 1013 output = proc.communicate()[0] 1014 rc = proc.wait() 1015 if not output or rc: 1016 return default 1017 else: 1018 return output 1019 1020### Information about the used architecture 1021 1022# Default values for architecture; non-empty strings override the 1023# defaults given as parameters 1024_default_architecture = { 1025 'win32': ('','WindowsPE'), 1026 'win16': ('','Windows'), 1027 'dos': ('','MSDOS'), 1028} 1029 1030_architecture_split = re.compile(r'[\s,]').split 1031 1032def architecture(executable=sys.executable,bits='',linkage=''): 1033 1034 """ Queries the given executable (defaults to the Python interpreter 1035 binary) for various architecture information. 1036 1037 Returns a tuple (bits,linkage) which contains information about 1038 the bit architecture and the linkage format used for the 1039 executable. Both values are returned as strings. 1040 1041 Values that cannot be determined are returned as given by the 1042 parameter presets. If bits is given as '', the sizeof(pointer) 1043 (or sizeof(long) on Python version < 1.5.2) is used as 1044 indicator for the supported pointer size. 1045 1046 The function relies on the system's "file" command to do the 1047 actual work. This is available on most if not all Unix 1048 platforms. On some non-Unix platforms where the "file" command 1049 does not exist and the executable is set to the Python interpreter 1050 binary defaults from _default_architecture are used. 1051 1052 """ 1053 # Use the sizeof(pointer) as default number of bits if nothing 1054 # else is given as default. 1055 if not bits: 1056 import struct 1057 try: 1058 size = struct.calcsize('P') 1059 except struct.error: 1060 # Older installations can only query longs 1061 size = struct.calcsize('l') 1062 bits = str(size*8) + 'bit' 1063 1064 # Get data from the 'file' system command 1065 if executable: 1066 output = _syscmd_file(executable, '') 1067 else: 1068 output = '' 1069 1070 if not output and \ 1071 executable == sys.executable: 1072 # "file" command did not return anything; we'll try to provide 1073 # some sensible defaults then... 1074 if sys.platform in _default_architecture: 1075 b, l = _default_architecture[sys.platform] 1076 if b: 1077 bits = b 1078 if l: 1079 linkage = l 1080 return bits, linkage 1081 1082 # Split the output into a list of strings omitting the filename 1083 fileout = _architecture_split(output)[1:] 1084 1085 if 'executable' not in fileout: 1086 # Format not supported 1087 return bits,linkage 1088 1089 # Bits 1090 if '32-bit' in fileout: 1091 bits = '32bit' 1092 elif 'N32' in fileout: 1093 # On Irix only 1094 bits = 'n32bit' 1095 elif '64-bit' in fileout: 1096 bits = '64bit' 1097 1098 # Linkage 1099 if 'ELF' in fileout: 1100 linkage = 'ELF' 1101 elif 'PE' in fileout: 1102 # E.g. Windows uses this format 1103 if 'Windows' in fileout: 1104 linkage = 'WindowsPE' 1105 else: 1106 linkage = 'PE' 1107 elif 'COFF' in fileout: 1108 linkage = 'COFF' 1109 elif 'MS-DOS' in fileout: 1110 linkage = 'MSDOS' 1111 else: 1112 # XXX the A.OUT format also falls under this class... 1113 pass 1114 1115 return bits,linkage 1116 1117### Portable uname() interface 1118 1119_uname_cache = None 1120 1121def uname(): 1122 1123 """ Fairly portable uname interface. Returns a tuple 1124 of strings (system,node,release,version,machine,processor) 1125 identifying the underlying platform. 1126 1127 Note that unlike the os.uname function this also returns 1128 possible processor information as an additional tuple entry. 1129 1130 Entries which cannot be determined are set to ''. 1131 1132 """ 1133 global _uname_cache 1134 no_os_uname = 0 1135 1136 if _uname_cache is not None: 1137 return _uname_cache 1138 1139 processor = '' 1140 1141 # Get some infos from the builtin os.uname API... 1142 try: 1143 system,node,release,version,machine = os.uname() 1144 except AttributeError: 1145 no_os_uname = 1 1146 1147 if no_os_uname or not filter(None, (system, node, release, version, machine)): 1148 # Hmm, no there is either no uname or uname has returned 1149 #'unknowns'... we'll have to poke around the system then. 1150 if no_os_uname: 1151 system = sys.platform 1152 release = '' 1153 version = '' 1154 node = _node() 1155 machine = '' 1156 1157 use_syscmd_ver = 1 1158 1159 # Try win32_ver() on win32 platforms 1160 if system == 'win32': 1161 release,version,csd,ptype = win32_ver() 1162 if release and version: 1163 use_syscmd_ver = 0 1164 # Try to use the PROCESSOR_* environment variables 1165 # available on Win XP and later; see 1166 # http://support.microsoft.com/kb/888731 and 1167 # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM 1168 if not machine: 1169 # WOW64 processes mask the native architecture 1170 if "PROCESSOR_ARCHITEW6432" in os.environ: 1171 machine = os.environ.get("PROCESSOR_ARCHITEW6432", '') 1172 else: 1173 machine = os.environ.get('PROCESSOR_ARCHITECTURE', '') 1174 if not processor: 1175 processor = os.environ.get('PROCESSOR_IDENTIFIER', machine) 1176 1177 # Try the 'ver' system command available on some 1178 # platforms 1179 if use_syscmd_ver: 1180 system,release,version = _syscmd_ver(system) 1181 # Normalize system to what win32_ver() normally returns 1182 # (_syscmd_ver() tends to return the vendor name as well) 1183 if system == 'Microsoft Windows': 1184 system = 'Windows' 1185 elif system == 'Microsoft' and release == 'Windows': 1186 # Under Windows Vista and Windows Server 2008, 1187 # Microsoft changed the output of the ver command. The 1188 # release is no longer printed. This causes the 1189 # system and release to be misidentified. 1190 system = 'Windows' 1191 if '6.0' == version[:3]: 1192 release = 'Vista' 1193 else: 1194 release = '' 1195 1196 # In case we still don't know anything useful, we'll try to 1197 # help ourselves 1198 if system in ('win32','win16'): 1199 if not version: 1200 if system == 'win32': 1201 version = '32bit' 1202 else: 1203 version = '16bit' 1204 system = 'Windows' 1205 1206 elif system[:4] == 'java': 1207 release,vendor,vminfo,osinfo = java_ver() 1208 system = 'Java' 1209 version = string.join(vminfo,', ') 1210 if not version: 1211 version = vendor 1212 1213 # System specific extensions 1214 if system == 'OpenVMS': 1215 # OpenVMS seems to have release and version mixed up 1216 if not release or release == '0': 1217 release = version 1218 version = '' 1219 # Get processor information 1220 try: 1221 import vms_lib 1222 except ImportError: 1223 pass 1224 else: 1225 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0) 1226 if (cpu_number >= 128): 1227 processor = 'Alpha' 1228 else: 1229 processor = 'VAX' 1230 if not processor: 1231 # Get processor information from the uname system command 1232 processor = _syscmd_uname('-p','') 1233 1234 #If any unknowns still exist, replace them with ''s, which are more portable 1235 if system == 'unknown': 1236 system = '' 1237 if node == 'unknown': 1238 node = '' 1239 if release == 'unknown': 1240 release = '' 1241 if version == 'unknown': 1242 version = '' 1243 if machine == 'unknown': 1244 machine = '' 1245 if processor == 'unknown': 1246 processor = '' 1247 1248 # normalize name 1249 if system == 'Microsoft' and release == 'Windows': 1250 system = 'Windows' 1251 release = 'Vista' 1252 1253 _uname_cache = system,node,release,version,machine,processor 1254 return _uname_cache 1255 1256### Direct interfaces to some of the uname() return values 1257 1258def system(): 1259 1260 """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'. 1261 1262 An empty string is returned if the value cannot be determined. 1263 1264 """ 1265 return uname()[0] 1266 1267def node(): 1268 1269 """ Returns the computer's network name (which may not be fully 1270 qualified) 1271 1272 An empty string is returned if the value cannot be determined. 1273 1274 """ 1275 return uname()[1] 1276 1277def release(): 1278 1279 """ Returns the system's release, e.g. '2.2.0' or 'NT' 1280 1281 An empty string is returned if the value cannot be determined. 1282 1283 """ 1284 return uname()[2] 1285 1286def version(): 1287 1288 """ Returns the system's release version, e.g. '#3 on degas' 1289 1290 An empty string is returned if the value cannot be determined. 1291 1292 """ 1293 return uname()[3] 1294 1295def machine(): 1296 1297 """ Returns the machine type, e.g. 'i386' 1298 1299 An empty string is returned if the value cannot be determined. 1300 1301 """ 1302 return uname()[4] 1303 1304def processor(): 1305 1306 """ Returns the (true) processor name, e.g. 'amdk6' 1307 1308 An empty string is returned if the value cannot be 1309 determined. Note that many platforms do not provide this 1310 information or simply return the same value as for machine(), 1311 e.g. NetBSD does this. 1312 1313 """ 1314 return uname()[5] 1315 1316### Various APIs for extracting information from sys.version 1317 1318_sys_version_parser = re.compile( 1319 r'([\w.+]+)\s*' # "version<space>" 1320 r'\(#?([^,]+)' # "(#buildno" 1321 r'(?:,\s*([\w ]*)' # ", builddate" 1322 r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)<space>" 1323 r'\[([^\]]+)\]?') # "[compiler]" 1324 1325_ironpython_sys_version_parser = re.compile( 1326 r'IronPython\s*' 1327 '([\d\.]+)' 1328 '(?: \(([\d\.]+)\))?' 1329 ' on (.NET [\d\.]+)') 1330 1331# IronPython covering 2.6 and 2.7 1332_ironpython26_sys_version_parser = re.compile( 1333 r'([\d.]+)\s*' 1334 '\(IronPython\s*' 1335 '[\d.]+\s*' 1336 '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)' 1337) 1338 1339_pypy_sys_version_parser = re.compile( 1340 r'([\w.+]+)\s*' 1341 '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*' 1342 '\[PyPy [^\]]+\]?') 1343 1344_sys_version_cache = {} 1345 1346def _sys_version(sys_version=None): 1347 1348 """ Returns a parsed version of Python's sys.version as tuple 1349 (name, version, branch, revision, buildno, builddate, compiler) 1350 referring to the Python implementation name, version, branch, 1351 revision, build number, build date/time as string and the compiler 1352 identification string. 1353 1354 Note that unlike the Python sys.version, the returned value 1355 for the Python version will always include the patchlevel (it 1356 defaults to '.0'). 1357 1358 The function returns empty strings for tuple entries that 1359 cannot be determined. 1360 1361 sys_version may be given to parse an alternative version 1362 string, e.g. if the version was read from a different Python 1363 interpreter. 1364 1365 """ 1366 # Get the Python version 1367 if sys_version is None: 1368 sys_version = sys.version 1369 1370 # Try the cache first 1371 result = _sys_version_cache.get(sys_version, None) 1372 if result is not None: 1373 return result 1374 1375 # Parse it 1376 if 'IronPython' in sys_version: 1377 # IronPython 1378 name = 'IronPython' 1379 if sys_version.startswith('IronPython'): 1380 match = _ironpython_sys_version_parser.match(sys_version) 1381 else: 1382 match = _ironpython26_sys_version_parser.match(sys_version) 1383 1384 if match is None: 1385 raise ValueError( 1386 'failed to parse IronPython sys.version: %s' % 1387 repr(sys_version)) 1388 1389 version, alt_version, compiler = match.groups() 1390 buildno = '' 1391 builddate = '' 1392 1393 elif sys.platform.startswith('java'): 1394 # Jython 1395 name = 'Jython' 1396 match = _sys_version_parser.match(sys_version) 1397 if match is None: 1398 raise ValueError( 1399 'failed to parse Jython sys.version: %s' % 1400 repr(sys_version)) 1401 version, buildno, builddate, buildtime, _ = match.groups() 1402 if builddate is None: 1403 builddate = '' 1404 compiler = sys.platform 1405 1406 elif "PyPy" in sys_version: 1407 # PyPy 1408 name = "PyPy" 1409 match = _pypy_sys_version_parser.match(sys_version) 1410 if match is None: 1411 raise ValueError("failed to parse PyPy sys.version: %s" % 1412 repr(sys_version)) 1413 version, buildno, builddate, buildtime = match.groups() 1414 compiler = "" 1415 1416 else: 1417 # CPython 1418 match = _sys_version_parser.match(sys_version) 1419 if match is None: 1420 raise ValueError( 1421 'failed to parse CPython sys.version: %s' % 1422 repr(sys_version)) 1423 version, buildno, builddate, buildtime, compiler = \ 1424 match.groups() 1425 name = 'CPython' 1426 if builddate is None: 1427 builddate = '' 1428 elif buildtime: 1429 builddate = builddate + ' ' + buildtime 1430 1431 if hasattr(sys, 'subversion'): 1432 # sys.subversion was added in Python 2.5 1433 _, branch, revision = sys.subversion 1434 else: 1435 branch = '' 1436 revision = '' 1437 1438 # Add the patchlevel version if missing 1439 l = string.split(version, '.') 1440 if len(l) == 2: 1441 l.append('0') 1442 version = string.join(l, '.') 1443 1444 # Build and cache the result 1445 result = (name, version, branch, revision, buildno, builddate, compiler) 1446 _sys_version_cache[sys_version] = result 1447 return result 1448 1449def python_implementation(): 1450 1451 """ Returns a string identifying the Python implementation. 1452 1453 Currently, the following implementations are identified: 1454 'CPython' (C implementation of Python), 1455 'IronPython' (.NET implementation of Python), 1456 'Jython' (Java implementation of Python), 1457 'PyPy' (Python implementation of Python). 1458 1459 """ 1460 return _sys_version()[0] 1461 1462def python_version(): 1463 1464 """ Returns the Python version as string 'major.minor.patchlevel' 1465 1466 Note that unlike the Python sys.version, the returned value 1467 will always include the patchlevel (it defaults to 0). 1468 1469 """ 1470 return _sys_version()[1] 1471 1472def python_version_tuple(): 1473 1474 """ Returns the Python version as tuple (major, minor, patchlevel) 1475 of strings. 1476 1477 Note that unlike the Python sys.version, the returned value 1478 will always include the patchlevel (it defaults to 0). 1479 1480 """ 1481 return tuple(string.split(_sys_version()[1], '.')) 1482 1483def python_branch(): 1484 1485 """ Returns a string identifying the Python implementation 1486 branch. 1487 1488 For CPython this is the Subversion branch from which the 1489 Python binary was built. 1490 1491 If not available, an empty string is returned. 1492 1493 """ 1494 1495 return _sys_version()[2] 1496 1497def python_revision(): 1498 1499 """ Returns a string identifying the Python implementation 1500 revision. 1501 1502 For CPython this is the Subversion revision from which the 1503 Python binary was built. 1504 1505 If not available, an empty string is returned. 1506 1507 """ 1508 return _sys_version()[3] 1509 1510def python_build(): 1511 1512 """ Returns a tuple (buildno, builddate) stating the Python 1513 build number and date as strings. 1514 1515 """ 1516 return _sys_version()[4:6] 1517 1518def python_compiler(): 1519 1520 """ Returns a string identifying the compiler used for compiling 1521 Python. 1522 1523 """ 1524 return _sys_version()[6] 1525 1526### The Opus Magnum of platform strings :-) 1527 1528_platform_cache = {} 1529 1530def platform(aliased=0, terse=0): 1531 1532 """ Returns a single string identifying the underlying platform 1533 with as much useful information as possible (but no more :). 1534 1535 The output is intended to be human readable rather than 1536 machine parseable. It may look different on different 1537 platforms and this is intended. 1538 1539 If "aliased" is true, the function will use aliases for 1540 various platforms that report system names which differ from 1541 their common names, e.g. SunOS will be reported as 1542 Solaris. The system_alias() function is used to implement 1543 this. 1544 1545 Setting terse to true causes the function to return only the 1546 absolute minimum information needed to identify the platform. 1547 1548 """ 1549 result = _platform_cache.get((aliased, terse), None) 1550 if result is not None: 1551 return result 1552 1553 # Get uname information and then apply platform specific cosmetics 1554 # to it... 1555 system,node,release,version,machine,processor = uname() 1556 if machine == processor: 1557 processor = '' 1558 if aliased: 1559 system,release,version = system_alias(system,release,version) 1560 1561 if system == 'Windows': 1562 # MS platforms 1563 rel,vers,csd,ptype = win32_ver(version) 1564 if terse: 1565 platform = _platform(system,release) 1566 else: 1567 platform = _platform(system,release,version,csd) 1568 1569 elif system in ('Linux',): 1570 # Linux based systems 1571 distname,distversion,distid = dist('') 1572 if distname and not terse: 1573 platform = _platform(system,release,machine,processor, 1574 'with', 1575 distname,distversion,distid) 1576 else: 1577 # If the distribution name is unknown check for libc vs. glibc 1578 libcname,libcversion = libc_ver(sys.executable) 1579 platform = _platform(system,release,machine,processor, 1580 'with', 1581 libcname+libcversion) 1582 elif system == 'Java': 1583 # Java platforms 1584 r,v,vminfo,(os_name,os_version,os_arch) = java_ver() 1585 if terse or not os_name: 1586 platform = _platform(system,release,version) 1587 else: 1588 platform = _platform(system,release,version, 1589 'on', 1590 os_name,os_version,os_arch) 1591 1592 elif system == 'MacOS': 1593 # MacOS platforms 1594 if terse: 1595 platform = _platform(system,release) 1596 else: 1597 platform = _platform(system,release,machine) 1598 1599 else: 1600 # Generic handler 1601 if terse: 1602 platform = _platform(system,release) 1603 else: 1604 bits,linkage = architecture(sys.executable) 1605 platform = _platform(system,release,machine,processor,bits,linkage) 1606 1607 _platform_cache[(aliased, terse)] = platform 1608 return platform 1609 1610### Command line interface 1611 1612if __name__ == '__main__': 1613 # Default is to print the aliased verbose platform string 1614 terse = ('terse' in sys.argv or '--terse' in sys.argv) 1615 aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv) 1616 print platform(aliased,terse) 1617 sys.exit(0) 1618