Skip to content

Commit 6dd7325

Browse files
committed
0.14.0: optionally force --fasta output for fastq input
1 parent 34191f7 commit 6dd7325

8 files changed

Lines changed: 66 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.14.0] - 2026-02-25
11+
12+
### Added
13+
14+
- `deacon filter` accepts `-f`/`--fasta` to force FASTA output regardless of input format.
15+
1016
## [0.13.2] - 2025-11-21
1117

1218
### Added

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "deacon"
3-
version = "0.13.2"
4-
description = "Fast DNA search and [host] depletion using minimizers"
3+
version = "0.14.0"
4+
description = "Accelerated DNA sequence search and [host] depletion using minimizers"
55
authors = ["Bede Constantinides <b@bede.im>"]
66
edition = "2024"
77
repository = "https://github.com/bede/deacon"

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ deacon filter -d -R panhuman-1.k31w15.idx reads.fq.gz > filt.fq
130130
# Only look for minimizer hits inside the first 1000bp per record
131131
deacon filter -d -p 1000 panhuman-1.k31w15.idx reads.fq.gz > filt.fq
132132

133+
# Output FASTA regardless of input format (discards quality scores)
134+
deacon filter -d -f panhuman-1.k31w15.idx reads.fq.gz > filt.fa
135+
133136
# Debug mode: see sequences with minimizer hits in stderr
134137
deacon filter -d --debug panhuman-1.k31w15.idx reads.fq.gz > filt.fq
135138
```
@@ -193,6 +196,8 @@ Options:
193196
Replace sequence headers with incrementing numbers
194197
--rename-random
195198
Replace sequence headers with incrementing numbers and random suffixes
199+
-f, --fasta
200+
Output FASTA format regardless of input format
196201
-o, --output <OUTPUT>
197202
Path to output fastx file (stdout if not specified; detects .gz and .zst)
198203
-O, --output2 <OUTPUT2>

src/filter.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct FilterProcessorConfig {
2828
deplete: bool,
2929
rename: bool,
3030
rename_random: bool,
31+
output_fasta: bool,
3132
debug: bool,
3233
}
3334

@@ -114,9 +115,10 @@ fn format_record_to_buffer<R: Record>(
114115
counter: u64,
115116
rename: bool,
116117
rename_random: bool,
118+
output_fasta: bool,
117119
buffer: &mut Vec<u8>,
118120
) -> Result<()> {
119-
let is_fasta = record.qual().is_none();
121+
let is_fasta = output_fasta || record.qual().is_none();
120122

121123
// Header
122124
buffer.write_all(if is_fasta { b">" } else { b"@" })?;
@@ -290,6 +292,7 @@ struct FilterProcessor {
290292
deplete: bool,
291293
rename: bool,
292294
rename_random: bool,
295+
output_fasta: bool,
293296
debug: bool,
294297

295298
hasher: KmerHasher,
@@ -394,6 +397,7 @@ impl FilterProcessor {
394397
deplete: config.deplete,
395398
rename: config.rename,
396399
rename_random: config.rename_random,
400+
output_fasta: config.output_fasta,
397401
debug: config.debug,
398402
hasher: KmerHasher::new(kmer_length as usize),
399403
local_buffer: Vec::with_capacity(DEFAULT_BUFFER_SIZE),
@@ -569,6 +573,7 @@ impl FilterProcessor {
569573
self.local_stats.output_seq_counter,
570574
self.rename,
571575
self.rename_random,
576+
self.output_fasta,
572577
&mut self.local_buffer,
573578
)
574579
}
@@ -581,6 +586,7 @@ impl FilterProcessor {
581586
self.local_stats.output_seq_counter,
582587
self.rename,
583588
self.rename_random,
589+
self.output_fasta,
584590
&mut self.local_buffer2,
585591
)
586592
}
@@ -928,6 +934,7 @@ pub fn run(config: &FilterConfig) -> Result<()> {
928934
deplete: config.deplete,
929935
rename: config.rename,
930936
rename_random: config.rename_random,
937+
output_fasta: config.output_fasta,
931938
debug: config.debug,
932939
};
933940
let mut processor = FilterProcessor::new(

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ pub struct FilterConfig<'a> {
172172
/// Replace headers with sequential numbers followed by random u64 (1-12345, 2-67890, ...)
173173
pub rename_random: bool,
174174

175+
/// Force FASTA output (discards quality scores)
176+
pub output_fasta: bool,
177+
175178
/// Number of execution threads (0 = auto)
176179
pub threads: u16,
177180

@@ -203,6 +206,7 @@ impl<'a> FilterConfig<'a> {
203206
deplete: false,
204207
rename: false,
205208
rename_random: false,
209+
output_fasta: false,
206210
threads: 0, // Use all available threads by default
207211
compression_level: 2, // Default compression level
208212
compression_threads: 0, // Auto-calculate as ceil(total/2)

src/main.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ enum Commands {
6464
#[arg(long = "rename-random", default_value_t = false)]
6565
rename_random: bool,
6666

67+
/// Output FASTA format regardless of input format
68+
#[arg(short = 'f', long = "fasta", default_value_t = false)]
69+
output_fasta: bool,
70+
6771
/// Path to output fastx file (stdout if not specified; detects .gz and .zst)
6872
#[arg(short = 'o', long = "output")]
6973
output: Option<PathBuf>,
@@ -420,6 +424,7 @@ fn process_command(command: &Commands) -> Result<(), anyhow::Error> {
420424
deplete,
421425
rename,
422426
rename_random,
427+
output_fasta,
423428
threads,
424429
compression_level,
425430
compression_threads,
@@ -446,6 +451,7 @@ fn process_command(command: &Commands) -> Result<(), anyhow::Error> {
446451
deplete: *deplete,
447452
rename: *rename,
448453
rename_random: *rename_random,
454+
output_fasta: *output_fasta,
449455
threads: *threads,
450456
compression_level: *compression_level,
451457
compression_threads: *compression_threads,

tests/filter_tests.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,40 @@ fn test_filter_rename() {
283283
);
284284
}
285285

286+
#[test]
287+
fn test_filter_fasta_flag() {
288+
let temp_dir = tempdir().unwrap();
289+
let fasta_path = temp_dir.path().join("ref.fasta");
290+
let fastq_path = temp_dir.path().join("reads.fastq");
291+
let bin_path = temp_dir.path().join("ref.bin");
292+
293+
create_test_fasta(&fasta_path);
294+
create_test_fastq(&fastq_path);
295+
build_index(&fasta_path, &bin_path);
296+
297+
let mut cmd = cargo::cargo_bin_cmd!("deacon");
298+
let output = cmd
299+
.arg("filter")
300+
.arg("-f")
301+
.arg("-a")
302+
.arg("1")
303+
.arg("-r")
304+
.arg("0.0")
305+
.arg(&bin_path)
306+
.arg(&fastq_path)
307+
.assert()
308+
.success()
309+
.get_output()
310+
.stdout
311+
.clone();
312+
313+
let output_str = std::str::from_utf8(&output).unwrap();
314+
assert!(
315+
output_str.starts_with('>'),
316+
"FASTQ in with -f should gen FASTA out"
317+
);
318+
}
319+
286320
#[test]
287321
fn test_filter_min_matches() {
288322
let temp_dir = tempdir().unwrap();

0 commit comments

Comments
 (0)