From 8b3b9e3d79634d14105ba185fb524e2b5f39d9ca Mon Sep 17 00:00:00 2001 From: Apeksha_2022 <70309060+Apeksha9389@users.noreply.github.com> Date: Mon, 19 Oct 2026 12:16:51 +0530 Subject: [PATCH] Allow touching existing read-only files --- newsfragments/+touch-readonly.bugfix.rst | 1 + path/__init__.py | 3 +-- tests/test_path.py | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 newsfragments/+touch-readonly.bugfix.rst diff --git a/newsfragments/+touch-readonly.bugfix.rst b/newsfragments/+touch-readonly.bugfix.rst new file mode 100644 index 0000000..24c43bc --- /dev/null +++ b/newsfragments/+touch-readonly.bugfix.rst @@ -0,0 +1 @@ +Allow ``Path.touch()`` to update timestamps on existing read-only files. diff --git a/path/__init__.py b/path/__init__.py index 731e88e..32bf44e 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -1415,8 +1415,7 @@ def touch(self) -> Self: """Set the access/modified times of this file to the current time. Create the file if it does not exist. """ - os.close(os.open(self, os.O_WRONLY | os.O_CREAT, 0o666)) - os.utime(self, None) + pathlib.Path(self).touch() return self def remove(self) -> Self: diff --git a/tests/test_path.py b/tests/test_path.py index 55d733c..68de987 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -460,6 +460,20 @@ class TestScratchDir: Tests that run in a temporary directory (does not test TempDir class) """ + @pytest.mark.skipif(os.name == 'nt', reason='POSIX file permissions') + def test_touch_readonly_file(self, tmp_path): + target = Path(tmp_path / 'readonly.txt') + target.write_text('preserved content') + target.utime((1_000_000_000, 1_000_000_000)) + target.chmod(0o444) + try: + assert target.touch() is target + assert target.stat().st_mtime > 1_000_000_000 + assert target.stat().st_mode & 0o777 == 0o444 + assert target.read_text(encoding='utf-8') == 'preserved content' + finally: + target.chmod(0o644) + def test_context_manager(self, tmpdir): """Can be used as context manager for chdir.""" d = Path(tmpdir)