diff --git a/CHANGELOG.md b/CHANGELOG.md index cc742e6160..8eaa7dec1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,8 @@ Unreleased changes template. * (toolchains) Remove all but `3.8.20` versions of the Python `3.8` interpreter who has reached EOL. If users still need other versions of the `3.8` interpreter, please supply the URLs manually {bzl:ob}`python.toolchain` or {bzl:obj}`python_register_toolchains` calls. +* (pypi) When running under `bazel test`, be sure that temporary `requirements` file + remains writable. [20250317]: https://github.com/astral-sh/python-build-standalone/releases/tag/20250317 diff --git a/python/private/pypi/dependency_resolver/dependency_resolver.py b/python/private/pypi/dependency_resolver/dependency_resolver.py index 293377dc6d..d0c5ab806e 100644 --- a/python/private/pypi/dependency_resolver/dependency_resolver.py +++ b/python/private/pypi/dependency_resolver/dependency_resolver.py @@ -148,9 +148,16 @@ def main( requirements_out = os.path.join( os.environ["TEST_TMPDIR"], os.path.basename(requirements_file) + ".out" ) + # Why this uses shutil.copyfileobj: + # # Those two files won't necessarily be on the same filesystem, so we can't use os.replace # or shutil.copyfile, as they will fail with OSError: [Errno 18] Invalid cross-device link. - shutil.copy(resolved_requirements_file, requirements_out) + # + # Further, shutil.copy preserves the source file's mode, and so if + # our source file is read-only (the default under Perforce Helix), + # this scratch file will also be read-only, defeating its purpose. + with open(resolved_requirements_file, "rb") as fsrc, open(requirements_out, "wb") as fdst: + shutil.copyfileobj(fsrc, fdst) update_command = os.getenv("CUSTOM_COMPILE_COMMAND") or "bazel run %s" % ( update_target_label,