From 57daeb2c7142e220651976e206c34e68364b6df0 Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 14:34:31 +0100 Subject: [PATCH 01/11] Update ismount() to return False if path does not exist when checking for mounted volume --- Lib/ntpath.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 08c529c5963a4d..f135e34522a20c 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -290,9 +290,11 @@ def ismount(path): return True if _getvolumepathname: - x = path.rstrip(seps) - y =_getvolumepathname(path).rstrip(seps) - return x.casefold() == y.casefold() + try: + # The path is a mount point if it's a mounted volume. + return path.rstrip(seps).casefold() == _getvolumepathname(path).rstrip(seps).casefold() + except (OSError, FileNotFoundError): + return False else: return False From e49c158b5126a2c898e99c2b29836e88897af9b3 Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 14:35:43 +0100 Subject: [PATCH 02/11] Update ismount() to return False for non-existent drive roots --- Lib/ntpath.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index f135e34522a20c..69db9034a5b1c7 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -287,7 +287,8 @@ def ismount(path): if drive and drive[0] in seps: return not rest if root and not rest: - return True + # Drive root is a mount point if it exists. + return exists(path) if _getvolumepathname: try: From 6e40c62c5053319607c2506a9453a2882b16229a Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 14:39:33 +0100 Subject: [PATCH 03/11] Add comment to ismount() --- Lib/ntpath.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 69db9034a5b1c7..48815b6d0ce82a 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -285,6 +285,7 @@ def ismount(path): path = abspath(path) drive, root, rest = splitroot(path) if drive and drive[0] in seps: + # Share path is a mount point if it conforms to UNC. return not rest if root and not rest: # Drive root is a mount point if it exists. From 7b7e9f651eb537b79a910d13174609bf0fdb29f7 Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 15:50:50 +0100 Subject: [PATCH 04/11] Add test for non-existent drive and non-existent path on non-existent drive --- Lib/test/test_ntpath.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index b9cd75a3b8adea..d4fd8a3922d9c9 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1368,6 +1368,17 @@ def test_ismount(self): self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\")) self.assertTrue(ntpath.ismount(b"\\\\.\\C:\\")) + # Look for a non-existent drive letter that can be used to test + # behaviour of ismount(). + for drive in "DEFGHIJKLMNOPQRSTUVWXYZ": + if not ntpath.exists(drive + ":\\"): + self.assertFalse(ntpath.ismount(drive + ":\\")) + self.assertFalse(ntpath.ismount(drive + ":\\NotExist")) + break + else: + if support.verbose: + print("No missing drive found to test 'ismount'") + with os_helper.temp_dir() as d: self.assertFalse(ntpath.ismount(d)) From 166d1f228799d15192724caf3c586299523a78ce Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 15:56:12 +0100 Subject: [PATCH 05/11] Revert to previous method of assigning rstrip() results to variables Attempting to to casefold() and compare in a single line results in AttributeError being raised during testing with test_ntpath.py --- Lib/ntpath.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 48815b6d0ce82a..8f535887ff5cce 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -294,7 +294,9 @@ def ismount(path): if _getvolumepathname: try: # The path is a mount point if it's a mounted volume. - return path.rstrip(seps).casefold() == _getvolumepathname(path).rstrip(seps).casefold() + x = path.rstrip(seps) + y = _getvolumepathname(path).rstrip(seps) + return x.casefold() == y.casefold() except (OSError, FileNotFoundError): return False else: From db140d8ca2fa5004715098c6d4dcc5853123d838 Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 15:59:07 +0100 Subject: [PATCH 06/11] Remove white space --- Lib/ntpath.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 8f535887ff5cce..1d9ee2b70d95b4 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -290,7 +290,6 @@ def ismount(path): if root and not rest: # Drive root is a mount point if it exists. return exists(path) - if _getvolumepathname: try: # The path is a mount point if it's a mounted volume. From 8c540f9ab931204a0143ecd453eef3f6ccffbd71 Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 16:07:52 +0100 Subject: [PATCH 07/11] Update ismount() to specify existent drive letter root is a mount point --- Doc/library/os.path.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index bb9a7c86464050..53e7a4c1921d17 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -299,8 +299,8 @@ the :mod:`glob` module.) i-node on the same device --- this should detect mount points for all Unix and POSIX variants. It is not able to reliably detect bind mounts on the same filesystem. On Linux systems, it will always return ``True`` for btrfs - subvolumes, even if they aren't mount points. On Windows, a drive letter root - and a share UNC are always mount points, and for any other path + subvolumes, even if they aren't mount points. On Windows, a existent drive + letter root and a share UNC are always mount points, and for any other path ``GetVolumePathName`` is called to see if it is different from the input path. .. versionchanged:: 3.4 From bda1ad8065fe2070e8c9d9296f175afab23da558 Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 16:15:13 +0100 Subject: [PATCH 08/11] Add NEWS.d entry --- .../next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst diff --git a/Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst b/Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst new file mode 100644 index 00000000000000..850b7be4098a5d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst @@ -0,0 +1 @@ +For Windows, os.path.ismount() now returns False for non-existent drive letter roots. \ No newline at end of file From a168cb814f01be3f4d86353be01f6e3a68d6b9ed Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 16:16:40 +0100 Subject: [PATCH 09/11] Add self to ACKS --- Misc/ACKS | 1 + 1 file changed, 1 insertion(+) diff --git a/Misc/ACKS b/Misc/ACKS index 0812b229e0ada4..c56800990a68b8 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -498,6 +498,7 @@ Eugene Dvurechenski Karmen Dykstra Josip Dzolonga Maxim Dzumanenko +Thomas Earp Hans Eckardt Rodolpho Eckhardt Ulrich Eckhardt From a96dc0985454da3833871d44c0c0228c15b885d4 Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 16:42:24 +0100 Subject: [PATCH 10/11] Modify to pass lint checks Added newline at end of News entry. Removed trailing whitespace on comment in test_ntpath.py --- Lib/test/test_ntpath.py | 2 +- .../next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index d4fd8a3922d9c9..43d3e4353630ef 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1368,7 +1368,7 @@ def test_ismount(self): self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\")) self.assertTrue(ntpath.ismount(b"\\\\.\\C:\\")) - # Look for a non-existent drive letter that can be used to test + # Look for a non-existent drive letter that can be used to test # behaviour of ismount(). for drive in "DEFGHIJKLMNOPQRSTUVWXYZ": if not ntpath.exists(drive + ":\\"): diff --git a/Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst b/Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst index 850b7be4098a5d..35b29fbc3389ac 100644 --- a/Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst +++ b/Misc/NEWS.d/next/Library/2025-10-10-16-13-00.gh-issue-73045.4ks8g7.rst @@ -1 +1 @@ -For Windows, os.path.ismount() now returns False for non-existent drive letter roots. \ No newline at end of file +For Windows, os.path.ismount() now returns False for non-existent drive letter roots. From dd75e7fa3c24a2b96f53a59153d4ebb16a05c60c Mon Sep 17 00:00:00 2001 From: cowgoesmoo69 Date: Fri, 10 Oct 2025 17:40:41 +0100 Subject: [PATCH 11/11] Add win32 condition to tests that will fail outside of Windows --- Lib/test/test_ntpath.py | 49 +++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 43d3e4353630ef..52736d1d1c85f4 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1354,30 +1354,31 @@ def test_sameopenfile(self): ntpath.sameopenfile(-1, -1) def test_ismount(self): - self.assertTrue(ntpath.ismount("c:\\")) - self.assertTrue(ntpath.ismount("C:\\")) - self.assertTrue(ntpath.ismount("c:/")) - self.assertTrue(ntpath.ismount("C:/")) - self.assertTrue(ntpath.ismount("\\\\.\\c:\\")) - self.assertTrue(ntpath.ismount("\\\\.\\C:\\")) - - self.assertTrue(ntpath.ismount(b"c:\\")) - self.assertTrue(ntpath.ismount(b"C:\\")) - self.assertTrue(ntpath.ismount(b"c:/")) - self.assertTrue(ntpath.ismount(b"C:/")) - self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\")) - self.assertTrue(ntpath.ismount(b"\\\\.\\C:\\")) - - # Look for a non-existent drive letter that can be used to test - # behaviour of ismount(). - for drive in "DEFGHIJKLMNOPQRSTUVWXYZ": - if not ntpath.exists(drive + ":\\"): - self.assertFalse(ntpath.ismount(drive + ":\\")) - self.assertFalse(ntpath.ismount(drive + ":\\NotExist")) - break - else: - if support.verbose: - print("No missing drive found to test 'ismount'") + if sys.platform == "win32": + self.assertTrue(ntpath.ismount("c:\\")) + self.assertTrue(ntpath.ismount("C:\\")) + self.assertTrue(ntpath.ismount("c:/")) + self.assertTrue(ntpath.ismount("C:/")) + self.assertTrue(ntpath.ismount("\\\\.\\c:\\")) + self.assertTrue(ntpath.ismount("\\\\.\\C:\\")) + + self.assertTrue(ntpath.ismount(b"c:\\")) + self.assertTrue(ntpath.ismount(b"C:\\")) + self.assertTrue(ntpath.ismount(b"c:/")) + self.assertTrue(ntpath.ismount(b"C:/")) + self.assertTrue(ntpath.ismount(b"\\\\.\\c:\\")) + self.assertTrue(ntpath.ismount(b"\\\\.\\C:\\")) + + # Look for a non-existent drive letter that can be used to test + # behaviour of ismount(). + for drive in "DEFGHIJKLMNOPQRSTUVWXYZ": + if not ntpath.exists(drive + ":\\"): + self.assertFalse(ntpath.ismount(drive + ":\\")) + self.assertFalse(ntpath.ismount(drive + ":\\NotExist")) + break + else: + if support.verbose: + print("No missing drive found to test 'ismount'") with os_helper.temp_dir() as d: self.assertFalse(ntpath.ismount(d))