summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnderson Bravalheri <andersonbravalheri@gmail.com>2022-08-12 19:40:31 +0100
committerAnderson Bravalheri <andersonbravalheri@gmail.com>2022-08-12 19:40:31 +0100
commite4dd4bdd923cfc2f69dd4cfbb119644bb46e5e9d (patch)
tree6c73d1ff87b8f0ef3b1dbf1a0edded8092ed9a95
parent4a3519dcf57092736e16240881e0ea3e2d2425d0 (diff)
parentd81613ac88ea1cba36a8d31eb747a8fe0e9c0fc8 (diff)
downloadpython-setuptools-git-e4dd4bdd923cfc2f69dd4cfbb119644bb46e5e9d.tar.gz
Prevent optional extensions from crashing editable builds (#3515)
- Don't try to copy the files of an optional extension if its build has failed.
-rw-r--r--changelog.d/3515.misc.rst2
-rw-r--r--setuptools/command/build_ext.py3
-rw-r--r--setuptools/tests/test_build_ext.py37
3 files changed, 41 insertions, 1 deletions
diff --git a/changelog.d/3515.misc.rst b/changelog.d/3515.misc.rst
new file mode 100644
index 00000000..c884a316
--- /dev/null
+++ b/changelog.d/3515.misc.rst
@@ -0,0 +1,2 @@
+Fixed "inline" file copying for editable installations and
+optional extensions. \ No newline at end of file
diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py
index 7ad5a87a..cbfe3ec1 100644
--- a/setuptools/command/build_ext.py
+++ b/setuptools/command/build_ext.py
@@ -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)
diff --git a/setuptools/tests/test_build_ext.py b/setuptools/tests/test_build_ext.py
index 07ebcaf8..92ce80ef 100644
--- a/setuptools/tests/test_build_ext.py
+++ b/setuptools/tests/test_build_ext.py
@@ -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(