countmut 0.3.1__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {countmut-0.3.1/countmut.egg-info → countmut-0.3.2}/PKG-INFO +1 -1
- {countmut-0.3.1 → countmut-0.3.2}/backend/countmut_core.c +18 -10
- {countmut-0.3.1 → countmut-0.3.2}/countmut/_core/countmut_core +0 -0
- {countmut-0.3.1 → countmut-0.3.2/countmut.egg-info}/PKG-INFO +1 -1
- {countmut-0.3.1 → countmut-0.3.2}/pyproject.toml +1 -1
- {countmut-0.3.1 → countmut-0.3.2}/tests/test_correctness.py +34 -0
- {countmut-0.3.1 → countmut-0.3.2}/LICENSE +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/MANIFEST.in +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/README.md +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/Makefile +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/bedidx.c +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/countmut_core.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/countmut_core_main.c +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/countmut_expr.c +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/countmut_expr.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/ketopt.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/khash.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/kseq.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/ksort.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/kstdint.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/backend/kstring.h +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut/__init__.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut/backend.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut/bam_tags.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut/cli.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut/core.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut/model.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut/utils.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut.egg-info/SOURCES.txt +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut.egg-info/dependency_links.txt +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut.egg-info/entry_points.txt +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut.egg-info/requires.txt +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/countmut.egg-info/top_level.txt +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/setup.cfg +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/tests/test_cli.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/tests/test_core.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/tests/test_router.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/tests/test_unified.py +0 -0
- {countmut-0.3.1 → countmut-0.3.2}/tests/test_utils.py +0 -0
|
@@ -569,10 +569,11 @@ static void count_interval(worker_t *w, const cm_config *cfg, bam_hdr_t *hdr, FI
|
|
|
569
569
|
int s = bio_strand(b);
|
|
570
570
|
uint8_t nt = bam_seqi(bam_get_seq(b), p->qpos);
|
|
571
571
|
int base_i = nt16_index(nt);
|
|
572
|
-
/*
|
|
573
|
-
* CIGAR order (left->right); complement the base into the
|
|
574
|
-
* reference frame
|
|
575
|
-
|
|
572
|
+
/* Reverse-oriented reads: stored SEQ is 5'->3' (SAM spec) but qpos
|
|
573
|
+
* walks CIGAR order (left->right); complement the base into the
|
|
574
|
+
* reference frame. Key on bam_is_rev (read orientation), not the
|
|
575
|
+
* biological strand s (which differs for R2 in paired data). */
|
|
576
|
+
if (bam_is_rev(b) && base_i < 4) base_i = 3 - base_i;
|
|
576
577
|
/* router-assigned category slot (0..CM_CAT_MAX-1); g_a set in
|
|
577
578
|
* the selection loop for every kept candidate. */
|
|
578
579
|
int cat = w->g_a[i];
|
|
@@ -764,10 +765,13 @@ static rw_w *rw_add_base(worker_t *w, const cm_config *cfg, bam_hdr_t *hdr, int
|
|
|
764
765
|
}
|
|
765
766
|
uint8_t nt = bam_seqi(bam_get_seq(b), qpos);
|
|
766
767
|
int base_i = nt16_index(nt);
|
|
767
|
-
/*
|
|
768
|
-
* (left->right); complement the base into the reference frame
|
|
769
|
-
* with countmut 0.0.x + pysam pairs).
|
|
770
|
-
|
|
768
|
+
/* Reverse-oriented reads: stored SEQ is 5'->3' (SAM spec) but qpos walks
|
|
769
|
+
* CIGAR order (left->right); complement the base into the reference frame
|
|
770
|
+
* (parity with countmut 0.0.x + pysam pairs). This must key on the read's
|
|
771
|
+
* own orientation (bam_is_rev), NOT on the biological strand s: for paired
|
|
772
|
+
* reads an R2 mapped forward has bio_strand=1 yet is NOT reverse-oriented,
|
|
773
|
+
* so complementing on s would wrongly flip its bases (A<->T). */
|
|
774
|
+
if (bam_is_rev(b) && base_i < 4) base_i = 3 - base_i;
|
|
771
775
|
int qual = (int)bam_get_qual(b)[qpos];
|
|
772
776
|
if (direct) {
|
|
773
777
|
int cat = rslot;
|
|
@@ -1040,7 +1044,9 @@ static void count_interval_readwalk(worker_t *w, const cm_config *cfg, bam_hdr_t
|
|
|
1040
1044
|
if (qpos >= qlen) break;
|
|
1041
1045
|
uint8_t nt = bam_seqi(bam_get_seq(b), qpos);
|
|
1042
1046
|
int base_i = nt16_index(nt);
|
|
1043
|
-
|
|
1047
|
+
/* Complement on read orientation (bam_is_rev), not
|
|
1048
|
+
* the biological strand s (R2 differs). */
|
|
1049
|
+
if (bam_is_rev(b) && base_i < 4) base_i = 3 - base_i;
|
|
1044
1050
|
int cat = 0;
|
|
1045
1051
|
if (w->expr && cm_expr_has_read(w->expr) && !cm_expr_read_constant(w->expr)) {
|
|
1046
1052
|
cat = cm_expr_route(w->expr, b, hdr->target_name[tid],
|
|
@@ -1110,7 +1116,9 @@ static void count_interval_readwalk(worker_t *w, const cm_config *cfg, bam_hdr_t
|
|
|
1110
1116
|
int in_ovl = ((int)qpos >= olo && (int)qpos < ohi);
|
|
1111
1117
|
uint8_t nt = bam_seqi(bam_get_seq(b), qpos);
|
|
1112
1118
|
int base_i = nt16_index(nt);
|
|
1113
|
-
|
|
1119
|
+
/* Complement on read orientation (bam_is_rev),
|
|
1120
|
+
* not the biological strand s (R2 differs). */
|
|
1121
|
+
if (bam_is_rev(b) && base_i < 4) base_i = 3 - base_i;
|
|
1114
1122
|
int cat = 0;
|
|
1115
1123
|
if (w->expr && cm_expr_has_read(w->expr) && !cm_expr_read_constant(w->expr)) {
|
|
1116
1124
|
cat = cm_expr_route(w->expr, b, hdr->target_name[tid],
|
|
Binary file
|
|
@@ -91,6 +91,40 @@ def indel_data(tmp_path_factory):
|
|
|
91
91
|
)
|
|
92
92
|
|
|
93
93
|
|
|
94
|
+
# ---------------------------------------------------------------------------
|
|
95
|
+
# BUG: base complement keyed on biological strand (s) instead of read
|
|
96
|
+
# orientation (bam_is_rev). For paired data an R2 read mapped forward has
|
|
97
|
+
# bio_strand=1 yet is NOT reverse-oriented, so its bases were wrongly
|
|
98
|
+
# reverse-complemented (A<->T), turning a pure-reference site into a 50/50
|
|
99
|
+
# A/T mix. Regression: R2-forward reads must count their stored bases as-is.
|
|
100
|
+
# ---------------------------------------------------------------------------
|
|
101
|
+
def test_r2_forward_not_complemented(tmp_path):
|
|
102
|
+
root = str(tmp_path / "r2f")
|
|
103
|
+
os.makedirs(root, exist_ok=True)
|
|
104
|
+
# reference base at 0-based 0 is 'A'. An R2 read mapped FORWARD stores the
|
|
105
|
+
# base as-is (A), so a pure-A site must stay A, not flip to T.
|
|
106
|
+
bam, fa = _write_bam(
|
|
107
|
+
root,
|
|
108
|
+
[
|
|
109
|
+
# R1 forward (flag 99) and R2 forward (flag 35) covering 0-based 0.
|
|
110
|
+
lambda h: _mk(h, "frag1", 99, 0, "ACGTACGTAC"),
|
|
111
|
+
lambda h: _mk(h, "frag1", 35, 0, "ACGTACGTAC"),
|
|
112
|
+
# R1 reverse (flag 83) and R2 reverse (flag 147): stored SEQ is the
|
|
113
|
+
# reverse complement, so they must be complemented back to A.
|
|
114
|
+
lambda h: _mk(h, "frag2", 83, 0, "ACGTACGTAC"),
|
|
115
|
+
lambda h: _mk(h, "frag2", 147, 0, "ACGTACGTAC"),
|
|
116
|
+
],
|
|
117
|
+
)
|
|
118
|
+
_h, rows = run_c(bam, fa, engine="read-walk", region="chr1:1-5")
|
|
119
|
+
# rows: [chrom, pos, ref, depth, a, c, g, t, n] (strandless default)
|
|
120
|
+
row = [r for r in rows if r[1] == 1][0]
|
|
121
|
+
a, c, g, t = row[4], row[5], row[6], row[7]
|
|
122
|
+
# All four reads carry reference 'A' at 0-based 0 -> A must dominate.
|
|
123
|
+
assert a > 0 and a >= c + g + t, (row)
|
|
124
|
+
# The bug produced ~50/50 A/T; assert T is a small minority.
|
|
125
|
+
assert t <= a * 0.1, (row)
|
|
126
|
+
|
|
127
|
+
|
|
94
128
|
# ---------------------------------------------------------------------------
|
|
95
129
|
# BUG: '-' mutation-row motif reverse-complemented with reference-forward bases
|
|
96
130
|
# ---------------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|