Commit 31f51212 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #19456: ntpath.join() now joins relative paths correctly when a drive

is present.
parent 027ab390
...@@ -59,61 +59,30 @@ def isabs(s): ...@@ -59,61 +59,30 @@ def isabs(s):
# Join two (or more) paths. # Join two (or more) paths.
def join(path, *paths):
def join(a, *p): """Join two or more pathname components, inserting "\\" as needed."""
"""Join two or more pathname components, inserting "\\" as needed. result_drive, result_path = splitdrive(path)
If any component is an absolute path, all previous path components for p in paths:
will be discarded.""" p_drive, p_path = splitdrive(p)
path = a if p_path and p_path[0] in '\\/':
for b in p: # Second path is absolute
b_wins = 0 # set to 1 iff b makes path irrelevant if p_drive or not result_drive:
if path == "": result_drive = p_drive
b_wins = 1 result_path = p_path
continue
elif isabs(b): elif p_drive and p_drive != result_drive:
# This probably wipes out path so far. However, it's more if p_drive.lower() != result_drive.lower():
# complicated if path begins with a drive letter: # Different drives => ignore the first path entirely
# 1. join('c:', '/a') == 'c:/a' result_drive = p_drive
# 2. join('c:/', '/a') == 'c:/a' result_path = p_path
# But continue
# 3. join('c:/a', '/b') == '/b' # Same drive in different case
# 4. join('c:', 'd:/') = 'd:/' result_drive = p_drive
# 5. join('c:/', 'd:/') = 'd:/' # Second path is relative to the first
if path[1:2] != ":" or b[1:2] == ":": if result_path and result_path[-1] not in '\\/':
# Path doesn't start with a drive letter, or cases 4 and 5. result_path = result_path + '\\'
b_wins = 1 result_path = result_path + p_path
return result_drive + result_path
# Else path has a drive letter, and b doesn't but is absolute.
elif len(path) > 3 or (len(path) == 3 and
path[-1] not in "/\\"):
# case 3
b_wins = 1
if b_wins:
path = b
else:
# Join, and ensure there's a separator.
assert len(path) > 0
if path[-1] in "/\\":
if b and b[0] in "/\\":
path += b[1:]
else:
path += b
elif path[-1] == ":":
path += b
elif b:
if b[0] in "/\\":
path += b
else:
path += "\\" + b
else:
# path is not empty and does not end with a backslash,
# but b is empty; since, e.g., split('a/') produces
# ('a', ''), it's best if join() adds a backslash in
# this case.
path += '\\'
return path
# Split a path in a drive specification (a drive letter followed by a # Split a path in a drive specification (a drive letter followed by a
......
...@@ -85,10 +85,7 @@ class TestNtpath(unittest.TestCase): ...@@ -85,10 +85,7 @@ class TestNtpath(unittest.TestCase):
tester('ntpath.join("/a")', '/a') tester('ntpath.join("/a")', '/a')
tester('ntpath.join("\\a")', '\\a') tester('ntpath.join("\\a")', '\\a')
tester('ntpath.join("a:")', 'a:') tester('ntpath.join("a:")', 'a:')
tester('ntpath.join("a:", "b")', 'a:b')
tester('ntpath.join("a:", "/b")', 'a:/b')
tester('ntpath.join("a:", "\\b")', 'a:\\b') tester('ntpath.join("a:", "\\b")', 'a:\\b')
tester('ntpath.join("a", "/b")', '/b')
tester('ntpath.join("a", "\\b")', '\\b') tester('ntpath.join("a", "\\b")', '\\b')
tester('ntpath.join("a", "b", "c")', 'a\\b\\c') tester('ntpath.join("a", "b", "c")', 'a\\b\\c')
tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c') tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c')
...@@ -96,22 +93,46 @@ class TestNtpath(unittest.TestCase): ...@@ -96,22 +93,46 @@ class TestNtpath(unittest.TestCase):
tester('ntpath.join("a", "b", "\\c")', '\\c') tester('ntpath.join("a", "b", "\\c")', '\\c')
tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep') tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep')
tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b') tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b')
tester("ntpath.join('c:', '/a')", 'c:/a')
tester("ntpath.join('c:/', '/a')", 'c:/a')
tester("ntpath.join('c:/a', '/b')", '/b')
tester("ntpath.join('c:', 'd:/')", 'd:/')
tester("ntpath.join('c:/', 'd:/')", 'd:/')
tester("ntpath.join('c:/', 'd:/a/b')", 'd:/a/b')
tester("ntpath.join('')", '')
tester("ntpath.join('', '', '', '', '')", '')
tester("ntpath.join('a')", 'a')
tester("ntpath.join('', 'a')", 'a') tester("ntpath.join('', 'a')", 'a')
tester("ntpath.join('', '', '', '', 'a')", 'a') tester("ntpath.join('', '', '', '', 'a')", 'a')
tester("ntpath.join('a', '')", 'a\\') tester("ntpath.join('a', '')", 'a\\')
tester("ntpath.join('a', '', '', '', '')", 'a\\') tester("ntpath.join('a', '', '', '', '')", 'a\\')
tester("ntpath.join('a\\', '')", 'a\\') tester("ntpath.join('a\\', '')", 'a\\')
tester("ntpath.join('a\\', '', '', '', '')", 'a\\') tester("ntpath.join('a\\', '', '', '', '')", 'a\\')
tester("ntpath.join('a/', '')", 'a/')
tester("ntpath.join('a/b', 'x/y')", 'a/b\\x/y')
tester("ntpath.join('/a/b', 'x/y')", '/a/b\\x/y')
tester("ntpath.join('/a/b/', 'x/y')", '/a/b/x/y')
tester("ntpath.join('c:', 'x/y')", 'c:x/y')
tester("ntpath.join('c:a/b', 'x/y')", 'c:a/b\\x/y')
tester("ntpath.join('c:a/b/', 'x/y')", 'c:a/b/x/y')
tester("ntpath.join('c:/', 'x/y')", 'c:/x/y')
tester("ntpath.join('c:/a/b', 'x/y')", 'c:/a/b\\x/y')
tester("ntpath.join('c:/a/b/', 'x/y')", 'c:/a/b/x/y')
#tester("ntpath.join('//computer/share', 'x/y')", '//computer/share\\x/y')
#tester("ntpath.join('//computer/share/', 'x/y')", '//computer/share/x/y')
#tester("ntpath.join('//computer/share/a/b', 'x/y')", '//computer/share/a/b\\x/y')
tester("ntpath.join('a/b', '/x/y')", '/x/y')
tester("ntpath.join('/a/b', '/x/y')", '/x/y')
tester("ntpath.join('c:', '/x/y')", 'c:/x/y')
tester("ntpath.join('c:a/b', '/x/y')", 'c:/x/y')
tester("ntpath.join('c:/', '/x/y')", 'c:/x/y')
tester("ntpath.join('c:/a/b', '/x/y')", 'c:/x/y')
#tester("ntpath.join('//computer/share', '/x/y')", '//computer/share/x/y')
#tester("ntpath.join('//computer/share/', '/x/y')", '//computer/share/x/y')
#tester("ntpath.join('//computer/share/a', '/x/y')", '//computer/share/x/y')
tester("ntpath.join('c:', 'C:x/y')", 'C:x/y')
tester("ntpath.join('c:a/b', 'C:x/y')", 'C:a/b\\x/y')
tester("ntpath.join('c:/', 'C:x/y')", 'C:/x/y')
tester("ntpath.join('c:/a/b', 'C:x/y')", 'C:/a/b\\x/y')
for x in ('', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b'):
for y in ('d:', 'd:x/y', 'd:/', 'd:/x/y'):
tester("ntpath.join(%r, %r)" % (x, y), y)
def test_normpath(self): def test_normpath(self):
tester("ntpath.normpath('A//////././//.//B')", r'A\B') tester("ntpath.normpath('A//////././//.//B')", r'A\B')
......
...@@ -38,6 +38,9 @@ Core and Builtins ...@@ -38,6 +38,9 @@ Core and Builtins
Library Library
------- -------
- Issue #19456: ntpath.join() now joins relative paths correctly when a drive
is present.
- Issue #8260: The read(), readline() and readlines() methods of - Issue #8260: The read(), readline() and readlines() methods of
codecs.StreamReader returned incomplete data when were called after codecs.StreamReader returned incomplete data when were called after
readline() or read(size). Based on patch by Amaury Forgeot d'Arc. readline() or read(size). Based on patch by Amaury Forgeot d'Arc.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment