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

Antonio Valentino (@antonio.valentino) gitlab at salsa.debian.org
Tue Feb 17 06:56:59 GMT 2026



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


Commits:
e80d78f5 by Antonio Valentino at 2026-02-17T06:48:00+00:00
New upstream version 12.0.0
- - - - -


11 changed files:

- CHANGELOG.md
- asf_search/CMR/datasets.py
- asf_search/Products/OPERAS1Product.py
- + asf_search/Products/TROPOProduct.py
- asf_search/Products/__init__.py
- asf_search/constants/DATASET.py
- asf_search/constants/PRODUCT_TYPE.py
- asf_search/export/jsonlite.py
- asf_search/search/search_generator.py
- tests/ASFProduct/test_ASFSubproduct.py
- tests/yml_tests/test_ASFSubproduct.yml


Changes:

=====================================
CHANGELOG.md
=====================================
@@ -25,6 +25,16 @@ and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 -
 
 -->
+------
+## [v12.0.0](https://github.com/asfadmin/Discovery-asf_search/compare/v11.0.3...v12.0.0)
+### Added
+- Add `DISP-S1-STATIC` support: product type constant, added to `OPERA-S1` dataset, supported in `OPERAS1Product` class
+- Add `TROPO` dataset for `TROPO-ZENITH` and `ECMWF_TROPO` product types
+- Add new `ASFProduct` subclass `TROPOProduct` for `TROPO-ZENITH` and `ECMWF_TROPO` product types
+
+### Changed
+- Moved `TROPO-ZENITH` out of `OPERA-S1` dataset, now in standalone `TROPO` dataset
+
 ------
 ## [v11.0.3](https://github.com/asfadmin/Discovery-asf_search/compare/v11.0.2...v11.0.3)
 ### Fixed


=====================================
asf_search/CMR/datasets.py
=====================================
@@ -441,7 +441,12 @@ dataset_collections = {
         'OPERA_L2_RTC-S1-STATIC_V1': ['C1259981910-ASF', 'C2795135174-ASF'],
         'OPERA_L2_RTC-S1_PROVISIONAL_V0': ['C1257995186-ASF'],
         'OPERA_L3_DISP-S1_V1': ['C3294057315-ASF', 'C1271830354-ASF'],
-        'OPERA_L4_TROPO-ZENITH_V1': ['C3717139408-ASF'],
+        'OPERA_L3_DISP-S1-STATIC_V1': ['C3959290248-ASF', 'C1273910948-ASF', 'C1273460752-ASFDEV'],
+        
+    },
+    'TROPO': {
+        'ASF_ECMWF_TROPO': ['C3653531162-ASF'],
+        'OPERA_L4_TROPO-ZENITH_V1': ['C3717139408-ASF', 'C1273910987-ASF', 'C1273615785-ASFDEV'],
     },
     'OPERA-S1-CALVAL': {
         'OPERA_L2_CSLC-S1_CALVAL_V1': ['C1260721945-ASF', 'C2803501758-ASF'],
@@ -1371,8 +1376,10 @@ collections_by_processing_level = {
         'C3294057315-ASF',
         'C1271830354-ASF'
     ],
-    'TROPO-ZENITH': [
-        'C3717139408-ASF',
+    'DISP-S1-STATIC': ['C3959290248-ASF', 'C1273910948-ASF', 'C1273460752-ASFDEV'],
+    'TROPO-ZENITH': ['C3717139408-ASF', 'C1273910987-ASF', 'C1273615785-ASFDEV'],
+    'ECMWF_TROPO': [
+        'C3653531162-ASF'
     ],
     'GRD_FD': [
         'C1214471197-ASF',


=====================================
asf_search/Products/OPERAS1Product.py
=====================================
@@ -127,7 +127,24 @@ class OPERAS1Product(S1Product):
 
             self.properties['zarrUri'] = self.find_urls(extension='.gz', pattern=product_zarr, directAccess=True)[0]
             self.properties['zarrStackUri'] = self.find_urls(extension='.gz', pattern=r'.*short_wavelength_displacement.zarr.json.gz', directAccess=True)[0]
-
+        elif processingLevel == 'DISP-S1-STATIC':
+            self.properties['frameNumber'] = try_parse_int(
+                self.umm_get(
+                    self.umm,
+                    'AdditionalAttributes',
+                    ('Name', 'FRAME_NUMBER'),
+                    'Values', 
+                    0)
+                )
+            self.properties['pathNumber'] = try_parse_int(
+                self.umm_get(
+                    self.umm,
+                    'AdditionalAttributes',
+                    ('Name', 'PATH_NUMBER'),
+                    'Values', 
+                    0)
+                )
+            pass
     @staticmethod
     def get_default_baseline_product_type() -> None:
         """


=====================================
asf_search/Products/TROPOProduct.py
=====================================
@@ -0,0 +1,51 @@
+from asf_search.ASFProduct import ASFProduct
+from asf_search import ASFSession
+from asf_search.CMR.translate import try_parse_date
+from asf_search.constants import PRODUCT_TYPE
+
+
+class TROPOProduct(ASFProduct):
+    """
+    S1Product Subclass made specifically for Sentinel-1 SLC-BURST products
+
+    Key features/properties:
+    - `properties['burst']` contains SLC-BURST Specific fields
+        such as `fullBurstID` and `burstIndex`
+    - `properties['additionalUrls']` contains BURST-XML url
+    - SLC-BURST specific stacking params
+
+    ASF Dataset Documentation Page:
+        https://asf.alaska.edu/datasets/data-sets/derived-data-sets/sentinel-1-bursts/
+    """
+
+    _base_properties = {
+        **ASFProduct._base_properties,
+        'processingLevel': {
+            'path': ['AdditionalAttributes', ('Name', 'PRODUCT_TYPE'), 'Values', 0]
+        },
+        'bytes': {'path': ['DataGranule', 'ArchiveAndDistributionInformation']},
+    }
+
+    def __init__(self, args: dict = {}, session: ASFSession = ASFSession()):
+        super().__init__(args, session)
+
+        if self.properties['processingLevel'] == PRODUCT_TYPE.TROPO_ZENITH:
+            self.umm_get(self.umm, 'AdditionalAttributes', ('Name', 'PRODUCT_VERSION'), 'values')
+        elif self.properties['processingLevel'] == PRODUCT_TYPE.ECMWF_TROPO:
+            self.properties['startTime'] = self.umm_cast(try_parse_date, self.umm_get(self.umm, 'TemporalExtent', 'SingleDateTime'))
+            self.properties['stopTime'] = self.properties['startTime']
+
+        bytes_mapping = {
+            entry['Name']: {'bytes': entry['SizeInBytes'], 'format': entry['Format']}
+            for entry in self.properties['bytes']
+        }
+        md5sum_mapping = {
+            entry['Name']: entry['Checksum']['Value'] for entry in self.properties['bytes']
+        }
+
+        self.properties['bytes'] = bytes_mapping
+        self.properties['md5sum'] = md5sum_mapping
+
+        self.properties['browse'] = [url for url in self._get_urls() if url.endswith('.png') or url.endswith('.jpg') or url.endswith('.jpeg')]
+        self.properties['additionalUrls'] = self._get_additional_urls()
+        self.properties['s3Urls'] = self._get_s3_uris()


=====================================
asf_search/Products/__init__.py
=====================================
@@ -13,3 +13,4 @@ from .OPERAS1Product import OPERAS1Product  # noqa: F401
 from .ARIAS1GUNWProduct import ARIAS1GUNWProduct  # noqa: F401
 from .NISARProduct import NISARProduct  # noqa: F401
 from .ALOS2Product import ALOS2Product  # noqa: F401
+from .TROPOProduct import TROPOProduct # noqa: F401


=====================================
asf_search/constants/DATASET.py
=====================================
@@ -18,3 +18,4 @@ NISAR = 'NISAR'
 """NISAR provides L and S-band SAR data to measure Earth's changing ecosystems,
  dynamic surfaces, and ice masses with 12-day regularity
  on ascending and descending passes."""
+TROPO = 'TROPO'


=====================================
asf_search/constants/PRODUCT_TYPE.py
=====================================
@@ -97,7 +97,11 @@ CSLC = 'CSLC'
 RTC_STATIC = 'RTC-STATIC'
 CSLC_STATIC = 'CSLC-STATIC'
 DISP_S1 = 'DISP-S1'
+DISP_S1_STATIC = 'DISP-S1-STATIC'
+
+# TROPO
 TROPO_ZENITH = 'TROPO-ZENITH'
+ECMWF_TROPO = 'ECMWF_TROPO'
 
 # NISAR
 L0B = 'L0B'


=====================================
asf_search/export/jsonlite.py
=====================================
@@ -8,7 +8,7 @@ from shapely.ops import transform
 
 from asf_search import ASF_LOGGER
 from asf_search.export.export_translators import ASFSearchResults_to_properties_list
-
+from asf_search.constants import PRODUCT_TYPE
 _MB = 1048576
 
 extra_jsonlite_fields = [
@@ -229,6 +229,10 @@ class JSONLiteStreamArray(list):
             result["burst"] = p["burst"]
             result["sizeMB"] = float(p["bytes"]) / 1024000
 
+        elif result.get('productType', None) in [PRODUCT_TYPE.TROPO_ZENITH, PRODUCT_TYPE.ECMWF_TROPO]:
+            result['sizeMB'] = p.get('bytes', {})
+            result['s3Urls'] = p.get('s3Urls', [])
+            result['additionalUrls'] = p.get('additionalUrls')
         elif p.get('operaBurstID') is not None or result['productID'].startswith('OPERA'):
             result['opera'] = {
                 'operaBurstID': p.get('operaBurstID'),


=====================================
asf_search/search/search_generator.py
=====================================
@@ -567,4 +567,5 @@ dataset_to_product_types = {
     'SEASAT 1': ASFProductType.SEASATProduct,
     'NISAR': ASFProductType.NISARProduct,
     'ALOS-2': ASFProductType.ALOS2Product,
+    'TROPO': ASFProductType.TROPOProduct,
 }


=====================================
tests/ASFProduct/test_ASFSubproduct.py
=====================================
@@ -2,6 +2,7 @@ from asf_search import Products, search, ASFSearchOptions
 from asf_search.ASFSearchResults import ASFSearchResults
 import json
 import pytest
+from asf_search.constants import PRODUCT_TYPE
 
 def run_test_ASFSubproduct(scene_names: list[str], expected_subclass: str, opts: ASFSearchOptions):
     scenes = search(granule_list=scene_names, opts=opts)
@@ -16,6 +17,8 @@ def run_test_ASFSubproduct(scene_names: list[str], expected_subclass: str, opts:
             _test_S1BurstProduct(scene)
         if isinstance(scene, Products.SEASATProduct):
             _test_SEASATProduct(scene)
+        if isinstance(scene, Products.TROPOProduct):
+            _test_TROPOProduct(scene)
 
     for output_format in ['geojson', 'json', 'jsonlite', 'jsonlite2', 'csv', 'metalink', 'kml']:
         try:
@@ -48,6 +51,13 @@ def _test_SEASATProduct(scene: Products.SEASATProduct):
     bytes_entries = scene.properties['bytes'].keys()
     _check_properties_set(scene.properties['md5sum'], bytes_entries)
 
+def _test_TROPOProduct(scene: Products.TROPOProduct):
+    assert scene.properties['processingLevel'] in [PRODUCT_TYPE.TROPO_ZENITH, PRODUCT_TYPE.ECMWF_TROPO]
+    assert isinstance(scene.properties['bytes'], dict)
+    
+    bytes_entries = scene.properties['bytes'].keys()
+    _check_properties_set(scene.properties['md5sum'], bytes_entries)
+
 def _test_S1BurstProduct(scene: Products.S1BurstProduct):
     burst_properties = [
         "absoluteBurstID",


=====================================
tests/yml_tests/test_ASFSubproduct.yml
=====================================
@@ -7,10 +7,17 @@ tests:
           "OPERA_L2_RTC-S1-STATIC_T160-342208-IW3_20140403_S1B_30_v1.0",
           "OPERA_L2_CSLC-S1-STATIC_T160-342208-IW3_20140403_S1B_v1.0",
           "OPERA_L3_DISP-S1_IW_F42776_VV_20180504T161139Z_20180516T161139Z_v1.0_20250829T201146Z",
-          "OPERA_L4_TROPO-ZENITH_20250930T180000Z_20251003T000713Z_HRES_v1.0",
         ]
       expected_subclass: OPERAS1Product
 
   - Test S1Burst ASFSubproduct:
       scenes: ["S1_055219_EW1_20250418T163543_HH_1D57-BURST"]
       expected_subclass: S1BurstProduct
+
+  - Test TROPO ASFSubproduct:
+      scenes:
+        [
+          "OPERA_L4_TROPO-ZENITH_20250930T180000Z_20251003T000713Z_HRES_v1.0",
+          "ECMWF_TROP_202602121200_202602121200_1",
+        ]
+      expected_subclass: TROPOProduct



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

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/asf-search/-/commit/e80d78f52c20bbe748e154045fa6e83a07bc52d5
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/20260217/e83915e0/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list