Skip to content

Commit f71edb5

Browse files
authored
Merge pull request #309 from gaoflow/fix-307-landsat-stac-nir08
FIX: Resolve Landsat STAC bands whose asset name differs from the common name (#307)
2 parents ff325b9 + dd3943b commit f71edb5

3 files changed

Lines changed: 46 additions & 8 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 0.24.1 (2026-mm-dd)
44

55
- FIX: Fix subsetting complex SAR data with a window (cannot be done directly in the ESA SNAP Read Operator)
6+
- FIX: Fix `KeyError` when loading a Landsat Collection-2 band from a STAC item whose asset name differs from the STAC common name (e.g. `nir08` instead of `nir`) [#307](https://github.com/sertit/eoreader/issues/307)
67

78
## 0.24.0 (2026-05-05)
89

ci/on_push/test_stac_items.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from tempenv import tempenv
99

1010
from ci.scripts_utils import READER, compare, reduce_verbosity
11+
from eoreader.bands import NIR
1112
from eoreader.products import Product
1213
from eoreader.reader import Constellation
1314

@@ -96,6 +97,24 @@ def test_l5_mpc():
9697
)
9798

9899

100+
def test_l9_l2_mpc_nir_asset():
101+
"""Resolving the NIR band of a Landsat C2 L2 MPC item must not raise (#307).
102+
103+
These items expose the NIR band under the versioned STAC asset name
104+
``nir08`` rather than the generic ``nir``, which used to raise
105+
``KeyError: 'nir'`` when getting the band path.
106+
"""
107+
prod = READER.open(
108+
"https://planetarycomputer.microsoft.com/api/stac/v1/collections/landsat-c2-l2/items/LC09_L2SP_095022_20231119_02_T2",
109+
remove_tmp=True,
110+
)
111+
assert prod is not None
112+
113+
band_paths = prod.get_band_paths([NIR])
114+
# NIR is band 5 on Landsat-8/9: the resolved asset is the SR_B5 file
115+
assert "B5" in str(band_paths[NIR])
116+
117+
99118
def test_s2_mpc():
100119
"""Function testing the support of Sentinel-2 L2A (COG) constellation processed by MPC and linked via a STAC URL"""
101120
_test_core(

eoreader/products/optical/landsat_product.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2048,18 +2048,36 @@ def _get_path(self, band_id: str) -> str:
20482048
if band is not None and f"B{band.id}" == band_id
20492049
][0]
20502050
asset_name = EOREADER_STAC_MAP[band_name].value
2051+
if asset_name not in self.item.assets:
2052+
# Some collections name the asset differently from the STAC
2053+
# common name (e.g. Landsat Collection-2 exposes the NIR band
2054+
# as "nir08" instead of "nir"). Fall back to a fuzzy match
2055+
# against the actual asset keys (#307).
2056+
asset_name = self._get_closest_asset(asset_name)
20512057
else:
2052-
try:
2053-
asset_name = difflib.get_close_matches(
2054-
band_id, self.item.assets.keys(), cutoff=0.5, n=1
2055-
)[0]
2056-
except Exception as exc:
2057-
raise FileNotFoundError(
2058-
f"Impossible to find an asset in {list(self.item.assets.keys())} close enough to '{band_id}'"
2059-
) from exc
2058+
asset_name = self._get_closest_asset(band_id)
20602059

20612060
return self.sign_url(self.item.assets[asset_name].href)
20622061

2062+
def _get_closest_asset(self, name: str) -> str:
2063+
"""
2064+
Find the STAC asset whose name is closest to the given one.
2065+
2066+
Args:
2067+
name (str): Asset name to look for
2068+
2069+
Returns:
2070+
str: Closest asset name
2071+
"""
2072+
try:
2073+
return difflib.get_close_matches(
2074+
name, self.item.assets.keys(), cutoff=0.5, n=1
2075+
)[0]
2076+
except Exception as exc:
2077+
raise FileNotFoundError(
2078+
f"Impossible to find an asset in {list(self.item.assets.keys())} close enough to '{name}'"
2079+
) from exc
2080+
20632081
def _read_mtd(self, force_pd=False) -> (etree._Element, dict):
20642082
"""
20652083
Read Landsat metadata as:

0 commit comments

Comments
 (0)