From 88bf331dd1abd4fa07ead8c8e67445f324e15e51 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Tue, 24 Oct 2023 22:10:08 -0400 Subject: [PATCH 01/21] Added support for UNC paths and tests for UNC and posix paths 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 d6c485917..422a189cb 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, @@ -45,16 +46,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 = PurePath(request.url2pathname(parsed_result.path)) @@ -63,10 +68,18 @@ def filepath_from_url(urlstr): if PureWindowsPath(parsed_result.netloc).drive: filepath = PurePath(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 = PurePosixPath(*filepath.parts[1:]) + # 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__": From 21c1bd43ee1e8480c72b493e70de210e7c0d5963 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Tue, 24 Oct 2023 22:18:14 -0400 Subject: [PATCH 02/21] Removed unused `sys` import Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 422a189cb..54ebe441d 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -4,8 +4,6 @@ """Utilities for conversion between urls and file paths""" import os -import sys - from urllib import ( parse as urlparse, request From ba31e57b2cf52409d36c5044ffc17da43c84d3c9 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Tue, 24 Oct 2023 22:22:12 -0400 Subject: [PATCH 03/21] Updated line spacing per failed unit tests Signed-off-by: Doug Halley --- tests/test_url_conversions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_url_conversions.py b/tests/test_url_conversions.py index 455c85bcc..405553345 100644 --- a/tests/test_url_conversions.py +++ b/tests/test_url_conversions.py @@ -44,6 +44,7 @@ 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): self.assertTrue(MEDIA_EXAMPLE_PATH_URL_ABS.startswith("file://")) From d7bf883d554ca46fe7f1fbf052f4cb22dba22cc3 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Tue, 24 Oct 2023 22:55:40 -0400 Subject: [PATCH 04/21] Simplified conditionals Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 54ebe441d..9a1e0c69d 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -66,8 +66,8 @@ def filepath_from_url(urlstr): if PureWindowsPath(parsed_result.netloc).drive: filepath = PurePath(parsed_result.netloc + parsed_result.path) - # Check if the specified index is a windows drive, if it is then do nothing - elif PureWindowsPath(filepath.parts[0]).drive: + # Check if the specified index has a specified `drive`, if so then do nothing + elif filepath.drive: filepath = filepath # Check if the specified index is a windows drive, then offset the path @@ -75,8 +75,8 @@ def filepath_from_url(urlstr): # Remove leading "/" if/when `request.url2pathname` yields "/S:/path/file.ext" filepath = PurePosixPath(*filepath.parts[1:]) - # Last resort, if using a "file" schema, then strip the "file:" prefix - elif parsed_result.scheme == 'file': + # Last resort, strip the "file:" prefix + else: filepath = Path(decoded_url_str.strip('file:')) # Convert "\" to "/" if needed From e7bc171719ce43a24dec7cf3d248d5b40a3e1c44 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Wed, 14 Feb 2024 23:31:17 -0500 Subject: [PATCH 05/21] Updated to use `netloc` comparison Signed-off-by: Doug Halley --- .../opentimelineio/url_utils.py | 33 ++++++++++++------- tests/test_url_conversions.py | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 9a1e0c69d..e525b4fc4 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, request @@ -11,7 +12,8 @@ from pathlib import ( PurePath, PureWindowsPath, - PurePosixPath + PurePosixPath, + Path ) @@ -53,18 +55,18 @@ def filepath_from_url(urlstr): .. _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(decoded_url_str) + 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) # Check if the specified index has a specified `drive`, if so then do nothing elif filepath.drive: @@ -75,9 +77,18 @@ def filepath_from_url(urlstr): # Remove leading "/" if/when `request.url2pathname` yields "/S:/path/file.ext" filepath = PurePosixPath(*filepath.parts[1:]) - # Last resort, strip the "file:" prefix - else: - filepath = Path(decoded_url_str.strip('file:')) + # 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 = Path('//', parsed_result.netloc + decoded_parsed_path) # Convert "\" to "/" if needed - return filepath.as_posix() + path = filepath.as_posix() + + # Since the previous code handles Windows drive letter, we can assume that any path + # starting with a "/" is a UNC path if executed is run on Windows. + if path.startswith('/') and sys.platform == 'win32': + path = '/' + path + + return path diff --git a/tests/test_url_conversions.py b/tests/test_url_conversions.py index 405553345..38c769b9d 100644 --- a/tests/test_url_conversions.py +++ b/tests/test_url_conversions.py @@ -32,7 +32,7 @@ MEDIA_EXAMPLE_PATH_ABS ) -ENCODED_WINDOWS_URL = "file://localhost/S%3a/path/file.ext" +ENCODED_WINDOWS_URL = "file://host/S%3a/path/file.ext" WINDOWS_DRIVE_URL = "file://S:/path/file.ext" CORRECTED_WINDOWS_DRIVE_PATH = "S:/path/file.ext" From 7ef498852298a22aeb4b4e6a354472a23f955d97 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:07:45 -0500 Subject: [PATCH 06/21] Resolved merge conflicts with `main` and removed Windows specific implementations Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index e525b4fc4..d04974e1f 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -68,10 +68,6 @@ def filepath_from_url(urlstr): if PureWindowsPath(parsed_result.netloc).drive: filepath = PurePath(parsed_result.netloc + decoded_parsed_path) - # Check if the specified index has a specified `drive`, if so then do nothing - elif filepath.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" @@ -86,9 +82,4 @@ def filepath_from_url(urlstr): # Convert "\" to "/" if needed path = filepath.as_posix() - # Since the previous code handles Windows drive letter, we can assume that any path - # starting with a "/" is a UNC path if executed is run on Windows. - if path.startswith('/') and sys.platform == 'win32': - path = '/' + path - return path From 56dc9eda6290a6dca4fc06e54a661846eaae8d3c Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:08:00 -0500 Subject: [PATCH 07/21] Added additional POSIX test path Signed-off-by: Doug Halley --- tests/test_url_conversions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_url_conversions.py b/tests/test_url_conversions.py index 38c769b9d..72512ae40 100644 --- a/tests/test_url_conversions.py +++ b/tests/test_url_conversions.py @@ -40,6 +40,7 @@ WINDOWS_UNC_URL = "file://unc/path/sub dir/file.ext" CORRECTED_WINDOWS_UNC_PATH = "//unc/path/sub dir/file.ext" +POSIX_LOCALHOST_URL = "file://localhost/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" @@ -74,7 +75,7 @@ def test_windows_unc_urls(self): self.assertEqual(processed_url, CORRECTED_WINDOWS_UNC_PATH) def test_posix_urls(self): - for url in (ENCODED_POSIX_URL, POSIX_URL): + for url in (ENCODED_POSIX_URL, POSIX_URL, POSIX_LOCALHOST_URL): processed_url = otio.url_utils.filepath_from_url(url) self.assertEqual(processed_url, CORRECTED_POSIX_PATH) From 60c61ec1da516bf939aa390bf3f1a9d24e4342a6 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:09:30 -0500 Subject: [PATCH 08/21] Remove unused `sys` import Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index d04974e1f..69dd6ec11 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -4,7 +4,6 @@ """Utilities for conversion between urls and file paths""" import os -import sys from urllib import ( parse as urlparse, request From a2219841a28f48d31a77cd4c37b1fa054b7924f7 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:10:15 -0500 Subject: [PATCH 09/21] Switched to using `PurePath` Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 69dd6ec11..62c8b177a 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -76,7 +76,7 @@ def filepath_from_url(urlstr): # 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 = Path('//', parsed_result.netloc + decoded_parsed_path) + filepath = PurePath('//', parsed_result.netloc + decoded_parsed_path) # Convert "\" to "/" if needed path = filepath.as_posix() From 40897e6e1bfd3fc9981029552cd6928632f5286e Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:27:06 -0500 Subject: [PATCH 10/21] Reduced diffs Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 62c8b177a..642f62ba4 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -79,6 +79,4 @@ def filepath_from_url(urlstr): filepath = PurePath('//', parsed_result.netloc + decoded_parsed_path) # Convert "\" to "/" if needed - path = filepath.as_posix() - - return path + return filepath.as_posix() From f79af0b94097a09bdf05d92d23c851bfa89be633 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:29:53 -0500 Subject: [PATCH 11/21] Renamed testing strings to be standardized Signed-off-by: Doug Halley --- tests/test_url_conversions.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/test_url_conversions.py b/tests/test_url_conversions.py index 72512ae40..04ef4398e 100644 --- a/tests/test_url_conversions.py +++ b/tests/test_url_conversions.py @@ -32,18 +32,18 @@ MEDIA_EXAMPLE_PATH_ABS ) -ENCODED_WINDOWS_URL = "file://host/S%3a/path/file.ext" +WINDOWS_ENCODED_URL = "file://host/S%3a/path/file.ext" WINDOWS_DRIVE_URL = "file://S:/path/file.ext" -CORRECTED_WINDOWS_DRIVE_PATH = "S:/path/file.ext" +WINDOWS_DRIVE_PATH = "S:/path/file.ext" -ENCODED_WINDOWS_UNC_URL = "file://unc/path/sub%20dir/file.ext" +WINDOWS_ENCODED_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" +WINDOWS_UNC_PATH = "//unc/path/sub dir/file.ext" POSIX_LOCALHOST_URL = "file://localhost/path/sub dir/file.ext" -ENCODED_POSIX_URL = "file:///path/sub%20dir/file.ext" +POSIX_ENCODED_URL = "file:///path/sub%20dir/file.ext" POSIX_URL = "file:///path/sub dir/file.ext" -CORRECTED_POSIX_PATH = "/path/sub dir/file.ext" +POSIX_PATH = "/path/sub dir/file.ext" class TestConversions(unittest.TestCase): @@ -65,19 +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_DRIVE_URL): + for url in (WINDOWS_ENCODED_URL, WINDOWS_DRIVE_URL): processed_url = otio.url_utils.filepath_from_url(url) - self.assertEqual(processed_url, CORRECTED_WINDOWS_DRIVE_PATH) + self.assertEqual(processed_url, WINDOWS_DRIVE_PATH) def test_windows_unc_urls(self): - for url in (ENCODED_WINDOWS_UNC_URL, WINDOWS_UNC_URL): + for url in (WINDOWS_ENCODED_UNC_URL, WINDOWS_UNC_URL): processed_url = otio.url_utils.filepath_from_url(url) - self.assertEqual(processed_url, CORRECTED_WINDOWS_UNC_PATH) + self.assertEqual(processed_url, WINDOWS_UNC_PATH) def test_posix_urls(self): - for url in (ENCODED_POSIX_URL, POSIX_URL, POSIX_LOCALHOST_URL): + 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_POSIX_PATH) + self.assertEqual(processed_url, POSIX_PATH) if __name__ == "__main__": From 9fe00fe9542fa0c32c9b426922ace1a49e5d5294 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:31:11 -0500 Subject: [PATCH 12/21] Removed unused `Path` import Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 642f62ba4..5cb7cebe3 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -11,8 +11,7 @@ from pathlib import ( PurePath, PureWindowsPath, - PurePosixPath, - Path + PurePosixPath ) From 92204f6b1b17e79008c28a2665f29b7d0c32c43d Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:44:42 -0500 Subject: [PATCH 13/21] Added additional condition for generating Windows drive letter paths Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 5cb7cebe3..f38261535 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -66,6 +66,10 @@ def filepath_from_url(urlstr): if PureWindowsPath(parsed_result.netloc).drive: 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:]) + # 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" From e0499ed2f44daa04f1b70a661560d29ea0a66754 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:46:08 -0500 Subject: [PATCH 14/21] Reduced diffs Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index f38261535..5eca2d41d 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 + from urllib import ( parse as urlparse, request From c80722bed930570eb4acd2cd22cb2a3045bc03dc Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 00:48:12 -0500 Subject: [PATCH 15/21] Updated comment Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 5eca2d41d..abb678442 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -71,7 +71,7 @@ def filepath_from_url(urlstr): elif PureWindowsPath(filepath.parts[0]).drive: filepath = PurePosixPath(filepath.drive, *filepath.parts[1:]) - # 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:]) From 7cb18ebf72e9000a3acf4b75da75983ebf3cecb2 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 01:18:17 -0500 Subject: [PATCH 16/21] Inverted parameters for `assertEqual` usages Signed-off-by: Doug Halley --- tests/test_url_conversions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_url_conversions.py b/tests/test_url_conversions.py index 04ef4398e..627e6f3f9 100644 --- a/tests/test_url_conversions.py +++ b/tests/test_url_conversions.py @@ -67,17 +67,17 @@ def test_roundtrip_rel(self): def test_windows_urls(self): 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) + self.assertEqual(WINDOWS_DRIVE_PATH, processed_url) 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) + self.assertEqual(WINDOWS_UNC_PATH, processed_url) 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, POSIX_PATH) + self.assertEqual(POSIX_PATH, processed_url) if __name__ == "__main__": From 403721c115a7c4fb7439495019064f88d2115e4c Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 09:42:38 -0500 Subject: [PATCH 17/21] Reverted `assertEqual` parameter flip Signed-off-by: Doug Halley --- tests/test_url_conversions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_url_conversions.py b/tests/test_url_conversions.py index 627e6f3f9..04ef4398e 100644 --- a/tests/test_url_conversions.py +++ b/tests/test_url_conversions.py @@ -67,17 +67,17 @@ def test_roundtrip_rel(self): def test_windows_urls(self): for url in (WINDOWS_ENCODED_URL, WINDOWS_DRIVE_URL): processed_url = otio.url_utils.filepath_from_url(url) - self.assertEqual(WINDOWS_DRIVE_PATH, processed_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(WINDOWS_UNC_PATH, processed_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(POSIX_PATH, processed_url) + self.assertEqual(processed_url, POSIX_PATH) if __name__ == "__main__": From 39ff7db3e9d0a4e65832ac0f6c751b6d0ff7a32a Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 10:08:17 -0500 Subject: [PATCH 18/21] Patched `/` conforming Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index abb678442..61eb125e7 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -40,7 +40,7 @@ def url_from_filepath(fpath): ) -def filepath_from_url(urlstr): +def filepath_from_url(urlstr, as_posix=True): """ Take an url and return a filepath. @@ -82,5 +82,12 @@ def filepath_from_url(urlstr): # Paths of type: "file://host/share/path/to/file.ext" provide "host" as netloc filepath = PurePath('//', parsed_result.netloc + decoded_parsed_path) + # When running `as_posix` the resulting path will have only 1 leading `/`, + # so we insert another `/` at the front of the string path and return it. + conformed_filepath = filepath.as_posix() + if conformed_filepath.startswith('/'): + conformed_filepath = '/' + conformed_filepath + return conformed_filepath + # Convert "\" to "/" if needed return filepath.as_posix() From dd6e112360f994b18da7ae270d303dfe6e0cf054 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 12:55:13 -0500 Subject: [PATCH 19/21] Reverted kwarg Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 61eb125e7..7bf8df7f4 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -40,7 +40,7 @@ def url_from_filepath(fpath): ) -def filepath_from_url(urlstr, as_posix=True): +def filepath_from_url(urlstr): """ Take an url and return a filepath. From 76ede60a6a0c23d49762feb4d46ddaccf513c8b1 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 12:56:30 -0500 Subject: [PATCH 20/21] Updated check to try sort out the slash discrepancy Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 7bf8df7f4..73b3236f3 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -85,7 +85,7 @@ def filepath_from_url(urlstr): # When running `as_posix` the resulting path will have only 1 leading `/`, # so we insert another `/` at the front of the string path and return it. conformed_filepath = filepath.as_posix() - if conformed_filepath.startswith('/'): + if not conformed_filepath.startswith('//'): conformed_filepath = '/' + conformed_filepath return conformed_filepath From 1ad7b7088b074a3cb41c148008fdb1d22418ac98 Mon Sep 17 00:00:00 2001 From: Doug Halley Date: Thu, 15 Feb 2024 13:08:04 -0500 Subject: [PATCH 21/21] Updated comment around `.startswith('//')`` check Signed-off-by: Doug Halley --- src/py-opentimelineio/opentimelineio/url_utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/py-opentimelineio/opentimelineio/url_utils.py b/src/py-opentimelineio/opentimelineio/url_utils.py index 73b3236f3..a1c0f4990 100644 --- a/src/py-opentimelineio/opentimelineio/url_utils.py +++ b/src/py-opentimelineio/opentimelineio/url_utils.py @@ -82,8 +82,9 @@ def filepath_from_url(urlstr): # Paths of type: "file://host/share/path/to/file.ext" provide "host" as netloc filepath = PurePath('//', parsed_result.netloc + decoded_parsed_path) - # When running `as_posix` the resulting path will have only 1 leading `/`, - # so we insert another `/` at the front of the string path and return it. + # 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