From 11764afc44e924071202fb35bae6e77b6b0cfd5d Mon Sep 17 00:00:00 2001 From: Vitaliy <160263432+vitalivo@users.noreply.github.com> Date: Sat, 12 Sep 2026 16:34:15 +0300 Subject: [PATCH 1/2] Reject existing files in mkdir_p --- newsfragments/+mkdir-p-file.bugfix.rst | 1 + path/__init__.py | 5 ++++- tests/test_path.py | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 newsfragments/+mkdir-p-file.bugfix.rst diff --git a/newsfragments/+mkdir-p-file.bugfix.rst b/newsfragments/+mkdir-p-file.bugfix.rst new file mode 100644 index 0000000..558a90e --- /dev/null +++ b/newsfragments/+mkdir-p-file.bugfix.rst @@ -0,0 +1 @@ +``Path.mkdir_p`` now raises ``FileExistsError`` when the path already exists as a file. diff --git a/path/__init__.py b/path/__init__.py index 33dd979..4f2e5b9 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -1369,8 +1369,11 @@ def mkdir(self, mode: int = 0o777) -> Self: def mkdir_p(self, mode: int = 0o777) -> Self: """Like :meth:`mkdir`, but does not raise an exception if the directory already exists.""" - with contextlib.suppress(FileExistsError): + try: self.mkdir(mode) + except FileExistsError: + if not self.is_dir(): + raise return self def makedirs(self, mode: int = 0o777) -> Self: diff --git a/tests/test_path.py b/tests/test_path.py index b424bb6..c3c5764 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -294,6 +294,17 @@ def test_renames(self, tmpdir): def test_mkdir_p(self, tmpdir): Path(tmpdir).mkdir_p() + def test_mkdir_p_existing_file(self, tmpdir): + file = (Path(tmpdir) / 'file').touch() + with pytest.raises(FileExistsError): + file.mkdir_p() + assert file.is_file() + + def test_mkdir_p_new_directory(self, tmpdir): + directory = Path(tmpdir) / 'new' + assert directory.mkdir_p() == directory + assert directory.is_dir() + def test_removedirs_p(self, tmpdir): dir = Path(tmpdir) / 'somedir' dir.mkdir() From 477ec716aabe8e46263f2df51c2621e71687cb12 Mon Sep 17 00:00:00 2001 From: Vitaliy <160263432+vitalivo@users.noreply.github.com> Date: Sat, 12 Sep 2026 16:49:06 +0300 Subject: [PATCH 2/2] Apply the existing-directory check to makedirs_p too --- newsfragments/+mkdir-p-file.bugfix.rst | 2 +- path/__init__.py | 5 ++++- tests/test_path.py | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/newsfragments/+mkdir-p-file.bugfix.rst b/newsfragments/+mkdir-p-file.bugfix.rst index 558a90e..d8f4512 100644 --- a/newsfragments/+mkdir-p-file.bugfix.rst +++ b/newsfragments/+mkdir-p-file.bugfix.rst @@ -1 +1 @@ -``Path.mkdir_p`` now raises ``FileExistsError`` when the path already exists as a file. +``Path.mkdir_p`` and ``Path.makedirs_p`` now raise ``FileExistsError`` when the path already exists as a file. diff --git a/path/__init__.py b/path/__init__.py index 4f2e5b9..587f8d8 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -1384,8 +1384,11 @@ def makedirs(self, mode: int = 0o777) -> Self: def makedirs_p(self, mode: int = 0o777) -> Self: """Like :meth:`makedirs`, but does not raise an exception if the directory already exists.""" - with contextlib.suppress(FileExistsError): + try: self.makedirs(mode) + except FileExistsError: + if not self.is_dir(): + raise return self def rmdir(self) -> Self: diff --git a/tests/test_path.py b/tests/test_path.py index c3c5764..3c1cde3 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -294,10 +294,11 @@ def test_renames(self, tmpdir): def test_mkdir_p(self, tmpdir): Path(tmpdir).mkdir_p() - def test_mkdir_p_existing_file(self, tmpdir): + @pytest.mark.parametrize('method', ['mkdir_p', 'makedirs_p']) + def test_mkdir_p_existing_file(self, tmpdir, method): file = (Path(tmpdir) / 'file').touch() with pytest.raises(FileExistsError): - file.mkdir_p() + getattr(file, method)() assert file.is_file() def test_mkdir_p_new_directory(self, tmpdir):