python (3.11.7)
       1  import os
       2  import string
       3  import urllib.parse
       4  import urllib.request
       5  from typing import Optional
       6  
       7  from .compat import WINDOWS
       8  
       9  
      10  def get_url_scheme(url: str) -> Optional[str]:
      11      if ":" not in url:
      12          return None
      13      return url.split(":", 1)[0].lower()
      14  
      15  
      16  def path_to_url(path: str) -> str:
      17      """
      18      Convert a path to a file: URL.  The path will be made absolute and have
      19      quoted path parts.
      20      """
      21      path = os.path.normpath(os.path.abspath(path))
      22      url = urllib.parse.urljoin("file:", urllib.request.pathname2url(path))
      23      return url
      24  
      25  
      26  def url_to_path(url: str) -> str:
      27      """
      28      Convert a file: URL to a path.
      29      """
      30      assert url.startswith(
      31          "file:"
      32      ), f"You can only turn file: urls into filenames (not {url!r})"
      33  
      34      _, netloc, path, _, _ = urllib.parse.urlsplit(url)
      35  
      36      if not netloc or netloc == "localhost":
      37          # According to RFC 8089, same as empty authority.
      38          netloc = ""
      39      elif WINDOWS:
      40          # If we have a UNC path, prepend UNC share notation.
      41          netloc = "\\\\" + netloc
      42      else:
      43          raise ValueError(
      44              f"non-local file URIs are not supported on this platform: {url!r}"
      45          )
      46  
      47      path = urllib.request.url2pathname(netloc + path)
      48  
      49      # On Windows, urlsplit parses the path as something like "/C:/Users/foo".
      50      # This creates issues for path-related functions like io.open(), so we try
      51      # to detect and strip the leading slash.
      52      if (
      53          WINDOWS
      54          and not netloc  # Not UNC.
      55          and len(path) >= 3
      56          and path[0] == "/"  # Leading slash to strip.
      57          and path[1] in string.ascii_letters  # Drive letter.
      58          and path[2:4] in (":", ":/")  # Colon + end of string, or colon + absolute path.
      59      ):
      60          path = path[1:]
      61  
      62      return path