Skip to content

Commit

Permalink
Add methods for setting parameter options (#75)
Browse files Browse the repository at this point in the history
* Added functions for setting parameter options in Query class.

* Revised doc strings on option functions. Added unit tests for each of the functions in test_queries.py.

* Reverted changes to implement a more generic singular option function. Enabled doctests. Query's options member is now a defaultdict

* removed unused import from test_queries

* Added entry to CHANGELOG.md for issue #74

---------

Co-authored-by: Frank Greguska <89428916+frankinspace@users.noreply.github.com>
  • Loading branch information
miabobia and frankinspace committed Aug 19, 2024
1 parent a797e35 commit fb58457
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 105 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Add `Query` method `option` for setting parameter options as described both in
[CMR Search API Parameter Options](https://cmr.earthdata.nasa.gov/search/site/docs/search/api.html#parameter-options)
and in other sections of the CMR Search API documentation, thus supporting
other parameter options that are not covered in that particular section of the
documentation. ([#74](https://github.com/nasa/python_cmr/issues/74))
- Support multi-point searches ([#72](https://github.com/nasa/python_cmr/issues/72))

### Fixed
Expand Down
66 changes: 58 additions & 8 deletions cmr/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

from abc import abstractmethod
from collections import defaultdict
from datetime import date, datetime, timezone
from inspect import getmembers, ismethod
from re import search
Expand Down Expand Up @@ -51,7 +52,7 @@ class Query:

def __init__(self, route: str, mode: str = CMR_OPS):
self.params: MutableMapping[str, Any] = {}
self.options: MutableMapping[str, Any] = {}
self.options: MutableMapping[str, MutableMapping[str, Any]] = defaultdict(dict)
self._route = route
self.mode(mode)
self.concept_id_chars: Set[str] = set()
Expand Down Expand Up @@ -203,13 +204,6 @@ def _build_url(self) -> str:
formatted_options: List[str] = []
for param_key in self.options:
for option_key, val in self.options[param_key].items():

# all CMR options must be booleans
if not isinstance(val, bool):
raise TypeError(
f"parameter '{param_key}' with option '{option_key}' must be a boolean"
)

formatted_options.append(f"options[{param_key}][{option_key}]={str(val).lower()}")

options_as_string = "&".join(formatted_options)
Expand Down Expand Up @@ -314,6 +308,62 @@ def bearer_token(self, bearer_token: str) -> Self:

return self

def option(
self, parameter: str, key: str, value: Union[str, bool, int, float, None]
) -> Self:
"""
Set or remove a search parameter option.
If either an empty parameter name or option key is given, do nothing.
Otherwise, if a non-`None` option value is given, set the specified parameter
option to the value; else _remove_ the parameter option, if previously given.
In all cases, return self to support method chaining.
See `CMR Search API Parameter Options`_ as well as other sections of the
documentation that describe other available parameter options.
.. _CMR Search API Parameter Options:
https://cmr.earthdata.nasa.gov/search/site/docs/search/api.html#parameter-options
Example:
.. code:: python
>>> query = CollectionQuery()
>>> query.option("short_name", "ignore_case", True) # doctest: +ELLIPSIS
<cmr.queries.CollectionQuery ...>
>>> query.options # doctest: +ELLIPSIS
defaultdict(..., {'short_name': {'ignore_case': True}})
>>> query.option("short_name", "ignore_case", False) # doctest: +ELLIPSIS
<cmr.queries.CollectionQuery ...>
>>> query.options # doctest: +ELLIPSIS
defaultdict(..., {'short_name': {'ignore_case': False}})
>>> (query
... .option("short_name", "ignore_case", None) # remove an option
... .option("short_name", "or", True)
... .option("highlights", "begin_tag", "<b>")
... .option("highlights", "end_tag", "</b>")
... )
<cmr.queries.CollectionQuery ...>
>>> query.options # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
defaultdict(..., {'short_name': {'or': True},
'highlights': {'begin_tag': '<b>', 'end_tag': '</b>'}})
:param parameter: search parameter to set an option for
:param key: option key to set a value for
:param value: value to set for the option, or `None` to remove the option
:returns: self
"""

if parameter and key:
if value is None:
del self.options[parameter][key]
else:
self.options[parameter][key] = value

return self


class GranuleCollectionBaseQuery(Query):
"""
Expand Down
Loading

0 comments on commit fb58457

Please sign in to comment.