Needletail

repository·master·Indexed 42 days ago

https://github.com/onecodex/needletail

A high-performance, minimal-copying FASTA/FASTQ parser and k-mer processing library for Rust and Python. Version 0.7.3 provides tools for sequence manipulation, including normalization, reverse complements, and canonical k-mer counting, designed to match the speed of the readfq C library.

Tokens
10.8K
Snippets
47
Records
55
Agent score
49%

What's inside Needletail

  1. Overview of Needletail

    master
    Needletail is a minimal-copying FASTA/FASTQ parser and k-mer processing library for Rust. It is designed for high performance, aiming to match the speed of the readfq C library for FASTX parsing and providing significantly faster k-mer counting than equivalent Python implementations.
  2. Build the Python library

    master

    To develop or build the Python bindings, use maturin.

    Local development (macOS/Unix):

    pip install maturin
    maturin develop --cargo-extra-args="--features=python"

    Build binary wheels for PyPI (macOS):

    maturin build --features python --release --strip

    Build binary wheels for PyPI (Linux via Docker):

    docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin:main build --features=python --release --strip -f
    twine upload target/wheels/*
  3. Install Needletail (Rust)

    master

    Needletail requires rust and cargo. You can install them via your local package manager or rustup.

    To add to your project:

    [dependencies]
    needletail = "0.6.0"

    To install for development:

    git clone https://github.com/onecodex/needletail
    cargo test
  4. Use the FastxReader iterator

    master

    The FastxReader class is an iterator returned by the parsing functions. It allows you to loop through sequence records in a file or string efficiently. Each iteration yields a Record object.

    reader = parse_fastx_file("example.fasta")
    for record in reader:
        # process record
        pass
  5. Represent k-mers using BitKmer and BitKmerSeq

    master

    K-mers are represented using a compact binary format to save space and speed up processing:

    • BitKmerSeq: A u64 containing the bit-packed nucleic acid bases.
    • BitKmer: A tuple of (BitKmerSeq, u8), where the u8 represents the length ($k$) of the k-mer.

    Bases are encoded as 2-bit values: A=0, C=1, G=2, T=3 (case-insensitive).

  6. Use Needletail in Rust

    master

    To use Needletail in a Rust project, add it to your Cargo.toml. You can parse FASTA/FASTX files using parse_fastx_file, which returns an iterator over records. Each record provides methods for sequence manipulation such as num_bases(), normalize(), reverse_complement(), and canonical_kmers() for k-mer processing.

    extern crate needletail;
    use needletail::{parse_fastx_file, Sequence, FastxReader};
    
    fn main() {
        let filename = "tests/data/28S.fasta";
    
        let mut n_bases = 0;
        let mut n_valid_kmers = 0;
        let mut reader = parse_fastx_file(&filename).expect("valid path/file");
        while let Some(record) = reader.next() {
            let seqrec = record.expect("invalid record");
            // keep track of the total number of bases
            n_bases += seqrec.num_bases();
            // normalize to make sure all the bases are consistently capitalized and
            // that we remove the newlines since this is FASTA
            let norm_seq = seqrec.normalize(false);
            // we make a reverse complemented copy of the sequence first for
            // `canonical_kmers` to draw the complemented sequences from.
            let rc = norm_seq.reverse_complement();
            // now we keep track of the number of AAAAs (or TTTTs via
            // canonicalization) in the file; note we also get the position (i.0; in the
            // event there were `N`-containing kmers that were skipped) 
            // and whether the sequence was complemented (i.2) in addition to
            // the canonical kmer (i.1)
            for (_, kmer, _) in norm_seq.canonical_kmers(4, &rc) {
                if kmer == b"AAAA" {
                    n_valid_kmers += 1;
                }
            }
        }
        println!("There are {} bases in your file.", n_bases);
        println!("There are {} AAAAs in your file.", n_valid_kmers);
    }
  7. Python Record API and Sequence Utilities

    master

    When iterating through files in Python, you receive Record objects with the following attributes and methods:

    Attributes:

    • id: The record identifier (string).
    • seq: The sequence (string).
    • qual: The quality scores (Optional string).

    Methods:

    • is_fasta(): Returns true if the record is FASTA format.
    • is_fastq(): Returns true if the record is FASTQ format.
    • normalize(iupac: bool): Mutates self.seq to normalize it.

    Standalone Utilities:

    • normalize_seq(seq: str, iupac: bool): Returns a normalized version of the sequence without mutating the original.
    • reverse_complement(seq: str): Returns the reverse complement of the sequence. This does not raise errors for invalid characters.
  8. Use Needletail in Python

    master

    The Python library provides iterators to parse FASTA/FASTQ data from either a file path or a string. All parsing errors raise a NeedletailError.

    from needletail import parse_fastx_file, NeedletailError, reverse_complement, normalize_seq
    
    try:
        for record in parse_fastx_file("myfile.fastq"):
            print(record.id)
            print(record.seq)
            print(record.qual)
    except NeedletailError:
        print("Invalid Fastq file")
  9. Decode Phred quality scores with `decode_phred`

    master

    Use the decode_phred function to convert ASCII-encoded Phred quality strings into numeric quality scores. You must specify the correct PhredEncoding for the input data.

    Parameters:

    • qual: A slice of bytes (&[u8]) representing the encoded quality characters.
    • encoding: A PhredEncoding variant (Phred33 or Phred64).

    Returns:

    • Ok(Vec<u8>): A vector of decoded numeric scores.
    • Err(PhredOffsetError): Returned if any character in the input has an ASCII value lower than the specified encoding's offset.
    use needletail::quality::{decode_phred, PhredEncoding};
    
    let qual_bytes = b"#</</BBFFFBF<";
    let scores = decode_phred(qual_bytes, PhredEncoding::Phred33).unwrap();
    // scores will be vec![2, 27, 14, 27, 14, 33, 33, 37, 37, 37, 33, 37, 27]
  10. Use the FastaReader to parse FASTA files

    master

    The Reader struct (specifically used as a FastaReader) provides a way to parse uncompressed FASTA files. It implements the FastxReader trait, allowing you to iterate through sequence records.

    Note: This reader does not handle decompression. If you are unsure of the file format or if it is compressed, use parse_fastx_file instead.

    To use it, you can create a reader from a byte slice or directly from a file path.

    use needletail::parser::{FastaReader, FastxReader};
    
    // From a byte slice
    let fasta = b">id\nSEQUENCE";
    let mut reader = FastaReader::new(&fasta[..]);
    let record = reader.next().unwrap().unwrap();
    assert_eq!(record.id(), b"id");
    
    // From a file path
    let mut reader = FastaReader::from_path("seqs.fasta").unwrap();
  11. Compute reverse complements

    master

    The reverse_complement(seq) function computes the reverse complement of a nucleotide sequence string.

    Warning: This function is designed for nucleotide sequences only. Using it on protein sequences will result in incorrect processing.

    from needletail import reverse_complement
    
    seq = "ACTG"
    rev_comp = reverse_complement(seq)
    # Result: "CAGT"
  12. Get the canonical BitKmer

    master

    The canonical function returns the lexicographically lowest version between a BitKmer and its reverse complement. It returns a tuple (BitKmer, bool), where the boolean is true if the returned k-mer is the reverse complement, and false if it is the original.

    let kmer = (some_u64, k_len);
    let (canonical_kmer, was_rc) = canonical(kmer);