Skip to content

Commit 498e72b

Browse files
committed
Fix #251.
Based closely on code provided by @lukesdm
1 parent d6b648b commit 498e72b

2 files changed

Lines changed: 40 additions & 2 deletions

File tree

odc/stac/_mdtools.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,13 +505,19 @@ def extract(self, md: Any) -> RasterGroupMetadata:
505505
# disabled that filter with `ignore_proj=True` option
506506
check_proj = has_proj_ext(item) and not c.ignore_proj
507507

508-
def _keep(kv: tuple[str, pystac.asset.Asset]) -> bool:
508+
def _keep(kv: tuple[str, pystac.asset.Asset], check_proj: bool) -> bool:
509509
name, asset = kv
510510
if name in c.band_cfg:
511511
return True
512512
return is_raster_data(asset, check_proj=check_proj)
513513

514-
data_bands = dicttoolz.itemfilter(_keep, item.assets)
514+
data_bands = dicttoolz.itemfilter(lambda kv: _keep(kv, check_proj), item.assets)
515+
516+
if len(data_bands) == 0 and check_proj:
517+
# If no data bands found with check_proj=True, fallback to check_proj=False
518+
# This handles items that declare proj extension at item level but don't have
519+
# per-asset proj data (shape/transform)
520+
data_bands = dicttoolz.itemfilter(lambda kv: _keep(kv, False), item.assets)
515521

516522
bands: dict[BandKey, RasterBandMetadata | AuxBandMetadata] = {}
517523
aliases = alias_map_from_eo(item)
@@ -665,6 +671,15 @@ def _bootstrap(self, item: pystac.item.Item) -> None:
665671
data_asset_names = set(n for n, _ in meta.bands if n in item.assets)
666672
data_assets = {n: item.assets[n] for n in data_asset_names}
667673

674+
# Check if any data assets have proj data.
675+
# If item declares proj extension but assets don't have proj data, fall back to has_proj=False
676+
if (
677+
has_proj
678+
and data_assets
679+
and not any(has_proj_data(a) for a in data_assets.values())
680+
):
681+
has_proj = False
682+
668683
# We assume that grouping of data bands into grids is consistent across
669684
# entire collection, so we compute it once and keep it
670685
if has_proj:

tests/test_mdtools.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,29 @@ def test_noassets_case(no_bands_stac) -> None:
298298
assert len(md.bands) == 0
299299

300300

301+
def test_partial_proj_fallback(partial_proj_stac: pystac.item.Item) -> None:
302+
"""
303+
Test that items declaring proj extension but without per-asset proj data
304+
fall back correctly and don't produce empty datasets.
305+
Regression test for https://github.com/opendatacube/odc-stac/issues/251
306+
"""
307+
# Item declares proj extension but assets don't have proj:shape/transform
308+
item = partial_proj_stac
309+
assert has_proj_ext(item) is True
310+
311+
# Extract collection metadata - should fall back to has_proj=False
312+
md = extract_collection_metadata(item)
313+
assert len(md.bands) > 0, "Should have found data bands with fallback"
314+
assert md.has_proj is False, "Should have fallen back to has_proj=False"
315+
316+
# Parse item - should successfully extract bands
317+
parsed = parse_item(item, md)
318+
assert len(parsed.bands) == len(item.assets), "All assets should be parsed as bands"
319+
# Verify bands are parsed correctly
320+
for asset_name in item.assets:
321+
assert (asset_name, 1) in parsed.bands, f"Asset {asset_name} should be in bands"
322+
323+
301324
def test_extract_md_raster_ext(
302325
sentinel_stac_ms_with_raster_ext: pystac.item.Item,
303326
) -> None:

0 commit comments

Comments
 (0)