@@ -45,9 +45,10 @@ def filepath_from_url(urlstr):
4545 Take an url and return a filepath.
4646
4747 URLs can either be encoded according to the `RFC 3986`_ standard or not.
48- Additionally, Windows mapped paths need to be accounted for when processing a
49- URL; however, there are `ongoing discussions`_ about how to best handle this within
50- Python. This function is meant to cover all of these scenarios in the interim.
48+ Additionally, Windows mapped drive letter and UNC paths need to be accounted for
49+ when processing URL(s); however, there are `ongoing discussions`_ about how to best
50+ handle this within Python developer community. This function is meant to cover
51+ these scenarios in the interim.
5152
5253 .. _RFC 3986: https://tools.ietf.org/html/rfc3986#section-2.1
5354 .. _ongoing discussions: https://discuss.python.org/t/file-uris-in-python/15600
@@ -56,17 +57,38 @@ def filepath_from_url(urlstr):
5657 # Parse provided URL
5758 parsed_result = urlparse .urlparse (urlstr )
5859
60+ # De-encode the parsed path
61+ decoded_parsed_path = urlparse .unquote (parsed_result .path )
62+
5963 # Convert the parsed URL to a path
60- filepath = PurePath (request .url2pathname (parsed_result . path ))
64+ filepath = PurePath (request .url2pathname (decoded_parsed_path ))
6165
6266 # If the network location is a window drive, reassemble the path
6367 if PureWindowsPath (parsed_result .netloc ).drive :
64- filepath = PurePath (parsed_result .netloc + parsed_result .path )
68+ filepath = PurePath (parsed_result .netloc + decoded_parsed_path )
69+
70+ # If the specified index is a windows drive, then append it to the other parts
71+ elif PureWindowsPath (filepath .parts [0 ]).drive :
72+ filepath = PurePosixPath (filepath .drive , * filepath .parts [1 :])
6573
66- # Otherwise check if the specified index is a windows drive, then offset the path
74+ # If the specified index is a windows drive, then offset the path
6775 elif PureWindowsPath (filepath .parts [1 ]).drive :
6876 # Remove leading "/" if/when `request.url2pathname` yields "/S:/path/file.ext"
6977 filepath = PurePosixPath (* filepath .parts [1 :])
7078
79+ # Should catch UNC paths,
80+ # as parsing "file:///some/path/to/file.ext" doesn't provide a netloc
81+ elif parsed_result .netloc and parsed_result .netloc != 'localhost' :
82+ # Paths of type: "file://host/share/path/to/file.ext" provide "host" as netloc
83+ filepath = PurePath ('//' , parsed_result .netloc + decoded_parsed_path )
84+
85+ # Executing `as_posix` on Windows seems to generate a path with only
86+ # 1 leading `/`, so we insert another `/` at the front of the string path
87+ # to match Linux and Windows UNC conventions and return it.
88+ conformed_filepath = filepath .as_posix ()
89+ if not conformed_filepath .startswith ('//' ):
90+ conformed_filepath = '/' + conformed_filepath
91+ return conformed_filepath
92+
7193 # Convert "\" to "/" if needed
7294 return filepath .as_posix ()
0 commit comments