[Git][debian-gis-team/asf-search][upstream] New upstream version 8.1.2

Antonio Valentino (@antonio.valentino) gitlab at salsa.debian.org
Sat Apr 19 06:47:30 BST 2025



Antonio Valentino pushed to branch upstream at Debian GIS Project / asf-search


Commits:
de27f2f9 by Antonio Valentino at 2025-04-19T05:41:42+00:00
New upstream version 8.1.2
- - - - -


16 changed files:

- CHANGELOG.md
- asf_search/ASFSearchOptions/validator_map.py
- asf_search/CMR/field_map.py
- asf_search/CMR/translate.py
- asf_search/Products/NISARProduct.py
- asf_search/__init__.py
- asf_search/constants/POLARIZATION.py
- + asf_search/constants/RANGE_BANDWIDTH.py
- asf_search/constants/__init__.py
- asf_search/export/jsonlite.py
- asf_search/export/jsonlite2.py
- asf_search/search/geo_search.py
- asf_search/search/search.py
- asf_search/search/search_count.py
- asf_search/search/search_generator.py
- tests/yml_tests/test_ASFSearchOptions.yml


Changes:

=====================================
CHANGELOG.md
=====================================
@@ -26,6 +26,12 @@ and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 -->
 ------
+## [v8.1.2](https://github.com/asfadmin/Discovery-asf_search/compare/v8.1.1...v8.1.2)
+### Added
+- Added NISAR search parameters `frameCoverage`, `jointObservation`, `mainBandPolarization`, `sideBandPolarization`, `rangeBandwidth`.
+- Updated `NISARProduct` to include these new searchable fields in `properties` dictionary
+- Include new NISAR fields in jsonlite & jsonlite2 output
+------
 ## [v8.1.1](https://github.com/asfadmin/Discovery-asf_search/compare/v8.1.0...v8.1.1)
 ### Fixed
 - SLC Burst product urls are now searchable with `find_urls()`


=====================================
asf_search/ASFSearchOptions/validator_map.py
=====================================
@@ -70,13 +70,22 @@ validator_map = {
     'instrument': parse_string,
     'collections': parse_string_list,
     'shortName': parse_string_list,
+    'dataset': parse_string_list,
+    'cmr_keywords': parse_cmr_keywords_list,
+    # S1 Inteferrogram Filters
     'temporalBaselineDays': parse_string_list,
+    # Opera Burst Filters
     'operaBurstID': parse_string_list,
+    # SLC Burst Filters
     'absoluteBurstID': parse_int_list,
     'relativeBurstID': parse_int_list,
     'fullBurstID': parse_string_list,
-    'dataset': parse_string_list,
-    'cmr_keywords': parse_cmr_keywords_list,
+    # nisar paramaters
+    'frameCoverage': parse_string,
+    'jointObservation': bool,
+    'mainBandPolarization': parse_string_list,
+    'sideBandPolarization': parse_string_list,
+    'rangeBandwidth': parse_string_list,
     # Config parameters       Parser
     'session': parse_session,
     'host': parse_string,


=====================================
asf_search/CMR/field_map.py
=====================================
@@ -1,50 +1,53 @@
 field_map = {
-    # API parameter               CMR keyword                       CMR format strings
-    'absoluteOrbit': {'key': 'orbit_number', 'fmt': '{0}'},
-    'asfFrame': {'key': 'attribute[]', 'fmt': 'int,FRAME_NUMBER,{0}'},
-    'maxBaselinePerp': {'key': 'attribute[]', 'fmt': 'float,INSAR_BASELINE,,{0}'},
-    'minBaselinePerp': {'key': 'attribute[]', 'fmt': 'float,INSAR_BASELINE,{0},'},
-    'bbox': {'key': 'bounding_box', 'fmt': '{0}'},
-    'beamMode': {'key': 'attribute[]', 'fmt': 'string,BEAM_MODE,{0}'},
-    'beamSwath': {'key': 'attribute[]', 'fmt': 'string,BEAM_MODE_TYPE,{0}'},
-    'campaign': {'key': 'attribute[]', 'fmt': 'string,MISSION_NAME,{0}'},
-    'circle': {'key': 'circle', 'fmt': '{0}'},
-    'maxDoppler': {'key': 'attribute[]', 'fmt': 'float,DOPPLER,,{0}'},
-    'minDoppler': {'key': 'attribute[]', 'fmt': 'float,DOPPLER,{0},'},
-    'maxFaradayRotation': {'key': 'attribute[]', 'fmt': 'float,FARADAY_ROTATION,,{0}'},  # noqa F401
-    'minFaradayRotation': {'key': 'attribute[]', 'fmt': 'float,FARADAY_ROTATION,{0},'},  # noqa F401
-    'flightDirection': {'key': 'attribute[]', 'fmt': 'string,ASCENDING_DESCENDING,{0}'},  # noqa F401
-    'flightLine': {'key': 'attribute[]', 'fmt': 'string,FLIGHT_LINE,{0}'},
-    'frame': {'key': 'attribute[]', 'fmt': 'int,CENTER_ESA_FRAME,{0}'},
-    'granule_list': {'key': 'readable_granule_name[]', 'fmt': '{0}'},
-    'groupID': {'key': 'attribute[]', 'fmt': 'string,GROUP_ID,{0}'},
-    'insarStackId': {'key': 'attribute[]', 'fmt': 'int,INSAR_STACK_ID,{0}'},
-    'linestring': {'key': 'line', 'fmt': '{0}'},
-    'lookDirection': {'key': 'attribute[]', 'fmt': 'string,LOOK_DIRECTION,{0}'},
-    'maxInsarStackSize': {'key': 'attribute[]', 'fmt': 'int,INSAR_STACK_SIZE,,{0}'},
-    'minInsarStackSize': {'key': 'attribute[]', 'fmt': 'int,INSAR_STACK_SIZE,{0},'},
-    'instrument': {'key': 'instrument[]', 'fmt': '{0}'},
-    'offNadirAngle': {'key': 'attribute[]', 'fmt': 'float,OFF_NADIR_ANGLE,{0}'},
-    'platform': {'key': 'platform[]', 'fmt': '{0}'},
-    'polarization': {'key': 'attribute[]', 'fmt': 'string,POLARIZATION,{0}'},
-    'point': {'key': 'point', 'fmt': '{0}'},
-    'polygon': {'key': 'polygon', 'fmt': '{0}'},
-    'processingDate': {'key': 'updated_since', 'fmt': '{0}'},
-    'processingLevel': {'key': 'attribute[]', 'fmt': 'string,PROCESSING_TYPE,{0}'},
-    'product_list': {'key': 'granule_ur[]', 'fmt': '{0}'},
-    'provider': {'key': 'provider', 'fmt': '{0}'},
-    'relativeOrbit': {'key': 'attribute[]', 'fmt': 'int,PATH_NUMBER,{0}'},
-    'temporal': {'key': 'temporal', 'fmt': '{0}'},
-    'collections': {'key': 'echo_collection_id[]', 'fmt': '{0}'},
-    'shortName': {'key': 'shortName', 'fmt': '{0}'},
-    'temporalBaselineDays': {
-        'key': 'attribute[]',
-        'fmt': 'int,TEMPORAL_BASELINE_DAYS,{0}',
-    },  # noqa F401
+    # API parameter                 CMR keyword                         CMR format strings
+    'absoluteOrbit':                {'key': 'orbit_number',             'fmt': '{0}'},
+    'asfFrame':                     {'key': 'attribute[]',              'fmt': 'int,FRAME_NUMBER,{0}'},
+    'maxBaselinePerp':              {'key': 'attribute[]',              'fmt': 'float,INSAR_BASELINE,,{0}'},
+    'minBaselinePerp':              {'key': 'attribute[]',              'fmt': 'float,INSAR_BASELINE,{0},'},
+    'bbox':                         {'key': 'bounding_box',             'fmt': '{0}'},
+    'beamMode':                     {'key': 'attribute[]',              'fmt': 'string,BEAM_MODE,{0}'},
+    'beamSwath':                    {'key': 'attribute[]',              'fmt': 'string,BEAM_MODE_TYPE,{0}'},
+    'campaign':                     {'key': 'attribute[]',              'fmt': 'string,MISSION_NAME,{0}'},
+    'circle':                       {'key': 'circle',                   'fmt': '{0}'},
+    'maxDoppler':                   {'key': 'attribute[]',              'fmt': 'float,DOPPLER,,{0}'},
+    'minDoppler':                   {'key': 'attribute[]',              'fmt': 'float,DOPPLER,{0},'},
+    'maxFaradayRotation':           {'key': 'attribute[]',              'fmt': 'float,FARADAY_ROTATION,,{0}'},  # noqa F401
+    'minFaradayRotation':           {'key': 'attribute[]',              'fmt': 'float,FARADAY_ROTATION,{0},'},  # noqa F401
+    'flightDirection':              {'key': 'attribute[]',              'fmt': 'string,ASCENDING_DESCENDING,{0}'},  # noqa F401
+    'flightLine':                   {'key': 'attribute[]',              'fmt': 'string,FLIGHT_LINE,{0}'},
+    'frame':                        {'key': 'attribute[]',              'fmt': 'int,CENTER_ESA_FRAME,{0}'},
+    'granule_list':                 {'key': 'readable_granule_name[]',  'fmt': '{0}'},
+    'groupID':                      {'key': 'attribute[]',              'fmt': 'string,GROUP_ID,{0}'},
+    'insarStackId':                 {'key': 'attribute[]',              'fmt': 'int,INSAR_STACK_ID,{0}'},
+    'linestring':                   {'key': 'line',                     'fmt': '{0}'},
+    'lookDirection':                {'key': 'attribute[]',              'fmt': 'string,LOOK_DIRECTION,{0}'},
+    'maxInsarStackSize':            {'key': 'attribute[]',              'fmt': 'int,INSAR_STACK_SIZE,,{0}'},
+    'minInsarStackSize':            {'key': 'attribute[]',              'fmt': 'int,INSAR_STACK_SIZE,{0},'},
+    'instrument':                   {'key': 'instrument[]',             'fmt': '{0}'},
+    'offNadirAngle':                {'key': 'attribute[]',              'fmt': 'float,OFF_NADIR_ANGLE,{0}'},
+    'platform':                     {'key': 'platform[]',               'fmt': '{0}'},
+    'polarization':                 {'key': 'attribute[]',              'fmt': 'string,POLARIZATION,{0}'},
+    'point':                        {'key': 'point',                    'fmt': '{0}'},
+    'polygon':                      {'key': 'polygon',                  'fmt': '{0}'},
+    'processingDate':               {'key': 'updated_since',            'fmt': '{0}'},
+    'processingLevel':              {'key': 'attribute[]',              'fmt': 'string,PROCESSING_TYPE,{0}'},
+    'product_list':                 {'key': 'granule_ur[]',             'fmt': '{0}'},
+    'provider':                     {'key': 'provider',                 'fmt': '{0}'},
+    'relativeOrbit':                {'key': 'attribute[]',              'fmt': 'int,PATH_NUMBER,{0}'},
+    'temporal':                     {'key': 'temporal',                 'fmt': '{0}'},
+    'collections':                  {'key': 'echo_collection_id[]',     'fmt': '{0}'},
+    'shortName':                    {'key': 'shortName',                'fmt': '{0}'},
+    'temporalBaselineDays':         {'key': 'attribute[]',              'fmt': 'int,TEMPORAL_BASELINE_DAYS,{0}'},  # noqa F401
     # SLC BURST fields
-    'absoluteBurstID': {'key': 'attribute[]', 'fmt': 'int,BURST_ID_ABSOLUTE,{0}'},
-    'relativeBurstID': {'key': 'attribute[]', 'fmt': 'int,BURST_ID_RELATIVE,{0}'},
-    'fullBurstID': {'key': 'attribute[]', 'fmt': 'string,BURST_ID_FULL,{0}'},
+    'absoluteBurstID':              {'key': 'attribute[]',              'fmt': 'int,BURST_ID_ABSOLUTE,{0}'},
+    'relativeBurstID':              {'key': 'attribute[]',              'fmt': 'int,BURST_ID_RELATIVE,{0}'},
+    'fullBurstID':                  {'key': 'attribute[]',              'fmt': 'string,BURST_ID_FULL,{0}'},
     # OPERA-S1 field
-    'operaBurstID': {'key': 'attribute[]', 'fmt': 'string,OPERA_BURST_ID,{0}'},
+    'operaBurstID':                 {'key': 'attribute[]',              'fmt': 'string,OPERA_BURST_ID,{0}'},
+    # NISAR fields
+    'mainBandPolarization':         {'key': 'attribute[]',             'fmt': 'string,FREQUENCY_A_POLARIZATION_CONCAT,{0}'},
+    'sideBandPolarization':         {'key': 'attribute[]',             'fmt': 'string,FREQUENCY_B_POLARIZATION_CONCAT,{0}'},
+    'frameCoverage':                {'key': 'attribute[]',             'fmt': 'string,FULL_FRAME,{0}'},
+    'jointObservation':             {'key': 'attribute[]',             'fmt': 'string,JOINT_OBSERVATION,{0}'},
+    'rangeBandwidth':               {'key': 'attribute[]',             'fmt': 'string,RANGE_BANDWIDTH_CONCAT,{0}'},
 }


=====================================
asf_search/CMR/translate.py
=====================================
@@ -30,6 +30,16 @@ def translate_opts(opts: ASFSearchOptions) -> List:
 
     dict_opts = fix_cmr_shapes(dict_opts)
 
+    # Additional Attribute FULL_FRAME stored as a TRUE/FALSE string
+    if 'frameCoverage' in dict_opts:
+        dict_opts['frameCoverage'] = {
+            'F': 'TRUE',
+            'P': 'FALSE',
+        }[dict_opts['frameCoverage'][0].upper()]
+
+    if 'jointObservation' in dict_opts:
+        dict_opts['jointObservation'] = str(dict_opts['jointObservation']).upper()
+
     # Special case to unravel WKT field a little for compatibility
     if 'intersectsWith' in dict_opts:
         shape = wkt.loads(dict_opts.pop('intersectsWith', None))
@@ -176,6 +186,22 @@ def try_parse_float(value: str) -> Optional[float]:
 
     return float(value)
 
+def try_parse_bool(val: str) -> Optional[bool]:
+    """Boolean values are stored as strings in umm json"""
+    if val is None:
+        return None
+    
+    return val.lower() == 'true'
+
+def try_parse_frame_coverage(val: str) -> Optional[str]:
+    """Frame Coverage is stored as a string boolean in FULL_FRAME, convert it to Partial/Full"""
+    if val is not None:
+        if val.lower() == 'true':
+            val = 'Full'
+        else:
+            val = 'Partial'
+    
+    return val
 
 def try_parse_date(value: str) -> Optional[str]:
     if value is None:


=====================================
asf_search/Products/NISARProduct.py
=====================================
@@ -1,6 +1,6 @@
 from typing import Dict, Tuple, Union
 from asf_search import ASFSearchOptions, ASFSession, ASFStackableProduct
-
+from asf_search.CMR.translate import try_parse_frame_coverage, try_parse_bool
 
 class NISARProduct(ASFStackableProduct):
     """
@@ -8,12 +8,15 @@ class NISARProduct(ASFStackableProduct):
 
     ASF Dataset Documentation Page: https://asf.alaska.edu/nisar/
     """
-
     _base_properties = {
         **ASFStackableProduct._base_properties,
         'pgeVersion': {'path': ['PGEVersionClass', 'PGEVersion']},
+        'mainBandPolarization': {'path': ['AdditionalAttributes', ('Name', 'FREQUENCY_A_POLARIZATION'), 'Values']},
+        'sideBandPolarization': {'path': ['AdditionalAttributes', ('Name', 'FREQUENCY_B_POLARIZATION'), 'Values']},
+        'frameCoverage': {'path': ['AdditionalAttributes', ('Name', 'FULL_FRAME'), 'Values', 0], 'cast': try_parse_frame_coverage},
+        'jointObservation': {'path': ['AdditionalAttributes', ('Name', 'JOINT_OBSERVATION'), 'Values', 0], 'cast': try_parse_bool},
+        'rangeBandwidth': {'path': ['AdditionalAttributes', ('Name', 'RANGE_BANDWIDTH_CONCAT'), 'Values']},
     }
-
     def __init__(self, args: Dict = {}, session: ASFSession = ASFSession()):
         super().__init__(args, session)
 


=====================================
asf_search/__init__.py
=====================================
@@ -45,6 +45,7 @@ from .constants import (  # noqa: F401 E402
     PRODUCT_TYPE,  # noqa: F401 E402
     INTERNAL,  # noqa: F401 E402
     DATASET,  # noqa: F401 E402
+    RANGE_BANDWIDTH,  # noqa: F401 E402
 )
 from .health import *  # noqa: F403 F401 E402
 from .search import *  # noqa: F403 F401 E402


=====================================
asf_search/constants/POLARIZATION.py
=====================================
@@ -14,3 +14,7 @@ HH_VV = 'HH+VV'
 HH_HV_VH_VV = 'HH+HV+VH+VV'
 FULL = 'full'
 UNKNOWN = 'UNKNOWN'
+# NISAR
+LH_LV="LH+LV"
+RH_RV="RH+RV"
+HH_HV_VV_VH="HH+HV+VV+VH"


=====================================
asf_search/constants/RANGE_BANDWIDTH.py
=====================================
@@ -0,0 +1,13 @@
+# Nisar Sensor Bandwidths
+## L-SAR
+BW_20_5 = "20+5"
+BW_40_5 = "40+5"
+BW_77 = "77"
+BW_5 = "5"
+BW_5_5 = "5+5"
+
+## S-SAR
+BW_10 = "10"
+BW_25 = "25"
+BW_37 = "37"
+BW_75 = "75"


=====================================
asf_search/constants/__init__.py
=====================================
@@ -9,3 +9,4 @@ from .POLARIZATION import *  # noqa: F403 F401
 from .PRODUCT_TYPE import *  # noqa: F403 F401
 from .INTERNAL import *  # noqa: F403 F401
 from .DATASET import *  # noqa: F403 F401
+from .RANGE_BANDWIDTH import *  # noqa: F403 F401


=====================================
asf_search/export/jsonlite.py
=====================================
@@ -229,6 +229,16 @@ class JSONLiteStreamArray(list):
             if p.get('validityStartDate'):
                 result['opera']['validityStartDate'] = p.get('validityStartDate')
 
+        if p.get('platform') == 'NISAR':
+            result['nisar'] = {
+                'pgeVersion':  p.get('pgeVersion'),
+                'mainBandPolarization':  p.get('mainBandPolarization'),
+                'sideBandPolarization':  p.get('sideBandPolarization'),
+                'frameCoverage':  p.get('frameCoverage'),
+                'jointObservation':  p.get('jointObservation'),
+                'rangeBandwidth':  p.get('rangeBandwidth'),
+            }
+        
         return result
 
     def getOutputType(self) -> str:


=====================================
asf_search/export/jsonlite2.py
=====================================
@@ -76,6 +76,9 @@ class JSONLite2StreamArray(JSONLiteStreamArray):
         if p.get('opera') is not None:
             result['s1o'] = p['opera']
         
+        if p.get('nisar') is not None:
+            result['nisar'] = p['nisar']
+        
         return result
 
     def getOutputType(self) -> str:


=====================================
asf_search/search/geo_search.py
=====================================
@@ -1,4 +1,4 @@
-from typing import Tuple, Union, Sequence
+from typing import Literal, Tuple, Union, Sequence
 import datetime
 from copy import copy
 
@@ -47,10 +47,15 @@ def geo_search(
     absoluteBurstID: Union[int, Sequence[int]] = None,
     relativeBurstID: Union[int, Sequence[int]] = None,
     fullBurstID: Union[str, Sequence[str]] = None,
-    collections: Union[str, Sequence[str]] = None,
     temporalBaselineDays: Union[str, Sequence[str]] = None,
     operaBurstID: Union[str, Sequence[str]] = None,
+    frameCoverage: Literal["FULL", "PARTIAL"] = None,
+    mainBandPolarization: Union[str, Sequence[str]] = None,
+    sideBandPolarization: Union[str, Sequence[str]] = None,
+    rangeBandwidth: Union[str, Sequence[str]] = None,
+    jointObservation: bool = None,
     dataset: Union[str, Sequence[str]] = None,
+    collections: Union[str, Sequence[str]] = None,
     shortName: Union[str, Sequence[str]] = None,
     cmr_keywords: Union[Tuple[str, str], Sequence[Tuple[str, str]]] = None,
     maxResults: int = None,


=====================================
asf_search/search/search.py
=====================================
@@ -1,5 +1,5 @@
 import time
-from typing import Union, Sequence, Tuple
+from typing import Literal, Union, Sequence, Tuple
 from copy import copy
 import datetime
 
@@ -48,10 +48,15 @@ def search(
     absoluteBurstID: Union[int, Sequence[int]] = None,
     relativeBurstID: Union[int, Sequence[int]] = None,
     fullBurstID: Union[str, Sequence[str]] = None,
-    collections: Union[str, Sequence[str]] = None,
     temporalBaselineDays: Union[str, Sequence[str]] = None,
     operaBurstID: Union[str, Sequence[str]] = None,
+    frameCoverage: Literal['FULL', 'PARTIAL'] = None,
+    mainBandPolarization: Union[str, Sequence[str]] = None,
+    sideBandPolarization: Union[str, Sequence[str]] = None,
+    rangeBandwidth: Union[str, Sequence[str]] = None,
+    jointObservation: bool = None,
     dataset: Union[str, Sequence[str]] = None,
+    collections: Union[str, Sequence[str]] = None,
     shortName: Union[str, Sequence[str]] = None,
     cmr_keywords: Union[Tuple[str, str], Sequence[Tuple[str, str]]] = None,
     maxResults: int = None,


=====================================
asf_search/search/search_count.py
=====================================
@@ -1,5 +1,5 @@
 import datetime
-from typing import Sequence, Tuple, Union
+from typing import Literal, Sequence, Tuple, Union
 from copy import copy
 from asf_search.ASFSearchOptions import ASFSearchOptions
 from asf_search.CMR.subquery import build_subqueries
@@ -48,10 +48,15 @@ def search_count(
     absoluteBurstID: Union[int, Sequence[int]] = None,
     relativeBurstID: Union[int, Sequence[int]] = None,
     fullBurstID: Union[str, Sequence[str]] = None,
-    collections: Union[str, Sequence[str]] = None,
     temporalBaselineDays: Union[str, Sequence[str]] = None,
     operaBurstID: Union[str, Sequence[str]] = None,
+    frameCoverage: Literal["FULL", "PARTIAL"] = None,
+    mainBandPolarization: Union[str, Sequence[str]] = None,
+    sideBandPolarization: Union[str, Sequence[str]] = None,
+    rangeBandwidth: Union[str, Sequence[str]] = None,
+    jointObservation: bool = None,
     dataset: Union[str, Sequence[str]] = None,
+    collections: Union[str, Sequence[str]] = None,
     shortName: Union[str, Sequence[str]] = None,
     cmr_keywords: Union[Tuple[str, str], Sequence[Tuple[str, str]]] = None,
     maxResults: int = None,


=====================================
asf_search/search/search_generator.py
=====================================
@@ -1,5 +1,5 @@
 import time
-from typing import Dict, Generator, Union, Sequence, Tuple, List
+from typing import Dict, Generator, Literal, Union, Sequence, Tuple, List
 from copy import copy
 from requests.exceptions import HTTPError
 from requests import ReadTimeout, Response
@@ -74,10 +74,15 @@ def search_generator(
     absoluteBurstID: Union[int, Sequence[int]] = None,
     relativeBurstID: Union[int, Sequence[int]] = None,
     fullBurstID: Union[str, Sequence[str]] = None,
-    collections: Union[str, Sequence[str]] = None,
     temporalBaselineDays: Union[str, Sequence[str]] = None,
     operaBurstID: Union[str, Sequence[str]] = None,
+    frameCoverage: Literal["FULL", "PARTIAL"] = None,
+    mainBandPolarization: Union[str, Sequence[str]] = None,
+    sideBandPolarization: Union[str, Sequence[str]] = None,
+    rangeBandwidth: Union[str, Sequence[str]] = None,
+    jointObservation: bool = None,
     dataset: Union[str, Sequence[str]] = None,
+    collections: Union[str, Sequence[str]] = None,
     shortName: Union[str, Sequence[str]] = None,
     cmr_keywords: Union[Tuple[str, str], Sequence[Tuple[str, str]]] = None,
     maxResults: int = None,


=====================================
tests/yml_tests/test_ASFSearchOptions.yml
=====================================
@@ -99,6 +99,24 @@ tests:
     output: null
     error: Invalid int list
 
+- test-validators parse_bbox_list:
+    validator: parse_bbox_list
+    input: [0.0, 0.0, 1.1, 2.5]
+    output: [0.0, 0.0, 1.1, 2.5]
+    error: null
+
+- test-validators parse_bbox_list error strings:
+    validator: parse_bbox_list
+    input: [0.0, 0.0, 1.1, 2.5, 5.5]
+    output: null
+    error: Invalid coordinate list
+
+- test-validators parse_bbox_list error strings:
+    validator: parse_bbox_list
+    input: [0.0, 0.0, 1.1, 2.5, 5.5, 0.0]
+    output: null
+    error: Invalid bbox
+
 - test-ASFSearchOptions - create blank object:
     exception: Null
     # At least once, make sure they all exist but are None:



View it on GitLab: https://salsa.debian.org/debian-gis-team/asf-search/-/commit/de27f2f9407540c05db07426e89c9a0a29e0b103

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/asf-search/-/commit/de27f2f9407540c05db07426e89c9a0a29e0b103
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20250419/d7f82d2c/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list