PyXR

c:\python24\lib \ platform.py



0001 #!/usr/bin/env python
0002 
0003 """ This module tries to retrieve as much platform-identifying data as
0004     possible. It makes this information available via function APIs.
0005 
0006     If called from the command line, it prints the platform
0007     information concatenated as single string to stdout. The output
0008     format is useable as part of a filename.
0009 
0010 """
0011 #    This module is maintained by Marc-Andre Lemburg <mal@egenix.com>.
0012 #    If you find problems, please submit bug reports/patches via the
0013 #    Python SourceForge Project Page and assign them to "lemburg".
0014 #
0015 #    Note: Please keep this module compatible to Python 1.5.2.
0016 #
0017 #    Still needed:
0018 #    * more support for WinCE
0019 #    * support for MS-DOS (PythonDX ?)
0020 #    * support for Amiga and other still unsupported platforms running Python
0021 #    * support for additional Linux distributions
0022 #
0023 #    Many thanks to all those who helped adding platform-specific
0024 #    checks (in no particular order):
0025 #
0026 #      Charles G Waldman, David Arnold, Gordon McMillan, Ben Darnell,
0027 #      Jeff Bauer, Cliff Crawford, Ivan Van Laningham, Josef
0028 #      Betancourt, Randall Hopper, Karl Putland, John Farrell, Greg
0029 #      Andruk, Just van Rossum, Thomas Heller, Mark R. Levinson, Mark
0030 #      Hammond, Bill Tutt, Hans Nowak, Uwe Zessin (OpenVMS support),
0031 #      Colin Kong, Trent Mick, Guido van Rossum
0032 #
0033 #    History:
0034 #    1.0.3 - added normalization of Windows system name
0035 #    1.0.2 - added more Windows support
0036 #    1.0.1 - reformatted to make doc.py happy
0037 #    1.0.0 - reformatted a bit and checked into Python CVS
0038 #    0.8.0 - added sys.version parser and various new access
0039 #            APIs (python_version(), python_compiler(), etc.)
0040 #    0.7.2 - fixed architecture() to use sizeof(pointer) where available
0041 #    0.7.1 - added support for Caldera OpenLinux
0042 #    0.7.0 - some fixes for WinCE; untabified the source file
0043 #    0.6.2 - support for OpenVMS - requires version 1.5.2-V006 or higher and
0044 #            vms_lib.getsyi() configured
0045 #    0.6.1 - added code to prevent 'uname -p' on platforms which are
0046 #            known not to support it
0047 #    0.6.0 - fixed win32_ver() to hopefully work on Win95,98,NT and Win2k;
0048 #            did some cleanup of the interfaces - some APIs have changed
0049 #    0.5.5 - fixed another type in the MacOS code... should have
0050 #            used more coffee today ;-)
0051 #    0.5.4 - fixed a few typos in the MacOS code
0052 #    0.5.3 - added experimental MacOS support; added better popen()
0053 #            workarounds in _syscmd_ver() -- still not 100% elegant
0054 #            though
0055 #    0.5.2 - fixed uname() to return '' instead of 'unknown' in all
0056 #            return values (the system uname command tends to return
0057 #            'unknown' instead of just leaving the field emtpy)
0058 #    0.5.1 - included code for slackware dist; added exception handlers
0059 #            to cover up situations where platforms don't have os.popen
0060 #            (e.g. Mac) or fail on socket.gethostname(); fixed libc
0061 #            detection RE
0062 #    0.5.0 - changed the API names referring to system commands to *syscmd*;
0063 #            added java_ver(); made syscmd_ver() a private
0064 #            API (was system_ver() in previous versions) -- use uname()
0065 #            instead; extended the win32_ver() to also return processor
0066 #            type information
0067 #    0.4.0 - added win32_ver() and modified the platform() output for WinXX
0068 #    0.3.4 - fixed a bug in _follow_symlinks()
0069 #    0.3.3 - fixed popen() and "file" command invokation bugs
0070 #    0.3.2 - added architecture() API and support for it in platform()
0071 #    0.3.1 - fixed syscmd_ver() RE to support Windows NT
0072 #    0.3.0 - added system alias support
0073 #    0.2.3 - removed 'wince' again... oh well.
0074 #    0.2.2 - added 'wince' to syscmd_ver() supported platforms
0075 #    0.2.1 - added cache logic and changed the platform string format
0076 #    0.2.0 - changed the API to use functions instead of module globals
0077 #            since some action take too long to be run on module import
0078 #    0.1.0 - first release
0079 #
0080 #    You can always get the latest version of this module at:
0081 #
0082 #             http://www.egenix.com/files/python/platform.py
0083 #
0084 #    If that URL should fail, try contacting the author.
0085 
0086 __copyright__ = """
0087     Copyright (c) 1999-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
0088     Copyright (c) 2000-2003, eGenix.com Software GmbH; mailto:info@egenix.com
0089 
0090     Permission to use, copy, modify, and distribute this software and its
0091     documentation for any purpose and without fee or royalty is hereby granted,
0092     provided that the above copyright notice appear in all copies and that
0093     both that copyright notice and this permission notice appear in
0094     supporting documentation or portions thereof, including modifications,
0095     that you make.
0096 
0097     EGENIX.COM SOFTWARE GMBH DISCLAIMS ALL WARRANTIES WITH REGARD TO
0098     THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
0099     FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
0100     INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
0101     FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
0102     NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
0103     WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
0104 
0105 """
0106 
0107 __version__ = '1.0.2'
0108 
0109 import sys,string,os,re
0110 
0111 ### Platform specific APIs
0112 
0113 _libc_search = re.compile(r'(__libc_init)'
0114                           '|'
0115                           '(GLIBC_([0-9.]+))'
0116                           '|'
0117                           '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
0118 
0119 def libc_ver(executable=sys.executable,lib='',version='',
0120 
0121              chunksize=2048):
0122 
0123     """ Tries to determine the libc version that the file executable
0124         (which defaults to the Python interpreter) is linked against.
0125 
0126         Returns a tuple of strings (lib,version) which default to the
0127         given parameters in case the lookup fails.
0128 
0129         Note that the function has intimate knowledge of how different
0130         libc versions add symbols to the executable and thus is probably
0131         only useable for executables compiled using gcc.
0132 
0133         The file is read and scanned in chunks of chunksize bytes.
0134 
0135     """
0136     f = open(executable,'rb')
0137     binary = f.read(chunksize)
0138     pos = 0
0139     while 1:
0140         m = _libc_search.search(binary,pos)
0141         if not m:
0142             binary = f.read(chunksize)
0143             if not binary:
0144                 break
0145             pos = 0
0146             continue
0147         libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
0148         if libcinit and not lib:
0149             lib = 'libc'
0150         elif glibc:
0151             if lib != 'glibc':
0152                 lib = 'glibc'
0153                 version = glibcversion
0154             elif glibcversion > version:
0155                 version = glibcversion
0156         elif so:
0157             if lib != 'glibc':
0158                 lib = 'libc'
0159                 if soversion > version:
0160                     version = soversion
0161                 if threads and version[-len(threads):] != threads:
0162                     version = version + threads
0163         pos = m.end()
0164     f.close()
0165     return lib,version
0166 
0167 def _dist_try_harder(distname,version,id):
0168 
0169     """ Tries some special tricks to get the distribution
0170         information in case the default method fails.
0171 
0172         Currently supports older SuSE Linux, Caldera OpenLinux and
0173         Slackware Linux distributions.
0174 
0175     """
0176     if os.path.exists('/var/adm/inst-log/info'):
0177         # SuSE Linux stores distribution information in that file
0178         info = open('/var/adm/inst-log/info').readlines()
0179         distname = 'SuSE'
0180         for line in info:
0181             tv = string.split(line)
0182             if len(tv) == 2:
0183                 tag,value = tv
0184             else:
0185                 continue
0186             if tag == 'MIN_DIST_VERSION':
0187                 version = string.strip(value)
0188             elif tag == 'DIST_IDENT':
0189                 values = string.split(value,'-')
0190                 id = values[2]
0191         return distname,version,id
0192 
0193     if os.path.exists('/etc/.installed'):
0194         # Caldera OpenLinux has some infos in that file (thanks to Colin Kong)
0195         info = open('/etc/.installed').readlines()
0196         for line in info:
0197             pkg = string.split(line,'-')
0198             if len(pkg) >= 2 and pkg[0] == 'OpenLinux':
0199                 # XXX does Caldera support non Intel platforms ? If yes,
0200                 #     where can we find the needed id ?
0201                 return 'OpenLinux',pkg[1],id
0202 
0203     if os.path.isdir('/usr/lib/setup'):
0204         # Check for slackware verson tag file (thanks to Greg Andruk)
0205         verfiles = os.listdir('/usr/lib/setup')
0206         for n in range(len(verfiles)-1, -1, -1):
0207             if verfiles[n][:14] != 'slack-version-':
0208                 del verfiles[n]
0209         if verfiles:
0210             verfiles.sort()
0211             distname = 'slackware'
0212             version = verfiles[-1][14:]
0213             return distname,version,id
0214 
0215     return distname,version,id
0216 
0217 _release_filename = re.compile(r'(\w+)[-_](release|version)')
0218 _release_version = re.compile(r'([\d.]+)[^(]*(?:\((.+)\))?')
0219 
0220 def dist(distname='',version='',id='',
0221 
0222          supported_dists=('SuSE','debian','redhat','mandrake')):
0223 
0224     """ Tries to determine the name of the Linux OS distribution name.
0225 
0226         The function first looks for a distribution release file in
0227         /etc and then reverts to _dist_try_harder() in case no
0228         suitable files are found.
0229 
0230         Returns a tuple (distname,version,id) which default to the
0231         args given as parameters.
0232 
0233     """
0234     try:
0235         etc = os.listdir('/etc')
0236     except os.error:
0237         # Probably not a Unix system
0238         return distname,version,id
0239     for file in etc:
0240         m = _release_filename.match(file)
0241         if m:
0242             _distname,dummy = m.groups()
0243             if _distname in supported_dists:
0244                 distname = _distname
0245                 break
0246     else:
0247         return _dist_try_harder(distname,version,id)
0248     f = open('/etc/'+file,'r')
0249     firstline = f.readline()
0250     f.close()
0251     m = _release_version.search(firstline)
0252     if m:
0253         _version,_id = m.groups()
0254         if _version:
0255             version = _version
0256         if _id:
0257             id = _id
0258     else:
0259         # Unkown format... take the first two words
0260         l = string.split(string.strip(firstline))
0261         if l:
0262             version = l[0]
0263             if len(l) > 1:
0264                 id = l[1]
0265     return distname,version,id
0266 
0267 class _popen:
0268 
0269     """ Fairly portable (alternative) popen implementation.
0270 
0271         This is mostly needed in case os.popen() is not available, or
0272         doesn't work as advertised, e.g. in Win9X GUI programs like
0273         PythonWin or IDLE.
0274 
0275         Writing to the pipe is currently not supported.
0276 
0277     """
0278     tmpfile = ''
0279     pipe = None
0280     bufsize = None
0281     mode = 'r'
0282 
0283     def __init__(self,cmd,mode='r',bufsize=None):
0284 
0285         if mode != 'r':
0286             raise ValueError,'popen()-emulation only supports read mode'
0287         import tempfile
0288         self.tmpfile = tmpfile = tempfile.mktemp()
0289         os.system(cmd + ' > %s' % tmpfile)
0290         self.pipe = open(tmpfile,'rb')
0291         self.bufsize = bufsize
0292         self.mode = mode
0293 
0294     def read(self):
0295 
0296         return self.pipe.read()
0297 
0298     def readlines(self):
0299 
0300         if self.bufsize is not None:
0301             return self.pipe.readlines()
0302 
0303     def close(self,
0304 
0305               remove=os.unlink,error=os.error):
0306 
0307         if self.pipe:
0308             rc = self.pipe.close()
0309         else:
0310             rc = 255
0311         if self.tmpfile:
0312             try:
0313                 remove(self.tmpfile)
0314             except error:
0315                 pass
0316         return rc
0317 
0318     # Alias
0319     __del__ = close
0320 
0321 def popen(cmd, mode='r', bufsize=None):
0322 
0323     """ Portable popen() interface.
0324     """
0325     # Find a working popen implementation preferring win32pipe.popen
0326     # over os.popen over _popen
0327     popen = None
0328     if os.environ.get('OS','') == 'Windows_NT':
0329         # On NT win32pipe should work; on Win9x it hangs due to bugs
0330         # in the MS C lib (see MS KnowledgeBase article Q150956)
0331         try:
0332             import win32pipe
0333         except ImportError:
0334             pass
0335         else:
0336             popen = win32pipe.popen
0337     if popen is None:
0338         if hasattr(os,'popen'):
0339             popen = os.popen
0340             # Check whether it works... it doesn't in GUI programs
0341             # on Windows platforms
0342             if sys.platform == 'win32': # XXX Others too ?
0343                 try:
0344                     popen('')
0345                 except os.error:
0346                     popen = _popen
0347         else:
0348             popen = _popen
0349     if bufsize is None:
0350         return popen(cmd,mode)
0351     else:
0352         return popen(cmd,mode,bufsize)
0353 
0354 def _norm_version(version,build=''):
0355 
0356     """ Normalize the version and build strings and return a single
0357         vesion string using the format major.minor.build (or patchlevel).
0358     """
0359     l = string.split(version,'.')
0360     if build:
0361         l.append(build)
0362     try:
0363         ints = map(int,l)
0364     except ValueError:
0365         strings = l
0366     else:
0367         strings = map(str,ints)
0368     version = string.join(strings[:3],'.')
0369     return version
0370 
0371 _ver_output = re.compile(r'(?:([\w ]+) ([\w.]+) '
0372                          '.*'
0373                          'Version ([\d.]+))')
0374 
0375 def _syscmd_ver(system='',release='',version='',
0376 
0377                supported_platforms=('win32','win16','dos','os2')):
0378 
0379     """ Tries to figure out the OS version used and returns
0380         a tuple (system,release,version).
0381 
0382         It uses the "ver" shell command for this which is known
0383         to exists on Windows, DOS and OS/2. XXX Others too ?
0384 
0385         In case this fails, the given parameters are used as
0386         defaults.
0387 
0388     """
0389     if sys.platform not in supported_platforms:
0390         return system,release,version
0391 
0392     # Try some common cmd strings
0393     for cmd in ('ver','command /c ver','cmd /c ver'):
0394         try:
0395             pipe = popen(cmd)
0396             info = pipe.read()
0397             if pipe.close():
0398                 raise os.error,'command failed'
0399             # XXX How can I supress shell errors from being written
0400             #     to stderr ?
0401         except os.error,why:
0402             #print 'Command %s failed: %s' % (cmd,why)
0403             continue
0404         except IOError,why:
0405             #print 'Command %s failed: %s' % (cmd,why)
0406             continue
0407         else:
0408             break
0409     else:
0410         return system,release,version
0411 
0412     # Parse the output
0413     info = string.strip(info)
0414     m = _ver_output.match(info)
0415     if m:
0416         system,release,version = m.groups()
0417         # Strip trailing dots from version and release
0418         if release[-1] == '.':
0419             release = release[:-1]
0420         if version[-1] == '.':
0421             version = version[:-1]
0422         # Normalize the version and build strings (eliminating additional
0423         # zeros)
0424         version = _norm_version(version)
0425     return system,release,version
0426 
0427 def _win32_getvalue(key,name,default=''):
0428 
0429     """ Read a value for name from the registry key.
0430 
0431         In case this fails, default is returned.
0432 
0433     """
0434     from win32api import RegQueryValueEx
0435     try:
0436         return RegQueryValueEx(key,name)
0437     except:
0438         return default
0439 
0440 def win32_ver(release='',version='',csd='',ptype=''):
0441 
0442     """ Get additional version information from the Windows Registry
0443         and return a tuple (version,csd,ptype) referring to version
0444         number, CSD level and OS type (multi/single
0445         processor).
0446 
0447         As a hint: ptype returns 'Uniprocessor Free' on single
0448         processor NT machines and 'Multiprocessor Free' on multi
0449         processor machines. The 'Free' refers to the OS version being
0450         free of debugging code. It could also state 'Checked' which
0451         means the OS version uses debugging code, i.e. code that
0452         checks arguments, ranges, etc. (Thomas Heller).
0453 
0454         Note: this function only works if Mark Hammond's win32
0455         package is installed and obviously only runs on Win32
0456         compatible platforms.
0457 
0458     """
0459     # XXX Is there any way to find out the processor type on WinXX ?
0460     # XXX Is win32 available on Windows CE ?
0461     #
0462     # Adapted from code posted by Karl Putland to comp.lang.python.
0463     #
0464     # The mappings between reg. values and release names can be found
0465     # here: http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
0466 
0467     # Import the needed APIs
0468     try:
0469         import win32api
0470     except ImportError:
0471         return release,version,csd,ptype
0472     from win32api import RegQueryValueEx,RegOpenKeyEx,RegCloseKey,GetVersionEx
0473     from win32con import HKEY_LOCAL_MACHINE,VER_PLATFORM_WIN32_NT,\
0474                          VER_PLATFORM_WIN32_WINDOWS
0475 
0476     # Find out the registry key and some general version infos
0477     maj,min,buildno,plat,csd = GetVersionEx()
0478     version = '%i.%i.%i' % (maj,min,buildno & 0xFFFF)
0479     if csd[:13] == 'Service Pack ':
0480         csd = 'SP' + csd[13:]
0481     if plat == VER_PLATFORM_WIN32_WINDOWS:
0482         regkey = 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
0483         # Try to guess the release name
0484         if maj == 4:
0485             if min == 0:
0486                 release = '95'
0487             elif min == 10:
0488                 release = '98'
0489             elif min == 90:
0490                 release = 'Me'
0491             else:
0492                 release = 'postMe'
0493         elif maj == 5:
0494             release = '2000'
0495     elif plat == VER_PLATFORM_WIN32_NT:
0496         regkey = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion'
0497         if maj <= 4:
0498             release = 'NT'
0499         elif maj == 5:
0500             if min == 0:
0501                 release = '2000'
0502             elif min == 1:
0503                 release = 'XP'
0504             elif min == 2:
0505                 release = '2003Server'
0506             else:
0507                 release = 'post2003'
0508     else:
0509         if not release:
0510             # E.g. Win3.1 with win32s
0511             release = '%i.%i' % (maj,min)
0512         return release,version,csd,ptype
0513 
0514     # Open the registry key
0515     try:
0516         keyCurVer = RegOpenKeyEx(HKEY_LOCAL_MACHINE,regkey)
0517         # Get a value to make sure the key exists...
0518         RegQueryValueEx(keyCurVer,'SystemRoot')
0519     except:
0520         return release,version,csd,ptype
0521 
0522     # Parse values
0523     #subversion = _win32_getvalue(keyCurVer,
0524     #                            'SubVersionNumber',
0525     #                            ('',1))[0]
0526     #if subversion:
0527     #   release = release + subversion # 95a, 95b, etc.
0528     build = _win32_getvalue(keyCurVer,
0529                             'CurrentBuildNumber',
0530                             ('',1))[0]
0531     ptype = _win32_getvalue(keyCurVer,
0532                            'CurrentType',
0533                            (ptype,1))[0]
0534 
0535     # Normalize version
0536     version = _norm_version(version,build)
0537 
0538     # Close key
0539     RegCloseKey(keyCurVer)
0540     return release,version,csd,ptype
0541 
0542 def _mac_ver_lookup(selectors,default=None):
0543 
0544     from gestalt import gestalt
0545     import MacOS
0546     l = []
0547     append = l.append
0548     for selector in selectors:
0549         try:
0550             append(gestalt(selector))
0551         except (RuntimeError, MacOS.Error):
0552             append(default)
0553     return l
0554 
0555 def _bcd2str(bcd):
0556 
0557     return hex(bcd)[2:]
0558 
0559 def mac_ver(release='',versioninfo=('','',''),machine=''):
0560 
0561     """ Get MacOS version information and return it as tuple (release,
0562         versioninfo, machine) with versioninfo being a tuple (version,
0563         dev_stage, non_release_version).
0564 
0565         Entries which cannot be determined are set to the paramter values
0566         which default to ''. All tuple entries are strings.
0567 
0568         Thanks to Mark R. Levinson for mailing documentation links and
0569         code examples for this function. Documentation for the
0570         gestalt() API is available online at:
0571 
0572            http://www.rgaros.nl/gestalt/
0573 
0574     """
0575     # Check whether the version info module is available
0576     try:
0577         import gestalt
0578         import MacOS
0579     except ImportError:
0580         return release,versioninfo,machine
0581     # Get the infos
0582     sysv,sysu,sysa = _mac_ver_lookup(('sysv','sysu','sysa'))
0583     # Decode the infos
0584     if sysv:
0585         major = (sysv & 0xFF00) >> 8
0586         minor = (sysv & 0x00F0) >> 4
0587         patch = (sysv & 0x000F)
0588         release = '%s.%i.%i' % (_bcd2str(major),minor,patch)
0589     if sysu:
0590         major =  int((sysu & 0xFF000000L) >> 24)
0591         minor =  (sysu & 0x00F00000) >> 20
0592         bugfix = (sysu & 0x000F0000) >> 16
0593         stage =  (sysu & 0x0000FF00) >> 8
0594         nonrel = (sysu & 0x000000FF)
0595         version = '%s.%i.%i' % (_bcd2str(major),minor,bugfix)
0596         nonrel = _bcd2str(nonrel)
0597         stage = {0x20:'development',
0598                  0x40:'alpha',
0599                  0x60:'beta',
0600                  0x80:'final'}.get(stage,'')
0601         versioninfo = (version,stage,nonrel)
0602     if sysa:
0603         machine = {0x1: '68k',
0604                    0x2: 'PowerPC'}.get(sysa,'')
0605     return release,versioninfo,machine
0606 
0607 def _java_getprop(name,default):
0608 
0609     from java.lang import System
0610     try:
0611         return System.getProperty(name)
0612     except:
0613         return default
0614 
0615 def java_ver(release='',vendor='',vminfo=('','',''),osinfo=('','','')):
0616 
0617     """ Version interface for Jython.
0618 
0619         Returns a tuple (release,vendor,vminfo,osinfo) with vminfo being
0620         a tuple (vm_name,vm_release,vm_vendor) and osinfo being a
0621         tuple (os_name,os_version,os_arch).
0622 
0623         Values which cannot be determined are set to the defaults
0624         given as parameters (which all default to '').
0625 
0626     """
0627     # Import the needed APIs
0628     try:
0629         import java.lang
0630     except ImportError:
0631         return release,vendor,vminfo,osinfo
0632 
0633     vendor = _java_getprop('java.vendor',vendor)
0634     release = _java_getprop('java.version',release)
0635     vm_name,vm_release,vm_vendor = vminfo
0636     vm_name = _java_getprop('java.vm.name',vm_name)
0637     vm_vendor = _java_getprop('java.vm.vendor',vm_vendor)
0638     vm_release = _java_getprop('java.vm.version',vm_release)
0639     vminfo = vm_name,vm_release,vm_vendor
0640     os_name,os_version,os_arch = osinfo
0641     os_arch = _java_getprop('java.os.arch',os_arch)
0642     os_name = _java_getprop('java.os.name',os_name)
0643     os_version = _java_getprop('java.os.version',os_version)
0644     osinfo = os_name,os_version,os_arch
0645 
0646     return release,vendor,vminfo,osinfo
0647 
0648 ### System name aliasing
0649 
0650 def system_alias(system,release,version):
0651 
0652     """ Returns (system,release,version) aliased to common
0653         marketing names used for some systems.
0654 
0655         It also does some reordering of the information in some cases
0656         where it would otherwise cause confusion.
0657 
0658     """
0659     if system == 'Rhapsody':
0660         # Apple's BSD derivative
0661         # XXX How can we determine the marketing release number ?
0662         return 'MacOS X Server',system+release,version
0663 
0664     elif system == 'SunOS':
0665         # Sun's OS
0666         if release < '5':
0667             # These releases use the old name SunOS
0668             return system,release,version
0669         # Modify release (marketing release = SunOS release - 3)
0670         l = string.split(release,'.')
0671         if l:
0672             try:
0673                 major = int(l[0])
0674             except ValueError:
0675                 pass
0676             else:
0677                 major = major - 3
0678                 l[0] = str(major)
0679                 release = string.join(l,'.')
0680         if release < '6':
0681             system = 'Solaris'
0682         else:
0683             # XXX Whatever the new SunOS marketing name is...
0684             system = 'Solaris'
0685 
0686     elif system == 'IRIX64':
0687         # IRIX reports IRIX64 on platforms with 64-bit support; yet it
0688         # is really a version and not a different platform, since 32-bit
0689         # apps are also supported..
0690         system = 'IRIX'
0691         if version:
0692             version = version + ' (64bit)'
0693         else:
0694             version = '64bit'
0695 
0696     elif system in ('win32','win16'):
0697         # In case one of the other tricks
0698         system = 'Windows'
0699 
0700     return system,release,version
0701 
0702 ### Various internal helpers
0703 
0704 def _platform(*args):
0705 
0706     """ Helper to format the platform string in a filename
0707         compatible format e.g. "system-version-machine".
0708     """
0709     # Format the platform string
0710     platform = string.join(
0711         map(string.strip,
0712             filter(len,args)),
0713         '-')
0714 
0715     # Cleanup some possible filename obstacles...
0716     replace = string.replace
0717     platform = replace(platform,' ','_')
0718     platform = replace(platform,'/','-')
0719     platform = replace(platform,'\\','-')
0720     platform = replace(platform,':','-')
0721     platform = replace(platform,';','-')
0722     platform = replace(platform,'"','-')
0723     platform = replace(platform,'(','-')
0724     platform = replace(platform,')','-')
0725 
0726     # No need to report 'unknown' information...
0727     platform = replace(platform,'unknown','')
0728 
0729     # Fold '--'s and remove trailing '-'
0730     while 1:
0731         cleaned = replace(platform,'--','-')
0732         if cleaned == platform:
0733             break
0734         platform = cleaned
0735     while platform[-1] == '-':
0736         platform = platform[:-1]
0737 
0738     return platform
0739 
0740 def _node(default=''):
0741 
0742     """ Helper to determine the node name of this machine.
0743     """
0744     try:
0745         import socket
0746     except ImportError:
0747         # No sockets...
0748         return default
0749     try:
0750         return socket.gethostname()
0751     except socket.error:
0752         # Still not working...
0753         return default
0754 
0755 # os.path.abspath is new in Python 1.5.2:
0756 if not hasattr(os.path,'abspath'):
0757 
0758     def _abspath(path,
0759 
0760                  isabs=os.path.isabs,join=os.path.join,getcwd=os.getcwd,
0761                  normpath=os.path.normpath):
0762 
0763         if not isabs(path):
0764             path = join(getcwd(), path)
0765         return normpath(path)
0766 
0767 else:
0768 
0769     _abspath = os.path.abspath
0770 
0771 def _follow_symlinks(filepath):
0772 
0773     """ In case filepath is a symlink, follow it until a
0774         real file is reached.
0775     """
0776     filepath = _abspath(filepath)
0777     while os.path.islink(filepath):
0778         filepath = os.path.normpath(
0779             os.path.join(filepath,os.readlink(filepath)))
0780     return filepath
0781 
0782 def _syscmd_uname(option,default=''):
0783 
0784     """ Interface to the system's uname command.
0785     """
0786     if sys.platform in ('dos','win32','win16','os2'):
0787         # XXX Others too ?
0788         return default
0789     try:
0790         f = os.popen('uname %s 2> /dev/null' % option)
0791     except (AttributeError,os.error):
0792         return default
0793     output = string.strip(f.read())
0794     rc = f.close()
0795     if not output or rc:
0796         return default
0797     else:
0798         return output
0799 
0800 def _syscmd_file(target,default=''):
0801 
0802     """ Interface to the system's file command.
0803 
0804         The function uses the -b option of the file command to have it
0805         ommit the filename in its output and if possible the -L option
0806         to have the command follow symlinks. It returns default in
0807         case the command should fail.
0808 
0809     """
0810     target = _follow_symlinks(target)
0811     try:
0812         f = os.popen('file %s 2> /dev/null' % target)
0813     except (AttributeError,os.error):
0814         return default
0815     output = string.strip(f.read())
0816     rc = f.close()
0817     if not output or rc:
0818         return default
0819     else:
0820         return output
0821 
0822 ### Information about the used architecture
0823 
0824 # Default values for architecture; non-empty strings override the
0825 # defaults given as parameters
0826 _default_architecture = {
0827     'win32': ('','WindowsPE'),
0828     'win16': ('','Windows'),
0829     'dos': ('','MSDOS'),
0830 }
0831 
0832 _architecture_split = re.compile(r'[\s,]').split
0833 
0834 def architecture(executable=sys.executable,bits='',linkage=''):
0835 
0836     """ Queries the given executable (defaults to the Python interpreter
0837         binary) for various architecture information.
0838 
0839         Returns a tuple (bits,linkage) which contains information about
0840         the bit architecture and the linkage format used for the
0841         executable. Both values are returned as strings.
0842 
0843         Values that cannot be determined are returned as given by the
0844         parameter presets. If bits is given as '', the sizeof(pointer)
0845         (or sizeof(long) on Python version < 1.5.2) is used as
0846         indicator for the supported pointer size.
0847 
0848         The function relies on the system's "file" command to do the
0849         actual work. This is available on most if not all Unix
0850         platforms. On some non-Unix platforms where the "file" command
0851         does not exist and the executable is set to the Python interpreter
0852         binary defaults from _default_architecture are used.
0853 
0854     """
0855     # Use the sizeof(pointer) as default number of bits if nothing
0856     # else is given as default.
0857     if not bits:
0858         import struct
0859         try:
0860             size = struct.calcsize('P')
0861         except struct.error:
0862             # Older installations can only query longs
0863             size = struct.calcsize('l')
0864         bits = str(size*8) + 'bit'
0865 
0866     # Get data from the 'file' system command
0867     output = _syscmd_file(executable,'')
0868 
0869     if not output and \
0870        executable == sys.executable:
0871         # "file" command did not return anything; we'll try to provide
0872         # some sensible defaults then...
0873         if _default_architecture.has_key(sys.platform):
0874             b,l = _default_architecture[sys.platform]
0875             if b:
0876                 bits = b
0877             if l:
0878                 linkage = l
0879         return bits,linkage
0880 
0881     # Split the output into a list of strings omitting the filename
0882     fileout = _architecture_split(output)[1:]
0883 
0884     if 'executable' not in fileout:
0885         # Format not supported
0886         return bits,linkage
0887 
0888     # Bits
0889     if '32-bit' in fileout:
0890         bits = '32bit'
0891     elif 'N32' in fileout:
0892         # On Irix only
0893         bits = 'n32bit'
0894     elif '64-bit' in fileout:
0895         bits = '64bit'
0896 
0897     # Linkage
0898     if 'ELF' in fileout:
0899         linkage = 'ELF'
0900     elif 'PE' in fileout:
0901         # E.g. Windows uses this format
0902         if 'Windows' in fileout:
0903             linkage = 'WindowsPE'
0904         else:
0905             linkage = 'PE'
0906     elif 'COFF' in fileout:
0907         linkage = 'COFF'
0908     elif 'MS-DOS' in fileout:
0909         linkage = 'MSDOS'
0910     else:
0911         # XXX the A.OUT format also falls under this class...
0912         pass
0913 
0914     return bits,linkage
0915 
0916 ### Portable uname() interface
0917 
0918 _uname_cache = None
0919 
0920 def uname():
0921 
0922     """ Fairly portable uname interface. Returns a tuple
0923         of strings (system,node,release,version,machine,processor)
0924         identifying the underlying platform.
0925 
0926         Note that unlike the os.uname function this also returns
0927         possible processor information as an additional tuple entry.
0928 
0929         Entries which cannot be determined are set to ''.
0930 
0931     """
0932     global _uname_cache
0933 
0934     if _uname_cache is not None:
0935         return _uname_cache
0936 
0937     # Get some infos from the builtin os.uname API...
0938     try:
0939         system,node,release,version,machine = os.uname()
0940 
0941     except AttributeError:
0942         # Hmm, no uname... we'll have to poke around the system then.
0943         system = sys.platform
0944         release = ''
0945         version = ''
0946         node = _node()
0947         machine = ''
0948         processor = ''
0949         use_syscmd_ver = 1
0950 
0951         # Try win32_ver() on win32 platforms
0952         if system == 'win32':
0953             release,version,csd,ptype = win32_ver()
0954             if release and version:
0955                 use_syscmd_ver = 0
0956 
0957         # Try the 'ver' system command available on some
0958         # platforms
0959         if use_syscmd_ver:
0960             system,release,version = _syscmd_ver(system)
0961             # Normalize system to what win32_ver() normally returns
0962             # (_syscmd_ver() tends to return the vendor name as well)
0963             if system == 'Microsoft Windows':
0964                 system = 'Windows'
0965 
0966         # In case we still don't know anything useful, we'll try to
0967         # help ourselves
0968         if system in ('win32','win16'):
0969             if not version:
0970                 if system == 'win32':
0971                     version = '32bit'
0972                 else:
0973                     version = '16bit'
0974             system = 'Windows'
0975 
0976         elif system[:4] == 'java':
0977             release,vendor,vminfo,osinfo = java_ver()
0978             system = 'Java'
0979             version = string.join(vminfo,', ')
0980             if not version:
0981                 version = vendor
0982 
0983         elif os.name == 'mac':
0984             release,(version,stage,nonrel),machine = mac_ver()
0985             system = 'MacOS'
0986 
0987     else:
0988         # System specific extensions
0989         if system == 'OpenVMS':
0990             # OpenVMS seems to have release and version mixed up
0991             if not release or release == '0':
0992                 release = version
0993                 version = ''
0994             # Get processor information
0995             try:
0996                 import vms_lib
0997             except ImportError:
0998                 pass
0999             else:
1000                 csid, cpu_number = vms_lib.getsyi('SYI$_CPU',0)
1001                 if (cpu_number >= 128):
1002                     processor = 'Alpha'
1003                 else:
1004                     processor = 'VAX'
1005         else:
1006             # Get processor information from the uname system command
1007             processor = _syscmd_uname('-p','')
1008 
1009     # 'unknown' is not really any useful as information; we'll convert
1010     # it to '' which is more portable
1011     if system == 'unknown':
1012         system = ''
1013     if node == 'unknown':
1014         node = ''
1015     if release == 'unknown':
1016         release = ''
1017     if version == 'unknown':
1018         version = ''
1019     if machine == 'unknown':
1020         machine = ''
1021     if processor == 'unknown':
1022         processor = ''
1023     _uname_cache = system,node,release,version,machine,processor
1024     return _uname_cache
1025 
1026 ### Direct interfaces to some of the uname() return values
1027 
1028 def system():
1029 
1030     """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.
1031 
1032         An empty string is returned if the value cannot be determined.
1033 
1034     """
1035     return uname()[0]
1036 
1037 def node():
1038 
1039     """ Returns the computer's network name (which may not be fully
1040         qualified)
1041 
1042         An empty string is returned if the value cannot be determined.
1043 
1044     """
1045     return uname()[1]
1046 
1047 def release():
1048 
1049     """ Returns the system's release, e.g. '2.2.0' or 'NT'
1050 
1051         An empty string is returned if the value cannot be determined.
1052 
1053     """
1054     return uname()[2]
1055 
1056 def version():
1057 
1058     """ Returns the system's release version, e.g. '#3 on degas'
1059 
1060         An empty string is returned if the value cannot be determined.
1061 
1062     """
1063     return uname()[3]
1064 
1065 def machine():
1066 
1067     """ Returns the machine type, e.g. 'i386'
1068 
1069         An empty string is returned if the value cannot be determined.
1070 
1071     """
1072     return uname()[4]
1073 
1074 def processor():
1075 
1076     """ Returns the (true) processor name, e.g. 'amdk6'
1077 
1078         An empty string is returned if the value cannot be
1079         determined. Note that many platforms do not provide this
1080         information or simply return the same value as for machine(),
1081         e.g.  NetBSD does this.
1082 
1083     """
1084     return uname()[5]
1085 
1086 ### Various APIs for extracting information from sys.version
1087 
1088 _sys_version_parser = re.compile(r'([\w.+]+)\s*'
1089                                   '\(#(\d+),\s*([\w ]+),\s*([\w :]+)\)\s*'
1090                                   '\[([^\]]+)\]?')
1091 _sys_version_cache = None
1092 
1093 def _sys_version():
1094 
1095     """ Returns a parsed version of Python's sys.version as tuple
1096         (version, buildno, builddate, compiler) referring to the Python
1097         version, build number, build date/time as string and the compiler
1098         identification string.
1099 
1100         Note that unlike the Python sys.version, the returned value
1101         for the Python version will always include the patchlevel (it
1102         defaults to '.0').
1103 
1104     """
1105     global _sys_version_cache
1106 
1107     if _sys_version_cache is not None:
1108         return _sys_version_cache
1109     version, buildno, builddate, buildtime, compiler = \
1110              _sys_version_parser.match(sys.version).groups()
1111     buildno = int(buildno)
1112     builddate = builddate + ' ' + buildtime
1113     l = string.split(version, '.')
1114     if len(l) == 2:
1115         l.append('0')
1116         version = string.join(l, '.')
1117     _sys_version_cache = (version, buildno, builddate, compiler)
1118     return _sys_version_cache
1119 
1120 def python_version():
1121 
1122     """ Returns the Python version as string 'major.minor.patchlevel'
1123 
1124         Note that unlike the Python sys.version, the returned value
1125         will always include the patchlevel (it defaults to 0).
1126 
1127     """
1128     return _sys_version()[0]
1129 
1130 def python_version_tuple():
1131 
1132     """ Returns the Python version as tuple (major, minor, patchlevel)
1133         of strings.
1134 
1135         Note that unlike the Python sys.version, the returned value
1136         will always include the patchlevel (it defaults to 0).
1137 
1138     """
1139     return string.split(_sys_version()[0], '.')
1140 
1141 def python_build():
1142 
1143     """ Returns a tuple (buildno, builddate) stating the Python
1144         build number and date as strings.
1145 
1146     """
1147     return _sys_version()[1:3]
1148 
1149 def python_compiler():
1150 
1151     """ Returns a string identifying the compiler used for compiling
1152         Python.
1153 
1154     """
1155     return _sys_version()[3]
1156 
1157 ### The Opus Magnum of platform strings :-)
1158 
1159 _platform_cache = {}
1160 
1161 def platform(aliased=0, terse=0):
1162 
1163     """ Returns a single string identifying the underlying platform
1164         with as much useful information as possible (but no more :).
1165 
1166         The output is intended to be human readable rather than
1167         machine parseable. It may look different on different
1168         platforms and this is intended.
1169 
1170         If "aliased" is true, the function will use aliases for
1171         various platforms that report system names which differ from
1172         their common names, e.g. SunOS will be reported as
1173         Solaris. The system_alias() function is used to implement
1174         this.
1175 
1176         Setting terse to true causes the function to return only the
1177         absolute minimum information needed to identify the platform.
1178 
1179     """
1180     result = _platform_cache.get((aliased, terse), None)
1181     if result is not None:
1182         return result
1183 
1184     # Get uname information and then apply platform specific cosmetics
1185     # to it...
1186     system,node,release,version,machine,processor = uname()
1187     if machine == processor:
1188         processor = ''
1189     if aliased:
1190         system,release,version = system_alias(system,release,version)
1191 
1192     if system == 'Windows':
1193         # MS platforms
1194         rel,vers,csd,ptype = win32_ver(version)
1195         if terse:
1196             platform = _platform(system,release)
1197         else:
1198             platform = _platform(system,release,version,csd)
1199 
1200     elif system in ('Linux',):
1201         # Linux based systems
1202         distname,distversion,distid = dist('')
1203         if distname and not terse:
1204             platform = _platform(system,release,machine,processor,
1205                                  'with',
1206                                  distname,distversion,distid)
1207         else:
1208             # If the distribution name is unknown check for libc vs. glibc
1209             libcname,libcversion = libc_ver(sys.executable)
1210             platform = _platform(system,release,machine,processor,
1211                                  'with',
1212                                  libcname+libcversion)
1213     elif system == 'Java':
1214         # Java platforms
1215         r,v,vminfo,(os_name,os_version,os_arch) = java_ver()
1216         if terse:
1217             platform = _platform(system,release,version)
1218         else:
1219             platform = _platform(system,release,version,
1220                                  'on',
1221                                  os_name,os_version,os_arch)
1222 
1223     elif system == 'MacOS':
1224         # MacOS platforms
1225         if terse:
1226             platform = _platform(system,release)
1227         else:
1228             platform = _platform(system,release,machine)
1229 
1230     else:
1231         # Generic handler
1232         if terse:
1233             platform = _platform(system,release)
1234         else:
1235             bits,linkage = architecture(sys.executable)
1236             platform = _platform(system,release,machine,processor,bits,linkage)
1237 
1238     _platform_cache[(aliased, terse)] = platform
1239     return platform
1240 
1241 ### Command line interface
1242 
1243 if __name__ == '__main__':
1244     # Default is to print the aliased verbose platform string
1245     terse = ('terse' in sys.argv or '--terse' in sys.argv)
1246     aliased = (not 'nonaliased' in sys.argv and not '--nonaliased' in sys.argv)
1247     print platform(aliased,terse)
1248     sys.exit(0)
1249 

Generated by PyXR 0.9.4
SourceForge.net Logo