SF.net SVN: jython:[7262] trunk/jython/Lib/platform.py

[email protected] Wed, 23 Mar 2011 05:03:29 +0000
Newsgroups gmane.comp.lang.jython.cvs
Message-ID <[email protected]>
Revision: 7262
          http://jython.svn.sourceforge.net/jython/?rev=7262&view=rev
Author:   fwierzbicki
Date:     2011-03-23 05:03:29 +0000 (Wed, 23 Mar 2011)

Log Message:
-----------
Update to 2.6 platform.py.

Modified Paths:
--------------
    trunk/jython/Lib/platform.py

Modified: trunk/jython/Lib/platform.py
===================================================================
--- trunk/jython/Lib/platform.py	2011-03-22 02:38:16 UTC (rev 7261)
+++ trunk/jython/Lib/platform.py	2011-03-23 05:03:29 UTC (rev 7262)
@@ -10,7 +10,7 @@
 """
 #    This module is maintained by Marc-Andre Lemburg <[email protected]>.
 #    If you find problems, please submit bug reports/patches via the
-#    Python SourceForge Project Page and assign them to "lemburg".
+#    Python bug tracker (http://bugs.python.org) and assign them to "lemburg".
 #
 #    Note: Please keep this module compatible to Python 1.5.2.
 #
@@ -28,12 +28,15 @@
 #      Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
 #      Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
 #      Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
-#      Colin Kong, Trent Mick, Guido van Rossum
+#      Colin Kong, Trent Mick, Guido van Rossum, Anthony Baxter
 #
 #    History:
 #
 #    <see CVS and SVN checkin messages for history>
 #
+#    1.0.6 - added linux_distribution()
+#    1.0.5 - fixed Java support to allow running the module on Jython
+#    1.0.4 - added IronPython support
 #    1.0.3 - added normalization of Windows system name
 #    1.0.2 - added more Windows support
 #    1.0.1 - reformatted to make doc.py happy
@@ -88,7 +91,7 @@
 
 __copyright__ = """
     Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:[email protected]
-    Copyright (c) 2000-2003, eGenix.com Software GmbH; mailto:[email protected]
+    Copyright (c) 2000-2010, eGenix.com Software GmbH; mailto:[email protected]
 
     Permission to use, copy, modify, and distribute this software and its
     documentation for any purpose and without fee or royalty is hereby granted,
@@ -107,7 +110,7 @@
 
 """
 
-__version__ = '1.0.4'
+__version__ = '1.0.6'
 
 import sys,string,os,re
 
@@ -136,6 +139,11 @@
         The file is read and scanned in chunks of chunksize bytes.
 
     """
+    if hasattr(os.path, 'realpath'):
+        # Python 2.2 introduced os.path.realpath(); it is used
+        # here to work around problems with Cygwin not being
+        # able to open symlinks for reading
+        executable = os.path.realpath(executable)
     f = open(executable,'rb')
     binary = f.read(chunksize)
     pos = 0
@@ -218,21 +226,90 @@
     return distname,version,id
 
 _release_filename = re.compile(r'(\w+)[-_](release|version)')
-_release_version = re.compile(r'([\d.]+)[^(]*(?:\((.+)\))?')
+_lsb_release_version = re.compile(r'(.+)'
+                                   ' release '
+                                   '([\d.]+)'
+                                   '[^(]*(?:\((.+)\))?')
+_release_version = re.compile(r'([^0-9]+)'
+                               '(?: release )?'
+                               '([\d.]+)'
+                               '[^(]*(?:\((.+)\))?')
 
-# Note:In supported_dists below we need 'fedora' before 'redhat' as in
-# Fedora redhat-release is a link to fedora-release.
+# See also http://www.novell.com/coolsolutions/feature/11251.html
+# and http://linuxmafia.com/faq/Admin/release-files.html
+# and http://data.linux-ntfs.org/rpm/whichrpm
+# and http://www.die.net/doc/linux/man/man1/lsb_release.1.html
 
-def dist(distname='',version='',id='',
+_supported_dists = (
+    'SuSE', 'debian', 'fedora', 'redhat', 'centos',
+    'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo',
+    'UnitedLinux', 'turbolinux')
 
-         supported_dists=('SuSE', 'debian', 'fedora', 'redhat', 'mandrake')):
+def _parse_release_file(firstline):
 
+    # Default to empty 'version' and 'id' strings.  Both defaults are used
+    # when 'firstline' is empty.  'id' defaults to empty when an id can not
+    # be deduced.
+    version = ''
+    id = ''
+
+    # Parse the first line
+    m = _lsb_release_version.match(firstline)
+    if m is not None:
+        # LSB format: "distro release x.x (codename)"
+        return tuple(m.groups())
+
+    # Pre-LSB format: "distro x.x (codename)"
+    m = _release_version.match(firstline)
+    if m is not None:
+        return tuple(m.groups())
+
+    # Unkown format... take the first two words
+    l = string.split(string.strip(firstline))
+    if l:
+        version = l[0]
+        if len(l) > 1:
+            id = l[1]
+    return '', version, id
+
+def _test_parse_release_file():
+
+    for input, output in (
+        # Examples of release file contents:
+        ('SuSE Linux 9.3 (x86-64)', ('SuSE Linux ', '9.3', 'x86-64'))
+        ('SUSE LINUX 10.1 (X86-64)', ('SUSE LINUX ', '10.1', 'X86-64'))
+        ('SUSE LINUX 10.1 (i586)', ('SUSE LINUX ', '10.1', 'i586'))
+        ('Fedora Core release 5 (Bordeaux)', ('Fedora Core', '5', 'Bordeaux'))
+        ('Red Hat Linux release 8.0 (Psyche)', ('Red Hat Linux', '8.0', 'Psyche'))
+        ('Red Hat Linux release 9 (Shrike)', ('Red Hat Linux', '9', 'Shrike'))
+        ('Red Hat Enterprise Linux release 4 (Nahant)', ('Red Hat Enterprise Linux', '4', 'Nahant'))
+        ('CentOS release 4', ('CentOS', '4', None))
+        ('Rocks release 4.2.1 (Cydonia)', ('Rocks', '4.2.1', 'Cydonia'))
+        ):
+        parsed = _parse_release_file(input)
+        if parsed != output:
+            print (input, parsed)
+
+def linux_distribution(distname='', version='', id='',
+
+                       supported_dists=_supported_dists,
+                       full_distribution_name=1):
+
     """ Tries to determine the name of the Linux OS distribution name.
 
         The function first looks for a distribution release file in
         /etc and then reverts to _dist_try_harder() in case no
         suitable files are found.
 
+        supported_dists may be given to define the set of Linux
+        distributions to look for. It defaults to a list of currently
+        supported Linux distributions identified by their release file
+        name.
+
+        If full_distribution_name is true (default), the full
+        distribution read from the OS is returned. Otherwise the short
+        name taken from supported_dists is used.
+
         Returns a tuple (distname,version,id) which default to the
         args given as parameters.
 
@@ -242,34 +319,51 @@
     except os.error:
         # Probably not a Unix system
         return distname,version,id
+    etc.sort()
     for file in etc:
         m = _release_filename.match(file)
-        if m:
+        if m is not None:
             _distname,dummy = m.groups()
             if _distname in supported_dists:
                 distname = _distname
                 break
     else:
         return _dist_try_harder(distname,version,id)
-    f = open('/etc/'+file,'r')
+
+    # Read the first line
+    f = open('/etc/'+file, 'r')
     firstline = f.readline()
     f.close()
-    m = _release_version.search(firstline)
-    if m:
-        _version,_id = m.groups()
-        if _version:
-            version = _version
-        if _id:
-            id = _id
-    else:
-        # Unkown format... take the first two words
-        l = string.split(string.strip(firstline))
-        if l:
-            version = l[0]
-            if len(l) > 1:
-                id = l[1]
-    return distname,version,id
+    _distname, _version, _id = _parse_release_file(firstline)
 
+    if _distname and full_distribution_name:
+        distname = _distname
+    if _version:
+        version = _version
+    if _id:
+        id = _id
+    return distname, version, id
+
+# To maintain backwards compatibility:
+
+def dist(distname='',version='',id='',
+
+         supported_dists=_supported_dists):
+
+    """ Tries to determine the name of the Linux OS distribution name.
+
+        The function first looks for a distribution release file in
+        /etc and then reverts to _dist_try_harder() in case no
+        suitable files are found.
+
+        Returns a tuple (distname,version,id) which default to the
+        args given as parameters.
+
+    """
+    return linux_distribution(distname, version, id,
+                              supported_dists=supported_dists,
+                              full_distribution_name=0)
+
 class _popen:
 
     """ Fairly portable (alternative) popen implementation.
@@ -357,7 +451,7 @@
     else:
         return popen(cmd,mode,bufsize)
 
-def _norm_version(version,build=''):
+def _norm_version(version, build=''):
 
     """ Normalize the version and build strings and return a single
         version string using the format major.minor.build (or patchlevel).
@@ -378,7 +472,7 @@
                          '.*'
                          'Version ([\d.]+))')
 
-def _syscmd_ver(system='',release='',version='',
+def _syscmd_ver(system='', release='', version='',
 
                supported_platforms=('win32','win16','dos','os2')):
 
@@ -418,7 +512,7 @@
     # Parse the output
     info = string.strip(info)
     m = _ver_output.match(info)
-    if m:
+    if m is not None:
         system,release,version = m.groups()
         # Strip trailing dots from version and release
         if release[-1] == '.':
@@ -437,8 +531,14 @@
         In case this fails, default is returned.
 
     """
-    from win32api import RegQueryValueEx
     try:
+        # Use win32api if available
+        from win32api import RegQueryValueEx
+    except ImportError:
+        # On Python 2.0 and later, emulate using _winreg
+        import _winreg
+        RegQueryValueEx = _winreg.QueryValueEx
+    try:
         return RegQueryValueEx(key,name)
     except:
         return default
@@ -457,9 +557,9 @@
         means the OS version uses debugging code, i.e. code that
         checks arguments, ranges, etc. (Thomas Heller).
 
-        Note: this function only works if Mark Hammond's win32
-        package is installed and obviously only runs on Win32
-        compatible platforms.
+        Note: this function works best with Mark Hammond's win32
+        package installed, but also on Python 2.3 and later. It
+        obviously only runs on Win32 compatible platforms.
 
     """
     # XXX Is there any way to find out the processor type on WinXX ?
@@ -473,17 +573,42 @@
     # Import the needed APIs
     try:
         import win32api
+        from win32api import RegQueryValueEx, RegOpenKeyEx, \
+             RegCloseKey, GetVersionEx
+        from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \
+             VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION
     except ImportError:
-        return release,version,csd,ptype
-    from win32api import RegQueryValueEx,RegOpenKeyEx,RegCloseKey,GetVersionEx
-    from win32con import HKEY_LOCAL_MACHINE,VER_PLATFORM_WIN32_NT,\
-                         VER_PLATFORM_WIN32_WINDOWS
+        # Emulate the win32api module using Python APIs
+        try:
+            sys.getwindowsversion
+        except AttributeError:
+            # No emulation possible, so return the defaults...
+            return release,version,csd,ptype
+        else:
+            # Emulation using _winreg (added in Python 2.0) and
+            # sys.getwindowsversion() (added in Python 2.3)
+            import _winreg
+            GetVersionEx = sys.getwindowsversion
+            RegQueryValueEx = _winreg.QueryValueEx
+            RegOpenKeyEx = _winreg.OpenKeyEx
+            RegCloseKey = _winreg.CloseKey
+            HKEY_LOCAL_MACHINE = _winreg.HKEY_LOCAL_MACHINE
+            VER_PLATFORM_WIN32_WINDOWS = 1
+            VER_PLATFORM_WIN32_NT = 2
+            VER_NT_WORKSTATION = 1
+            VER_NT_SERVER = 3
+            REG_SZ = 1
 
     # Find out the registry key and some general version infos
-    maj,min,buildno,plat,csd = GetVersionEx()
+    winver = GetVersionEx()
+    maj,min,buildno,plat,csd = winver
     version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
-    if csd[:13] == 'Service Pack ':
-        csd = 'SP' + csd[13:]
+    if hasattr(winver, "service_pack"):
+        if winver.service_pack != "":
+            csd = 'SP%s' % winver.service_pack_major
+    else:
+        if csd[:13] == 'Service Pack ':
+            csd = 'SP' + csd[13:]
     if plat == VER_PLATFORM_WIN32_WINDOWS:
         regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
         # Try to guess the release name
@@ -511,6 +636,36 @@
                 release = '2003Server'
             else:
                 release = 'post2003'
+        elif maj == 6:
+            if hasattr(winver, "product_type"):
+                product_type = winver.product_type
+            else:
+                product_type = VER_NT_WORKSTATION
+                # Without an OSVERSIONINFOEX capable sys.getwindowsversion(),
+                # or help from the registry, we cannot properly identify
+                # non-workstation versions.
+                try:
+                    key = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
+                    name, type = RegQueryValueEx(key, "ProductName")
+                    # Discard any type that isn't REG_SZ
+                    if type == REG_SZ and name.find("Server") != -1:
+                        product_type = VER_NT_SERVER
+                except WindowsError:
+                    # Use default of VER_NT_WORKSTATION
+                    pass
+
+            if min == 0:
+                if product_type == VER_NT_WORKSTATION:
+                    release = 'Vista'
+                else:
+                    release = '2008Server'
+            elif min == 1:
+                if product_type == VER_NT_WORKSTATION:
+                    release = '7'
+                else:
+                    release = '2008ServerR2'
+            else:
+                release = 'post2008Server'
     else:
         if not release:
             # E.g. Win3.1 with win32s
@@ -519,9 +674,9 @@
 
     # Open the registry key
     try:
-        keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE,regkey)
+        keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey)
         # Get a value to make sure the key exists...
-        RegQueryValueEx(keyCurVer,'SystemRoot')
+        RegQueryValueEx(keyCurVer, 'SystemRoot')
     except:
         return release,version,csd,ptype
 
@@ -562,30 +717,22 @@
 
     return hex(bcd)[2:]
 
-def mac_ver(release='',versioninfo=('','',''),machine=''):
-
-    """ Get MacOS version information and return it as tuple (release,
-        versioninfo, machine) with versioninfo being a tuple (version,
-        dev_stage, non_release_version).
-
-        Entries which cannot be determined are set to the paramter values
-        which default to ''. All tuple entries are strings.
-
+def _mac_ver_gestalt():
+    """
         Thanks to Mark R. Levinson for mailing documentation links and
         code examples for this function. Documentation for the
         gestalt() API is available online at:
 
            http://www.rgaros.nl/gestalt/
-
     """
     # Check whether the version info module is available
     try:
         import gestalt
         import MacOS
     except ImportError:
-        return release,versioninfo,machine
+        return None
     # Get the infos
-    sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
+    sysv,sysa = _mac_ver_lookup(('sysv','sysa'))
     # Decode the infos
     if sysv:
         major = (sysv & 0xFF00) >> 8
@@ -602,32 +749,70 @@
             release = '%i.%i.%i' %(major, minor, patch)
         else:
             release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
-    if sysu:
-        major =  int((sysu & 0xFF000000L) >> 24)
-        minor =  (sysu & 0x00F00000) >> 20
-        bugfix = (sysu & 0x000F0000) >> 16
-        stage =  (sysu & 0x0000FF00) >> 8
-        nonrel = (sysu & 0x000000FF)
-        version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
-        nonrel = _bcd2str(nonrel)
-        stage = {0x20:'development',
-                 0x40:'alpha',
-                 0x60:'beta',
-                 0x80:'final'}.get(stage,'')
-        versioninfo = (version,stage,nonrel)
+
     if sysa:
         machine = {0x1: '68k',
                    0x2: 'PowerPC',
                    0xa: 'i386'}.get(sysa,'')
+
     return release,versioninfo,machine
 
+def _mac_ver_xml():
+    fn = '/System/Library/CoreServices/SystemVersion.plist'
+    if not os.path.exists(fn):
+        return None
+
+    try:
+        import plistlib
+    except ImportError:
+        return None
+
+    pl = plistlib.readPlist(fn)
+    release = pl['ProductVersion']
+    versioninfo=('', '', '')
+    machine = os.uname()[4]
+    if machine in ('ppc', 'Power Macintosh'):
+        # for compatibility with the gestalt based code
+        machine = 'PowerPC'
+
+    return release,versioninfo,machine
+
+
+def mac_ver(release='',versioninfo=('','',''),machine=''):
+
+    """ Get MacOS version information and return it as tuple (release,
+        versioninfo, machine) with versioninfo being a tuple (version,
+        dev_stage, non_release_version).
+
+        Entries which cannot be determined are set to the paramter values
+        which default to ''. All tuple entries are strings.
+    """
+
+    # First try reading the information from an XML file which should
+    # always be present
+    info = _mac_ver_xml()
+    if info is not None:
+        return info
+
+    # If that doesn't work for some reason fall back to reading the
+    # information using gestalt calls.
+    info = _mac_ver_gestalt()
+    if info is not None:
+        return info
+
+    # If that also doesn't work return the default values
+    return release,versioninfo,machine
+
 def _java_getprop(name,default):
 
     from java.lang import System
     from org.python.core.Py import newString
     try:
-        return newString(System.getProperty(name))
-    except:
+        value = System.getProperty(name)
+        if value is None:
+            return default
+        return newString(value)
+    except AttributeError:
         return default
 
 def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
@@ -648,20 +833,20 @@
     except ImportError:
         return release,vendor,vminfo,osinfo
 
-    vendor = _java_getprop('java.vendor',vendor)
-    release = _java_getprop('java.version',release)
-    vm_name,vm_release,vm_vendor = vminfo
-    vm_name = _java_getprop('java.vm.name',vm_name)
-    vm_vendor = _java_getprop('java.vm.vendor',vm_vendor)
-    vm_release = _java_getprop('java.vm.version',vm_release)
-    vminfo = vm_name,vm_release,vm_vendor
-    os_name,os_version,os_arch = osinfo
-    os_arch = _java_getprop('os.arch',os_arch)
-    os_name = _java_getprop('os.name',os_name)
-    os_version = _java_getprop('os.version',os_version)
-    osinfo = os_name,os_version,os_arch
+    vendor = _java_getprop('java.vendor', vendor)
+    release = _java_getprop('java.version', release)
+    vm_name, vm_release, vm_vendor = vminfo
+    vm_name = _java_getprop('java.vm.name', vm_name)
+    vm_vendor = _java_getprop('java.vm.vendor', vm_vendor)
+    vm_release = _java_getprop('java.vm.version', vm_release)
+    vminfo = vm_name, vm_release, vm_vendor
+    os_name, os_version, os_arch = osinfo
+    os_arch = _java_getprop('os.arch', os_arch)
+    os_name = _java_getprop('os.name', os_name)
+    os_version = _java_getprop('os.version', os_version)
+    osinfo = os_name, os_version, os_arch
 
-    return release,vendor,vminfo,osinfo
+    return release, vendor, vminfo, osinfo
 
 ### System name aliasing
 
@@ -727,7 +912,7 @@
     # Format the platform string
     platform = string.join(
         map(string.strip,
-            filter(len,args)),
+            filter(len, args)),
         '-')
 
     # Cleanup some possible filename obstacles...
@@ -825,9 +1010,12 @@
         case the command should fail.
 
     """
-    target = _follow_symlinks(target)
+    if sys.platform in ('dos','win32','win16','os2'):
+        # XXX Others too ?
+        return default
+    target = _follow_symlinks(target).replace('"', '\\"')
     try:
-        f = os.popen('file %s 2> /dev/null' % target)
+        f = os.popen('file "%s" 2> /dev/null' % target)
     except (AttributeError,os.error):
         return default
     output = string.strip(f.read())
@@ -882,19 +1070,22 @@
         bits = str(size*8) + 'bit'
 
     # Get data from the 'file' system command
-    output = _syscmd_file(executable,'')
+    if executable:
+        output = _syscmd_file(executable, '')
+    else:
+        output = ''
 
     if not output and \
        executable == sys.executable:
         # "file" command did not return anything; we'll try to provide
         # some sensible defaults then...
-        if _default_architecture.has_key(sys.platform):
-            b,l = _default_architecture[sys.platform]
+        if sys.platform in _default_architecture:
+            b, l = _default_architecture[sys.platform]
             if b:
                 bits = b
             if l:
                 linkage = l
-        return bits,linkage
+        return bits, linkage
 
     # Split the output into a list of strings omitting the filename
     fileout = _architecture_split(output)[1:]
@@ -948,29 +1139,44 @@
 
     """
     global _uname_cache
+    no_os_uname = 0
 
     if _uname_cache is not None:
         return _uname_cache
 
+    processor = ''
+
     # Get some infos from the builtin os.uname API...
     try:
         system,node,release,version,machine = os.uname()
-
     except AttributeError:
-        # Hmm, no uname... we'll have to poke around the system then.
-        system = sys.platform
-        release = ''
-        version = ''
-        node = _node()
-        machine = ''
-        processor = ''
-        use_syscmd_ver = 1
+        no_os_uname = 1
 
+    if no_os_uname or not filter(None, (system, node, release, version, machine)):
+        # Hmm, no there is either no uname or uname has returned
+        #'unknowns'... we'll have to poke around the system then.
+        if no_os_uname:
+            system = sys.platform
+            release = ''
+            version = ''
+            node = _node()
+            machine = ''
+
+        use_syscmd_ver = 01
+
         # Try win32_ver() on win32 platforms
         if system == 'win32':
             release,version,csd,ptype = win32_ver()
             if release and version:
                 use_syscmd_ver = 0
+            # Try to use the PROCESSOR_* environment variables
+            # available on Win XP and later; see
+            # http://support.microsoft.com/kb/888731 and
+            # http://www.geocities.com/rick_lively/MANUALS/ENV/MSWIN/PROCESSI.HTM
+            if not machine:
+                machine = os.environ.get('PROCESSOR_ARCHITECTURE', '')
+            if not processor:
+                processor = os.environ.get('PROCESSOR_IDENTIFIER', machine)
 
         # Try the 'ver' system command available on some
         # platforms
@@ -980,6 +1186,16 @@
             # (_syscmd_ver() tends to return the vendor name as well)
             if system == 'Microsoft Windows':
                 system = 'Windows'
+            elif system == 'Microsoft' and release == 'Windows':
+                # Under Windows Vista and Windows Server 2008,
+                # Microsoft changed the output of the ver command. The
+                # release is no longer printed.  This causes the
+                # system and release to be misidentified.
+                system = 'Windows'
+                if '6.0' == version[:3]:
+                    release = 'Vista'
+                else:
+                    release = ''
 
         # In case we still don't know anything useful, we'll try to
         # help ourselves
@@ -1002,30 +1218,28 @@
             release,(version,stage,nonrel),machine = mac_ver()
             system = 'MacOS'
 
-    else:
-        # System specific extensions
-        if system == 'OpenVMS':
-            # OpenVMS seems to have release and version mixed up
-            if not release or release == '0':
-                release = version
-                version = ''
-            # Get processor information
-            try:
-                import vms_lib
-            except ImportError:
-                pass
+    # System specific extensions
+    if system == 'OpenVMS':
+        # OpenVMS seems to have release and version mixed up
+        if not release or release == '0':
+            release = version
+            version = ''
+        # Get processor information
+        try:
+            import vms_lib
+        except ImportError:
+            pass
+        else:
+            csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
+            if (cpu_number >= 128):
+                processor = 'Alpha'
             else:
-                csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
-                if (cpu_number >= 128):
-                    processor = 'Alpha'
-                else:
-                    processor = 'VAX'
-        else:
-            # Get processor information from the uname system command
-            processor = _syscmd_uname('-p','')
+                processor = 'VAX'
+    if not processor:
+        # Get processor information from the uname system command
+        processor = _syscmd_uname('-p','')
 
-    # 'unknown' is not really any useful as information; we'll convert
-    # it to '' which is more portable
+    #If any unknowns still exist, replace them with ''s, which are more portable
     if system == 'unknown':
         system = ''
     if node == 'unknown':
@@ -1109,37 +1323,137 @@
 
 ### Various APIs for extracting information from sys.version
 
-_sys_version_parser = re.compile(r'([\w.+]+)\s*'
-                                  '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
-                                  '\[([^\]]+)\]?')
-_sys_version_cache = None
+_sys_version_parser = re.compile(
+    r'([\w.+]+)\s*'
+    '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*'
+    '\[([^\]]+)\]?')
 
-def _sys_version():
+_jython_sys_version_parser = re.compile(
+    r'([\d\.]+)')
 
+_ironpython_sys_version_parser = re.compile(
+    r'IronPython\s*'
+    '([\d\.]+)'
+    '(?: \(([\d\.]+)\))?'
+    ' on (.NET [\d\.]+)')
+
+_sys_version_cache = {}
+
+def _sys_version(sys_version=None):
+
     """ Returns a parsed version of Python's sys.version as tuple
-        (version, buildno, builddate, compiler) referring to the Python
-        version, build number, build date/time as string and the compiler
+        (name, version, branch, revision, buildno, builddate, compiler)
+        referring to the Python implementation name, version, branch,
+        revision, build number, build date/time as string and the compiler
         identification string.
 
         Note that unlike the Python sys.version, the returned value
         for the Python version will always include the patchlevel (it
         defaults to '.0').
 
+        The function returns empty strings for tuple entries that
+        cannot be determined.
+
+        sys_version may be given to parse an alternative version
+        string, e.g. if the version was read from a different Python
+        interpreter.
+
     """
-    global _sys_version_cache
+    # Get the Python version
+    if sys_version is None:
+        sys_version = sys.version
 
-    if _sys_version_cache is not None:
-        return _sys_version_cache
-    version, buildno, builddate, buildtime, compiler = \
-             _sys_version_parser.match(sys.version).groups()
-    builddate = builddate + ' ' + buildtime
+    # Try the cache first
+    result = _sys_version_cache.get(sys_version, None)
+    if result is not None:
+        return result
+
+    # Parse it
+    if sys_version[:10] == 'IronPython':
+        # IronPython
+        name = 'IronPython'
+        match = _ironpython_sys_version_parser.match(sys_version)
+        if match is None:
+            raise ValueError(
+                'failed to parse IronPython sys.version: %s' %
+                repr(sys_version))
+        version, alt_version, compiler = match.groups()
+        branch = ''
+        revision = ''
+        buildno = ''
+        builddate = ''
+
+    elif sys.platform[:4] == 'java':
+        # Jython
+        name = 'Jython'
+        match = _jython_sys_version_parser.match(sys_version)
+        if match is None:
+            raise ValueError(
+                'failed to parse Jython sys.version: %s' %
+                repr(sys_version))
+        version, = match.groups()
+        branch = ''
+        revision = ''
+        compiler = sys.platform
+        buildno = ''
+        builddate = ''
+
+    else:
+        # CPython
+        match = _sys_version_parser.match(sys_version)
+        if match is None:
+            raise ValueError(
+                'failed to parse CPython sys.version: %s' %
+                repr(sys_version))
+        version, buildno, builddate, buildtime, compiler = \
+              match.groups()
+        if hasattr(sys, 'subversion'):
+            # sys.subversion was added in Python 2.5
+            name, branch, revision = sys.subversion
+        else:
+            name = 'CPython'
+            branch = ''
+            revision = ''
+        builddate = builddate + ' ' + buildtime
+
+    # Add the patchlevel version if missing
     l = string.split(version, '.')
     if len(l) == 2:
         l.append('0')
         version = string.join(l, '.')
-    _sys_version_cache = (version, buildno, builddate, compiler)
-    return _sys_version_cache
 
+    # Build and cache the result
+    result = (name, version, branch, revision, buildno, builddate, compiler)
+    _sys_version_cache[sys_version] = result
+    return result
+
+def _test_sys_version():
+
+    _sys_version_cache.clear()
+    for input, output in (
+        ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]',
+         ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')),
+        ('IronPython 1.0.60816 on .NET 2.0.50727.42',
+         ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')),
+        ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42',
+         ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')),
+        ):
+        parsed = _sys_version(input)
+        if parsed != output:
+            print (input, parsed)
+
+def python_implementation():
+
+    """ Returns a string identifying the Python implementation.
+
+        Currently, the following implementations are identified:
+        'CPython' (C implementation of Python),
+        'IronPython' (.NET implementation of Python),
+        'Jython' (Java implementation of Python).
+
+    """
+    return _sys_version()[0]
+
 def python_version():
 
     """ Returns the Python version as string 'major.minor.patchlevel'
@@ -1148,7 +1462,7 @@
         will always include the patchlevel (it defaults to 0).
 
     """
-    return _sys_version()[0]
+    return _sys_version()[1]
 
 def python_version_tuple():
 
@@ -1159,15 +1473,42 @@
         will always include the patchlevel (it defaults to 0).
 
     """
-    return string.split(_sys_version()[0], '.')
+    return tuple(string.split(_sys_version()[1], '.'))
 
+def python_branch():
+
+    """ Returns a string identifying the Python implementation
+        branch.
+
+        For CPython this is the Subversion branch from which the
+        Python binary was built.
+
+        If not available, an empty string is returned.
+
+    """
+
+    return _sys_version()[2]
+
+def python_revision():
+
+    """ Returns a string identifying the Python implementation
+        revision.
+
+        For CPython this is the Subversion revision from which the
+        Python binary was built.
+
+        If not available, an empty string is returned.
+
+    """
+    return _sys_version()[3]
+
 def python_build():
 
     """ Returns a tuple (buildno, builddate) stating the Python
         build number and date as strings.
 
     """
-    return _sys_version()[1:3]
+    return _sys_version()[4:6]
 
 def python_compiler():
 
@@ -1175,7 +1516,7 @@
         Python.
 
     """
-    return _sys_version()[3]
+    return _sys_version()[6]
 
 ### The Opus Magnum of platform strings :-)
 
@@ -1236,7 +1577,7 @@
     elif system == 'Java':
         # Java platforms
         r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
-        if terse:
+        if terse or not os_name:
             platform = _platform(system,release,version)
         else:
             platform = _platform(system,release,version,


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

------------------------------------------------------------------------------
Enable your software for Intel(R) Active Management Technology to meet the
growing manageability and security demands of your customers. Businesses
are taking advantage of Intel(R) vPro (TM) technology - will your software 
be a part of the solution? Download the Intel(R) Manageability Checker 
today! http://p.sf.net/sfu/intel-dev2devmar