Skip to content

Add BGEN support via shared encoder-server stack#17

Merged
jeromekelleher merged 5 commits into
sgkit-dev:mainfrom
jeromekelleher:bgen-initial
May 13, 2026
Merged

Add BGEN support via shared encoder-server stack#17
jeromekelleher merged 5 commits into
sgkit-dev:mainfrom
jeromekelleher:bgen-initial

Conversation

@jeromekelleher

Copy link
Copy Markdown
Member

No description provided.

Factor the plink_* modules into format-agnostic encoder_* modules
driven by a FormatSpec (PLINK_SPEC, BGEN_SPEC in biofuse.formats),
and add mount-bgen alongside mount-plink. The wire-protocol metadata
header is now variable-arity (n_static + per-static sizes + bodies)
so the same handshake serves either format's sidecar set. BGEN serves
.bgen + .sample + .bgen.bgi; the .bgi SQLite sidecar is materialised
to a tempfile at session-init time and held in the worker's memory.
Encoder dispatch is duck-typed over vcztools.format_encoder.FormatEncoder
(total_size + read(off, size) + context manager), so both
BedEncoder and BgenEncoder plug into the same per-connection loop.
bgenix and qctool aren't on most CI images; plink2 is, and it's already
the canonical PLINK 1.9 binary check elsewhere in the suite. The new
test runs plink2 --bgen --freq against the FUSE mount and against a
side-by-side copy of the encoder's bytes, then byte-compares the
resulting .afreq files. Uses ref-first to match the VCZ allele order
vcztools writes (allele 0 = REF).
The parent-list pair (static_bytes positional list + static_suffixes
tuple) was brittle: callers had to keep index alignment in sync.
Replace it with a single static_files: dict[str, bytes] on the client
and server session, keyed by suffix. FormatSpec.build_static_bytes
becomes build_static_files; the wire still serialises in
spec.static_suffixes order so the protocol is unchanged, and the
server now validates that the builder's keys match the spec's
declared suffix set.
Switch _build_bgen_static to tempfile.TemporaryDirectory so the .bgi
scratch file is cleaned up by the context manager rather than a manual
try/finally. Drop imports that existed only for type annotations
(contextlib, vcztools.format_encoder, vcztools.retrieval in formats.py;
vcztools.retrieval in encoder_server.py) per the new CLAUDE.md rule:
"Use type annotations sparingly, and avoid complex annotations
requiring imports from external libraries." FormatSpec's two function
fields become bare Callable; helper params lose their VczReader
annotation.
The previous test read the bytes out and wrote them to a sidecar copy
just to satisfy sqlite3.connect's path argument. Open the mounted
.bgen.bgi directly via a sqlite3 URI with mode=ro instead — that
skips the -journal sidecar creation that a default RW open would
attempt against the read-only mount.
@jeromekelleher
jeromekelleher merged commit a86b683 into sgkit-dev:main May 13, 2026
5 checks passed
@jeromekelleher
jeromekelleher deleted the bgen-initial branch May 13, 2026 15:52
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