gh-150880: Normalize Windows scandir wildcard paths#152906
Conversation
|
Thanks @zainnadeem786 for the PR, and @zooba for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15. |
|
GH-152963 is a backport of this pull request to the 3.15 branch. |
|
GH-152964 is a backport of this pull request to the 3.14 branch. |
|
GH-152965 is a backport of this pull request to the 3.13 branch. |
GH-152906) (GH-152965) gh-150880: Normalize paths on Windows before appending wildcard (GH-152906) This ensures that we don't turn a "valid" path with trailing spaces into an invalid path with embedded spaces. (cherry picked from commit 1b4135a) Co-authored-by: Zain Nadeem <zainnadeemzainnadeem80@gmail.com>
GH-152906) (GH-152964) gh-150880: Normalize paths on Windows before appending wildcard (GH-152906) This ensures that we don't turn a "valid" path with trailing spaces into an invalid path with embedded spaces. (cherry picked from commit 1b4135a) Co-authored-by: Zain Nadeem <zainnadeemzainnadeem80@gmail.com>
GH-152906) (GH-152963) gh-150880: Normalize paths on Windows before appending wildcard (GH-152906) This ensures that we don't turn a "valid" path with trailing spaces into an invalid path with embedded spaces. (cherry picked from commit 1b4135a) Co-authored-by: Zain Nadeem <zainnadeemzainnadeem80@gmail.com>
|
os.scandir() doesn't normalize the entries path. Is it a deliberate choice? The space in the last |
|
Unintentional. If that's done in native code, it probably needs to be updated to use the same join function |
|
Thanks for pointing this out, @vstinner. I'll reproduce this on my side and investigate where DirEntry.path is being constructed. If it turns out to be a separate issue from the wildcard normalization addressed in this PR, I'll prepare a follow-up fix and submit a separate PR. Thanks for taking another look! |
|
|
This is probably true, actually, as it'll make sure that a relative path doesn't get calculated to the wrong value if |
|
I investigated this further on Windows. The root cause appears to be that GH-152906 normalizes only the temporary wildcard path passed to I also confirmed the Based on your comments, the right follow-up seems to be normalizing the scandir base path once inside One compatibility point I noticed: this would make relative Windows If that behavior change is acceptable for Windows in order to match the actual directory opened and avoid the |
Oh, it says that? Yeah, we can't do that change then. I don't want to encode platform-specific normalisation rules in Python (we'll never get them 100% right). If we can't use an OS API to make the path suitable for the OS, then it's on the user. It probably just has to be a failure in this case, though we can update the docs to say that other than the filename, the path is preserved from the provided argument, and the end result may not be valid (e.g. the CWD changes or the result of joining the path isn't valid). |
|
Thanks for the clarification, @zooba. That makes sense. I agree that preserving the documented API semantics is more important than trying to mirror Windows normalization rules here. I'll take a look at preparing a documentation update to clarify that, apart from the filename, DirEntry.path preserves the original argument and may not remain valid if the working directory changes or if the supplied path itself isn't valid for later path construction. Thanks again for the guidance! |
Summary
On Windows,
os.listdir()andos.scandir()append a wildcard before callingFindFirstFileW().For paths with a trailing space, this changes the path from a final-component trailing-space case into an internal path component, so Windows no longer trims the space. This makes
listdir()andscandir()behave differently from APIs such asopen(),os.stat(), andos.path.exists().This PR normalizes non-extended Windows base paths with
GetFullPathNameW()before appending the wildcard used for enumeration.Extended paths beginning with
\\?\continue to bypass normalization.Changes
listdir()andscandir().DirEntry.pathconstruction behavior.Tests
Close #150880