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

bpo-37609: Update ntpath.splitdrive to use native functionality where possible #25261

Closed
wants to merge 3 commits into from

Conversation

zooba
Copy link
Member

@zooba zooba commented Apr 7, 2021

Lib/ntpath.py Outdated Show resolved Hide resolved
Comment on lines +119 to 123
path = [p for p in (p1.rstrip(path_separators) for p1 in path) if p]
if not path:
# Avoid losing the root's trailing separator when joining with nothing
return root + path_sep
return root + path_sep.join(path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • _path_join('//server/share', 'spam') should return "//server/share/spam", not "//server/sharespam"
  • _path_join("C:/", "spam") should return "C:/spam", not "C:spam"
  • _path_join("C:", "") should return "C:", not "C:\".
  • _path_join("C:", "D:") should return "D:", not "D:\"

I don't like the change to make _path_splitroot() shift the separator into the path. It goes against what I expect given the function name, in terms of separating the root from the rest of the path. The root variable here actually has no root path, which is counterintuitive.

As it stands, the following fixes the above case by shifting the separator back into root. The UNC + relative case has to be handled specially at the end.

    if path and path[0].startswith(path_sep_tuple):
        root += path[0][0]
        path[0] = path[0][1:]
    tail = path_sep.join(c for p in path if (c := p.rstrip(path_separators)))
    # Fix up appending a relative path to a UNC root
    if (tail and root.startswith(path_sep_tuple) and
          not root.endswith(path_sep_tuple) and
          not tail.startswith(path_sep_tuple)):
        root += path_sep
    return root + tail

Comment on lines +65 to +71
else:
def _splitroot(p):
p = os.fspath(p)
r = _path_splitroot(p)
if isinstance(p, bytes):
return tuple(map(os.fsencode, r))
return r
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change the name to nt._path_splitdrive, since that makes more sense now that the root is shifted over to the path side. Implement the POSIX fallback as _path_splitdrive, which only returns str, just like the builtin function. Move the above bytes support code into a common implementation of ntpath.splitdrive(), which is likely the only place it will ever be needed. _path_splitdrive() will be used directly when bytes support isn't required.

I'm sure you know the os.fspath() call isn't necessary since it's handled for a path_t argument in C, so why is it called explicitly here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isinstance at 69 needs to recognise values for p that have __fspath__ that returns bytes, as well as actual bytes, which is why we fspath once instead of doing it multiple times.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isinstance at 69 needs to recognise values for p that have __fspath__ that returns bytes, as well as actual bytes, which is why we fspath once instead of doing it multiple times.

Sigh... sorry about that. :-$

@zooba
Copy link
Member Author

zooba commented Apr 9, 2021

Frankly, I'm out of energy for this patch. Someone else can work on it if they're keen, or maybe I'll get back to it one day.

@zooba zooba closed this Apr 9, 2021
@eryksun
Copy link
Contributor

eryksun commented Apr 10, 2021

Frankly, I'm out of energy for this patch. Someone else can work on it if they're keen, or maybe I'll get back to it one day.

Thank you for all of your work here. Do you want to repurpose the work for test_ntpath.py in a new issue, to refine exactly what should be be supported by ntpath.join() and ntpath.splitdrive() when used in POSIX? That sets the limits for what a fallback implementation of splitdrive() needs to implement and whatever needs to be adapted in the PathCchSkipRoot result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants