[Python-checkins] r74026 - in python/branches/py3k: Lib/distutils/cygwinccompiler.py Lib/distutils/emxccompiler.py Lib/distutils/tests/test_cygwinccompiler.py Lib/distutils/tests/test_emxccompiler.py Lib/distutils/tests/test_util.py Lib/distutils/util.py Misc/NEWS

tarek.ziade python-checkins at python.org
Thu Jul 16 18:18:19 CEST 2009


Author: tarek.ziade
Date: Thu Jul 16 18:18:19 2009
New Revision: 74026

Log:
Merged revisions 74024 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r74024 | tarek.ziade | 2009-07-16 17:35:45 +0200 (Thu, 16 Jul 2009) | 1 line
  
  #6466 refactored distutils duplicate get_versions() functions (used to get gcc/ld/dllwrap versions)
........


Added:
   python/branches/py3k/Lib/distutils/tests/test_emxccompiler.py
      - copied, changed from r74024, /python/trunk/Lib/distutils/tests/test_emxccompiler.py
Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Lib/distutils/cygwinccompiler.py
   python/branches/py3k/Lib/distutils/emxccompiler.py
   python/branches/py3k/Lib/distutils/tests/test_cygwinccompiler.py
   python/branches/py3k/Lib/distutils/tests/test_util.py
   python/branches/py3k/Lib/distutils/util.py
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Lib/distutils/cygwinccompiler.py
==============================================================================
--- python/branches/py3k/Lib/distutils/cygwinccompiler.py	(original)
+++ python/branches/py3k/Lib/distutils/cygwinccompiler.py	Thu Jul 16 18:18:19 2009
@@ -50,16 +50,15 @@
 import os
 import sys
 import copy
-from subprocess import Popen, PIPE
 import re
+from warnings import warn
 
 from distutils.ccompiler import gen_preprocess_options, gen_lib_options
 from distutils.unixccompiler import UnixCCompiler
 from distutils.file_util import write_file
 from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
 from distutils import log
-from distutils.version import LooseVersion
-from distutils.spawn import find_executable
+from distutils.util import get_compiler_versions
 
 def get_msvcr():
     """Include the appropriate MSVC runtime library if Python was built
@@ -110,7 +109,7 @@
                 % details)
 
         self.gcc_version, self.ld_version, self.dllwrap_version = \
-            get_versions()
+            get_compiler_versions()
         self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
                          (self.gcc_version,
                           self.ld_version,
@@ -359,33 +358,27 @@
         return (CONFIG_H_UNCERTAIN,
                 "couldn't read '%s': %s" % (fn, exc.strerror))
 
-RE_VERSION = re.compile(b'(\d+\.\d+(\.\d+)*)')
+class _Deprecated_SRE_Pattern(object):
+    def __init__(self, pattern):
+        self.pattern = pattern
+
+    def __getattr__(self, name):
+        if name in ('findall', 'finditer', 'match', 'scanner', 'search',
+                    'split', 'sub', 'subn'):
+            warn("'distutils.cygwinccompiler.RE_VERSION' is deprecated "
+                 "and will be removed in the next version", DeprecationWarning)
+        return getattr(self.pattern, name)
 
-def _find_exe_version(cmd):
-    """Find the version of an executable by running `cmd` in the shell.
 
-    If the command is not found, or the output does not match
-    `RE_VERSION`, returns None.
-    """
-    executable = cmd.split()[0]
-    if find_executable(executable) is None:
-        return None
-    out = Popen(cmd, shell=True, stdout=PIPE).stdout
-    try:
-        out_string = out.read()
-    finally:
-        out.close()
-    result = RE_VERSION.search(out_string)
-    if result is None:
-        return None
-    # LooseVersion works with strings
-    # so we need to decode our bytes
-    return LooseVersion(result.group(1).decode())
+RE_VERSION = _Deprecated_SRE_Pattern(re.compile('(\d+\.\d+(\.\d+)*)'))
 
 def get_versions():
     """ Try to find out the versions of gcc, ld and dllwrap.
 
     If not possible it returns None for it.
     """
-    commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']
-    return tuple([_find_exe_version(cmd) for cmd in commands])
+    warn("'distutils.cygwinccompiler.get_versions' is deprecated "
+         "use 'distutils.util.get_compiler_versions' instead",
+         DeprecationWarning)
+
+    return get_compiler_versions()

Modified: python/branches/py3k/Lib/distutils/emxccompiler.py
==============================================================================
--- python/branches/py3k/Lib/distutils/emxccompiler.py	(original)
+++ python/branches/py3k/Lib/distutils/emxccompiler.py	Thu Jul 16 18:18:19 2009
@@ -21,12 +21,15 @@
 
 __revision__ = "$Id$"
 
-import os,sys,copy
+import os, sys, copy
+from warnings import warn
+
 from distutils.ccompiler import gen_preprocess_options, gen_lib_options
 from distutils.unixccompiler import UnixCCompiler
 from distutils.file_util import write_file
 from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
 from distutils import log
+from distutils.util import get_compiler_versions
 
 class EMXCCompiler (UnixCCompiler):
 
@@ -55,8 +58,8 @@
                 ("Reason: %s." % details) +
                 "Compiling may fail because of undefined preprocessor macros.")
 
-        (self.gcc_version, self.ld_version) = \
-            get_versions()
+        gcc_version, ld_version, dllwrap_version = get_compiler_versions()
+        self.gcc_version, self.ld_version = gcc_version, ld_version
         self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" %
                          (self.gcc_version,
                           self.ld_version) )
@@ -291,23 +294,11 @@
     """ Try to find out the versions of gcc and ld.
         If not possible it returns None for it.
     """
-    from distutils.version import StrictVersion
-    from distutils.spawn import find_executable
-    import re
-
-    gcc_exe = find_executable('gcc')
-    if gcc_exe:
-        out = os.popen(gcc_exe + ' -dumpversion','r')
-        out_string = out.read()
-        out.close()
-        result = re.search('(\d+\.\d+\.\d+)', out_string, re.ASCII)
-        if result:
-            gcc_version = StrictVersion(result.group(1))
-        else:
-            gcc_version = None
-    else:
-        gcc_version = None
+    warn("'distutils.emxccompiler.get_versions' is deprecated "
+         "use 'distutils.util.get_compiler_versions' instead",
+         DeprecationWarning)
+
     # EMX ld has no way of reporting version number, and we use GCC
     # anyway - so we can link OMF DLLs
-    ld_version = None
-    return (gcc_version, ld_version)
+    gcc_version, ld_version, dllwrap_version = get_compiler_versions()
+    return gcc_version, None

Modified: python/branches/py3k/Lib/distutils/tests/test_cygwinccompiler.py
==============================================================================
--- python/branches/py3k/Lib/distutils/tests/test_cygwinccompiler.py	(original)
+++ python/branches/py3k/Lib/distutils/tests/test_cygwinccompiler.py	Thu Jul 16 18:18:19 2009
@@ -2,29 +2,20 @@
 import unittest
 import sys
 import os
-from io import BytesIO
 import subprocess
+import warnings
+
+from test.support import check_warnings
+from test.support import captured_stdout
 
 from distutils import cygwinccompiler
 from distutils.cygwinccompiler import (CygwinCCompiler, check_config_h,
                                        CONFIG_H_OK, CONFIG_H_NOTOK,
                                        CONFIG_H_UNCERTAIN, get_versions,
-                                       get_msvcr)
+                                       get_msvcr, RE_VERSION)
+from distutils.util import get_compiler_versions
 from distutils.tests import support
 
-class FakePopen(object):
-    test_class = None
-
-    def __init__(self, cmd, shell, stdout):
-        self.cmd = cmd.split()[0]
-        exes = self.test_class._exes
-        if self.cmd in exes:
-            # issue #6438 in Python 3.x, Popen returns bytes
-            self.stdout = BytesIO(exes[self.cmd])
-        else:
-            self.stdout = os.popen(cmd, 'r')
-
-
 class CygwinCCompilerTestCase(support.TempdirManager,
                               unittest.TestCase):
 
@@ -35,29 +26,16 @@
         from distutils import sysconfig
         self.old_get_config_h_filename = sysconfig.get_config_h_filename
         sysconfig.get_config_h_filename = self._get_config_h_filename
-        self.old_find_executable = cygwinccompiler.find_executable
-        cygwinccompiler.find_executable = self._find_executable
-        self._exes = {}
-        self.old_popen = cygwinccompiler.Popen
-        FakePopen.test_class = self
-        cygwinccompiler.Popen = FakePopen
 
     def tearDown(self):
         sys.version = self.version
         from distutils import sysconfig
         sysconfig.get_config_h_filename = self.old_get_config_h_filename
-        cygwinccompiler.find_executable = self.old_find_executable
-        cygwinccompiler.Popen = self.old_popen
         super(CygwinCCompilerTestCase, self).tearDown()
 
     def _get_config_h_filename(self):
         return self.python_h
 
-    def _find_executable(self, name):
-        if name in self._exes:
-            return name
-        return None
-
     def test_check_config_h(self):
 
         # check_config_h looks for "GCC" in sys.version first
@@ -81,40 +59,6 @@
         self.write_file(self.python_h, 'xxx __GNUC__ xxx')
         self.assertEquals(check_config_h()[0], CONFIG_H_OK)
 
-    def test_get_versions(self):
-
-        # get_versions calls distutils.spawn.find_executable on
-        # 'gcc', 'ld' and 'dllwrap'
-        self.assertEquals(get_versions(), (None, None, None))
-
-        # Let's fake we have 'gcc' and it returns '3.4.5'
-        self._exes['gcc'] = b'gcc (GCC) 3.4.5 (mingw special)\nFSF'
-        res = get_versions()
-        self.assertEquals(str(res[0]), '3.4.5')
-
-        # and let's see what happens when the version
-        # doesn't match the regular expression
-        # (\d+\.\d+(\.\d+)*)
-        self._exes['gcc'] = b'very strange output'
-        res = get_versions()
-        self.assertEquals(res[0], None)
-
-        # same thing for ld
-        self._exes['ld'] = b'GNU ld version 2.17.50 20060824'
-        res = get_versions()
-        self.assertEquals(str(res[1]), '2.17.50')
-        self._exes['ld'] = b'@(#)PROGRAM:ld  PROJECT:ld64-77'
-        res = get_versions()
-        self.assertEquals(res[1], None)
-
-        # and dllwrap
-        self._exes['dllwrap'] = b'GNU dllwrap 2.17.50 20060824\nFSF'
-        res = get_versions()
-        self.assertEquals(str(res[2]), '2.17.50')
-        self._exes['dllwrap'] = b'Cheese Wrap'
-        res = get_versions()
-        self.assertEquals(res[2], None)
-
     def test_get_msvcr(self):
 
         # none
@@ -147,6 +91,21 @@
                        '[MSC v.1999 32 bits (Intel)]')
         self.assertRaises(ValueError, get_msvcr)
 
+
+    def test_get_version_deprecated(self):
+        with check_warnings() as w:
+            warnings.simplefilter("always")
+            # make sure get_compiler_versions and get_versions
+            # returns the same thing
+            self.assertEquals(get_compiler_versions(), get_versions())
+            # make sure using get_version() generated a warning
+            self.assertEquals(len(w.warnings), 1)
+            # make sure any usage of RE_VERSION will also
+            # generate a warning, but till works
+            version = RE_VERSION.search('1.2').group(1)
+            self.assertEquals(version, '1.2')
+            self.assertEquals(len(w.warnings), 2)
+
 def test_suite():
     return unittest.makeSuite(CygwinCCompilerTestCase)
 

Copied: python/branches/py3k/Lib/distutils/tests/test_emxccompiler.py (from r74024, /python/trunk/Lib/distutils/tests/test_emxccompiler.py)
==============================================================================
--- /python/trunk/Lib/distutils/tests/test_emxccompiler.py	(original)
+++ python/branches/py3k/Lib/distutils/tests/test_emxccompiler.py	Thu Jul 16 18:18:19 2009
@@ -4,8 +4,8 @@
 import os
 import warnings
 
-from test.test_support import check_warnings
-from test.test_support import captured_stdout
+from test.support import check_warnings
+from test.support import captured_stdout
 
 from distutils.emxccompiler import get_versions
 from distutils.util import get_compiler_versions

Modified: python/branches/py3k/Lib/distutils/tests/test_util.py
==============================================================================
--- python/branches/py3k/Lib/distutils/tests/test_util.py	(original)
+++ python/branches/py3k/Lib/distutils/tests/test_util.py	Thu Jul 16 18:18:19 2009
@@ -6,15 +6,33 @@
 import sys
 import unittest
 from copy import copy
+from io import BytesIO
+import subprocess
 
 from distutils.errors import DistutilsPlatformError
 from distutils.util import (get_platform, convert_path, change_root,
                             check_environ, split_quoted, strtobool,
-                            rfc822_escape)
-from distutils import util # used to patch _environ_checked
+                            rfc822_escape, get_compiler_versions,
+                            _find_exe_version, _MAC_OS_X_LD_VERSION)
+from distutils import util
 from distutils.sysconfig import get_config_vars
 from distutils import sysconfig
 from distutils.tests import support
+from distutils.version import LooseVersion
+
+class FakePopen(object):
+    test_class = None
+    def __init__(self, cmd, shell, stdout, stderr):
+        self.cmd = cmd.split()[0]
+        exes = self.test_class._exes
+        if self.cmd not in exes:
+            # we don't want to call the system, returning an empty
+            # output so it doesn't match
+            self.stdout = BytesIO()
+            self.stderr = BytesIO()
+        else:
+            self.stdout = BytesIO(exes[self.cmd])
+            self.stderr = BytesIO()
 
 class UtilTestCase(support.EnvironGuard, unittest.TestCase):
 
@@ -37,9 +55,16 @@
         else:
             self.uname = None
             self._uname = None
-
         os.uname = self._get_uname
 
+        # patching POpen
+        self.old_find_executable = util.find_executable
+        util.find_executable = self._find_executable
+        self._exes = {}
+        self.old_popen = subprocess.Popen
+        FakePopen.test_class = self
+        subprocess.Popen = FakePopen
+
     def tearDown(self):
         # getting back the environment
         os.name = self.name
@@ -54,6 +79,8 @@
         else:
             del os.uname
         sysconfig._config_vars = copy(self._config_vars)
+        util.find_executable = self.old_find_executable
+        subprocess.Popen = self.old_popen
         super(UtilTestCase, self).tearDown()
 
     def _set_uname(self, uname):
@@ -237,6 +264,70 @@
                   'header%(8s)s') % {'8s': '\n'+8*' '}
         self.assertEquals(res, wanted)
 
+    def test_find_exe_version(self):
+        # the ld version scheme under MAC OS is:
+        #   ^@(#)PROGRAM:ld  PROJECT:ld64-VERSION
+        #
+        # where VERSION is a 2-digit number for major
+        # revisions. For instance under Leopard, it's
+        # currently 77
+        #
+        # Dots are used when branching is done.
+        #
+        # The SnowLeopard ld64 is currently 95.2.12
+
+        for output, version in ((b'@(#)PROGRAM:ld  PROJECT:ld64-77', '77'),
+                                (b'@(#)PROGRAM:ld  PROJECT:ld64-95.2.12',
+                                 '95.2.12')):
+            result = _MAC_OS_X_LD_VERSION.search(output)
+            self.assertEquals(result.group(1).decode(), version)
+
+    def _find_executable(self, name):
+        if name in self._exes:
+            return name
+        return None
+
+    def test_get_compiler_versions(self):
+        # get_versions calls distutils.spawn.find_executable on
+        # 'gcc', 'ld' and 'dllwrap'
+        self.assertEquals(get_compiler_versions(), (None, None, None))
+
+        # Let's fake we have 'gcc' and it returns '3.4.5'
+        self._exes['gcc'] = b'gcc (GCC) 3.4.5 (mingw special)\nFSF'
+        res = get_compiler_versions()
+        self.assertEquals(str(res[0]), '3.4.5')
+
+        # and let's see what happens when the version
+        # doesn't match the regular expression
+        # (\d+\.\d+(\.\d+)*)
+        self._exes['gcc'] = b'very strange output'
+        res = get_compiler_versions()
+        self.assertEquals(res[0], None)
+
+        # same thing for ld
+        if sys.platform != 'darwin':
+            self._exes['ld'] = b'GNU ld version 2.17.50 20060824'
+            res = get_compiler_versions()
+            self.assertEquals(str(res[1]), '2.17.50')
+            self._exes['ld'] = b'@(#)PROGRAM:ld  PROJECT:ld64-77'
+            res = get_compiler_versions()
+            self.assertEquals(res[1], None)
+        else:
+            self._exes['ld'] = b'GNU ld version 2.17.50 20060824'
+            res = get_compiler_versions()
+            self.assertEquals(res[1], None)
+            self._exes['ld'] = b'@(#)PROGRAM:ld  PROJECT:ld64-77'
+            res = get_compiler_versions()
+            self.assertEquals(str(res[1]), '77')
+
+        # and dllwrap
+        self._exes['dllwrap'] = b'GNU dllwrap 2.17.50 20060824\nFSF'
+        res = get_compiler_versions()
+        self.assertEquals(str(res[2]), '2.17.50')
+        self._exes['dllwrap'] = b'Cheese Wrap'
+        res = get_compiler_versions()
+        self.assertEquals(res[2], None)
+
 def test_suite():
     return unittest.makeSuite(UtilTestCase)
 

Modified: python/branches/py3k/Lib/distutils/util.py
==============================================================================
--- python/branches/py3k/Lib/distutils/util.py	(original)
+++ python/branches/py3k/Lib/distutils/util.py	Thu Jul 16 18:18:19 2009
@@ -7,10 +7,12 @@
 __revision__ = "$Id$"
 
 import sys, os, string, re
+
 from distutils.errors import DistutilsPlatformError
 from distutils.dep_util import newer
-from distutils.spawn import spawn
+from distutils.spawn import spawn, find_executable
 from distutils import log
+from distutils.version import LooseVersion
 
 def get_platform():
     """Return a string that identifies the current platform.
@@ -539,6 +541,56 @@
     sep = '\n' + 8*' '
     return sep.join(lines)
 
+_RE_VERSION = re.compile(b'(\d+\.\d+(\.\d+)*)')
+_MAC_OS_X_LD_VERSION = re.compile(b'^@\(#\)PROGRAM:ld  PROJECT:ld64-((\d+)(\.\d+)*)')
+
+def _find_ld_version():
+    """Finds the ld version. The version scheme differs under Mac OSX."""
+    if sys.platform == 'darwin':
+        return _find_exe_version('ld -v', _MAC_OS_X_LD_VERSION)
+    else:
+        return _find_exe_version('ld -v')
+
+def _find_exe_version(cmd, pattern=_RE_VERSION):
+    """Find the version of an executable by running `cmd` in the shell.
+
+    `pattern` is a compiled regular expression. If not provided, default
+    to _RE_VERSION. If the command is not found, or the output does not
+    match the mattern, returns None.
+    """
+    from subprocess import Popen, PIPE
+    executable = cmd.split()[0]
+    if find_executable(executable) is None:
+        return None
+    pipe = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
+    try:
+        stdout, stderr = pipe.stdout.read(), pipe.stderr.read()
+    finally:
+        pipe.stdout.close()
+        pipe.stderr.close()
+    # some commands like ld under MacOS X, will give the
+    # output in the stderr, rather than stdout.
+    if stdout != b'':
+        out_string = stdout
+    else:
+        out_string = stderr
+
+    result = pattern.search(out_string)
+    if result is None:
+        return None
+    return LooseVersion(result.group(1).decode())
+
+def get_compiler_versions():
+    """Returns a tuple providing the versions of gcc, ld and dllwrap
+
+    For each command, if a command is not found, None is returned.
+    Otherwise a LooseVersion instance is returned.
+    """
+    gcc = _find_exe_version('gcc -dumpversion')
+    ld = _find_ld_version()
+    dllwrap = _find_exe_version('dllwrap --version')
+    return gcc, ld, dllwrap
+
 # 2to3 support
 
 def run_2to3(files, fixer_names=None, options=None, explicit=None):

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Thu Jul 16 18:18:19 2009
@@ -901,6 +901,11 @@
 Library
 -------
 
+- Issue #6466: now distutils.cygwinccompiler and distutils.emxccompiler
+  uses the same refactored function to get gcc/ld/dllwrap versions numbers.
+  It's `distutils.util.get_compiler_versions`. Added deprecation warnings
+  for the obsolete get_versions() functions.
+
 - Issue #6459: distutils.command.build_ext.get_export_symbols now uses the
   "PyInit" prefix, rather than "init".
 


More information about the Python-checkins mailing list