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
{{ message }}
Repository navigation
Support preserving path meaning in os.path.normpath() and abspath() #88482
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=Nonecreated_at=<Date2021-06-04.21:21:19.230>labels= ['type-feature', 'library', '3.11']
title='Support preserving path meaning in os.path.normpath() and abspath()'updated_at=<Date2021-06-14.03:35:12.692>user='https://github.com/barneygale'
pathlib takes care not to change the meaning of the path when normalising. That means preserving '..' entries, as these can't be simplified without resolving symlinks etc.
normpath(), on the other handle, /always/ eliminates '..' entries, which can change the meaning of the path.
We could add a new argument to normpath() and abspath() that leaves '..' entries intact. This was closed as "won't fix" back in bpo-2289, but I think it's worth re-considering.
This enhancement would be helpful for my longer-term work to make pathlib an OOP wrapper of os + os.path, rather than a parallel implementation.
The bit about normpath() is towards the middle of the post.
barneygale commented on Jun 12, 2021
barneygalemannequin
MannequinAuthor
More actions
For this bug specifically, the pathlib docs describe the desirable behaviour:
<quote>
Spurious slashes and single dots are collapsed, but double dots ('..') are not, since this would change the meaning of a path in the face of symbolic links:
(a naïve approach would make PurePosixPath('foo/../bar') equivalent to PurePosixPath('bar'), which is wrong if foo is a symbolic link to another directory)
For pathlib, I've previously discussed a desire to retain a leading dot component from the initializing path. This could be implemented in strict mode for normpath().
A leading dot is significant in the path of an executable in a search context, such as the first item in the args sequence of subprocess.Popen(). For example, if "./spam" is normalized as "spam", then the system will search the PATH directories instead of the current working directory. It's also import to note that in Windows a leading dot component is required in order to preclude searching even if the path contains slashes. For example, CreateProcessW() and SearchPathW() will try to resolve r"spam\eggs.exe" against every directory in the search path, whereas r".\spam\eggs.exe" is explicitly relative to just the current working directory.
Retaining a leading dot component can also be important in Windows in order to disambiguate a drive-relative path from a named data stream of a file that has a single-letter filename. For example, "C:spam" is a file named "spam" in the working path on drive "C:" (e.g. "C:spam" -> r"C:\working\path\spam"), but r".\C:spam" is a data stream named "spam" in a file named "C" in the current working directory.
barneygale commented on Jun 12, 2021
barneygalemannequin
MannequinAuthor
More actions
I think I agree
How would you feel about two new arguments? Following os.curdir and os.pardir names:
I think separate keep_curdir and keep_pardir options is over-complicating the signature. Also, I'd prefer to remove a dot component if it's not the first component since there's no reason to keep it.
If you plan to use normpath() in pathlib, then the case for special_prefixes in ntpath.normpath() should be removed. Actually, it never should have been added. IIRC it was added as a workaround for a buggy implementation that's no longer an issue. Only \\?\ is special, and that's only when opening/accessing a path. It's not special in GetFullPathNameW(), as is called by ntpath.abspath() in Windows. This needlessly introduces inconsistency for ntpath.abspath() calls in Windows vs Unix.
It's reasonable/safe for abspath() to eliminate leading../ segments from the given path, because os.getcwd() is guaranteed to return a path without symlinks.
>>>os.getcwd()
'/home/barney'>>>os.path.abspath('../foo')
'/home/foo'# ok>>>os.path.abspath('foo/..')
'/home/barney'# wrong if `foo/` is a symlink
Activity
barneygale commentedon Jun 4, 2021
pathlib takes care not to change the meaning of the path when normalising. That means preserving '..' entries, as these can't be simplified without resolving symlinks etc.
normpath(), on the other handle, /always/ eliminates '..' entries, which can change the meaning of the path.
We could add a new argument to
normpath()andabspath()that leaves '..' entries intact. This was closed as "won't fix" back in bpo-2289, but I think it's worth re-considering.This enhancement would be helpful for my longer-term work to make pathlib an OOP wrapper of os + os.path, rather than a parallel implementation.
terryjreedy commentedon Jun 12, 2021
I think you should propose this for discussion on python-ideas list to try for more support. If you can, say more about why reconsider.
barneygale commentedon Jun 12, 2021
Thanks Terry, I've added a topic here: https://discuss.python.org/t/pathlib-and-os-path-code-duplication-and-feature-parity/9239
The bit about
normpath()is towards the middle of the post.barneygale commentedon Jun 12, 2021
For this bug specifically, the pathlib docs describe the desirable behaviour:
<quote>
Spurious slashes and single dots are collapsed, but double dots ('..') are not, since this would change the meaning of a path in the face of symbolic links:
(a naïve approach would make PurePosixPath('foo/../bar') equivalent to PurePosixPath('bar'), which is wrong if foo is a symbolic link to another directory)
</quote>
eryksun commentedon Jun 12, 2021
For pathlib, I've previously discussed a desire to retain a leading dot component from the initializing path. This could be implemented in strict mode for normpath().
A leading dot is significant in the path of an executable in a search context, such as the first item in the args sequence of subprocess.Popen(). For example, if "./spam" is normalized as "spam", then the system will search the PATH directories instead of the current working directory. It's also import to note that in Windows a leading dot component is required in order to preclude searching even if the path contains slashes. For example, CreateProcessW() and SearchPathW() will try to resolve r"spam\eggs.exe" against every directory in the search path, whereas r".\spam\eggs.exe" is explicitly relative to just the current working directory.
Retaining a leading dot component can also be important in Windows in order to disambiguate a drive-relative path from a named data stream of a file that has a single-letter filename. For example, "C:spam" is a file named "spam" in the working path on drive "C:" (e.g. "C:spam" -> r"C:\working\path\spam"), but r".\C:spam" is a data stream named "spam" in a file named "C" in the current working directory.
barneygale commentedon Jun 12, 2021
I think I agree
How would you feel about two new arguments? Following
os.curdirandos.pardirnames:eryksun commentedon Jun 14, 2021
I think separate keep_curdir and keep_pardir options is over-complicating the signature. Also, I'd prefer to remove a dot component if it's not the first component since there's no reason to keep it.
If you plan to use normpath() in pathlib, then the case for special_prefixes in ntpath.normpath() should be removed. Actually, it never should have been added. IIRC it was added as a workaround for a buggy implementation that's no longer an issue. Only \\?\ is special, and that's only when opening/accessing a path. It's not special in GetFullPathNameW(), as is called by ntpath.abspath() in Windows. This needlessly introduces inconsistency for ntpath.abspath() calls in Windows vs Unix.
barneygale commentedon Jan 13, 2024
It's reasonable/safe for
abspath()to eliminate leading../segments from the given path, becauseos.getcwd()is guaranteed to return a path without symlinks.