Skip to content

Commit

Permalink
Merge pull request #65 from lsst/tickets/DM-35695
Browse files Browse the repository at this point in the history
  • Loading branch information
timj committed Sep 2, 2023
2 parents 9e43544 + 772d5ab commit 87a22c7
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 7 deletions.
1 change: 1 addition & 0 deletions doc/changes/DM-35695.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed problem where a fragment associated with a schemeless URI was erroneously being quoted.
21 changes: 14 additions & 7 deletions python/lsst/resources/_resourcePath.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,21 @@ def __new__(
if ESCAPES_RE.search(uri):
log.warning("Possible double encoding of %s", uri)
else:
uri = urllib.parse.quote(uri)
# Special case hash since we must support fragments
# even in schemeless URIs -- although try to only replace
# them in file part and not directory part
if ESCAPED_HASH in uri:
# Fragments are generally not encoded so we must search
# for the fragment boundary ourselves. This is making
# an assumption that the filename does not include a "#"
# and also that there is no "/" in the fragment itself.
to_encode = uri
fragment = ""
if "#" in uri:
dirpos = uri.rfind("/")
# Do replacement after this /
uri = uri[: dirpos + 1] + uri[dirpos + 1 :].replace(ESCAPED_HASH, "#")
trailing = uri[dirpos + 1 :]
hashpos = trailing.rfind("#")
if hashpos != -1:
fragment = trailing[hashpos:]
to_encode = uri[: dirpos + hashpos + 1]

uri = urllib.parse.quote(to_encode) + fragment

parsed = urllib.parse.urlparse(uri)
elif isinstance(uri, urllib.parse.ParseResult):
Expand Down
8 changes: 8 additions & 0 deletions tests/test_schemeless.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ def test_creation(self) -> None:
file_uri = ResourcePath(relative + "#frag", root=prefix_uri)
self.assertEqual(str(file_uri), f"file://{prefix_uri.ospath}{relative}#frag")

# Fragments should not be encoded.
relative_uri = ResourcePath(relative + "#a,b", forceAbsolute=False)
self.assertEqual(str(relative_uri), f"{relative}#a,b")

# file URI with # in directory name does not encode fragment.
file_uri = ResourcePath("./relati#ve/file.yaml#a,v", root=prefix_uri)
self.assertEqual(str(file_uri), f"file://{prefix_uri.ospath}relati%23ve/file.yaml#a,v")

# For historical reasons a a root can not be anything other
# than a file. This does not really make sense in the general
# sense but can be implemented using uri.join().
Expand Down

0 comments on commit 87a22c7

Please sign in to comment.