Skip to content

Commit

Permalink
Merge pull request #134 from nansencenter/update_earthdata_cmr_provider
Browse files Browse the repository at this point in the history
Update earthdata cmr provider
  • Loading branch information
aperrin66 authored Jan 10, 2024
2 parents f99ab76 + 1877f83 commit 81cff2c
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
env:
BASE_IMAGE: "${{ vars.DOCKER_ORG }}/geospaas:2.5.2-python${{ matrix.python_version }}"
IMAGE_NAME: "${{ vars.DOCKER_ORG }}/geospaas_harvesting"
METANORM_VERSION: '4.2.0'
METANORM_VERSION: '4.2.2'
GEOSPAAS_DB_HOST: 'db'
GEOSPAAS_DB_USER: 'test'
GEOSPAAS_DB_PASSWORD: "${{ secrets.GEOSPAAS_DB_PASSWORD }}"
Expand Down
26 changes: 25 additions & 1 deletion geospaas_harvesting/providers/earthdata_cmr.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Code for searching EarthData CMR (https://www.earthdata.nasa.gov/)"""
import json

import shapely.errors
from shapely.geometry import LineString, Point, Polygon

import geospaas.catalog.managers as catalog_managers
Expand All @@ -18,7 +19,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.search_url = 'https://cmr.earthdata.nasa.gov/search/granules.umm_json'
self.search_parameters_parser.add_arguments([
WKTArgument('location', required=False, geometry_types=(LineString, Point, Polygon)),
EarthDataSpatialArgument('location', required=False, geometry_types=(LineString, Point, Polygon)),
StringArgument('short_name', required=True, description='Short name of the collection'),
ChoiceArgument('downloadable', valid_options=['true', 'false'], default='true'),
StringArgument('platform'),
Expand Down Expand Up @@ -49,11 +50,34 @@ def _make_spatial_parameter(self, geometry):
result = {'line': ','.join([f"{lon},{lat}" for lon, lat in points])}
elif isinstance(geometry, Point):
result = {'point': f"{geometry.xy[0][0]},{geometry.xy[1][0]}"}
elif isinstance(geometry, str):
name, value = geometry.split('=')
result = {name: value}
else:
raise ValueError(f"Unsupported geometry type {type(geometry)}")
return result


class EarthDataSpatialArgument(WKTArgument):
"""Argument that provides the specific spatial format required by
queries to the CMR API.
See https://cmr.earthdata.nasa.gov/search/site/docs/search/api.html#g-spatial
for valid parameters.
"""
def parse(self, value):
valid_prefixes = ('polygon', 'bounding_box', 'point', 'line', 'circle')
try:
return super().parse(value)
except (shapely.errors.ShapelyError, ValueError) as error:
if isinstance(value, str):
for prefix in valid_prefixes:
if value.startswith(f"{prefix}=") or value.startswith(f"{prefix}[]="):
return value
raise ValueError(
"location should be a geometry or a valid CMR spatial parameter"
) from error


class EarthDataCMRCrawler(HTTPPaginatedAPICrawler):
"""Crawler for the CMR Earthdata search API"""

Expand Down
31 changes: 31 additions & 0 deletions tests/providers/test_earthdata_cmr.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,39 @@ def test_make_spatial_parameter(self):
self.assertEqual(
provider._make_spatial_parameter(Point((1, 2))),
{'point': '1.0,2.0'})
self.assertEqual(
provider._make_spatial_parameter('bounding_box=-180,60,180,90'),
{'bounding_box': '-180,60,180,90'})
with self.assertRaises(ValueError):
provider._make_spatial_parameter(MultiPoint(((1, 2), (3, 4))))
with self.assertRaises(ValueError):
provider._make_spatial_parameter('polygon:1.0,2.0,2.0,3.0,3.0,4.0,1.0,2.0')


class EarthDataSpatialArgumentTestCase(unittest.TestCase):
"""Tests for the Earthdata CMR spatial argument"""
def setUp(self):
self.argument = provider_earthdata_cmr.EarthDataSpatialArgument(
'location', geometry_types=(Polygon,))

def test_parse_wkt(self):
"""Test parsing a WKT geometry"""
self.assertEqual(self.argument.parse('POLYGON((1 2,2 3,3 4,1 2))'),
Polygon(((1, 2), (2, 3), (3, 4), (1, 2))))

def test_parse_raw_spatial_extent(self):
"""Test parsing raw CMR spatial extent parameters"""
self.assertEqual(self.argument.parse('bounding_box=-180,60,180,90'),
'bounding_box=-180,60,180,90')
self.assertEqual(self.argument.parse('polygon=1.0,2.0,2.0,3.0,3.0,4.0,1.0,2.0'),
'polygon=1.0,2.0,2.0,3.0,3.0,4.0,1.0,2.0')
self.assertEqual(self.argument.parse('line=1.0,2.0,3.0,4.0'), 'line=1.0,2.0,3.0,4.0')
self.assertEqual(self.argument.parse('point=1.0,2.0'), 'point=1.0,2.0')

with self.assertRaises(ValueError):
self.argument.parse('foo=1.0,2.0')
with self.assertRaises(ValueError):
self.argument.parse('point:1.0,2.0')


class EarthdataCMRCrawlerTestCase(unittest.TestCase):
Expand Down

0 comments on commit 81cff2c

Please sign in to comment.