Imported Upstream version 45.3.0 upstream/45.3.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 28 Dec 2020 02:28:50 +0000 (11:28 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 28 Dec 2020 02:28:50 +0000 (11:28 +0900)
14 files changed:
.bumpversion.cfg
.readthedocs.yml
.travis.yml
CHANGES.rst
appveyor.yml
docs/requirements.txt [new file with mode: 0644]
docs/setuptools.txt
pyproject.toml
setup.cfg
setuptools/command/bdist_egg.py
setuptools/msvc.py
setuptools/tests/test_bdist_egg.py
setuptools/tests/test_msvc14.py [new file with mode: 0644]
tox.ini

index 8e86f31..c438b5a 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 45.2.0
+current_version = 45.3.0
 commit = True
 tag = True
 
index 7b994a3..cb10a7f 100644 (file)
@@ -2,4 +2,5 @@ python:
   version: 3
   extra_requirements:
   - docs
-  pip_install: true
+  pip_install: false
+  requirements: docs/requirements.txt
index fe875ab..38a66f3 100644 (file)
@@ -26,6 +26,9 @@ jobs:
     if: tag IS present
     script: tox -e release
     after_success: skip
+  allow_failures:
+  # suppress failures due to pypa/setuptools#2000
+  - python: pypy3
 
 cache: pip
 
index f97f514..e35c447 100644 (file)
@@ -1,3 +1,10 @@
+v45.3.0
+-------
+
+* #1557: Deprecated eggsecutable scripts and updated docs.
+* #1904: Update msvc.py to use CPython 3.8.0 mechanism to find msvc 14+
+
+
 v45.2.0
 -------
 
index f7ab22f..de4e6c6 100644 (file)
@@ -7,6 +7,15 @@ environment:
   CODECOV_ENV: APPVEYOR_JOB_NAME
 
   matrix:
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      APPVEYOR_JOB_NAME: "python35-x64-vs2015"
+      PYTHON: "C:\\Python35-x64"
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      APPVEYOR_JOB_NAME: "python35-x64-vs2017"
+      PYTHON: "C:\\Python35-x64"
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      APPVEYOR_JOB_NAME: "python35-x64-vs2019"
+      PYTHON: "C:\\Python35-x64"
     - APPVEYOR_JOB_NAME: "python36-x64"
       PYTHON: "C:\\Python36-x64"
     - APPVEYOR_JOB_NAME: "python37-x64"
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644 (file)
index 0000000..6c35bf6
--- /dev/null
@@ -0,0 +1,4 @@
+# keep these in sync with setup.cfg
+sphinx
+jaraco.packaging>=6.1
+rst.linker>=1.9
index f84837f..efcd0a8 100644 (file)
@@ -560,6 +560,8 @@ Services and Plugins`_.
 "Eggsecutable" Scripts
 ----------------------
 
+.. deprecated:: 45.3.0
+
 Occasionally, there are situations where it's desirable to make an ``.egg``
 file directly executable.  You can do this by including an entry point such
 as the following::
index f0fd852..cfdc257 100644 (file)
@@ -1,5 +1,9 @@
 [build-system]
-requires = ["setuptools >= 40.8", "wheel"]
+requires = [
+    # avoid self install on Python 2; ref #1996
+    "setuptools >= 40.8; python_version > '3'",
+    "wheel",
+]
 build-backend = "setuptools.build_meta"
 backend-path = ["."]
 
index 8cca647..2e65b7a 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -16,7 +16,7 @@ formats = zip
 
 [metadata]
 name = setuptools
-version = 45.2.0
+version = 45.3.0
 description = Easily download, build, install, upgrade, and uninstall Python packages
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
@@ -74,6 +74,7 @@ tests =
     pip>=19.1 # For proper file:// URLs support.
 
 docs =
+    # Keep these in sync with docs/requirements.txt
     sphinx
     jaraco.packaging>=6.1
     rst.linker>=1.9
index 98470f1..1b28d4c 100644 (file)
@@ -11,13 +11,14 @@ import os
 import re
 import textwrap
 import marshal
+import warnings
 
 from setuptools.extern import six
 
 from pkg_resources import get_build_platform, Distribution, ensure_directory
 from pkg_resources import EntryPoint
 from setuptools.extension import Library
-from setuptools import Command
+from setuptools import Command, SetuptoolsDeprecationWarning
 
 try:
     # Python 2.7 or >=3.2
@@ -278,6 +279,12 @@ class bdist_egg(Command):
         if ep is None:
             return 'w'  # not an eggsecutable, do it the usual way.
 
+        warnings.warn(
+            "Eggsecutables are deprecated and will be removed in a future "
+            "version.",
+            SetuptoolsDeprecationWarning
+        )
+
         if not ep.attrs or ep.extras:
             raise DistutilsSetupError(
                 "eggsecutable entry point (%r) cannot have 'extras' "
index c2cbd1e..213e39c 100644 (file)
@@ -26,6 +26,7 @@ from os.path import join, isfile, isdir, dirname
 import sys
 import platform
 import itertools
+import subprocess
 import distutils.errors
 from setuptools.extern.packaging.version import LegacyVersion
 
@@ -142,6 +143,154 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
         raise
 
 
+def _msvc14_find_vc2015():
+    """Python 3.8 "distutils/_msvccompiler.py" backport"""
+    try:
+        key = winreg.OpenKey(
+            winreg.HKEY_LOCAL_MACHINE,
+            r"Software\Microsoft\VisualStudio\SxS\VC7",
+            0,
+            winreg.KEY_READ | winreg.KEY_WOW64_32KEY
+        )
+    except OSError:
+        return None, None
+
+    best_version = 0
+    best_dir = None
+    with key:
+        for i in itertools.count():
+            try:
+                v, vc_dir, vt = winreg.EnumValue(key, i)
+            except OSError:
+                break
+            if v and vt == winreg.REG_SZ and isdir(vc_dir):
+                try:
+                    version = int(float(v))
+                except (ValueError, TypeError):
+                    continue
+                if version >= 14 and version > best_version:
+                    best_version, best_dir = version, vc_dir
+    return best_version, best_dir
+
+
+def _msvc14_find_vc2017():
+    """Python 3.8 "distutils/_msvccompiler.py" backport
+
+    Returns "15, path" based on the result of invoking vswhere.exe
+    If no install is found, returns "None, None"
+
+    The version is returned to avoid unnecessarily changing the function
+    result. It may be ignored when the path is not None.
+
+    If vswhere.exe is not available, by definition, VS 2017 is not
+    installed.
+    """
+    root = environ.get("ProgramFiles(x86)") or environ.get("ProgramFiles")
+    if not root:
+        return None, None
+
+    try:
+        path = subprocess.check_output([
+            join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
+            "-latest",
+            "-prerelease",
+            "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
+            "-property", "installationPath",
+            "-products", "*",
+        ]).decode(encoding="mbcs", errors="strict").strip()
+    except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
+        return None, None
+
+    path = join(path, "VC", "Auxiliary", "Build")
+    if isdir(path):
+        return 15, path
+
+    return None, None
+
+
+PLAT_SPEC_TO_RUNTIME = {
+    'x86': 'x86',
+    'x86_amd64': 'x64',
+    'x86_arm': 'arm',
+    'x86_arm64': 'arm64'
+}
+
+
+def _msvc14_find_vcvarsall(plat_spec):
+    """Python 3.8 "distutils/_msvccompiler.py" backport"""
+    _, best_dir = _msvc14_find_vc2017()
+    vcruntime = None
+
+    if plat_spec in PLAT_SPEC_TO_RUNTIME:
+        vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec]
+    else:
+        vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
+
+    if best_dir:
+        vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**",
+                        vcruntime_plat, "Microsoft.VC14*.CRT",
+                        "vcruntime140.dll")
+        try:
+            import glob
+            vcruntime = glob.glob(vcredist, recursive=True)[-1]
+        except (ImportError, OSError, LookupError):
+            vcruntime = None
+
+    if not best_dir:
+        best_version, best_dir = _msvc14_find_vc2015()
+        if best_version:
+            vcruntime = join(best_dir, 'redist', vcruntime_plat,
+                             "Microsoft.VC140.CRT", "vcruntime140.dll")
+
+    if not best_dir:
+        return None, None
+
+    vcvarsall = join(best_dir, "vcvarsall.bat")
+    if not isfile(vcvarsall):
+        return None, None
+
+    if not vcruntime or not isfile(vcruntime):
+        vcruntime = None
+
+    return vcvarsall, vcruntime
+
+
+def _msvc14_get_vc_env(plat_spec):
+    """Python 3.8 "distutils/_msvccompiler.py" backport"""
+    if "DISTUTILS_USE_SDK" in environ:
+        return {
+            key.lower(): value
+            for key, value in environ.items()
+        }
+
+    vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec)
+    if not vcvarsall:
+        raise distutils.errors.DistutilsPlatformError(
+            "Unable to find vcvarsall.bat"
+        )
+
+    try:
+        out = subprocess.check_output(
+            'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
+            stderr=subprocess.STDOUT,
+        ).decode('utf-16le', errors='replace')
+    except subprocess.CalledProcessError as exc:
+        raise distutils.errors.DistutilsPlatformError(
+            "Error executing {}".format(exc.cmd)
+        )
+
+    env = {
+        key.lower(): value
+        for key, _, value in
+        (line.partition('=') for line in out.splitlines())
+        if key and value
+    }
+
+    if vcruntime:
+        env['py_vcruntime_redist'] = vcruntime
+    return env
+
+
 def msvc14_get_vc_env(plat_spec):
     """
     Patched "distutils._msvccompiler._get_vc_env" for support extra
@@ -159,16 +308,10 @@ def msvc14_get_vc_env(plat_spec):
     dict
         environment
     """
-    # Try to get environment from vcvarsall.bat (Classical way)
-    try:
-        return get_unpatched(msvc14_get_vc_env)(plat_spec)
-    except distutils.errors.DistutilsPlatformError:
-        # Pass error Vcvarsall.bat is missing
-        pass
 
-    # If error, try to set environment directly
+    # Always use backport from CPython 3.8
     try:
-        return EnvironmentInfo(plat_spec, vc_min_ver=14.0).return_env()
+        return _msvc14_get_vc_env(plat_spec)
     except distutils.errors.DistutilsPlatformError as exc:
         _augment_exception(exc, 14.0)
         raise
index fb5b90b..8760ea3 100644 (file)
@@ -7,6 +7,7 @@ import zipfile
 import pytest
 
 from setuptools.dist import Distribution
+from setuptools import SetuptoolsDeprecationWarning
 
 from . import contexts
 
@@ -64,3 +65,17 @@ class Test:
         names = list(zi.filename for zi in zip.filelist)
         assert 'hi.pyc' in names
         assert 'hi.py' not in names
+
+    def test_eggsecutable_warning(self, setup_context, user_override):
+        dist = Distribution(dict(
+            script_name='setup.py',
+            script_args=['bdist_egg'],
+            name='foo',
+            py_modules=['hi'],
+            entry_points={
+                'setuptools.installation':
+                    ['eggsecutable = my_package.some_module:main_func']},
+        ))
+        dist.parse_command_line()
+        with pytest.warns(SetuptoolsDeprecationWarning):
+            dist.run_commands()
diff --git a/setuptools/tests/test_msvc14.py b/setuptools/tests/test_msvc14.py
new file mode 100644 (file)
index 0000000..7833aab
--- /dev/null
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+"""
+Tests for msvc support module (msvc14 unit tests).
+"""
+
+import os
+from distutils.errors import DistutilsPlatformError
+import pytest
+import sys
+
+
+@pytest.mark.skipif(sys.platform != "win32",
+                    reason="These tests are only for win32")
+class TestMSVC14:
+    """Python 3.8 "distutils/tests/test_msvccompiler.py" backport"""
+    def test_no_compiler(self):
+        import setuptools.msvc as _msvccompiler
+        # makes sure query_vcvarsall raises
+        # a DistutilsPlatformError if the compiler
+        # is not found
+
+        def _find_vcvarsall(plat_spec):
+            return None, None
+
+        old_find_vcvarsall = _msvccompiler._msvc14_find_vcvarsall
+        _msvccompiler._msvc14_find_vcvarsall = _find_vcvarsall
+        try:
+            pytest.raises(DistutilsPlatformError,
+                          _msvccompiler._msvc14_get_vc_env,
+                          'wont find this version')
+        finally:
+            _msvccompiler._msvc14_find_vcvarsall = old_find_vcvarsall
+
+    @pytest.mark.skipif(sys.version_info[0] < 3,
+                        reason="Unicode requires encode/decode on Python 2")
+    def test_get_vc_env_unicode(self):
+        import setuptools.msvc as _msvccompiler
+
+        test_var = 'ṰḖṤṪ┅ṼẨṜ'
+        test_value = '₃⁴₅'
+
+        # Ensure we don't early exit from _get_vc_env
+        old_distutils_use_sdk = os.environ.pop('DISTUTILS_USE_SDK', None)
+        os.environ[test_var] = test_value
+        try:
+            env = _msvccompiler._msvc14_get_vc_env('x86')
+            assert test_var.lower() in env
+            assert test_value == env[test_var.lower()]
+        finally:
+            os.environ.pop(test_var)
+            if old_distutils_use_sdk:
+                os.environ['DISTUTILS_USE_SDK'] = old_distutils_use_sdk
+
+    def test_get_vc2017(self):
+        import setuptools.msvc as _msvccompiler
+
+        # This function cannot be mocked, so pass it if we find VS 2017
+        # and mark it skipped if we do not.
+        version, path = _msvccompiler._msvc14_find_vc2017()
+        if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in [
+            'Visual Studio 2017'
+        ]:
+            assert version
+        if version:
+            assert version >= 15
+            assert os.path.isdir(path)
+        else:
+            pytest.skip("VS 2017 is not installed")
+
+    def test_get_vc2015(self):
+        import setuptools.msvc as _msvccompiler
+
+        # This function cannot be mocked, so pass it if we find VS 2015
+        # and mark it skipped if we do not.
+        version, path = _msvccompiler._msvc14_find_vc2015()
+        if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in [
+            'Visual Studio 2015', 'Visual Studio 2017'
+        ]:
+            assert version
+        if version:
+            assert version >= 14
+            assert os.path.isdir(path)
+        else:
+            pytest.skip("VS 2015 is not installed")
diff --git a/tox.ini b/tox.ini
index 2164599..1ebb922 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -7,6 +7,8 @@ envlist=python
 minversion = 3.2
 requires =
        tox-pip-version >= 0.0.6
+       # workaround for #1998
+       virtualenv < 20
 
 [helpers]
 # Custom pip behavior
@@ -20,7 +22,7 @@ setenv =
        COVERAGE_FILE={toxworkdir}/.coverage.{envname}
 # TODO: The passed environment variables came from copying other tox.ini files
 # These should probably be individually annotated to explain what needs them.
-passenv=APPDATA HOMEDRIVE HOMEPATH windir APPVEYOR APPVEYOR_* CI CODECOV_* TRAVIS TRAVIS_* NETWORK_REQUIRED
+passenv=APPDATA HOMEDRIVE HOMEPATH windir Program* CommonProgram* VS* APPVEYOR APPVEYOR_* CI CODECOV_* TRAVIS TRAVIS_* NETWORK_REQUIRED
 commands=pytest --cov-config={toxinidir}/tox.ini --cov-report= {posargs}
 usedevelop=True
 extras =