Summary
Follow-up to #1654 (annotate-parity sweep): two more drift sites surfaced by the api-consistency sweep on 2026-05-12. Both are type-hint gaps where the same parameter has an explicit annotation on one public function in the writer trio and bare =None / different breadth on its sibling. Type-checkers and IDE autocomplete therefore see different types for the same parameter depending on which entry point the caller picked.
1. nodata: annotated on write_vrt, unannotated on to_geotiff and write_geotiff_gpu
xrspatial/geotiff/__init__.py
def to_geotiff(data, path, *, crs=..., nodata=None, ...):
"""... nodata : float, int, or None ..."""
def write_geotiff_gpu(data, path, *, crs=..., nodata=None, ...):
"""... nodata : float, int, or None ..."""
def write_vrt(vrt_path, source_files, *, relative=True, crs_wkt=None,
nodata: float | int | None = None) -> str:
...
write_vrt got the float | int | None annotation in #1684. The two sibling writers still expose nodata=None with no annotation, even though every docstring in the trio describes the same accepted-type set ("float, int, or None"). mypy --strict therefore infers Any for to_geotiff(..., nodata=...) and write_geotiff_gpu(..., nodata=...) while inferring float | int | None for write_vrt(..., nodata=...).
2. streaming_buffer_bytes: int on to_geotiff, int | None on write_geotiff_gpu
xrspatial/geotiff/__init__.py
def to_geotiff(..., streaming_buffer_bytes: int = 256 * 1024 * 1024, ...):
def write_geotiff_gpu(..., streaming_buffer_bytes: int | None = None):
write_geotiff_gpu's implementation immediately does del streaming_buffer_bytes (the kwarg is accepted only for API parity with to_geotiff; the GPU writer has no streaming concept). The default and type annotation differ from to_geotiff even though the documented purpose and accepted-value set are the same. Either both should be int = <default> (the CPU writer's contract) or both int | None = None (the GPU writer's no-op contract). Matching to_geotiff's int annotation is the cheaper fix: users who pass through the same kwargs to either entry point get the same type signature, and the GPU writer's no-op semantics are unchanged by tightening the type alone.
Severity
MEDIUM (Cat 3, type hint drift). Annotation-only; no runtime behaviour change. Same shape as the gap #1654 closed for window, path, and on_gpu_failure.
Proposed fix
- Add
nodata: float | int | None = None to to_geotiff and write_geotiff_gpu.
- Change
write_geotiff_gpu's streaming_buffer_bytes annotation from int | None = None to int = 256 * 1024 * 1024, matching to_geotiff. The existing del streaming_buffer_bytes no-op stays.
- Extend
tests/test_signature_annotations_1654.py with pinned-annotation assertions for both kwargs across the writer trio so future drift fails CI.
Non-breaking. nodata=None and streaming_buffer_bytes=256*1024*1024 are the existing defaults and the existing call sites in the codebase already match those types.
Discovered by
/sweep-api-consistency against the geotiff module on 2026-05-12.
Summary
Follow-up to #1654 (annotate-parity sweep): two more drift sites surfaced by the api-consistency sweep on 2026-05-12. Both are type-hint gaps where the same parameter has an explicit annotation on one public function in the writer trio and bare
=None/ different breadth on its sibling. Type-checkers and IDE autocomplete therefore see different types for the same parameter depending on which entry point the caller picked.1.
nodata: annotated onwrite_vrt, unannotated onto_geotiffandwrite_geotiff_gpuxrspatial/geotiff/__init__.pywrite_vrtgot thefloat | int | Noneannotation in #1684. The two sibling writers still exposenodata=Nonewith no annotation, even though every docstring in the trio describes the same accepted-type set ("float, int, or None").mypy --stricttherefore infersAnyforto_geotiff(..., nodata=...)andwrite_geotiff_gpu(..., nodata=...)while inferringfloat | int | Noneforwrite_vrt(..., nodata=...).2.
streaming_buffer_bytes:intonto_geotiff,int | Noneonwrite_geotiff_gpuxrspatial/geotiff/__init__.pywrite_geotiff_gpu's implementation immediately doesdel streaming_buffer_bytes(the kwarg is accepted only for API parity withto_geotiff; the GPU writer has no streaming concept). The default and type annotation differ fromto_geotiffeven though the documented purpose and accepted-value set are the same. Either both should beint = <default>(the CPU writer's contract) or bothint | None = None(the GPU writer's no-op contract). Matchingto_geotiff'sintannotation is the cheaper fix: users who pass through the same kwargs to either entry point get the same type signature, and the GPU writer's no-op semantics are unchanged by tightening the type alone.Severity
MEDIUM (Cat 3, type hint drift). Annotation-only; no runtime behaviour change. Same shape as the gap #1654 closed for
window,path, andon_gpu_failure.Proposed fix
nodata: float | int | None = Nonetoto_geotiffandwrite_geotiff_gpu.write_geotiff_gpu'sstreaming_buffer_bytesannotation fromint | None = Nonetoint = 256 * 1024 * 1024, matchingto_geotiff. The existingdel streaming_buffer_bytesno-op stays.tests/test_signature_annotations_1654.pywith pinned-annotation assertions for both kwargs across the writer trio so future drift fails CI.Non-breaking.
nodata=Noneandstreaming_buffer_bytes=256*1024*1024are the existing defaults and the existing call sites in the codebase already match those types.Discovered by
/sweep-api-consistencyagainst thegeotiffmodule on 2026-05-12.