Skip to content

FileParser.from_bytes falls back to from_fileobj - #311

Merged
balbasty merged 1 commit into
mainfrom
claude/feat/297-fileparser-bytes-fileobj
Oct 6, 2026
Merged

balbasty merged 1 commit into
mainfrom
claude/feat/297-fileparser-bytes-fileobj

Conversation

@balbasty

@balbasty balbasty commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Part of #297.

Problem. FileParser.from_fileobj reads the whole stream and hands it to from_bytes, but FileParser.from_bytes raises ParserNotImplementedError. So a binary format that implements only from_fileobj, because it reads just a header from a stream, couldn't be loaded from bytes. Hdf5Parser, and the metadata parsers in #310, each worked around this with their own from_bytes = from_fileobj(BytesIO(...)).

Change.

  • When a class has its own from_fileobj, FileParser.from_bytes now wraps the bytes in io.BytesIO and calls it.
  • A parser that implements neither still raises ParserNotImplementedError, without recursing:
    • "its own" skips methods that only forward to super(): the FileParser default and FormatDispatcher's forwarder, both tagged by a small marker decorator.
    • A guard stops a re-entrant from_bytes for the same class, for forwarders that aren't tagged (e.g. FNIRT, NIfTI fields, arrays).
  • TextFileParser.from_bytes is unchanged (it still decodes to text).
  • Hdf5Parser.from_bytes is removed; it was identical to the new default.

Tests. Seven new tests in tests/test_io_parsers.py:

  • a fileobj-only parser loads from bytes, through from_content, and from a subclass;
  • a parser with neither method raises, from bytes and from a stream;
  • an untagged forwarding from_fileobj raises instead of recursing;
  • a bytes-only parser still loads from a stream;
  • mixing in FormatDispatcher isn't mistaken for an override;
  • text parsers still decode.

Full suite: 4978 passed. Ruff and codespell are clean.

Once this merges, #310 drops its MetadataParser.from_bytes override.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VmK1jLTwd2hMkvYnMWEyYw


Generated by Claude Code

)

The default `FileParser.from_bytes` now wraps the bytes in `io.BytesIO`
and calls `from_fileobj` when the class implements `from_fileobj`
itself, so a binary format that only reads a header from a stream can
be loaded from bytes. Pass-through implementations (the `FileParser`
default and the `FormatDispatcher` forwarder) are marked and skipped
when walking the MRO, and a re-entry guard catches unmarked forwarders,
so a parser with neither entry point still raises
`ParserNotImplementedError` instead of recursing.

`Hdf5Parser.from_bytes` was identical to the new default and is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmK1jLTwd2hMkvYnMWEyYw
@balbasty
balbasty merged commit ec48233 into main Oct 6, 2026
5 checks passed
@balbasty
balbasty deleted the claude/feat/297-fileparser-bytes-fileobj branch October 6, 2026 11:26
balbasty pushed a commit that referenced this pull request Oct 6, 2026
…e wiring

Brings the operation objects (`derive(operation)`), the hidden `format`
of the format classes, and origin/main with #311. The images and the
Zarr pyramid move to `derive(operation)` in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmK1jLTwd2hMkvYnMWEyYw
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