Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ Pierre Sassoulas
Pieter Mulder
Piotr Banaszkiewicz
Piotr Helm
Poorva Barve
Poulami Sau
Prakhar Gurunani
Praneeth Kodumagulla
Expand Down
1 change: 1 addition & 0 deletions changelog/15043.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cache writes now emit :class:`pytest.PytestCacheWarning` when writing or closing the cache file fails, consistent with errors opening the file.
6 changes: 2 additions & 4 deletions src/_pytest/cacheprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,15 +240,13 @@ def set(self, key: str, value: object) -> None:
return
data = json.dumps(value, ensure_ascii=False, indent=2)
try:
f = path.open("w", encoding="UTF-8")
with path.open("w", encoding="UTF-8") as f:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick we now can use path.write_text

f.write(data)
except OSError as exc:
self.warn(
f"cache could not write path {path}: {exc}",
_ispytest=True,
)
else:
with f:
f.write(data)

def _ensure_cache_dir_and_supporting_files(self) -> None:
"""Create the cache dir and its supporting files."""
Expand Down
26 changes: 26 additions & 0 deletions testing/test_cacheprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
from collections.abc import Sequence
from enum import auto
from enum import Enum
import errno
import os
from pathlib import Path
import shutil
from typing import Any
from unittest.mock import mock_open

from _pytest.compat import assert_never
from _pytest.config import ExitCode
Expand Down Expand Up @@ -104,6 +106,30 @@ def test_cache_writefail_cachefile_silent(self, pytester: Pytester) -> None:
assert cache is not None
cache.set("test/broken", [])

@pytest.mark.parametrize("failure", ["open", "write", "close"])
def test_cache_writefail_warns(
self, pytester: Pytester, monkeypatch: MonkeyPatch, failure: str
) -> None:
config = pytester.parseconfigure()
cache = config.cache
assert cache is not None
cache.set("test/broken", [])
mocked_open = mock_open()
failing_operation = {
"open": mocked_open,
"write": mocked_open.return_value.write,
"close": mocked_open.return_value.__exit__,
}[failure]
failing_operation.side_effect = OSError(errno.ENOSPC, "No space left on device")

with monkeypatch.context() as m:
m.setattr(Path, "open", mocked_open)
with pytest.warns(
pytest.PytestCacheWarning,
match="cache could not write path .*: .*No space left on device",
):
cache.set("test/broken", [])

@pytest.fixture
def unwritable_cache_dir(self, pytester: Pytester) -> Generator[Path]:
cache_dir = pytester.path.joinpath(".pytest_cache")
Expand Down