PageRenderTime 147ms CodeModel.GetById 82ms app.highlight 54ms RepoModel.GetById 1ms app.codeStats 1ms

/lib-python/2.7/platform.py

https://bitbucket.org/evelyn559/pypy
Python | 1614 lines | 1518 code | 4 blank | 92 comment | 3 complexity | 3dbecc8f6039b119610e67ac342434f5 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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 > 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 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            else:
 677                release = 'post2008Server'
 678
 679    else:
 680        if not release:
 681            # E.g. Win3.1 with win32s
 682            release = '%i.%i' % (maj,min)
 683        return release,version,csd,ptype
 684
 685    # Open the registry key
 686    try:
 687        keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
 688        # Get a value to make sure the key exists...
 689        RegQueryValueEx(keyCurVer, 'SystemRoot')
 690    except:
 691        return release,version,csd,ptype
 692
 693    # Parse values
 694    #subversion = _win32_getvalue(keyCurVer,
 695    #                            'SubVersionNumber',
 696    #                            ('',1))[0]
 697    #if subversion:
 698    #   release = release + subversion # 95a, 95b, etc.
 699    build = _win32_getvalue(keyCurVer,
 700                            'CurrentBuildNumber',
 701                            ('',1))[0]
 702    ptype = _win32_getvalue(keyCurVer,
 703                           'CurrentType',
 704                           (ptype,1))[0]
 705
 706    # Normalize version
 707    version = _norm_version(version,build)
 708
 709    # Close key
 710    RegCloseKey(keyCurVer)
 711    return release,version,csd,ptype
 712
 713def _mac_ver_lookup(selectors,default=None):
 714
 715    from gestalt import gestalt
 716    import MacOS
 717    l = []
 718    append = l.append
 719    for selector in selectors:
 720        try:
 721            append(gestalt(selector))
 722        except (RuntimeError, MacOS.Error):
 723            append(default)
 724    return l
 725
 726def _bcd2str(bcd):
 727
 728    return hex(bcd)[2:]
 729
 730def _mac_ver_gestalt():
 731    """
 732        Thanks to Mark R. Levinson for mailing documentation links and
 733        code examples for this function. Documentation for the
 734        gestalt() API is available online at:
 735
 736           http://www.rgaros.nl/gestalt/
 737    """
 738    # Check whether the version info module is available
 739    try:
 740        import gestalt
 741        import MacOS
 742    except ImportError:
 743        return None
 744    # Get the infos
 745    sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
 746    # Decode the infos
 747    if sysv:
 748        major = (sysv & 0xFF00) >> 8
 749        minor = (sysv & 0x00F0) >> 4
 750        patch = (sysv & 0x000F)
 751
 752        if (major, minor) >= (10, 4):
 753            # the 'sysv' gestald cannot return patchlevels
 754            # higher than 9. Apple introduced 3 new
 755            # gestalt codes in 10.4 to deal with this
 756            # issue (needed because patch levels can
 757            # run higher than 9, such as 10.4.11)
 758            major,minor,patch = _mac_ver_lookup(('sys1','sys2','sys3'))
 759            release = '%i.%i.%i' %(major, minor, patch)
 760        else:
 761            release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
 762
 763    if sysa:
 764        machine = {0x1: '68k',
 765                   0x2: 'PowerPC',
 766                   0xa: 'i386'}.get(sysa,'')
 767
 768    return release,versioninfo,machine
 769
 770def _mac_ver_xml():
 771    fn = '/System/Library/CoreServices/SystemVersion.plist'
 772    if not os.path.exists(fn):
 773        return None
 774
 775    try:
 776        import plistlib
 777    except ImportError:
 778        return None
 779
 780    pl = plistlib.readPlist(fn)
 781    release = pl['ProductVersion']
 782    versioninfo=('', '', '')
 783    machine = os.uname()[4]
 784    if machine in ('ppc', 'Power Macintosh'):
 785        # for compatibility with the gestalt based code
 786        machine = 'PowerPC'
 787
 788    return release,versioninfo,machine
 789
 790
 791def mac_ver(release='',versioninfo=('','',''),machine=''):
 792
 793    """ Get MacOS version information and return it as tuple (release,
 794        versioninfo, machine) with versioninfo being a tuple (version,
 795        dev_stage, non_release_version).
 796
 797        Entries which cannot be determined are set to the paramter values
 798        which default to ''. All tuple entries are strings.
 799    """
 800
 801    # First try reading the information from an XML file which should
 802    # always be present
 803    info = _mac_ver_xml()
 804    if info is not None:
 805        return info
 806
 807    # If that doesn't work for some reason fall back to reading the
 808    # information using gestalt calls.
 809    info = _mac_ver_gestalt()
 810    if info is not None:
 811        return info
 812
 813    # If that also doesn't work return the default values
 814    return release,versioninfo,machine
 815
 816def _java_getprop(name,default):
 817
 818    from java.lang import System
 819    try:
 820        value = System.getProperty(name)
 821        if value is None:
 822            return default
 823        return value
 824    except AttributeError:
 825        return default
 826
 827def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
 828
 829    """ Version interface for Jython.
 830
 831        Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
 832        a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
 833        tuple (os_name,os_version,os_arch).
 834
 835        Values which cannot be determined are set to the defaults
 836        given as parameters (which all default to '').
 837
 838    """
 839    # Import the needed APIs
 840    try:
 841        import java.lang
 842    except ImportError:
 843        return release,vendor,vminfo,osinfo
 844
 845    vendor = _java_getprop('java.vendor', vendor)
 846    release = _java_getprop('java.version', release)
 847    vm_name, vm_release, vm_vendor = vminfo
 848    vm_name = _java_getprop('java.vm.name', vm_name)
 849    vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
 850    vm_release = _java_getprop('java.vm.version', vm_release)
 851    vminfo = vm_name, vm_release, vm_vendor
 852    os_name, os_version, os_arch = osinfo
 853    os_arch = _java_getprop('java.os.arch', os_arch)
 854    os_name = _java_getprop('java.os.name', os_name)
 855    os_version = _java_getprop('java.os.version', os_version)
 856    osinfo = os_name, os_version, os_arch
 857
 858    return release, vendor, vminfo, osinfo
 859
 860### System name aliasing
 861
 862def system_alias(system,release,version):
 863
 864    """ Returns (system,release,version) aliased to common
 865        marketing names used for some systems.
 866
 867        It also does some reordering of the information in some cases
 868        where it would otherwise cause confusion.
 869
 870    """
 871    if system == 'Rhapsody':
 872        # Apple's BSD derivative
 873        # XXX How can we determine the marketing release number ?
 874        return 'MacOS X Server',system+release,version
 875
 876    elif system == 'SunOS':
 877        # Sun's OS
 878        if release < '5':
 879            # These releases use the old name SunOS
 880            return system,release,version
 881        # Modify release (marketing release = SunOS release - 3)
 882        l = string.split(release,'.')
 883        if l:
 884            try:
 885                major = int(l[0])
 886            except ValueError:
 887                pass
 888            else:
 889                major = major - 3
 890                l[0] = str(major)
 891                release = string.join(l,'.')
 892        if release < '6':
 893            system = 'Solaris'
 894        else:
 895            # XXX Whatever the new SunOS marketing name is...
 896            system = 'Solaris'
 897
 898    elif system == 'IRIX64':
 899        # IRIX reports IRIX64 on platforms with 64-bit support; yet it
 900        # is really a version and not a different platform, since 32-bit
 901        # apps are also supported..
 902        system = 'IRIX'
 903        if version:
 904            version = version + ' (64bit)'
 905        else:
 906            version = '64bit'
 907
 908    elif system in ('win32','win16'):
 909        # In case one of the other tricks
 910        system = 'Windows'
 911
 912    return system,release,version
 913
 914### Various internal helpers
 915
 916def _platform(*args):
 917
 918    """ Helper to format the platform string in a filename
 919        compatible format e.g. "system-version-machine".
 920    """
 921    # Format the platform string
 922    platform = string.join(
 923        map(string.strip,
 924            filter(len, args)),
 925        '-')
 926
 927    # Cleanup some possible filename obstacles...
 928    replace = string.replace
 929    platform = replace(platform,' ','_')
 930    platform = replace(platform,'/','-')
 931    platform = replace(platform,'\\','-')
 932    platform = replace(platform,':','-')
 933    platform = replace(platform,';','-')
 934    platform = replace(platform,'"','-')
 935    platform = replace(platform,'(','-')
 936    platform = replace(platform,')','-')
 937
 938    # No need to report 'unknown' information...
 939    platform = replace(platform,'unknown','')
 940
 941    # Fold '--'s and remove trailing '-'
 942    while 1:
 943        cleaned = replace(platform,'--','-')
 944        if cleaned == platform:
 945            break
 946        platform = cleaned
 947    while platform[-1] == '-':
 948        platform = platform[:-1]
 949
 950    return platform
 951
 952def _node(default=''):
 953
 954    """ Helper to determine the node name of this machine.
 955    """
 956    try:
 957        import socket
 958    except ImportError:
 959        # No sockets...
 960        return default
 961    try:
 962        return socket.gethostname()
 963    except socket.error:
 964        # Still not working...
 965        return default
 966
 967# os.path.abspath is new in Python 1.5.2:
 968if not hasattr(os.path,'abspath'):
 969
 970    def _abspath(path,
 971
 972                 isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
 973                 normpath=os.path.normpath):
 974
 975        if not isabs(path):
 976            path = join(getcwd(), path)
 977        return normpath(path)
 978
 979else:
 980
 981    _abspath = os.path.abspath
 982
 983def _follow_symlinks(filepath):
 984
 985    """ In case filepath is a symlink, follow it until a
 986        real file is reached.
 987    """
 988    filepath = _abspath(filepath)
 989    while os.path.islink(filepath):
 990        filepath = os.path.normpath(
 991            os.path.join(os.path.dirname(filepath),os.readlink(filepath)))
 992    return filepath
 993
 994def _syscmd_uname(option,default=''):
 995
 996    """ Interface to the system's uname command.
 997    """
 998    if sys.platform in ('dos','win32','win16','os2'):
 999        # XXX Others too ?
1000        return default
1001    try:
1002        f = os.popen('uname %s 2> %s' % (option, DEV_NULL))
1003    except (AttributeError,os.error):
1004        return default
1005    output = string.strip(f.read())
1006    rc = f.close()
1007    if not output or rc:
1008        return default
1009    else:
1010        return output
1011
1012def _syscmd_file(target,default=''):
1013
1014    """ Interface to the system's file command.
1015
1016        The function uses the -b option of the file command to have it
1017        ommit the filename in its output and if possible the -L option
1018        to have the command follow symlinks. It returns default in
1019        case the command should fail.
1020
1021    """
1022    if sys.platform in ('dos','win32','win16','os2'):
1023        # XXX Others too ?
1024        return default
1025    target = _follow_symlinks(target).replace('"', '\\"')
1026    try:
1027        f = os.popen('file "%s" 2> %s' % (target, DEV_NULL))
1028    except (AttributeError,os.error):
1029        return default
1030    output = string.strip(f.read())
1031    rc = f.close()
1032    if not output or rc:
1033        return default
1034    else:
1035        return output
1036
1037### Information about the used architecture
1038
1039# Default values for architecture; non-empty strings override the
1040# defaults given as parameters
1041_default_architecture = {
1042    'win32': ('','WindowsPE'),
1043    'win16': ('','Windows'),
1044    'dos': ('','MSDOS'),
1045}
1046
1047_architecture_split = re.compile(r'[\s,]').split
1048
1049def architecture(executable=sys.executable,bits='',linkage=''):
1050
1051    """ Queries the given executable (defaults to the Python interpreter
1052        binary) for various architecture information.
1053
1054        Returns a tuple (bits,linkage) which contains information about
1055        the bit architecture and the linkage format used for the
1056        executable. Both values are returned as strings.
1057
1058        Values that cannot be determined are returned as given by the
1059        parameter presets. If bits is given as '', the sizeof(pointer)
1060        (or sizeof(long) on Python version < 1.5.2) is used as
1061        indicator for the supported pointer size.
1062
1063        The function relies on the system's "file" command to do the
1064        actual work. This is available on most if not all Unix
1065        platforms. On some non-Unix platforms where the "file" command
1066        does not exist and the executable is set to the Python interpreter
1067        binary defaults from _default_architecture are used.
1068
1069    """
1070    # Use the sizeof(pointer) as default number of bits if nothing
1071    # else is given as default.
1072    if not bits:
1073        import struct
1074        try:
1075            size = struct.calcsize('P')
1076        except struct.error:
1077            # Older installations can only query longs
1078            size = struct.calcsize('l')
1079        bits = str(size*8) + 'bit'
1080
1081    # Get data from the 'file' system command
1082    if executable:
1083        output = _syscmd_file(executable, '')
1084    else:
1085        output = ''
1086
1087    if not output and \
1088       executable == sys.executable:
1089        # "file" command did not return anything; we'll try to provide
1090        # some sensible defaults then...
1091        if sys.platform in _default_architecture:
1092            b, l = _default_architecture[sys.platform]
1093            if b:
1094                bits = b
1095            if l:
1096                linkage = l
1097        return bits, linkage
1098
1099    # Split the output into a list of strings omitting the filename
1100    fileout = _architecture_split(output)[1:]
1101
1102    if 'executable' not in fileout:
1103        # Format not supported
1104        return bits,linkage
1105
1106    # Bits
1107    if '32-bit' in fileout:
1108        bits = '32bit'
1109    elif 'N32' in fileout:
1110        # On Irix only
1111        bits = 'n32bit'
1112    elif '64-bit' in fileout:
1113        bits = '64bit'
1114
1115    # Linkage
1116    if 'ELF' in fileout:
1117        linkage = 'ELF'
1118    elif 'PE' in fileout:
1119        # E.g. Windows uses this format
1120        if 'Windows' in fileout:
1121            linkage = 'WindowsPE'
1122        else:
1123            linkage = 'PE'
1124    elif 'COFF' in fileout:
1125        linkage = 'COFF'
1126    elif 'MS-DOS' in fileout:
1127        linkage = 'MSDOS'
1128    else:
1129        # XXX the A.OUT format also falls under this class...
1130        pass
1131
1132    return bits,linkage
1133
1134### Portable uname() interface
1135
1136_uname_cache = None
1137
1138def uname():
1139
1140    """ Fairly portable uname interface. Returns a tuple
1141        of strings (system,node,release,version,machine,processor)
1142        identifying the underlying platform.
1143
1144        Note that unlike the os.uname function this also returns
1145        possible processor information as an additional tuple entry.
1146
1147        Entries which cannot be determined are set to ''.
1148
1149    """
1150    global _uname_cache
1151    no_os_uname = 0
1152
1153    if _uname_cache is not None:
1154        return _uname_cache
1155
1156    processor = ''
1157
1158    # Get some infos from the builtin os.uname API...
1159    try:
1160        system,node,release,version,machine = os.uname()
1161    except AttributeError:
1162        no_os_uname = 1
1163
1164    if no_os_uname or not filter(None, (system, node, release, version, machine)):
1165        # Hmm, no there is either no uname or uname has returned
1166        #'unknowns'... we'll have to poke around the system then.
1167        if no_os_uname:
1168            system = sys.platform
1169            release = ''
1170            version = ''
1171            node = _node()
1172            machine = ''
1173
1174        use_syscmd_ver = 1
1175
1176        # Try win32_ver() on win32 platforms
1177        if system == 'win32':
1178            release,version,csd,ptype = win32_ver()
1179            if release and version:
1180                use_syscmd_ver = 0
1181            # Try to use the PROCESSOR_* environment variables
1182            # available on Win XP and later; see
1183            # http://support.microsoft.com/kb/888731 and
1184            # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
1185            if not machine:
1186                # WOW64 processes mask the native architecture
1187                if "PROCESSOR_ARCHITEW6432" in os.environ:
1188                    machine = os.environ.get("PROCESSOR_ARCHITEW6432", '')
1189                else:
1190                    machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
1191            if not processor:
1192                processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
1193
1194        # Try the 'ver' system command available on some
1195        # platforms
1196        if use_syscmd_ver:
1197            system,release,version = _syscmd_ver(system)
1198            # Normalize system to what win32_ver() normally returns
1199            # (_syscmd_ver() tends to return the vendor name as well)
1200            if system == 'Microsoft Windows':
1201                system = 'Windows'
1202            elif system == 'Microsoft' and release == 'Windows':
1203                # Under Windows Vista and Windows Server 2008,
1204                # Microsoft changed the output of the ver command. The
1205                # release is no longer printed.  This causes the
1206                # system and release to be misidentified.
1207                system = 'Windows'
1208                if '6.0' == version[:3]:
1209                    release = 'Vista'
1210                else:
1211                    release = ''
1212
1213        # In case we still don't know anything useful, we'll try to
1214        # help ourselves
1215        if system in ('win32','win16'):
1216            if not version:
1217                if system == 'win32':
1218                    version = '32bit'
1219                else:
1220                    version = '16bit'
1221            system = 'Windows'
1222
1223        elif system[:4] == 'java':
1224            release,vendor,vminfo,osinfo = java_ver()
1225            system = 'Java'
1226            version = string.join(vminfo,', ')
1227            if not version:
1228                version = vendor
1229
1230    # System specific extensions
1231    if system == 'OpenVMS':
1232        # OpenVMS seems to have release and version mixed up
1233        if not release or release == '0':
1234            release = version
1235            version = ''
1236        # Get processor information
1237        try:
1238            import vms_lib
1239        except ImportError:
1240            pass
1241        else:
1242            csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1243            if (cpu_number >= 128):
1244                processor = 'Alpha'
1245            else:
1246                processor = 'VAX'
1247    if not processor:
1248        # Get processor information from the uname system command
1249        processor = _syscmd_uname('-p','')
1250
1251    #If any unknowns still exist, replace them with ''s, which are more portable
1252    if system == 'unknown':
1253        system = ''
1254    if node == 'unknown':
1255        node = ''
1256    if release == 'unknown':
1257        release = ''
1258    if version == 'unknown':
1259        version = ''
1260    if machine == 'unknown':
1261        machine = ''
1262    if processor == 'unknown':
1263        processor = ''
1264
1265    #  normalize name
1266    if system == 'Microsoft' and release == 'Windows':
1267        system = 'Windows'
1268        release = 'Vista'
1269
1270    _uname_cache = system,node,release,version,machine,processor
1271    return _uname_cache
1272
1273### Direct interfaces to some of the uname() return values
1274
1275def system():
1276
1277    """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1278
1279        An empty string is returned if the value cannot be determined.
1280
1281    """
1282    return uname()[0]
1283
1284def node():
1285
1286    """ Returns the computer's network name (which may not be fully
1287        qualified)
1288
1289        An empty string is returned if the value cannot be determined.
1290
1291    """
1292    return uname()[1]
1293
1294def release():
1295
1296    """ Returns the system's release, e.g. '2.2.0' or 'NT'
1297
1298        An empty string is returned if the value cannot be determined.
1299
1300    """
1301    return uname()[2]
1302
1303def version():
1304
1305    """ Returns the system's release version, e.g. '#3 on degas'
1306
1307        An empty string is returned if the value cannot be determined.
1308
1309    """
1310    return uname()[3]
1311
1312def machine():
1313
1314    """ Returns the machine type, e.g. 'i386'
1315
1316        An empty string is returned if the value cannot be determined.
1317
1318    """
1319    return uname()[4]
1320
1321def processor():
1322
1323    """ Returns the (true) processor name, e.g. 'amdk6'
1324
1325        An empty string is returned if the value cannot be
1326        determined. Note that many platforms do not provide this
1327        information or simply return the same value as for machine(),
1328        e.g.  NetBSD does this.
1329
1330    """
1331    return uname()[5]
1332
1333### Various APIs for extracting information from sys.version
1334
1335_sys_version_parser = re.compile(
1336    r'([\w.+]+)\s*'
1337    '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1338    '\[([^\]]+)\]?')
1339
1340_ironpython_sys_version_parser = re.compile(
1341    r'IronPython\s*'
1342    '([\d\.]+)'
1343    '(?: \(([\d\.]+)\))?'
1344    ' on (.NET [\d\.]+)')
1345
1346_pypy_sys_version_parser = re.compile(
1347    r'([\w.+]+)\s*'
1348    '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1349    '\[PyPy [^\]]+\]?')
1350
1351_sys_version_cache = {}
1352
1353def _sys_version(sys_version=None):
1354
1355    """ Returns a parsed version of Python's sys.version as tuple
1356        (name, version, branch, revision, buildno, builddate, compiler)
1357        referring to the Python implementation name, version, branch,
1358        revision, build number, build date/time as string and the compiler
1359        identification string.
1360
1361        Note that unlike the Python sys.version, the returned value
1362        for the Python version will always include the patchlevel (it
1363        defaults to '.0').
1364
1365        The function returns empty strings for tuple entries that
1366        cannot be determined.
1367
1368        sys_version may be given to parse an alternative version
1369        string, e.g. if the version was read from a different Python
1370        interpreter.
1371
1372    """
1373    # Get the Python version
1374    if sys_version is None:
1375        sys_version = sys.version
1376
1377    # Try the cache first
1378    result = _sys_version_cache.get(sys_version, None)
1379    if result is not None:
1380        return result
1381
1382    # Parse it
1383    if sys_version[:10] == 'IronPython':
1384        # IronPython
1385        name = 'IronPython'
1386        match = _ironpython_sys_version_parser.match(sys_version)
1387        if match is None:
1388            raise ValueError(
1389                'failed to parse IronPython sys.version: %s' %
1390                repr(sys_version))
1391        version, alt_version, compiler = match.groups()
1392        buildno = ''
1393        builddate = ''
1394
1395    elif sys.platform[:4] == 'java':
1396        # Jython
1397        name = 'Jython'
1398        match = _sys_version_parser.match(sys_version)
1399        if match is None:
1400            raise ValueError(
1401                'failed to parse Jython sys.version: %s' %
1402                repr(sys_version))
1403        version, buildno, builddate, buildtime, _ = match.groups()
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        builddate = builddate + ' ' + buildtime
1427
1428    if hasattr(sys, 'subversion'):
1429        # sys.subversion was added in Python 2.5
1430        _, branch, revision = sys.subversion
1431    else:
1432        branch = ''
1433        revision = ''
1434
1435    # Add the patchlevel version if missing
1436    l = string.split(version, '.')
1437    if len(l) == 2:
1438        l.append('0')
1439        version = string.join(l, '.')
1440
1441    # Build and cache the result
1442    result = (name, version, branch, revision, buildno, builddate, compiler)
1443    _sys_version_cache[sys_version] = result
1444    return result
1445
1446def python_implementation():
1447
1448    """ Returns a string identifying the Python implementation.
1449
1450        Currently, the following implementations are identified:
1451          'CPython' (C implementation of Python),
1452          'IronPython' (.NET implementation of Python),
1453          'Jython' (Java implementation of Python),
1454          'PyPy' (Python implementation of Python).
1455
1456    """
1457    return _sys_version()[0]
1458
1459def python_version():
1460
1461    """ Returns the Python version as string 'major.minor.patchlevel'
1462
1463        Note that unlike the Python sys.version, the returned value
1464        will always include the patchlevel (it defaults to 0).
1465
1466    """
1467    return _sys_version()[1]
1468
1469def python_version_tuple():
1470
1471    """ Returns the Python version as tuple (major, minor, patchlevel)
1472        of strings.
1473
1474        Note that unlike the Python sys.version, the returned value
1475        will always include the patchlevel (it defaults to 0).
1476
1477    """
1478    return tuple(string.split(_sys_version()[1], '.'))
1479
1480def python_branch():
1481
1482    """ Returns a string identifying the Python implementation
1483        branch.
1484
1485        For CPython this is the Subversion branch from which the
1486        Python binary was built.
1487
1488        If not available, an empty string is returned.
1489
1490    """
1491
1492    return _sys_version()[2]
1493
1494def python_revision():
1495
1496    """ Returns a string identifying the Python implementation
1497        revision.
1498
1499        For CPython this is the Subversion revision from which the
1500        Python binary was built.
1501
1502        If not available, an empty string is returned.
1503
1504    """
1505    return _sys_version()[3]
1506
1507def python_build():
1508
1509    """ Returns a tuple (buildno, builddate) stating the Python
1510        build number and date as strings.
1511
1512    """
1513    return _sys_version()[4:6]
1514
1515def python_compiler():
1516
1517    """ Returns a string identifying the compiler used for compiling
1518        Python.
1519
1520    """
1521    return _sys_version()[6]
1522
1523### The Opus Magnum of platform strings :-)
1524
1525_platform_cache = {}
1526
1527def platform(aliased=0, terse=0):
1528
1529    """ Returns a single string identifying the underlying platform
1530        with as much useful information as possible (but no more :).
1531
1532        The output is intended to be human readable rather than
1533        machine parseable. It may look different on different
1534        platforms and this is intended.
1535
1536        If "aliased" is true, the function will use aliases for
1537        various platforms that report system names which differ from
1538        their common names, e.g. SunOS will be reported as
1539        Solaris. The system_alias() function is used to implement
1540        this.
1541
1542        Setting terse to true causes the function to return only the
1543        absolute minimum information needed to identify the platform.
1544
1545    """
1546    result = _platform_cache.get((aliased, terse), None)
1547    if result is not None:
1548        return result
1549
1550    # Get uname information and then apply platform specific cosmetics…

Large files files are truncated, but you can click here to view the full file