Skip to content

Commit 9867dba

Browse files
committed
Propagate fragments with ResourcePath.join
Previously fragments were either dropped completely (if a ResourcePath was given that had a fragment) or included in the file name (if a plain string was given). Now fragments are always propagated if the ResourcePath parsing finds a fragment. This means that if a filename has a "#" in it that "#" will now always be treated as a fragment and not part of the filename.
1 parent 8ddb459 commit 9867dba

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

python/lsst/resources/_resourcePath.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ def join(
693693
quoted depending on the associated URI scheme. If the path looks
694694
like a URI referring to an absolute location, it will be returned
695695
directly (matching the behavior of `os.path.join`). It can
696-
also be a `ResourcePath`.
696+
also be a `ResourcePath`. Fragments are propagated.
697697
isTemporary : `bool`, optional
698698
Indicate that the resulting URI represents a temporary resource.
699699
Default is ``self.isTemporary``.
@@ -723,6 +723,9 @@ def join(
723723
refer to a file. Use `updatedFile` if the file is to be
724724
replaced.
725725
726+
If an unquoted ``#`` is included in the path it is assumed to be
727+
referring to a fragment and not part of the file name.
728+
726729
Raises
727730
------
728731
ValueError
@@ -757,10 +760,10 @@ def join(
757760
# Absolute URI so return it directly.
758761
return path_uri
759762

760-
# If this was originally a ResourcePath extract the unquoted path from
761-
# it. Otherwise we use the string we were given to allow "#" to appear
762-
# in the filename if given as a plain string.
763-
if not isinstance(path, str):
763+
# We want to propagate fragments to the joined path and we rely on
764+
# the ResourcePath parser to find these fragments for us even in plain
765+
# strings. Must assume there are no `#` characters in filenames.
766+
if not isinstance(path, str) or path_uri.fragment:
764767
path = path_uri.unquoted_path
765768

766769
# Might need to quote the path.
@@ -780,6 +783,7 @@ def join(
780783
path=newpath,
781784
forceDirectory=forceDirectory,
782785
isTemporary=isTemporary,
786+
fragment=path_uri.fragment,
783787
)
784788

785789
def relative_to(self, other: ResourcePath) -> str | None:

python/lsst/resources/tests.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,22 @@ def test_join(self) -> None:
474474
self.assertFalse(up_relative.isdir())
475475
self.assertEqual(up_relative.geturl(), f"{root_str}b/c.txt")
476476

477+
# Check that fragment is passed through join (simple unquoted case).
478+
fnew3 = root.join("a/b.txt#fragment")
479+
self.assertEqual(fnew3.fragment, "fragment")
480+
self.assertEqual(fnew3.basename(), "b.txt", msg=f"Got: {fnew3._uri}")
481+
482+
# Join a resource path.
483+
subpath = ResourcePath("a/b.txt#fragment2", forceAbsolute=False, forceDirectory=False)
484+
fnew3 = root.join(subpath)
485+
self.assertEqual(fnew3.fragment, "fragment2")
486+
self.assertEqual(fnew3.basename(), "b.txt", msg=f"Got: {fnew3._uri}")
487+
488+
# Quoted string with fragment.
477489
quote_example = "hsc/payload/b&c.t@x#t"
478490
needs_quote = root.join(quote_example)
479-
self.assertEqual(needs_quote.unquoted_path, "/" + quote_example)
491+
self.assertEqual(needs_quote.unquoted_path, "/" + quote_example[:-2])
492+
self.assertEqual(needs_quote.fragment, "t")
480493

481494
other = ResourcePath(f"{self.root}test.txt")
482495
self.assertEqual(root.join(other), other)

0 commit comments

Comments
 (0)