Repository navigation
Declared axes: a plain stack's positional Y and X are open (v0.3.4) - #58
Merged
Merged
Conversation
tifffile reports the last two axes of any plain page as Y and X (QYX, QQYX, IYX) even when the file has no axis metadata. check_declared_axes treated them as named, so it refused a correct declaration such as YXC on a plain QYX stack (a (Y, X, C) array written without metadata). Only what the metadata names now binds a declaration. New named_axes gives the rule position by position (? for open), and both header_axes and check_declared_axes use it. TiffMetadata.axes_from_metadata records whether the axes came from axis metadata (OME, ImageJ, shaped with axes, other vendor formats, OME-NGFF). Declarations the header contradicts (ImageJ ZYX as CYX, OME or shaped CYX as YXC) are still refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VbytvBRB9CmKQ5AAkhEFcv
A brick that builds a TiffMetadata for a series other than the first (MorphoRelate's series reader) needs the same flag inspect_tiff records. A header built by hand keeps the strict default: a placeholder stack's Y and X stay binding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VbytvBRB9CmKQ5AAkhEFcv
Owner decision of 31 October 2026: a declaration that differs from the header's named axes only by swapping Y and X (CYX declared CXY, ZYX declared ZXY) means the image is read transposed and is accepted. The new declared_axes_transposed(meta, declared) tells the caller so it can record it; it raises ValueError for a declaration that does not fit. Any other disagreement stays refused (CYX as YXC, ZYX as CYX or CXY). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VbytvBRB9CmKQ5AAkhEFcv
Leaving a plain stack's positional Y and X open let a declaration with no spatial axes at all (QYX declared CTZ) pass. Refuse it by name, and correct the header_axes/contract wording: check_declared_axes accepts the header's axes, them with Y and X swapped, and S declared C, not "no others". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VbytvBRB9CmKQ5AAkhEFcv
Contributor
Author
|
Review (independent, from GitHub's current state at Checked:
Merging with a merge commit. Generated by Claude Code |
guijacquemet
marked this pull request as ready for review
October 31, 2026 14:38
guijacquemet
pushed a commit
that referenced
this pull request
Oct 31, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WX6rdMV1r5jUPUR94kxV5a
This was referenced Oct 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Core fix for v0.3.4 (owner decisions of 31 October 2026):
check_declared_axeson plain stacks, and named Y/X declared swapped. No version bump here.Summary
IYX,QYX,QQYX), even when the file has no axis metadata. Newnamed_axes(meta)is now the one rule behind bothheader_axesandcheck_declared_axes. It gives the header's axes, with?(OPEN_AXIS) for each dimension the metadata does not name. That covers the placeholders (I,Q). In a plain stack of pages it also covers the positionalYandX.TiffMetadata.axes_from_metadata, set byinspect_tifffrom the publicseries_axes_from_metadata(series). It is False for tifffilegeneric/uniformseries and for a shaped series without"axes". It defaults to True, the strict reading, for a header built by hand.check_declared_axesbinds only named positions; an open position takes any role.declared_axes_transposed(meta, declared) -> booltells callers when that happened, so they can record it. It raisesValueErrorfor a declaration that does not fit. Any other disagreement stays refused.S-> C rule are unchanged.header_axesgives exactly the same results as before. When it gives axes, the check accepts those axes and their Y/X swap, and nothing else (tested).Behaviour changes
QYX/IYX(no metadata)YXC,XYZQQYXYXZCCYXCXYdeclared_axes_transposedTrueZYXZXYYXXYCYXYXCZYXCYX,CXY,XZYIYXSTYXZScomes from a tag)Callers (GitHub main, read only, not edited)
None of the three calls
check_declared_axesonmain; each has its ownprefill_mappingcopy. The D86 adoption branches do call it.claude/d86-core, Re-pin the vendored Spec to b197ac1; reserved names apply to used_ids.channels #208): theheader_axes-gated workaround in_series_axescan go._series_headerbuildsTiffMetadataby hand for any series, so it must passaxes_from_metadata=series_axes_from_metadata(selected).claude/d86-core, PP-4: manifest version 2, row keys, per-file plain-stack confirmation #110):check_header_axes's retry with X and Y swapped is now redundant. Usedeclared_axes_transposedto record the transposition. Plain stacks declaredYXCbecome accepted, matchingmain's copy.main,io.header_axes_disagreement): it already allows swapped Y/X, so adopting the shared check now changes only these:R,A, ...) cannot be declared;Tests
tests/test_header_axes.py, plain stacks:tests/test_header_axes.py, named axes:tests/test_header_axes.py, swaps:tests/test_header_axes.py, rule and helpers:named_axesfor each writer;header_axesandcheck_declared_axes.declared_axes_transposedis missing).PYTHONPATH=src):ruff check .passed,ruff format --check .passed,pytest1394 passed, 1 skipped (the root file-mode testtest_discovery.py:665).🤖 Generated with Claude Code
https://claude.ai/code/session_01VbytvBRB9CmKQ5AAkhEFcv