Skip to content

fix: Make write_cog refuse or apply every option it is given - #75

Merged
kylebarron merged 1 commit into
mainfrom
fix/write-cog-ignored-options
Oct 1, 2026
Merged

kylebarron merged 1 commit into
mainfrom
fix/write-cog-ignored-options

Conversation

@kylebarron

Copy link
Copy Markdown
Member

Note

This PR was written by Claude (Claude Code), not by @kylebarron.

Follow-up to #74. Reviewing #74 turned up other ways write_cog can write a fixture without an option it was given. GDAL only logs a warning when it ignores a creation option, and the generators never show rasterio's log, so these failures are silent.

Changes

  • A predictor with a codec that can't use it now raises ValueError. GDAL only writes a predictor for DEFLATE, LZW and ZSTD. JPEG, WEBP, LERC and PACKBITS drop it with a logged warning. LZMA drops it with no warning at all: GDAL's option check lists LZMA as taking a predictor (gtiffdataset_write.cpp), but GTIFFSupportsPredictor, which writes the tag, leaves it out. GDAL master is the same.
  • nodata is respected. With the default nodata_type="nodata", a nodata you passed was overwritten with 0. Now 0 is only the default.
  • scale and offset apply independently. Before, they were only applied when both were given.
  • Removed tiled=True and copy_src_overviews=True. The COG driver doesn't support either, so they only logged a warning on every write.

Not changed: raising on every GDAL warning

The #74 review suggested making write_cog raise whenever GDAL logs CPLE_NotSupported. That doesn't work cleanly. GDAL also logs '64' is an unexpected value for BLOCKSIZE creation option that should be >= 128 for every fixture with 64×64 tiles, even though it writes those tiles. A blanket check would need exceptions keyed on message text.

Instead, test_no_ignored_creation_options asserts that a plain write_cog call logs no warnings, which would have caught the two dead options. I also ran every generator with rasterio's log captured. With this change, the BLOCKSIZE warning is the only one left.

Tests

tests/test_write_cog.py calls write_cog directly into tmp_path and checks:

  • predictor 2 with each supported codec, and predictor 3 on float data
  • ValueError for JPEG, LERC, LZMA, PACKBITS and WEBP
  • nodata, scale and offset
  • no logged warnings

9 of its 16 cases fail on main. To let tests import the generators, pyproject.toml gains pythonpath = ["."]. #73 adds the identical lines, so that part merges cleanly.

No fixture changes: pixi run check regenerates every fixture byte for byte. pixi run test passes.

Merging with #73

#73 adds rewrite_big_endian directly below the copy(...) call this PR edits, so whichever lands second will likely get a one-line conflict.

🤖 Written by Claude Code

GDAL only logs a warning when it ignores a creation option, and the
generators never show rasterio's log, so write_cog could silently write a
fixture without an option it was asked for, as happened with the predictor
in #74.

- Raise a ValueError when a predictor is combined with a codec other than
  DEFLATE, LZW or ZSTD. GDAL drops it for the others; for LZMA it doesn't
  even warn, although its own check says LZMA takes a predictor.
- Keep a `nodata` value passed with the default nodata_type instead of
  overwriting it with 0.
- Apply `scale` and `offset` independently instead of only when both are
  given.
- Drop `tiled` and `copy_src_overviews`, which the COG driver doesn't
  support, so they only produced warnings on every write.

No fixture changes: every existing call either passes a supported codec,
nodata=0, or both scale and offset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@kylebarron kylebarron left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

"driver": "COG",
"interleave": interleave,
"compress": "DEFLATE",
"tiled": True,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this automatic in the cog_profile?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This reply was written by Claude (Claude Code), not by @kylebarron.

Yes. The COG driver always tiles: it writes the file with TILED=YES and takes the tile size from BLOCKSIZE (cogdriver.cpp#L1204-L1208). TILED isn't one of its own creation options, so passing it only logged driver COG does not support creation option TILED.

The same lines set COPY_SRC_OVERVIEWS=YES, so dropping copy_src_overviews=True is a no-op too. Without either option, pixi run check still regenerates every fixture byte for byte.

🤖 Written by Claude Code

@kylebarron
kylebarron merged commit 60ccc2d into main Oct 1, 2026
1 check passed
@kylebarron
kylebarron deleted the fix/write-cog-ignored-options branch October 1, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant