Skip to content

geotiff: write_geotiff_gpu accepts file-like+cog where to_geotiff rejects #1652

@brendancol

Description

@brendancol

Summary

to_geotiff rejects two combos that write_geotiff_gpu accepts and processes successfully:

  • to_geotiff(gpu=True, path=BytesIO) raises ValueError ("gpu=True is not supported for file-like destinations"). write_geotiff_gpu(cupy_data, BytesIO) writes valid TIFF bytes to the buffer.
  • to_geotiff(cog=True, path=BytesIO) raises ValueError. write_geotiff_gpu(cupy_data, BytesIO, cog=True) writes a COG to the buffer.

The path : str annotation on write_geotiff_gpu says only string paths are accepted, so the file-like support is undocumented yet functional. The cog=True block on to_geotiff predates the BytesIO support that landed for the eager numpy path.

Reproducer

import io, numpy as np, xarray as xr, cupy
import xrspatial.geotiff as geo

arr = np.arange(64*64, dtype=np.float32).reshape(64, 64)
da_cpu = xr.DataArray(arr, dims=['y', 'x'])
da_gpu = xr.DataArray(cupy.asarray(arr), dims=['y', 'x'])

# 1. to_geotiff(gpu=True, file-like) rejected
buf = io.BytesIO()
try:
    geo.to_geotiff(da_gpu, buf)  # auto-dispatches to GPU
except ValueError as e:
    print('to_geotiff(gpu_data, BytesIO):', e)

# 2. write_geotiff_gpu(file-like) accepted (round-trips fine)
buf = io.BytesIO()
geo.write_geotiff_gpu(da_gpu, buf)
print('write_geotiff_gpu(BytesIO): bytes=', len(buf.getvalue()))

# 3. write_geotiff_gpu(file-like, cog=True) accepted
buf = io.BytesIO()
geo.write_geotiff_gpu(da_gpu, buf, cog=True)
print('write_geotiff_gpu(BytesIO, cog=True): bytes=', len(buf.getvalue()))

Severity

MEDIUM (Cat 5, public API surface drift). to_geotiff is the documented preferred entry point; users who follow that path miss capabilities that the explicit GPU writer exposes silently.

Fix options

  1. Drop the file-like block in to_geotiff for the GPU path now that write_geotiff_gpu proves it works. Verify the BytesIO round-trip through open_geotiff in CI.
  2. Drop the cog=True file-like block in to_geotiff. The CPU COG assembler also writes to bytes via _write_bytes; the comment about "atomic rename" is only true for the streaming path.
  3. Add matching ValueError guards to write_geotiff_gpu to mirror to_geotiff's stricter contract. Document path as "string path only" in both writer docstrings.

Option 1 + 2 expose existing capabilities. Option 3 is the conservative direction.

Related

This is the GPU-write analog to #1511 (which fixed reader file-like support). The reader side now consistently accepts BytesIO; the writer side still has the gpu=True and cog=True gates on to_geotiff that don't apply to the lower-layer writer.

Deprecation impact

None. The contract change is additive (accepting cases that currently raise).

Found by /sweep-api-consistency on 2026-05-11.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions