nturl2path.py 2.8 KB

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