Skip to content

Commit

Permalink
Add option to search for collections without granules (#940)
Browse files Browse the repository at this point in the history
Co-authored-by: Matt Fisher <3608264+mfisher87@users.noreply.github.com>
Co-authored-by: Chuck Daniels <cjdaniels4@gmail.com>
  • Loading branch information
3 people authored Feb 10, 2025
1 parent 3f5d17c commit 3f8b03a
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 0 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Changed
- `search_datasets` now accepts a `has_granules` keyword argument. Use
`has_granules=False` to search for metadata about collections with no
associated granules. The default value set in `DataCollections` remains `True`.
([#939](https://github.com/nsidc/earthaccess/issues/939))
([**@juliacollins**](https://github.com/juliacollins))

## [v0.13.0] - 2025-01-28

### Changed
Expand Down
1 change: 1 addition & 0 deletions earthaccess/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def search_datasets(count: int = -1, **kwargs: Any) -> List[DataCollection]:
* **doi**: DOI for a dataset
* **daac**: e.g. NSIDC or PODAAC
* **provider**: particular to each DAAC, e.g. POCLOUD, LPDAAC etc.
* **has_granules**: if true, only return collections with granules
* **temporal**: a tuple representing temporal bounds in the form
`(date_from, date_to)`
* **bounding_box**: a tuple representing spatial bounds in the form
Expand Down
22 changes: 22 additions & 0 deletions earthaccess/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,28 @@ def debug(self, debug: bool = True) -> Self:
self._debug = debug
return self

def has_granules(self, has_granules: bool | None = True) -> Self:
"""Match only collections with granules, without granules, or either.
Parameters:
has_granules:
If `True`, only return collections with granules. If
`False`, only return collections without granules.
If `None`, return both types of collections.
Returns:
self
"""
if has_granules is not None and not isinstance(has_granules, bool):
raise TypeError("has_granules must be of type bool or None")

if has_granules is None and "has_granules" in self.params:
del self.params["has_granules"]
else:
self.params["has_granules"] = has_granules

return self

def cloud_hosted(self, cloud_hosted: bool = True) -> Self:
"""Only match granules that are hosted in the cloud. This is valid for public
collections.
Expand Down
9 changes: 9 additions & 0 deletions tests/unit/test_collection_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ def test_querybuilder_can_handle_doi():
assert query.params["doi"] == doi


def test_querybuilder_can_handle_has_granules():
query = DataCollections().has_granules(False)
assert not query.params["has_granules"]
query = DataCollections().has_granules(True)
assert query.params["has_granules"]
query = DataCollections().has_granules(None)
assert "has_granules" not in query.params


@pytest.mark.parametrize("start,end,expected", valid_single_dates)
def test_query_can_parse_single_dates(start, end, expected):
query = DataCollections().temporal(start, end)
Expand Down

0 comments on commit 3f8b03a

Please sign in to comment.