Describe the bug
read_vrt(path) on a multi-band integer VRT with per-band <NoDataValue> tags only masks band 0's sentinel. Bands 1 and up keep their integer sentinels as literal finite values in the returned float64 array.
The float-VRT path masks per-band sentinels correctly in _vrt._read_data (lines 296-297 and 347-351). For integer rasters the masking happens later, in __init__.py:read_vrt (lines 2795-2809), and only uses vrt.bands[0].nodata, so bands 1+ are left untouched.
Same class of bug as #1598. PR #1602 fixed band=N selection (single-band reads of band N). The band=None multi-band case still mis-masks every non-first band.
To Reproduce
import tempfile, os, numpy as np
from xrspatial.geotiff import read_vrt
from xrspatial.geotiff._writer import write
with tempfile.TemporaryDirectory() as td:
b0 = np.array([[1, 2], [3, 65535]], dtype=np.uint16)
b1 = np.array([[7, 8], [9, 65000]], dtype=np.uint16)
p0, p1 = os.path.join(td, 'b0.tif'), os.path.join(td, 'b1.tif')
write(b0, p0, nodata=65535, compression='none', tiled=False)
write(b1, p1, nodata=65000, compression='none', tiled=False)
vrt = os.path.join(td, 't.vrt')
open(vrt, 'w').write(f'''<VRTDataset rasterXSize="2" rasterYSize="2">
<GeoTransform>0.0, 1.0, 0.0, 0.0, 0.0, -1.0</GeoTransform>
<VRTRasterBand dataType="UInt16" band="1"><NoDataValue>65535</NoDataValue>
<SimpleSource><SourceFilename relativeToVRT="0">{p0}</SourceFilename><SourceBand>1</SourceBand><SrcRect xOff="0" yOff="0" xSize="2" ySize="2"/><DstRect xOff="0" yOff="0" xSize="2" ySize="2"/></SimpleSource></VRTRasterBand>
<VRTRasterBand dataType="UInt16" band="2"><NoDataValue>65000</NoDataValue>
<SimpleSource><SourceFilename relativeToVRT="0">{p1}</SourceFilename><SourceBand>1</SourceBand><SrcRect xOff="0" yOff="0" xSize="2" ySize="2"/><DstRect xOff="0" yOff="0" xSize="2" ySize="2"/></SimpleSource></VRTRasterBand>
</VRTDataset>''')
r = read_vrt(vrt)
print(r.values[1, 1, 0], r.values[1, 1, 1])
# Got: nan 65000.0
# Expected: nan nan
Expected behavior
Every band's per-band <NoDataValue> sentinel should be NaN-masked in the returned float64 array, matching the float-VRT path.
Additional context
Describe the bug
read_vrt(path)on a multi-band integer VRT with per-band<NoDataValue>tags only masks band 0's sentinel. Bands 1 and up keep their integer sentinels as literal finite values in the returned float64 array.The float-VRT path masks per-band sentinels correctly in
_vrt._read_data(lines 296-297 and 347-351). For integer rasters the masking happens later, in__init__.py:read_vrt(lines 2795-2809), and only usesvrt.bands[0].nodata, so bands 1+ are left untouched.Same class of bug as #1598. PR #1602 fixed
band=Nselection (single-band reads of band N). Theband=Nonemulti-band case still mis-masks every non-first band.To Reproduce
Expected behavior
Every band's per-band
<NoDataValue>sentinel should be NaN-masked in the returned float64 array, matching the float-VRT path.Additional context
np.isnanfor nodata detection will treat 65000, -9999, etc. as real data.band=Nsingle-band selection path.attrs['nodata']value is intentionally band 0's sentinel forband=Nonereads (one attr can't encode per-band values); this issue is about the pixel mask, not the attr.__init__.py:read_vrt, whenband is None, loop overvrt.bandsand mask each band's slice against its own<NoDataValue>, gated by the existing_int_nodata_in_rangehelper from PR Fix OverflowError on uint TIFF with negative GDAL_NODATA sentinel (#1581) #1583.