diff --git a/changelog.d/1671.change.rst b/changelog.d/1671.change.rst new file mode 100644 index 0000000000..95ae49da64 --- /dev/null +++ b/changelog.d/1671.change.rst @@ -0,0 +1 @@ +Fixed issue with the PEP 517 backend that prevented building a wheel when the ``dist/`` directory contained existing ``.whl`` files. diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 47cbcbf684..e40904a5df 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -35,6 +35,7 @@ import setuptools import distutils +from setuptools.py31compat import TemporaryDirectory from pkg_resources import parse_requirements @@ -182,14 +183,22 @@ def build_wheel(self, wheel_directory, config_settings=None, metadata_directory=None): config_settings = self._fix_config(config_settings) wheel_directory = os.path.abspath(wheel_directory) - sys.argv = sys.argv[:1] + ['bdist_wheel'] + \ - config_settings["--global-option"] - self.run_setup() - if wheel_directory != 'dist': - shutil.rmtree(wheel_directory) - shutil.copytree('dist', wheel_directory) - return _file_with_extension(wheel_directory, '.whl') + # Build the wheel in a temporary directory, then copy to the target + with TemporaryDirectory(dir=wheel_directory) as tmp_dist_dir: + sys.argv = (sys.argv[:1] + + ['bdist_wheel', '--dist-dir', tmp_dist_dir] + + config_settings["--global-option"]) + self.run_setup() + + wheel_basename = _file_with_extension(tmp_dist_dir, '.whl') + wheel_path = os.path.join(wheel_directory, wheel_basename) + if os.path.exists(wheel_path): + # os.rename will fail overwriting on non-unix env + os.remove(wheel_path) + os.rename(os.path.join(tmp_dist_dir, wheel_basename), wheel_path) + + return wheel_basename def build_sdist(self, sdist_directory, config_settings=None): config_settings = self._fix_config(config_settings) diff --git a/setuptools/py31compat.py b/setuptools/py31compat.py index 1a0705ece3..e1da7ee2a2 100644 --- a/setuptools/py31compat.py +++ b/setuptools/py31compat.py @@ -17,9 +17,9 @@ class TemporaryDirectory: errors on deletion. """ - def __init__(self): + def __init__(self, **kwargs): self.name = None # Handle mkdtemp raising an exception - self.name = tempfile.mkdtemp() + self.name = tempfile.mkdtemp(**kwargs) def __enter__(self): return self.name diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py index 90400afc50..88e29ffe1a 100644 --- a/setuptools/tests/test_build_meta.py +++ b/setuptools/tests/test_build_meta.py @@ -157,7 +157,6 @@ def test_build_wheel(self, build_backend): assert os.path.isfile(os.path.join(dist_dir, wheel_name)) - @pytest.mark.xfail(reason="Known error, see GH #1671") def test_build_wheel_with_existing_wheel_file_present(self, tmpdir_cwd): # Building a wheel should still succeed if there's already a wheel # in the wheel directory @@ -195,6 +194,12 @@ def test_build_wheel_with_existing_wheel_file_present(self, tmpdir_cwd): assert os.path.isfile(os.path.join(dist_dir, wheel_one)) assert wheel_one != wheel_two + # and if rebuilding the same wheel? + open(os.path.join(dist_dir, wheel_two), 'w').close() + wheel_three = self.get_build_backend().build_wheel(dist_dir) + assert wheel_three == wheel_two + assert os.path.getsize(os.path.join(dist_dir, wheel_three)) > 0 + def test_build_sdist(self, build_backend): dist_dir = os.path.abspath('pip-sdist') os.makedirs(dist_dir)