Dev 0.5.12 - #203
Conversation
Feat/reverse complement flag
Feat/grep on sequence headers
Feat/introduce revcomp
Feat/introduce verify command
There was a problem hiding this comment.
Code Review
This pull request introduces the revcomp command to reverse complement sequences in BINSEQ files and the verify command to compute order-independent checksums using xxh3-64. It also enhances grep and split with pattern reverse-complementation (--rc), adds header-matching capabilities to grep, and prevents binary data from being implicitly written to stdout. The reviewer feedback suggests improving error handling in revcomp by explicitly bailing out when --mate 2 is requested on single-channel files and reusing the already opened BinseqReader to avoid redundant file I/O. Additionally, the reviewer recommends suppressing noisy header warnings when verifying BQ files.
| pub fn run(args: &RevcompCommand) -> Result<()> { | ||
| let reader = BinseqReader::new(args.input.path())?; | ||
| if !reader.is_paired() && args.mate != Mate::Both { | ||
| warn!("Ignoring `--mate/-M` flag as only single channel found in file"); | ||
| } | ||
|
|
||
| let builder = get_builder(args)?; |
There was a problem hiding this comment.
If a user requests --mate/-M 2 on a single-channel file, the current implementation silently ignores the flag and writes the output file completely unmodified (since rc_extended is false and rc_primary is false), while still logging that it wrote reverse-complemented records. We should explicitly bail out in this case (similar to the verify command), and warn if -M 1 is passed redundantly.
pub fn run(args: &RevcompCommand) -> Result<()> {
let reader = BinseqReader::new(args.input.path())?;
if !reader.is_paired() {
if args.mate == Mate::Two {
bail!(
"`--mate/-M 2` was requested but `{}` is single-channel (no extended/mate-2 channel)",
args.input.path()
);
} else if args.mate == Mate::One {
warn!("`--mate/-M 1` is redundant as only a single channel exists in `{}`", args.input.path());
}
}
let builder = get_builder(&reader);| @@ -0,0 +1,227 @@ | |||
| mod processor; | |||
|
|
|||
| use anyhow::Result; | |||
| fn get_builder(args: &RevcompCommand) -> Result<BinseqWriterBuilder> { | ||
| let builder = match args.input.mode()? { | ||
| BinseqMode::Bq => { | ||
| let reader = bq::MmapReader::new(args.input.path())?; | ||
| BinseqWriterBuilder::from_bq_header(reader.header()) | ||
| } | ||
| BinseqMode::Vbq => { | ||
| let reader = vbq::MmapReader::new(args.input.path())?; | ||
| BinseqWriterBuilder::from_vbq_header(reader.header()) | ||
| } | ||
| BinseqMode::Cbq => { | ||
| let reader = cbq::MmapReader::new(args.input.path())?; | ||
| BinseqWriterBuilder::from_cbq_header(reader.header()) | ||
| } | ||
| }; | ||
| Ok(builder) | ||
| } |
There was a problem hiding this comment.
Instead of re-opening and re-mapping the input file using MmapReader::new in get_builder, we can reuse the already opened BinseqReader by matching on its variants. This avoids redundant file I/O and simplifies the function signature by removing the Result wrapper.
fn get_builder(reader: &BinseqReader) -> BinseqWriterBuilder {
match reader {
BinseqReader::Bq(r) => BinseqWriterBuilder::from_bq_header(r.header()),
BinseqReader::Vbq(r) => BinseqWriterBuilder::from_vbq_header(r.header()),
BinseqReader::Cbq(r) => BinseqWriterBuilder::from_cbq_header(r.header()),
}
}| if fields.seq || fields.qual || fields.flags { | ||
| warn!( | ||
| "`{}` has no header data; excluding headers from the checksum", | ||
| args.input.path() | ||
| ); |
There was a problem hiding this comment.
BQ files (.bq) never store header data by design. Printing a warning when verifying a BQ file is noisy and unnecessary. We should suppress this warning when the reader is a BQ reader.
if fields.seq || fields.qual || fields.flags {
if !matches!(reader, BinseqReader::Bq(_)) {
warn!(
"`{}` has no header data; excluding headers from the checksum",
args.input.path()
);
}
No description provided.