Skip to main content

CountMut

Unified ultra-fast strand-aware mutation counter — C backend, Python wrapper.

CountMut counts base/substitution ratios from BAM files with fast C core and a thin Python wrapper. It fuses the two classic ways of walking a BAM:

  • pileup-based (bam_mplp_auto / pysam pileup) — fast, sees indels/ref-skips, general.
  • read-walk (countmut's "no pileup") — walk reads directly, only touch the target sites.

Both produce identical output, and the tool can process whole genomes in parallel (threads).

Why it's fast & correct

  • The hot loop (BAM read, pileup, per-(site,strand) base counting, mate-overlap dedup, quality/conversion classification) is in C (backend/countmut_core, built on the self-contained htslib subset from lh3/minipileup).
  • Strand-aware (countmut biological-strand rule for paired-end reads).
  • Paired-end overlap dedup: at an overlapping position a fragment is counted once, choosing the best mate by (mapq, read1, base-qual) — the thing minipileup gets wrong.
  • Parallel: divides the genome into bins and processes them across threads (--threads).
  • Memory-clean (verified under AddressSanitizer).

Install

pip install -e .
# or, to prebuild the C core:
make backend

Quick start

# strand-aware A->G mutation count (bisulfite / m6A style)
countmut -i in.bam -r ref.fa -o mut.tsv --ref-base A --mut-base G

# per-site base counts (perbase/mpileup style)
countmut -i in.bam -r ref.fa --mode base -o depth.tsv

# alleles -> VCF (minipileup style)
countmut -i in.bam -r ref.fa --mode allele --vcf -o allele.vcf

Modes

Mode Output
mutation chrom pos strand motif u0 u1 u2 m0 m1 m2 [o0 o1 o2] (strand-aware substitution table)
base chrom pos [strand] ref depth a c g t n [ins del ref_skip fail]
allele chrom pos ref depth ref_count alt alt_count, or VCF with --vcf

Filtering with expressions (-e / -p)

Filtering is done with samtools-style filter expressions — there are no separate --min-mapq/--min-baseq/--trim-* flags; write them as expressions instead.

  • -e, --expression <STR> — per-base read filter (samtools SAM fields).
  • -p, --pile-expression <STR> — per-site filter (pileup fields).

Grammar is the samtools filter=STRING expression language (C-style precedence, &&/||/!, bit fields, tags, regex). See docs/filter_grammar.md.

# keep high-quality, non-5prime, properly paired reads
countmut -i x.bam -r ref.fa -e "mapq >= 20 && bq >= 20 && dist5 >= 2 && flag & PROPER_PAIR"

# restrict to one RG group
countmut -i x.bam -r ref.fa -e "tag('RG') == 'sampleA'"

# report only A-reference sites with depth >= 5 and > 2 G alleles
countmut -i x.bam -r ref.fa -p "ref == 'A' && depth >= 5 && g > 2"

Read variables: mapq, flag (+ flag.dup, flag.unmap, ...), qname, pos, endpos, pnext, rname, mrname, tlen, qlen, rlen, ncigar, seq, qual, sclen, hclen, bq, dist5/dist3, strand, [NM]/[RG] tags, avg(qual), exists([NM]), sqrt(mapq), ...

Site variables: depth, pos, ref, a c g t n, ins, del, ref_skip, fail.

When -e/-p is given, counting runs on the Python engine (the C core cannot evaluate strings). Without expressions, the fast C backend is used.

Engine selection

--engine {auto|read-walk|pileup} (default auto):

  • auto → read-walk for mutation (targeted sites), pileup for base/allele.
  • read-walk / pileup → force a strategy.

Options

-i/--input, -r/--reference, -o/--output
--mode {mutation,base,allele}   --engine {auto,read-walk,pileup}
--region, --threads/-t
--ref-base, --mut-base, --pad, --save-rest
--split-strand, --count-indels, --min-depth, --min-allele-support, --vcf
-e/--expression, -p/--pile-expression

Design

countmut/
  cli.py               rich CLI (routes to the C core directly)
  backend.py           builds/loads the C binary and calls it
  model.py             FilterConfig / MutationConfig / StrandConfig / EngineConfig
  core.py              the original pure-Python countmut (legacy reference)
backend/
  countmut_core.c      computation core: read-walk AND pileup engines,
                       mate-overlap dedup, -e/-p Lua filters (embedded lua5.4)
  countmut_expr.c      Lua filter-expression evaluator (-e / -p)
  countmut_core_main.c CLI wrapper
  Makefile             builds the `countmut_core` binary (links lua5.4)

Both BAM-walk strategies (--engine read-walk and --engine pileup) are implemented in C; Python is a thin wrapper and does no counting. -e/-p filters are embedded-Lua expressions (see docs/filter_grammar.md), evaluated in C identically by both engines.

Both walks fill the same per-site, per-strand base counts and emit byte-identical output -- the two strategies are interchangeable, with identical results (and identical -e/-p filtering) whether you pick read-walk or pileup.

References this tool learns from

  • minipileup — pileup walk, filters, allele counting
  • perbase / pbr — mate-aware overlap dedup, base counts
  • countmut — biological strand, bisulfite NS/Zf/Yf tiers
  • mpileup / cpup — base-count output
  • samtools --input-fmt-option filter=STRING — the expression grammar

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

countmut-0.1.5.tar.gz (38.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

countmut-0.1.5-py3-none-any.whl (29.9 kB view details)

Uploaded Python 3

File details

Details for the file countmut-0.1.5.tar.gz.

File metadata

  • Download URL: countmut-0.1.5.tar.gz
  • Upload date:
  • Size: 38.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for countmut-0.1.5.tar.gz
Algorithm Hash digest
SHA256 7aa83912f695b8f905872cef8d1d68d49dc2f41a3fbc8e9b7d8ba0e9f78c6db9
MD5 15274fd7aafcca7aaebb03917d7e5752
BLAKE2b-256 aca557c5ec0d035a98d0207f42e8c63698000b8d37cf9eb8d6e7cf3e6813c82d

See more details on using hashes here.

Provenance

The following attestation bundles were made for countmut-0.1.5.tar.gz:

Publisher: publish.yml on y9c/countmut

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file countmut-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: countmut-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 29.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for countmut-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 7c292ab7450d471c6b050b74de00d8ed27b63c52a49376c89399a7f3738ef3ad
MD5 9401b7225cca32b581e31147875f2937
BLAKE2b-256 3c136e5276abc7fa0091e7743b16c99e94957cc5286fd97846842e65940bd811

See more details on using hashes here.

Provenance

The following attestation bundles were made for countmut-0.1.5-py3-none-any.whl:

Publisher: publish.yml on y9c/countmut

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.0

2 files

0.1.6

2 files

This release

0.1.5 This release

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page