write_vrt(nodata=True) writes <NoDataValue>True</NoDataValue> into the VRT XML, dropping the numeric sentinel the same way to_geotiff did before #1911. bool is a subclass of int, so the typo slips past the isinstance(nodata, (int, float)) guard and the XML emitter just calls str(True). No reader parses "True" as numeric, so the round-trip silently loses the nodata mask.
Reproduce:
import numpy as np, xarray as xr
from xrspatial.geotiff import to_geotiff, write_vrt
arr = xr.DataArray(np.zeros((4,4), dtype=np.uint8), dims=['y','x'])
to_geotiff(arr, '/tmp/src.tif')
write_vrt('/tmp/out.vrt', ['/tmp/src.tif'], nodata=True)
# VRT contains <NoDataValue>True</NoDataValue>
Fix: reject bool / np.bool_ at the write_vrt entry point (and inside the lower-level _vrt.write_vrt as defense in depth), matching the to_geotiff guard added in #1911. Suggested error: TypeError("nodata must be numeric (int or float), got {nodata!r}").
Also: write_geotiff_gpu direct call lacks an explicit top-of-function bool-nodata check. The behaviour is currently correct (build_geo_tags raises), but the rejection is defense-in-depth rather than entry-point parity. A future refactor that moves the build_geo_tags check could regress the GPU writer without anyone noticing.
Found by /sweep-test-coverage pass 15.
write_vrt(nodata=True)writes<NoDataValue>True</NoDataValue>into the VRT XML, dropping the numeric sentinel the same wayto_geotiffdid before #1911.boolis a subclass ofint, so the typo slips past theisinstance(nodata, (int, float))guard and the XML emitter just callsstr(True). No reader parses"True"as numeric, so the round-trip silently loses the nodata mask.Reproduce:
Fix: reject
bool/np.bool_at thewrite_vrtentry point (and inside the lower-level_vrt.write_vrtas defense in depth), matching theto_geotiffguard added in #1911. Suggested error:TypeError("nodata must be numeric (int or float), got {nodata!r}").Also:
write_geotiff_gpudirect call lacks an explicit top-of-function bool-nodata check. The behaviour is currently correct (build_geo_tagsraises), but the rejection is defense-in-depth rather than entry-point parity. A future refactor that moves thebuild_geo_tagscheck could regress the GPU writer without anyone noticing.Found by
/sweep-test-coveragepass 15.