Skip to content

Commit 90ca9f3

Browse files
committed
Added support for UNC paths and tests for UNC and posix paths
Signed-off-by: Doug Halley <[email protected]>
1 parent 745e614 commit 90ca9f3

File tree

2 files changed

+39
-9
lines changed

2 files changed

+39
-9
lines changed

src/py-opentimelineio/opentimelineio/url_utils.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""Utilities for conversion between urls and file paths"""
55

66
import os
7+
import sys
78

89
from urllib import (
910
parse as urlparse,
@@ -44,16 +45,20 @@ def filepath_from_url(urlstr):
4445
Take an url and return a filepath.
4546
4647
URLs can either be encoded according to the `RFC 3986`_ standard or not.
47-
Additionally, Windows mapped paths need to be accounted for when processing a
48-
URL; however, there are `ongoing discussions`_ about how to best handle this within
49-
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.
5052
5153
.. _RFC 3986: https://tools.ietf.org/html/rfc3986#section-2.1
5254
.. _ongoing discussions: https://discuss.python.org/t/file-uris-in-python/15600
5355
"""
5456

57+
# De-encode the URL
58+
decoded_url_str = urlparse.unquote(urlstr)
59+
5560
# Parse provided URL
56-
parsed_result = urlparse.urlparse(urlstr)
61+
parsed_result = urlparse.urlparse(decoded_url_str)
5762

5863
# Convert the parsed URL to a path
5964
filepath = Path(request.url2pathname(parsed_result.path))
@@ -62,10 +67,18 @@ def filepath_from_url(urlstr):
6267
if PureWindowsPath(parsed_result.netloc).drive:
6368
filepath = Path(parsed_result.netloc + parsed_result.path)
6469

65-
# Otherwise check if the specified index is a windows drive, then offset the path
70+
# Check if the specified index is a windows drive, if it is then do nothing
71+
elif PureWindowsPath(filepath.parts[0]).drive:
72+
filepath = filepath
73+
74+
# Check if the specified index is a windows drive, then offset the path
6675
elif PureWindowsPath(filepath.parts[1]).drive:
6776
# Remove leading "/" if/when `request.url2pathname` yields "/S:/path/file.ext"
6877
filepath = filepath.relative_to(filepath.root)
6978

79+
# Last resort, if using a "file" schema, then strip the "file:" prefix
80+
elif parsed_result.scheme == 'file':
81+
filepath = Path(decoded_url_str.strip('file:'))
82+
7083
# Convert "\" to "/" if needed
7184
return filepath.as_posix()

tests/test_url_conversions.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,16 @@
3333
)
3434

3535
ENCODED_WINDOWS_URL = "file://localhost/S%3a/path/file.ext"
36-
WINDOWS_URL = "file://S:/path/file.ext"
37-
CORRECTED_WINDOWS_PATH = "S:/path/file.ext"
36+
WINDOWS_DRIVE_URL = "file://S:/path/file.ext"
37+
CORRECTED_WINDOWS_DRIVE_PATH = "S:/path/file.ext"
3838

39+
ENCODED_WINDOWS_UNC_URL = "file://unc/path/sub%20dir/file.ext"
40+
WINDOWS_UNC_URL = "file://unc/path/sub dir/file.ext"
41+
CORRECTED_WINDOWS_UNC_PATH = "//unc/path/sub dir/file.ext"
42+
43+
ENCODED_POSIX_URL = "file:///path/sub%20dir/file.ext"
44+
POSIX_URL = "file:///path/sub dir/file.ext"
45+
CORRECTED_POSIX_PATH = "/path/sub dir/file.ext"
3946

4047
class TestConversions(unittest.TestCase):
4148
def test_roundtrip_abs(self):
@@ -56,9 +63,19 @@ def test_roundtrip_rel(self):
5663
self.assertEqual(os.path.normpath(result), MEDIA_EXAMPLE_PATH_REL)
5764

5865
def test_windows_urls(self):
59-
for url in (ENCODED_WINDOWS_URL, WINDOWS_URL):
66+
for url in (ENCODED_WINDOWS_URL, WINDOWS_DRIVE_URL):
67+
processed_url = otio.url_utils.filepath_from_url(url)
68+
self.assertEqual(processed_url, CORRECTED_WINDOWS_DRIVE_PATH)
69+
70+
def test_windows_unc_urls(self):
71+
for url in (ENCODED_WINDOWS_UNC_URL, WINDOWS_UNC_URL):
72+
processed_url = otio.url_utils.filepath_from_url(url)
73+
self.assertEqual(processed_url, CORRECTED_WINDOWS_UNC_PATH)
74+
75+
def test_posix_urls(self):
76+
for url in (ENCODED_POSIX_URL, POSIX_URL):
6077
processed_url = otio.url_utils.filepath_from_url(url)
61-
self.assertEqual(processed_url, CORRECTED_WINDOWS_PATH)
78+
self.assertEqual(processed_url, CORRECTED_POSIX_PATH)
6279

6380

6481
if __name__ == "__main__":

0 commit comments

Comments
 (0)