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