Skip to content

rs_client/stac/stac_base.md

<< Back to index

StacBase class implementation.

StacBase

Bases: RsClient

Base class for interacting with a STAC (SpatioTemporal Asset Catalog) API using pystac-client.

This class provides methods to retrieve STAC collections, items, queryables, and perform searches.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
class StacBase(RsClient):
    """
    Base class for interacting with a STAC (SpatioTemporal Asset Catalog) API using pystac-client.

    This class provides methods to retrieve STAC collections, items, queryables, and perform searches.
    """

    @handle_api_error
    def __init__(  # pylint: disable=too-many-branches, too-many-arguments, too-many-positional-arguments
        self,
        rs_server_href: str | None,
        rs_server_api_key: str | None = None,
        owner_id: str | None = None,
        logger: logging.Logger | None = None,
        stac_href: str | None = None,  # Flag to enable pystac_client for specific subclasses
        headers: dict[str, str] | None = None,
        parameters: dict[str, Any] | None = None,
        ignore_conformance: bool | None = None,
        modifier: Callable[[Collection | Item | ItemCollection | dict[Any, Any]], None] | None = None,
        request_modifier: Callable[[Request], Request | None] | None = None,
        stac_io: StacApiIO | None = None,
        timeout: Timeout | None = TIMEOUT,
    ):
        """
        Initialize the StacBase instance.

        Args:
            rs_server_href (str | None): URL of the RS server.
            rs_server_api_key (str | None, optional): API key for authentication.
            owner_id (str | None, optional): Owner identifier.
            logger (logging.Logger | None, optional): Logger instance.
            stac_href (str | None): STAC API URL.
            headers (Optional[Dict[str, str]], optional): HTTP headers.
            parameters (Optional[Dict[str, Any]], optional): Additional query parameters.
            ignore_conformance (Optional[bool], optional): Whether to ignore conformance.
            modifier (Callable, optional): Function to modify collection, item, or item collection.
            request_modifier (Optional[Callable[[Request], Union[Request, None]]], optional):
                                                                Function to modify requests.
            stac_io (Optional[StacApiIO], optional): Custom STAC API I/O handler.
            timeout (Optional[Timeout], optional): Request timeout.
        """
        # call RsClient init
        super().__init__(rs_server_href, rs_server_api_key, owner_id, logger)

        # Initialize pystac_client.Client only if required (for CadipClient, AuxipClient, StacClient)
        if not stac_href:
            raise RuntimeError("No stac href provided")
        # pystac_client may throw APIError exception this is handled by the decorator handle_api_error
        self.stac_href = stac_href
        if rs_server_api_key:
            if headers is None:
                headers = {}
            headers[APIKEY_HEADER] = rs_server_api_key
        if stac_io is None:
            stac_io = StacApiIO(  # This is what is done in pystac_client/client.py::from_file
                headers=headers,
                parameters=parameters,
                request_modifier=request_modifier,
                timeout=timeout,
            )
        # Save the OAuth2 authentication cookie in the pystac client cookies
        if self.rs_server_oauth2_cookie:
            stac_io.session.cookies.set("session", self.rs_server_oauth2_cookie)
        self.ps_client = Client.open(
            stac_href,
            headers=headers,
            parameters=parameters,
            ignore_conformance=ignore_conformance,
            modifier=modifier,
            request_modifier=request_modifier,
            stac_io=stac_io,
            timeout=timeout,
        )

    ################################
    # Specific STAC implementation #
    ################################
    @handle_api_error
    def get_landing(self) -> dict:
        """
        Retrieve the STAC API landing page.

        Returns:
            dict: The landing page response.

        Raises:
            RuntimeError: If an API error occurs.
        """

        return self.ps_client.to_dict()

    @handle_api_error
    def get_collections(self) -> Iterator[Collection]:
        """
        Retrieve available STAC collections the user has permission to access.

        Returns:
            Iterator[Collection]: An iterator over available collections.

        Raises:
            RuntimeError: If an API error occurs.
        """

        # Get all the available collections
        return self.ps_client.get_collections()

    @lru_cache
    @handle_api_error
    def get_collection(self, collection_id: str) -> Collection | CollectionClient:
        """
        Retrieve a specific STAC collection by ID.

        Args:
            collection_id (str): The ID of the collection.

        Returns:
            Union[Collection, CollectionClient]: The requested collection.

        Raises:
            RuntimeError: If an API error occurs.
        """
        return self.ps_client.get_collection(collection_id)

    @handle_api_error
    def get_items(
        self,
        collection_id: str,
        items_ids: list[str] | None = None,
        **query_params: Any,
    ) -> Iterator["Item"]:
        """
        Retrieve items from a collection.

        Args:
            collection_id (str): The ID of the collection.
            items_ids (Union[str, None], optional): Specific item ID(s) to retrieve.
            query_params: Extra query parameters forwarded to the collection /items endpoint
                          (non-standard STAC extension, used by some services).

        Returns:
            Iterator[Item]: An iterator over retrieved items.
        Raises:
            RuntimeError: If an API error occurs.
        """

        # Retrieve the collection
        collection = self.ps_client.get_collection(collection_id)

        # If non-standard query params are provided, call the /items endpoint manually.
        if query_params:
            params = query_params.copy()
            if items_ids and "ids" not in params:
                params["ids"] = ",".join(items_ids)
            self.logger.info(
                "Retrieving items from collection '%s' with query params: %s.",
                collection_id,
                params,
            )
            items_link_obj = collection.get_single_link("items")
            if items_link_obj is None:
                raise RuntimeError(f"Collection '{collection_id}' has no 'items' link")
            items_link = items_link_obj.get_href()
            if hasattr(self.ps_client, "_request"):
                # Use protected API to call /items with custom query params (default get_items ignores filters).
                response = self.ps_client._request(  # pylint: disable=protected-access
                    "GET",
                    items_link,
                    params=params,
                )
                # pylint: disable=protected-access
                item_collection = self.ps_client._parse_item_collection(  # type: ignore[attr-defined]
                    response,
                    collection,
                )
                # pylint: enable=protected-access
                return iter(item_collection)
            # Fallback for pystac-client versions without _request
            stac_io = getattr(self.ps_client, "_stac_io", None)
            if stac_io and hasattr(stac_io, "read_json"):
                response_dict = stac_io.read_json(items_link, parameters=params)
                return iter(ItemCollection.from_dict(response_dict).items)
            raise RuntimeError("pystac-client API has changed: cannot perform custom /items request with params.")

        # Retrieve a list of items
        if items_ids:
            self.logger.info(f"Retrieving specific items from collection '{collection_id}'.")

            try:
                return collection.get_items(*items_ids)

            # Avoid pystac-client fallback through /search (EDRS has no /search); fetch items one by one.
            # collection.get_items(*ids) internally triggers a search request, which fails on EDRS.
            except (APIError, requests.HTTPError, STACError, ValueError, TypeError) as exc:
                self.logger.debug("Direct retrieval failed, fallback to per-item: %s", exc)

                def iter_items():
                    for item_id in items_ids:
                        try:
                            item = collection.get_item(item_id)
                            if item:
                                yield item
                        except (APIError, requests.HTTPError, STACError, ValueError, TypeError) as new_exc:
                            self.logger.warning("Failed to retrieve item '%s': %s", item_id, new_exc)

                return iter_items()

        # Retrieve all items
        self.logger.info(f"Retrieving all items from collection '{collection_id}'.")
        return collection.get_items()

    @handle_api_error
    def get_item(self, collection_id: str, item_id: str) -> Item | None:
        """
        Retrieve a specific item from a collection.

        Args:
            collection_id (str): The collection ID.
            item_id (str): The item ID.

        Returns:
            Item | None: The retrieved item or None if not found.

        Raises:
            RuntimeError: If an API error occurs.
        """

        # Retrieve the collection
        collection = self.ps_client.get_collection(collection_id)
        item = collection.get_item(item_id)
        if not item:
            self.logger.error(f"Item with ID '{item_id}' not found in collection '{collection_id}'.")
        return item

    @handle_api_error
    def get_collection_queryables(self, collection_id) -> dict[str, Any]:
        """
        Retrieve queryable fields for a specific collection.

        Args:
            collection_id (str): The collection ID.

        Returns:
            Dict[str, Any]: Dictionary of queryable fields.

        Raises:
            RuntimeError: If an API error occurs.
        """

        return self.ps_client.get_merged_queryables([collection_id])

    def get_queryables(self) -> dict[str, Any]:
        """
        Retrieve queryable fields for all collections in the STAC API. These are the available terms for
        usage when writing filter expressions in /search endpoint for all the collections
        NOTE: the pystac-client library doesn't have a function for this action, so the direct call of
        the endpoint is needed

        Returns:
            Dict[str, Any]: Dictionary of queryable fields.

        Raises:
            RuntimeError: If an exception occurs from the request level.
        """
        try:
            href_queryables = self.stac_href + "queryables"
            response = self.http_session.get(
                href_queryables,
                **self.apikey_headers,
                timeout=TIMEOUT,
            )
        except (requests.exceptions.RequestException, requests.exceptions.Timeout) as e:
            self.logger.exception(f"Could not get the response from the endpoint {href_queryables}: {e}")
            raise RuntimeError(
                f"Could not get the response from the endpoint {href_queryables}",
            ) from e
        if not response.ok:
            raise RuntimeError(f"Could not get queryables from {href_queryables}")
        try:
            json_data = response.json()
            return cast(dict[str, Any], json_data)  # Explicitly cast to Dict[str, Any]
        except ValueError as e:
            raise RuntimeError(f"Invalid JSON response from {href_queryables}") from e

    @handle_api_error
    def search(  # pylint: disable=too-many-arguments, too-many-positional-arguments
        self,
        **kwargs,
    ) -> ItemCollection | None:
        """
        Perform a STAC search using query parameters.

        Returns:
            ItemCollection | None: Retrieved item collection or None if not found.

        Raises:
            RuntimeError: If an API error occurs.
        """
        kwargs.pop("owner_id", None)
        kwargs["datetime"] = kwargs.pop("timestamp", None)
        kwargs["filter"] = kwargs.pop("stac_filter", None)

        try:
            items_search = self.ps_client.search(**kwargs)

            return items_search.item_collection()
        except NotImplementedError:
            self.logger.exception(
                "The API does not conform to the STAC API Item Search spec"
                "or does not have a link with a 'rel' type of 'search' ",
            )
        return None

__init__(rs_server_href, rs_server_api_key=None, owner_id=None, logger=None, stac_href=None, headers=None, parameters=None, ignore_conformance=None, modifier=None, request_modifier=None, stac_io=None, timeout=TIMEOUT)

Initialize the StacBase instance.

Parameters:

Name Type Description Default
rs_server_href str | None

URL of the RS server.

required
rs_server_api_key str | None

API key for authentication.

None
owner_id str | None

Owner identifier.

None
logger Logger | None

Logger instance.

None
stac_href str | None

STAC API URL.

None
headers Optional[Dict[str, str]]

HTTP headers.

None
parameters Optional[Dict[str, Any]]

Additional query parameters.

None
ignore_conformance Optional[bool]

Whether to ignore conformance.

None
modifier Callable

Function to modify collection, item, or item collection.

None
request_modifier Optional[Callable[[Request], Union[Request, None]]]
                                            Function to modify requests.
None
stac_io Optional[StacApiIO]

Custom STAC API I/O handler.

None
timeout Optional[Timeout]

Request timeout.

TIMEOUT
Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
@handle_api_error
def __init__(  # pylint: disable=too-many-branches, too-many-arguments, too-many-positional-arguments
    self,
    rs_server_href: str | None,
    rs_server_api_key: str | None = None,
    owner_id: str | None = None,
    logger: logging.Logger | None = None,
    stac_href: str | None = None,  # Flag to enable pystac_client for specific subclasses
    headers: dict[str, str] | None = None,
    parameters: dict[str, Any] | None = None,
    ignore_conformance: bool | None = None,
    modifier: Callable[[Collection | Item | ItemCollection | dict[Any, Any]], None] | None = None,
    request_modifier: Callable[[Request], Request | None] | None = None,
    stac_io: StacApiIO | None = None,
    timeout: Timeout | None = TIMEOUT,
):
    """
    Initialize the StacBase instance.

    Args:
        rs_server_href (str | None): URL of the RS server.
        rs_server_api_key (str | None, optional): API key for authentication.
        owner_id (str | None, optional): Owner identifier.
        logger (logging.Logger | None, optional): Logger instance.
        stac_href (str | None): STAC API URL.
        headers (Optional[Dict[str, str]], optional): HTTP headers.
        parameters (Optional[Dict[str, Any]], optional): Additional query parameters.
        ignore_conformance (Optional[bool], optional): Whether to ignore conformance.
        modifier (Callable, optional): Function to modify collection, item, or item collection.
        request_modifier (Optional[Callable[[Request], Union[Request, None]]], optional):
                                                            Function to modify requests.
        stac_io (Optional[StacApiIO], optional): Custom STAC API I/O handler.
        timeout (Optional[Timeout], optional): Request timeout.
    """
    # call RsClient init
    super().__init__(rs_server_href, rs_server_api_key, owner_id, logger)

    # Initialize pystac_client.Client only if required (for CadipClient, AuxipClient, StacClient)
    if not stac_href:
        raise RuntimeError("No stac href provided")
    # pystac_client may throw APIError exception this is handled by the decorator handle_api_error
    self.stac_href = stac_href
    if rs_server_api_key:
        if headers is None:
            headers = {}
        headers[APIKEY_HEADER] = rs_server_api_key
    if stac_io is None:
        stac_io = StacApiIO(  # This is what is done in pystac_client/client.py::from_file
            headers=headers,
            parameters=parameters,
            request_modifier=request_modifier,
            timeout=timeout,
        )
    # Save the OAuth2 authentication cookie in the pystac client cookies
    if self.rs_server_oauth2_cookie:
        stac_io.session.cookies.set("session", self.rs_server_oauth2_cookie)
    self.ps_client = Client.open(
        stac_href,
        headers=headers,
        parameters=parameters,
        ignore_conformance=ignore_conformance,
        modifier=modifier,
        request_modifier=request_modifier,
        stac_io=stac_io,
        timeout=timeout,
    )

get_collection(collection_id) cached

Retrieve a specific STAC collection by ID.

Parameters:

Name Type Description Default
collection_id str

The ID of the collection.

required

Returns:

Type Description
Collection | CollectionClient

Union[Collection, CollectionClient]: The requested collection.

Raises:

Type Description
RuntimeError

If an API error occurs.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
@lru_cache
@handle_api_error
def get_collection(self, collection_id: str) -> Collection | CollectionClient:
    """
    Retrieve a specific STAC collection by ID.

    Args:
        collection_id (str): The ID of the collection.

    Returns:
        Union[Collection, CollectionClient]: The requested collection.

    Raises:
        RuntimeError: If an API error occurs.
    """
    return self.ps_client.get_collection(collection_id)

get_collection_queryables(collection_id)

Retrieve queryable fields for a specific collection.

Parameters:

Name Type Description Default
collection_id str

The collection ID.

required

Returns:

Type Description
dict[str, Any]

Dict[str, Any]: Dictionary of queryable fields.

Raises:

Type Description
RuntimeError

If an API error occurs.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
@handle_api_error
def get_collection_queryables(self, collection_id) -> dict[str, Any]:
    """
    Retrieve queryable fields for a specific collection.

    Args:
        collection_id (str): The collection ID.

    Returns:
        Dict[str, Any]: Dictionary of queryable fields.

    Raises:
        RuntimeError: If an API error occurs.
    """

    return self.ps_client.get_merged_queryables([collection_id])

get_collections()

Retrieve available STAC collections the user has permission to access.

Returns:

Type Description
Iterator[Collection]

Iterator[Collection]: An iterator over available collections.

Raises:

Type Description
RuntimeError

If an API error occurs.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
@handle_api_error
def get_collections(self) -> Iterator[Collection]:
    """
    Retrieve available STAC collections the user has permission to access.

    Returns:
        Iterator[Collection]: An iterator over available collections.

    Raises:
        RuntimeError: If an API error occurs.
    """

    # Get all the available collections
    return self.ps_client.get_collections()

get_item(collection_id, item_id)

Retrieve a specific item from a collection.

Parameters:

Name Type Description Default
collection_id str

The collection ID.

required
item_id str

The item ID.

required

Returns:

Type Description
Item | None

Item | None: The retrieved item or None if not found.

Raises:

Type Description
RuntimeError

If an API error occurs.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
@handle_api_error
def get_item(self, collection_id: str, item_id: str) -> Item | None:
    """
    Retrieve a specific item from a collection.

    Args:
        collection_id (str): The collection ID.
        item_id (str): The item ID.

    Returns:
        Item | None: The retrieved item or None if not found.

    Raises:
        RuntimeError: If an API error occurs.
    """

    # Retrieve the collection
    collection = self.ps_client.get_collection(collection_id)
    item = collection.get_item(item_id)
    if not item:
        self.logger.error(f"Item with ID '{item_id}' not found in collection '{collection_id}'.")
    return item

get_items(collection_id, items_ids=None, **query_params)

Retrieve items from a collection.

Parameters:

Name Type Description Default
collection_id str

The ID of the collection.

required
items_ids Union[str, None]

Specific item ID(s) to retrieve.

None
query_params Any

Extra query parameters forwarded to the collection /items endpoint (non-standard STAC extension, used by some services).

{}

Returns:

Type Description
Iterator[Item]

Iterator[Item]: An iterator over retrieved items.

Raises: RuntimeError: If an API error occurs.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
@handle_api_error
def get_items(
    self,
    collection_id: str,
    items_ids: list[str] | None = None,
    **query_params: Any,
) -> Iterator["Item"]:
    """
    Retrieve items from a collection.

    Args:
        collection_id (str): The ID of the collection.
        items_ids (Union[str, None], optional): Specific item ID(s) to retrieve.
        query_params: Extra query parameters forwarded to the collection /items endpoint
                      (non-standard STAC extension, used by some services).

    Returns:
        Iterator[Item]: An iterator over retrieved items.
    Raises:
        RuntimeError: If an API error occurs.
    """

    # Retrieve the collection
    collection = self.ps_client.get_collection(collection_id)

    # If non-standard query params are provided, call the /items endpoint manually.
    if query_params:
        params = query_params.copy()
        if items_ids and "ids" not in params:
            params["ids"] = ",".join(items_ids)
        self.logger.info(
            "Retrieving items from collection '%s' with query params: %s.",
            collection_id,
            params,
        )
        items_link_obj = collection.get_single_link("items")
        if items_link_obj is None:
            raise RuntimeError(f"Collection '{collection_id}' has no 'items' link")
        items_link = items_link_obj.get_href()
        if hasattr(self.ps_client, "_request"):
            # Use protected API to call /items with custom query params (default get_items ignores filters).
            response = self.ps_client._request(  # pylint: disable=protected-access
                "GET",
                items_link,
                params=params,
            )
            # pylint: disable=protected-access
            item_collection = self.ps_client._parse_item_collection(  # type: ignore[attr-defined]
                response,
                collection,
            )
            # pylint: enable=protected-access
            return iter(item_collection)
        # Fallback for pystac-client versions without _request
        stac_io = getattr(self.ps_client, "_stac_io", None)
        if stac_io and hasattr(stac_io, "read_json"):
            response_dict = stac_io.read_json(items_link, parameters=params)
            return iter(ItemCollection.from_dict(response_dict).items)
        raise RuntimeError("pystac-client API has changed: cannot perform custom /items request with params.")

    # Retrieve a list of items
    if items_ids:
        self.logger.info(f"Retrieving specific items from collection '{collection_id}'.")

        try:
            return collection.get_items(*items_ids)

        # Avoid pystac-client fallback through /search (EDRS has no /search); fetch items one by one.
        # collection.get_items(*ids) internally triggers a search request, which fails on EDRS.
        except (APIError, requests.HTTPError, STACError, ValueError, TypeError) as exc:
            self.logger.debug("Direct retrieval failed, fallback to per-item: %s", exc)

            def iter_items():
                for item_id in items_ids:
                    try:
                        item = collection.get_item(item_id)
                        if item:
                            yield item
                    except (APIError, requests.HTTPError, STACError, ValueError, TypeError) as new_exc:
                        self.logger.warning("Failed to retrieve item '%s': %s", item_id, new_exc)

            return iter_items()

    # Retrieve all items
    self.logger.info(f"Retrieving all items from collection '{collection_id}'.")
    return collection.get_items()

get_landing()

Retrieve the STAC API landing page.

Returns:

Name Type Description
dict dict

The landing page response.

Raises:

Type Description
RuntimeError

If an API error occurs.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
142
143
144
145
146
147
148
149
150
151
152
153
154
@handle_api_error
def get_landing(self) -> dict:
    """
    Retrieve the STAC API landing page.

    Returns:
        dict: The landing page response.

    Raises:
        RuntimeError: If an API error occurs.
    """

    return self.ps_client.to_dict()

get_queryables()

Retrieve queryable fields for all collections in the STAC API. These are the available terms for usage when writing filter expressions in /search endpoint for all the collections NOTE: the pystac-client library doesn't have a function for this action, so the direct call of the endpoint is needed

Returns:

Type Description
dict[str, Any]

Dict[str, Any]: Dictionary of queryable fields.

Raises:

Type Description
RuntimeError

If an exception occurs from the request level.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
def get_queryables(self) -> dict[str, Any]:
    """
    Retrieve queryable fields for all collections in the STAC API. These are the available terms for
    usage when writing filter expressions in /search endpoint for all the collections
    NOTE: the pystac-client library doesn't have a function for this action, so the direct call of
    the endpoint is needed

    Returns:
        Dict[str, Any]: Dictionary of queryable fields.

    Raises:
        RuntimeError: If an exception occurs from the request level.
    """
    try:
        href_queryables = self.stac_href + "queryables"
        response = self.http_session.get(
            href_queryables,
            **self.apikey_headers,
            timeout=TIMEOUT,
        )
    except (requests.exceptions.RequestException, requests.exceptions.Timeout) as e:
        self.logger.exception(f"Could not get the response from the endpoint {href_queryables}: {e}")
        raise RuntimeError(
            f"Could not get the response from the endpoint {href_queryables}",
        ) from e
    if not response.ok:
        raise RuntimeError(f"Could not get queryables from {href_queryables}")
    try:
        json_data = response.json()
        return cast(dict[str, Any], json_data)  # Explicitly cast to Dict[str, Any]
    except ValueError as e:
        raise RuntimeError(f"Invalid JSON response from {href_queryables}") from e

search(**kwargs)

Perform a STAC search using query parameters.

Returns:

Type Description
ItemCollection | None

ItemCollection | None: Retrieved item collection or None if not found.

Raises:

Type Description
RuntimeError

If an API error occurs.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
@handle_api_error
def search(  # pylint: disable=too-many-arguments, too-many-positional-arguments
    self,
    **kwargs,
) -> ItemCollection | None:
    """
    Perform a STAC search using query parameters.

    Returns:
        ItemCollection | None: Retrieved item collection or None if not found.

    Raises:
        RuntimeError: If an API error occurs.
    """
    kwargs.pop("owner_id", None)
    kwargs["datetime"] = kwargs.pop("timestamp", None)
    kwargs["filter"] = kwargs.pop("stac_filter", None)

    try:
        items_search = self.ps_client.search(**kwargs)

        return items_search.item_collection()
    except NotImplementedError:
        self.logger.exception(
            "The API does not conform to the STAC API Item Search spec"
            "or does not have a link with a 'rel' type of 'search' ",
        )
    return None

handle_api_error(func)

Decorator to handle APIError exceptions in methods that interact with pystac-client.

This decorator wraps methods of the StacBase class that call self.ps_client, catching APIError exceptions and logging them using the instance's logger.

If the logger attribute is not found or is None, it falls back to printing the error.

Parameters:

Name Type Description Default
func Callable

The method to be wrapped.

required

Returns:

Name Type Description
Callable

The wrapped method that catches and logs APIError exceptions,

then raises a RuntimeError.

Source code in docs/rs-client-libraries/rs_client/stac/stac_base.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def handle_api_error(func):
    """
    Decorator to handle APIError exceptions in methods that interact with pystac-client.

    This decorator wraps methods of the StacBase class that call `self.ps_client`,
    catching `APIError` exceptions and logging them using the instance's `logger`.

    If the `logger` attribute is not found or is `None`, it falls back to printing the error.

    Args:
        func (Callable): The method to be wrapped.

    Returns:
        Callable: The wrapped method that catches and logs `APIError` exceptions,
        then raises a RuntimeError.
    """

    @wraps(func)
    def wrapper(self, *args, **kwargs):
        try:
            return func(self, *args, **kwargs)
        except APIError as e:
            error_message = f"Pystac client returned exception: {e}"
            if hasattr(self, "logger") and self.logger:
                self.logger.exception(error_message)
            else:
                print(error_message)  # Fallback logging
            raise RuntimeError(error_message) from e

    return wrapper