pathlib method relative_to doesnt work with // in paths #91317
Copy link
Copy link
Closed
Labels
3.8 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
| BPO | 47161 |
|---|---|
| Nosy | @eryksun, @barneygale, @arhadthedev, @John15321 |
| PRs | // #32193 |
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 = None
closed_at = None
created_at = <Date 2022-03-30.11:01:52.097>
labels = ['3.8', 'type-bug', 'library']
title = 'pathlib method relative_to doesnt work with // in paths'
updated_at = <Date 2022-04-01.15:38:13.214>
user = 'https://github.com/John15321'bugs.python.org fields:
activity = <Date 2022-04-01.15:38:13.214>
actor = 'barneygale'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2022-03-30.11:01:52.097>
creator = 'John15321'
dependencies = []
files = []
hgrepos = []
issue_num = 47161
keywords = ['patch']
message_count = 8.0
messages = ['416336', '416342', '416348', '416351', '416352', '416355', '416356', '416489']
nosy_count = 4.0
nosy_names = ['eryksun', 'barneygale', 'arhadthedev', 'John15321']
pr_nums = ['32193']
priority = 'normal'
resolution = None
stage = 'patch review'
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue47161'
versions = ['Python 3.8']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.8 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
John15321 commentedon Mar 30, 2022
The
//path should be equivalent to/, and in some ways, it does behave like that in pathlib. But in therelative_tomethod on aPathobject, it does not workThis is causing our CI pipeline to fail. In the documentation here you can see
//being properly processed:https://docs.python.org/3/library/pathlib.html
arhadthedev commentedon Mar 30, 2022
I started to investigate and found that a double slash in the beginning cancels any parsing of a path:
>>> Path("//Library/Video")._parts ['\\\\Library\\Video\\']vs
>>> Path("/Library/Video")._parts ['\\', 'Library', 'Video']Investigating further.
arhadthedev commentedon Mar 30, 2022
As I found out, any path starting with two double slashes is treated as an UNC (network) path:
So "/Library/Video" and "/" are directories mounted on your machine while "//Library/Video" is a computer named "Library" with a share named "Video".
However, an error message in Python 3.8 (as a file path suggests) is misleading. In 3.11 it was changed to "'\\Library\Video\' is not in the subpath of '\' OR one path is relative and the other is absolute."
arhadthedev commentedon Mar 30, 2022
Also, the error message cannot be fixed because for 3.8 only security fixes are accepted since May 2021. For 3.9 and later, the message is already corrected.
John15321 commentedon Mar 30, 2022
But shouldn't it just work with
//as a/? It seems like this is the behavior elsewhere. Sure I get that it cannot be done for 3.8. But the new error message implies that either//is not a subpath of/which it is, or that one is relative and the other is absolute, which is also false because both are absolutesarhadthedev commentedon Mar 30, 2022
It works elsewhere because empty directory names are impossible so can be dropped. But if
//is placed in the beginning, it gets a special meaning that totally changes the whole path so its plain replacement would give a totally wrong one.Roughly speaking, "//Library/Video" is
/Videoon a computer namedLibrary.John15321 commentedon Mar 30, 2022
Hmm..., I get it, but Im not gonna lie it's pretty confusing given that in other places
//works as a substitute for/. Maybe it should be mentioned in the documentation?eryksun commentedon Apr 1, 2022
In Linux, the system resolves "//" as just "/". In other POSIX systems, such as Cygwin or MSYS2 (running in Windows), "//" is a UNC path of the form "//server/share/filepath". I would expect resolve() to handle this. For example:
Linux:
>>> p = pathlib.Path('//tmp') >>> p PosixPath('//tmp') >>> p.resolve() PosixPath('/tmp')However, resolve() is broken for a UNC path in 3.9 under MSYS2:
>>> p = pathlib.Path('//localhost/C$/temp') >>> p.exists() True >>> p.resolve() PosixPath('/localhost/C$/temp') >>> p.resolve().exists() Falserealpath() is also broken for this case in 3.9 under MSYS2:
>>> os.path.realpath(p) '/localhost/C$/temp'gh-91317: Document that Path does not collapse initial `//` (GH-32193)
pythongh-91317: Document that Path does not collapse initial `//` (py…
pythongh-91317: Document that Path does not collapse initial `//` (py…
gh-91317: Document that Path does not collapse initial `//` (GH-32193)
gh-91317: Document that Path does not collapse initial `//` (GH-32193)
Revert 30935 defer bpo45162 to 312 (#94285)