[Git][debian-gis-team/usgs][upstream] New upstream version 0.3.7
Antonio Valentino (@antonio.valentino)
gitlab at salsa.debian.org
Thu May 28 06:50:52 BST 2026
Antonio Valentino pushed to branch upstream at Debian GIS Project / usgs
Commits:
f0853c1c by Antonio Valentino at 2026-05-28T05:26:26+00:00
New upstream version 0.3.7
- - - - -
5 changed files:
- tests/MockPost.py
- tests/test_api.py
- tests/test_payloads.py
- usgs/api.py
- usgs/payloads.py
Changes:
=====================================
tests/MockPost.py
=====================================
@@ -2,20 +2,31 @@
import os
import json
+import requests
+
testdir = os.path.dirname(os.path.abspath(__file__))
class MockPost(object):
- def __init__(self, filename):
+ def __init__(self, filename=None, status_code=200, reason="OK"):
self.filename = filename
+ self.status_code = status_code
+ self.reason = reason
- def __call__(self, url, payload):
+ def __call__(self, url, payload=None):
return self
+ def raise_for_status(self):
+ if self.status_code >= 400:
+ raise requests.HTTPError(
+ "%d %s" % (self.status_code, self.reason))
+ return None
+
+
def json(self):
filepath = os.path.join(testdir, 'data', self.filename)
=====================================
tests/test_api.py
=====================================
@@ -1,7 +1,9 @@
-import pytest
+import unittest
from unittest import mock
-from usgs import api
+import requests
+
+from usgs import api, USGSError
from .MockPost import MockPost
@@ -111,3 +113,74 @@ def test_scene_search():
for expected_key in expected_keys:
assert expected_key in response['data']["results"][0]
+
+
+class HttpErrorTests(unittest.TestCase):
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_dataset_filters_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.dataset_filters("LANDSAT_8_C1")
+ assert "HTTP error occurred during dataset filters request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_download_options_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.download_options("LANDSAT_8_C1", ["LC82260782020217LGN00"])
+ assert "HTTP error occurred during download options request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_dataset_download_options_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.dataset_download_options("LANDSAT_8_C1")
+ assert "HTTP error occurred during dataset download options request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_download_request_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.download_request(
+ "LANDSAT_8_C1", "LC82260782020217LGN00", "5e83d0b84df8d8c2")
+ assert "HTTP error occurred during download request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_dataset_search_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.dataset_search()
+ assert "HTTP error occurred during dataset search request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_login_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.login("user", "token", save=False)
+ assert "HTTP error occurred during login request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_scene_metadata_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.scene_metadata("LANDSAT_8_C1", "LC82260782020217LGN00")
+ assert "HTTP error occurred during scene metadata request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ def test_scene_search_http_error(self):
+ with self.assertRaises(USGSError) as cm:
+ api.scene_search("LANDSAT_8_C1")
+ assert "HTTP error occurred during scene search request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+
+ @mock.patch('usgs.api.requests.Session.post', MockPost(status_code=500, reason="Server Error"))
+ @mock.patch('usgs.api.os.remove')
+ @mock.patch('usgs.api.os.path.exists', return_value=True)
+ def test_logout_http_error(self, mock_exists, mock_remove):
+ with self.assertRaises(USGSError) as cm:
+ api.logout()
+ assert "HTTP error occurred during logout request" in str(cm.exception)
+ assert isinstance(cm.exception.__cause__, requests.HTTPError)
+ # credentials file is always removed on logout, even when the request fails
+ mock_remove.assert_called_once()
=====================================
tests/test_payloads.py
=====================================
@@ -66,7 +66,7 @@ class PayloadsTest(unittest.TestCase):
def test_scene_search(self):
- expected = """{"datasetName": "GLS2005", "maxResults": 3, "metadataType": null, "sceneFilter": {"acquisitionFilter": {"start": "2006-01-01T00:00:00Z", "end": "2007-12-01T00:00:00Z"}, "spatialFilter": {"filterType": "mbr", "lowerLeft": {"longitude": -135, "latitude": 75}, "upperRight": {"longitude": -120, "latitude": 90}}}}"""
+ expected = """{"datasetName": "GLS2005", "maxResults": 3, "startingNumber": null, "metadataType": null, "sceneFilter": {"acquisitionFilter": {"start": "2006-01-01T00:00:00Z", "end": "2007-12-01T00:00:00Z"}, "spatialFilter": {"filterType": "mbr", "lowerLeft": {"longitude": -135, "latitude": 75}, "upperRight": {"longitude": -120, "latitude": 90}}}}"""
ll = {"longitude": -135, "latitude": 75}
ur = {"longitude": -120, "latitude": 90}
@@ -82,7 +82,7 @@ class PayloadsTest(unittest.TestCase):
def test_scene_search_radial_distance(self):
- expected = """{"datasetName": "GLS2005", "maxResults": 3, "metadataType": null, "sceneFilter": {"acquisitionFilter": {"start": "2006-01-01T00:00:00Z", "end": "2007-12-01T00:00:00Z"}, "spatialFilter": {"filterType": "mbr", "lowerLeft": {"longitude": -125.01823502237109, "latitude": 84.99840995696343}, "upperRight": {"longitude": -124.98175340746137, "latitude": 85.00158953883317}}}}"""
+ expected = """{"datasetName": "GLS2005", "maxResults": 3, "startingNumber": null, "metadataType": null, "sceneFilter": {"acquisitionFilter": {"start": "2006-01-01T00:00:00Z", "end": "2007-12-01T00:00:00Z"}, "spatialFilter": {"filterType": "mbr", "lowerLeft": {"longitude": -125.01823502237109, "latitude": 84.99840995696343}, "upperRight": {"longitude": -124.98175340746137, "latitude": 85.00158953883317}}}}"""
lat = 85
lng = -125
@@ -93,4 +93,33 @@ class PayloadsTest(unittest.TestCase):
payload = payloads.scene_search(
"GLS2005", lat=lat, lng=lng, distance=dist, start_date=start_date, end_date=end_date, max_results=3)
+ assert compare_json(payload, expected), "wrong result: {r} \n for expected: {e}".format(r=payload, e=expected)
+
+
+ def test_scene_search_with_scene_filter(self):
+ expected = """{"datasetName": "GLS2005", "maxResults": 3, "startingNumber": null, "metadataType": null, "sceneFilter": {"acquisitionFilter": {"start": "2006-01-01T00:00:00Z", "end": "2007-12-01T00:00:00Z"}, "ingestFilter": {"start": "2010-01-01", "end": "2012-01-31"}}}"""
+
+ start_date = "2006-01-01T00:00:00Z"
+ end_date = "2007-12-01T00:00:00Z"
+ scene_filter = {"ingestFilter": {"start": "2010-01-01", "end": "2012-01-31"}}
+
+ payload = payloads.scene_search(
+ "GLS2005", start_date=start_date, end_date=end_date,
+ max_results=3, scene_filter=scene_filter)
+
+ assert compare_json(payload, expected), "wrong result: {r} \n for expected: {e}".format(r=payload, e=expected)
+
+
+ def test_scene_search_scene_filter_overrides(self):
+ # scene_filter should override values set by other parameters
+ expected = """{"datasetName": "GLS2005", "maxResults": 3, "startingNumber": null, "metadataType": null, "sceneFilter": {"acquisitionFilter": {"start": "2010-01-01", "end": "2010-12-31"}}}"""
+
+ start_date = "2006-01-01T00:00:00Z"
+ end_date = "2007-12-01T00:00:00Z"
+ scene_filter = {"acquisitionFilter": {"start": "2010-01-01", "end": "2010-12-31"}}
+
+ payload = payloads.scene_search(
+ "GLS2005", start_date=start_date, end_date=end_date,
+ max_results=3, scene_filter=scene_filter)
+
assert compare_json(payload, expected), "wrong result: {r} \n for expected: {e}".format(r=payload, e=expected)
\ No newline at end of file
=====================================
usgs/api.py
=====================================
@@ -24,6 +24,13 @@ def _get_api_key(api_key):
return api_key
+def _check_for_requests_error(response, message_context=""):
+ try:
+ response.raise_for_status()
+ except requests.HTTPError as e:
+ msg = f"HTTP error occurred during {message_context} request, {e}"
+ raise USGSError(msg) from e
+
def _check_for_usgs_error(data):
error_code = data['errorCode']
@@ -61,6 +68,8 @@ def dataset_filters(dataset, api_key=None):
payload = payloads.dataset_filters(dataset)
r = session.post(url, payload)
+ _check_for_requests_error(r, "dataset filters")
+
response = r.json()
_check_for_usgs_error(response)
@@ -75,6 +84,8 @@ def download_options(dataset, entity_ids, api_key=None):
payload = payloads.download_options(dataset, entity_ids)
r = session.post(url, payload)
+ _check_for_requests_error(r, "download options")
+
response = r.json()
_check_for_usgs_error(response)
@@ -96,6 +107,8 @@ def dataset_download_options(dataset, api_key=None):
payload = payloads.dataset_download_options(dataset)
r = session.post(url, payload)
+ _check_for_requests_error(r, "dataset download options")
+
response = r.json()
_check_for_usgs_error(response)
@@ -114,6 +127,8 @@ def download_request(dataset, entity_id, product_id, api_key=None):
payload = payloads.download_request(dataset, entity_id, product_id)
r = session.post(url, payload)
+ _check_for_requests_error(r, "download request")
+
response = r.json()
_check_for_usgs_error(response)
@@ -130,6 +145,8 @@ def dataset_search(dataset=None, catalog=None, ll=None, ur=None, start_date=None
end_date=end_date, ll=ll, ur=ur)
r = session.post(url, payload)
+ _check_for_requests_error(r, "dataset search")
+
response = r.json()
_check_for_usgs_error(response)
@@ -154,6 +171,8 @@ def login(username, token, save=True):
created = datetime.now().isoformat()
r = session.post(url, payload)
+ _check_for_requests_error(r, "login")
+
response = r.json()
_check_for_usgs_error(response)
@@ -181,19 +200,21 @@ def logout():
url = '{}/logout'.format(USGS_API)
- with _create_session(api_key=None) as session:
- r = session.post(url)
-
- response = r.json()
-
try:
- _check_for_usgs_error(response)
- except USGSAuthExpiredError:
- pass
+ with _create_session(api_key=None) as session:
+ r = session.post(url)
- os.remove(TMPFILE)
+ _check_for_requests_error(r, "logout")
- return response
+ response = r.json()
+ try:
+ _check_for_usgs_error(response)
+ except USGSAuthExpiredError:
+ pass
+
+ return response
+ finally:
+ os.remove(TMPFILE)
def scene_metadata(dataset, entity_id, api_key=None):
"""
@@ -211,6 +232,8 @@ def scene_metadata(dataset, entity_id, api_key=None):
with _create_session(api_key) as session:
r = session.post(url, payload)
+ _check_for_requests_error(r, "scene metadata")
+
response = r.json()
_check_for_usgs_error(response)
@@ -222,38 +245,41 @@ def scene_search(dataset,
start_date=None, end_date=None,
ll=None, ur=None,
lat=None, lng=None, distance=100,
- where=None, starting_number=1, sort_order="DESC", api_key=None):
+ where=None, scene_filter=None, starting_number=1, sort_order="DESC", api_key=None):
"""
- :param dataset:
+ :param str dataset:
USGS dataset (e.g. EO1_HYP_PUB, LANDSAT_8)
- :param lat:
+ :param str lat:
Latitude
- :param lng:
+ :param str lng:
Longitude
- :param distance:
+ :param int distance:
Distance in meters used to for a radial search
- :param ll:
+ :param dict ll:
Dictionary of longitude/latitude coordinates for the lower left corner
of a bounding box search. e.g. { "longitude": 0.0, "latitude": 0.0 }
- :param ur:
+ :param dict ur:
Dictionary of longitude/latitude coordinates for the upper right corner
of a bounding box search. e.g. { "longitude": 0.0, "latitude": 0.0 }
- :param start_date:
+ :param str start_date:
Start date for when a scene has been acquired
- :param end_date:
+ :param str end_date:
End date for when a scene has been acquired
- :where:
+ :param dict where:
Dictionary representing key/values for finer grained conditional
queries. Only a subset of metadata fields are supported. Available
fields depend on the value of `dataset`, and maybe be found by
submitting a dataset_filters query.
- :max_results:
+ :param int max_results:
Maximum results returned by the server
- :starting_number:
+ :param dict scene_filter:
+ Additional filters to apply to the "sceneFilter". Can override filters set using other parameters.
+ e.g. {"ingestFilter": {"start": "2010-01-01", "end": "2012-01-31"}}
+ :param int starting_number:
Starting offset for results of a query.
- :sort_order:
+ :param str sort_order:
Order in which results are sorted. Ascending or descending w.r.t the acquisition date.
- :api_key:
+ :param str api_key:
API key for EROS. Required for searching.
"""
api_key = _get_api_key(api_key)
@@ -264,9 +290,11 @@ def scene_search(dataset,
dataset, max_results=max_results, metadata_type=metadata_type,
start_date=start_date, end_date=end_date,
ll=ll, ur=ur, lat=lat, lng=lng, distance=distance, where=where,
- starting_number=starting_number)
+ scene_filter=scene_filter, starting_number=starting_number)
r = session.post(url, payload)
+ _check_for_requests_error(r, "scene search")
+
response = r.json()
_check_for_usgs_error(response)
=====================================
usgs/payloads.py
=====================================
@@ -184,7 +184,7 @@ def scene_search(
dataset, max_results=None, metadata_type=None, start_date=None,
end_date=None, ll=None, ur=None,
lat=None, lng=None, distance=100,
- where=None, starting_number=None):
+ where=None, starting_number=None, scene_filter=None):
payload = defaultdict(dict, {
"datasetName": dataset,
@@ -221,4 +221,7 @@ def scene_search(
"operand": "="
}
+ if scene_filter is not None:
+ payload["sceneFilter"].update(scene_filter)
+
return json.dumps(payload)
View it on GitLab: https://salsa.debian.org/debian-gis-team/usgs/-/commit/f0853c1c1b25720308e0d5f2ecc7bb923e00d013
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/usgs/-/commit/f0853c1c1b25720308e0d5f2ecc7bb923e00d013
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260528/de279cd4/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list