• 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    if not ':' in p:
54        # No drive specifier, just convert slashes and quote the name
55        if p[:2] == '\\\\':
56        # path is something like \\host\path\on\remote\host
57        # convert this to ////host/path/on/remote/host
58        # (notice doubling of slashes at the start of the path)
59            p = '\\\\' + p
60        components = p.split('\\')
61        return urllib.parse.quote('/'.join(components))
62    comp = p.split(':')
63    if len(comp) != 2 or len(comp[0]) > 1:
64        error = 'Bad path: ' + p
65        raise OSError(error)
66
67    drive = urllib.parse.quote(comp[0].upper())
68    components = comp[1].split('\\')
69    path = '///' + drive + ':'
70    for comp in components:
71        if comp:
72            path = path + '/' + urllib.parse.quote(comp)
73    return path
74