Skip to content

Commit 934b2c3

Browse files
committed
Harden band alias support
related to eu-cdse/openeo-cdse-infra#799 (load_stac based collection configuration)
1 parent add5864 commit 934b2c3

File tree

3 files changed

+54
-7
lines changed

3 files changed

+54
-7
lines changed

openeo/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.47.0a2"
1+
__version__ = "0.47.0a3"

openeo/metadata.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,15 @@ def rename_labels(self, target, source) -> Dimension:
113113
class Band(NamedTuple):
114114
"""
115115
Simple container class for band metadata.
116-
Based on https://github.com/stac-extensions/eo#band-object
116+
Based on STAC-1.1 common band object
117+
and https://github.com/stac-extensions/eo#band-object
117118
"""
118119

119120
name: str
120121
common_name: Optional[str] = None
121122
# wavelength in micrometer
122123
wavelength_um: Optional[float] = None
124+
# Note: "aliases" is non-standard band metadata (probably just VITO-specific).
123125
aliases: Optional[List[str]] = None
124126
# "openeo:gsd" field (https://github.com/Open-EO/openeo-stac-extensions#GSD-Object)
125127
gsd: Optional[dict] = None
@@ -143,6 +145,16 @@ def band_aliases(self) -> List[List[str]]:
143145
def common_names(self) -> List[str]:
144146
return [b.common_name for b in self.bands]
145147

148+
def _alias_match(self, name: str) -> Union[Tuple[int, Band], None]:
149+
"""Look up band by alias, return (index, Band) or None if not found."""
150+
matches = [(i, b) for (i, b) in enumerate(self.bands) if b.aliases and name in b.aliases]
151+
if len(matches) == 0:
152+
return None
153+
elif len(matches) == 1:
154+
return matches[0]
155+
else:
156+
raise ValueError(f"Multiple alias matches for band {name!r}: {[b.name for _, b in matches]}")
157+
146158
def band_index(self, band: Union[int, str]) -> int:
147159
"""
148160
Resolve a given band (common) name/index to band index
@@ -161,9 +173,8 @@ def band_index(self, band: Union[int, str]) -> int:
161173
if band in band_names:
162174
return band_names.index(band)
163175
# Check band aliases to still support old band names
164-
aliases = [True if aliases and band in aliases else False for aliases in self.band_aliases]
165-
if any(aliases):
166-
return aliases.index(True)
176+
if alias_match := self._alias_match(name=band):
177+
return alias_match[0]
167178
raise ValueError("Invalid band name/index {b!r}. Valid names: {n!r}".format(b=band, n=band_names))
168179

169180
def band_name(self, band: Union[str, int], allow_common=True) -> str:
@@ -176,8 +187,8 @@ def band_name(self, band: Union[str, int], allow_common=True) -> str:
176187
return band
177188
else:
178189
return self.band_names[self.common_names.index(band)]
179-
elif any([True if aliases and band in aliases else False for aliases in self.band_aliases]):
180-
return self.band_names[self.band_index(band)]
190+
elif alias_match := self._alias_match(name=band):
191+
return alias_match[1].name
181192
elif isinstance(band, int) and 0 <= band < len(self.bands):
182193
return self.band_names[band]
183194
raise ValueError("Invalid band name/index {b!r}. Valid names: {n!r}".format(b=band, n=self.band_names))

tests/test_metadata.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,22 @@ def test_band_dimension_band_index():
112112
bdim.band_index("yellow")
113113

114114

115+
def test_band_dimension_band_index_with_aliases():
116+
bdim = BandDimension(
117+
name="spectral",
118+
bands=[
119+
Band("B02", "blue", 0.490, aliases=["sky"]),
120+
Band("B03", "green", 0.560, aliases=["grass", "apple"]),
121+
Band("B04", "red", 0.560, aliases=["apple"]),
122+
],
123+
)
124+
assert bdim.band_index("sky") == 0
125+
assert bdim.band_index("grass") == 1
126+
127+
with pytest.raises(ValueError, match=r"Multiple alias matches for band 'apple': \['B03', 'B04'\]"):
128+
bdim.band_index("apple")
129+
130+
115131
def test_band_dimension_contains_band():
116132
bdim = BandDimension(
117133
name="spectral",
@@ -146,16 +162,36 @@ def test_band_dimension_band_name():
146162
assert bdim.band_name("B03") == "B03"
147163
with pytest.raises(ValueError, match="Invalid band name/index"):
148164
bdim.band_name("B04")
165+
149166
assert bdim.band_name("blue") == "blue"
167+
assert bdim.band_name("blue", allow_common=False) == "B02"
150168
assert bdim.band_name("green") == "green"
169+
assert bdim.band_name("green", allow_common=False) == "B03"
151170
with pytest.raises(ValueError, match="Invalid band name/index"):
152171
bdim.band_name("red")
172+
153173
assert bdim.band_name(0) == "B02"
154174
assert bdim.band_name(1) == "B03"
155175
with pytest.raises(ValueError, match="Invalid band name/index"):
156176
bdim.band_name(2)
157177

158178

179+
def test_band_dimension_band_name_with_aliases():
180+
bdim = BandDimension(
181+
name="spectral",
182+
bands=[
183+
Band("B02", "blue", 0.490, aliases=["sky"]),
184+
Band("B03", "green", 0.560, aliases=["grass", "apple"]),
185+
Band("B04", "red", 0.560, aliases=["apple"]),
186+
],
187+
)
188+
assert bdim.band_name("sky") == "B02"
189+
assert bdim.band_name("grass") == "B03"
190+
191+
with pytest.raises(ValueError, match=r"Multiple alias matches for band 'apple': \['B03', 'B04'\]"):
192+
bdim.band_name("apple")
193+
194+
159195
def test_band_dimension_filter_bands():
160196
b02 = Band("B02", "blue", 0.490)
161197
b03 = Band("B03", "green", 0.560)

0 commit comments

Comments
 (0)