You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Antoine almost certainly thought about this with pathlib and may know about the change, or at least have some decent context on it.
I'm more inclined to think that os.path.isabs(r"\\server") should also return False, since it's not a path that can be opened directly unless you add more path before or after it.
Indeed, pathlib seems to support my understanding:
My experience says the main reason people want to know whether the path is absolute is to figure out whether to do Path.cwd() / path or not. According to that MSDN page, they shouldn't because the path starts with "//" (that is, the last character and the existence of the share name are irrelevant here).
Both pathlib and ntpath are reasonably consistent in determining the "drive" of the path:
>>> splitdrive('\\\\server\\')[0]
'\\\\server\\'
>>> splitdrive('\\\\server')[0]
''
>>> Path('\\\\server\\').parts[0]
'\\\\server\\\\'
>>> Path('\\\\server').parts[0]
'\\'
I assume the bug in the last statement is what Antoine is referring to.
The difference in results then comes from how they determine roots.
>>> splitdrive('\\\\server\\')[1]
''
>>> splitdrive('\\\\server')[1]
'\\\\server'
>>> Path('//server/').root
'\\'
>>> Path('//server').root
'\\'
Pathlib always has a root, but splitdrive doesn't.
I'm not sure exactly which one to fix where, but hopefully that helps someone else figure it out.
It looks to me that rather handling of "//server/" is buggy than "//server". "//server" is just the same as "/server" or "///server". But "//server/" looks as an UNC path with empty ("") mount point. This is invalid path and we can't create valid path from this path by adding components. Perhaps PureWindowsPath("//server/") should raise an exception.
I think '//server/share' is an absolute path, and pathlib agrees. Network shares do not maintain a current directory the way drives do (i.e. the hidden environment variable trick). There's no such thing as a share-relative path, nor would there be any way to even write such a path, as compared to "C:drive/relative/path".
"//server" is just the same as "/server" or "///server".
Repeated slashes aren't collapsed at the start of a Windows path. Here's what I get in Windows 7:
>>> os.listdir('/server')
[]
>>> os.listdir('//server')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [WinError 53] The network path was not found: '//server'
>>> os.listdir('///server')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [WinError 161] The specified path is invalid: '///server'
1 remaining item
akima commented on Sep 6, 2014
akimamannequin
MannequinAuthor
More actions
I just realised that "&monkeyfart!££" is actually a valid relative path name. What I said still holds, just replace "&monkeyfart!££" with ">elephant*dung?" (which contains the invalid characters: >*? ).
akima commented on Sep 6, 2014
akimamannequin
MannequinAuthor
More actions
eryksun: You have marked this bug as effecting Python 2.7. When I tested for the bug on 2.7.5 the problem didn't show up:
Python 2.7.5 (default, May 15 2013, 22:43:36) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os.path
>>> os.path.isabs(r"\\server")
True
>>> os.path.isabs(r"\\server\share")
True
>>> os.path.isabs(r"\\server\share\folder")
True
>>> os.path.isabs(r"\\server\share\folder\folder")
True
>>>
Did you independently test a later release of version 2.7 and find the issue? If not, could you remove Python 2.7 from the "Versions" list.
isabs also fails for device paths such as r"\\.\C:", which is an absolute path for opening the C: volume. UNC and device paths (i.e. \\server, \\?, and \\.) should always be considered absolute. Only logical drives (i.e. C:, D:, etc) support drive-relative paths.
It doesn't insert a backslash because the 'drive' ends in a colon. It needs to always insert a backslash for UNC paths, which cannot be reliably identified by checking whether the last character of the drive is a colon.
Thus a UNC path is absolute, i.e. any path that starts with 2 or more slashes, and all other paths are relative unless they have both a drive and a root. For example:
defisabs(s):
"""Test whether a path is absolute"""s=os.fspath(s)
seps=_get_bothseps(s)
iflen(s) >1ands[0] insepsands[1] inseps:
returnTruedrive, rest=splitdrive(s)
ifdriveandrest:
returnrest[0] insepsreturnFalse
This also fixes the mistaken result that a rooted path such as "/spam" is absolute. When opened directly, a rooted path is relative to the drive of the current working directory. When accessed indirectly as the target of a symlink, a rooted path is relative to the volume device of the opened path.
An example of the latter is a symlink named "link" that targets "\". If it's accessed as E:\link, it resolves to E:\. If it's accessed as C:\Mount\VolumeE\link, it resolves instead to C:\. The relative link resolves differently depending on the path traversed to access it. (Note that when resolving the target of a relative symlink, mountpoints such as "VolumeE" that are traversed in the opened path do not get replaced by their target path, unlike directory symlinks, which do get replaced by their target path. This behavior is basically the same as the way mountpoints and symlinks are handled in Unix.)
Would a new strict argument for isabs() help? It wouldn't affect how UNC paths (two leading slashes) are handled, as they're always absolute per Eryk's comment above, but otherwise:
isabs('blah', strict=None): true if the path has a root (default)
Backwards-compatible but rarely useful
isabs('blah', strict=False): true if the path has either drive or a root
Useful for checking if a path is entirely relative (negate its result)
isabs('blah', strict=True): true if the path has both a drive and a root
Useful for checking if a path is entirely absolute
No, we should just strive for the most consistency. Testing for starting with two sep/altseps or {A-Z}:{sep} should be enough. And it should be consistent with how join() handles each segment.
If users really want to know whether a path is relative but has a drive segment, they can splitdrive.
Activity
akima commentedon Aug 29, 2014
A UNC path pointing to the root of a share is not being recognised as an absolute path when it should be.
See this interpreter session.
eryksun commentedon Aug 29, 2014
On second thought, while the parallels between drives and shares are nice, beyond that this makes no sense to me.
http://hg.python.org/cpython/file/c0e311e010fc/Lib/ntpath.py#l91
Windows uses hidden environment variables (e.g. "=C:") for the working directory on each drive, but not for network shares.
akima commentedon Aug 30, 2014
FYI: I've only tested this bug on Python 3.3.5 on Windows 7. I expect the bug exists in other versions of Python.
akima commentedon Sep 1, 2014
I checked for the existence of this bug in 2 other python versions today. It's present in CPython 3.4.1, but CPython 2.7.5 doesn't exhibit the issue.
zooba commentedon Sep 5, 2014
Antoine almost certainly thought about this with pathlib and may know about the change, or at least have some decent context on it.
I'm more inclined to think that os.path.isabs(r"\\server") should also return False, since it's not a path that can be opened directly unless you add more path before or after it.
Indeed, pathlib seems to support my understanding:
If the regression appeared in 3.4, it should be easy enough to look at what changed.
pitrou commentedon Sep 5, 2014
Under Windows, pathlib's "absolute" means a fully qualified path as defined in http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
The fact that "//server" isn't considered absolute is a bug in pathlib, since "//server/" is:
I agree that it's not really important, since both aren't actual paths (in the sense that they may not point to anything, AFAIK).
zooba commentedon Sep 5, 2014
My experience says the main reason people want to know whether the path is absolute is to figure out whether to do
Path.cwd() / pathor not. According to that MSDN page, they shouldn't because the path starts with "//" (that is, the last character and the existence of the share name are irrelevant here).I assume the bug in the last statement is what Antoine is referring to.
Pathlib always has a root, but splitdrive doesn't.
I'm not sure exactly which one to fix where, but hopefully that helps someone else figure it out.
zooba commentedon Sep 5, 2014
Just did a double-take, but that output for Path('\\\\server\\').parts[0] is actually correct...
serhiy-storchaka commentedon Sep 5, 2014
It looks to me that rather handling of "//server/" is buggy than "//server". "//server" is just the same as "/server" or "///server". But "//server/" looks as an UNC path with empty ("") mount point. This is invalid path and we can't create valid path from this path by adding components. Perhaps PureWindowsPath("//server/") should raise an exception.
eryksun commentedon Sep 5, 2014
Isn't this bug about the "root of a share" case with ntpath.isabs in 3.x and 2.7 (splitdrive was backported)? For example:
>>> os.path.isabs("//server/share") False >>> os.path.splitdrive('//server/share') ('//server/share', '')vs.
>>> os.path.isabs('//server/share/') True >>> os.path.splitdrive('//server/share/') ('//server/share', '/')I think '//server/share' is an absolute path, and pathlib agrees. Network shares do not maintain a current directory the way drives do (i.e. the hidden environment variable trick). There's no such thing as a share-relative path, nor would there be any way to even write such a path, as compared to "C:drive/relative/path".
pitrou commentedon Sep 5, 2014
Serhiy, you may be right. I'd suggest opening a python-dev discussion to gather more feedback.
eryksun commentedon Sep 5, 2014
Repeated slashes aren't collapsed at the start of a Windows path. Here's what I get in Windows 7:
>>> os.listdir('/server') [] >>> os.listdir('//server') Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundError: [WinError 53] The network path was not found: '//server' >>> os.listdir('///server') Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundError: [WinError 161] The specified path is invalid: '///server'1 remaining item
akima commentedon Sep 6, 2014
I just realised that "&monkeyfart!££" is actually a valid relative path name. What I said still holds, just replace "&monkeyfart!££" with ">elephant*dung?" (which contains the invalid characters: >*? ).
akima commentedon Sep 6, 2014
eryksun: You have marked this bug as effecting Python 2.7. When I tested for the bug on 2.7.5 the problem didn't show up:
Did you independently test a later release of version 2.7 and find the issue? If not, could you remove Python 2.7 from the "Versions" list.
serhiy-storchaka commentedon Sep 6, 2014
This is the consequence of recent backporting splitdrive() implementation from
3.x to 2.7.
eryksun commentedon Jan 15, 2017
isabs also fails for device paths such as r"\\.\C:", which is an absolute path for opening the C: volume. UNC and device paths (i.e. \\server, \\?, and \\.) should always be considered absolute. Only logical drives (i.e. C:, D:, etc) support drive-relative paths.
Also, join() needs to be smarter in this case:
>>> os.path.join(r'\\.\C:', 'spam') '\\\\.\\C:spam'It doesn't insert a backslash because the 'drive' ends in a colon. It needs to always insert a backslash for UNC paths, which cannot be reliably identified by checking whether the last character of the drive is a colon.
eryksun commentedon Feb 25, 2021
Thus a UNC path is absolute, i.e. any path that starts with 2 or more slashes, and all other paths are relative unless they have both a drive and a root. For example:
This also fixes the mistaken result that a rooted path such as "/spam" is absolute. When opened directly, a rooted path is relative to the drive of the current working directory. When accessed indirectly as the target of a symlink, a rooted path is relative to the volume device of the opened path.
An example of the latter is a symlink named "link" that targets "\". If it's accessed as E:\link, it resolves to E:\. If it's accessed as C:\Mount\VolumeE\link, it resolves instead to C:\. The relative link resolves differently depending on the path traversed to access it. (Note that when resolving the target of a relative symlink, mountpoints such as "VolumeE" that are traversed in the opened path do not get replaced by their target path, unlike directory symlinks, which do get replaced by their target path. This behavior is basically the same as the way mountpoints and symlinks are handled in Unix.)
barneygale commentedon Dec 23, 2023
Would a new strict argument for
isabs()help? It wouldn't affect how UNC paths (two leading slashes) are handled, as they're always absolute per Eryk's comment above, but otherwise:isabs('blah', strict=None): true if the path has a root (default)isabs('blah', strict=False): true if the path has either drive or a rootisabs('blah', strict=True): true if the path has both a drive and a rootzooba commentedon Jan 4, 2024
No, we should just strive for the most consistency. Testing for starting with two sep/altseps or
{A-Z}:{sep}should be enough. And it should be consistent with howjoin()handles each segment.If users really want to know whether a path is relative but has a drive segment, they can
splitdrive.barneygale commentedon Jan 4, 2024
I think I misunderstood this bug, and thought it was a dupe of #44626.
This bug appears to be fixed in 3.12 by #29041 and #100351:
zooba commentedon Jan 4, 2024
Yeah, it was fixed by that, but the fix then caused #112563 (which is already being looked into). So this one can be closed.