This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients eryksun, kmaork, paul.moore, steve.dower, tim.golden, zach.ware
Date 2019-03-24.00:25:37
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1553387138.08.0.383636178937.issue36305@roundup.psfhosted.org>
In-reply-to
Content
Paul, I agree that joining Path(".") and Path("c:a") should yield Path("c:a"). However, I disagree that we should always be able to construct Path("a/b") from components Path("a") and Path("b"). It doesn't apply to Path("./c:a"). There's no way to split it up as the joining of two pathlib paths because there is no way to represent "c:a" by itself as anything other than a drive-relative path. The name "./c:a" has to be taken as a unit, which is fundamentally different from "c:a". pathlib agrees:

    >>> p1 = Path('./c:a')
    >>> p1
    WindowsPath('c:a')
    >>> [p1.drive, p1.root, p1.parts]
    ['', '', ('c:a',)]

    >>> p2 = Path('.') / Path('c:a')
    >>> p2
    WindowsPath('c:a')
    >>> [p2.drive, p2.root, p2.parts]
    ['c:', '', ('c:', 'a')]

Path('./c:a') is correctly parsed as a relative filename (no root and no drive). So, if it helps any, on the PR I wasn't requesting to change how it's parsed. The ambiguity is due to the way pathlib always collapses all "." components. I would like it to retain an initial "." component. That way the string representation will come out correctly as ".\\c:a" as opposed to the drive-relative path "c:a". 

Some Windows API and runtime library functions behave differently depending whether a relative path has a leading "." or ".." component. We're at a disadvantage if we throw this information away. For example, "./spam/eggs.ext" and "spam/eggs.ext" can yield different results when searching for the file via SearchPathW, CreateProcessW (if using lpCommandLine, not lpApplicationName), or LoadLibraryExW (data/image DLL loading, not normal module loading). "./spam/eggs.ext" will be resolved relative to the process working directory, but "spam/eggs.ext" will be tried against every directory in the default file, executable, or library search path, which may not even include the working directory. (The latter behavior is unique to Windows. POSIX never searches for a name with a slash in it.)

The CreateProcessW case is a generalization of the case that we're used to across various platforms, in which, for the sake of security, the "." entry is excluded from PATH. In this case, the only way to run an executable in the working directory is to reference it explicitly. For example (in Linux):

    >>> p = Path('./test.sh')
    >>> open(p, 'w').write('#!/bin/sh\necho spam\n')
    20
    >>> os.chmod(p, 0o700)
    >>> subprocess.call(['./test.sh'])
    spam
    0
    >>> try: subprocess.call([str(p)])
    ... except FileNotFoundError: print('eggs')
    ... 
    eggs
    >>> str(p)
    'test.sh'

This would work if pathlib kept the initial "." component.

An example where we currently retain information that's not obviously needed is with ".." components. Even Path.absolute() retains ".." components. It's important in POSIX. For example, "spam/../eggs" shouldn't be reduced to "eggs" because "spam" might be a symlink. This doesn't generally matter in Windows, since it normalizes paths in user mode as strings before they're passed to the kernel, but we still don't throw the information away because it could be useful to code that implements POSIX-like behavior.
History
Date User Action Args
2019-03-24 00:25:38eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower, kmaork
2019-03-24 00:25:38eryksunsetmessageid: <1553387138.08.0.383636178937.issue36305@roundup.psfhosted.org>
2019-03-24 00:25:38eryksunlinkissue36305 messages
2019-03-24 00:25:37eryksuncreate