Prepare GeoIntel for public release
Managed validation / Managed repository validation (pull_request) Successful in 1m46s
GeoIntel release gates / Compile, test, contracts and builds (pull_request) Successful in 1m51s
GeoIntel release gates / Python and npm vulnerability policy (pull_request) Successful in 20s
GeoIntel release gates / Production AI image, SBOM and container scan (pull_request) Successful in 15m3s
GeoIntel release gates / Deploy exact gated revision to Unraid (pull_request) Skipped
Managed validation / Managed repository validation (pull_request) Successful in 1m46s
GeoIntel release gates / Compile, test, contracts and builds (pull_request) Successful in 1m51s
GeoIntel release gates / Python and npm vulnerability policy (pull_request) Successful in 20s
GeoIntel release gates / Production AI image, SBOM and container scan (pull_request) Successful in 15m3s
GeoIntel release gates / Deploy exact gated revision to Unraid (pull_request) Skipped
This commit is contained in:
@@ -2,9 +2,26 @@ from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.core.errors import AppError
|
||||
|
||||
|
||||
_DTYPE_BYTES = {
|
||||
"uint8": 1,
|
||||
"int8": 1,
|
||||
"uint16": 2,
|
||||
"int16": 2,
|
||||
"uint32": 4,
|
||||
"int32": 4,
|
||||
"float32": 4,
|
||||
"uint64": 8,
|
||||
"int64": 8,
|
||||
"float64": 8,
|
||||
"complex64": 8,
|
||||
"complex128": 16,
|
||||
}
|
||||
|
||||
|
||||
def _import_rasterio():
|
||||
import importlib
|
||||
|
||||
@@ -26,6 +43,33 @@ def extract_raster_metadata(path: str) -> dict:
|
||||
dataset_path = Path(path)
|
||||
try:
|
||||
with rasterio.open(dataset_path) as dataset:
|
||||
settings = get_settings()
|
||||
width = int(dataset.width)
|
||||
height = int(dataset.height)
|
||||
band_count = int(dataset.count)
|
||||
pixel_count = width * height
|
||||
dtype_bytes = max((_DTYPE_BYTES.get(str(dtype), 16) for dtype in dataset.dtypes), default=16)
|
||||
decoded_bytes = pixel_count * band_count * dtype_bytes
|
||||
if (
|
||||
width <= 0
|
||||
or height <= 0
|
||||
or band_count <= 0
|
||||
or pixel_count > settings.max_raster_pixels
|
||||
or band_count > settings.max_raster_bands
|
||||
or decoded_bytes > settings.max_decoded_raster_mb * 1024 * 1024
|
||||
):
|
||||
raise AppError(
|
||||
code="RASTER_RESOURCE_LIMIT_EXCEEDED",
|
||||
message="Raster dimensions or decoded size exceed the configured processing budget.",
|
||||
details={
|
||||
"width": width,
|
||||
"height": height,
|
||||
"band_count": band_count,
|
||||
"pixel_count": pixel_count,
|
||||
"estimated_decoded_bytes": decoded_bytes,
|
||||
},
|
||||
status_code=413,
|
||||
)
|
||||
nodata = dataset.nodata
|
||||
if isinstance(nodata, (list, tuple)):
|
||||
nodata_value = [None if value is None else float(value) for value in nodata]
|
||||
@@ -35,9 +79,9 @@ def extract_raster_metadata(path: str) -> dict:
|
||||
transform = dataset.transform.to_gdal() if hasattr(dataset, "transform") else None
|
||||
return {
|
||||
"driver": dataset.driver,
|
||||
"width": int(dataset.width),
|
||||
"height": int(dataset.height),
|
||||
"band_count": int(dataset.count),
|
||||
"width": width,
|
||||
"height": height,
|
||||
"band_count": band_count,
|
||||
"crs": str(dataset.crs) if dataset.crs else None,
|
||||
"bounds": list(dataset.bounds),
|
||||
"resolution": list(dataset.res),
|
||||
@@ -45,6 +89,8 @@ def extract_raster_metadata(path: str) -> dict:
|
||||
"nodata": nodata_value,
|
||||
"transform": list(transform) if transform is not None else None,
|
||||
}
|
||||
except AppError:
|
||||
raise
|
||||
except Exception as exc:
|
||||
if isinstance(exc, errors.RasterioIOError):
|
||||
raise AppError(code="INVALID_RASTER", message="Uploaded raster file is invalid", status_code=400) from exc
|
||||
|
||||
Reference in New Issue
Block a user