Imported Upstream version 60.1.0 upstream/60.1.0
authorJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:42 +0000 (17:02 +0900)
committerJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:42 +0000 (17:02 +0900)
.bumpversion.cfg
CHANGES.rst
_distutils_hack/__init__.py
setup.cfg
setup.py
setuptools/_distutils/_msvccompiler.py
setuptools/_distutils/command/install.py
setuptools/_distutils/cygwinccompiler.py
setuptools/_distutils/tests/test_cygwinccompiler.py
setuptools/tests/test_distutils_adoption.py

index 65eec0b030f7a363cfb8043b077ae03c337b5bae..d5a104b05955b620e00282532ec28de6573b6285 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 60.0.5
+current_version = 60.1.0
 commit = True
 tag = True
 
index 998dda4e581e677ec1ab2ca3aa30f67b2d63e74d..096925441f2c2e5ce02bc938676b70980997e503 100644 (file)
@@ -1,3 +1,13 @@
+v60.1.0
+-------
+
+
+Changes
+^^^^^^^
+* #2958: In distutils_hack, only add the metadata finder once. In ensure_local_distutils, rely on a context manager for reliable manipulation.
+* #2963: Merge with pypa/distutils@a5af364910. Includes revisited fix for pypa/distutils#15 and improved MinGW/Cygwin support from pypa/distutils#77.
+
+
 v60.0.5
 -------
 
index 22bc9ed6e8ead9e9a23e4587006f14a21bce3e14..85a51370b6ac747798f3c213181d568f278bc728 100644 (file)
@@ -3,6 +3,7 @@ import os
 import re
 import importlib
 import warnings
+import contextlib
 
 
 is_pypy = '__pypy__' in sys.builtin_module_names
@@ -52,9 +53,8 @@ def ensure_local_distutils():
     # With the DistutilsMetaFinder in place,
     # perform an import to cause distutils to be
     # loaded from setuptools._distutils. Ref #2906.
-    add_shim()
-    importlib.import_module('distutils')
-    remove_shim()
+    with shim():
+        importlib.import_module('distutils')
 
     # check that submodules load as expected
     core = importlib.import_module('distutils.core')
@@ -129,6 +129,19 @@ class DistutilsMetaFinder:
 DISTUTILS_FINDER = DistutilsMetaFinder()
 
 
+def ensure_shim():
+    DISTUTILS_FINDER in sys.meta_path or add_shim()
+
+
+@contextlib.contextmanager
+def shim():
+    add_shim()
+    try:
+        yield
+    finally:
+        remove_shim()
+
+
 def add_shim():
     sys.meta_path.insert(0, DISTUTILS_FINDER)
 
index f1a6fc5278da73a587fa1c1dda16e38f23dd126f..3daca1df8d7afd852bfd4b9dbb2a5e6c0259f036 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = setuptools
-version = 60.0.5
+version = 60.1.0
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
 description = Easily download, build, install, upgrade, and uninstall Python packages
index 4cda3d38900800259bf56618cf489d686749d46f..d15189db0f01d8efa5e0c5e361f4f29c6166bf19 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -55,7 +55,7 @@ class install_with_pth(install):
         import os
         var = 'SETUPTOOLS_USE_DISTUTILS'
         enabled = os.environ.get(var, 'local') == 'local'
-        enabled and __import__('_distutils_hack').add_shim()
+        enabled and __import__('_distutils_hack').ensure_shim()
         """).lstrip().replace('\n', '; ')
 
     def initialize_options(self):
index b7a06082ae7c34e31f9d4669768c9c6a153612fd..c41ea9ae30b6f3d753c3fb71d2766e7be263df0b 100644 (file)
@@ -527,7 +527,7 @@ class MSVCCompiler(CCompiler) :
             return
         warnings.warn(
             "Fallback spawn triggered. Please update distutils monkeypatch.")
-        with unittest.mock.patch('os.environ', env):
+        with unittest.mock.patch.dict('os.environ', env):
             bag.value = super().spawn(cmd)
 
     # -- Miscellaneous methods -----------------------------------------
index 65844927f6be65f7f9d1fe4d33ff8d4ea8fff3bf..cdcc05281437bd03b27008796ede8f6f6eee7ac7 100644 (file)
@@ -408,8 +408,7 @@ class install(Command):
                             'platlibdir': getattr(sys, 'platlibdir', 'lib'),
                             'implementation_lower': _get_implementation().lower(),
                             'implementation': _get_implementation(),
-                            # all values must be str; see #86
-                            'platsubdir': str(sysconfig.get_config_var('platsubdir')),
+                            'platsubdir': sysconfig.get_config_var('platsubdir'),
                            }
 
         if HAS_USER_SITE:
@@ -650,7 +649,7 @@ class install(Command):
             return
         home = convert_path(os.path.expanduser("~"))
         for name, path in self.config_vars.items():
-            if path.startswith(home) and not os.path.isdir(path):
+            if str(path).startswith(home) and not os.path.isdir(path):
                 self.debug_print("os.makedirs('%s', 0o700)" % path)
                 os.makedirs(path, 0o700)
 
index 09be5ba2c1041acced8c5d5cb27652e7c8b5cd0f..4a38dfdadd0b2034d68bcbc199254edb275b7cc7 100644 (file)
@@ -51,16 +51,14 @@ import os
 import sys
 import copy
 import shlex
-from subprocess import Popen, PIPE, check_output
-import re
+import warnings
+from subprocess import check_output
 
-import distutils.version
 from distutils.unixccompiler import UnixCCompiler
 from distutils.file_util import write_file
 from distutils.errors import (DistutilsExecError, CCompilerError,
         CompileError, UnknownFileError)
-from distutils.version import LooseVersion
-from distutils.spawn import find_executable
+from distutils.version import LooseVersion, suppress_known_deprecation
 
 def get_msvcr():
     """Include the appropriate MSVC runtime library if Python was built
@@ -125,33 +123,8 @@ class CygwinCCompiler(UnixCCompiler):
         self.cc = os.environ.get('CC', 'gcc')
         self.cxx = os.environ.get('CXX', 'g++')
 
-        if ('gcc' in self.cc): # Start gcc workaround
-            self.gcc_version, self.ld_version, self.dllwrap_version = \
-                get_versions()
-            self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
-                             (self.gcc_version,
-                              self.ld_version,
-                              self.dllwrap_version) )
-
-            # ld_version >= "2.10.90" and < "2.13" should also be able to use
-            # gcc -mdll instead of dllwrap
-            # Older dllwraps had own version numbers, newer ones use the
-            # same as the rest of binutils ( also ld )
-            # dllwrap 2.10.90 is buggy
-            if self.ld_version >= "2.10.90":
-                self.linker_dll = self.cc
-            else:
-                self.linker_dll = "dllwrap"
-
-            # ld_version >= "2.13" support -shared so use it instead of
-            # -mdll -static
-            if self.ld_version >= "2.13":
-                shared_option = "-shared"
-            else:
-                shared_option = "-mdll -static"
-        else: # Assume linker is up to date
-            self.linker_dll = self.cc
-            shared_option = "-shared"
+        self.linker_dll = self.cc
+        shared_option = "-shared"
 
         self.set_executables(compiler='%s -mcygwin -O -Wall' % self.cc,
                              compiler_so='%s -mcygwin -mdll -O -Wall' % self.cc,
@@ -160,17 +133,24 @@ class CygwinCCompiler(UnixCCompiler):
                              linker_so=('%s -mcygwin %s' %
                                         (self.linker_dll, shared_option)))
 
-        # cygwin and mingw32 need different sets of libraries
-        if ('gcc' in self.cc and self.gcc_version == "2.91.57"):
-            # cygwin shouldn't need msvcrt, but without the dlls will crash
-            # (gcc version 2.91.57) -- perhaps something about initialization
-            self.dll_libraries=["msvcrt"]
-            self.warn(
-                "Consider upgrading to a newer version of gcc")
-        else:
-            # Include the appropriate MSVC runtime library if Python was built
-            # with MSVC 7.0 or later.
-            self.dll_libraries = get_msvcr()
+        # Include the appropriate MSVC runtime library if Python was built
+        # with MSVC 7.0 or later.
+        self.dll_libraries = get_msvcr()
+
+    @property
+    def gcc_version(self):
+        # Older numpy dependend on this existing to check for ancient
+        # gcc versions. This doesn't make much sense with clang etc so
+        # just hardcode to something recent.
+        # https://github.com/numpy/numpy/pull/20333
+        warnings.warn(
+            "gcc_version attribute of CygwinCCompiler is deprecated. "
+            "Instead of returning actual gcc version a fixed value 11.2.0 is returned.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        with suppress_known_deprecation():
+            return LooseVersion("11.2.0")
 
     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
         """Compiles the source by spawning GCC and windres if needed."""
@@ -232,24 +212,17 @@ class CygwinCCompiler(UnixCCompiler):
 
             # next add options for def-file and to creating import libraries
 
-            # dllwrap uses different options than gcc/ld
-            if self.linker_dll == "dllwrap":
-                extra_preargs.extend(["--output-lib", lib_file])
-                # for dllwrap we have to use a special option
-                extra_preargs.extend(["--def", def_file])
-            # we use gcc/ld here and can be sure ld is >= 2.9.10
-            else:
-                # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
-                #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
-                # for gcc/ld the def-file is specified as any object files
-                objects.append(def_file)
+            # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
+            #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
+            # for gcc/ld the def-file is specified as any object files
+            objects.append(def_file)
 
         #end: if ((export_symbols is not None) and
         #        (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
 
         # who wants symbols and a many times larger output file
         # should explicitly switch the debug mode on
-        # otherwise we let dllwrap/ld strip the output file
+        # otherwise we let ld strip the output file
         # (On my machine: 10KiB < stripped_file < ??100KiB
         #   unstripped_file = stripped_file + XXX KiB
         #  ( XXX=254 for a typical python extension))
@@ -297,19 +270,7 @@ class Mingw32CCompiler(CygwinCCompiler):
 
         CygwinCCompiler.__init__ (self, verbose, dry_run, force)
 
-        # ld_version >= "2.13" support -shared so use it instead of
-        # -mdll -static
-        if ('gcc' in self.cc and self.ld_version < "2.13"):
-            shared_option = "-mdll -static"
-        else:
-            shared_option = "-shared"
-
-        # A real mingw32 doesn't need to specify a different entry point,
-        # but cygwin 2.91.57 in no-cygwin-mode needs it.
-        if ('gcc' in self.cc and self.gcc_version <= "2.91.57"):
-            entry_point = '--entry _DllMain@12'
-        else:
-            entry_point = ''
+        shared_option = "-shared"
 
         if is_cygwincc(self.cc):
             raise CCompilerError(
@@ -319,9 +280,9 @@ class Mingw32CCompiler(CygwinCCompiler):
                              compiler_so='%s -mdll -O -Wall' % self.cc,
                              compiler_cxx='%s -O -Wall' % self.cxx,
                              linker_exe='%s' % self.cc,
-                             linker_so='%s %s %s'
-                                        % (self.linker_dll, shared_option,
-                                           entry_point))
+                             linker_so='%s %s'
+                                        % (self.linker_dll, shared_option))
+
         # Maybe we should also append -mthreads, but then the finished
         # dlls need another dll (mingwm10.dll see Mingw32 docs)
         # (-mthreads: Support thread-safe exception handling on `Mingw32')
@@ -388,39 +349,8 @@ def check_config_h():
         return (CONFIG_H_UNCERTAIN,
                 "couldn't read '%s': %s" % (fn, exc.strerror))
 
-RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)')
-
-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; decode
-    ver_str = result.group(1).decode()
-    with distutils.version.suppress_known_deprecation():
-        return LooseVersion(ver_str)
-
-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])
-
 def is_cygwincc(cc):
     '''Try to determine if the compiler that would be used is from cygwin.'''
     out_string = check_output(shlex.split(cc) + ['-dumpmachine'])
     return out_string.strip().endswith(b'cygwin')
+
index 2a02eed40d5047921371f1c95d317528c95a49b9..0e52c88fb079a484c801799b661f01ceaf4db7c7 100644 (file)
@@ -2,28 +2,14 @@
 import unittest
 import sys
 import os
-from io import BytesIO
 from test.support import run_unittest
 
-from distutils import cygwinccompiler
 from distutils.cygwinccompiler import (check_config_h,
                                        CONFIG_H_OK, CONFIG_H_NOTOK,
-                                       CONFIG_H_UNCERTAIN, get_versions,
+                                       CONFIG_H_UNCERTAIN,
                                        get_msvcr)
 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 +21,16 @@ class CygwinCCompilerTestCase(support.TempdirManager,
         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 +54,6 @@ class CygwinCCompilerTestCase(support.TempdirManager,
         self.write_file(self.python_h, 'xxx __GNUC__ xxx')
         self.assertEqual(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.assertEqual(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.assertEqual(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.assertEqual(res[0], None)
-
-        # same thing for ld
-        self._exes['ld'] = b'GNU ld version 2.17.50 20060824'
-        res = get_versions()
-        self.assertEqual(str(res[1]), '2.17.50')
-        self._exes['ld'] = b'@(#)PROGRAM:ld  PROJECT:ld64-77'
-        res = get_versions()
-        self.assertEqual(res[1], None)
-
-        # and dllwrap
-        self._exes['dllwrap'] = b'GNU dllwrap 2.17.50 20060824\nFSF'
-        res = get_versions()
-        self.assertEqual(str(res[2]), '2.17.50')
-        self._exes['dllwrap'] = b'Cheese Wrap'
-        res = get_versions()
-        self.assertEqual(res[2], None)
-
     def test_get_msvcr(self):
 
         # none
index b6b9c00eafd97573506295db65d68d5865593928..27759b1df831f71e420c186b7a4198813ddb7bcb 100644 (file)
@@ -3,6 +3,7 @@ import sys
 import functools
 import subprocess
 import platform
+import textwrap
 
 import pytest
 import jaraco.envs
@@ -49,12 +50,24 @@ def find_distutils(venv, imports='distutils', env=None, **kwargs):
     return popen_text(venv.run)(cmd, env=env, **kwargs)
 
 
+def count_meta_path(venv, env=None):
+    py_cmd = textwrap.dedent(
+        """
+        import sys
+        is_distutils = lambda finder: finder.__class__.__name__ == "DistutilsMetaFinder"
+        print(len(list(filter(is_distutils, sys.meta_path))))
+        """)
+    cmd = ['python', '-c', py_cmd]
+    return int(popen_text(venv.run)(cmd, env=env))
+
+
 def test_distutils_stdlib(venv):
     """
     Ensure stdlib distutils is used when appropriate.
     """
     env = dict(SETUPTOOLS_USE_DISTUTILS='stdlib')
     assert venv.name not in find_distutils(venv, env=env).split(os.sep)
+    assert count_meta_path(venv, env=env) == 0
 
 
 def test_distutils_local_with_setuptools(venv):
@@ -64,6 +77,7 @@ def test_distutils_local_with_setuptools(venv):
     env = dict(SETUPTOOLS_USE_DISTUTILS='local')
     loc = find_distutils(venv, imports='setuptools, distutils', env=env)
     assert venv.name in loc.split(os.sep)
+    assert count_meta_path(venv, env=env) <= 1
 
 
 @pytest.mark.xfail('IS_PYPY', reason='pypy imports distutils on startup')
@@ -74,3 +88,4 @@ def test_distutils_local(venv):
     """
     env = dict(SETUPTOOLS_USE_DISTUTILS='local')
     assert venv.name in find_distutils(venv, env=env).split(os.sep)
+    assert count_meta_path(venv, env=env) <= 1