diff options
Diffstat (limited to 'Lib/platform.py')
-rwxr-xr-x | Lib/platform.py | 169 |
1 files changed, 59 insertions, 110 deletions
diff --git a/Lib/platform.py b/Lib/platform.py index 686a045845..030ef2a3a4 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -111,6 +111,7 @@ __copyright__ = """ __version__ = '1.0.7' +import collections import sys, os, re, subprocess ### Globals & Constants @@ -128,17 +129,21 @@ except AttributeError: # Standard Unix uses /dev/null DEV_NULL = '/dev/null' +# Directory to search for configuration information on Unix. +# Constant used by test_platform to test linux_distribution(). +_UNIXCONFDIR = '/etc' + ### Platform specific APIs -_libc_search = re.compile(r'(__libc_init)' - '|' - '(GLIBC_([0-9.]+))' - '|' - '(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII) +_libc_search = re.compile(b'(__libc_init)' + b'|' + b'(GLIBC_([0-9.]+))' + b'|' + br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII) def libc_ver(executable=sys.executable,lib='',version='', - chunksize=2048): + chunksize=16384): """ Tries to determine the libc version that the file executable (which defaults to the Python interpreter) is linked against. @@ -159,17 +164,22 @@ def libc_ver(executable=sys.executable,lib='',version='', # able to open symlinks for reading executable = os.path.realpath(executable) f = open(executable,'rb') - binary = f.read(chunksize).decode('latin-1') + binary = f.read(chunksize) pos = 0 while 1: - m = _libc_search.search(binary,pos) + if b'libc' in binary or b'GLIBC' in binary: + m = _libc_search.search(binary,pos) + else: + m = None if not m: - binary = f.read(chunksize).decode('latin-1') + binary = f.read(chunksize) if not binary: break pos = 0 continue - libcinit,glibc,glibcversion,so,threads,soversion = m.groups() + libcinit,glibc,glibcversion,so,threads,soversion = [ + s.decode('latin1') if s is not None else s + for s in m.groups()] if libcinit and not lib: lib = 'libc' elif glibc: @@ -224,7 +234,7 @@ def _dist_try_harder(distname,version,id): return 'OpenLinux',pkg[1],id if os.path.isdir('/usr/lib/setup'): - # Check for slackware verson tag file (thanks to Greg Andruk) + # Check for slackware version tag file (thanks to Greg Andruk) verfiles = os.listdir('/usr/lib/setup') for n in range(len(verfiles)-1, -1, -1): if verfiles[n][:14] != 'slack-version-': @@ -255,7 +265,7 @@ _release_version = re.compile(r'([^0-9]+)' _supported_dists = ( 'SuSE', 'debian', 'fedora', 'redhat', 'centos', 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo', - 'UnitedLinux', 'turbolinux') + 'UnitedLinux', 'turbolinux', 'arch', 'mageia') def _parse_release_file(firstline): @@ -276,7 +286,7 @@ def _parse_release_file(firstline): if m is not None: return tuple(m.groups()) - # Unkown format... take the first two words + # Unknown format... take the first two words l = firstline.strip().split() if l: version = l[0] @@ -309,7 +319,7 @@ def linux_distribution(distname='', version='', id='', """ try: - etc = os.listdir('/etc') + etc = os.listdir(_UNIXCONFDIR) except os.error: # Probably not a Unix system return distname,version,id @@ -325,7 +335,8 @@ def linux_distribution(distname='', version='', id='', return _dist_try_harder(distname,version,id) # Read the first line - with open('/etc/'+file, 'r') as f: + with open(os.path.join(_UNIXCONFDIR, file), 'r', + encoding='utf-8', errors='surrogateescape') as f: firstline = f.readline() _distname, _version, _id = _parse_release_file(firstline) @@ -357,92 +368,13 @@ def dist(distname='',version='',id='', supported_dists=supported_dists, full_distribution_name=0) -class _popen: - - """ Fairly portable (alternative) popen implementation. - - This is mostly needed in case os.popen() is not available, or - doesn't work as advertised, e.g. in Win9X GUI programs like - PythonWin or IDLE. - - Writing to the pipe is currently not supported. - - """ - tmpfile = '' - pipe = None - bufsize = None - mode = 'r' - - def __init__(self,cmd,mode='r',bufsize=None): - - if mode != 'r': - raise ValueError('popen()-emulation only supports read mode') - import tempfile - self.tmpfile = tmpfile = tempfile.mktemp() - os.system(cmd + ' > %s' % tmpfile) - self.pipe = open(tmpfile,'rb') - self.bufsize = bufsize - self.mode = mode - - def read(self): - - return self.pipe.read() - - def readlines(self): - - if self.bufsize is not None: - return self.pipe.readlines() - - def close(self, - - remove=os.unlink,error=os.error): - - if self.pipe: - rc = self.pipe.close() - else: - rc = 255 - if self.tmpfile: - try: - remove(self.tmpfile) - except error: - pass - return rc - - # Alias - __del__ = close - def popen(cmd, mode='r', bufsize=-1): """ Portable popen() interface. """ - # Find a working popen implementation preferring win32pipe.popen - # over os.popen over _popen - popen = None - if os.environ.get('OS','') == 'Windows_NT': - # On NT win32pipe should work; on Win9x it hangs due to bugs - # in the MS C lib (see MS KnowledgeBase article Q150956) - try: - import win32pipe - except ImportError: - pass - else: - popen = win32pipe.popen - if popen is None: - if hasattr(os,'popen'): - popen = os.popen - # Check whether it works... it doesn't in GUI programs - # on Windows platforms - if sys.platform == 'win32': # XXX Others too ? - try: - popen('') - except os.error: - popen = _popen - else: - popen = _popen - if bufsize is None: - return popen(cmd,mode) - else: - return popen(cmd,mode,bufsize) + import warnings + warnings.warn('use os.popen instead', DeprecationWarning, stacklevel=2) + return os.popen(cmd, mode, bufsize) def _norm_version(version, build=''): @@ -779,7 +711,7 @@ def _mac_ver_xml(): pl = plistlib.readPlist(fn) release = pl['ProductVersion'] versioninfo=('', '', '') - machine = os.uname()[4] + machine = os.uname().machine if machine in ('ppc', 'Power Macintosh'): # for compatibility with the gestalt based code machine = 'PowerPC' @@ -793,7 +725,7 @@ def mac_ver(release='',versioninfo=('','',''),machine=''): versioninfo, machine) with versioninfo being a tuple (version, dev_stage, non_release_version). - Entries which cannot be determined are set to the paramter values + Entries which cannot be determined are set to the parameter values which default to ''. All tuple entries are strings. """ @@ -1004,9 +936,10 @@ def _syscmd_file(target,default=''): try: proc = subprocess.Popen(['file', target], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except (AttributeError,os.error): return default - output = proc.communicate()[0].decode("latin-1") + output = proc.communicate()[0].decode('latin-1') rc = proc.wait() if not output or rc: return default @@ -1107,6 +1040,9 @@ def architecture(executable=sys.executable,bits='',linkage=''): ### Portable uname() interface +uname_result = collections.namedtuple("uname_result", + "system node release version machine processor") + _uname_cache = None def uname(): @@ -1241,7 +1177,7 @@ def uname(): system = 'Windows' release = 'Vista' - _uname_cache = system,node,release,version,machine,processor + _uname_cache = uname_result(system,node,release,version,machine,processor) return _uname_cache ### Direct interfaces to some of the uname() return values @@ -1253,7 +1189,7 @@ def system(): An empty string is returned if the value cannot be determined. """ - return uname()[0] + return uname().system def node(): @@ -1263,7 +1199,7 @@ def node(): An empty string is returned if the value cannot be determined. """ - return uname()[1] + return uname().node def release(): @@ -1272,7 +1208,7 @@ def release(): An empty string is returned if the value cannot be determined. """ - return uname()[2] + return uname().release def version(): @@ -1281,7 +1217,7 @@ def version(): An empty string is returned if the value cannot be determined. """ - return uname()[3] + return uname().version def machine(): @@ -1290,7 +1226,7 @@ def machine(): An empty string is returned if the value cannot be determined. """ - return uname()[4] + return uname().machine def processor(): @@ -1302,7 +1238,7 @@ def processor(): e.g. NetBSD does this. """ - return uname()[5] + return uname().processor ### Various APIs for extracting information from sys.version @@ -1317,6 +1253,14 @@ _ironpython_sys_version_parser = re.compile( '(?: \(([\d\.]+)\))?' ' on (.NET [\d\.]+)', re.ASCII) +# IronPython covering 2.6 and 2.7 +_ironpython26_sys_version_parser = re.compile( + r'([\d.]+)\s*' + '\(IronPython\s*' + '[\d.]+\s*' + '\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)' +) + _pypy_sys_version_parser = re.compile( r'([\w.+]+)\s*' '\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*' @@ -1354,19 +1298,24 @@ def _sys_version(sys_version=None): return result # Parse it - if sys_version[:10] == 'IronPython': + if 'IronPython' in sys_version: # IronPython name = 'IronPython' - match = _ironpython_sys_version_parser.match(sys_version) + if sys_version.startswith('IronPython'): + match = _ironpython_sys_version_parser.match(sys_version) + else: + match = _ironpython26_sys_version_parser.match(sys_version) + if match is None: raise ValueError( 'failed to parse IronPython sys.version: %s' % repr(sys_version)) + version, alt_version, compiler = match.groups() buildno = '' builddate = '' - elif sys.platform[:4] == 'java': + elif sys.platform.startswith('java'): # Jython name = 'Jython' match = _sys_version_parser.match(sys_version) |