Skip to content

Commit 1fe4b08

Browse files
committed
fix: don't strip slash from root href
Some servers require it (per #373 (comment)).
1 parent bd5b817 commit 1fe4b08

File tree

2 files changed

+72
-6
lines changed

2 files changed

+72
-6
lines changed

pystac_client/client.py

+26-5
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ def open(
149149
Return:
150150
catalog : A :class:`Client` instance for this Catalog/API
151151
"""
152-
url = url.rstrip("/")
153152
client: Client = cls.from_file(
154153
url,
155154
headers=headers,
@@ -254,7 +253,7 @@ def get_collection(self, collection_id: str) -> Optional[Collection]:
254253
CollectionClient: A STAC Collection
255254
"""
256255
if self._supports_collections() and self._stac_io:
257-
url = f"{self.get_self_href()}/collections/{collection_id}"
256+
url = self._get_collections_href(collection_id)
258257
collection = CollectionClient.from_dict(
259258
self._stac_io.read_json(url),
260259
root=self,
@@ -281,9 +280,9 @@ def get_collections(self) -> Iterator[Collection]:
281280
"""
282281
collection: Union[Collection, CollectionClient]
283282

284-
if self._supports_collections() and self.get_self_href() is not None:
285-
url = f"{self.get_self_href()}/collections"
286-
for page in self._stac_io.get_pages(url): # type: ignore
283+
if self._supports_collections() and self._stac_io:
284+
url = self._get_collections_href()
285+
for page in self._stac_io.get_pages(url):
287286
if "collections" not in page:
288287
raise APIError("Invalid response from /collections")
289288
for col in page["collections"]:
@@ -504,3 +503,25 @@ def get_search_link(self) -> Optional[pystac.Link]:
504503
),
505504
None,
506505
)
506+
507+
def _get_collections_href(self, id: Optional[str] = None) -> str:
508+
self_href = self.get_self_href()
509+
if self_href is None:
510+
data_link = self.get_single_link("data")
511+
if data_link is None:
512+
raise ValueError(
513+
"cannot build a collections href without a self href or a data link"
514+
)
515+
else:
516+
collections_href = data_link.href
517+
elif self_href.endswith("/"):
518+
collections_href = f"{self_href}collections"
519+
else:
520+
collections_href = f"{self_href}/collections"
521+
522+
if id is None:
523+
return collections_href
524+
elif collections_href.endswith("/"):
525+
return f"{collections_href}{id}"
526+
else:
527+
return f"{collections_href}/{id}"

tests/test_client.py

+46-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import warnings
44
from datetime import datetime
55
from tempfile import TemporaryDirectory
6-
from typing import Any
6+
from typing import Any, Dict
77
from urllib.parse import parse_qs, urlsplit
88

99
import pystac
@@ -146,6 +146,51 @@ def test_get_collections_single_slash(self, requests_mock: Mocker) -> None:
146146
assert len(history) == 2
147147
assert history[1].url == f"{root_url}collections"
148148

149+
def test_keep_trailing_slash_on_root(self, requests_mock: Mocker) -> None:
150+
pc_root_text = read_data_file("planetary-computer-root.json")
151+
root_url = "http://pystac-client.test/"
152+
requests_mock.get(root_url, status_code=200, text=pc_root_text)
153+
client = Client.open(root_url)
154+
self_href = client.get_self_href()
155+
assert self_href
156+
assert self_href.endswith("/")
157+
158+
def test_fall_back_to_data_link_for_collections(
159+
self, requests_mock: Mocker
160+
) -> None:
161+
pc_root_text = read_data_file("planetary-computer-root.json")
162+
root_url = "http://pystac-client.test/"
163+
requests_mock.get(root_url, status_code=200, text=pc_root_text)
164+
api = Client.open(root_url)
165+
api.set_self_href(None)
166+
pc_collection_dict = read_data_file(
167+
"planetary-computer-aster-l1t-collection.json", parse_json=True
168+
)
169+
requests_mock.get(
170+
# the href of the data link
171+
"https://planetarycomputer.microsoft.com/api/stac/v1/collections",
172+
status_code=200,
173+
json={"collections": [pc_collection_dict], "links": []},
174+
)
175+
_ = next(api.get_collections())
176+
history = requests_mock.request_history
177+
assert len(history) == 2
178+
assert (
179+
history[1].url
180+
== "https://planetarycomputer.microsoft.com/api/stac/v1/collections"
181+
)
182+
183+
def test_error_if_no_self_href_or_data_link(self, requests_mock: Mocker) -> None:
184+
pc_root = read_data_file("planetary-computer-root.json", parse_json=True)
185+
assert isinstance(pc_root, Dict)
186+
pc_root["links"] = [link for link in pc_root["links"] if link["rel"] != "data"]
187+
root_url = "http://pystac-client.test/"
188+
requests_mock.get(root_url, status_code=200, text=json.dumps(pc_root))
189+
api = Client.open(root_url)
190+
api.set_self_href(None)
191+
with pytest.raises(ValueError):
192+
_ = api.get_collection("an-id")
193+
149194
def test_custom_request_parameters(self, requests_mock: Mocker) -> None:
150195
pc_root_text = read_data_file("planetary-computer-root.json")
151196
pc_collection_dict = read_data_file(

0 commit comments

Comments
 (0)