From 30215690819fd1546641b3a13e986538d72778c3 Mon Sep 17 00:00:00 2001 From: red person Date: Mon, 29 Jun 2026 06:36:21 -0700 Subject: [PATCH] Reject non-string atomic text writes (#1819) --- core/atomic_io.py | 2 ++ tests/test_atomic_io.py | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/core/atomic_io.py b/core/atomic_io.py index 9d6ca126b..81c640d8a 100644 --- a/core/atomic_io.py +++ b/core/atomic_io.py @@ -34,6 +34,8 @@ def atomic_write_json(path: str, data: Any, *, indent: Optional[int] = None) -> def atomic_write_text(path: str, text: str) -> None: + if not isinstance(text, str): + raise TypeError("atomic_write_text expects a string") os.makedirs(os.path.dirname(path) or ".", exist_ok=True) tmp = f"{path}.tmp.{os.getpid()}" with open(tmp, "w", encoding="utf-8") as f: diff --git a/tests/test_atomic_io.py b/tests/test_atomic_io.py index 02ed7e8e5..9fadec20a 100644 --- a/tests/test_atomic_io.py +++ b/tests/test_atomic_io.py @@ -138,6 +138,16 @@ def test_atomic_write_text_leaves_no_tmp_file(tmp_path): assert _tmp_siblings(tmp_path, "note.txt") == [] +def test_atomic_write_text_rejects_non_string_before_tmp_file(tmp_path): + target = tmp_path / "note.txt" + + with pytest.raises(TypeError): + atomic_write_text(str(target), 123) + + assert not target.exists() + assert _tmp_siblings(tmp_path, "note.txt") == [] + + # --------------------------------------------------------------------------- # atomic_write_text — failure path: target preserved when replace fails. # ---------------------------------------------------------------------------