55import logging
66import os .path
77import re
8- import shutil
98from collections .abc import Iterable
9+ from tempfile import TemporaryDirectory
1010
1111from pip ._vendor .packaging .utils import canonicalize_name , canonicalize_version
1212from pip ._vendor .packaging .version import InvalidVersion , Version
2424from pip ._internal .utils .misc import ensure_dir , hash_file
2525from pip ._internal .utils .setuptools_build import make_setuptools_clean_args
2626from pip ._internal .utils .subprocess import call_subprocess
27- from pip ._internal .utils .temp_dir import TempDirectory
2827from pip ._internal .utils .urls import path_to_url
2928from pip ._internal .vcs import vcs
3029
@@ -189,7 +188,7 @@ def _build_one_inside_env(
189188 global_options : list [str ],
190189 editable : bool ,
191190) -> str | None :
192- with TempDirectory ( kind = "wheel" ) as temp_dir :
191+ with TemporaryDirectory ( dir = output_dir ) as wheel_directory :
193192 assert req .name
194193 if req .use_pep517 :
195194 assert req .metadata_directory
@@ -207,14 +206,14 @@ def _build_one_inside_env(
207206 name = req .name ,
208207 backend = req .pep517_backend ,
209208 metadata_directory = req .metadata_directory ,
210- tempd = temp_dir . path ,
209+ wheel_directory = wheel_directory ,
211210 )
212211 else :
213212 wheel_path = build_wheel_pep517 (
214213 name = req .name ,
215214 backend = req .pep517_backend ,
216215 metadata_directory = req .metadata_directory ,
217- tempd = temp_dir . path ,
216+ wheel_directory = wheel_directory ,
218217 )
219218 else :
220219 wheel_path = build_wheel_legacy (
@@ -223,15 +222,19 @@ def _build_one_inside_env(
223222 source_dir = req .unpacked_source_directory ,
224223 global_options = global_options ,
225224 build_options = build_options ,
226- tempd = temp_dir . path ,
225+ wheel_directory = wheel_directory ,
227226 )
228227
229228 if wheel_path is not None :
230229 wheel_name = os .path .basename (wheel_path )
231230 dest_path = os .path .join (output_dir , wheel_name )
232231 try :
233232 wheel_hash , length = hash_file (wheel_path )
234- shutil .move (wheel_path , dest_path )
233+ # We can do a replace here because wheel_path is guaranteed to
234+ # be in the same filesystem as output_dir. This will perform an
235+ # atomic rename, which is necessary to avoid concurrency issues
236+ # when populating the cache.
237+ os .replace (wheel_path , dest_path )
235238 logger .info (
236239 "Created wheel for %s: filename=%s size=%d sha256=%s" ,
237240 req .name ,
0 commit comments