[Python-checkins] cpython (2.7): fix ntpath.join on UNC-style paths by backporting py3k's splitdrive (closes

benjamin.peterson python-checkins at python.org
Mon Jun 23 04:11:05 CEST 2014


http://hg.python.org/cpython/rev/26ec6248ee8b
changeset:   91340:26ec6248ee8b
branch:      2.7
parent:      91337:f463387d2434
user:        Benjamin Peterson <benjamin at python.org>
date:        Sun Jun 22 19:07:38 2014 -0700
summary:
  fix ntpath.join on UNC-style paths by backporting py3k's splitdrive (closes #21672)

files:
  Lib/ntpath.py           |  47 +++++++++++++++++++++++++---
  Lib/test/test_ntpath.py |  32 ++++++++++++++----
  Misc/NEWS               |   2 +
  3 files changed, 68 insertions(+), 13 deletions(-)


diff --git a/Lib/ntpath.py b/Lib/ntpath.py
--- a/Lib/ntpath.py
+++ b/Lib/ntpath.py
@@ -82,6 +82,10 @@
         if result_path and result_path[-1] not in '\\/':
             result_path = result_path + '\\'
         result_path = result_path + p_path
+    ## add separator between UNC and non-absolute path
+    if (result_path and result_path[0] not in '\\/' and
+        result_drive and result_drive[-1:] != ':'):
+        return result_drive + sep + result_path
     return result_drive + result_path
 
 
@@ -89,13 +93,46 @@
 # colon) and the path specification.
 # It is always true that drivespec + pathspec == p
 def splitdrive(p):
-    """Split a pathname into drive and path specifiers. Returns a 2-tuple
-"(drive,path)";  either part may be empty"""
-    if p[1:2] == ':':
-        return p[0:2], p[2:]
+    """Split a pathname into drive/UNC sharepoint and relative path specifiers.
+    Returns a 2-tuple (drive_or_unc, path); either part may be empty.
+
+    If you assign
+        result = splitdrive(p)
+    It is always true that:
+        result[0] + result[1] == p
+
+    If the path contained a drive letter, drive_or_unc will contain everything
+    up to and including the colon.  e.g. splitdrive("c:/dir") returns ("c:", "/dir")
+
+    If the path contained a UNC path, the drive_or_unc will contain the host name
+    and share up to but not including the fourth directory separator character.
+    e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
+
+    Paths cannot contain both a drive letter and a UNC path.
+
+    """
+    if len(p) > 1:
+        normp = p.replace(altsep, sep)
+        if (normp[0:2] == sep*2) and (normp[2] != sep):
+            # is a UNC path:
+            # vvvvvvvvvvvvvvvvvvvv drive letter or UNC path
+            # \\machine\mountpoint\directory\etc\...
+            #           directory ^^^^^^^^^^^^^^^
+            index = normp.find(sep, 2)
+            if index == -1:
+                return '', p
+            index2 = normp.find(sep, index + 1)
+            # a UNC path can't have two slashes in a row
+            # (after the initial two)
+            if index2 == index + 1:
+                return '', p
+            if index2 == -1:
+                index2 = len(p)
+            return p[:index2], p[index2:]
+        if normp[1] == ':':
+            return p[:2], p[2:]
     return '', p
 
-
 # Parse UNC paths
 def splitunc(p):
     """Split a pathname into UNC mount point and relative path specifiers.
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -1,3 +1,4 @@
+# coding: utf-8
 import ntpath
 import os
 import sys
@@ -34,6 +35,21 @@
                ('c:', '\\foo\\bar'))
         tester('ntpath.splitdrive("c:/foo/bar")',
                ('c:', '/foo/bar'))
+        tester('ntpath.splitdrive("\\\\conky\\mountpoint\\foo\\bar")',
+               ('\\\\conky\\mountpoint', '\\foo\\bar'))
+        tester('ntpath.splitdrive("//conky/mountpoint/foo/bar")',
+               ('//conky/mountpoint', '/foo/bar'))
+        tester('ntpath.splitdrive("\\\\\\conky\\mountpoint\\foo\\bar")',
+            ('', '\\\\\\conky\\mountpoint\\foo\\bar'))
+        tester('ntpath.splitdrive("///conky/mountpoint/foo/bar")',
+            ('', '///conky/mountpoint/foo/bar'))
+        tester('ntpath.splitdrive("\\\\conky\\\\mountpoint\\foo\\bar")',
+               ('', '\\\\conky\\\\mountpoint\\foo\\bar'))
+        tester('ntpath.splitdrive("//conky//mountpoint/foo/bar")',
+               ('', '//conky//mountpoint/foo/bar'))
+        # Issue #19911: UNC part containing U+0130
+        self.assertEqual(ntpath.splitdrive(u'//conky/MOUNTPOİNT/foo/bar'),
+                         (u'//conky/MOUNTPOİNT', '/foo/bar'))
 
     def test_splitunc(self):
         tester('ntpath.splitunc("c:\\foo\\bar")',
@@ -62,10 +78,10 @@
 
         tester('ntpath.split("c:\\")', ('c:\\', ''))
         tester('ntpath.split("\\\\conky\\mountpoint\\")',
-               ('\\\\conky\\mountpoint', ''))
+               ('\\\\conky\\mountpoint\\', ''))
 
         tester('ntpath.split("c:/")', ('c:/', ''))
-        tester('ntpath.split("//conky/mountpoint/")', ('//conky/mountpoint', ''))
+        tester('ntpath.split("//conky/mountpoint/")', ('//conky/mountpoint/', ''))
 
     def test_isabs(self):
         tester('ntpath.isabs("c:\\")', 1)
@@ -114,9 +130,9 @@
         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('//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')
@@ -124,9 +140,9 @@
         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('//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')
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -29,6 +29,8 @@
 Library
 -------
 
+- Issue #21672: Fix the behavior of ntpath.join on UNC-style paths.
+
 - Issue #21491: SocketServer: Fix a race condition in child processes reaping.
 
 - Issue #21635:  The difflib SequenceMatcher.get_matching_blocks() method

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list