xarray-spatial 0.10.0__tar.gz → 0.10.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/rockout.md +6 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/sweep-accuracy-state.csv +2 -2
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/sweep-api-consistency-state.csv +2 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/sweep-metadata-state.csv +2 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/sweep-performance-state.csv +2 -2
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/sweep-security-state.csv +1 -1
- xarray_spatial-0.10.1/.claude/sweep-style-state.csv +6 -0
- xarray_spatial-0.10.1/.claude/sweep-test-coverage-state.csv +14 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/CHANGELOG.md +43 -1
- xarray_spatial-0.10.1/CLAUDE.md +73 -0
- {xarray_spatial-0.10.0/xarray_spatial.egg-info → xarray_spatial-0.10.1}/PKG-INFO +1 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1/xarray_spatial.egg-info}/PKG-INFO +1 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xarray_spatial.egg-info/SOURCES.txt +19 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/_version.py +3 -3
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/accessor.py +242 -24
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/__init__.py +166 -98
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_attrs.py +161 -143
- xarray_spatial-0.10.1/xrspatial/geotiff/_backends/__init__.py +7 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_backends/_gpu_helpers.py +7 -12
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_backends/dask.py +64 -102
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_backends/gpu.py +124 -147
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_backends/vrt.py +86 -111
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_cog_http.py +65 -71
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_compression.py +4 -4
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_coords.py +58 -64
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_crs.py +8 -13
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_decode.py +33 -37
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_dtypes.py +1 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_encode.py +9 -13
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_errors.py +66 -41
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_geotags.py +55 -70
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_gpu_decode.py +40 -48
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_header.py +1 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_layout.py +88 -11
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_nodata.py +7 -9
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_overview.py +17 -20
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_overview_kernels.py +1 -2
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_reader.py +30 -40
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_runtime.py +11 -17
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_sidecar.py +7 -9
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_sources.py +28 -40
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_validation.py +168 -106
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_vrt.py +116 -125
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_vrt_validation.py +8 -8
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_write_layout.py +16 -16
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_writer.py +65 -70
- xarray_spatial-0.10.1/xrspatial/geotiff/_writers/__init__.py +7 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_writers/eager.py +128 -132
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_writers/gpu.py +59 -65
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_writers/vrt.py +10 -12
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/attrs/test_contract.py +32 -44
- xarray_spatial-0.10.1/xrspatial/geotiff/tests/golden_corpus/__init__.py +11 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/_marks.py +38 -2
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/_oracle.py +37 -39
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/generate.py +6 -7
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_compression.py +11 -11
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_corpus_determinism.py +6 -7
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_dask_gpu.py +7 -7
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_dask_numpy.py +14 -12
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_dtype_variants.py +12 -12
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_eager_numpy.py +20 -19
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_fsspec.py +18 -17
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_gpu.py +5 -5
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_http.py +9 -9
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_layout_endian.py +6 -6
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_manifest.py +7 -7
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_metadata_tags.py +2 -2
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_nodata_sentinels.py +9 -10
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_oracle.py +22 -24
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_overview_cog.py +11 -13
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/test_vrt.py +6 -6
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/gpu/test_codec.py +13 -13
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/gpu/test_kernels_and_kwargs.py +54 -49
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/gpu/test_reader.py +27 -30
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/gpu/test_writer.py +18 -20
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/integration/test_dask_pipeline.py +350 -33
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/integration/test_gpu_pipeline.py +1 -4
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/integration/test_http_sources.py +113 -148
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/integration/test_sidecar.py +32 -43
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/parity/test_backend_matrix.py +16 -18
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/parity/test_finalization.py +23 -30
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/parity/test_pixel_equality.py +43 -5
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/parity/test_reference.py +5 -6
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/parity/test_signature_contract.py +21 -21
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_basic.py +11 -20
- xarray_spatial-0.10.1/xrspatial/geotiff/tests/read/test_bbox_2555.py +220 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_compression.py +8 -11
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_coords.py +57 -63
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_crs.py +19 -25
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_dtypes.py +7 -8
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_endianness.py +5 -6
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_georef.py +83 -117
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_nodata.py +71 -79
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_overview.py +18 -23
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_streaming.py +3 -6
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/test_tiling.py +37 -44
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/release_gates/test_features.py +83 -92
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/release_gates/test_stable_features.py +153 -24
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/test_edge_cases.py +5 -4
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/test_fuzz_hypothesis.py +18 -19
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/test_polish.py +24 -24
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/test_round_trip.py +33 -37
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/test_security.py +169 -27
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_codec_roundtrip.py +18 -21
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_compression.py +1 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_geotags.py +39 -59
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_header.py +9 -11
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_ifd.py +12 -13
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_input_validation.py +37 -40
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_metadata.py +144 -44
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_photometric.py +4 -4
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_predictor.py +20 -26
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_safe_xml.py +2 -2
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/test_signatures.py +81 -77
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/vrt/test_dtype_conversion.py +22 -32
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/vrt/test_metadata.py +64 -85
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/vrt/test_missing_sources.py +5 -11
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/vrt/test_parity.py +4 -10
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/vrt/test_validation.py +28 -36
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/vrt/test_window.py +72 -54
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/test_basic.py +46 -51
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/test_bigtiff.py +8 -14
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/test_cog.py +16 -18
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/test_crs.py +21 -44
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/test_nodata.py +22 -25
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/test_overview.py +21 -23
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/test_streaming.py +9 -11
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/polygonize.py +432 -71
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/rasterize.py +207 -45
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/__init__.py +117 -12
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_crs_utils.py +52 -13
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_datum_grids.py +14 -2
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_grid.py +83 -23
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_vertical.py +35 -10
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/resample.py +198 -72
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_dask_cupy_gaps.py +4 -4
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_hypsometric_integral.py +151 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_polygonize.py +265 -7
- xarray_spatial-0.10.1/xrspatial/tests/test_polygonize_atol_rtol_backend_coverage_2026_05_27.py +405 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_polygonize_issue_2583.py +212 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_coverage_2026_05_17.py +25 -37
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_coverage_2026_05_27.py +429 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_descending_x_2568.py +227 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_nan_int_fill_2504.py +163 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_partial_dims_2569.py +92 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_props_hoist_2506.py +203 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_resolution_exact_2573.py +276 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_resolution_validation_2576.py +168 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_rasterize_signed_step_2566.py +143 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_reproject.py +702 -2
- xarray_spatial-0.10.1/xrspatial/tests/test_reproject_coverage_2026_05_27.py +338 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_reproject_cupy_gate_2564.py +41 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_resample.py +315 -1
- xarray_spatial-0.10.1/xrspatial/tests/test_resample_coverage_2026_05_27.py +432 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_resample_input_validation_2574.py +151 -0
- xarray_spatial-0.10.1/xrspatial/tests/test_resample_signature_annot_2544.py +47 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_validation.py +1 -1
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_zonal.py +658 -54
- xarray_spatial-0.10.1/xrspatial/tests/test_zonal_backend_coverage_2026_05_27.py +835 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/zonal.py +323 -86
- xarray_spatial-0.10.0/.claude/sweep-style-state.csv +0 -2
- xarray_spatial-0.10.0/.claude/sweep-test-coverage-state.csv +0 -7
- xarray_spatial-0.10.0/xrspatial/geotiff/_backends/__init__.py +0 -8
- xarray_spatial-0.10.0/xrspatial/geotiff/_writers/__init__.py +0 -7
- xarray_spatial-0.10.0/xrspatial/geotiff/tests/golden_corpus/__init__.py +0 -12
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/backend-parity.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/bench.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/dask-notebook.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/deep-sweep.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/efficiency-audit.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/new-issues.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/release-major.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/release-minor.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/release-patch.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/review-pr.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/sweep-accuracy.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/sweep-api-consistency.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/sweep-metadata.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/sweep-performance.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/sweep-security.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/sweep-test-coverage.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/user-guide-notebook.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.claude/commands/validate.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.efficiency-audit-baseline.json +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.efficiency-audit-baseline.prev.json +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.gitattributes +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/ISSUE_TEMPLATE/feature-proposal.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/ISSUE_TEMPLATE/new-contributor.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/labeler.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/pull_request_template.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/benchmarks.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/copilot-review.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/labeler.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/pypi-publish.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/test-cog-validator.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/test-geotiff-corpus.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/test.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.github/workflows/welcome-contributor.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.gitignore +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/.readthedocs.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/AI_POLICY.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/CODE_OF_CONDUCT.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/CONTRIBUTING.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/Citation-styles.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/LICENSE.txt +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/MANIFEST.in +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/README.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/RELEASE.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/codecov.yml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/pyproject.toml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/setup.cfg +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/setup.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xarray_spatial.egg-info/dependency_links.txt +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xarray_spatial.egg-info/entry_points.txt +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xarray_spatial.egg-info/not-zip-safe +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xarray_spatial.egg-info/requires.txt +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xarray_spatial.egg-info/top_level.txt +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/__main__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/analytics.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/aspect.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/balanced_allocation.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/bilateral.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/bump.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/classify.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/contour.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/convolution.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/corridor.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/cost_distance.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/curvature.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/dasymetric.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/dataset_support.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/datasets/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/datasets/sentinel-2/blue_band.nc +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/datasets/sentinel-2/green_band.nc +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/datasets/sentinel-2/nir_band.nc +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/datasets/sentinel-2/red_band.nc +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/datasets/sentinel-2/swir1_band.nc +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/datasets/sentinel-2/swir2_band.nc +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/diagnostics.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/diffusion.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/edge_detection.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/emerging_hotspots.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/erosion.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/experimental/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/experimental/min_observable_height.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/fire.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/flood.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/focal.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geodesic.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/_safe_xml.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/_helpers/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/_helpers/markers.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/_helpers/tiff_builders.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/_helpers/tiff_surgery.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/attrs/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/bench_vs_rioxarray.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/conftest.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/README.md +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/cog_internal_overview_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/compression_deflate_predictor2_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/compression_deflate_predictor3_float32.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/compression_jpeg_uint8_ycbcr.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/compression_lerc_float32.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/compression_lzw_predictor2_int16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/compression_none_uint8.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/crs_citation_only.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/crs_epsg_3857.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/crs_wkt_utm10n.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_float32.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_float64.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_int16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_int32.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_int8.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_uint32.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/dtype_uint8.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/extra_tags_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/gdal_metadata_namespaced_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/nodata_int_sentinel_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/nodata_miniswhite_uint8.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/nodata_nan_float32.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/overview_external_ovr_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/overview_external_ovr_uint16.tif.ovr +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/overview_internal_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/planar_separate_uint8_rgb.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/sparse_tiled_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/stripped_be_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/stripped_le_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/tiled_be_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/fixtures/tiled_le_uint16.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/golden_corpus/manifest.yaml +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/gpu/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/integration/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/parity/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/read/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/release_gates/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/test_shutdown_cleanup_2486.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/unit/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/vrt/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/geotiff/tests/write/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/glcm.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/gpu_rtx/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/gpu_rtx/_memory.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/gpu_rtx/cuda_utils.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/gpu_rtx/hillshade.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/gpu_rtx/mesh_utils.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/gpu_rtx/viewshed.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hillshade.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/_boundary_store.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/basin_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/fill_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_accumulation_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_accumulation_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_accumulation_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_direction_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_direction_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_direction_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_length_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_length_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_length_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_path_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_path_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/flow_path_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/hand_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/hand_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/hand_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/sink_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/snap_pour_point_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/stream_link_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/stream_link_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/stream_link_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/stream_order_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/stream_order_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/stream_order_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/conftest.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_basin_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_fill_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_accumulation_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_accumulation_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_accumulation_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_direction_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_direction_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_direction_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_length_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_length_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_length_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_path_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_path_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_flow_path_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_hand_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_hand_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_hand_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_sink_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_snap_pour_point_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_stream_link_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_stream_link_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_stream_link_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_stream_order_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_stream_order_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_stream_order_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_twi_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_validate_cellsize.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_validate_scalar_params.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_validate_secondary_args.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_watershed_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_watershed_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/tests/test_watershed_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/twi_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/watershed_d8.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/watershed_dinf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/hydro/watershed_mfd.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/interpolate/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/interpolate/_idw.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/interpolate/_kriging.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/interpolate/_spline.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/interpolate/_validation.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/kde.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/mahalanobis.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/mcda/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/mcda/combine.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/mcda/constrain.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/mcda/sensitivity.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/mcda/standardize.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/mcda/weights.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/morphology.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/multispectral.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/normalize.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/pathfinding.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/perlin.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/polygon_clip.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/preview.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/proximity.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_interpolate.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_itrf.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_lite_crs.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_merge.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_projections.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_projections_cuda.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/_transform.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/at_bev_AT_GIS_GRID.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/au_icsm_A66_National_13_09_01.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/be_ign_bd72lb72_etrs89lb08.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/ch_swisstopo_CHENyx06_ETRS.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/de_adv_BETA2007.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/es_ign_SPED2ETV2.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/nl_nsgi_rdcorr2018.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/pt_dgt_D73_ETRS89_geo.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/uk_os_OSTN15_NTv2_OSGBtoETRS.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/us_nga_egm96_15.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/us_noaa_alaska.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/us_noaa_conus.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/us_noaa_hawaii.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/us_noaa_nadcon5_nad27_nad83_1986_conus.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/reproject/grids/us_noaa_prvi.tif +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/sieve.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/sky_view_factor.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/slope.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/surface_distance.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/terrain.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/terrain_metrics.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/__init__.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/bench_reproject_vs_rioxarray.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/conftest.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/general_checks.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_accessor.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_analytics.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_aspect.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_balanced_allocation.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_bilateral.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_bump.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_classify.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_contour.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_convolution.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_corridor.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_cost_distance.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_curvature.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_dask_laziness.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_dasymetric.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_dataset_support.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_datasets.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_diagnostics.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_diffusion.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_edge_detection.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_emerging_hotspots.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_erosion.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_fire.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_flood.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_focal.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_fused_overlap.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_geodesic_aspect.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_geodesic_slope.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_glcm.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_glcm_metric_order.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_gpu_rtx_memory.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_gpu_rtx_mesh.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_hillshade.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_interpolation.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_kde.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_lite_crs.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_mahalanobis.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_mcda.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_min_observable_height.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_morphology.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_morphology_derived.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_multi_overlap.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_multispectral.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_normalize.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_northness_eastness.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_optional_shapely.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_pathfinding.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_perlin.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_polygon_clip.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_polygonize_coverage_2026_05_19.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_polygonize_issue_2172.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_preview.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_proximity.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_accuracy.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_all_touched_supercover_2169.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_coverage_2026_05_21.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_gpu_race_2167.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_nan_propagation_2255.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_signature_annot_2250.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rasterize_tile_props_slice_2020.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_rechunk_no_shuffle.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_sieve.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_sieve_gdal_parity.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_sky_view_factor.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_slope.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_surface_distance.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_terrain.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_terrain_metrics.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_utils.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_viewshed.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/tests/test_visibility.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/utils.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/viewshed.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/visibility.py +0 -0
- {xarray_spatial-0.10.0 → xarray_spatial-0.10.1}/xrspatial/worley.py +0 -0
|
@@ -108,6 +108,10 @@ from the main checkout, you have breached this contract.
|
|
|
108
108
|
3. If a new module was created, add a new `.rst` file and include it in the
|
|
109
109
|
appropriate `toctree`.
|
|
110
110
|
|
|
111
|
+
**Do NOT edit `CHANGELOG.md`.** Multiple rockout agents run in parallel and
|
|
112
|
+
every one of them touching `CHANGELOG.md` produces merge conflicts. Leave the
|
|
113
|
+
changelog alone -- it is updated separately at release time.
|
|
114
|
+
|
|
111
115
|
## Step 6 -- Create a User Guide Notebook
|
|
112
116
|
|
|
113
117
|
**Skip this step** if the change is a pure bug fix with no new user-facing API.
|
|
@@ -367,6 +371,8 @@ The rockout run is only complete when:
|
|
|
367
371
|
before every commit.
|
|
368
372
|
- Commit progress after each major step with a clear commit message referencing
|
|
369
373
|
the issue number (e.g. `Add flood velocity function (#42)`).
|
|
374
|
+
- Never modify `CHANGELOG.md` during a rockout run. Parallel agents all editing
|
|
375
|
+
it cause merge conflicts; the changelog is maintained separately at release time.
|
|
370
376
|
- Run `/humanizer` on any text destined for GitHub (issue body, PR description,
|
|
371
377
|
commit messages) to remove AI writing artifacts.
|
|
372
378
|
- If any step is not applicable (e.g. no docs update needed for a typo fix),
|
|
@@ -25,7 +25,7 @@ perlin,2026-04-10T12:00:00Z,,,,Improved Perlin noise implementation correct. Fad
|
|
|
25
25
|
polygon_clip,2026-04-13T12:00:00Z,1197,,,crop=True + all_touched=True drops boundary pixels. Fix in PR #1200.
|
|
26
26
|
polygonize,2026-05-19,2151,HIGH,5,cupy backend used exact-equality vs numba _is_close tolerance for float dtypes; fixed via tolerance-aware value grouping
|
|
27
27
|
proximity,2026-03-30T15:00:00Z,,,,Direction >= boundary fragile but works due to truncated constant. Float32 truncation is design choice. No wrong-results bugs found.
|
|
28
|
-
reproject,2026-05-
|
|
28
|
+
reproject,2026-05-27,2508,HIGH,4;5,"HIGH (#2508, fixed): _interp_geoid_point and _grid_interp_point indexed pixel-edge coords on pixel-center anchored grids; up to 2.1 m geoid error (mean 24 cm, p95 69 cm), ~9 cm cross-check vs pyproj at NYC; same offset in NADCON/OSTN/NTv2 horizontal datum grids. Fixed by subtracting 0.5 from row/col indices; added TestGeoidPixelCenterIndexing with pyproj cross-check. MEDIUM (deferred): _resample_cupy cubic uses cardinal spline (cupyx.scipy.ndimage.map_coordinates order=3) while numpy / _resample_cupy_native use Catmull-Rom; ~0.007 absolute divergence on a smooth quadratic. Fires when CRS pair has no CUDA fast path. MEDIUM (deferred): _reproject_dask(is_cupy=True) returns dask with cupy chunks but numpy meta; _apply_vertical_shift_dask would call _apply_vertical_shift_numpy on cupy blocks and crash on np.asarray(cupy). Untriggered by tests (needs >GPU output). LOW: try_cuda_transform doesn't apply Helmert datum shifts (only WGS84/NAD83 supported) so non-WGS84 datums fall back to pyproj instead of running the GPU fast path; correctness is OK but performance asymmetric vs CPU path."
|
|
29
29
|
resample,2026-04-14T12:00:00Z,1202,,,Interpolation used edge-aligned coords instead of block-centered. Fix in PR #1204.
|
|
30
30
|
sieve,2026-04-13T12:00:00Z,,,,Union-find CCL correct. NaN excluded from labeling. All backends funnel through _sieve_numpy.
|
|
31
31
|
sky_view_factor,2026-05-01,1407,HIGH,4,Horizon angle ignored cell size; fixed by passing cellsize_x/cellsize_y into CPU+GPU kernels and using ground distance
|
|
@@ -33,4 +33,4 @@ terrain,2026-04-10T12:00:00Z,,,,Perlin/Worley/ridged noise correct. Dask chunk b
|
|
|
33
33
|
terrain_metrics,2026-04-30,,LOW,2;5,"LOW: Inf input not rejected, propagates as Inf (consistent across backends but undocumented). LOW: dask+cupy non-nan boundary path double-pads (wasted compute, central output values still correct). No CRIT/HIGH; tests cover NaN propagation, all 4 backends, all 4 boundary modes, dtype acceptance."
|
|
34
34
|
visibility,2026-04-13T12:00:00Z,,,,"Bresenham line, LOS kernel, Fresnel zone all correct. All backends converge to numpy."
|
|
35
35
|
worley,2026-05-01,,MEDIUM,2;5,"MEDIUM: numpy backend uses np.empty_like(data) so integer input dtype produces integer output (distances truncated to 0); cupy/dask paths always produce float32. LOW: freq=inf produces 100000 sentinel (sqrt of initial min_dist=1e10), no validation of freq/seed for non-finite values."
|
|
36
|
-
zonal,2026-03-30T12:00:00Z
|
|
36
|
+
zonal,2026-05-27,2528,MEDIUM,5,"Pass 2 (2026-05-27): MEDIUM fixed -- issue #2528. zonal_stats() on dask-backed inputs silently dropped 'majority' from the requested stats list. The mutable default stats_funcs included 'majority' (added in commit 7c8d5759), but the dask path filtered it out at xrspatial/zonal.py:459 (computed_stats = [s for s in stats_funcs.keys() if s in stats_dict]) because 'majority' is not in _DASK_BLOCK_STATS. Symptom: stats(zones=dask, values=dask) returned 7 columns instead of the 8 the docstring promises; stats(..., stats_funcs=['mean','majority']) returned only ['zone','mean'] with no error or warning. Both dask+numpy and dask+cupy were affected (dask+cupy delegates to dask+numpy). Fix: replaced the mutable list literal default with stats_funcs=None and resolved the default per backend inside the function -- numpy/cupy get the full 8-stat list, dask gets the 7-stat subset (no majority). Explicit majority on dask now raises ValueError with a clear supported-stats message instead of silently filtering. 4 regression tests in test_zonal.py: explicit majority raises on dask, bare default omits majority on dask, bare default keeps majority on numpy, default list is not mutated across calls (covers the historical mutable-default pitfall). All 129 test_zonal.py tests pass (125 pre-existing + 4 new); test_dasymetric.py 61 tests still pass (dasymetric uses zonal.stats internally). Categories: Cat 5 (backend inconsistency: numpy/cupy honoured majority; dask paths silently dropped it). | Pass 1 (2026-03-30T12:00:00Z): historical entry #1090."
|
|
@@ -3,3 +3,5 @@ geotiff,2026-05-18,2106,MEDIUM,3,"Sweep 2026-05-18 (deep-sweep-api-consistency-g
|
|
|
3
3
|
polygonize,2026-05-19,2148,HIGH,1;3,"Sweep 2026-05-19 (deep-sweep-api-consistency-polygonize-2026-05-19). 1 MEDIUM Cat 3 finding fixed in this branch (#2148): polygonize() was the only public vector/raster conversion function without a return type annotation. Sieve/contours/rasterize/clip_polygon all declare one. Fix adds a Union return annotation (numpy tuple | awkward tuple | geopandas GeoDataFrame | spatialpandas GeoDataFrame | geojson dict) using TYPE_CHECKING forward refs for optional deps, and expands the docstring Returns section to enumerate the per-return_type shapes. 1 HIGH Cat 1 finding NOT fixed in this PR -- cross-module rename: polygonize uses `connectivity` (int 4|8) while sieve uses `neighborhood` (int 4|8) for the identical rook/queen pixel-connectivity concept. Industry convention (GDAL, rasterio.features.sieve) favours `connectivity`; the deprecation shim belongs in sieve.py, not polygonize, so this is out of scope for the polygonize-scoped sweep branch. Documented here for the next sieve sweep pass. 1 LOW Cat 1 cross-cutting: polygonize/sieve/clip_polygon use `raster` while contours and many older modules use `agg` for the input DataArray -- library-wide drift, not filed per-module per sweep template. Cat 2 return-shape: polygonize returns tuple/GeoDataFrame/dict by return_type; consistent with contours' tuple/GeoDataFrame dispatch. No Cat 4 (no mutable defaults; connectivity=4 default matches sieve neighborhood=4 default). No Cat 5 (polygonize re-exported in xrspatial/__init__.py; no orphan API; no __all__ but consistent with module convention). cuda-validated: cupy backend accepts identical kwargs, smoke-tested with cupy DataArray on host with CUDA_AVAILABLE."
|
|
4
4
|
rasterize,2026-05-21,2250,MEDIUM,3,"Sweep 2026-05-21 (deep-sweep-api-consistency-rasterize-2026-05-21). 1 MEDIUM Cat 3 finding fixed in this branch (#2250): rasterize() was missing type annotations on geometries, columns, and merge (3 of 16 public params); the other 13 plus the return type were annotated. The docstring already declared the intended types so this was a doc-vs-signature drift. Fix annotates geometries: Any (because the accepted GeoDataFrame / dask_geopandas / iterable union spans optional deps), columns: Optional[Sequence[str]], merge: Union[str, Callable]. Regression test in test_rasterize_signature_annot_2250.py pins every param + the return annotation so a future contributor can't silently drop annotations again. Cross-module drift documented but not filed per template: clip_polygon(nodata) vs rasterize(fill) same concept different name; clip_polygon(name: Optional[str]=None) vs rasterize(name: str='rasterize') default convention; polygonize(column_name) vs rasterize(column) column selector. No Cat 1 in-module rename, no Cat 2 return drift (returns xr.DataArray as documented), no Cat 4 mutable defaults, no Cat 5 orphan API (rasterize is the only public symbol from the module and is re-exported in __init__). cuda-validated: cupy backend accepts identical kwargs, smoke-tested with use_cuda=True on host with CUDA_AVAILABLE."
|
|
5
5
|
reproject,2026-05-10,1570,HIGH,2;5,"Filed cross-module attrs['vertical_crs'] type collision (string vs EPSG int) vs xrspatial.geotiff. Fixed in PR (TBD): reproject now writes EPSG int and preserves friendly token under vertical_datum. MEDIUM kwarg-order drift (transform_precision vs chunk_size) and missing type hints vs geotiff documented but not fixed (cosmetic, kwarg-only)."
|
|
6
|
+
resample,2026-05-27,2544,MEDIUM,3,"Sweep 2026-05-27 (deep-sweep-api-consistency-resample-2026-05-27). 1 MEDIUM Cat 3 finding fixed in this branch (#2544): resample() was the only public symbol in xrspatial.resample without type annotations on any parameter or return; siblings slope/aspect/hillshade/curvature all annotate `agg: xr.DataArray` and `-> xr.DataArray`. Fix adds annotations matching the docstring (agg: xr.DataArray; scale_factor / target_resolution: float | tuple[float, float] | None; method: str; nodata: float | None; name: str) and a `-> xr.DataArray` return type, plus a docstring note that the @supports_dataset decorator accepts Dataset too. Regression test test_resample_signature_annot_2544.py pins every param and the return annotation. Other findings documented but not filed per template: (MEDIUM Cat 1 cross-module) `method` (resample) vs `resampling` (reproject/merge) -- same conceptual parameter, different name, cross-cutting rename, needs design issue. (LOW Cat 1 cross-cutting) first-arg `agg` (resample/slope/aspect/...) vs `raster` (reproject/rasterize/polygonize/sieve) -- library-wide drift, not per-module. (LOW Cat 5) ALL_METHODS imported by tests but not in __all__ (module has no __all__); borderline orphan but used for test parametrisation only. No Cat 2 (returns xr.DataArray as documented). No Cat 4 mutable defaults. resample is exported in xrspatial/__init__.py. cuda-validated: cupy backend smoke-tested with nearest, bilinear, and average on host with CUDA_AVAILABLE=True."
|
|
7
|
+
zonal,2026-05-27,2521,HIGH,1;3;5,"Sweep 2026-05-27 (deep-sweep-api-consistency-zonal-2026-05-27). 1 HIGH Cat 1 finding fixed in this branch (#2521): crop() used zones_ids while stats/crosstab use zone_ids -- pure typo creating a TypeError trap when switching between sibling zonal functions. Fix accepts both, deprecates zones_ids with DeprecationWarning, raises if both supplied, raises if neither. All call sites in tests migrated to canonical zone_ids; legacy zones_ids paths covered by new regression tests. Other findings not fixed in this PR: (HIGH Cat 1+4) nodata vs nodata_values drift across stats/crosstab (nodata_values=None) vs apply/hypsometric_integral (nodata=0) -- different name AND different default, breaks substitutability; cross-function scope, needs a design issue. (MEDIUM Cat 3) crosstab docstring says 'layer: int, default=0' but signature is 'Optional[int] = None'. (MEDIUM Cat 3) hypsometric_integral lacks all type annotations; apply and crop lack return type annotations (siblings have them). (MEDIUM Cat 5) get_full_extent has public-style docstring with 'from xrspatial.zonal import get_full_extent' example but is not in __init__.py -- borderline orphan, but minor utility. (LOW Cat 3) apply() docstring mixes 'values' parameter name with 'agg' prose; example returns np.array shape (not DataArray) while function actually returns a DataArray. Cross-cutting: zones/raster as first-arg name varies (zonal.stats uses zones; zonal.regions/trim use raster). Regions/trim are single-array operations on the zone raster itself, so the rename arguably matches the role. Documented, not filed. cuda-validated: CUDA_AVAILABLE=True on this host."
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module,last_inspected,issue,severity_max,categories_found,notes
|
|
2
2
|
geotiff,2026-05-18,1909,HIGH,4;5,"Re-audit 2026-05-15 (agent-a55b69cec1ef2a092 worktree, branch deep-sweep-metadata-geotiff-2026-05-15). 4-backend (numpy/cupy/dask+numpy/dask+cupy) parity reverified after the #1813 modular refactor: full reads, windowed reads, multi-band, band=N selection, no-georef integer pixel coords, crs/crs_wkt/transform/nodata/x_resolution/y_resolution/resolution_unit/image_description/gdal_metadata all agree across backends. DataArray .name and dims agree (y, x for 2D; y, x, band for 3D). NEW HIGH finding #1909: GDS chunked GPU path (_read_geotiff_gpu_chunked_gds) declared the dask graph dtype as float64 when source had an in-range integer nodata sentinel, matching the CPU dask path's #1597 contract, but the per-chunk _chunk_task did not cast its returned cupy array to declared_dtype -- chunks with no sentinel hit returned the raw uint16/int16 source dtype, producing a silent declared/actual dtype mismatch. Fix mirrors the #1597 + #1624 CPU dask pattern: compute declared_dtype before defining _chunk_task, cast inside the task only when arr.dtype != declared_dtype to skip the no-op astype(copy=True). 6 regression tests added in test_chunked_gpu_declared_dtype_1909.py covering declared vs computed parity, CPU/GPU dask declared-dtype agreement, eager paths preserve source dtype, no-nodata round-trip, explicit dtype= kwarg, and sentinel-hit float64 promotion. Pre-existing test failures in test_predictor2_big_endian_gpu_1517.py and test_size_param_validation_gpu_vrt_1776.py exist on main (read_to_array AttributeError after #1813 refactor, tile_size=4 rejected by stricter _validate_tile_size_arg) and are unrelated to this audit. | Re-audited 2026-05-18 (agent-a59a61958f181c31a worktree, branch deep-sweep-metadata-geotiff-2026-05-18). 4-backend (numpy / cupy / dask+numpy / dask+cupy) metadata parity reverified end-to-end: open_geotiff over a tiled uint16 fixture with crs + transform + GDAL_NODATA sentinel emits identical attrs across all 4 backends (crs=32633, crs_wkt, transform 6-tuple, nodata=5, masked_nodata=True, _xrspatial_geotiff_contract=2, extra_tags, image_description, resolution_unit, x_resolution, y_resolution). Multi-band 3D (y, x, band) with band coord, no-georef int64 pixel coords, windowed reads with transform origin shift, and mask_nodata=False keeping integer dtype all agree across the 4 backends. Write round-trip via to_geotiff (numpy, cupy, dask streaming) re-emits crs / transform / nodata / masked_nodata / contract version with byte-stable transform. Band-first (band, y, x) input correctly remaps to (y, x, band) on disk. _populate_attrs_from_geo_info, _set_nodata_attrs, and _extract_rich_tags centralise attrs emission across all read paths (_init_, _backends/dask, _backends/gpu, _backends/vrt) and write paths (_writers/eager, _writers/gpu, _writers/vrt). _ATTRS_CONTRACT_VERSION=2 is stamped on every path including the chunked GPU GDS and chunked VRT inline-attrs branches. No new CRITICAL/HIGH/MEDIUM/LOW findings."
|
|
3
3
|
polygonize,2026-05-19,2149,MEDIUM,1,"Audited 2026-05-19 (agent-ad1070530d37a4fdf worktree, branch deep-sweep-metadata-polygonize-2026-05-19). Output is vector (column, polygon_points / GeoDataFrame / GeoJSON dict / awkward) so Cat 2/3 do not apply in the DataArray sense. Cat 1 MEDIUM finding #2149: GeoDataFrame output drops raster.attrs['crs'] (and crs_wkt and rioxarray rio.crs); GeoDataFrame.crs is always None even when input is georeferenced. Fix: new _detect_raster_crs helper + crs= kwarg threaded into _to_geopandas; df.set_crs is called when a CRS is detected. spatialpandas has no CRS slot and GeoJSON RFC 7946 is WGS84-only, so propagation lives only on the geopandas path. CRS propagation runs at the public API level so all 4 backends (numpy / cupy / dask+numpy / dask+cupy) propagate consistently -- verified end-to-end with EPSG:4326 attrs across all 4 backends. 8 new tests in TestPolygonizeCRSPropagation cover EPSG string/int, crs_wkt, no CRS, unparseable CRS, attrs-vs-rioxarray preference, rioxarray-only path, and simplify interaction. Cat 2 LOW (not fixed): output coords are pixel-space when input has georeferenced x/y or attrs['transform']; user must pass transform= explicitly. Documented behavior, leave as-is. Cat 4 LOW (not fixed): nodatavals from input attrs is not auto-applied as a mask; documented behavior (explicit mask= kwarg)."
|
|
4
|
-
rasterize,2026-05-
|
|
4
|
+
rasterize,2026-05-27,2504,HIGH,4,"rasterize() drops like.attrs, rebuilds like.coords via linspace (not bit-identical), and never emits _FillValue/nodatavals even when fill is non-NaN. Cat 1 HIGH: chained pipelines like slope(rasterize(gdf, like=elevation)) silently lose crs/res/transform. Cat 2 MEDIUM: linspace round-trip from re-derived bounds breaks xr.align with like. Cat 4 MEDIUM: rasterize(..., fill=-9999, dtype=int32) emits no _FillValue. All 4 backends share the same final return so the fix is one place. Fixed in deep-sweep-metadata-rasterize-2026-05-17-01 (worktree agent-ab7a9aee97c1e4cdf): _extract_grid_from_like now returns coords/attrs; rasterize() reuses like.coords directly when grid matches, copies like.attrs, and emits _FillValue + nodatavals when fill is not NaN. 9 new tests in TestMetadataPropagation cover attrs propagation, bit-identical coord reuse, fill-value emission, isolation from template attrs, and parity across numpy/cupy/dask+numpy/dask+cupy backends. Full test suite (193 passing) clean. | Re-audited 2026-05-21 (agent-a645dc07f847ae8ae worktree, branch deep-sweep-metadata-rasterize-2026-05-21). 4-backend (numpy/cupy/dask+numpy/dask+cupy) metadata parity reverified: all 4 backends route through the same final xr.DataArray constructor in rasterize(); crs / spatial_ref non-dim coord / coords / dims agree across backends. NEW HIGH finding #2251 (Cat 1): when rasterize(geoms, like=template, bounds=..., width=..., height=..., resolution=...) overrides the grid relative to like, the inherited attrs['transform'] and attrs['res'] from like are propagated unchanged so they describe the template's grid, not the actual output. get_dataarray_resolution() prefers attrs['res'] over calc_res from coords, so downstream slope/aspect/proximity see the wrong cellsize. Same class as #1407 sky_view_factor bug. Fix in rasterize(): out_attrs.pop('res') / out_attrs.pop('transform') when like_attrs is present but reuse_like_coords is False (output grid != template grid). Preserves crs / nodata triplet / spatial_ref handling. 9 new tests in TestLikeStaleGridAttrs2251 cover bounds override, width/height override, resolution override, matching width/height preserves attrs, get_dataarray_resolution consistency, and parity across all 4 backends. Full rasterize test suite (224 passed, 2 skipped) clean. | Re-audited 2026-05-27 (agent-ae44e871ba3e6bc50 worktree, branch deep-sweep-metadata-rasterize-2026-05-27). 4-backend (numpy/cupy/dask+numpy/dask+cupy) metadata parity reverified end-to-end with explicit cupy and dask+cupy live runs on the CUDA host. attrs / coords / dims / non-dim coords (spatial_ref) all agree across backends; the existing TestMetadataPropagation and TestLikeStaleGridAttrs2251 suites still pass cleanly. NEW HIGH finding #2504 (Cat 4): rasterize(..., dtype=<int>) with the default fill=np.nan silently coerced NaN to a platform-specific sentinel (INT_MIN on x86, 0 on Apple Silicon, 0 for unsigned dtypes) and emitted no _FillValue / nodata / nodatavals attr to mark unwritten pixels. Downstream consumers (geotiff writer, rioxarray masks) had no sentinel to key off and treated unwritten cells as legitimate burns -- a metadata propagation failure equivalent in shape to #1407. Fix in rasterize() before any host/device allocation: detect NaN fill against an integer final_dtype via np.issubdtype + float(fill) + np.isnan and raise ValueError with a pointer to fill=0/fill=-9999 or a floating dtype. Same guard fires on all 4 backends because it runs before backend dispatch. 18 new tests in test_rasterize_nan_int_fill_2504.py cover every signed/unsigned int width, the like=<int dtype> branch, all 4 backends, explicit-vs-default NaN, numpy-typed NaN, and the unaffected float-dtype path. The previous TestIntegerDtypeNanFill test (which had pinned the silent cast as observed behaviour on 2026-05-17) was rewritten to pin the raise. Full rasterize test suite (476 passed, 2 skipped) clean."
|
|
5
5
|
reproject,2026-05-10,1572;1573,HIGH,1;3;4,geoid_height_raster dropped input attrs and used dims[-2:] for 3D inputs (#1572). reproject/merge ignored nodatavals (rasterio convention) when rioxarray absent (#1573). Fixed in same branch.
|
|
6
|
+
resample,2026-05-27,2542,MEDIUM,2;4;5,"Audited 2026-05-27 (agent-a8135a6a246ecb93c worktree, branch deep-sweep-metadata-resample-2026-05-27). Cat 2 MEDIUM + Cat 4 MEDIUM + Cat 5 MEDIUM all rolled into issue #2542. (a) 2D non-identity path dropped scalar non-dim coords like rioxarrays spatial_ref and squeezed time/band selectors; identity path (scale==1.0, agg.copy()) and 3D path (per-band xr.concat) preserved them, so the bug was path-inconsistent (Cat 5). (b) _resolve_nodata reads attrs[nodata] as a fallback sentinel but the output post-processing only refreshed _FillValue and nodatavals, leaving attrs[nodata]=-9999 alongside data that was now NaN. Fix in resample(): refresh attrs[nodata] to NaN whenever the input had it, and carry across zero-dim non-dim coords on the 2D non-identity path. 7 new tests in TestMetadataPropagation cover nodata-attr refresh, spatial_ref/scalar coord carry, identity-vs-downsample coord parity, and the explicit choice to drop spatially-shaped extra coords. 4-backend (numpy/cupy/dask+numpy/dask+cupy) parity verified for spatial_ref carry; nodata-attr refresh verified on numpy/cupy/dask+numpy (dask+cupy non-NaN nodata masking hits a pre-existing xarray xr.where + cupy.astype quirk unrelated to this audit). Full resample test suite (175 passed) clean."
|
|
@@ -32,7 +32,7 @@ perlin,2026-03-31T18:00:00Z,WILL OOM,memory-bound,0,,
|
|
|
32
32
|
polygon_clip,2026-04-16T12:00:00Z,SAFE,compute-bound,0,1207,Re-audit 2026-04-16: fix verified SAFE. Mask stays lazy via rasterize chunks kwarg; per-chunk peak bounded.
|
|
33
33
|
polygonize,2026-04-16T12:00:00Z,RISKY,compute-bound,0,,Re-audit 2026-04-16 after PR 1190 NaN fix + 1176 simplification. No HIGH. MEDIUM: sequential per-chunk dask.compute loop at L1528 serializes work; _polygonize_cupy full GPU->CPU transfer at L665; per-value bin_mask alloc in _calculate_regions_cupy.
|
|
34
34
|
proximity,2026-03-31T18:00:00Z,WILL OOM,memory-bound,3,1111,Memory guard added to line-sweep path. KDTree path (EUCLIDEAN/MANHATTAN + scipy) already had guards. GREAT_CIRCLE unbounded path already guarded.
|
|
35
|
-
rasterize,2026-05-
|
|
35
|
+
rasterize,2026-05-27,SAFE,graph-bound,0,2506,"Pass 3 (2026-05-27): re-audit identified 1 MEDIUM Cat-3 GPU-transfer finding. _run_cupy (L2065/L2083) and _rasterize_tile_cupy (L2541/L2555) called cupy.asarray(poly_props/poly_global) twice when all_touched=True -- once for the scanline poly_launch tuple and once for the supercover boundary_launch tuple. The two tuples reference the same per-tile props tables. Filed #2506 and fixed by hoisting the upload above the scanline/boundary conditional so both launches share the same device buffer. Microbench: 1000 polys/4 cols 0.051->0.024 ms/iter (2.1x); 10000 polys/8 cols 0.218->0.092 ms/iter (2.4x, saves 720 KB/tile of redundant H2D transfer). 12 new tests in test_rasterize_props_hoist_2506.py (4 AST-structural single-asarray-call assertions + 5 cupy all_touched parity merges + 3 dask+cupy smoke tests). All 470 rasterize tests pass. Dask graph probe: 25600x25600 chunks=1024 yields 2500 tasks for 625 tiles (4 tasks/chunk), unchanged. Noted pre-existing dask+cupy all_touched parity gap on boundary segments crossing tile borders (not addressed by this PR). SAFE/graph-bound verdict holds. | Pass 2 (2026-05-17): re-audit identified MEDIUM Cat-2/Cat-3 graph-bound waste in _run_dask_numpy/_run_dask_cupy -- full line_props/point_props embedded in every delayed tile task (polygon path already filtered via poly_props[pmask]). Filed #2020 and fixed: added _slice_props_for_tile helper to remap geom_idx and slice props per tile (mirrors polygon path). Measured 5000 points x 8 cols / 100 tiles graph shrank from ~30 MB to <0.3 MB (37x); localized lines from ~32 MB to ~1.1 MB. 9 new tests in test_rasterize_tile_props_slice_2020.py (helper unit tests + graph-payload bound + numpy/dask output parity for lines/points/sum-merge). All 184 existing rasterize tests pass; dask+cupy parity verified. Dask graph probe: 2560x2560 chunks=256 yields 400 tasks (4 tasks/chunk constant); 25600x25600 chunks=1024 yields 2500 tasks. cupy 512x512 returns cupy.ndarray with no host round-trip. CUDA _scanline_fill_gpu: 39 regs/thread, 24576 B local_mem/thread (matches static cuda.local.array allocations 2048*8 + 2048*4 bytes). SAFE/graph-bound verdict holds; previous 2026-04-15 false-positive on polygon filtering still valid. | Original (2026-04-15): Tile-by-tile graph construction with per-tile geometry filtering is the correct pattern. Pre-filtering ensures each delayed task gets only its relevant subset."
|
|
36
36
|
reproject,2026-05-10,SAFE,compute-bound,1,1571,"Pass 5 (2026-05-10): 1 HIGH filed and fixed in tree -- issue #1571 + fix _merge_block_adapter same-CRS dask path. _place_same_crs in the dask adapter previously called src_data.compute() on the full source per output chunk (68x amplification measured on 256x256x2 source split into 32x32 output chunks, 8.9M pixels materialized vs 131K total source). Fix: added _place_same_crs_lazy at __init__.py:1716 that slices the source window first then computes only that slice. Verified post-fix: 1.00x ratio, 131K pixels materialized for 131K source. New regression test test_merge_dask_same_crs_bounded_materialization codifies the bound. Other audits clean: CUDA resample kernels use 16x16 blocks (cubic=46 regs, bilinear=36, nearest=22 -- well under the 64K-per-block limit, 0 local mem). _reproject_chunk_numpy/cupy already slice source first before .compute(). Dask graph at 25600x25600 src with 1024 chunks yields 4752 tasks (no per-chunk source dependency). _apply_vertical_shift uses in-place += that may not work on dask arrays -- correctness concern, not perf, defer to accuracy sweep."
|
|
37
37
|
resample,2026-04-15T12:00:00Z,SAFE,compute-bound,0,false-positive,Downgraded. GPU-CPU-GPU round-trip only in aggregate path for non-integer scale factors. Interpolation (nearest/bilinear/cubic) stays on GPU. No GPU kernel exists for irregular per-pixel binning.
|
|
38
38
|
sieve,2026-04-14T12:00:00Z,WILL OOM,memory-bound,0,false-positive,False positive. Memory guards already in place on both dask paths. CCL is inherently global — documented limitation. CuPy CPU fallback is deliberate and documented.
|
|
@@ -44,4 +44,4 @@ terrain_metrics,2026-03-31T18:00:00Z,SAFE,memory-bound,0,,
|
|
|
44
44
|
viewshed,2026-04-05T12:00:00Z,SAFE,memory-bound,0,fixed-in-tree,Tier B memory estimate tightened from 280 to 368 bytes/pixel (accounts for lexsort double-alloc + computed raster). astype copy=False avoids needless float64 copy.
|
|
45
45
|
visibility,2026-04-16T12:00:00Z,SAFE,memory-bound,0,fixed-in-tree,"Re-audit after Numba-ize (PR 1177) confirms SAFE. @ngjit kernels clean, type-stable. MEDIUM: K-observer graph growth in cumulative_viewshed (recommend periodic persist)."
|
|
46
46
|
worley,2026-03-31T18:00:00Z,SAFE,compute-bound,0,,
|
|
47
|
-
zonal,2026-
|
|
47
|
+
zonal,2026-05-27,SAFE,compute-bound,0,2526,"Pass 2 (2026-05-27): re-audit identified 3 MEDIUM findings. (1) zonal_apply 3D dask path: da.stack(layers, axis=2) left output chunks at size 1 along axis 2 -- filed #2526 and fixed by rechunking back to values_data.chunks[2] in _apply_dask_numpy (zonal.py:1691) and _apply_dask_cupy (zonal.py:1731). Confirmed via graph probe: 256x256 raster chunks=(64,64) 3 bands previously yielded chunks[2]=(1,1,1); now (3,). 1 new test (test_apply_dask_3d_axis2_rechunked_2526). 126 existing zonal tests pass. (2) _stats_cupy (zonal.py:588-608): per-zone x per-stat Python loop with cupy.float_(result) forces O(n_zones * n_stats) GPU<->CPU sync points; not fixed in this pass (CUDA-native rewrite needed, larger refactor). (3) _parallel_variance @delayed reduce iterates over all blocks in driver memory; for very large block counts the single-task merge becomes scheduler-bound but is not OOM since per-block arrays are O(n_zones). Not fixed (algorithmic refactor needed). Dask graph probe: stats(7 stats) on 2560x2560 chunks=256 -> 4449 tasks (44/chunk); stats(mean only) -> 823 tasks (8/chunk); crosstab -> 304 (3/chunk); hypsometric_integral -> 300 (3/chunk). All under 50K cap. SAFE/compute-bound verdict holds. | Fixed-in-tree 2026-04-16: rewrote hypsometric_integral dask path. Eliminated double-compute (_unique_finite_zones removed, each block discovers own zones). Replaced np.stack (O(n_blocks * n_zones) scheduler memory) with streaming dict-merge (O(n_zones)). 29 existing tests pass."
|
|
@@ -45,4 +45,4 @@ terrain,2026-05-03,1443,MEDIUM,1;3,,"Re-audit 2026-05-03. MEDIUM Cat 1 + Cat 3 f
|
|
|
45
45
|
viewshed,2026-04-22,1229,HIGH,1,,"HIGH (fixed #1229): _viewshed_cpu allocated ~500 bytes/pixel of working memory (event_list 3*H*W*7*8 bytes + status_values/status_struct/idle + visibility_grid + lexsort temporary) with no guard. A 20000x20000 raster tried to allocate ~200 GB. Fixed by adding peak-memory guard mirroring the _viewshed_dask pattern (_available_memory_bytes() check, raises MemoryError with max_distance= hint). No other HIGH findings: dask path already guarded, _validate_raster is called, distance-sweep uses dtype=float64, _calc_dist_n_grad guards zero distance."
|
|
46
46
|
visibility,2026-04-28,,,,,"Clean. line_of_sight (line 190) and cumulative_viewshed (line 259) call _validate_raster; visibility_frequency delegates. Cat 1: cumulative_viewshed allocates int32 accumulator (4 B/px) but delegates per-observer to viewshed() which has 500 B/px memory guard at viewshed.py:1523-1531; viewshed will fail first on oversize rasters. _bresenham_line (line 35) and _los_kernel (lines 112-143) bounded by transect length (<=W+H+1). Cat 2: int64 throughout, no int32 overflow path. Cat 3: divisions in _los_kernel guarded (D==0 in _fresnel_radius_1 line 87, distance[i]==0 continue line 133, total_dist>0 check line 123); NaN elevation at observer cell would taint los_height but is a correctness not DoS concern. Cat 4: no CUDA kernels. Cat 5: no file I/O. Cat 6: elevations cast to float64 in _extract_transect line 79."
|
|
47
47
|
worley,2026-04-28,,,,,"Clean. worley() calls _validate_raster at line 234 (Cat 6 OK). Cat 1: output allocation matches input agg.shape (np.empty_like at line 80, cupy.empty at line 174); not a width/height generator like bump, so unbounded alloc N/A. Cat 2: cell_x/cell_y use & 255 mask before perm-table indexing, no overflow risk; tid/block_size math bounded by hardware limits. Cat 3: no division by data-derived values; out.shape guards prevent zero-div in coordinate computation; no NaN read from input (pure noise generator). Cat 4 (PRIMARY): both @cuda.jit kernels (_worley_gpu line 99, _worley_gpu_xy line 135) have correct bounds guard 'if i < out.shape[0] and j < out.shape[1]'. cuda.shared.array(512, nb.int32) uses HARDCODED constant 512 (matches 256*2 perm table size), NOT derived from caller input — safe. cuda.syncthreads() called at line 110/147 between strided shared-mem write and reads. Each thread writes distinct sp[k] indices via 'range(tid, 512, block_size)', no race. All threads (incl. out-of-bounds) participate in the load loop before the bounds check, so syncthreads divergence is avoided. Cat 5: no file I/O. Minor: freq/seed not range-validated, _worley_numpy uses np.empty_like(data) which preserves int dtype if input is int (truncation). Functional, not security."
|
|
48
|
-
zonal,2026-
|
|
48
|
+
zonal,2026-05-27,2523,HIGH,1;2;6,,"Re-audit 2026-05-27. HIGH Cat 1 (fixed #2523): _stats_numpy xarray.DataArray return path allocated np.full((n_stats, H*W), float64) with no memory guard; n_stats user-controlled via stats_funcs dict. Fixed by adding _check_stats_dataarray_memory helper that calls _available_memory_bytes() and raises MemoryError when n_stats*H*W*8 > 0.5*avail. Carry-over MEDIUMs still present (no new commits to zonal.py since 2026-04-22): _strides uses np.int32 stride indices (wraps at H*W > ~2.1B elements); hypsometric_integral() skips _validate_raster on zones/values (only validate_arrays for shape parity); _regions_numpy/_regions_cupy have no memory guard but allocations match input shape (bounded by caller). HIGH #1227 remains fixed. No CUDA bounds issues: _apply CUDA kernel has (y < zones.shape[0] and x < zones.shape[1]) guard. No file I/O beyond hardcoded /proc/meminfo read."
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
module,last_inspected,issue,severity_max,categories_found,notes
|
|
2
|
+
geotiff,2026-05-27,2481,HIGH,1;3;4,"Bundled 387 flake8 + ~30 isort fixes since #2285/#2430. F401 x9, F811 x6, F841 x3. E501 x250 (mostly wrapped, 3 file-scope imports keep noqa: E402+E501). E252 x62, blank-line cluster, E128/E127 indents. importorskip imports use # noqa: E402. Cat 5 grep clean."
|
|
3
|
+
polygonize,2026-05-27,2534,HIGH,1;3;4,"F401 line 58 (is_cupy_array unused, not re-exported). E127 lines 83/88 (overload continuation indent in generated_jit). isort: 5-line .utils import block collapses to one line at 100-char limit. Cat 2 clean. Cat 5 grep clean."
|
|
4
|
+
rasterize,2026-05-27,2503,HIGH,1;3,F401 line 15 + F811 line 1193 (paired: local import warnings shadowed unused module-level import); E306 line 1775 (nested @cuda.jit). isort clean. Cat 5 grep clean. Fix in PR #2507.
|
|
5
|
+
resample,2026-05-27,2543,MEDIUM,4,isort drift only: 4 multi-line parenthesised imports collapsed to single/one-per-line under line_length=100 (top-of-file scipy.ndimage + xrspatial.utils; local cupyx imports in _nan_aware_interp_cupy and _interp_block_cupy); two blank-line nits after import math in _run_dask_numpy/_run_dask_cupy. flake8 clean. Cat 5 grep clean. 169 resample tests pass.
|
|
6
|
+
zonal,2026-05-27,2522,HIGH,1;3;4,"F401 not_implemented_func (line 42, only present on import line). E501 line 455 (dd.concat one-liner, 117 chars) wrapped across 3 lines. isort: consolidated xrspatial.utils block (merged has_dask_array, dropped not_implemented_func, alphabetised, trimmed extra blank line). Cat 5 grep clean. 125 zonal tests pass."
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module,last_inspected,issue,severity_max,categories_found,notes
|
|
2
|
+
geotiff,2026-05-18,,HIGH,3;4,"Pass 18 (2026-05-18): added test_parallel_strip_decode_sparse_2100.py closing Cat 3 HIGH geometric-edge / Cat 4 HIGH parameter-coverage gap on the parallel-decode strip paths (#2100/#2104). The strip-decode parallelisation in _read_strips (lines 1942-2014) and _fetch_decode_cog_http_strips (lines 2685-2740) added a collect-decode-place pipeline whose job-collection loop filters sparse strips (byte_counts[idx] == 0) before they reach the ThreadPoolExecutor. The existing test_parallel_strip_decode_2100.py covers parallel/serial parity, the pool-engaged branch, single-strip serial short-circuit, windowed strip reads, and planar=2 multi-band, but every fixture is fully populated. The 128x128 sparse fixture in test_sparse_cog.py is below the 64K-pixel parallel gate, so the sparse-strip filter inside the parallel branch is wholly untested. A regression that lost the byte_counts==0 guard would silently ship: the decoder would receive an empty data[offsets[idx]:offsets[idx]+0] slice and either raise 'Decompressed tile/strip size mismatch' or return corrupt pixels. 7 new tests, all passing: local-strip full-image parallel/serial parity with sparse strips, parallel-pool-engaged on multi-strip sparse images, windowed reads across the sparse boundary, all-sparse degenerate (zero filled rows -> empty job list -> short-circuit gate), planar=2 sparse parity (dedicated 'planar == 2 and samples > 1' branch with its own byte_counts==0 guard at lines 1949-1962), HTTP windowed read on a non-sparse strict subset (parallel decode of fetched strips), and HTTP windowed read across the sparse boundary (parallel decode of the fetched strips with placement matching the local read). Mutation against the strip-job collection sparse guard (delete the byte_counts == 0 continue) flips 5 of 5 local tests red with 'Decompressed tile/strip size mismatch: expected ... got 0'; mutation against the HTTP path sparse guard at line 2646 flips the boundary HTTP test red. Confirmed clean restore via md5sum. Source untouched. Cat 3 HIGH + Cat 4 HIGH (geometric edge case + parameter coverage on the sparse-strip code path under parallel decode).
|
|
3
|
+
|
|
4
|
+
Pass 17 (2026-05-18): added test_mask_nodata_gpu_vrt_2052.py closing Cat 1 HIGH backend-coverage gap on the mask_nodata= opt-out kwarg (#2052). The kwarg was added in #2052 and wired through the four public readers (open_geotiff, read_geotiff_gpu, read_geotiff_dask, read_vrt), but test_mask_nodata_kwarg_2052.py only exercised the eager-numpy and dask+numpy branches. The pure-GPU mask gating at _backends/gpu.py:709, the dask+GPU dispatcher forwarding at _backends/gpu.py:991, the eager VRT mask gating at _backends/vrt.py:320, and the chunked VRT graph builder at _backends/vrt.py:408/588 had zero direct coverage. 19 new tests, all passing on GPU host: GPU eager + dask+GPU mask_nodata=False preserves uint16, GPU defaults still promote to float64, dispatcher thread-through for open_geotiff(gpu=True, mask_nodata=False) and open_geotiff(gpu=True, chunks=N, mask_nodata=False), VRT eager and chunked branches mirror, cross-backend parity (eager vs dask, eager vs GPU, eager vs dask+GPU, eager vs VRT) bit-exact under mask_nodata=False, direct read_geotiff_dask entry-point coverage. Fixture uses tiled+deflate compression so the pure nvCOMP decode path is exercised, not the CPU-fallback piggyback path. Mutation against gpu.py:709 (force mask_nodata=True) flipped 4 GPU tests red; mutation against vrt.py eager mask gate flipped 4 VRT tests red. Cat 1 HIGH (backend coverage on mask_nodata=False for GPU, dask+GPU, VRT eager, VRT chunked). Pass 16 (2026-05-15): added test_max_cloud_bytes_dispatcher_silent_drop_2026_05_15.py closing Cat 4 HIGH parameter-coverage gap on the open_geotiff dispatcher's max_cloud_bytes kwarg. The kwarg was added in #1928 (eager fsspec budget) and re-ordered into the canonical reader signature by #1957, but open_geotiff only forwards it to _read_to_array on the eager non-VRT branch (__init__.py:431). The GPU branch at line 410, the dask branch at line 422, and the VRT branch at line 362 never reference the kwarg, so open_geotiff(p, max_cloud_bytes=8, gpu=True) / open_geotiff(p, max_cloud_bytes=8, chunks=N) / open_geotiff(vrt, max_cloud_bytes=8) all silently drop the budget. Same class of dispatcher-silently-drops-backend-kwarg bug fixed by #1561 / #1605 / #1685 / #1810 for other kwargs; the two sibling kwargs on_gpu_failure (line 339) and missing_sources (line 355) already raise ValueError when used on a path where they do not apply. 11 tests: 4 xfail(strict=True) pinning the fix surface (gpu, dask, vrt, dask+gpu), 3 passing pins on the current silent-drop behaviour so the fix is visible as a diff, 4 positive pins that the eager local + file-like paths accept the kwarg (docstring no-op contract). Filed issue #1974 for the dispatcher fix (sweep is test-only). Cat 4 HIGH (silent backend-kwarg drop). Pass 15 (2026-05-15): added test_write_vrt_bool_nodata_1921.py closing Cat 1 HIGH backend-parity gap on bool nodata rejection. Issue #1911 added the isinstance(nodata, (bool, np.bool_)) -> TypeError guard at to_geotiff and build_geo_tags, but the sibling writers were left unchecked: write_vrt(nodata=True) silently emits <NoDataValue>True</NoDataValue> into the VRT XML (str(True) drops the sentinel because no reader parses 'True' as numeric); write_geotiff_gpu direct call relies on the build_geo_tags defense-in-depth rather than an entry-point check, so a future refactor moving that guard would regress the GPU writer with no test coverage. 17 new tests: 4 xfail (strict=True) pinning the write_vrt fix surface (issue #1921), 1 passing pin on the current buggy str(True) emission so the fix is visible as a diff, 6 numeric/None happy-path tests on write_vrt, 4 GPU writer direct-call bool-reject tests (4 dtypes x 1 call), 1 to_geotiff(gpu=True) dispatcher thread-through. Filed issue #1921 for the write_vrt fix (sweep is test-only). Cat 1 HIGH (write_vrt backend parity bug) + Cat 1 MEDIUM (write_geotiff_gpu defense-in-depth pin). Pass 14 (2026-05-15): added test_dask_streaming_write_degenerate_2026_05_15.py closing Cat 3 HIGH and Cat 2 HIGH/MEDIUM gaps on the dask streaming write path (to_geotiff with dask-backed DataArray, #1084). test_streaming_write.py covered 100x100 with a NaN block plus a 2x2 small raster but had nothing 1-pixel-row, 1-pixel-column, all-NaN, all-Inf, or +/-Inf-mixed. The streaming tile-row segmenter (#1485) on a 1-pixel-tall raster and the streaming nodata-mask coercion on an all-NaN chunk were reachable only with a dask input and had no direct coverage; a regression on either would not surface from the eager numpy path or the write_geotiff_gpu path (pass 5 covered the GPU writer's degenerate shapes). 16 new tests, all passing: 1x1 chunk-matches-shape + nodata-attr round-trip + uint16, 1xN single chunk + chunks-split-columns + wide-segmented-by-buffer (#1485 streaming_buffer_bytes=1 forces the segmenter), Nx1 single chunk + chunks-split-rows, all-NaN with finite sentinel + all-NaN without sentinel, mixed NaN/+Inf/-Inf preserving Inf bit-exact + sentinel masking NaN only, all-+Inf and all--Inf, predictor=3 (float predictor) round-trip on float32 + float64 plus int-dtype ValueError. predictor=3 streaming coverage extends the small-chunk and int-rejection geometry around test_predictor_fp_write_1313.test_predictor3_streaming_dask (which already covers a 128x192 predictor=3 dask streaming write with a Predictor-tag assertion). Cat 3 HIGH (1x1/1xN/Nx1) + Cat 2 HIGH (all-NaN with sentinel) + Cat 2 MEDIUM (mixed-Inf, all-Inf) + Cat 4 MEDIUM (predictor=3 streaming). Pass 13 (2026-05-13): added test_size_param_validation_gpu_vrt_1776.py closing Cat 4 HIGH parameter-coverage gap on size-arg validation. Issue #1752 added tile_size validation to to_geotiff and chunks validation to read_geotiff_dask, but the matching kwargs on three sibling entry points were left unchecked: write_geotiff_gpu(tile_size=) raised ZeroDivisionError for 0, struct.error for -1, TypeError for 256.0; read_geotiff_gpu(chunks=) and read_vrt(chunks=) raised ZeroDivisionError for 0 and silently accepted negative values. Factored two shared validators (_validate_tile_size_arg, _validate_chunks_arg) and called them up front from each entry point. 34 new tests, all passing on GPU host: tile_size matrix on write_geotiff_gpu (0/-1/256.0/True/False/positive/np.int64), chunks matrix on read_geotiff_gpu and read_vrt (0/-1/(0,N)/(N,-1)/wrong-length/bool/non-int/(N,float)/positive/np.int64), dispatcher thread-through tests (open_geotiff(gpu=True, chunks=0), to_geotiff(gpu=True, tile_size=0)). Pre-existing 13 #1752 tests still pass after refactor. Filed issue #1776. Pass 12 (2026-05-12): added test_gpu_writer_overview_mode_and_compression_level_1740.py closing Cat 4 HIGH and Cat 4 MEDIUM parameter-coverage gaps. (1) write_geotiff_gpu(overview_resampling='mode') and the dedicated _block_reduce_2d_gpu mode-fallback branch (_gpu_decode.py:3051-3056) had zero direct tests; six of the seven overview_resampling modes were covered (mean/nearest by test_features, min/max/median by pass 6, cubic by test_signature_parity_1631) but mode was the odd one out -- a regression dropping the mode dispatch from _block_reduce_2d_gpu would fall through to the mean reshape branch and emit wrong overview pixels for integer rasters. (2) write_geotiff_gpu(compression_level=) documented as accepted-but-ignored had no test; the CPU writer rejects out-of-range levels with ValueError, the GPU writer is documented not to -- a regression wiring the GPU writer up to the CPU range validator would silently break every to_geotiff(gpu=True, compression_level=X) caller for in-range levels and noisily for out-of-range. 19 tests, all passing on GPU host: _block_reduce_2d_gpu(method='mode') CPU-parity on 4x4 deterministic + random 8x8 + dtype-preserved across u8/u16/i16/i32, write_geotiff_gpu(cog=True, overview_resampling='mode') end-to-end round trip, to_geotiff(gpu=True, ..., overview_resampling='mode') dispatcher thread-through, GPU-vs-CPU pixel parity on 8x8 input, write_geotiff_gpu(compression_level=) in-range matrix on zstd/deflate, out-of-range matrix (zstd=999/-5, deflate=50/0) accepted without raising + round-trip preserved, to_geotiff(gpu=True, compression_level=999) dispatcher thread-through, companion CPU rejects-OOR pin to lock the asymmetry. Mutation against the mode branch (drop the 'if method == mode' block in _block_reduce_2d_gpu) flipped 9 mode tests red. Filed issue #1740. Pass 11 (2026-05-12): added test_gpu_writer_cpu_fallback_codecs_2026_05_12.py closing a Cat 4 HIGH parameter-coverage gap on write_geotiff_gpu compression= modes for the CPU-fallback codecs (lzw, packbits, lz4, lerc, jpeg2000/j2k). Pass 7 (test_gpu_writer_compression_modes_2026_05_11) covered only none/deflate/zstd/jpeg; the remaining five codecs route through dedicated branches in gpu_compress_tiles (_gpu_decode.py:2974-3019) with CPU fallbacks (lerc_compress, jpeg2000_compress, cpu_compress) that had zero direct tests via write_geotiff_gpu. A regression in routing/tag-wiring/fallback dispatch would ship silently because the internal reader uses the same compression-tag table. 17 tests, all passing on GPU host: lzw/packbits/lz4 round-trip + compression-tag pin on uint16, lerc lossless float32 + uint16 round-trip + tag pin, jpeg2000 uint8 single-band + RGB multi-band lossless round-trip + j2k-alias parity + tag pin, GPU-vs-CPU writer pixel parity for lzw/packbits, to_geotiff(gpu=True, compression=lzw/packbits) dispatcher thread-through. Mutation against compression dispatch (swap lzw bytes to zstd; swap lerc bytes to deflate) flipped round-trip tests red. Filed issue #1706. Pass 10 (2026-05-12): added test_kwarg_behaviour_2026_05_12_v2.py closing two Cat 4 HIGH parameter-coverage gaps. (1) write_geotiff_gpu(predictor=True/2/3) had zero direct tests; the GPU writer threads predictor= through normalize_predictor and gpu_compress_tiles into five CUDA encode kernels (_predictor_encode_kernel_u8/u16/u32/u64 for predictor=2, _fp_predictor_encode_kernel for predictor=3) and a regression dropping the encode-kernel calls would ship corrupt files. (2) read_vrt(window=) had no behaviour tests (only a signature pin in test_signature_annotations_1654); the kwarg is documented and _vrt.read_vrt implements full windowed-read semantics (clip, multi-source overlap, src/dst scaling, GeoTransform origin shift on coords + attrs['transform']). 23 tests, all passing on GPU host: predictor=True/2 round-trips on u8/u16/i32 + 3-band RGB samples_per_pixel stride; predictor=3 lossless round-trip on f32 and f64; predictor=3 int-dtype ValueError (CPU/GPU parity); CPU/GPU pixel-exact parity for pred=2 u16 and pred=3 f32; read_vrt(window=) subregion + full + clamp-overflow + clamp-negative + 2x1 mosaic seam straddle + offset past seam + transform-attr origin shift + y/x coords half-pixel shift + window+band + window+chunks (dask) + window+gpu (cupy) + window+gpu+chunks (dask+cupy). Mutation against the encode dispatch flipped 7 predictor tests red. Filed issue #1690. Pass 9 (2026-05-12): added test_kwarg_behaviour_2026_05_12.py closing three Cat 4 MEDIUM parameter-coverage gaps plus one Cat 4 LOW error path. write_vrt documented kwargs (relative/crs_wkt/nodata) had a smoke-test pinning that the kwargs are accepted but no test verified the override *effect* -- a regression dropping the override branch and silently using the default-from-first-source would ship undetected. read_geotiff_gpu(dtype=) cast had zero direct tests; the eager path has TestDtypeEager and dask has TestDtypeDask but the GPU branch had no equivalent. write_geotiff_gpu(bigtiff=) threads through to _assemble_tiff(force_bigtiff=) but no test asserted the on-disk header byte switches; the CPU writer had it via test_features::test_force_bigtiff_via_public_api. write_vrt(source_files=[]) ValueError was uncovered. 26 tests, all passing on GPU host: write_vrt relative=True/False XML attribute + path inspection + parse-back round-trip, write_vrt crs_wkt= override distinct-from-default XML check, write_vrt nodata= override + default-from-source coverage, write_vrt([]) ValueError + no-file side effect, read_geotiff_gpu dtype= matrix (float64->float32, float64->float16, uint16->int32, uint16->uint8, float-to-int raise, dtype=None preserves native), open_geotiff(gpu=True, dtype=) dispatcher, read_geotiff_gpu(chunks=, dtype=) dask+GPU branch, write_geotiff_gpu bigtiff=True/False/None header verification, to_geotiff(gpu=True, bigtiff=True) dispatcher thread-through. Pass 8 (2026-05-11): added test_lz4_compression_level_2026_05_11.py closing Cat 4 MEDIUM parameter-coverage gap on compression='lz4' + compression_level=. _LEVEL_RANGES advertises lz4: (0, 16) but only deflate (1, 9) and zstd (1, 22) had direct level boundary + round-trip + reject tests. The range check is the gatekeeper -- lz4_compress silently accepts any int level -- so a regression dropping 'lz4' from _LEVEL_RANGES would ship undetected. 18 tests, all passing: round-trip at levels 0/1/9/16 (lossless), default-level no-arg path, higher-level-not-larger smoke check on compressible input, out-of-range reject at -1/-10/17/100 on eager path, valid-range message format pin (lz4 valid: 0-16), dask streaming round-trip at 0/1/8/16, dask streaming out-of-range reject at -1/17/50 (separate _LEVEL_RANGES call site). Pass 7 (2026-05-11): added test_gpu_writer_compression_modes_2026_05_11.py closing Cat 4 HIGH gap on write_geotiff_gpu compression= modes. The writer documents zstd (default, fastest GPU), deflate, jpeg, and none, but only deflate + none had round-trip tests; the default zstd and the jpeg (nvJPEG/Pillow) paths shipped without targeted coverage. 11 new tests, all passing on GPU host: zstd round-trip + default-codec pinning, jpeg round-trip on 3-band RGB uint8 + 1-band greyscale, TIFF compression-tag header check across none/deflate/zstd/jpeg, plain deflate + none round-trips outside the COG/sentinel paths, and a cross-codec lossless parity check (zstd/deflate/none agree pixel-exact). nvJPEG path was exercised live, not just the Pillow fallback. Pass 6 (2026-05-11): added test_overview_resampling_min_max_median_2026_05_11.py covering Cat 4 HIGH parameter-coverage gap on overview_resampling=min/max/median. CPU end-to-end paths were already covered by test_cog_overview_nodata_1613::test_cpu_cog_overview_aggregations_ignore_sentinel; the GPU end-to-end paths and the direct CPU+GPU block-reducer branches had no targeted tests, so a regression on those code paths would ship undetected. 26 tests, all passing on GPU host: block-reducer unit tests (finite + partial-NaN), end-to-end COG writes for both to_geotiff and write_geotiff_gpu, CPU/GPU parity for to_geotiff(gpu=True), CPU nodata-sentinel regression check, and ValueError error-path tests for unknown method names on both backends. Pass 5 (2026-05-11): added test_degenerate_shapes_backends_2026_05_11.py covering Cat 3 HIGH geometric gaps (1x1 / 1xN / Nx1 reads on dask+numpy, GPU, dask+cupy backends; 1x1 / 1xN / Nx1 writes through write_geotiff_gpu) and Cat 2 MEDIUM NaN/Inf gaps (all-NaN read on GPU + dask+cupy, Inf / -Inf reads on all non-eager backends, NaN sentinel mask on dask read path including sentinel block split across chunk boundary). 23 tests, all passing on GPU host. Prior passes still hold: pass 4 (r4) closed read_geotiff_gpu/dask name= + max_pixels= kwargs (Cat 4), pass 3 (r3) closed read_vrt GPU/dask+GPU backend dispatch (Cat 1) and dtype/name kwargs (Cat 4)."
|
|
5
|
+
polygonize,2026-05-27,2537,MEDIUM,4,"Pass 2 (2026-05-27): added test_polygonize_atol_rtol_backend_coverage_2026_05_27.py with 15 tests, all passing on a CUDA host. Closes Cat 4 MEDIUM parameter-coverage gap on atol/rtol forwarding through the cupy and dask+cupy backends. atol/rtol were exposed by #2173 / #2194 and thread through _polygonize_cupy (polygonize.py:808) and _polygonize_dask (polygonize.py:1719); the dask path further plumbs them into dask.delayed(_polygonize_chunk)(...) at lines 1748-1754 and into _bucket_key_for_value for cross-chunk merge bucketing at lines 1757-1758. Pre-existing tests covered non-default atol/rtol only on numpy and dask+numpy. The cupy and dask+cupy dispatchers were untested -- a regression dropping the kwargs there would silently change the float polygon count and would not be caught. Same dispatcher-silently-drops-kwarg pattern fixed by #1561 / #1605 / #1685 / #1810 / #1974 on adjacent GeoTIFF surfaces. 15 tests: cupy strict-equality + default-tolerance pin on _REPRO_2173, dask+cupy strict-equality single-chunk + multi-chunk (engages cross-chunk merge bucket) + default-tolerance multi-chunk pin, cupy intermediate-atol small/large pair, dask+cupy intermediate-atol single/multi-chunk small + single-chunk large, cupy integer atol-ignored matrix, dask+cupy integer atol-ignored single-chunk + multi-chunk, cupy rtol-only large/small matrix. Mutation against _polygonize_cupy float branch (drop atol/rtol kwargs in the _polygonize_numpy forward call at polygonize.py:823-825) flips 3 of 5 cupy tests red; mutation against dask.delayed(_polygonize_chunk)(...) at polygonize.py:1748-1754 (drop atol, rtol args) flips 2 of 6 dask+cupy tests red. Confirmed clean restore via md5sum. Source untouched. Filed issue #2537 (test-only). Cat 4 MEDIUM (parameter coverage on cupy + dask+cupy atol/rtol forwarding). Pass 1 (2026-05-19): added test_polygonize_coverage_2026_05_19.py with 58 tests, all passing on a CUDA host. Closes Cat 3 HIGH 1x1 / Nx1 single-column geometric gaps (Nx1 exercises the nx==1 padding path at polygonize.py:565 and the cupy nx==1 numpy-fallback at polygonize.py:671), Cat 3 MEDIUM 1xN single-row and all-equal-value rasters on all four backends. Closes Cat 2 HIGH NaN parity for cupy + dask+cupy (numpy/dask were already covered by test_polygonize_nan_pixels_excluded*), Cat 2 MEDIUM all-NaN raster on all four backends, Cat 2 HIGH +/-Inf pins on all four backends. Filed source-bug issue #2155: numpy/dask/dask+cupy backends silently absorb Inf cells into adjacent finite polygons because _is_close reduces abs(inf-inf) to nan; cupy backend handles Inf correctly. Pins lock the asymmetric behaviour so the fix is visible. Closes Cat 1 MEDIUM simplify_tolerance + mask= parity gaps on dask+cupy backend (numpy/cupy/dask were already covered). Closes Cat 4 MEDIUM column_name non-default value across geopandas/spatialpandas/geojson return types and Cat 4 MEDIUM validation error paths (bad connectivity, bad transform length, mask shape mismatch, mask underlying-type mismatch). Cat 5 N/A: polygonize returns lists/dataframes, not a DataArray with attrs to propagate."
|
|
6
|
+
rasterize,2026-05-27,,HIGH,1;2;4,"Pass 3 (2026-05-27): added test_rasterize_coverage_2026_05_27.py with 23 tests, all passing on a CUDA host. Closes Cat 1 HIGH eager-cupy merge-mode parity gap: pass-1 only pinned merge='last' on a single non-overlapping polygon via TestCuPy.test_cupy_matches_numpy, and the Inf-burn tests in pass-2 only partially exercised sum/min/max on eager cupy; the parametrised six-mode parity test (last/first/max/min/sum/count) that TestDaskNumpy and TestDaskCupy carry had no eager-cupy twin, so a routing regression that swapped any of the six GPU atomic kernels in _ensure_gpu_kernels (rasterize.py:1308-1556) would slip past the dask+cupy tiled-finalize tests. Pin a three-way overlapping polygon scene plus a three-way overlapping point scene across all six modes on the eager cupy backend, with sanity checks (first!=last, min<max) so the fixture is non-degenerate. Closes Cat 1 MEDIUM eager-cupy empty-geometry-list gap: numpy + dask+numpy + dask+cupy had empty-list coverage but the eager _run_cupy zero-geometry path (zero-sized cupy bbox/edge/segment buffers) did not -- pin that use_cuda=True with [] still returns a cupy.ndarray (not a numpy short-circuit) under both an explicit fill and the default NaN fill. Closes Cat 2 MEDIUM all-equal-value count gap: four overlapping rectangles all burning 1.0 under merge='count' must still count overlaps as >1; a future GPU atomic optimisation that deduped identical-value writes would silently break density rasters. Closes Cat 4 MEDIUM name= kwarg thread-through on dask+numpy / eager cupy / dask+cupy (the eager numpy path was the only one with name= coverage at TestBasic.test_output_name). Source untouched. Pass 2 (2026-05-21): added test_rasterize_coverage_2026_05_21.py with 58 tests, all passing on a CUDA host. Closes Cat 2 HIGH +/-Inf and NaN burn-value gaps that pass-1 left untouched: pin +Inf / -Inf / Inf+(-Inf)/NaN polygon, point, and line burn behaviour across numpy / cupy / dask+numpy / dask+cupy, plus Inf+finite under sum stays Inf, Inf+(-Inf) under sum collapses to NaN, min(Inf, 1.0) and max(-Inf, 1.0) pick the finite value, and Inf-as-bound is rejected with the same ValueError as NaN-as-bound (pass-1 only tested the NaN-bound rejection). Closes Cat 1 MEDIUM nested GeometryCollection on all four backends: a GC inside a GC has no direct test today even though rasterize.py:1995 documents recursive unpacking, and the deeply-nested-3-levels eager test pins the recursion depth limit isn't 1 or 2. Closes Cat 1 MEDIUM columns= (multi-column) parity on cupy and dask+cupy (TestMultiColumn covered numpy/dask+numpy only); pin three columns of props on GPU so the (N, P) loop survives the kernel boundary. Closes Cat 3 LOW rectangular-pixel parity with resolution=(rx, ry) across backends. Filed source-bug issue #2255: GPU max/min merge silently suppresses NaN burn values -- CPU returns NaN (1.0 > NaN is False, keeps NaN); GPU returns 1.0 because the kernel inits the output buffer to -inf for max (or +inf for min) and atomicMax/Min is NaN-suppressing under IEEE device semantics. Pinned both the CPU NaN-propagating behaviour and the GPU NaN-suppressing behaviour as paired tests (test_nan_burn_overlaps_max_cpu_propagates vs test_nan_burn_overlaps_max_gpu_suppresses_nan, plus test_nan_burn_single_geom_max_gpu_returns_neg_inf for the single-write-on-GPU-returns-buffer-init case) so the divergence is visible in CI until the GPU kernels are aligned. Source untouched. Pass 1 (2026-05-17): added test_rasterize_coverage_2026_05_17.py with 34 tests, all passing on a CUDA host. Closes four documented public-API gaps left after the pass-0 audit. (1) Cat 3 HIGH 1x1 single-pixel raster -- test_rasterize.py covers 1xN strips and Nx1 strips but never width=1 AND height=1, so the polygon scanline / line Bresenham / point burn kernels all ship without the single-cell degenerate case; the new TestSinglePixelRaster class pins polygon/point/line on eager numpy plus polygon parity across cupy / dask+numpy / dask+cupy. (2) Cat 4 HIGH like= template-raster parameter is documented at rasterize.py:2038 and implemented by _extract_grid_from_like (line 1930) but no test exercises it; TestLikeParameter pins dtype/bounds/coords inheritance, the three override branches (dtype, bounds, width/height), the three validation branches (not-DataArray, 3D, wrong dim names) and like= on all four backends. Mutation against the like-dtype branch (rasterize.py:2183-2184) flipped the inheritance test red. (3) Cat 4 HIGH resolution= happy path -- only the oversize-rejection error path was tested (line 304); TestResolutionParameter pins the scalar branch, the tuple branch, the ceil-and-clamp-to-1 semantics, and resolution= on all four backends. (4) Cat 4 HIGH non-empty GeometryCollection unpacking is documented at rasterize.py:1995 and implemented by _classify_geometries_loop (line 228) but only the empty-GC case was tested (line 269); TestGeometryCollection pins polygon+point and polygon+line+point collections on eager numpy plus parity across cupy / dask+numpy / dask+cupy so the loop classifier's polygon/line/point sub-bucketing has direct coverage. Cat 1 MEDIUM gap closed: eager cupy all_touched=True parity vs eager numpy (TestEagerCupyAllTouched) -- the existing test only covered dask+cupy all_touched, leaving the direct GPU all_touched kernel untested. Cat 2 MEDIUM gap closed: int32 dtype with default NaN fill silently casts to the int32-min sentinel (TestIntegerDtypeNanFill) -- pin the cast so any future ValueError-raises switch is visible as a code-review diff. Pre-existing 143 passing + 2 skipped tests in test_rasterize.py untouched."
|
|
7
|
+
reproject,2026-05-10,,HIGH,1;4;5,"Added 39 tests: LiteCRS direct coverage, itrf_transform behaviour/roundtrip/array, itrf_frames, geoid_height numerical correctness + raster happy-path, vertical helpers (ellipsoidal<->orthometric/depth), reproject() lat/lon and latitude/longitude dim propagation. Note: _merge_arrays_cupy is imported but unused (no cupy merge dispatch in merge()); flagged as feature gap not test gap."
|
|
8
|
+
Pass 17 (2026-05-18): added test_mask_nodata_gpu_vrt_2052.py closing Cat 1 HIGH backend-coverage gap on the mask_nodata= opt-out kwarg (#2052). The kwarg was added in #2052 and wired through the four public readers (open_geotiff, read_geotiff_gpu, read_geotiff_dask, read_vrt), but test_mask_nodata_kwarg_2052.py only exercised the eager-numpy and dask+numpy branches. The pure-GPU mask gating at _backends/gpu.py:709, the dask+GPU dispatcher forwarding at _backends/gpu.py:991, the eager VRT mask gating at _backends/vrt.py:320, and the chunked VRT graph builder at _backends/vrt.py:408/588 had zero direct coverage. 19 new tests, all passing on GPU host: GPU eager + dask+GPU mask_nodata=False preserves uint16, GPU defaults still promote to float64, dispatcher thread-through for open_geotiff(gpu=True, mask_nodata=False) and open_geotiff(gpu=True, chunks=N, mask_nodata=False), VRT eager and chunked branches mirror, cross-backend parity (eager vs dask, eager vs GPU, eager vs dask+GPU, eager vs VRT) bit-exact under mask_nodata=False, direct read_geotiff_dask entry-point coverage. Fixture uses tiled+deflate compression so the pure nvCOMP decode path is exercised, not the CPU-fallback piggyback path. Mutation against gpu.py:709 (force mask_nodata=True) flipped 4 GPU tests red; mutation against vrt.py eager mask gate flipped 4 VRT tests red. Cat 1 HIGH (backend coverage on mask_nodata=False for GPU, dask+GPU, VRT eager, VRT chunked). Pass 16 (2026-05-15): added test_max_cloud_bytes_dispatcher_silent_drop_2026_05_15.py closing Cat 4 HIGH parameter-coverage gap on the open_geotiff dispatcher's max_cloud_bytes kwarg. The kwarg was added in #1928 (eager fsspec budget) and re-ordered into the canonical reader signature by #1957, but open_geotiff only forwards it to _read_to_array on the eager non-VRT branch (__init__.py:431). The GPU branch at line 410, the dask branch at line 422, and the VRT branch at line 362 never reference the kwarg, so open_geotiff(p, max_cloud_bytes=8, gpu=True) / open_geotiff(p, max_cloud_bytes=8, chunks=N) / open_geotiff(vrt, max_cloud_bytes=8) all silently drop the budget. Same class of dispatcher-silently-drops-backend-kwarg bug fixed by #1561 / #1605 / #1685 / #1810 for other kwargs; the two sibling kwargs on_gpu_failure (line 339) and missing_sources (line 355) already raise ValueError when used on a path where they do not apply. 11 tests: 4 xfail(strict=True) pinning the fix surface (gpu, dask, vrt, dask+gpu), 3 passing pins on the current silent-drop behaviour so the fix is visible as a diff, 4 positive pins that the eager local + file-like paths accept the kwarg (docstring no-op contract). Filed issue #1974 for the dispatcher fix (sweep is test-only). Cat 4 HIGH (silent backend-kwarg drop). Pass 15 (2026-05-15): added test_write_vrt_bool_nodata_1921.py closing Cat 1 HIGH backend-parity gap on bool nodata rejection. Issue #1911 added the isinstance(nodata, (bool, np.bool_)) -> TypeError guard at to_geotiff and build_geo_tags, but the sibling writers were left unchecked: write_vrt(nodata=True) silently emits <NoDataValue>True</NoDataValue> into the VRT XML (str(True) drops the sentinel because no reader parses 'True' as numeric); write_geotiff_gpu direct call relies on the build_geo_tags defense-in-depth rather than an entry-point check, so a future refactor moving that guard would regress the GPU writer with no test coverage. 17 new tests: 4 xfail (strict=True) pinning the write_vrt fix surface (issue #1921), 1 passing pin on the current buggy str(True) emission so the fix is visible as a diff, 6 numeric/None happy-path tests on write_vrt, 4 GPU writer direct-call bool-reject tests (4 dtypes x 1 call), 1 to_geotiff(gpu=True) dispatcher thread-through. Filed issue #1921 for the write_vrt fix (sweep is test-only). Cat 1 HIGH (write_vrt backend parity bug) + Cat 1 MEDIUM (write_geotiff_gpu defense-in-depth pin). Pass 14 (2026-05-15): added test_dask_streaming_write_degenerate_2026_05_15.py closing Cat 3 HIGH and Cat 2 HIGH/MEDIUM gaps on the dask streaming write path (to_geotiff with dask-backed DataArray, #1084). test_streaming_write.py covered 100x100 with a NaN block plus a 2x2 small raster but had nothing 1-pixel-row, 1-pixel-column, all-NaN, all-Inf, or +/-Inf-mixed. The streaming tile-row segmenter (#1485) on a 1-pixel-tall raster and the streaming nodata-mask coercion on an all-NaN chunk were reachable only with a dask input and had no direct coverage; a regression on either would not surface from the eager numpy path or the write_geotiff_gpu path (pass 5 covered the GPU writer's degenerate shapes). 16 new tests, all passing: 1x1 chunk-matches-shape + nodata-attr round-trip + uint16, 1xN single chunk + chunks-split-columns + wide-segmented-by-buffer (#1485 streaming_buffer_bytes=1 forces the segmenter), Nx1 single chunk + chunks-split-rows, all-NaN with finite sentinel + all-NaN without sentinel, mixed NaN/+Inf/-Inf preserving Inf bit-exact + sentinel masking NaN only, all-+Inf and all--Inf, predictor=3 (float predictor) round-trip on float32 + float64 plus int-dtype ValueError. predictor=3 streaming coverage extends the small-chunk and int-rejection geometry around test_predictor_fp_write_1313.test_predictor3_streaming_dask (which already covers a 128x192 predictor=3 dask streaming write with a Predictor-tag assertion). Cat 3 HIGH (1x1/1xN/Nx1) + Cat 2 HIGH (all-NaN with sentinel) + Cat 2 MEDIUM (mixed-Inf, all-Inf) + Cat 4 MEDIUM (predictor=3 streaming). Pass 13 (2026-05-13): added test_size_param_validation_gpu_vrt_1776.py closing Cat 4 HIGH parameter-coverage gap on size-arg validation. Issue #1752 added tile_size validation to to_geotiff and chunks validation to read_geotiff_dask, but the matching kwargs on three sibling entry points were left unchecked: write_geotiff_gpu(tile_size=) raised ZeroDivisionError for 0, struct.error for -1, TypeError for 256.0; read_geotiff_gpu(chunks=) and read_vrt(chunks=) raised ZeroDivisionError for 0 and silently accepted negative values. Factored two shared validators (_validate_tile_size_arg, _validate_chunks_arg) and called them up front from each entry point. 34 new tests, all passing on GPU host: tile_size matrix on write_geotiff_gpu (0/-1/256.0/True/False/positive/np.int64), chunks matrix on read_geotiff_gpu and read_vrt (0/-1/(0,N)/(N,-1)/wrong-length/bool/non-int/(N,float)/positive/np.int64), dispatcher thread-through tests (open_geotiff(gpu=True, chunks=0), to_geotiff(gpu=True, tile_size=0)). Pre-existing 13 #1752 tests still pass after refactor. Filed issue #1776. Pass 12 (2026-05-12): added test_gpu_writer_overview_mode_and_compression_level_1740.py closing Cat 4 HIGH and Cat 4 MEDIUM parameter-coverage gaps. (1) write_geotiff_gpu(overview_resampling='mode') and the dedicated _block_reduce_2d_gpu mode-fallback branch (_gpu_decode.py:3051-3056) had zero direct tests; six of the seven overview_resampling modes were covered (mean/nearest by test_features, min/max/median by pass 6, cubic by test_signature_parity_1631) but mode was the odd one out -- a regression dropping the mode dispatch from _block_reduce_2d_gpu would fall through to the mean reshape branch and emit wrong overview pixels for integer rasters. (2) write_geotiff_gpu(compression_level=) documented as accepted-but-ignored had no test; the CPU writer rejects out-of-range levels with ValueError, the GPU writer is documented not to -- a regression wiring the GPU writer up to the CPU range validator would silently break every to_geotiff(gpu=True, compression_level=X) caller for in-range levels and noisily for out-of-range. 19 tests, all passing on GPU host: _block_reduce_2d_gpu(method='mode') CPU-parity on 4x4 deterministic + random 8x8 + dtype-preserved across u8/u16/i16/i32, write_geotiff_gpu(cog=True, overview_resampling='mode') end-to-end round trip, to_geotiff(gpu=True, ..., overview_resampling='mode') dispatcher thread-through, GPU-vs-CPU pixel parity on 8x8 input, write_geotiff_gpu(compression_level=) in-range matrix on zstd/deflate, out-of-range matrix (zstd=999/-5, deflate=50/0) accepted without raising + round-trip preserved, to_geotiff(gpu=True, compression_level=999) dispatcher thread-through, companion CPU rejects-OOR pin to lock the asymmetry. Mutation against the mode branch (drop the 'if method == mode' block in _block_reduce_2d_gpu) flipped 9 mode tests red. Filed issue #1740. Pass 11 (2026-05-12): added test_gpu_writer_cpu_fallback_codecs_2026_05_12.py closing a Cat 4 HIGH parameter-coverage gap on write_geotiff_gpu compression= modes for the CPU-fallback codecs (lzw, packbits, lz4, lerc, jpeg2000/j2k). Pass 7 (test_gpu_writer_compression_modes_2026_05_11) covered only none/deflate/zstd/jpeg; the remaining five codecs route through dedicated branches in gpu_compress_tiles (_gpu_decode.py:2974-3019) with CPU fallbacks (lerc_compress, jpeg2000_compress, cpu_compress) that had zero direct tests via write_geotiff_gpu. A regression in routing/tag-wiring/fallback dispatch would ship silently because the internal reader uses the same compression-tag table. 17 tests, all passing on GPU host: lzw/packbits/lz4 round-trip + compression-tag pin on uint16, lerc lossless float32 + uint16 round-trip + tag pin, jpeg2000 uint8 single-band + RGB multi-band lossless round-trip + j2k-alias parity + tag pin, GPU-vs-CPU writer pixel parity for lzw/packbits, to_geotiff(gpu=True, compression=lzw/packbits) dispatcher thread-through. Mutation against compression dispatch (swap lzw bytes to zstd; swap lerc bytes to deflate) flipped round-trip tests red. Filed issue #1706. Pass 10 (2026-05-12): added test_kwarg_behaviour_2026_05_12_v2.py closing two Cat 4 HIGH parameter-coverage gaps. (1) write_geotiff_gpu(predictor=True/2/3) had zero direct tests; the GPU writer threads predictor= through normalize_predictor and gpu_compress_tiles into five CUDA encode kernels (_predictor_encode_kernel_u8/u16/u32/u64 for predictor=2, _fp_predictor_encode_kernel for predictor=3) and a regression dropping the encode-kernel calls would ship corrupt files. (2) read_vrt(window=) had no behaviour tests (only a signature pin in test_signature_annotations_1654); the kwarg is documented and _vrt.read_vrt implements full windowed-read semantics (clip, multi-source overlap, src/dst scaling, GeoTransform origin shift on coords + attrs['transform']). 23 tests, all passing on GPU host: predictor=True/2 round-trips on u8/u16/i32 + 3-band RGB samples_per_pixel stride; predictor=3 lossless round-trip on f32 and f64; predictor=3 int-dtype ValueError (CPU/GPU parity); CPU/GPU pixel-exact parity for pred=2 u16 and pred=3 f32; read_vrt(window=) subregion + full + clamp-overflow + clamp-negative + 2x1 mosaic seam straddle + offset past seam + transform-attr origin shift + y/x coords half-pixel shift + window+band + window+chunks (dask) + window+gpu (cupy) + window+gpu+chunks (dask+cupy). Mutation against the encode dispatch flipped 7 predictor tests red. Filed issue #1690. Pass 9 (2026-05-12): added test_kwarg_behaviour_2026_05_12.py closing three Cat 4 MEDIUM parameter-coverage gaps plus one Cat 4 LOW error path. write_vrt documented kwargs (relative/crs_wkt/nodata) had a smoke-test pinning that the kwargs are accepted but no test verified the override *effect* -- a regression dropping the override branch and silently using the default-from-first-source would ship undetected. read_geotiff_gpu(dtype=) cast had zero direct tests; the eager path has TestDtypeEager and dask has TestDtypeDask but the GPU branch had no equivalent. write_geotiff_gpu(bigtiff=) threads through to _assemble_tiff(force_bigtiff=) but no test asserted the on-disk header byte switches; the CPU writer had it via test_features::test_force_bigtiff_via_public_api. write_vrt(source_files=[]) ValueError was uncovered. 26 tests, all passing on GPU host: write_vrt relative=True/False XML attribute + path inspection + parse-back round-trip, write_vrt crs_wkt= override distinct-from-default XML check, write_vrt nodata= override + default-from-source coverage, write_vrt([]) ValueError + no-file side effect, read_geotiff_gpu dtype= matrix (float64->float32, float64->float16, uint16->int32, uint16->uint8, float-to-int raise, dtype=None preserves native), open_geotiff(gpu=True, dtype=) dispatcher, read_geotiff_gpu(chunks=, dtype=) dask+GPU branch, write_geotiff_gpu bigtiff=True/False/None header verification, to_geotiff(gpu=True, bigtiff=True) dispatcher thread-through. Pass 8 (2026-05-11): added test_lz4_compression_level_2026_05_11.py closing Cat 4 MEDIUM parameter-coverage gap on compression='lz4' + compression_level=. _LEVEL_RANGES advertises lz4: (0, 16) but only deflate (1, 9) and zstd (1, 22) had direct level boundary + round-trip + reject tests. The range check is the gatekeeper -- lz4_compress silently accepts any int level -- so a regression dropping 'lz4' from _LEVEL_RANGES would ship undetected. 18 tests, all passing: round-trip at levels 0/1/9/16 (lossless), default-level no-arg path, higher-level-not-larger smoke check on compressible input, out-of-range reject at -1/-10/17/100 on eager path, valid-range message format pin (lz4 valid: 0-16), dask streaming round-trip at 0/1/8/16, dask streaming out-of-range reject at -1/17/50 (separate _LEVEL_RANGES call site). Pass 7 (2026-05-11): added test_gpu_writer_compression_modes_2026_05_11.py closing Cat 4 HIGH gap on write_geotiff_gpu compression= modes. The writer documents zstd (default, fastest GPU), deflate, jpeg, and none, but only deflate + none had round-trip tests; the default zstd and the jpeg (nvJPEG/Pillow) paths shipped without targeted coverage. 11 new tests, all passing on GPU host: zstd round-trip + default-codec pinning, jpeg round-trip on 3-band RGB uint8 + 1-band greyscale, TIFF compression-tag header check across none/deflate/zstd/jpeg, plain deflate + none round-trips outside the COG/sentinel paths, and a cross-codec lossless parity check (zstd/deflate/none agree pixel-exact). nvJPEG path was exercised live, not just the Pillow fallback. Pass 6 (2026-05-11): added test_overview_resampling_min_max_median_2026_05_11.py covering Cat 4 HIGH parameter-coverage gap on overview_resampling=min/max/median. CPU end-to-end paths were already covered by test_cog_overview_nodata_1613::test_cpu_cog_overview_aggregations_ignore_sentinel; the GPU end-to-end paths and the direct CPU+GPU block-reducer branches had no targeted tests, so a regression on those code paths would ship undetected. 26 tests, all passing on GPU host: block-reducer unit tests (finite + partial-NaN), end-to-end COG writes for both to_geotiff and write_geotiff_gpu, CPU/GPU parity for to_geotiff(gpu=True), CPU nodata-sentinel regression check, and ValueError error-path tests for unknown method names on both backends. Pass 5 (2026-05-11): added test_degenerate_shapes_backends_2026_05_11.py covering Cat 3 HIGH geometric gaps (1x1 / 1xN / Nx1 reads on dask+numpy, GPU, dask+cupy backends; 1x1 / 1xN / Nx1 writes through write_geotiff_gpu) and Cat 2 MEDIUM NaN/Inf gaps (all-NaN read on GPU + dask+cupy, Inf / -Inf reads on all non-eager backends, NaN sentinel mask on dask read path including sentinel block split across chunk boundary). 23 tests, all passing on GPU host. Prior passes still hold: pass 4 (r4) closed read_geotiff_gpu/dask name= + max_pixels= kwargs (Cat 4), pass 3 (r3) closed read_vrt GPU/dask+GPU backend dispatch (Cat 1) and dtype/name kwargs (Cat 4)."
|
|
9
|
+
polygonize,2026-05-27,2537,MEDIUM,4,"Pass 2 (2026-05-27): added test_polygonize_atol_rtol_backend_coverage_2026_05_27.py with 15 tests, all passing on a CUDA host. Closes Cat 4 MEDIUM parameter-coverage gap on atol/rtol forwarding through the cupy and dask+cupy backends. atol/rtol were exposed by #2173 / #2194 and thread through _polygonize_cupy (polygonize.py:808) and _polygonize_dask (polygonize.py:1719); the dask path further plumbs them into dask.delayed(_polygonize_chunk)(...) at lines 1748-1754 and into _bucket_key_for_value for cross-chunk merge bucketing at lines 1757-1758. Pre-existing tests covered non-default atol/rtol only on numpy and dask+numpy. The cupy and dask+cupy dispatchers were untested -- a regression dropping the kwargs there would silently change the float polygon count and would not be caught. Same dispatcher-silently-drops-kwarg pattern fixed by #1561 / #1605 / #1685 / #1810 / #1974 on adjacent GeoTIFF surfaces. 15 tests: cupy strict-equality + default-tolerance pin on _REPRO_2173, dask+cupy strict-equality single-chunk + multi-chunk (engages cross-chunk merge bucket) + default-tolerance multi-chunk pin, cupy intermediate-atol small/large pair, dask+cupy intermediate-atol single/multi-chunk small + single-chunk large, cupy integer atol-ignored matrix, dask+cupy integer atol-ignored single-chunk + multi-chunk, cupy rtol-only large/small matrix. Mutation against _polygonize_cupy float branch (drop atol/rtol kwargs in the _polygonize_numpy forward call at polygonize.py:823-825) flips 3 of 5 cupy tests red; mutation against dask.delayed(_polygonize_chunk)(...) at polygonize.py:1748-1754 (drop atol, rtol args) flips 2 of 6 dask+cupy tests red. Confirmed clean restore via md5sum. Source untouched. Filed issue #2537 (test-only). Cat 4 MEDIUM (parameter coverage on cupy + dask+cupy atol/rtol forwarding). Pass 1 (2026-05-19): added test_polygonize_coverage_2026_05_19.py with 58 tests, all passing on a CUDA host. Closes Cat 3 HIGH 1x1 / Nx1 single-column geometric gaps (Nx1 exercises the nx==1 padding path at polygonize.py:565 and the cupy nx==1 numpy-fallback at polygonize.py:671), Cat 3 MEDIUM 1xN single-row and all-equal-value rasters on all four backends. Closes Cat 2 HIGH NaN parity for cupy + dask+cupy (numpy/dask were already covered by test_polygonize_nan_pixels_excluded*), Cat 2 MEDIUM all-NaN raster on all four backends, Cat 2 HIGH +/-Inf pins on all four backends. Filed source-bug issue #2155: numpy/dask/dask+cupy backends silently absorb Inf cells into adjacent finite polygons because _is_close reduces abs(inf-inf) to nan; cupy backend handles Inf correctly. Pins lock the asymmetric behaviour so the fix is visible. Closes Cat 1 MEDIUM simplify_tolerance + mask= parity gaps on dask+cupy backend (numpy/cupy/dask were already covered). Closes Cat 4 MEDIUM column_name non-default value across geopandas/spatialpandas/geojson return types and Cat 4 MEDIUM validation error paths (bad connectivity, bad transform length, mask shape mismatch, mask underlying-type mismatch). Cat 5 N/A: polygonize returns lists/dataframes, not a DataArray with attrs to propagate."
|
|
10
|
+
rasterize,2026-05-21,2255,HIGH,1;2;3,"Pass 2 (2026-05-21): added test_rasterize_coverage_2026_05_21.py with 58 tests, all passing on a CUDA host. Closes Cat 2 HIGH +/-Inf and NaN burn-value gaps that pass-1 left untouched: pin +Inf / -Inf / Inf+(-Inf)/NaN polygon, point, and line burn behaviour across numpy / cupy / dask+numpy / dask+cupy, plus Inf+finite under sum stays Inf, Inf+(-Inf) under sum collapses to NaN, min(Inf, 1.0) and max(-Inf, 1.0) pick the finite value, and Inf-as-bound is rejected with the same ValueError as NaN-as-bound (pass-1 only tested the NaN-bound rejection). Closes Cat 1 MEDIUM nested GeometryCollection on all four backends: a GC inside a GC has no direct test today even though rasterize.py:1995 documents recursive unpacking, and the deeply-nested-3-levels eager test pins the recursion depth limit isn't 1 or 2. Closes Cat 1 MEDIUM columns= (multi-column) parity on cupy and dask+cupy (TestMultiColumn covered numpy/dask+numpy only); pin three columns of props on GPU so the (N, P) loop survives the kernel boundary. Closes Cat 3 LOW rectangular-pixel parity with resolution=(rx, ry) across backends. Filed source-bug issue #2255: GPU max/min merge silently suppresses NaN burn values -- CPU returns NaN (1.0 > NaN is False, keeps NaN); GPU returns 1.0 because the kernel inits the output buffer to -inf for max (or +inf for min) and atomicMax/Min is NaN-suppressing under IEEE device semantics. Pinned both the CPU NaN-propagating behaviour and the GPU NaN-suppressing behaviour as paired tests (test_nan_burn_overlaps_max_cpu_propagates vs test_nan_burn_overlaps_max_gpu_suppresses_nan, plus test_nan_burn_single_geom_max_gpu_returns_neg_inf for the single-write-on-GPU-returns-buffer-init case) so the divergence is visible in CI until the GPU kernels are aligned. Source untouched. Pass 1 (2026-05-17): added test_rasterize_coverage_2026_05_17.py with 34 tests, all passing on a CUDA host. Closes four documented public-API gaps left after the pass-0 audit. (1) Cat 3 HIGH 1x1 single-pixel raster -- test_rasterize.py covers 1xN strips and Nx1 strips but never width=1 AND height=1, so the polygon scanline / line Bresenham / point burn kernels all ship without the single-cell degenerate case; the new TestSinglePixelRaster class pins polygon/point/line on eager numpy plus polygon parity across cupy / dask+numpy / dask+cupy. (2) Cat 4 HIGH like= template-raster parameter is documented at rasterize.py:2038 and implemented by _extract_grid_from_like (line 1930) but no test exercises it; TestLikeParameter pins dtype/bounds/coords inheritance, the three override branches (dtype, bounds, width/height), the three validation branches (not-DataArray, 3D, wrong dim names) and like= on all four backends. Mutation against the like-dtype branch (rasterize.py:2183-2184) flipped the inheritance test red. (3) Cat 4 HIGH resolution= happy path -- only the oversize-rejection error path was tested (line 304); TestResolutionParameter pins the scalar branch, the tuple branch, the ceil-and-clamp-to-1 semantics, and resolution= on all four backends. (4) Cat 4 HIGH non-empty GeometryCollection unpacking is documented at rasterize.py:1995 and implemented by _classify_geometries_loop (line 228) but only the empty-GC case was tested (line 269); TestGeometryCollection pins polygon+point and polygon+line+point collections on eager numpy plus parity across cupy / dask+numpy / dask+cupy so the loop classifier's polygon/line/point sub-bucketing has direct coverage. Cat 1 MEDIUM gap closed: eager cupy all_touched=True parity vs eager numpy (TestEagerCupyAllTouched) -- the existing test only covered dask+cupy all_touched, leaving the direct GPU all_touched kernel untested. Cat 2 MEDIUM gap closed: int32 dtype with default NaN fill silently casts to the int32-min sentinel (TestIntegerDtypeNanFill) -- pin the cast so any future ValueError-raises switch is visible as a code-review diff. Pre-existing 143 passing + 2 skipped tests in test_rasterize.py untouched."
|
|
11
|
+
reproject,2026-05-27,,MEDIUM,1,"Pass 2 (2026-05-27): added test_reproject_coverage_2026_05_27.py with 10 tests, all passing on a CUDA host. Closes Cat 1 MEDIUM backend-coverage gaps left after pass 1: (a) bounds_policy=#2187 had numpy + dask+numpy coverage but no cupy / dask+cupy tests -- a regression dropping the kwarg from the GPU dispatchers would ship undetected; TestBoundsPolicyCupy and TestBoundsPolicyDaskCupy pin raw/clamp/bogus on both GPU backends and assert clamp-grid parity with numpy. (b) test_reproject_handles_inf_input only covered eager numpy; the dask, cupy, and dask+cupy chunk workers each ship their own bilinear/cubic resampler so a regression raising on +/-Inf in any one backend would not surface from the existing test. Four new tests close the matrix (dask+numpy, cupy, dask+cupy with scattered +/-Inf cells; cupy with all-Inf raster checking no spurious finite cells appear). Note carried forward from pass 1: _merge_arrays_cupy is imported but unused -- no cupy merge dispatch in merge(); feature gap not test gap. Added 39 tests: LiteCRS direct coverage, itrf_transform behaviour/roundtrip/array, itrf_frames, geoid_height numerical correctness + raster happy-path, vertical helpers (ellipsoidal<->orthometric/depth), reproject() lat/lon and latitude/longitude dim propagation. Note: _merge_arrays_cupy is imported but unused (no cupy merge dispatch in merge()); flagged as feature gap not test gap."
|
|
12
|
+
reproject,2026-05-10,,HIGH,1;4;5,"Added 39 tests: LiteCRS direct coverage, itrf_transform behaviour/roundtrip/array, itrf_frames, geoid_height numerical correctness + raster happy-path, vertical helpers (ellipsoidal<->orthometric/depth), reproject() lat/lon and latitude/longitude dim propagation. Note: _merge_arrays_cupy is imported but unused (no cupy merge dispatch in merge()); flagged as feature gap not test gap."
|
|
13
|
+
resample,2026-05-27,2547,HIGH,2;3;5,"Pass 1 (2026-05-27): added test_resample_coverage_2026_05_27.py with 70 tests (68 passing, 2 skipped). Closes Cat 3 HIGH Nx1 single-column gap across numpy/cupy/dask+numpy/dask+cupy x 8 methods (nearest/bilinear/cubic/average/min/max/median/mode) plus Nx1 upsample-nearest parity and Nx1 cross-backend aggregate parity. Closes Cat 2 MEDIUM NaN-parity gap on cupy and dask+cupy (existing TestCuPyParity/TestDaskCuPyParity used random data without NaN; the weight-mask gate and spline-prepad had no GPU NaN coverage). Closes Cat 3 MEDIUM all-equal-value raster across 8 methods (downsample) and 3 interp methods (upsample) plus a constant-with-NaN aggregate variant. Closes Cat 5 MEDIUM non-default dim-name propagation: lat/lon, latitude/longitude, and (channel, lat, lon) 3D round-trip without being renamed to y/x; per-dim attrs (units) preserved. Closes Cat 3 MEDIUM empty-raster behaviour pin: 0-row and 0-col rasters raise (currently IndexError) -- contract covered. Filed source-bug issue #2547: cubic on dask backends fails for Nx1 / arrays smaller than depth=16; the 2 skipped tests in this file gate on that fix landing. Source untouched."
|
|
14
|
+
zonal,2026-05-27,,HIGH,1;3;4;5,"Pass 1 (2026-05-27): added test_zonal_backend_coverage_2026_05_27.py with 32 tests, all passing on a CUDA host. Closes Cat 1 HIGH backend-coverage gaps: crosstab cupy + dask+cupy (_crosstab_cupy / _crosstab_dask_cupy were dispatched but never invoked by tests), regions cupy + dask+cupy (_regions_cupy via cupyx.scipy.ndimage + _regions_dask_cupy), trim dask+numpy + cupy + dask+cupy (_trim_bounds_dask isnan path and cupy data.get() path), crop dask+numpy + cupy + dask+cupy (_crop_bounds_dask + cupy data.get() path), apply 3D cupy + dask+cupy (per-layer kernel launch over the third axis in _apply_cupy and _apply_dask_cupy). Existing test_zonal.py covered only numpy + dask+numpy for crosstab/regions/trim/crop and 2D-only for cupy apply. Closes Cat 3 MEDIUM 1x1 / 1xN / Nx1 strip edge cases for trim, crop, and regions. Closes Cat 4 LOW pins: regions(neighborhood=6) ValueError, suggest_zonal_canvas(crs='Geographic') aspect-ratio pin and invalid-crs KeyError, crosstab cupy zone_ids/cat_ids filter, crosstab cupy agg='percentage'. Closes Cat 5 MEDIUM: regions coords/attrs propagation across numpy + dask+numpy, trim/crop name='trim'/'crop' default + attrs preservation. Also pins the documented numpy-vs-dask trim asymmetry on NaN sentinel (numpy _trim does equality which never matches NaN; dask _trim_bounds_dask has dedicated isnan branch). Mutation against the cupy.asnumpy() conversion in _crosstab_cupy flipped test_crosstab_cupy_matches_numpy red. Source untouched."
|
|
@@ -2,7 +2,49 @@
|
|
|
2
2
|
-----------
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### Version 0.10.1 - 2026-05-29
|
|
6
|
+
|
|
7
|
+
#### New features
|
|
8
|
+
- accessor: backend-aware .xrs.open_geotiff on DataArray and Dataset (#2598)
|
|
9
|
+
- geotiff: add bbox= to open_geotiff for geographic-space windowed reads (#2556)
|
|
10
|
+
|
|
11
|
+
#### Bug fixes and improvements
|
|
12
|
+
- rasterize: honor resolution= exactly when bounds don't divide evenly (#2597)
|
|
13
|
+
- reproject: fix vertical-datum shift crash on integer DEMs (#2596)
|
|
14
|
+
- resample: clamp dask interp overlap depth per axis (#2547) (#2599)
|
|
15
|
+
- zonal: fix trim() with NaN sentinel on numpy and cupy backends (#2559) (#2594)
|
|
16
|
+
- reproject: reject explicit out-of-range nodata for integer dtypes (#2591)
|
|
17
|
+
- zonal: fix cupy backend dropping all-NaN zones and desyncing zone_ids (#2562) (#2589)
|
|
18
|
+
- resample: refresh transform to match actual coord orientation (#2571) (#2587)
|
|
19
|
+
- rasterize: validate resolution= shape and element type (#2576) (#2586)
|
|
20
|
+
- resample: preserve integer precision in nodata mask comparison (#2570) (#2592)
|
|
21
|
+
- zonal: keep hypsometric_integral dask path fully lazy (#2563) (#2593)
|
|
22
|
+
- geotiff: accept projected GeoTIFFs that carry a base geographic CRS (#2603)
|
|
23
|
+
- polygonize: reject non-finite simplify_tolerance (#2575) (#2584)
|
|
24
|
+
- reproject: unit-aware bounds_policy="auto" blow-up detection (#2600)
|
|
25
|
+
- zonal: validate return_type at entry to stats() (#2558) (#2578)
|
|
26
|
+
- resample: validate target_resolution and scale_factor up front (#2574) (#2590)
|
|
27
|
+
- rasterize: support descending-x in like= templates (#2568) (#2595)
|
|
28
|
+
- rasterize: reject zig-zag duplicate-coord patterns in _check_uniform_axis (#2585)
|
|
29
|
+
- polygonize: fix dask chunk-dependent merging and DN corruption (#2601)
|
|
30
|
+
- zonal: make crop() return (0, 0) on all backends when no zone matches (#2580)
|
|
31
|
+
- rasterize: reject partial width/height overrides instead of silent ignore (#2579)
|
|
32
|
+
- zonal: fix crosstab cat_ids overcount when earlier categories are filtered out (#2560) (#2577)
|
|
33
|
+
- resample: preserve scalar non-dim coords and refresh stale nodata attr (#2542) (#2549)
|
|
34
|
+
- zonal: fix hypsometric_integral dask+cupy backend (#2525) (#2529)
|
|
35
|
+
- geotiff: include GB allocation estimate in max_pixels error message (#2554)
|
|
36
|
+
- zonal: raise on 'majority' in zonal_stats dask path instead of silent drop (#2528) (#2531)
|
|
37
|
+
- reproject: fix half-pixel offset in geoid and datum-shift grid lookups (#2508) (#2516)
|
|
38
|
+
- rasterize: reject NaN fill against integer dtype (#2504) (#2512)
|
|
39
|
+
- geotiff: reject distinct per-band nodatavals on write (#2514) (#2519)
|
|
40
|
+
- zonal: guard unbounded allocation in stats(return_type='xarray.DataArray') (#2523) (#2533)
|
|
41
|
+
- zonal: rechunk apply 3D dask output along stacked axis (#2526) (#2532)
|
|
42
|
+
- rasterize: hoist poly_props/poly_global cupy.asarray above all_touched (#2506) (#2510)
|
|
43
|
+
- polygonize: auto-detect attrs['transform'] for output georeferencing (#2536) (#2541)
|
|
44
|
+
- geotiff: reconcile COG write stability across registry, contract, and docstring (#2520)
|
|
45
|
+
- zonal: rename crop(zones_ids=) to crop(zone_ids=) with deprecation shim (#2521) (#2527)
|
|
46
|
+
- reproject: preserve integer dtype in dask+cupy fast path (#2505) (#2509)
|
|
47
|
+
- geotiff: scope max_pixels to the chunk when chunks= is supplied (#2501) (#2502)
|
|
6
48
|
|
|
7
49
|
|
|
8
50
|
### Version 0.10.0 - 2026-05-27
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Source: https://github.com/forrestchang/andrej-karpathy-skills/blob/main/CLAUDE.md
|
|
3
|
+
Upstream license: not specified at time of fetch (2026-05-28). If the upstream
|
|
4
|
+
repo adds a LICENSE later, re-verify redistribution terms here.
|
|
5
|
+
To refresh from upstream:
|
|
6
|
+
curl -o CLAUDE.md https://raw.githubusercontent.com/forrestchang/andrej-karpathy-skills/main/CLAUDE.md
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
# CLAUDE.md
|
|
10
|
+
|
|
11
|
+
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
|
12
|
+
|
|
13
|
+
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
|
14
|
+
|
|
15
|
+
## 1. Think Before Coding
|
|
16
|
+
|
|
17
|
+
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
|
18
|
+
|
|
19
|
+
Before implementing:
|
|
20
|
+
- State your assumptions explicitly. If uncertain, ask.
|
|
21
|
+
- If multiple interpretations exist, present them - don't pick silently.
|
|
22
|
+
- If a simpler approach exists, say so. Push back when warranted.
|
|
23
|
+
- If something is unclear, stop. Name what's confusing. Ask.
|
|
24
|
+
|
|
25
|
+
## 2. Simplicity First
|
|
26
|
+
|
|
27
|
+
**Minimum code that solves the problem. Nothing speculative.**
|
|
28
|
+
|
|
29
|
+
- No features beyond what was asked.
|
|
30
|
+
- No abstractions for single-use code.
|
|
31
|
+
- No "flexibility" or "configurability" that wasn't requested.
|
|
32
|
+
- No error handling for impossible scenarios.
|
|
33
|
+
- If you write 200 lines and it could be 50, rewrite it.
|
|
34
|
+
|
|
35
|
+
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
|
36
|
+
|
|
37
|
+
## 3. Surgical Changes
|
|
38
|
+
|
|
39
|
+
**Touch only what you must. Clean up only your own mess.**
|
|
40
|
+
|
|
41
|
+
When editing existing code:
|
|
42
|
+
- Don't "improve" adjacent code, comments, or formatting.
|
|
43
|
+
- Don't refactor things that aren't broken.
|
|
44
|
+
- Match existing style, even if you'd do it differently.
|
|
45
|
+
- If you notice unrelated dead code, mention it - don't delete it.
|
|
46
|
+
|
|
47
|
+
When your changes create orphans:
|
|
48
|
+
- Remove imports/variables/functions that YOUR changes made unused.
|
|
49
|
+
- Don't remove pre-existing dead code unless asked.
|
|
50
|
+
|
|
51
|
+
The test: Every changed line should trace directly to the user's request.
|
|
52
|
+
|
|
53
|
+
## 4. Goal-Driven Execution
|
|
54
|
+
|
|
55
|
+
**Define success criteria. Loop until verified.**
|
|
56
|
+
|
|
57
|
+
Transform tasks into verifiable goals:
|
|
58
|
+
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
|
59
|
+
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
|
60
|
+
- "Refactor X" → "Ensure tests pass before and after"
|
|
61
|
+
|
|
62
|
+
For multi-step tasks, state a brief plan:
|
|
63
|
+
```
|
|
64
|
+
1. [Step] → verify: [check]
|
|
65
|
+
2. [Step] → verify: [check]
|
|
66
|
+
3. [Step] → verify: [check]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
.readthedocs.yml
|
|
6
6
|
AI_POLICY.md
|
|
7
7
|
CHANGELOG.md
|
|
8
|
+
CLAUDE.md
|
|
8
9
|
CODE_OF_CONDUCT.md
|
|
9
10
|
CONTRIBUTING.md
|
|
10
11
|
Citation-styles.md
|
|
@@ -246,6 +247,7 @@ xrspatial/geotiff/tests/parity/test_reference.py
|
|
|
246
247
|
xrspatial/geotiff/tests/parity/test_signature_contract.py
|
|
247
248
|
xrspatial/geotiff/tests/read/__init__.py
|
|
248
249
|
xrspatial/geotiff/tests/read/test_basic.py
|
|
250
|
+
xrspatial/geotiff/tests/read/test_bbox_2555.py
|
|
249
251
|
xrspatial/geotiff/tests/read/test_compression.py
|
|
250
252
|
xrspatial/geotiff/tests/read/test_coords.py
|
|
251
253
|
xrspatial/geotiff/tests/read/test_crs.py
|
|
@@ -450,8 +452,10 @@ xrspatial/tests/test_pathfinding.py
|
|
|
450
452
|
xrspatial/tests/test_perlin.py
|
|
451
453
|
xrspatial/tests/test_polygon_clip.py
|
|
452
454
|
xrspatial/tests/test_polygonize.py
|
|
455
|
+
xrspatial/tests/test_polygonize_atol_rtol_backend_coverage_2026_05_27.py
|
|
453
456
|
xrspatial/tests/test_polygonize_coverage_2026_05_19.py
|
|
454
457
|
xrspatial/tests/test_polygonize_issue_2172.py
|
|
458
|
+
xrspatial/tests/test_polygonize_issue_2583.py
|
|
455
459
|
xrspatial/tests/test_preview.py
|
|
456
460
|
xrspatial/tests/test_proximity.py
|
|
457
461
|
xrspatial/tests/test_rasterize.py
|
|
@@ -459,13 +463,26 @@ xrspatial/tests/test_rasterize_accuracy.py
|
|
|
459
463
|
xrspatial/tests/test_rasterize_all_touched_supercover_2169.py
|
|
460
464
|
xrspatial/tests/test_rasterize_coverage_2026_05_17.py
|
|
461
465
|
xrspatial/tests/test_rasterize_coverage_2026_05_21.py
|
|
466
|
+
xrspatial/tests/test_rasterize_coverage_2026_05_27.py
|
|
467
|
+
xrspatial/tests/test_rasterize_descending_x_2568.py
|
|
462
468
|
xrspatial/tests/test_rasterize_gpu_race_2167.py
|
|
469
|
+
xrspatial/tests/test_rasterize_nan_int_fill_2504.py
|
|
463
470
|
xrspatial/tests/test_rasterize_nan_propagation_2255.py
|
|
471
|
+
xrspatial/tests/test_rasterize_partial_dims_2569.py
|
|
472
|
+
xrspatial/tests/test_rasterize_props_hoist_2506.py
|
|
473
|
+
xrspatial/tests/test_rasterize_resolution_exact_2573.py
|
|
474
|
+
xrspatial/tests/test_rasterize_resolution_validation_2576.py
|
|
464
475
|
xrspatial/tests/test_rasterize_signature_annot_2250.py
|
|
476
|
+
xrspatial/tests/test_rasterize_signed_step_2566.py
|
|
465
477
|
xrspatial/tests/test_rasterize_tile_props_slice_2020.py
|
|
466
478
|
xrspatial/tests/test_rechunk_no_shuffle.py
|
|
467
479
|
xrspatial/tests/test_reproject.py
|
|
480
|
+
xrspatial/tests/test_reproject_coverage_2026_05_27.py
|
|
481
|
+
xrspatial/tests/test_reproject_cupy_gate_2564.py
|
|
468
482
|
xrspatial/tests/test_resample.py
|
|
483
|
+
xrspatial/tests/test_resample_coverage_2026_05_27.py
|
|
484
|
+
xrspatial/tests/test_resample_input_validation_2574.py
|
|
485
|
+
xrspatial/tests/test_resample_signature_annot_2544.py
|
|
469
486
|
xrspatial/tests/test_sieve.py
|
|
470
487
|
xrspatial/tests/test_sieve_gdal_parity.py
|
|
471
488
|
xrspatial/tests/test_sky_view_factor.py
|
|
@@ -477,4 +494,5 @@ xrspatial/tests/test_utils.py
|
|
|
477
494
|
xrspatial/tests/test_validation.py
|
|
478
495
|
xrspatial/tests/test_viewshed.py
|
|
479
496
|
xrspatial/tests/test_visibility.py
|
|
480
|
-
xrspatial/tests/test_zonal.py
|
|
497
|
+
xrspatial/tests/test_zonal.py
|
|
498
|
+
xrspatial/tests/test_zonal_backend_coverage_2026_05_27.py
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.10.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 10,
|
|
21
|
+
__version__ = version = '0.10.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 10, 1)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g57e7c576e'
|