From 38f3e0053785e0bfb40342518f78829289b1d3cb Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Thu, 21 Mar 2024 10:20:35 +0100 Subject: [PATCH 01/11] Same interface for `posixpath` & `ntpath` --- Lib/genericpath.py | 11 ++++++++++- Lib/ntpath.py | 13 ++----------- Lib/posixpath.py | 31 +++++++++++-------------------- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/Lib/genericpath.py b/Lib/genericpath.py index 1bd5b3897c3af9..862450c86220ee 100644 --- a/Lib/genericpath.py +++ b/Lib/genericpath.py @@ -8,7 +8,7 @@ __all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime', 'getsize', 'isdir', 'isfile', 'islink', 'samefile', 'sameopenfile', - 'samestat'] + 'samestat','lexists'] # Does a path exist? @@ -22,6 +22,15 @@ def exists(path): return True +# Being true for dangling symbolic links is also useful. +def lexists(path): + """Test whether a path exists. Returns True for broken symbolic links""" + try: + os.lstat(path) + except (OSError, ValueError): + return False + return True + # This follows symbolic links, so both islink() and isdir() can be true # for the same path on systems that support symlinks def isfile(path): diff --git a/Lib/ntpath.py b/Lib/ntpath.py index e7cbfe17ecb3c8..109d43445a2b50 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -29,7 +29,8 @@ "ismount","isreserved","expanduser","expandvars","normpath", "abspath","curdir","pardir","sep","pathsep","defpath","altsep", "extsep","devnull","realpath","supports_unicode_filenames","relpath", - "samefile", "sameopenfile", "samestat", "commonpath", "isjunction"] + "samefile", "sameopenfile", "samestat", "commonpath", "isjunction", + "isdevdrive"] def _get_bothseps(path): if isinstance(path, bytes): @@ -286,16 +287,6 @@ def isjunction(path): return False -# Being true for dangling symbolic links is also useful. - -def lexists(path): - """Test whether a path exists. Returns True for broken symbolic links""" - try: - st = os.lstat(path) - except (OSError, ValueError): - return False - return True - # Is a path a mount point? # Any drive letter root (eg c:\) # Any share UNC (eg \\server\share) diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 33943b4403636a..bd5efc277a77a6 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -35,7 +35,7 @@ "samefile","sameopenfile","samestat", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", "devnull","realpath","supports_unicode_filenames","relpath", - "commonpath", "isjunction"] + "commonpath", "isjunction","isreserved","isdevdrive"] def _get_sep(path): @@ -168,23 +168,14 @@ def splitroot(p): def basename(p): """Returns the final component of a pathname""" - p = os.fspath(p) - sep = _get_sep(p) - i = p.rfind(sep) + 1 - return p[i:] + return split(p)[1] # Return the head (dirname) part of a path, same as split(path)[0]. def dirname(p): """Returns the directory component of a pathname""" - p = os.fspath(p) - sep = _get_sep(p) - i = p.rfind(sep) + 1 - head = p[:i] - if head and head != sep*len(head): - head = head.rstrip(sep) - return head + return split(p)[0] # Is a path a junction? @@ -196,16 +187,16 @@ def isjunction(path): return False -# Being true for dangling symbolic links is also useful. +def isreserved(path): + """Return true if the pathname is reserved by the system. + Always returns False on posix""" + return False -def lexists(path): - """Test whether a path exists. Returns True for broken symbolic links""" - try: - os.lstat(path) - except (OSError, ValueError): - return False - return True +def isdevdrive(path): + """Determines whether the specified path is on a Dev Drive. + Dev Drives are not a part of posix semantics""" + return False # Is a path a mount point? # (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) From ca1376bb3d9a37136ba633c31f33db041589b580 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 09:57:58 +0000 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst new file mode 100644 index 00000000000000..4694ac83aba73c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst @@ -0,0 +1 @@ +Added posix implementation for isreserved & isdevdrive. From e29802efbb66af2129ef4d9b90e70a38d694004b Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Thu, 21 Mar 2024 13:17:35 +0100 Subject: [PATCH 03/11] Decouple logic for `splitdrive` from `splitroot` --- Lib/ntpath.py | 65 +++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 109d43445a2b50..9c27069cfb0b99 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -165,8 +165,33 @@ def splitdrive(p): Paths cannot contain both a drive letter and a UNC path. """ - drive, root, tail = splitroot(p) - return drive, root + tail + p = os.fspath(p) + if isinstance(p, bytes): + sep = b'\\' + altsep = b'/' + colon = b':' + unc_prefix = b'\\\\?\\UNC\\' + else: + sep = '\\' + altsep = '/' + colon = ':' + unc_prefix = '\\\\?\\UNC\\' + normp = p.replace(altsep, sep) + if normp[:2] == sep * 2: + # UNC drives, e.g. \\server\share or \\?\UNC\server\share + # Device drives, e.g. \\.\device or \\?\device + start = 8 if normp[:8].upper() == unc_prefix else 2 + index = normp.find(sep, start) + if index == -1: + return p, p[:0] + index2 = normp.find(sep, index + 1) + if index2 == -1: + return p, p[:0] + return p[:index2], p[index2:] + if normp[1:2] == colon: + # Drive-letter drives, e.g. X: + return p[:2], p[2:] + return p[:0], p def splitroot(p): @@ -180,45 +205,19 @@ def splitroot(p): splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham') splitroot('Windows/notepad') == ('', '', 'Windows/notepad') """ - p = os.fspath(p) + drive, p = splitdrive(p) if isinstance(p, bytes): sep = b'\\' altsep = b'/' - colon = b':' - unc_prefix = b'\\\\?\\UNC\\' - empty = b'' else: sep = '\\' altsep = '/' - colon = ':' - unc_prefix = '\\\\?\\UNC\\' - empty = '' normp = p.replace(altsep, sep) if normp[:1] == sep: - if normp[1:2] == sep: - # UNC drives, e.g. \\server\share or \\?\UNC\server\share - # Device drives, e.g. \\.\device or \\?\device - start = 8 if normp[:8].upper() == unc_prefix else 2 - index = normp.find(sep, start) - if index == -1: - return p, empty, empty - index2 = normp.find(sep, index + 1) - if index2 == -1: - return p, empty, empty - return p[:index2], p[index2:index2 + 1], p[index2 + 1:] - else: - # Relative path with root, e.g. \Windows - return empty, p[:1], p[1:] - elif normp[1:2] == colon: - if normp[2:3] == sep: - # Absolute drive-letter path, e.g. X:\Windows - return p[:2], p[2:3], p[3:] - else: - # Relative path with drive, e.g. X:Windows - return p[:2], empty, p[2:] - else: - # Relative path, e.g. Windows - return empty, empty, p + # Absolute path, e.g. X:\Windows + return drive, p[:1], p[1:] + # Relative path, e.g. X:Windows + return drive, p[:0], p # Split a path in head (everything up to the last '/') and tail (the From e9cc0c968135e61436c56e6b27c66f4bdbea1760 Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Thu, 21 Mar 2024 16:40:50 +0100 Subject: [PATCH 04/11] Fixed `splitdrive` for "/:/foo" --- Lib/ntpath.py | 9 +++++---- Lib/test/test_ntpath.py | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 9c27069cfb0b99..5a8b2eb5f65ced 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -177,7 +177,11 @@ def splitdrive(p): colon = ':' unc_prefix = '\\\\?\\UNC\\' normp = p.replace(altsep, sep) - if normp[:2] == sep * 2: + if normp[:1] != sep: + if normp[1:2] == colon: + # Drive-letter drives, e.g. X: + return p[:2], p[2:] + elif normp[1:2] == sep: # UNC drives, e.g. \\server\share or \\?\UNC\server\share # Device drives, e.g. \\.\device or \\?\device start = 8 if normp[:8].upper() == unc_prefix else 2 @@ -188,9 +192,6 @@ def splitdrive(p): if index2 == -1: return p, p[:0] return p[:index2], p[index2:] - if normp[1:2] == colon: - # Drive-letter drives, e.g. X: - return p[:2], p[2:] return p[:0], p diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index 9cb03e3cd5de8d..ee2a6186c7294a 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -124,6 +124,11 @@ def test_splitdrive(self): tester('ntpath.splitdrive("//?/UNC/server/share/dir")', ("//?/UNC/server/share", "/dir")) + # gh-101363: match GetFullPathNameW() drive letter parsing behaviour + tester('ntpath.splitdrive(" :/foo")', (" :", "/foo")) + tester('ntpath.splitdrive("/:/foo")', ("", "/:/foo")) + + def test_splitroot(self): tester("ntpath.splitroot('')", ('', '', '')) tester("ntpath.splitroot('foo')", ('', '', 'foo')) @@ -210,10 +215,6 @@ def test_splitroot(self): tester('ntpath.splitroot("//x")', ("//x", "", "")) # non-empty server & missing share tester('ntpath.splitroot("//x/")', ("//x/", "", "")) # non-empty server & empty share - # gh-101363: match GetFullPathNameW() drive letter parsing behaviour - tester('ntpath.splitroot(" :/foo")', (" :", "/", "foo")) - tester('ntpath.splitroot("/:/foo")', ("", "/", ":/foo")) - def test_split(self): tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar')) tester('ntpath.split("\\\\conky\\mountpoint\\foo\\bar")', From d4aef8676f28bdcf0f2b91ec3b2813258a8bcc33 Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Fri, 22 Mar 2024 14:26:21 +0100 Subject: [PATCH 05/11] Make requested changes --- Lib/ntpath.py | 60 ++++++++++--------- Lib/posixpath.py | 21 ++++--- Lib/test/test_ntpath.py | 9 ++- ...-03-21-09-57-57.gh-issue-117114.Qu-p55.rst | 2 +- 4 files changed, 48 insertions(+), 44 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 5a8b2eb5f65ced..3e065886270283 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -165,6 +165,22 @@ def splitdrive(p): Paths cannot contain both a drive letter and a UNC path. """ + drive, root, tail = splitroot(p) + return drive, root + tail + + +def splitroot(p): + """Split a pathname into drive, root and tail. The drive is defined + exactly as in splitdrive(). On Windows, the root may be a single path + separator or an empty string. The tail contains anything after the root. + For example: + + splitroot('//server/share/') == ('//server/share', '/', '') + splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney') + splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham') + splitroot('Windows/notepad') == ('', '', 'Windows/notepad') + """ + # Split drive p = os.fspath(p) if isinstance(p, bytes): sep = b'\\' @@ -180,41 +196,27 @@ def splitdrive(p): if normp[:1] != sep: if normp[1:2] == colon: # Drive-letter drives, e.g. X: - return p[:2], p[2:] - elif normp[1:2] == sep: + drive, p = p[:2], p[2:] + else: + drive = p[:0] + elif normp[1:2] != sep: + drive = p[:0] + else: # UNC drives, e.g. \\server\share or \\?\UNC\server\share # Device drives, e.g. \\.\device or \\?\device start = 8 if normp[:8].upper() == unc_prefix else 2 index = normp.find(sep, start) if index == -1: - return p, p[:0] - index2 = normp.find(sep, index + 1) - if index2 == -1: - return p, p[:0] - return p[:index2], p[index2:] - return p[:0], p - - -def splitroot(p): - """Split a pathname into drive, root and tail. The drive is defined - exactly as in splitdrive(). On Windows, the root may be a single path - separator or an empty string. The tail contains anything after the root. - For example: + drive, p = p, p[:0] + else: + index2 = normp.find(sep, index + 1) + if index2 == -1: + drive, p = p, p[:0] + else: + drive, p = p[:index2], p[index2:] - splitroot('//server/share/') == ('//server/share', '/', '') - splitroot('C:/Users/Barney') == ('C:', '/', 'Users/Barney') - splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham') - splitroot('Windows/notepad') == ('', '', 'Windows/notepad') - """ - drive, p = splitdrive(p) - if isinstance(p, bytes): - sep = b'\\' - altsep = b'/' - else: - sep = '\\' - altsep = '/' - normp = p.replace(altsep, sep) - if normp[:1] == sep: + # Split root + if normp[len(drive):len(drive)+1] == sep: # Absolute path, e.g. X:\Windows return drive, p[:1], p[1:] # Relative path, e.g. X:Windows diff --git a/Lib/posixpath.py b/Lib/posixpath.py index bd5efc277a77a6..53f2d391906fa9 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -35,7 +35,7 @@ "samefile","sameopenfile","samestat", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", "devnull","realpath","supports_unicode_filenames","relpath", - "commonpath", "isjunction","isreserved","isdevdrive"] + "commonpath", "isjunction","isdevdrive"] def _get_sep(path): @@ -168,14 +168,23 @@ def splitroot(p): def basename(p): """Returns the final component of a pathname""" - return split(p)[1] + p = os.fspath(p) + sep = _get_sep(p) + i = p.rfind(sep) + 1 + return p[i:] # Return the head (dirname) part of a path, same as split(path)[0]. def dirname(p): """Returns the directory component of a pathname""" - return split(p)[0] + p = os.fspath(p) + sep = _get_sep(p) + i = p.rfind(sep) + 1 + head = p[:i] + if head and head != sep*len(head): + head = head.rstrip(sep) + return head # Is a path a junction? @@ -187,12 +196,6 @@ def isjunction(path): return False -def isreserved(path): - """Return true if the pathname is reserved by the system. - Always returns False on posix""" - return False - - def isdevdrive(path): """Determines whether the specified path is on a Dev Drive. Dev Drives are not a part of posix semantics""" diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py index ee2a6186c7294a..9cb03e3cd5de8d 100644 --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -124,11 +124,6 @@ def test_splitdrive(self): tester('ntpath.splitdrive("//?/UNC/server/share/dir")', ("//?/UNC/server/share", "/dir")) - # gh-101363: match GetFullPathNameW() drive letter parsing behaviour - tester('ntpath.splitdrive(" :/foo")', (" :", "/foo")) - tester('ntpath.splitdrive("/:/foo")', ("", "/:/foo")) - - def test_splitroot(self): tester("ntpath.splitroot('')", ('', '', '')) tester("ntpath.splitroot('foo')", ('', '', 'foo')) @@ -215,6 +210,10 @@ def test_splitroot(self): tester('ntpath.splitroot("//x")', ("//x", "", "")) # non-empty server & missing share tester('ntpath.splitroot("//x/")', ("//x/", "", "")) # non-empty server & empty share + # gh-101363: match GetFullPathNameW() drive letter parsing behaviour + tester('ntpath.splitroot(" :/foo")', (" :", "/", "foo")) + tester('ntpath.splitroot("/:/foo")', ("", "/", ":/foo")) + def test_split(self): tester('ntpath.split("c:\\foo\\bar")', ('c:\\foo', 'bar')) tester('ntpath.split("\\\\conky\\mountpoint\\foo\\bar")', diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst index 4694ac83aba73c..40ff2ed01feaa8 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst @@ -1 +1 @@ -Added posix implementation for isreserved & isdevdrive. +Added posix implementation for isdevdrive. From 63d219c61d6fbea6233c79cff630fba302a76ff4 Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Fri, 22 Mar 2024 19:20:44 +0100 Subject: [PATCH 06/11] Revert `splitroot` --- Lib/ntpath.py | 51 +++++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 3e065886270283..96c8c0a5983036 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -187,40 +187,39 @@ def splitroot(p): altsep = b'/' colon = b':' unc_prefix = b'\\\\?\\UNC\\' + empty = b'' else: sep = '\\' altsep = '/' colon = ':' unc_prefix = '\\\\?\\UNC\\' + empty = '' normp = p.replace(altsep, sep) - if normp[:1] != sep: - if normp[1:2] == colon: - # Drive-letter drives, e.g. X: - drive, p = p[:2], p[2:] - else: - drive = p[:0] - elif normp[1:2] != sep: - drive = p[:0] - else: - # UNC drives, e.g. \\server\share or \\?\UNC\server\share - # Device drives, e.g. \\.\device or \\?\device - start = 8 if normp[:8].upper() == unc_prefix else 2 - index = normp.find(sep, start) - if index == -1: - drive, p = p, p[:0] - else: + if normp[:1] == sep: + if normp[1:2] == sep: + # UNC drives, e.g. \\server\share or \\?\UNC\server\share + # Device drives, e.g. \\.\device or \\?\device + start = 8 if normp[:8].upper() == unc_prefix else 2 + index = normp.find(sep, start) + if index == -1: + return p, empty, empty index2 = normp.find(sep, index + 1) if index2 == -1: - drive, p = p, p[:0] - else: - drive, p = p[:index2], p[index2:] - - # Split root - if normp[len(drive):len(drive)+1] == sep: - # Absolute path, e.g. X:\Windows - return drive, p[:1], p[1:] - # Relative path, e.g. X:Windows - return drive, p[:0], p + return p, empty, empty + return p[:index2], p[index2:index2 + 1], p[index2 + 1:] + else: + # Relative path with root, e.g. \Windows + return empty, p[:1], p[1:] + elif normp[1:2] == colon: + if normp[2:3] == sep: + # Absolute drive-letter path, e.g. X:\Windows + return p[:2], p[2:3], p[3:] + else: + # Relative path with drive, e.g. X:Windows + return p[:2], empty, p[2:] + else: + # Relative path, e.g. Windows + return empty, empty, p # Split a path in head (everything up to the last '/') and tail (the From 22f2c7985d642e47eb3d3a1b05db7319bc18f08e Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Fri, 22 Mar 2024 19:23:03 +0100 Subject: [PATCH 07/11] Remove comment --- Lib/ntpath.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 96c8c0a5983036..109d43445a2b50 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -180,7 +180,6 @@ def splitroot(p): splitroot('C:///spam///ham') == ('C:', '/', '//spam///ham') splitroot('Windows/notepad') == ('', '', 'Windows/notepad') """ - # Split drive p = os.fspath(p) if isinstance(p, bytes): sep = b'\\' From 50a9e30cc78eb9e8cea17756c03109bcc7d87513 Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Sat, 23 Mar 2024 09:37:09 +0100 Subject: [PATCH 08/11] Update Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst Co-authored-by: Kirill Podoprigora --- .../2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst index 40ff2ed01feaa8..1d7359072a4a04 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst @@ -1 +1 @@ -Added posix implementation for isdevdrive. +Added POSIX implementation for :func:`os.path.isdevdrive`. From 0193598e2b80d8002bf3a52c10d98548d0baf389 Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Sun, 24 Mar 2024 20:42:47 +0100 Subject: [PATCH 09/11] Allow checking support for Dev Drives / junctions You can now check if a platform supports Dev Drives / junctions: - `ntpath.isdevdrive` is not `genericpath.isdevdrive`, `posixpath.isdevdrive` is not `genericpath.isdevdrive` - `ntpath.isjunction` is not `genericpath.isjunction`, `posixpath.isjunction` is not `genericpath.isjunction` --- Doc/library/os.path.rst | 5 ++++- Lib/genericpath.py | 19 +++++++++++++++++-- Lib/ntpath.py | 15 +++++---------- Lib/posixpath.py | 14 -------------- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index 3ee2b7db1e511b..b7150afbafc99b 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -324,10 +324,13 @@ the :mod:`glob` module.) Dev Drives. See `the Windows documentation `_ for information on enabling and creating Dev Drives. - .. availability:: Windows. + .. availability:: Unix, Windows. .. versionadded:: 3.12 + .. versionchanged:: 3.13 + The function is now available on all platforms, and will always return ``False`` on those that have no support for Dev Drives + .. function:: isreserved(path) diff --git a/Lib/genericpath.py b/Lib/genericpath.py index 862450c86220ee..ba7b0a13c7f81d 100644 --- a/Lib/genericpath.py +++ b/Lib/genericpath.py @@ -7,8 +7,8 @@ import stat __all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime', - 'getsize', 'isdir', 'isfile', 'islink', 'samefile', 'sameopenfile', - 'samestat','lexists'] + 'getsize', 'isdevdrive', 'isdir', 'isfile', 'isjunction', 'islink', + 'lexists', 'samefile', 'sameopenfile', 'samestat'] # Does a path exist? @@ -66,6 +66,21 @@ def islink(path): return stat.S_ISLNK(st.st_mode) +# Is a path a junction? +def isjunction(path): + """Test whether a path is a junction + Junctions are not supported on the current platform""" + os.fspath(path) + return False + + +def isdevdrive(path): + """Determines whether the specified path is on a Windows Dev Drive. + Dev Drives are not supported on the current platform""" + os.fspath(path) + return False + + def getsize(filename): """Return the size of a file, reported by os.stat().""" return os.stat(filename).st_size diff --git a/Lib/ntpath.py b/Lib/ntpath.py index 109d43445a2b50..f1c48ecd1e5e2a 100644 --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -281,10 +281,8 @@ def isjunction(path): return False return bool(st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT) else: - def isjunction(path): - """Test whether a path is a junction""" - os.fspath(path) - return False + # Use genericpath.isjunction as imported above + pass # Is a path a mount point? @@ -907,15 +905,12 @@ def commonpath(paths): try: from nt import _path_isdevdrive -except ImportError: - def isdevdrive(path): - """Determines whether the specified path is on a Windows Dev Drive.""" - # Never a Dev Drive - return False -else: def isdevdrive(path): """Determines whether the specified path is on a Windows Dev Drive.""" try: return _path_isdevdrive(abspath(path)) except OSError: return False +except ImportError: + # Use genericpath.isdevdrive as imported above + pass diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 53f2d391906fa9..4fc02be69bd6e1 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -187,20 +187,6 @@ def dirname(p): return head -# Is a path a junction? - -def isjunction(path): - """Test whether a path is a junction - Junctions are not a part of posix semantics""" - os.fspath(path) - return False - - -def isdevdrive(path): - """Determines whether the specified path is on a Dev Drive. - Dev Drives are not a part of posix semantics""" - return False - # Is a path a mount point? # (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) From cbf1dc25765f5a70f2c6d2aa3f684e0e2902f147 Mon Sep 17 00:00:00 2001 From: Nice Zombies Date: Mon, 25 Mar 2024 21:39:44 +0100 Subject: [PATCH 10/11] Update Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst Co-authored-by: Steve Dower --- .../2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst index 1d7359072a4a04..c9c028a8dda0e5 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-03-21-09-57-57.gh-issue-117114.Qu-p55.rst @@ -1 +1 @@ -Added POSIX implementation for :func:`os.path.isdevdrive`. +Make :func:`os.path.isdevdrive` available on all platforms. For those that do not offer Dev Drives, it will always return ``False``. From 84c0c97dd5fdf3a45213cf4fba3f109527e45dd8 Mon Sep 17 00:00:00 2001 From: Nineteendo Date: Mon, 25 Mar 2024 21:52:00 +0100 Subject: [PATCH 11/11] added link to `genericpath.py` --- Doc/library/os.path.rst | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index b7150afbafc99b..dcc877da0b3122 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -4,7 +4,7 @@ .. module:: os.path :synopsis: Operations on pathnames. -**Source code:** :source:`Lib/posixpath.py` (for POSIX) and +**Source code:** :source:`Lib/genericpath.py`, :source:`Lib/posixpath.py` (for POSIX) and :source:`Lib/ntpath.py` (for Windows). .. index:: single: path; operations @@ -85,8 +85,6 @@ the :mod:`glob` module.) if *paths* is empty. Unlike :func:`commonprefix`, this returns a valid path. - .. availability:: Unix, Windows. - .. versionadded:: 3.5 .. versionchanged:: 3.6 @@ -324,8 +322,6 @@ the :mod:`glob` module.) Dev Drives. See `the Windows documentation `_ for information on enabling and creating Dev Drives. - .. availability:: Unix, Windows. - .. versionadded:: 3.12 .. versionchanged:: 3.13 @@ -445,8 +441,6 @@ the :mod:`glob` module.) *start* defaults to :data:`os.curdir`. - .. availability:: Unix, Windows. - .. versionchanged:: 3.6 Accepts a :term:`path-like object`. @@ -457,8 +451,6 @@ the :mod:`glob` module.) This is determined by the device number and i-node number and raises an exception if an :func:`os.stat` call on either pathname fails. - .. availability:: Unix, Windows. - .. versionchanged:: 3.2 Added Windows support. @@ -473,8 +465,6 @@ the :mod:`glob` module.) Return ``True`` if the file descriptors *fp1* and *fp2* refer to the same file. - .. availability:: Unix, Windows. - .. versionchanged:: 3.2 Added Windows support. @@ -489,8 +479,6 @@ the :mod:`glob` module.) :func:`os.lstat`, or :func:`os.stat`. This function implements the underlying comparison used by :func:`samefile` and :func:`sameopenfile`. - .. availability:: Unix, Windows. - .. versionchanged:: 3.4 Added Windows support.