Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to filepath_from_url for UNC paths and tests for UNC and posix paths #1674

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions src/py-opentimelineio/opentimelineio/url_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ def filepath_from_url(urlstr):
Take an url and return a filepath.

URLs can either be encoded according to the `RFC 3986`_ standard or not.
Additionally, Windows mapped paths need to be accounted for when processing a
URL; however, there are `ongoing discussions`_ about how to best handle this within
Python. This function is meant to cover all of these scenarios in the interim.
Additionally, Windows mapped drive letter and UNC paths need to be accounted for
when processing URL(s); however, there are `ongoing discussions`_ about how to best
handle this within Python developer community. This function is meant to cover
these scenarios in the interim.

.. _RFC 3986: https://tools.ietf.org/html/rfc3986#section-2.1
.. _ongoing discussions: https://discuss.python.org/t/file-uris-in-python/15600
Expand All @@ -56,17 +57,38 @@ def filepath_from_url(urlstr):
# Parse provided URL
parsed_result = urlparse.urlparse(urlstr)

# De-encode the parsed path
decoded_parsed_path = urlparse.unquote(parsed_result.path)

# Convert the parsed URL to a path
filepath = PurePath(request.url2pathname(parsed_result.path))
filepath = PurePath(request.url2pathname(decoded_parsed_path))

# If the network location is a window drive, reassemble the path
if PureWindowsPath(parsed_result.netloc).drive:
filepath = PurePath(parsed_result.netloc + parsed_result.path)
filepath = PurePath(parsed_result.netloc + decoded_parsed_path)

# If the specified index is a windows drive, then append it to the other parts
elif PureWindowsPath(filepath.parts[0]).drive:
filepath = PurePosixPath(filepath.drive, *filepath.parts[1:])

# Otherwise check if the specified index is a windows drive, then offset the path
# If the specified index is a windows drive, then offset the path
elif PureWindowsPath(filepath.parts[1]).drive:
# Remove leading "/" if/when `request.url2pathname` yields "/S:/path/file.ext"
filepath = PurePosixPath(*filepath.parts[1:])

# Should catch UNC paths,
# as parsing "file:///some/path/to/file.ext" doesn't provide a netloc
elif parsed_result.netloc and parsed_result.netloc != 'localhost':
# Paths of type: "file://host/share/path/to/file.ext" provide "host" as netloc
filepath = PurePath('//', parsed_result.netloc + decoded_parsed_path)

# Executing `as_posix` on Windows seems to generate a path with only
# 1 leading `/`, so we insert another `/` at the front of the string path
# to match Linux and Windows UNC conventions and return it.
conformed_filepath = filepath.as_posix()
if not conformed_filepath.startswith('//'):
conformed_filepath = '/' + conformed_filepath
return conformed_filepath

# Convert "\" to "/" if needed
return filepath.as_posix()
29 changes: 24 additions & 5 deletions tests/test_url_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,18 @@
MEDIA_EXAMPLE_PATH_ABS
)

ENCODED_WINDOWS_URL = "file://localhost/S%3a/path/file.ext"
WINDOWS_URL = "file://S:/path/file.ext"
CORRECTED_WINDOWS_PATH = "S:/path/file.ext"
WINDOWS_ENCODED_URL = "file://host/S%3a/path/file.ext"
WINDOWS_DRIVE_URL = "file://S:/path/file.ext"
WINDOWS_DRIVE_PATH = "S:/path/file.ext"

WINDOWS_ENCODED_UNC_URL = "file://unc/path/sub%20dir/file.ext"
WINDOWS_UNC_URL = "file://unc/path/sub dir/file.ext"
WINDOWS_UNC_PATH = "//unc/path/sub dir/file.ext"

POSIX_LOCALHOST_URL = "file://localhost/path/sub dir/file.ext"
POSIX_ENCODED_URL = "file:///path/sub%20dir/file.ext"
POSIX_URL = "file:///path/sub dir/file.ext"
POSIX_PATH = "/path/sub dir/file.ext"


class TestConversions(unittest.TestCase):
Expand All @@ -56,9 +65,19 @@ def test_roundtrip_rel(self):
self.assertEqual(os.path.normpath(result), MEDIA_EXAMPLE_PATH_REL)

def test_windows_urls(self):
for url in (ENCODED_WINDOWS_URL, WINDOWS_URL):
for url in (WINDOWS_ENCODED_URL, WINDOWS_DRIVE_URL):
processed_url = otio.url_utils.filepath_from_url(url)
self.assertEqual(processed_url, WINDOWS_DRIVE_PATH)

def test_windows_unc_urls(self):
for url in (WINDOWS_ENCODED_UNC_URL, WINDOWS_UNC_URL):
processed_url = otio.url_utils.filepath_from_url(url)
self.assertEqual(processed_url, WINDOWS_UNC_PATH)

def test_posix_urls(self):
for url in (POSIX_ENCODED_URL, POSIX_URL, POSIX_LOCALHOST_URL):
processed_url = otio.url_utils.filepath_from_url(url)
self.assertEqual(processed_url, CORRECTED_WINDOWS_PATH)
self.assertEqual(processed_url, POSIX_PATH)


if __name__ == "__main__":
Expand Down
Loading