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