Imported Upstream version 65.6.1 upstream/65.6.1
authorJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:57 +0000 (17:02 +0900)
committerJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:57 +0000 (17:02 +0900)
29 files changed:
.bumpversion.cfg
.github/workflows/main.yml
CHANGES.rst
docs/build_meta.rst
docs/conf.py
docs/deprecated/distutils-legacy.rst
docs/deprecated/distutils/commandref.rst
docs/deprecated/distutils/configfile.rst
docs/deprecated/distutils/extending.rst
docs/deprecated/zip_safe.rst
docs/userguide/development_mode.rst
docs/userguide/entry_point.rst
docs/userguide/quickstart.rst
launcher.c
setup.cfg
setuptools/_distutils/log.py
setuptools/_entry_points.py
setuptools/build_meta.py
setuptools/command/build_clib.py
setuptools/command/upload_docs.py
setuptools/dist.py
setuptools/tests/script-with-bom.py
setuptools/tests/test_build_clib.py
setuptools/tests/test_build_meta.py
setuptools/tests/test_config_discovery.py
setuptools/tests/test_egg_info.py
setuptools/tests/test_manifest.py
setuptools/tests/test_msvc14.py
setuptools/tests/test_wheel.py

index 6a4b339c05f5fde977ef4126872fedac0952cd85..d3921d9a4a21851e69ebda84c2aa0a7639b84336 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 65.6.0
+current_version = 65.6.1
 commit = True
 tag = True
 
index a877b765857a9e6b90caca63e594d3afebe5b2c2..7413fa7de4f7c997a5598133139fc8f35b681d7e 100644 (file)
@@ -131,9 +131,9 @@ jobs:
     runs-on: ${{ matrix.platform }}
     timeout-minutes: 75
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - name: Install Cygwin with Python
-        uses: cygwin/cygwin-install-action@v1
+        uses: cygwin/cygwin-install-action@v2
         with:
           platform: x86_64
           packages: >-
@@ -187,13 +187,13 @@ jobs:
     runs-on: ubuntu-latest
     timeout-minutes: 75
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - name: Install OS-level dependencies
         run: |
           sudo apt-get update
           sudo apt-get install build-essential gfortran libopenblas-dev
       - name: Setup Python
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@v4
         with:
           # Use a release that is not very new but still have a long life:
           python-version: "3.8"
index 5a24ff7a03d4c5efd5d2614c84246ab1acd05507..52a87965193f3a2c8f17871a76af23e97f4381e6 100644 (file)
@@ -1,3 +1,21 @@
+v65.6.1
+-------
+
+
+Documentation changes
+^^^^^^^^^^^^^^^^^^^^^
+* #3689: Document that ``distutils.cfg`` might be ignored unless
+  ``SETUPTOOLS_USE_DISTUTILS=stdlib``.
+
+Misc
+^^^^
+* #3678: Improve clib builds reproducibility by sorting sources -- by :user:`danigm`
+* #3684: Improved exception/traceback when invalid entry-points are specified.
+* #3690: Fixed logging errors: 'underlying buffer has been detached' (issue #1631).
+* #3693: Merge pypa/distutils@3e9d47e with compatibility fix for distutils.log.Log.
+* #3704: Fix temporary build directories interference with auto-discovery.
+
+
 v65.6.0
 -------
 
index 3c778d800d8edc0c6ab9fdc15f3591e482ed9dfc..37738b8f9423f83f0aa967ef5022432c336f8da3 100644 (file)
@@ -48,8 +48,8 @@ files, a ``pyproject.toml`` file and a ``setup.cfg`` file::
         pyproject.toml
         setup.cfg
         meowpkg/
-                   __init__.py
-                       module.py
+            __init__.py
+            module.py
 
 The ``pyproject.toml`` file specifies the build system (i.e. what is
 being used to package your scripts and install from source). To use it with
@@ -161,7 +161,7 @@ requirements.
    and :pypi:`setuptools-svn`), or by correctly setting up :ref:`MANIFEST.in
    <manifest>`.
 
-   The generated ``.tar.gz`` and ``.whl`` files are compressed archives that 
+   The generated ``.tar.gz`` and ``.whl`` files are compressed archives that
    can be inspected as follows:
    On POSIX systems, this can be done with ``tar -tf dist/*.tar.gz``
    and ``unzip -l dist/*.whl``.
index a9c9800af6896c931a3033cf9a286dfe84efda61..64c2625f4a3d00b8936dedf6fb1efa33b1a4d6d3 100644 (file)
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-# -*- coding: utf-8 -*-
 
 extensions = [
     'sphinx.ext.autodoc',
index e106ce97b48ec976680ce2a4e75bec3973eb4520..63c8ff07c003c053f8b0c346d34bd5c43f7c56ce 100644 (file)
@@ -7,6 +7,15 @@ Since the 60.0.0 release, Setuptools includes a local, vendored copy of distutil
 
     SETUPTOOLS_USE_DISTUTILS=stdlib
 
+.. warning::
+   Please note that this also affects how ``distutils.cfg`` files inside stdlib's ``distutils``
+   package directory are processed.
+   Unless ``SETUPTOOLS_USE_DISTUTILS=stdlib``, they will have no effect on the build process.
+
+   You can still use a global user config file, ``~/.pydistutils.cfg`` (POSIX) or ``%USERPROFILE%/pydistutils.cfg`` (Windows),
+   or use the environment variable :doc:`DIST_EXTRA_CONFIG <deprecated/distutils/configfile>` to point to another
+   supplementary configuration file.
+
 
 Prefer Setuptools
 -----------------
index 3e247e68d3a05f4333cdb64545c447f96e9e9ce9..d02b38c33682f85730ae8a0cabd8f0bd17159028 100644 (file)
@@ -101,5 +101,3 @@ anything except backslash or colon.
 .. % \subsection{\protect\command{bdist}}
 .. % \subsection{\protect\command{bdist\_dumb}}
 .. % \subsection{\protect\command{bdist\_rpm}}
-
-
index 2a0fbb31d8980b3cb95b29d0e2c8091f5af30e0e..ab199dcaf7c9bf81c8dc1a2b3817cb5c61893f74 100644 (file)
@@ -142,4 +142,3 @@ split across multiple lines for readability.
 
 .. [#] This ideal probably won't be achieved until auto-configuration is fully
    supported by the Distutils.
-
index c99d3c791f6ba79f316cd5ece50edb79268d6f9f..fc49461647c335ac6f2fff786d090cdfb378af1c 100644 (file)
@@ -94,5 +94,3 @@ to add ``(command, filename)`` pairs to ``self.distribution.dist_files`` so that
 :command:`upload` can upload it to PyPI.  The *filename* in the pair contains no
 path information, only the name of the file itself.  In dry-run mode, pairs
 should still be added to represent what would have been created.
-
-
index 08a13334ec1e3425e2045761bd735e5f6c9ad0aa..26b4566232f8618d46f2e3a82e0764abe89a1957 100644 (file)
@@ -62,7 +62,7 @@ Currently, popular Python package installers (such as :pypi:`pip`) and package
 indexes (such as PyPI_) consider that distribution packages are always
 installed as a directory.
 It is however still possible to load packages from zip files added to
-:obj:`sys.path`, thanks to the :mod:`zipimport` module 
+:obj:`sys.path`, thanks to the :mod:`zipimport` module
 and the :mod:`importlib` machinery provided by Python standard library.
 
 When working with modules loaded from a zip file, it is important to keep in
index 1716e0afb444450598f5f48a9d8e62949563eddd..6f9f5417f7fab5aaa81ff84f1e35a0d22cd659f1 100644 (file)
@@ -17,7 +17,7 @@ without requiring a new installation.
 
 You can enter this "development mode" by performing an :doc:`editable installation
 <pip:topics/local-project-installs>` inside of a :term:`virtual environment`,
-using :doc:`pip's <pip:cli/pip_install>` ``-e/--editable`` flag, as shown bellow:
+using :doc:`pip's <pip:cli/pip_install>` ``-e/--editable`` flag, as shown below:
 
 .. code-block:: bash
 
@@ -69,7 +69,7 @@ Please have a look on the following section if you are looking for a different b
 
        sudo apt install python3-venv
 
-   Alternatively, you can also try installing :pypi:`virtualen`.
+   Alternatively, you can also try installing :pypi:`virtualenv`.
    More information is available on the Python Packaging User Guide on
    :doc:`PyPUG:guides/installing-using-pip-and-virtual-environments`.
 
@@ -93,7 +93,7 @@ expectations:
 Unfortunately these expectations are in conflict with each other.
 To solve this problem ``setuptools`` allows developers to choose a more
 *"strict"* mode for the editable installation. This can be done by passing
-a special *configuration setting* via :pypi:`pip`, as indicated bellow:
+a special *configuration setting* via :pypi:`pip`, as indicated below:
 
 .. code-block:: bash
 
index 6ba00287d76bfe72799651cb009802ca78123590..163ce1d9d7e00416c250788fd7ea465e0ca3d576 100644 (file)
@@ -89,7 +89,7 @@ configuration:
 .. tab:: setup.py
 
     .. code-block:: python
-    
+
         from setuptools import setup
 
         setup(
index fe5c5bc2ba74be4293ffad499bfb898e7b3e7e75..bf92f6a2de3e6749ed32d9b31b81ef84e8b3e93f 100644 (file)
@@ -165,7 +165,7 @@ to specify to properly package your project.
   :doc:`setup.cfg <declarative_config>`, and keep the ``setup.py`` minimal
   with only the dynamic parts (or even omit it completely if applicable).
 
-  See `Why you shouldn't invoke setup.py directly`_ for more background.  
+  See `Why you shouldn't invoke setup.py directly`_ for more background.
 
 .. _Why you shouldn't invoke setup.py directly: https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html
 
index 23ef3ac206e13c24fb5d547ef30b24959274ff34..83b487898a661abfbbf71cea7316bd20bd9e7600 100644 (file)
@@ -180,7 +180,7 @@ void pass_control_to_child(DWORD control_type) {
 }
 
 BOOL control_handler(DWORD control_type) {
-    /* 
+    /*
      * distribute-issue207
      * control event handler callback function
      */
@@ -204,12 +204,12 @@ int create_and_wait_for_subprocess(char* command) {
     ZeroMemory(&p_info, sizeof(p_info));
     ZeroMemory(&s_info, sizeof(s_info));
     s_info.cb = sizeof(STARTUPINFO);
-    // set-up control handler callback funciotn
+    // set-up control handler callback function
     SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
     if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
         fprintf(stderr, "failed to create process.\n");
         return 0;
-    }   
+    }
     child_pid = p_info.dwProcessId;
     // wait for Python to exit
     WaitForSingleObject(p_info.hProcess, INFINITE);
@@ -229,7 +229,7 @@ char* join_executable_and_args(char *executable, char **args, int argc)
      */
     int len,counter;
     char* cmdline;
-    
+
     len=strlen(executable)+2;
     for (counter=1; counter<argc; counter++) {
         len+=strlen(args[counter])+1;
@@ -333,4 +333,3 @@ int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
 int main(int argc, char** argv) {
     return run(argc, argv, GUI);
 }
-
index a34af39c1d6a7bf9aba1f44d6fd62650ee5cb4ad..588d4a4155870aeade64a2f57a328febbef1c5b6 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = setuptools
-version = 65.6.0
+version = 65.6.1
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
 description = Easily download, build, install, upgrade, and uninstall Python packages
index bb789c300d64357971724ec6ba34a025b05f4ca4..239f31585068ca6f1b03c8bc7e7dd7e447037c89 100644 (file)
@@ -5,6 +5,7 @@ Retained for compatibility and should not be used.
 """
 
 import logging
+import warnings
 
 from ._log import log as _global_log
 
@@ -36,3 +37,21 @@ def set_verbosity(v):
         set_threshold(logging.INFO)
     elif v >= 2:
         set_threshold(logging.DEBUG)
+
+
+class Log(logging.Logger):
+    """distutils.log.Log is deprecated, please use an alternative from `logging`."""
+
+    def __init__(self, threshold=WARN):
+        warnings.warn(Log.__doc__)  # avoid DeprecationWarning to ensure warn is shown
+        super().__init__(__name__, level=threshold)
+
+    @property
+    def threshold(self):
+        return self.level
+
+    @threshold.setter
+    def threshold(self, level):
+        self.setLevel(level)
+
+    warn = logging.Logger.warning
index f087681b5980b586c79fb4d87f99e33597eb1575..a2346342d62a426986e05ead248707316d0c7102 100644 (file)
@@ -2,6 +2,7 @@ import functools
 import operator
 import itertools
 
+from .errors import OptionError
 from .extern.jaraco.text import yield_lines
 from .extern.jaraco.functools import pass_none
 from ._importlib import metadata
@@ -14,7 +15,14 @@ def ensure_valid(ep):
     Exercise one of the dynamic properties to trigger
     the pattern match.
     """
-    ep.extras
+    try:
+        ep.extras
+    except AttributeError as ex:
+        msg = (
+            f"Problems to parse {ep}.\nPlease ensure entry-point follows the spec: "
+            "https://packaging.python.org/en/latest/specifications/entry-points/"
+        )
+        raise OptionError(msg) from ex
 
 
 def load_group(value, group):
index e8f1c72d598d6d5a03b75f68a6d567b1d6b1e9a2..1fb4c3b10815b1760a0c96eb20a0a99119056e7c 100644 (file)
@@ -385,7 +385,8 @@ class _BuildMetaBackend(_ConfigSettingsTranslator):
 
         # Build in a temporary directory, then copy to the target.
         os.makedirs(result_directory, exist_ok=True)
-        with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir:
+        temp_opts = {"prefix": ".tmp-", "dir": result_directory}
+        with tempfile.TemporaryDirectory(**temp_opts) as tmp_dist_dir:
             sys.argv = [
                 *sys.argv[:1],
                 *self._global_args(config_settings),
index 67ce2444ea69a0bbdfab0bda8c2aa14951187096..09483e69e5b76ef28d4389d7f17699aee7ecbd0a 100644 (file)
@@ -28,7 +28,7 @@ class build_clib(orig.build_clib):
                     "in 'libraries' option (library '%s'), "
                     "'sources' must be present and must be "
                     "a list of source filenames" % lib_name)
-            sources = list(sources)
+            sources = sorted(list(sources))
 
             log.info("building '%s' library", lib_name)
 
index 3263f07f4877ad6f9ecc881c12df29a4a65b03f4..63eb28c70ceeb5d22dd767472ad9737409c810fd 100644 (file)
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 """upload_docs
 
 Implements a Distutils 'upload_docs' subcommand (upload documentation to
index 824235488666c6ecdb22240b08354806fadb58ca..1c71e5eed2f1484020cc16cae3c5a3645f18afa3 100644 (file)
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 __all__ = ['Distribution']
 
 import io
@@ -1195,19 +1194,11 @@ class Distribution(_Distribution):
 
         # Print metadata in UTF-8 no matter the platform
         encoding = sys.stdout.encoding
-        errors = sys.stdout.errors
-        newline = sys.platform != 'win32' and '\n' or None
-        line_buffering = sys.stdout.line_buffering
-
-        sys.stdout = io.TextIOWrapper(
-            sys.stdout.detach(), 'utf-8', errors, newline, line_buffering
-        )
+        sys.stdout.reconfigure(encoding='utf-8')
         try:
             return _Distribution.handle_display_options(self, option_order)
         finally:
-            sys.stdout = io.TextIOWrapper(
-                sys.stdout.detach(), encoding, errors, newline, line_buffering
-            )
+            sys.stdout.reconfigure(encoding=encoding)
 
     def run_command(self, command):
         self.set_defaults()
index 22dee0d2a32a276cc217664420410970ab10b770..93d28f16001b160ae5afd44225dae352e76e529c 100644 (file)
@@ -1,3 +1 @@
-# -*- coding: utf-8 -*-
-
-result = 'passed'
+result = 'passed'
index af9e7c6dc397d052f603c8a86aace6551d624ba3..2d9273cdcabe37a8d30ab933ffd7ceb7c0655478 100644 (file)
@@ -2,6 +2,7 @@ from unittest import mock
 
 import pytest
 
+import random
 from distutils.errors import DistutilsSetupError
 from setuptools.command.build_clib import build_clib
 from setuptools.dist import Distribution
@@ -56,3 +57,30 @@ class TestBuildCLib:
         cmd.build_libraries(libs)
         assert cmd.compiler.compile.call_count == 1
         assert cmd.compiler.create_static_lib.call_count == 1
+
+    @mock.patch(
+        'setuptools.command.build_clib.newer_pairwise_group')
+    def test_build_libraries_reproducible(self, mock_newer):
+        dist = Distribution()
+        cmd = build_clib(dist)
+
+        # with that out of the way, let's see if the crude dependency
+        # system works
+        cmd.compiler = mock.MagicMock(spec=cmd.compiler)
+        mock_newer.return_value = ([], [])
+
+        original_sources = ['a-example.c', 'example.c']
+        sources = original_sources
+
+        obj_deps = {'': ('global.h',), 'example.c': ('example.h',)}
+        libs = [('example', {'sources': sources, 'obj_deps': obj_deps})]
+
+        cmd.build_libraries(libs)
+        computed_call_args = mock_newer.call_args[0]
+
+        while sources == original_sources:
+            sources = random.sample(original_sources, len(original_sources))
+        libs = [('example', {'sources': sources, 'obj_deps': obj_deps})]
+
+        cmd.build_libraries(libs)
+        assert computed_call_args == mock_newer.call_args[0]
index bf1c27ff1d4f349d3466e9311e7e16fd840f2923..9e55a938116db5aba41027173efbbef72392f735 100644 (file)
@@ -44,7 +44,7 @@ class BuildBackend(BuildBackendBase):
         self.pool = futures.ProcessPoolExecutor(max_workers=1)
 
     def __getattr__(self, name):
-        """Handles aribrary function invocations on the build backend."""
+        """Handles arbitrary function invocations on the build backend."""
 
         def method(*args, **kw):
             root = os.path.abspath(self.cwd)
@@ -79,7 +79,7 @@ class BuildBackendCaller(BuildBackendBase):
          self.backend_obj) = self.backend_name.partition(':')
 
     def __call__(self, name, *args, **kw):
-        """Handles aribrary function invocations on the build backend."""
+        """Handles arbitrary function invocations on the build backend."""
         os.chdir(self.cwd)
         os.environ.update(self.env)
         mod = importlib.import_module(self.backend_name)
index 85b64b31dde987034f5a4308cc7c14d87bf3a019..f65b00b61f6cee59e1706d0b5b53ff72cc7d63b8 100644 (file)
@@ -248,6 +248,19 @@ class TestDiscoverPackagesAndPyModules:
         with pytest.raises(PackageDiscoveryError, match="multiple (packages|modules)"):
             _get_dist(tmp_path, {})
 
+    def test_py_modules_when_wheel_dir_is_cwd(self, tmp_path):
+        """Regression for issue 3692"""
+        from setuptools import build_meta
+
+        pyproject = '[project]\nname = "test"\nversion = "1"'
+        (tmp_path / "pyproject.toml").write_text(DALS(pyproject), encoding="utf-8")
+        (tmp_path / "foo.py").touch()
+        with jaraco.path.DirectoryStack().context(tmp_path):
+            build_meta.build_wheel(".")
+        # Ensure py_modules are found
+        wheel_files = get_wheel_members(next(tmp_path.glob("*.whl")))
+        assert "foo.py" in wheel_files
+
 
 class TestNoConfig:
     DEFAULT_VERSION = "0.0.0"  # Default version given by setuptools
index ee07b5a1be35339952d61873d242410a2e2291c8..387773c13556ecf8cb8d2421cfc7d5d6fb44e691 100644 (file)
@@ -6,12 +6,18 @@ import re
 import stat
 import time
 from typing import List, Tuple
+from pathlib import Path
 
 import pytest
 from jaraco import path
 
+from setuptools import errors
 from setuptools.command.egg_info import (
-    egg_info, manifest_maker, EggInfoDeprecationWarning, get_pkg_info_revision,
+    EggInfoDeprecationWarning,
+    egg_info,
+    get_pkg_info_revision,
+    manifest_maker,
+    write_entries,
 )
 from setuptools.dist import Distribution
 
@@ -24,6 +30,28 @@ class Environment(str):
     pass
 
 
+@pytest.fixture
+def env():
+    with contexts.tempdir(prefix='setuptools-test.') as env_dir:
+        env = Environment(env_dir)
+        os.chmod(env_dir, stat.S_IRWXU)
+        subs = 'home', 'lib', 'scripts', 'data', 'egg-base'
+        env.paths = dict(
+            (dirname, os.path.join(env_dir, dirname))
+            for dirname in subs
+        )
+        list(map(os.mkdir, env.paths.values()))
+        path.build({
+            env.paths['home']: {
+                '.pydistutils.cfg': DALS("""
+                [egg_info]
+                egg-base = %(egg-base)s
+                """ % env.paths)
+            }
+        })
+        yield env
+
+
 class TestEggInfo:
 
     setup_script = DALS("""
@@ -51,27 +79,6 @@ class TestEggInfo:
         version_str = pkg_info_lines[0].split(' ')[1]
         return tuple(map(int, version_str.split('.')[:2]))
 
-    @pytest.fixture
-    def env(self):
-        with contexts.tempdir(prefix='setuptools-test.') as env_dir:
-            env = Environment(env_dir)
-            os.chmod(env_dir, stat.S_IRWXU)
-            subs = 'home', 'lib', 'scripts', 'data', 'egg-base'
-            env.paths = dict(
-                (dirname, os.path.join(env_dir, dirname))
-                for dirname in subs
-            )
-            list(map(os.mkdir, env.paths.values()))
-            path.build({
-                env.paths['home']: {
-                    '.pydistutils.cfg': DALS("""
-                    [egg_info]
-                    egg-base = %(egg-base)s
-                    """ % env.paths)
-                }
-            })
-            yield env
-
     def test_egg_info_save_version_info_setup_empty(self, tmpdir_cwd, env):
         """
         When the egg_info section is empty or not present, running
@@ -1084,3 +1091,27 @@ class TestEggInfo:
 
     def test_get_pkg_info_revision_deprecated(self):
         pytest.warns(EggInfoDeprecationWarning, get_pkg_info_revision)
+
+
+class TestWriteEntries:
+
+    def test_invalid_entry_point(self, tmpdir_cwd, env):
+        dist = Distribution({"name": "foo", "version": "0.0.1"})
+        dist.entry_points = {"foo": "foo = invalid-identifier:foo"}
+        cmd = dist.get_command_obj("egg_info")
+        expected_msg = r"Problems to parse .*invalid-identifier.*"
+        with pytest.raises(errors.OptionError, match=expected_msg) as ex:
+            write_entries(cmd, "entry_points", "entry_points.txt")
+            assert "ensure entry-point follows the spec" in ex.value.args[0]
+
+    def test_valid_entry_point(self, tmpdir_cwd, env):
+        dist = Distribution({"name": "foo", "version": "0.0.1"})
+        dist.entry_points = {
+            "abc": "foo = bar:baz",
+            "def": ["faa = bor:boz"],
+        }
+        cmd = dist.get_command_obj("egg_info")
+        write_entries(cmd, "entry_points", "entry_points.txt")
+        content = Path("entry_points.txt").read_text(encoding="utf-8")
+        assert "[abc]\nfoo = bar:baz\n" in content
+        assert "[def]\nfaa = bor:boz\n" in content
index ecc83c2fddf54f5439cce4466a419744ff38b48c..3a973b01c4988ae3a057ac04e979e2627e3217b8 100644 (file)
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 """sdist tests"""
 
 import contextlib
@@ -8,6 +7,7 @@ import sys
 import tempfile
 import itertools
 import io
+import logging
 from distutils import log
 from distutils.errors import DistutilsTemplateError
 
@@ -18,6 +18,9 @@ from setuptools.tests.textwrap import DALS
 import pytest
 
 
+IS_PYPY = '__pypy__' in sys.builtin_module_names
+
+
 def make_local_path(s):
     """Converts '/' in a string to os.sep"""
     return s.replace('/', os.sep)
@@ -321,43 +324,29 @@ class TestFileListTest(TempDirTestCase):
     to ensure setuptools' version of FileList keeps parity with distutils.
     """
 
-    def setup_method(self, method):
-        if not hasattr(log, 'Log'):
-            pytest.skip("These tests rely on old logging infra")
-        super(TestFileListTest, self).setup_method(method)
-        self.threshold = log.set_threshold(log.FATAL)
-        self._old_log = log.Log._log
-        log.Log._log = self._log
-        self.logs = []
+    @pytest.fixture(autouse=os.getenv("SETUPTOOLS_USE_DISTUTILS") == "stdlib")
+    def _compat_record_logs(self, monkeypatch, caplog):
+        """Account for stdlib compatibility"""
+        def _log(_logger, level, msg, args):
+            exc = sys.exc_info()
+            rec = logging.LogRecord("distutils", level, "", 0, msg, args, exc)
+            caplog.records.append(rec)
 
-    def teardown_method(self, method):
-        log.set_threshold(self.threshold)
-        log.Log._log = self._old_log
-        super(TestFileListTest, self).teardown_method(method)
-
-    def _log(self, level, msg, args):
-        if level not in (log.DEBUG, log.INFO, log.WARN, log.ERROR, log.FATAL):
-            raise ValueError('%s wrong log level' % str(level))
-        self.logs.append((level, msg, args))
-
-    def get_logs(self, *levels):
-        def _format(msg, args):
-            if len(args) == 0:
-                return msg
-            return msg % args
-        return [_format(msg, args) for level, msg, args
-                in self.logs if level in levels]
-
-    def clear_logs(self):
-        self.logs = []
-
-    def assertNoWarnings(self):
-        assert self.get_logs(log.WARN) == []
-        self.clear_logs()
-
-    def assertWarnings(self):
-        assert len(self.get_logs(log.WARN)) > 0
-        self.clear_logs()
+        monkeypatch.setattr(log.Log, "_log", _log)
+
+    def get_records(self, caplog, *levels):
+        return [r for r in caplog.records if r.levelno in levels]
+
+    def assertNoWarnings(self, caplog):
+        assert self.get_records(caplog, log.WARN) == []
+        caplog.clear()
+
+    def assertWarnings(self, caplog):
+        if IS_PYPY and not caplog.records:
+            pytest.xfail("caplog checks may not work well in PyPy")
+        else:
+            assert len(self.get_records(caplog, log.WARN)) > 0
+            caplog.clear()
 
     def make_files(self, files):
         for file in files:
@@ -474,7 +463,8 @@ class TestFileListTest(TempDirTestCase):
             else:
                 assert False, "Should have thrown an error"
 
-    def test_include(self):
+    def test_include(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # include
         file_list = FileList()
@@ -483,14 +473,15 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('include *.py')
         file_list.sort()
         assert file_list.files == ['a.py']
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('include *.rb')
         file_list.sort()
         assert file_list.files == ['a.py']
-        self.assertWarnings()
+        self.assertWarnings(caplog)
 
-    def test_exclude(self):
+    def test_exclude(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # exclude
         file_list = FileList()
@@ -499,14 +490,15 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('exclude *.py')
         file_list.sort()
         assert file_list.files == ['b.txt', ml('d/c.py')]
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('exclude *.rb')
         file_list.sort()
         assert file_list.files == ['b.txt', ml('d/c.py')]
-        self.assertWarnings()
+        self.assertWarnings(caplog)
 
-    def test_global_include(self):
+    def test_global_include(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # global-include
         file_list = FileList()
@@ -515,14 +507,15 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('global-include *.py')
         file_list.sort()
         assert file_list.files == ['a.py', ml('d/c.py')]
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('global-include *.rb')
         file_list.sort()
         assert file_list.files == ['a.py', ml('d/c.py')]
-        self.assertWarnings()
+        self.assertWarnings(caplog)
 
-    def test_global_exclude(self):
+    def test_global_exclude(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # global-exclude
         file_list = FileList()
@@ -531,14 +524,15 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('global-exclude *.py')
         file_list.sort()
         assert file_list.files == ['b.txt']
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('global-exclude *.rb')
         file_list.sort()
         assert file_list.files == ['b.txt']
-        self.assertWarnings()
+        self.assertWarnings(caplog)
 
-    def test_recursive_include(self):
+    def test_recursive_include(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # recursive-include
         file_list = FileList()
@@ -547,14 +541,15 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('recursive-include d *.py')
         file_list.sort()
         assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('recursive-include e *.py')
         file_list.sort()
         assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
-        self.assertWarnings()
+        self.assertWarnings(caplog)
 
-    def test_recursive_exclude(self):
+    def test_recursive_exclude(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # recursive-exclude
         file_list = FileList()
@@ -563,14 +558,15 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('recursive-exclude d *.py')
         file_list.sort()
         assert file_list.files == ['a.py', ml('d/c.txt')]
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('recursive-exclude e *.py')
         file_list.sort()
         assert file_list.files == ['a.py', ml('d/c.txt')]
-        self.assertWarnings()
+        self.assertWarnings(caplog)
 
-    def test_graft(self):
+    def test_graft(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # graft
         file_list = FileList()
@@ -579,14 +575,15 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('graft d')
         file_list.sort()
         assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('graft e')
         file_list.sort()
         assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
-        self.assertWarnings()
+        self.assertWarnings(caplog)
 
-    def test_prune(self):
+    def test_prune(self, caplog):
+        caplog.set_level(logging.DEBUG)
         ml = make_local_path
         # prune
         file_list = FileList()
@@ -595,9 +592,9 @@ class TestFileListTest(TempDirTestCase):
         file_list.process_template_line('prune d')
         file_list.sort()
         assert file_list.files == ['a.py', ml('f/f.py')]
-        self.assertNoWarnings()
+        self.assertNoWarnings(caplog)
 
         file_list.process_template_line('prune e')
         file_list.sort()
         assert file_list.files == ['a.py', ml('f/f.py')]
-        self.assertWarnings()
+        self.assertWarnings(caplog)
index 1aca12dd3760a10835ff5f06102478ada4a5febf..271d6be562d96376dfb234a13a572afb2eb7f2bd 100644 (file)
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 """
 Tests for msvc support module (msvc14 unit tests).
 """
index 89d65d0b791cd63dc6100f59f9e081e47eeb936f..b2bbdfae7ff159425a1365849f555b6c04566701 100644 (file)
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """wheel tests
 """