the path component of a URL. This does not produce a complete URL. The return
value will already be quoted using the :func:`~urllib.parse.quote` function.
+ .. versionchanged:: 3.14
+ On Windows, ``:`` characters not following a drive letter are quoted. In
+ previous versions, :exc:`OSError` was raised if a colon character was
+ found in any position other than the second character.
+
.. function:: url2pathname(path)
# C:\foo\bar\spam.foo
# becomes
# ///C:/foo/bar/spam.foo
+ import ntpath
import urllib.parse
# First, clean up some special forms. We are going to sacrifice
# the additional information anyway
p = p[4:]
if p[:4].upper() == 'UNC/':
p = '//' + p[4:]
- elif p[1:2] != ':':
- raise OSError('Bad path: ' + p)
- if not ':' in p:
- # No DOS drive specified, just quote the pathname
- return urllib.parse.quote(p)
- comp = p.split(':', maxsplit=2)
- if len(comp) != 2 or len(comp[0]) > 1:
- error = 'Bad path: ' + p
- raise OSError(error)
+ drive, tail = ntpath.splitdrive(p)
+ if drive[1:] == ':':
+ # DOS drive specified. Add three slashes to the start, producing
+ # an authority section with a zero-length authority, and a path
+ # section starting with a single slash.
+ drive = f'///{drive.upper()}'
- drive = urllib.parse.quote(comp[0].upper())
- tail = urllib.parse.quote(comp[1])
- return '///' + drive + ':' + tail
+ drive = urllib.parse.quote(drive, safe='/:')
+ tail = urllib.parse.quote(tail)
+ return drive + tail
self.assertEqual(fn('C:\\a\\b%#c'), '///C:/a/b%25%23c')
self.assertEqual(fn('C:\\a\\b\xe9'), '///C:/a/b%C3%A9')
self.assertEqual(fn('C:\\foo\\bar\\spam.foo'), "///C:/foo/bar/spam.foo")
- # Long drive letter
- self.assertRaises(IOError, fn, "XX:\\")
+ # NTFS alternate data streams
+ self.assertEqual(fn('C:\\foo:bar'), '///C:/foo%3Abar')
+ self.assertEqual(fn('foo:bar'), 'foo%3Abar')
# No drive letter
self.assertEqual(fn("\\folder\\test\\"), '/folder/test/')
self.assertEqual(fn("\\\\folder\\test\\"), '//folder/test/')
--- /dev/null
+Fix issue where :func:`urllib.request.pathname2url` raised :exc:`OSError`
+when given a Windows path containing a colon character not following a
+drive letter, such as before an NTFS alternate data stream.