Skip to content

load_design raises DesignCheckError for an unreadable experiment_design.csv - #62

Merged
guijacquemet merged 1 commit into
mainfrom
claude/load-design-raises
Oct 31, 2026
Merged

guijacquemet merged 1 commit into
mainfrom
claude/load-design-raises

Conversation

@guijacquemet

Copy link
Copy Markdown
Contributor

Summary

Owner decision of 31 October 2026 (plan §12 question 43, follow-up to PR #61). This is a breaking API change for the next release.

  • design.py: when the saved experiment_design.csv cannot be read, load_design(output_folder, repeats) now raises DesignCheckError. Before, it returned the default design together with a problem string. The error holds one issue, unreadable_experiment_design. Its message is read_confirmed_design's "The experiment design cannot be read: …" followed by the lenient reader's refusal, which names the line and column (for example experiment_design.csv, line 2, column confirmed_on: '26/10/2026' is not a date in the form YYYY-MM-DD …). The issue also gives the path and a suggested action, and the DesignFormatError is its __cause__. No default design is returned and the file is not touched. The return value is now (design, changes). The issue builder is shared with read_confirmed_design (_unreadable), so both readers give the same refusal text.
  • notebook_ui.py (_open_design): catches the error and keeps the PR Keep an unreadable experiment_design.csv untouched in step 1 #61 behaviour: the file is left untouched, the refusal is shown in the red box, the questions start unanswered, and an explicit answer replaces the file.
  • cli.py (check): prints the refusal and its suggested action and writes nothing. The exit code is unchanged. run never called load_design: it uses read_experiment_design and already refused such a file without writing it.
  • Docs: contract §12 (Reading and Notebook rows) and §16 (Experiment design row, with the breaking-change note), user guide §5 (check), §8 (message code) and §9 (Python example), and plan §12 question 43.

Decisions

  • Error type. I reused the existing DesignCheckError with the existing code unreadable_experiment_design, so the error carries a ValidationIssue (code, message, paths, action) like the rest of the brick. It is still a ValueError. DesignFormatError stays the lenient reader's own error and is chained as __cause__.
  • Missing file. I kept the existing behaviour: load_design returns the default design and DesignChanges(). A missing file is the normal first run, not an unreadable file. A path that exists but cannot be read (for example a folder named experiment_design.csv, or an I/O error) does raise.
  • Third return value. I dropped the third value (problem) rather than keeping it as an always-None field. Old callers that unpack three values now fail loudly instead of silently ignoring a field that no longer means anything.

Uses in other bricks (read-only grep of the local checkouts, not edited)

There are no uses of load_design or its problem value in CellPatcher (32b8f8a), MorphoCoverage (beadc9d), MorphoEmbed (f0092aa), MorphoFeature (60a7832), MorphoObjects (b5cafef), MorphoRelate (5ccbaac), fiberfeatures (e2f5b97) or morphobricks-normalization (f784c95). Those bricks read the design with read_confirmed_design, or with their own readers. The SHAs are the local checkout HEADs, which may be behind their remotes.

Notes for review

Tests

  • New regression tests in tests/test_design.py:
    • load_design raises for a re-saved date, an NA repeat group, and a file without the columns (parametrised), and for a folder in place of the file. Each case checks the code, the message with its line and column, the path, the action and the cause, and that the file is unchanged.
    • A missing file gives the default design.
    • A saved design is read and reconciled.
    • check refuses an unreadable design without writing it.
  • On old main (febe0a8), all 7 new tests fail: the unreadable cases with "DID NOT RAISE DesignCheckError", the two return-value tests with "too many values to unpack", and the CLI test because the message differs.
  • Locally (Python 3.13, zarr 3.4.2, extras dev,notebook,zarr): ruff check . passes, ruff format --check . reports 74 files already formatted, and pytest gives 1469 passed, 1 skipped. The skip is tests/test_discovery.py:665, "running with permissions that ignore file modes" (the run was as root), and is unrelated to this change.

Generated by Claude Code

Owner decision of 31 October 2026 (plan §12 question 43): the public
load_design() no longer returns the default design together with a
`problem` string when the saved experiment_design.csv cannot be read.
It raises DesignCheckError with the one error
unreadable_experiment_design, whose message is read_confirmed_design's
"The experiment design cannot be read: ..." followed by the lenient
reader's refusal naming the line and column; the DesignFormatError is
its __cause__. It now returns (design, changes). Without a file it
still returns the default design (the first run, not an unreadable
file).

Callers keep their behaviour: notebook step 1 leaves the file
untouched, shows the refusal and replaces the file only on an answer
(question 42); `check` prints the refusal and its suggested action and
writes nothing. Contract §12 and §16, the user guide and plan §12
record it as a breaking change for the next release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WX6rdMV1r5jUPUR94kxV5a
@guijacquemet
guijacquemet merged commit 81d0be2 into main Oct 31, 2026
7 checks passed
@guijacquemet
guijacquemet deleted the claude/load-design-raises branch November 1, 2026 18:05
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.

2 participants