Description
Description
If there's not enough space left available in the user's cache directory for a wheel that has just been successfully built in a temp directory on a different disk, then this attempt to copy the built wheel into the cache directory fails:
pip/src/pip/_internal/wheel_builder.py
Line 276 in e6414d6
Because moving files across disks is done by first copying the file then removing the original, this can result in an incomplete copy and an ENOSPC
OSError
being raised. The OSError
is caught by pip, but the exception handler doesn't attempt to handle this case and clean up after it. Future runs of pip
can then find this invalid, incomplete .whl
file in the wheel cache, and go on to fail with zipfile.BadZipFile: File is not a zip file
Expected behavior
If writing the wheel file into the cache fails, pip
should clean up after itself so the truncated file can't be found by future pip install
calls.
pip version
master
Python version
3.9
OS
Linux
How to Reproduce
This was surprisingly difficult to reproduce, but I managed to get it by doing:
mkdir /tmp/too_small
sudo mount -t tmpfs -o size=400K tmpfs /tmp/too_small
python3.9 -m venv /tmp/venv
. /tmp/venv/bin/activate
pip --cache-dir=/tmp/too_small install --no-binary python-dateutil python-dateutil==2.8.1
python -m zipfile -l /tmp/too_small/wheels/*/*/*/*/python_dateutil*.whl
Output
$ mkdir /tmp/too_small
$ sudo mount -t tmpfs -o size=400K tmpfs /tmp/too_small
$ python3.9 -m venv /tmp/venv
$ . /tmp/venv/bin/activate
(venv) $ pip --cache-dir=/tmp/too_small install --no-binary python-dateutil python-dateutil==2.8.1
Looking in indexes: https://artprod.dev.bloomberg.com/artifactory/api/pypi/bloomberg-pypi/simple
Collecting python-dateutil==2.8.1
Downloading https://artprod.dev.bloomberg.com/artifactory/api/pypi/bloomberg-pypi/packages/packages/be/ed/5bbc91f03fa4c839c4c7360375da77f9659af5f7086b7a7bdda65771c8e0/python-dateutil-2.8.1.tar.gz (331 kB)
|████████████████████████████████| 331 kB 2.6 MB/s
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing wheel metadata ... done
Collecting six>=1.5
Downloading https://artprod.dev.bloomberg.com/artifactory/api/pypi/bloomberg-pypi/packages/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl (11 kB)
Building wheels for collected packages: python-dateutil
Building wheel for python-dateutil (PEP 517) ... done
WARNING: Building wheel for python-dateutil failed: [Errno 28] No space left on device: '/tmp/pip-wheel-kygit9c7/python_dateutil-2.8.1-py2.py3-none-any.whl' -> '/tmp/too_small/wheels/ed/3a/11/f3c3a429e4e3d97c7003108cca4a71a45a3f2ac87be8e3b11a/python_dateutil-2.8.1-py2.py3-none-any.whl'
Failed to build python-dateutil
ERROR: Could not build wheels for python-dateutil which use PEP 517 and cannot be installed directly
(venv) $ python -m zipfile -l /tmp/too_small/wheels/*/*/*/*/python_dateutil*.whl
Traceback (most recent call last):
File "/opt/bb/lib/python3.9/runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/opt/bb/lib/python3.9/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/opt/bb/lib/python3.9/zipfile.py", line 2428, in <module>
main()
File "/opt/bb/lib/python3.9/zipfile.py", line 2394, in main
with ZipFile(src, 'r') as zf:
File "/opt/bb/lib/python3.9/zipfile.py", line 1257, in __init__
self._RealGetContents()
File "/opt/bb/lib/python3.9/zipfile.py", line 1324, in _RealGetContents
raise BadZipFile("File is not a zip file")
__main__.BadZipFile: File is not a zip file
(venv) $
Code of Conduct
- I agree to follow the PSF Code of Conduct.