99"""
1010
1111import json
12+ import logging
1213import re
1314from datetime import datetime , timezone
1415
1920from rio_cogeo .cogeo import cog_validate
2021from shapely .geometry import box , mapping
2122
23+ logger = logging .getLogger (__name__ )
24+
2225
2326# =============================================================================
2427# Path Configuration
@@ -93,11 +96,12 @@ def datetime_parse_item(s: str | None) -> datetime | None:
9396# =============================================================================
9497
9598def geotiff_extract_metadata (url : str ) -> dict :
96- """Extract spatial metadata and validate GeoTIFF/COG status in one remote read .
99+ """Extract spatial metadata and validate GeoTIFF/COG status.
97100
98- Opens the remote GeoTIFF via /vsicurl/, extracts CRS, bounds, shape, and
99- transform, then validates COG status. All metadata needed for STAC item
100- creation is returned so subsequent builds can skip the remote read.
101+ Opens the remote GeoTIFF via /vsicurl/ to extract CRS, bounds, shape, and
102+ transform, then validates COG status (second remote read via cog_validate).
103+ All metadata needed for STAC item creation is cached so subsequent builds
104+ skip remote reads entirely.
101105
102106 Returns dict with url, is_geotiff, is_cog, epsg, height, width, transform, bounds.
103107 """
@@ -106,7 +110,7 @@ def geotiff_extract_metadata(url: str) -> dict:
106110
107111 try :
108112 with rasterio .open (vsicurl_path ) as src :
109- epsg = src .crs .to_epsg ()
113+ epsg = src .crs .to_epsg () if src . crs else None
110114 height = src .height
111115 width = src .width
112116 transform = list (src .transform )[:6 ]
@@ -124,7 +128,8 @@ def geotiff_extract_metadata(url: str) -> dict:
124128 "transform" : json .dumps (transform ),
125129 "bounds" : json .dumps (bounds ),
126130 }
127- except Exception :
131+ except Exception as e :
132+ logger .warning ("Failed to read %s: %s" , url , e )
128133 return {
129134 "url" : url ,
130135 "is_geotiff" : False ,
0 commit comments