Repository navigation
PP-8b: refuse X-before-Y masks in the run; RunInputs names unrecorded files - #115
Merged
Merged
Conversation
… files - A mask whose own header names X before Y (e.g. XY, TXY) is refused by check and run with mask_layout, naming the mask and its header axes and the numpy.swapaxes fix. mask_issues dropped this error together with the header size comparison it supersedes, so rc1 recorded such a mask with axes "". mask_manifest now refuses a mask without roles, and RunInputs.open refuses such an older record with its own message. - unrecorded_files lists the images discover_experiment would analyse and the masks find_masks would pair with a recorded image (masks folder, OME-Zarr label images) that the run neither recorded nor excluded. RunInputs.open always runs it and raises UnrecordedFilesError (a RunInputsError naming the files). No pixel or TIFF header is read. - Contract 9.1/15, plan questions 50 and 51, user guide, AGENTS map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
guijacquemet
marked this pull request as ready for review
November 2, 2026 07:34
…asks for --masks Owner decisions on the review questions (2 November 2026): - Without the zarr extra, RunInputs.open refuses a run holding OME-Zarr images, naming morphobricks-preprocessing[zarr], instead of skipping their label images in the unrecorded-files check. - A recorded OME-Zarr image whose labels group cannot be read is its own refusal naming the image, no longer listed as an unrecorded "<image>/labels" mask. - Unrecorded masks (also a masks_root given to a run that recorded no masks folder): the message says to run preprocessing again with the masks folder (--masks); --exclude is offered only for images. - Contract 9.1, user guide, plan question 51 record the decisions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Contributor
Author
Independent review: merged as
|
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.
This is a small fix PR that comes before PP-9 (owner decision, 2026-11-02). It comes from CellPatcher CP-2a (CellMigrationLab/CellPatcher#69, owner questions 1 and 2). It is based on
mainat501c2dc. The version stays 0.3.4.Summary
mask_checks.py:mask_issuesnow keeps themask_layouterror for a mask whose own header names X before Y.mask_layout/mask_size_mismatchissue fromfind_masks, because the size comparison by role supersedes them. But a refused header also givesmask_layout, so that error disappeared too.axes: "",shape: []._header_refusals: it keeps a size-code issue only for the masks the header check gave no roles, so it never repeats a size comparison.masks/stated.py: themask_layoutdetail names the header axes:Cells/a.tif: header axes XY: X is stored before Y. When axes were stated it adds, stated …. The fix (numpy.swapaxes(mask, -1, -2)) is in the action. This reuses the existing code and message; no new code was added.mask_record.py:mask_manifestraisesValueErrorfor a mask without roles. A manifest can never record a mask with empty axes.unrecorded.py(new, layerio):unrecorded_files(manifest, experiment_root, masks_root, output_folder=None) -> UnrecordedFiles(images, masks).discover_experimentwould analyse, less the recorded and the excluded images.find_masks's own pairing (masks.files._folder_masks, whoseimagesargument is now aCollection[str]) pairs with a recorded image;run_inputs.py:RunInputs.opennow runs_check_files: the existing fingerprint checks, then a refusal of a mask recorded without axes (its own message: "recorded … without axes … numpy.swapaxes … run preprocessing again", not "changed or missing"), then the unrecorded-files check.UnrecordedFilesError(RunInputsError). It has.files, and it pickles. Its message names up to five files per kind and says to run preprocessing again (morphobricks-preprocessing run --output <output folder>) or to exclude them (--exclude).UnrecordedFiles,UnrecordedFilesError,unrecorded_files.mask_layoutrow, a newUnrecordedFilesErrorrow, and §7 "Running again";Decisions
checkandrunwith the existingmask_layoutcode. Images are different: a header-named X-before-Y image is still read in canonical order (design change log, 2026-11-01), but masks are never reordered (design §3).RunInputs.openrefuses it for the whole run, not only atread_mask. Such a run would not be written today, so it is not a clean run.RunInputs.openalways runs it, and there is no opt-out. The reasons:discover_experimentfolder walk, plus, when a masks folder is recorded or given, anrglobof that folder, pluslabelsmetadata for each recorded OME-Zarr image.Notes for review
make_clean_runand then open the run will now getUnrecordedFilesError. That is intended.c37d58f): never skipped. Without thezarrextra,RunInputs.openrefuses a run holding OME-Zarr images, namingmorphobricks-preprocessing[zarr]. A recorded OME-Zarr image whoselabelsgroup can no longer be read is its ownRunInputsErrornaming the image (no longer listed as an unrecorded<image>/labelsmask).unrecorded_filesraisesZarrUnavailableError/NgffErrorfor these.masks_rootwhile the run recorded no masks folder, every paired mask there counts as unrecorded. The run did not use them, so a rerun is needed.mask_layoutthrough the same path, but it has no separate test, because a plain?YXstack statedTXYcontradicts the named Y first.open.Tests
tests/test_brick_checks.pyhas 10 tests.main's source (501c2dc;UnrecordedFilesErroraliased toRunInputsErrorso it imports), 9 fail:XYandTXY): the run was written;mask_manifestdid not raise;.DS_Store,Thumbs.db,._a.tif, a TIFF outside a leaf folder, an unpaired mask, a non-mask file in the masks folder) do not trigger the check..[dev,notebook,zarr], run as root.ruff check .: all checks passed.ruff format --check .: 122 files already formatted.tools/check.py --rules: passes. The baseline and# noqacounts are unchanged, andtools/code_rules_baseline.jsonwas not touched.pytest: 1519 passed, 1 skipped. Main has 1509 passed, 1 skipped. The one skip istest_discovery.py:665("running with permissions that ignore file modes", as root, as expected).§9 figures (measured on every new or changed function)
tools/code_rules.pyfor executable lines and parameters;ruff --select C901with max-complexity 0 for the complexity of each function.ruff --select C901,PLR0913,PLR0915,ANN,Dwith the §9 limits passes on every changed module.unrecorded.unrecorded_filesunrecorded._label_pathsunrecorded._folder_mask_pathsRunInputs.openRunInputs._check_filesrun_inputs._unrecorded_text/_without_axes_text/_shownmask_checks._header_refusalsmask_record.mask_manifestmasks.stated.mask_rolesmasks.files._folder_masks(annotation only)unrecorded_files,UnrecordedFiles,UnrecordedFilesError), andfrom __future__ import annotations.iois declared inpyproject.toml.discover_experiment,_folder_masks,ngff_label_namesandvalidation.plural.run_inputs.pymask_checks.pymask_record.py__init__.pymasks/stated.pymasks/files.pyunrecorded.py(new)tests/test_brick_checks.py(new)Review (independent reviewer, 2026-11-02)
c37d58f): missingzarrextra simulated withsys.modules["zarr"] = None, and an unreadablelabelsgroup. The 3 new tests fail on2e1a956..[dev,notebook,zarr], root): ruff check and format clean (122 files);tools/check.py --rulespasses, baseline untouched,# noqa73 = main; pytest 1522 passed, 1 skipped (test_discovery.py:665, root). CI green.RunInputs.openmedian 28 ms on main vs 88–103 ms here (unrecorded_filesalone ~64 ms); 0 TIFF opens/TiffFile/imreadcalls during the check (instrumented).Generated by Claude Code