X Tutup
The Wayback Machine - https://web.archive.org/web/20221127083119/https://github.com/python/cpython/issues/99029
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disagreement between PureWindowsPath.relative_to() and ntpath.relpath() with rootless drives #99029

Closed
barneygale opened this issue Nov 2, 2022 · 4 comments
Labels
expert-pathlib OS-windows type-bug An unexpected behavior, bug, or error

Comments

@barneygale
Copy link
Contributor

barneygale commented Nov 2, 2022

On Windows, the path C: means "the current directory on the C: drive".

But pathlib's relative_to() treats it as the immediate parent of C:\. This makes sense lexographically, but it's inconsistent with everything else:

C:\Users\Barney>python
>>> import ntpath, pathlib
>>> ntpath.relpath('C:/Windows', 'C:/Users/Barney')
'..\\..\\Windows'
>>> ntpath.relpath('C:/Windows', '.')
'..\\..\\Windows'
>>> ntpath.relpath('C:/Windows', 'C:')
'..\\..\\Windows'
>>> pathlib.Path('C:/Windows').relative_to('C:/Users/Barney', walk_up=True)
WindowsPath('../../Windows')
>>> pathlib.Path('C:/Windows').relative_to('.', walk_up=True)
ValueError: One path is relative and the other is absolute.
>>> pathlib.Path('C:/Windows').relative_to('C:')
WindowsPath('/Windows')  # should be ValueError, as we're mixing absolute + relative paths

This prevents us from using relpath() from pathlib, and renders the two implementations incompatible. Booo! Also prevents us from simplifying is_relative_to() down to other == self or other in self.parents

Special cases aren't special enough to break the rules. Let's make these compatible!

Previous discussion: #84538

@barneygale barneygale added the type-bug An unexpected behavior, bug, or error label Nov 2, 2022
barneygale added a commit to barneygale/cpython that referenced this issue Nov 2, 2022
…e_to('C:')`

`relative_to()` now treats naked drive paths as relative. This brings its
behaviour in line with other parts of pathlib, and with `ntpath.relpath()`,
and so allows us to factor out the pathlib-specific implementation.
@brettcannon
Copy link
Member

brettcannon commented Nov 4, 2022

@zooba @eryksun any reason to not standardize on os.path.relpath() instead of pathlib's custom code?

@zooba
Copy link
Member

zooba commented Nov 7, 2022

Pathlib uses a pure implementation that doesn't rely on global state, such as the current working directory or current operating system (the implementation is in PurePath.relative_to). We don't resolve symlinks or junctions here, so why would we combine it with CWD?

If anything, we should make relative_to raise because C: is a relative path, and it requires an absolute path. There's a note saying that it treats a pathless root like this on purpose, but it's in a comment and not the docstring.

Provided walk_up=True doesn't affect this result, the result is correct. Anywhere on the C drive combined with \Windows will get to the right path - if it gets ..\..\Windows then it's incorrect. But I didn't try this because it's new in 3.12 and so we can change the behaviour if we feel like it.

@barneygale
Copy link
Contributor Author

barneygale commented Nov 7, 2022

If anything, we should make relative_to raise because C: is a relative path, and it requires an absolute path. There's a note saying that it treats a pathless root like this on purpose, but it's in a comment and not the docstring.

Indeed. This seems to be the only case where a.relative_path(b) allows a and b to have different anchors (e.g. one relative, one absolute; or different Windows drives); in all other cases, ValueError is raised. My suggestion here is that we make Path('C:/Windows').relative_to('C:') also raise.

I've logged #99199 to cover relpath() calling abspath(). It doesn't cause us any problems for us in pathlib, though (see discussion on #99031). It's "wrong" but has no observable effect, as far as I can tell.

@barneygale
Copy link
Contributor Author

barneygale commented Nov 12, 2022

I found another incompatibility between PurePath.relative_to() and os.path.relpath() - see #99199 (comment)

This bug is still valid, but we can't fix it by using relpath(). I've revised my PR.

brettcannon pushed a commit that referenced this issue Nov 25, 2022
…C:')` (GH-99031)

`relative_to()` now treats naked drive paths as relative. This brings its
behaviour in line with other parts of pathlib, and with `ntpath.relpath()`,
and so allows us to factor out the pathlib-specific implementation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
expert-pathlib OS-windows type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants
X Tutup