Repository navigation
Conversation
Autodetect uBAM input (file or stdin) and write the same format by default; --output-format converts between FASTQ and BAM. Uses noodles (pure Rust, keeps the static musl build simple). BAM records are given to the unchanged filters and trimmers as a FASTQ view, and BAM output starts from the original record, so every tag keeps its type and order and the header is passed through with a chained @pg line. FASTQ to FASTQ output is byte-identical to v0.14.1, checked against digests of the release's output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add chopper's @pg unchained when the input's PP chain is dangling or cyclic, instead of panicking inside noodles. - Rewrite SO to unsorted (dropping GO/SS) when output order or names can change: more than one thread, or split-by-low-quality. - Reject secondary, supplementary and reverse-complemented records. - Flush stdout after the BGZF EOF block, so a failed final write is not ignored at exit. - Report read names BAM cannot hold as a record error naming the read. - Skip tag parsing when there are no tags to rewrite; give BGZF a quarter of --threads instead of as many again. - Tests for each of the above, gzipped FASTQ from file and stdin, legacy Mm/Ml tags in BAM, and multithreaded split output with --update-mods. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mates are filtered and trimmed independently, so a pair could lose one mate or be split into renamed segments while the remaining records stay flagged as paired, which breaks tools that rely on pairing. Fail with a clear error instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # Cargo.lock
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.
Closes #79. chopper now reads unaligned BAM (uBAM), the default output of ONT basecallers, and can write it. The format is detected automatically. This PR changes I/O only: filtering, trimming, thresholds and FASTQ output are untouched.
Design
Crate: noodles (
noodles-bam,-sam,-bgzf). It is pure Rust and MIT-licensed. I didn't use rust-htslib because it would pull in a C build of htslib (clang/bindgen), which complicates the static musl release binaries.One pipeline for both record types. Filters and trimmers keep taking
&fastq::Record. A BAM record gets a FASTQ view and keeps its original record alongside it:get_valid_segmentsand everyTrimStrategyare unchanged.--update-modsworks for BAM without changes becausemodtagsalready operates on the SAM text ofMM/ML/MN.Detection. BAM is BGZF, i.e. gzip, so it goes through the existing gzip decoder and is recognised by the decompressed
BAM\1magic. stdin is now peeked for gzip so thatcat x.bam | chopperworks. Side effect: gzipped FASTQ on stdin, which used to fail to parse, now works too.Output format defaults to the input format. A new flag,
--output-format fastq|bam, converts between them; it is needed for the two cross-format cases.Tags and header on a round trip
@HD/@RG/@PG/@CO…) plus a@PG ID:chopperchained viaPPafter the last program_segment_N), seq and qual change, plusMM/ML/MNwith--update-mods, which are replaced in place. Flags kept.samtools fastq -T '*'. Byte-identical to htslib's formatting for the fixture.@HD VN:1.6 SO:unknown+@PGCO:Z:. Flag 4.Nothing is dropped silently. The known limitations, all documented in the README:
itype.RG:Z:tag gets no@RGheader line.qs,ns,ts,du,mv) go stale, as they already did for FASTQ.The following are fatal errors rather than lossy output:
COtagBug caught along the way
With
--update-mods, a split segment that keeps no modification calls gets an emptyML:B:C. The SAM spec allows this, but noodles' SAM parser rejects it.text_to_tagsnow builds empty arrays itself; there is a unit test for it.Validation
test-data/regression/v0.14.1.sha256holds digests of the v0.14.1 release binary's output for 14 command lines: every trim approach, the GC/quality/contam filters,--inverse,--update-mods, a multi-threaded run (order-insensitive) and stdin input.fastq_output_is_identical_to_v0_14_1checks them. I also compared a wider set by hand, at-t 1and-t 4and including gzip input and stderr. All identical.--update-mods(28 segments), I decoded the original and the output reads independently with htslib'smodified_bases. Every surviving call lands atpos - startwith the same probability,MNequals the segment length, every other tag is unchanged in value, type and order, and sequence/qualities equal the slice.test-data/ubam/are synthetic: 6 seeded random reads with dorado-like tags and header. They are written by htslib throughmake_fixtures.py, so tests compare against an independent implementation.make ci, the 4#[ignore]d smoke tests and clippy-D warningsare clean. I did not runmake musllocally (no musl-gcc here); the new crates are pure Rust.Performance (rough, release build, 4 threads, ~200 MB of reads)
FASTQ→FASTQ 0.09 s · BAM→BAM 0.78 s · BAM→FASTQ 0.59 s · FASTQ→BAM 0.71 s. BAM input is decompressed on one thread (the existing
MultiGzDecoder). BAM output uses noodles' multithreaded BGZF writer with--threadsworkers. A multithreaded BGZF reader would be a natural follow-up if BAM input throughput matters.Test output
🤖 Generated with Claude Code