[Git][debian-gis-team/usgs][master] 5 commits: New upstream version 0.3.7

Antonio Valentino (@antonio.valentino) gitlab at salsa.debian.org
Thu May 28 06:50:47 BST 2026



Antonio Valentino pushed to branch master at Debian GIS Project / usgs


Commits:
f0853c1c by Antonio Valentino at 2026-05-28T05:26:26+00:00
New upstream version 0.3.7
- - - - -
9f4d03a9 by Antonio Valentino at 2026-05-28T05:26:27+00:00
Update upstream source from tag 'upstream/0.3.7'

Update to upstream version '0.3.7'
with Debian dir db8ff99ed32319a8d0add96e2de79cfd31a3acda
- - - - -
03702129 by Antonio Valentino at 2026-05-28T05:28:06+00:00
New upstream release

- - - - -
863c750f by Antonio Valentino at 2026-05-28T05:47:03+00:00
Skip broken tests

- - - - -
0c97f9be by Antonio Valentino at 2026-05-28T05:50:10+00:00
Set distribution to unstable

- - - - -


7 changed files:

- debian/changelog
- debian/rules
- tests/MockPost.py
- tests/test_api.py
- tests/test_payloads.py
- usgs/api.py
- usgs/payloads.py


Changes:

=====================================
debian/changelog
=====================================
@@ -1,13 +1,18 @@
-usgs (0.3.6-2) UNRELEASED; urgency=medium
+usgs (0.3.7-1) unstable; urgency=medium
 
-  * Team upload.
+  [ Bas Couwenberg ]
   * Update lintian overrides.
   * Drop Rules-Requires-Root: no, default since dpkg 1.22.13.
   * Use test-build-validate-cleanup instead of test-build-twice.
   * Drop Priority: optional, default since dpkg 1.22.13.
   * Bump Standards-Version to 4.7.4, changes: priority.
 
- -- Bas Couwenberg <sebastic at debian.org>  Fri, 12 Sep 2025 17:51:49 +0200
+  [ Antonio Valentino ]
+  * New usptream release.
+  * debian/rules:
+    - Skip broken test: test_logout_http_error.
+
+ -- Antonio Valentino <antonio.valentino at tiscali.it>  Thu, 28 May 2026 05:28:35 +0000
 
 usgs (0.3.6-1) unstable; urgency=medium
 


=====================================
debian/rules
=====================================
@@ -1,6 +1,9 @@
 #! /usr/bin/make -f
 
-export PYBUILD_TEST_ARGS=-k "not test_scene_search and not test_scene_search_radial_distance"
+export PYBUILD_TEST_ARGS=\
+-k "not test_scene_search \
+and not test_scene_search_radial_distance \
+and not test_logout_http_error"
 
 %:
 	dh $@ --buildsystem=pybuild


=====================================
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/-/compare/e4e9df2846d23c767801cc670ca9be5b4d603aea...0c97f9be7ca43c2339e954a6d4d1f646cc62113a

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/usgs/-/compare/e4e9df2846d23c767801cc670ca9be5b4d603aea...0c97f9be7ca43c2339e954a6d4d1f646cc62113a
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/8828a646/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list