From 71d3088078d7502e5e398b0d3d0399d92167174f Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Mon, 28 Dec 2020 11:28:50 +0900 Subject: [PATCH] Imported Upstream version 45.3.0 --- .bumpversion.cfg | 2 +- .readthedocs.yml | 3 +- .travis.yml | 3 + CHANGES.rst | 7 ++ appveyor.yml | 9 +++ docs/requirements.txt | 4 + docs/setuptools.txt | 2 + pyproject.toml | 6 +- setup.cfg | 3 +- setuptools/command/bdist_egg.py | 9 ++- setuptools/msvc.py | 159 +++++++++++++++++++++++++++++++++++-- setuptools/tests/test_bdist_egg.py | 15 ++++ setuptools/tests/test_msvc14.py | 84 ++++++++++++++++++++ tox.ini | 4 +- 14 files changed, 296 insertions(+), 14 deletions(-) create mode 100644 docs/requirements.txt create mode 100644 setuptools/tests/test_msvc14.py diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 8e86f31..c438b5a 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 45.2.0 +current_version = 45.3.0 commit = True tag = True diff --git a/.readthedocs.yml b/.readthedocs.yml index 7b994a3..cb10a7f 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,4 +2,5 @@ python: version: 3 extra_requirements: - docs - pip_install: true + pip_install: false + requirements: docs/requirements.txt diff --git a/.travis.yml b/.travis.yml index fe875ab..38a66f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/CHANGES.rst b/CHANGES.rst index f97f514..e35c447 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -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 ------- diff --git a/appveyor.yml b/appveyor.yml index f7ab22f..de4e6c6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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 index 0000000..6c35bf6 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +# keep these in sync with setup.cfg +sphinx +jaraco.packaging>=6.1 +rst.linker>=1.9 diff --git a/docs/setuptools.txt b/docs/setuptools.txt index f84837f..efcd0a8 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -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:: diff --git a/pyproject.toml b/pyproject.toml index f0fd852..cfdc257 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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 = ["."] diff --git a/setup.cfg b/setup.cfg index 8cca647..2e65b7a 100644 --- 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 diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 98470f1..1b28d4c 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -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' " diff --git a/setuptools/msvc.py b/setuptools/msvc.py index c2cbd1e..213e39c 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -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 diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py index fb5b90b..8760ea3 100644 --- a/setuptools/tests/test_bdist_egg.py +++ b/setuptools/tests/test_bdist_egg.py @@ -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 index 0000000..7833aab --- /dev/null +++ b/setuptools/tests/test_msvc14.py @@ -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 --- 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 = -- 2.7.4