summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBarney Gale <barney.gale@gmail.com>2022-08-12 21:23:41 (GMT)
committerGitHub <noreply@github.com>2022-08-12 21:23:41 (GMT)
commit187949ebf2ae36fcf0817a06f4a7637d0a8b7fc5 (patch)
tree97e2247dba696d69d682cefedf05d760c926bb07
parenta965db37f27ffb232312bc13d9a509f0d93fcd20 (diff)
downloadcpython-187949ebf2ae36fcf0817a06f4a7637d0a8b7fc5.zip
cpython-187949ebf2ae36fcf0817a06f4a7637d0a8b7fc5.tar.gz
cpython-187949ebf2ae36fcf0817a06f4a7637d0a8b7fc5.tar.bz2
gh-94909: fix joining of absolute and relative Windows paths in pathlib (GH-95450)
Have pathlib use `os.path.join()` to join arguments to the `PurePath` initialiser, which fixes a minor bug when handling relative paths with drives. Previously: ```python >>> from pathlib import PureWindowsPath >>> a = 'C:/a/b' >>> b = 'C:x/y' >>> PureWindowsPath(a, b) PureWindowsPath('C:x/y') ``` Now: ```python >>> PureWindowsPath(a, b) PureWindowsPath('C:/a/b/x/y') ```
-rw-r--r--Lib/pathlib.py41
-rw-r--r--Lib/test/test_pathlib.py4
-rw-r--r--Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst2
3 files changed, 14 insertions, 33 deletions
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 54da1c8..0ea621c 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -61,41 +61,16 @@ class _Flavour(object):
self.join = self.sep.join
def parse_parts(self, parts):
- parsed = []
+ if not parts:
+ return '', '', []
sep = self.sep
altsep = self.altsep
- drv = root = ''
- it = reversed(parts)
- for part in it:
- if not part:
- continue
- if altsep:
- part = part.replace(altsep, sep)
- drv, root, rel = self.splitroot(part)
- if sep in rel:
- for x in reversed(rel.split(sep)):
- if x and x != '.':
- parsed.append(sys.intern(x))
- else:
- if rel and rel != '.':
- parsed.append(sys.intern(rel))
- if drv or root:
- if not drv:
- # If no drive is present, try to find one in the previous
- # parts. This makes the result of parsing e.g.
- # ("C:", "/", "a") reasonably intuitive.
- for part in it:
- if not part:
- continue
- if altsep:
- part = part.replace(altsep, sep)
- drv = self.splitroot(part)[0]
- if drv:
- break
- break
- if drv or root:
- parsed.append(drv + root)
- parsed.reverse()
+ path = self.pathmod.join(*parts)
+ if altsep:
+ path = path.replace(altsep, sep)
+ drv, root, rel = self.splitroot(path)
+ unfiltered_parsed = [drv + root] + rel.split(sep)
+ parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.']
return drv, root, parsed
def join_parsed_parts(self, drv, root, parts, drv2, root2, parts2):
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index 668af80..f324177 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -136,6 +136,10 @@ class NTFlavourTest(_BaseFlavourTest, unittest.TestCase):
check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c']))
check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c']))
check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c']))
+ # Joining with the same drive => the first path is appended to if
+ # the second path is relative.
+ check(['c:/a/b', 'c:x/y'], ('c:', '\\', ['c:\\', 'a', 'b', 'x', 'y']))
+ check(['c:/a/b', 'c:/x/y'], ('c:', '\\', ['c:\\', 'x', 'y']))
def test_splitroot(self):
f = self.flavour.splitroot
diff --git a/Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst b/Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst
new file mode 100644
index 0000000..b6d8538
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-29-20-58-37.gh-issue-94909.YjMusj.rst
@@ -0,0 +1,2 @@
+Fix incorrect joining of relative Windows paths with drives in
+:class:`pathlib.PurePath` initializer.