• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Convert a NT pathname to a file URL and vice versa.
2
3This module only exists to provide OS-specific code
4for urllib.requests, thus do not use directly.
5"""
6# Testing is done through test_urllib.
7
8def url2pathname(url):
9    """OS-specific conversion from a relative URL of the 'file' scheme
10    to a file system path; not recommended for general use."""
11    # e.g.
12    #   ///C|/foo/bar/spam.foo
13    # and
14    #   ///C:/foo/bar/spam.foo
15    # become
16    #   C:\foo\bar\spam.foo
17    import string, urllib.parse
18    # Windows itself uses ":" even in URLs.
19    url = url.replace(':', '|')
20    if not '|' in url:
21        # No drive specifier, just convert slashes
22        if url[:4] == '////':
23            # path is something like ////host/path/on/remote/host
24            # convert this to \\host\path\on\remote\host
25            # (notice halving of slashes at the start of the path)
26            url = url[2:]
27        components = url.split('/')
28        # make sure not to convert quoted slashes :-)
29        return urllib.parse.unquote('\\'.join(components))
30    comp = url.split('|')
31    if len(comp) != 2 or comp[0][-1] not in string.ascii_letters:
32        error = 'Bad URL: ' + url
33        raise OSError(error)
34    drive = comp[0][-1].upper()
35    components = comp[1].split('/')
36    path = drive + ':'
37    for comp in components:
38        if comp:
39            path = path + '\\' + urllib.parse.unquote(comp)
40    # Issue #11474 - handing url such as |c/|
41    if path.endswith(':') and url.endswith('/'):
42        path += '\\'
43    return path
44
45def pathname2url(p):
46    """OS-specific conversion from a file system path to a relative URL
47    of the 'file' scheme; not recommended for general use."""
48    # e.g.
49    #   C:\foo\bar\spam.foo
50    # becomes
51    #   ///C:/foo/bar/spam.foo
52    import urllib.parse
53    # First, clean up some special forms. We are going to sacrifice
54    # the additional information anyway
55    if p[:4] == '\\\\?\\':
56        p = p[4:]
57        if p[:4].upper() == 'UNC\\':
58            p = '\\' + p[4:]
59        elif p[1:2] != ':':
60            raise OSError('Bad path: ' + p)
61    if not ':' in p:
62        # No drive specifier, just convert slashes and quote the name
63        if p[:2] == '\\\\':
64        # path is something like \\host\path\on\remote\host
65        # convert this to ////host/path/on/remote/host
66        # (notice doubling of slashes at the start of the path)
67            p = '\\\\' + p
68        components = p.split('\\')
69        return urllib.parse.quote('/'.join(components))
70    comp = p.split(':', maxsplit=2)
71    if len(comp) != 2 or len(comp[0]) > 1:
72        error = 'Bad path: ' + p
73        raise OSError(error)
74
75    drive = urllib.parse.quote(comp[0].upper())
76    components = comp[1].split('\\')
77    path = '///' + drive + ':'
78    for comp in components:
79        if comp:
80            path = path + '/' + urllib.parse.quote(comp)
81    return path
82