From f8737b9fcc70eed9d5bbee91f6fb0907c2878874 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Tue, 24 Oct 2023 22:10:08 -0400 Subject: [PATCH] Added support for UNC paths and tests for UNC and posix tests Signed-off-by: Doug Halley --- .../opentimelineio/url_utils.py | 23 +++++++++++++---- tests/test_url_conversions.py | 25 ++++++++++++++++--- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 61e44be58..e668d816d 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -4,6 +4,7 @@ """Utilities for conversion between urls and file paths""" import os +import sys from urllib import ( parse as urlparse, @@ -44,16 +45,20 @@ 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 """ + # De-encode the URL + decoded_url_str = urlparse.unquote(urlstr) + # Parse provided URL - parsed_result = urlparse.urlparse(urlstr) + parsed_result = urlparse.urlparse(decoded_url_str) # Convert the parsed URL to a path filepath = Path(request.url2pathname(parsed_result.path)) @@ -62,10 +67,18 @@ def filepath_from_url(urlstr): if PureWindowsPath(parsed_result.netloc).drive: filepath = Path(parsed_result.netloc + parsed_result.path) - # Otherwise check if the specified index is a windows drive, then offset the path + # Check if the specified index is a windows drive, if it is then do nothing + elif PureWindowsPath(filepath.parts[0]).drive: + filepath = filepath + + # Check 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 = filepath.relative_to(filepath.root) + # Last resort, if using a "file" schema, then strip the "file:" prefix + elif parsed_result.scheme == 'file': + filepath = Path(decoded_url_str.strip('file:')) + # Convert "\" to "/" if needed return filepath.as_posix() diff --git a/tests/test_url_conversions.py b/tests/test_url_conversions.py index 6a2e8d63c..455c85bcc 100644 --- a/tests/test_url_conversions.py +++ b/tests/test_url_conversions.py @@ -33,9 +33,16 @@ ) 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_DRIVE_URL = "file://S:/path/file.ext" +CORRECTED_WINDOWS_DRIVE_PATH = "S:/path/file.ext" +ENCODED_WINDOWS_UNC_URL = "file://unc/path/sub%20dir/file.ext" +WINDOWS_UNC_URL = "file://unc/path/sub dir/file.ext" +CORRECTED_WINDOWS_UNC_PATH = "//unc/path/sub dir/file.ext" + +ENCODED_POSIX_URL = "file:///path/sub%20dir/file.ext" +POSIX_URL = "file:///path/sub dir/file.ext" +CORRECTED_POSIX_PATH = "/path/sub dir/file.ext" class TestConversions(unittest.TestCase): def test_roundtrip_abs(self): @@ -56,9 +63,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 (ENCODED_WINDOWS_URL, WINDOWS_DRIVE_URL): + processed_url = otio.url_utils.filepath_from_url(url) + self.assertEqual(processed_url, CORRECTED_WINDOWS_DRIVE_PATH) + + def test_windows_unc_urls(self): + for url in (ENCODED_WINDOWS_UNC_URL, WINDOWS_UNC_URL): + processed_url = otio.url_utils.filepath_from_url(url) + self.assertEqual(processed_url, CORRECTED_WINDOWS_UNC_PATH) + + def test_posix_urls(self): + for url in (ENCODED_POSIX_URL, POSIX_URL): processed_url = otio.url_utils.filepath_from_url(url) - self.assertEqual(processed_url, CORRECTED_WINDOWS_PATH) + self.assertEqual(processed_url, CORRECTED_POSIX_PATH) if __name__ == "__main__":