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
Returning False for "/:foo" is the correct behavior starting with 3.13. Barney fixed ntpath.isabs() in the PR for #44626.
On Windows, "/:foo" is a rooted path, but it's not an absolute path. When a rooted path is opened directly, it's relative to the drive or UNC share of the current working directory. When a rooted path is the target path of a symlink, it's relative to the drive or UNC share of the opened path of the symlink.
Note that "/:foo" also happens to be invalid in practice, because ":" is reserved by Microsoft's filesystems as an illegal filename character. NTFS and ReFS use colon as the separator in file stream names (e.g. "filename:streamname:streamtype", such as "spam:eggs:$DATA").
/:/ is a totally unusable path right? Not convinced this is worth fixing (yet).
It's possible that a non-Microsoft filesystem on Windows might allow creating a directory named ":", but that's not explicitly supported by Microsoft. Still, I'd prefer to keep the implementation generic and in principle behave the same as checking for a drive and root via splitroot(), but without the cost of splitroot().
Fun fact: You can actually create a directory named ":" on a USB stick on Linux, but Windows treats that as \uf022 (private use).
I guess you mean creating a directory named ":" in a Microsoft filesystem type (e.g. FAT32, NTFS), assuming the Linux driver is configured to allow it. In that case, maybe the driver on Linux is what translates the reserved character to the private use area, or maybe it's done at access time by the filesystem driver on Windows, but mostly likely not by the system I/O manager (i.e. system Io* API) or Filesystem Runtime Library (i.e. system FsRtl* API). It's probably the same for other reserved filesystem characters, such as \, | or one of the 5 wildcard characters *?<>".
The example I had in mind is the VirtualBox shared-folder filesystem, which is lenient about accessing names in the host filesystem (e.g. a Linux host running a Windows guest). But the shared-folder filesystem driver is also broken in many cases. For example, it can open a directory named ":" to set it as the current working directory of a process, but trying to open files in the directory causes the driver to fail with STATUS_OBJECT_PATH_SYNTAX_BAD (0xC000003B). That's probably due to inconsistent use of the Filesystem Runtime Library.
why do the other functions need to handle it correctly then? If you follow the same logic, these wouldn't have been accepted.
What other functions do you mean?
It's possible there was more logic at play there than what is guiding this one, or it's also possible that they were merged by different committers following different logic.
Right now, I'm with @barneygale. Invalid paths are allowed to have invalid behaviour.
Right now, I'm with @barneygale. Invalid paths are allowed to have invalid behaviour.
I got an upvote from Barney that it would be better to make isabs() and splitroot() consistent, and splitroot() has the correct behavior. "/:" can never be a drive, and nothing in the Windows API will ever handle it as a drive. The system will try to resolve the path on the drive of the current working directory. Anyway, it isn't critical. It's an invalid path, and at best it's poorly supported by the VirtualBox shared-folder filesystem.
The choice made here should be consistent with whether nineteendo's other issue about calling normpath('/:) gets fixed or closed as won't fix. If it doesn't matter here that "/:" can never be a drive, then it doesn't matter there either. We'd just let normpath() handle "/:" as a drive.
Expected: False, as /:/foo is not a valid absolute path
This means that if we had an isrelative function, it could also return False. We're in a NaN type situation here, which gives us fairly complete freedom to return whatever we like, since the input is not-a-path. Typically is* functions return False rather than raise, norm* type functions do garbage-in-garbage-out, and anything that actually needs to resolve the path should raise.
This also means we can wontfix normpath and fix this one, and it's perfectly consistent 😉
Ideally these should behave the same, and I think here fixing ntpath.isabs() and therefore the fallback implementation of ntpath.abspath() has the lowest risk. The separator will then be fixed automatically, regardless of whether ntpath.normpath() is fixed.
I don't feel strongly about this, but for me the garbage-in-garbage-out principal applies to isabs(), splitroot() and normpath() equally, and allows the C and Python implementations to produce different values for the same invalid input. If this freedom allows us to add (or retain) a faster and/or more idiomatic implementation then we should use it.
Reacted by Erlend E. Aasland, Eric V. Smith and Steve Dower
Activity
eryksun commentedon Mar 29, 2024
Returning
Falsefor "/:foo" is the correct behavior starting with 3.13. Barney fixedntpath.isabs()in the PR for #44626.On Windows, "/:foo" is a rooted path, but it's not an absolute path. When a rooted path is opened directly, it's relative to the drive or UNC share of the current working directory. When a rooted path is the target path of a symlink, it's relative to the drive or UNC share of the opened path of the symlink.
Note that "/:foo" also happens to be invalid in practice, because ":" is reserved by Microsoft's filesystems as an illegal filename character. NTFS and ReFS use colon as the separator in file stream names (e.g. "filename:streamname:streamtype", such as "spam:eggs:$DATA").
nineteendo commentedon Mar 29, 2024
Yeah, you're right. But, for this exact reason
/:/foowould be not an absolute path.I've updated the bug report reflecting this.
barneygale commentedon Mar 29, 2024
/:/is a totally unusable path right? Not convinced this is worth fixing (yet).nineteendo commentedon Mar 29, 2024
Eh, why do the other functions need to handle it correctly then? If you follow the same logic, these wouldn't have been accepted.
eryksun commentedon Mar 29, 2024
It's possible that a non-Microsoft filesystem on Windows might allow creating a directory named ":", but that's not explicitly supported by Microsoft. Still, I'd prefer to keep the implementation generic and in principle behave the same as checking for a drive and root via
splitroot(), but without the cost ofsplitroot().>>> os.path.splitroot('/:/foo') ('', '/', ':/foo')Also,
pathlib.PurePath.is_absolute()usesntpath.isabs(), so it has a similar issue:But
>>> pathlib.Path('/:/foo').is_absolute() Truenineteendo commentedon Mar 31, 2024
Fun fact: You can actually create a directory named ":" on a USB stick on Linux, but Windows treats that as
\uf022(private use).eryksun commentedon Mar 31, 2024
I guess you mean creating a directory named ":" in a Microsoft filesystem type (e.g. FAT32, NTFS), assuming the Linux driver is configured to allow it. In that case, maybe the driver on Linux is what translates the reserved character to the private use area, or maybe it's done at access time by the filesystem driver on Windows, but mostly likely not by the system I/O manager (i.e. system
Io*API) or Filesystem Runtime Library (i.e. systemFsRtl*API). It's probably the same for other reserved filesystem characters, such as\,|or one of the 5 wildcard characters*?<>".The example I had in mind is the VirtualBox shared-folder filesystem, which is lenient about accessing names in the host filesystem (e.g. a Linux host running a Windows guest). But the shared-folder filesystem driver is also broken in many cases. For example, it can open a directory named ":" to set it as the current working directory of a process, but trying to open files in the directory causes the driver to fail with
STATUS_OBJECT_PATH_SYNTAX_BAD(0xC000003B). That's probably due to inconsistent use of the Filesystem Runtime Library.[-]Handle `/:` for `ntpath.isabs`[/-][+]Handle `/:/` for `ntpath.isabs`[/+]nineteendo commentedon Mar 31, 2024
I can confirm it's the Linux driver:
\uf022is treated as:, but I wanted to try just in case it would work.zooba commentedon Apr 2, 2024
What other functions do you mean?
It's possible there was more logic at play there than what is guiding this one, or it's also possible that they were merged by different committers following different logic.
Right now, I'm with @barneygale. Invalid paths are allowed to have invalid behaviour.
nineteendo commentedon Apr 2, 2024
Probably just
ntpath.splitroot(), which might have been accidentially fixed when the logic for handling the root was added.eryksun commentedon Apr 2, 2024
I got an upvote from Barney that it would be better to make
isabs()andsplitroot()consistent, andsplitroot()has the correct behavior. "/:" can never be a drive, and nothing in the Windows API will ever handle it as a drive. The system will try to resolve the path on the drive of the current working directory. Anyway, it isn't critical. It's an invalid path, and at best it's poorly supported by the VirtualBox shared-folder filesystem.The choice made here should be consistent with whether nineteendo's other issue about calling
normpath('/:)gets fixed or closed as won't fix. If it doesn't matter here that "/:" can never be a drive, then it doesn't matter there either. We'd just letnormpath()handle "/:" as a drive.zooba commentedon Apr 3, 2024
Okay then, I'll phrase my preference as:
This means that if we had an
isrelativefunction, it could also return False. We're in a NaN type situation here, which gives us fairly complete freedom to return whatever we like, since the input is not-a-path. Typicallyis*functions return False rather than raise,norm*type functions do garbage-in-garbage-out, and anything that actually needs to resolve the path should raise.This also means we can wontfix
normpathand fix this one, and it's perfectly consistent 😉nineteendo commentedon Apr 3, 2024
I probably should've mentioned this sooner, but this also breaks the fallback implementation for
ntpath.abspath():Ideally these should behave the same, and I think here fixing
ntpath.isabs()and therefore the fallback implementation ofntpath.abspath()has the lowest risk. The separator will then be fixed automatically, regardless of whetherntpath.normpath()is fixed.barneygale commentedon Apr 4, 2024
I don't feel strongly about this, but for me the garbage-in-garbage-out principal applies to
isabs(),splitroot()andnormpath()equally, and allows the C and Python implementations to produce different values for the same invalid input. If this freedom allows us to add (or retain) a faster and/or more idiomatic implementation then we should use it.nineteendo commentedon Apr 5, 2024
OK, I'm closing this. If you change your mind this can be re-opened.