Parent: #2162
Goal
Add a shared validator that open_geotiff and every direct backend (read_geotiff_dask, read_geotiff_gpu, read_vrt) call up front, so identical inputs produce identical errors no matter which entry point you use.
Today open_geotiff validates overview_level, on_gpu_failure, missing_sources, band_nodata, max_cloud_bytes, and file-like source restrictions inline at xrspatial/geotiff/__init__.py:508-584. Direct backends each call _validate_overview_level_arg individually but skip the rest. Direct callers can pass an invalid band_nodata to dask, or max_cloud_bytes to GPU, and they will not see the error open_geotiff would raise.
Scope
Add _validate_dispatch_kwargs(...) to xrspatial/geotiff/_validation.py. It validates:
overview_level (delegates to existing _validate_overview_level_arg)
on_gpu_failure (must be auto or strict; raises when GPU is off)
missing_sources (VRT only)
band_nodata (VRT only)
max_cloud_bytes (incompatible with VRT/GPU/dask per current policy)
- file-like source restrictions for
gpu=True and chunks=...
Wire it in:
open_geotiff at __init__.py:508-584 replaces the inline checks with one call.
read_geotiff_dask, read_geotiff_gpu, and read_vrt each gain one call near the top of their bodies, next to the existing _validate_overview_level_arg calls at dask.py:116 and gpu.py:204.
Keep error messages the same as today's inline checks.
Tests
Add xrspatial/geotiff/tests/test_dispatch_validation_parity_2162.py. Parametrize over open_geotiff and the three direct backends. Prove that each invalid input raises the same exception type and a recognizable message regardless of entry point:
- Invalid
overview_level (bool, str, float) through all four entry points.
max_cloud_bytes with dask, GPU, and VRT.
missing_sources on non-VRT sources.
band_nodata on non-VRT sources.
on_gpu_failure when GPU is disabled.
Files
xrspatial/geotiff/_validation.py (add helper)
xrspatial/geotiff/__init__.py (replace 508-584 with helper call)
xrspatial/geotiff/_backends/dask.py (one new call)
xrspatial/geotiff/_backends/gpu.py (one new call)
xrspatial/geotiff/_backends/vrt.py (one new call)
xrspatial/geotiff/tests/test_dispatch_validation_parity_2162.py (new)
Constraints
- No public API change. Behavior preserved for valid inputs.
- Default sentinels (
_ON_GPU_FAILURE_SENTINEL, _MISSING_SOURCES_SENTINEL, _MAX_CLOUD_BYTES_SENTINEL in _runtime.py) still mean "caller did not pass this kwarg" and skip the rejection.
Out of scope
- Adding finalization helpers (this is wave 1; helpers are a sibling issue in the same wave).
- Migrating backends to a shared finalization pipeline (waves 2 and 3).
Parent: #2162
Goal
Add a shared validator that
open_geotiffand every direct backend (read_geotiff_dask,read_geotiff_gpu,read_vrt) call up front, so identical inputs produce identical errors no matter which entry point you use.Today
open_geotiffvalidatesoverview_level,on_gpu_failure,missing_sources,band_nodata,max_cloud_bytes, and file-like source restrictions inline atxrspatial/geotiff/__init__.py:508-584. Direct backends each call_validate_overview_level_argindividually but skip the rest. Direct callers can pass an invalidband_nodatato dask, ormax_cloud_bytesto GPU, and they will not see the erroropen_geotiffwould raise.Scope
Add
_validate_dispatch_kwargs(...)toxrspatial/geotiff/_validation.py. It validates:overview_level(delegates to existing_validate_overview_level_arg)on_gpu_failure(must beautoorstrict; raises when GPU is off)missing_sources(VRT only)band_nodata(VRT only)max_cloud_bytes(incompatible with VRT/GPU/dask per current policy)gpu=Trueandchunks=...Wire it in:
open_geotiffat__init__.py:508-584replaces the inline checks with one call.read_geotiff_dask,read_geotiff_gpu, andread_vrteach gain one call near the top of their bodies, next to the existing_validate_overview_level_argcalls atdask.py:116andgpu.py:204.Keep error messages the same as today's inline checks.
Tests
Add
xrspatial/geotiff/tests/test_dispatch_validation_parity_2162.py. Parametrize overopen_geotiffand the three direct backends. Prove that each invalid input raises the same exception type and a recognizable message regardless of entry point:overview_level(bool,str,float) through all four entry points.max_cloud_byteswith dask, GPU, and VRT.missing_sourceson non-VRT sources.band_nodataon non-VRT sources.on_gpu_failurewhen GPU is disabled.Files
xrspatial/geotiff/_validation.py(add helper)xrspatial/geotiff/__init__.py(replace 508-584 with helper call)xrspatial/geotiff/_backends/dask.py(one new call)xrspatial/geotiff/_backends/gpu.py(one new call)xrspatial/geotiff/_backends/vrt.py(one new call)xrspatial/geotiff/tests/test_dispatch_validation_parity_2162.py(new)Constraints
_ON_GPU_FAILURE_SENTINEL,_MISSING_SOURCES_SENTINEL,_MAX_CLOUD_BYTES_SENTINELin_runtime.py) still mean "caller did not pass this kwarg" and skip the rejection.Out of scope