Imported Upstream version 64.0.3 upstream/64.0.3
authorJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:54 +0000 (17:02 +0900)
committerJinWang An <jinwang.an@samsung.com>
Mon, 27 Mar 2023 08:02:54 +0000 (17:02 +0900)
.bumpversion.cfg
CHANGES.rst
docs/userguide/development_mode.rst
setup.cfg
setuptools/command/build_ext.py
setuptools/command/build_py.py
setuptools/command/editable_wheel.py
setuptools/tests/test_build_ext.py
setuptools/tests/test_editable_install.py

index 617ffcbfacc7f36f6fa2fa8d39892abc596c2403..f8ab2b2d242408a057fc8a9440cd012dbe961824 100644 (file)
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 64.0.2
+current_version = 64.0.3
 commit = True
 tag = True
 
index 3efa5f7718a2cbe65adee51570f156201366c7db..cceb12bd250273f01c7b3703dffa7c4757077759 100644 (file)
@@ -1,3 +1,18 @@
+v64.0.3
+-------
+
+
+Misc
+^^^^
+* #3515: Fixed "inline" file copying for editable installations and
+  optional extensions.
+* #3517: Fixed ``editable_wheel`` to ensure other commands are finalized before using
+  them. This should prevent errors with plugins trying to use different commands
+  or reinitializing them.
+* #3517: Augmented filter to prevent transient/temporary source files from being
+  considered ``package_data`` or ``data_files``.
+
+
 v64.0.2
 -------
 
index ddf9a3f49fcb8efefe1f6b1210ba3c03b3048aee..d2d5c7055fce7c943616424c8f90ad43a69ce7d1 100644 (file)
@@ -200,8 +200,8 @@ This *may* cause the installer (e.g. ``pip``) to effectively run the "legacy"
 installation command: ``python setup.py develop`` [#installer]_.
 
 
-How editable installations work?
---------------------------------
+How editable installations work
+-------------------------------
 
 *Advanced topic*
 
index 840b82e2c3c9053420872cec28879f15e23e218c..23f119a0ddebfce467ebc687c93e50a485cc47e3 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = setuptools
-version = 64.0.2
+version = 64.0.3
 author = Python Packaging Authority
 author_email = distutils-sig@python.org
 description = Easily download, build, install, upgrade, and uninstall Python packages
index 7ad5a87adcff594b7d328e6f7668f189019f0404..cbfe3ec1c28529aade613b000d5b051807287deb 100644 (file)
@@ -104,7 +104,8 @@ class build_ext(_build_ext):
             # Always copy, even if source is older than destination, to ensure
             # that the right extensions for the current Python/platform are
             # used.
-            self.copy_file(regular_file, inplace_file, level=self.verbose)
+            if os.path.exists(regular_file) or not ext.optional:
+                self.copy_file(regular_file, inplace_file, level=self.verbose)
 
             if ext._needs_stub:
                 inplace_stub = self._get_equivalent_stub(ext, inplace_file)
index 8b1a3320a7f7b2d2206cb752e7e0eda118163429..ec0627429ccbb88f3a17325726441ebcb28fb597 100644 (file)
@@ -184,7 +184,7 @@ class build_py(orig.build_py):
             files = ei_cmd.filelist.files
 
         check = _IncludePackageDataAbuse()
-        for path in _filter_absolute_egg_info(files, egg_info_dir):
+        for path in self._filter_build_files(files, egg_info_dir):
             d, f = os.path.split(assert_relative(path))
             prev = None
             oldf = f
@@ -202,6 +202,25 @@ class build_py(orig.build_py):
                         check.warn(importable)
                 mf.setdefault(src_dirs[d], []).append(path)
 
+    def _filter_build_files(self, files: Iterable[str], egg_info: str) -> Iterator[str]:
+        """
+        ``build_meta`` may try to create egg_info outside of the project directory,
+        and this can be problematic for certain plugins (reported in issue #3500).
+
+        Extensions might also include between their sources files created on the
+        ``build_lib`` and ``build_temp`` directories.
+
+        This function should filter this case of invalid files out.
+        """
+        build = self.get_finalized_command("build")
+        build_dirs = (egg_info, self.build_lib, build.build_temp, build.build_base)
+        norm_dirs = [os.path.normpath(p) for p in build_dirs if p]
+
+        for file in files:
+            norm_path = os.path.normpath(file)
+            if not os.path.isabs(file) or all(d not in norm_path for d in norm_dirs):
+                yield file
+
     def get_data_files(self):
         pass  # Lazily compute data files in _get_data_files() function.
 
@@ -347,15 +366,3 @@ class _IncludePackageDataAbuse:
             msg = textwrap.dedent(self.MESSAGE).format(importable=importable)
             warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2)
             self._already_warned.add(importable)
-
-
-def _filter_absolute_egg_info(files: Iterable[str], egg_info: str) -> Iterator[str]:
-    """
-    ``build_meta`` may try to create egg_info outside of the project directory,
-    and this can be problematic for certain plugins (reported in issue #3500).
-    This function should filter this case of invalid files out.
-    """
-    egg_info_name = Path(egg_info).name
-    for file in files:
-        if not (egg_info_name in file and os.path.isabs(file)):
-            yield file
index 2631a0827ee55f8d795835bdf3b86bd002e8d1d9..560efebdac17c4c2d6ea826ae61b092ee4e00fee 100644 (file)
@@ -133,7 +133,8 @@ class editable_wheel(Command):
             self._ensure_dist_info()
 
             # Add missing dist_info files
-            bdist_wheel = self.reinitialize_command("bdist_wheel")
+            self.reinitialize_command("bdist_wheel")
+            bdist_wheel = self.get_finalized_command("bdist_wheel")
             bdist_wheel.write_wheelfile(self.dist_info_dir)
 
             self._create_wheel_file(bdist_wheel)
@@ -156,7 +157,7 @@ class editable_wheel(Command):
         if self.dist_info_dir is None:
             dist_info = self.reinitialize_command("dist_info")
             dist_info.output_dir = self.dist_dir
-            dist_info.finalize_options()
+            dist_info.ensure_finalized()
             dist_info.run()
             self.dist_info_dir = dist_info.dist_info_dir
         else:
@@ -278,7 +279,7 @@ class editable_wheel(Command):
         #       Also remove _safely_run, TestCustomBuildPy. Suggested date: Aug/2023.
         build: Command = self.get_finalized_command("build")
         for name in build.get_sub_commands():
-            cmd = self.distribution.get_command_obj(name)
+            cmd = self.get_finalized_command(name)
             if name == "build_py" and type(cmd) != build_py_cls:
                 self._safely_run(name)
             else:
index 07ebcaf82b60a143bad767fa7141edc277c325db..92ce80efe20f1b583c38e52e19777ded9f5694a2 100644 (file)
@@ -9,10 +9,13 @@ from jaraco import path
 from setuptools.command.build_ext import build_ext, get_abi3_suffix
 from setuptools.dist import Distribution
 from setuptools.extension import Extension
+from setuptools.errors import CompileError
 
 from . import environment
 from .textwrap import DALS
 
+import pytest
+
 
 IS_PYPY = '__pypy__' in sys.builtin_module_names
 
@@ -176,6 +179,40 @@ class TestBuildExt:
         assert example_stub.endswith(".pyc")
 
 
+class TestBuildExtInplace:
+    def get_build_ext_cmd(self, optional: bool, **opts):
+        files = {
+            "eggs.c": "#include missingheader.h\n",
+            ".build": {"lib": {}, "tmp": {}},
+        }
+        path.build(files)
+        extension = Extension('spam.eggs', ['eggs.c'], optional=optional)
+        dist = Distribution(dict(ext_modules=[extension]))
+        dist.script_name = 'setup.py'
+        cmd = build_ext(dist)
+        vars(cmd).update(build_lib=".build/lib", build_temp=".build/tmp", **opts)
+        cmd.ensure_finalized()
+        return cmd
+
+    def test_optional(self, tmpdir_cwd, capsys):
+        """
+        If optional extensions fail to build, setuptools should show the error
+        in the logs but not fail to build
+        """
+        cmd = self.get_build_ext_cmd(optional=True, inplace=True)
+        cmd.run()
+        logs = capsys.readouterr()
+        messages = (logs.out + logs.err)
+        assert 'build_ext: building extension "spam.eggs" failed' in messages
+        # No compile error exception should be raised
+
+    def test_non_optional(self, tmpdir_cwd):
+        # Non-optional extensions should raise an exception
+        cmd = self.get_build_ext_cmd(optional=False, inplace=True)
+        with pytest.raises(CompileError):
+            cmd.run()
+
+
 def test_build_ext_config_handling(tmpdir_cwd):
     files = {
         'setup.py': DALS(
index 67d377ef6a53c8309c9084a30fc169691bc5d359..900ec1b3ccd56e47ff1926215dddcd50a652e5aa 100644 (file)
@@ -25,6 +25,7 @@ from setuptools.command.editable_wheel import (
     _find_namespaces,
     _find_package_roots,
     _finder_template,
+    editable_wheel,
 )
 from setuptools.dist import Distribution
 
@@ -846,6 +847,36 @@ class TestCustomBuildPy:
         assert b"42" in out
 
 
+class TestCustomBuildWheel:
+    def install_custom_build_wheel(self, dist):
+        bdist_wheel_cls = dist.get_command_class("bdist_wheel")
+
+        class MyBdistWheel(bdist_wheel_cls):
+            def get_tag(self):
+                # In issue #3513, we can see that some extensions may try to access
+                # the `plat_name` property in bdist_wheel
+                if self.plat_name.startswith("macosx-"):
+                    _ = "macOS platform"
+                return super().get_tag()
+
+        dist.cmdclass["bdist_wheel"] = MyBdistWheel
+
+    def test_access_plat_name(self, tmpdir_cwd):
+        # Even when a custom bdist_wheel tries to access plat_name the build should
+        # be successful
+        jaraco.path.build({"module.py": "x = 42"})
+        dist = Distribution()
+        dist.script_name = "setup.py"
+        dist.set_defaults()
+        self.install_custom_build_wheel(dist)
+        cmd = editable_wheel(dist)
+        cmd.ensure_finalized()
+        cmd.run()
+        wheel_file = str(next(Path().glob('dist/*')))
+        assert "editable" in wheel_file
+        assert wheel_file.endswith(".whl")
+
+
 def install_project(name, venv, tmp_path, files, *opts):
     project = tmp_path / name
     project.mkdir()