alnkit 0.2.0__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.
Files changed (101) hide show
  1. alnkit-0.2.0/.gitignore +16 -0
  2. alnkit-0.2.0/CHANGELOG.md +128 -0
  3. alnkit-0.2.0/LICENSE +674 -0
  4. alnkit-0.2.0/PKG-INFO +163 -0
  5. alnkit-0.2.0/README.md +125 -0
  6. alnkit-0.2.0/docs/cli/alnkit-align-reads.md +37 -0
  7. alnkit-0.2.0/docs/cli/alnkit-doctor.md +26 -0
  8. alnkit-0.2.0/docs/cli/alnkit-long-assemble.md +39 -0
  9. alnkit-0.2.0/docs/cli/alnkit-long-breakpoints.md +44 -0
  10. alnkit-0.2.0/docs/cli/alnkit-long-classify.md +45 -0
  11. alnkit-0.2.0/docs/cli/alnkit-long-graph.md +37 -0
  12. alnkit-0.2.0/docs/cli/alnkit-long-locate.md +44 -0
  13. alnkit-0.2.0/docs/cli/alnkit-plot-ribbon.md +55 -0
  14. alnkit-0.2.0/docs/cli/alnkit-plot-tracks.md +51 -0
  15. alnkit-0.2.0/docs/cli/alnkit-ref-merge.md +35 -0
  16. alnkit-0.2.0/docs/cli/alnkit-seg-table.md +38 -0
  17. alnkit-0.2.0/docs/cli/alnkit-selftest.md +26 -0
  18. alnkit-0.2.0/docs/cli/alnkit-short-scan.md +67 -0
  19. alnkit-0.2.0/docs/cli/index.md +20 -0
  20. alnkit-0.2.0/docs/concepts/coordinates.md +65 -0
  21. alnkit-0.2.0/docs/concepts/tables.md +73 -0
  22. alnkit-0.2.0/docs/index.md +34 -0
  23. alnkit-0.2.0/docs/install.md +47 -0
  24. alnkit-0.2.0/docs/quickstart.md +68 -0
  25. alnkit-0.2.0/mkdocs.yml +59 -0
  26. alnkit-0.2.0/pyproject.toml +89 -0
  27. alnkit-0.2.0/scripts/gen_cli_docs.py +221 -0
  28. alnkit-0.2.0/scripts/gen_table_docs.py +35 -0
  29. alnkit-0.2.0/src/alnkit/__init__.py +11 -0
  30. alnkit-0.2.0/src/alnkit/__main__.py +10 -0
  31. alnkit-0.2.0/src/alnkit/_docs.py +53 -0
  32. alnkit-0.2.0/src/alnkit/cli/__init__.py +53 -0
  33. alnkit-0.2.0/src/alnkit/cli/__main__.py +10 -0
  34. alnkit-0.2.0/src/alnkit/cli/_common.py +25 -0
  35. alnkit-0.2.0/src/alnkit/cli/align.py +52 -0
  36. alnkit-0.2.0/src/alnkit/cli/doctor.py +81 -0
  37. alnkit-0.2.0/src/alnkit/cli/long.py +346 -0
  38. alnkit-0.2.0/src/alnkit/cli/plot.py +293 -0
  39. alnkit-0.2.0/src/alnkit/cli/ref.py +50 -0
  40. alnkit-0.2.0/src/alnkit/cli/seg.py +131 -0
  41. alnkit-0.2.0/src/alnkit/cli/selftest.py +308 -0
  42. alnkit-0.2.0/src/alnkit/cli/short.py +245 -0
  43. alnkit-0.2.0/src/alnkit/core/__init__.py +9 -0
  44. alnkit-0.2.0/src/alnkit/core/bam_segments.py +183 -0
  45. alnkit-0.2.0/src/alnkit/core/coords.py +129 -0
  46. alnkit-0.2.0/src/alnkit/core/errors.py +25 -0
  47. alnkit-0.2.0/src/alnkit/core/external.py +63 -0
  48. alnkit-0.2.0/src/alnkit/core/fasta.py +83 -0
  49. alnkit-0.2.0/src/alnkit/core/logging.py +25 -0
  50. alnkit-0.2.0/src/alnkit/core/paf.py +52 -0
  51. alnkit-0.2.0/src/alnkit/core/segments.py +253 -0
  52. alnkit-0.2.0/src/alnkit/core/tables.py +340 -0
  53. alnkit-0.2.0/src/alnkit/longread/__init__.py +5 -0
  54. alnkit-0.2.0/src/alnkit/longread/assemble.py +453 -0
  55. alnkit-0.2.0/src/alnkit/longread/breakpoints.py +910 -0
  56. alnkit-0.2.0/src/alnkit/longread/classify.py +958 -0
  57. alnkit-0.2.0/src/alnkit/longread/graph.py +174 -0
  58. alnkit-0.2.0/src/alnkit/longread/locate.py +904 -0
  59. alnkit-0.2.0/src/alnkit/plot/__init__.py +5 -0
  60. alnkit-0.2.0/src/alnkit/plot/ribbon.py +1306 -0
  61. alnkit-0.2.0/src/alnkit/plot/tracks.py +1035 -0
  62. alnkit-0.2.0/src/alnkit/prepare.py +256 -0
  63. alnkit-0.2.0/src/alnkit/py.typed +0 -0
  64. alnkit-0.2.0/src/alnkit/shortread/__init__.py +20 -0
  65. alnkit-0.2.0/src/alnkit/shortread/bam.py +527 -0
  66. alnkit-0.2.0/src/alnkit/shortread/evidence.py +214 -0
  67. alnkit-0.2.0/src/alnkit/shortread/interference.py +44 -0
  68. alnkit-0.2.0/src/alnkit/shortread/merge.py +126 -0
  69. alnkit-0.2.0/src/alnkit/shortread/model.py +301 -0
  70. alnkit-0.2.0/src/alnkit/shortread/origin.py +507 -0
  71. alnkit-0.2.0/src/alnkit/shortread/report.py +316 -0
  72. alnkit-0.2.0/src/alnkit/shortread/scan.py +788 -0
  73. alnkit-0.2.0/tests/_fs.py +22 -0
  74. alnkit-0.2.0/tests/fixtures/build_private_longread.py +297 -0
  75. alnkit-0.2.0/tests/fixtures/build_private_shortread.py +174 -0
  76. alnkit-0.2.0/tests/fixtures/ribbon/example4_alignment.paf +17 -0
  77. alnkit-0.2.0/tests/fixtures/ribbon/expected.blocks.tsv +4 -0
  78. alnkit-0.2.0/tests/fixtures/segtable/expected.legacy.tsv +9 -0
  79. alnkit-0.2.0/tests/fixtures/segtable/make_fixture.py +42 -0
  80. alnkit-0.2.0/tests/fixtures/segtable/reads.bam +0 -0
  81. alnkit-0.2.0/tests/fixtures/segtable/ref.fa +4 -0
  82. alnkit-0.2.0/tests/fixtures/segtable/ref.fa.fai +2 -0
  83. alnkit-0.2.0/tests/fixtures/tracks/example_segments.tsv +19 -0
  84. alnkit-0.2.0/tests/fixtures/tracks/expected.segments.tsv +19 -0
  85. alnkit-0.2.0/tests/test_cli.py +62 -0
  86. alnkit-0.2.0/tests/test_coords.py +97 -0
  87. alnkit-0.2.0/tests/test_docs.py +56 -0
  88. alnkit-0.2.0/tests/test_doctor.py +46 -0
  89. alnkit-0.2.0/tests/test_fasta_paf.py +75 -0
  90. alnkit-0.2.0/tests/test_golden_provenance.py +87 -0
  91. alnkit-0.2.0/tests/test_long_assemble.py +173 -0
  92. alnkit-0.2.0/tests/test_long_breakpoints.py +125 -0
  93. alnkit-0.2.0/tests/test_long_classify.py +162 -0
  94. alnkit-0.2.0/tests/test_long_locate.py +142 -0
  95. alnkit-0.2.0/tests/test_plot_ribbon.py +199 -0
  96. alnkit-0.2.0/tests/test_plot_tracks.py +168 -0
  97. alnkit-0.2.0/tests/test_prepare.py +132 -0
  98. alnkit-0.2.0/tests/test_seg_table.py +189 -0
  99. alnkit-0.2.0/tests/test_segments.py +265 -0
  100. alnkit-0.2.0/tests/test_short_scan.py +302 -0
  101. alnkit-0.2.0/tests/test_tables.py +172 -0
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ venv/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+ site/
14
+ .DS_Store
15
+ *.local.md
16
+ .plans/
@@ -0,0 +1,128 @@
1
+ # Changelog
2
+
3
+ 格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 SemVer。
4
+ 条目按功能 ID(`A*` 三代 / `B*` 二代 / `C*` 绘图 / `D*` 公共层)分组,ID 定义见规划文档。
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.2.0] - 2026-11-02
9
+
10
+ ### Security
11
+
12
+ - **全量脱敏**(0.1.0 发布后发现仓库与包内含内部信息,本版一并清理):
13
+ - 本机绝对路径 → 改由 `ALNKIT_UPSTREAM_*` 环境变量或 `--source/--bam-dir` 指定;
14
+ - 样本名/细胞系名/项目号 → `sampleA` / `sampleB`;
15
+ - 外源构建体与靶点名 → `target_ref` / `homolog_ref` / `decoy_ref` / `insertA` / `insertB`;
16
+ - 真实参考序列号与坐标 → `chr1`/`chr2` 与 100 万级合成坐标;
17
+ - 测试 fixture 的 read 名与坐标同步替换(黄金用上游工具按新 fixture 重新生成);
18
+ - 移除作者邮箱;真实序列名只保留在**本地** `manifest.json`(不入库),测试从 manifest 读。
19
+
20
+ ### Changed
21
+
22
+ - **`samtools` 从必需变成可选**:`align reads` 的排序/建索引改用 `pysam` 内置的 samtools
23
+ (`pysam.sort` / `pysam.index`,0.24 对应 samtools 1.23),比对记录与旧 shell 产物逐字节相同;
24
+ 只有 pysam 封装不可用时才回退到 PATH 里的 `samtools`。
25
+ - **项目描述收敛**为最短版本:「BAM/PAF 的插入证据工具箱:断点提取 + 独立绘图」
26
+ (英文 `Insertion evidence toolkit for BAM/PAF: breakpoint extraction and standalone plots`)。
27
+ - `sites.canonical.tsv` 增加插入归属三列:`query_insert` / `nearest_other_insert` / `other_inserts`
28
+ (一条 read 可能同时命中多个插入序列,"最近"按支持 read 数定义,query 自己不算竞争者)。
29
+
30
+ ## [0.1.1] - 2026-11-01
31
+
32
+ ### Added
33
+
34
+ - **`<sample>.sites.canonical.tsv`**(`short scan` 新增产物,0.1.0 缺失的那张表):
35
+ 二代位点的机器接口,带 `insert_pos_1based` / `insert_pos_0based` / `insert_boundary_0based`
36
+ 三列,恒等式 `insert_pos_0based + 1 == insert_pos_1based == insert_boundary_0based`;
37
+ 与 `<sample>.Insert_Position.result.xls` 按 `(chrom, insert_pos_1based)` 逐行对应。
38
+
39
+ ## [0.1.0] - 2026-11-01
40
+
41
+ ### Fixed
42
+
43
+ - **基础安装可用**:`alnkit` 之前会在 import 阶段无条件导入绘图模块,未装 matplotlib 时
44
+ 连 `alnkit --version` 都崩(`pip install alnkit` 只装 pysam)。改为惰性导入,缺依赖时
45
+ 给 `pip install "alnkit[plot]"` 的可行动提示 + 退出码 2。
46
+ - **反链 overlap 落位差 `aligned_bp-1`**:`placement_from_block` 在 `strand="-"` 时把
47
+ unplaced 起点与 placed 起点配对,反链应为头尾相对(起点对终点)。本数据集 38% 的 overlap
48
+ 是反链,所以 06 组装的 contig 与 07 的图都会变;同一修复已提交到上游(`82a50b7`)。
49
+ - **合并参考漏一条序列**:输入 FASTA 末尾缺换行时,`ref merge` 的拼接会把 `>下一条` 粘到
50
+ 上一条序列末尾,`faidx` 仍然成功、下游静默少一条参考。现在边界处强制补换行。
51
+ - `long classify` 的 `--exog` 打错名字不再静默输出 0 条结果,直接报可用序列名。
52
+ - `long locate` 的位点表与参考 `.fai` 不匹配时给 `UsageError`(原来是 `KeyError` traceback)。
53
+ - `short scan` 两个 BAM 推导出同名样本时提前报错(原来后一个会静默覆盖前一个的输出)。
54
+ - `short scan` 缺 `NM` 标签的插入侧比对不再被当成“零错配”(那是最优 tie-break,会让它抢到归属)。
55
+
56
+ ### Added
57
+
58
+ - 契约层加固(独立复审后修):strand 空值不再静默当 `+`;可选整数列坏值报 `UsageError`
59
+ 而不是裸 `ValueError`;坐标列后缀校验不再能被 `ref_end_bp` 这类名字绕过;
60
+ 原子写保留目标文件原权限(`mkstemp` 的 0600 不再泄漏);`write_legacy_tsv` 也改成原子写
61
+ (失败不覆盖旧文件);零长区间/`left_base_0based(0)`/千分位位置错误一律报错。
62
+ - 黄金回归的**出身校验**:`tests/fixtures/build_private_*.py` 默认要求旧脚本存在
63
+ (`--trust-current` 需显式给),每个黄金目录写 `PROVENANCE.txt`(generator/命令/脚本 sha256),
64
+ `tests/test_golden_provenance.py` 拒绝 `generator=alnkit` 的黄金。
65
+ builder 同时补齐了 A5 需要的三个输入(以前只能手工准备)。
66
+ - 私有数据已设 `ALNKIT_TEST_DATA` 时,缺输入从 `skip` 改为 `fail`。
67
+
68
+ - A4 `alnkit long graph`:read-vs-read overlap 边与连通分量,移植 `overlap_graph.py`;
69
+ 三张产物逐字节一致。
70
+ - A1 `alnkit ref merge`:把 `01_merge_ref.sh` 改写成 Python(不再依赖 awk)。
71
+ `reference_headers.tsv`(含 awk 的单空格重组语义)、`exogenous_uppercased.fa`、两个 `.fai`
72
+ 逐字节一致;2.3 GB 的 `merged_reference.fa` md5 相同。
73
+ - A2 `alnkit align reads`:把 `02_align_merged.sh` 改写成外部命令层调用。
74
+ **BAM 不能逐字节比**(minimap2 把命令行含输出路径写进 `@PG`),验收改为比对记录
75
+ `samtools view -F 0x900` 的 md5 一致(实测相同)。
76
+ - A7 `alnkit long locate`:50 bp 断点锚点 + 外源 → 丝带图 + 参考坐标还原,移植
77
+ `ribbon_positions.py`。非 PDF 产物(7 张 PNG、`class_assembly_positions.tsv`、
78
+ `contig_map.tsv`、`work/*.paf`、`summary.md`、`tables/*`)与旧脚本逐字节一致。
79
+ 两处**有意改动**:① 不再 subprocess 调 vendored `tools/synteny_ribbon.py` 1.8.0,
80
+ 改为进程内调用本包 `plot.ribbon`(1.10.1);audit 的版本影响评估已实测两者对当前
81
+ 参数产物相同,本次也复核了 PNG 逐字节一致。② PDF 不参与逐字节对账——matplotlib 在
82
+ PDF 里写生成时间,旧脚本自己连跑两次也不一致,测试只比大小。
83
+ - A6 `alnkit long assemble`:三代每类 overlap 贪心延伸组装,移植 `overlap_assembly.py`。
84
+ 旧实现用 `for unplaced_name in list(unplaced)` 遍历 `set`,同一输入在不同
85
+ `PYTHONHASHSEED` 下会产出不同 `layout.tsv`(实测三次三种结果)。该问题已**先在上游修**
86
+ (`upstream` commit `20b4dda`,本包 `src/alnkit/longread/assemble.py` 为同构实现),
87
+ 修完两边 `diff -r` 整目录逐字节一致(含 `layout.tsv`)。
88
+ - core 补齐:`paf.parse_paf`、`fasta.{reverse_complement,write_fasta_records,read_fastq_sequences}`;
89
+ 新增 `python -m alnkit` / `python -m alnkit.cli` 入口。
90
+ - A5 `alnkit long breakpoints`:三代断点(S##/G##)+ 共享 reads 并查集合并成类 + 类池,
91
+ 移植 `breakpoints.py`;`diff -r` 整目录逐字节一致(含 `classes/<C>/*.fastq` 与 `graph_summary.txt`)。
92
+ 唯一非内容差异:`class_read_pools.tsv` 的 `reads_fastq` 列是绝对路径,比对时按 `<OUTDIR>` 归一化。
93
+ - core 补齐:`tables.read_legacy_tsv`(旧语义读取,行是字符串列表)。
94
+ - A3 `alnkit long classify`:三代目标 reads 分类 + 接头事件/位点/区域聚类,
95
+ 移植 `03_classify_reads.py`;**整目录**(4 张表 + 4 个 FASTQ 子集 + `regions/`)
96
+ 与旧脚本逐字节一致。
97
+ - core 补齐:`Segment` 增加 `nm` / `match_columns` / `inserted_bases` / `deleted_bases`;
98
+ `tables.write_legacy_tsv`(旧语义写出);`coords.merge_intervals`。
99
+ - `shortread` 按依赖分成 7 个模块(`model` / `bam` / `interference` / `evidence` /
100
+ `origin` / `merge` / `report`)+ 编排层 `scan`;拆分后 owned / markdup / consensus
101
+ 三种口径的黄金回归仍然逐字节一致。
102
+ - B1 `alnkit short scan`:二代插入断点证据(SR / PESR / DUP),移植 `parse_bam.py` v3.0.0;
103
+ 三张表在 owned / markdup / consensus 三种口径下与旧脚本逐字节一致(黄金回归需私有数据,
104
+ 公开 CI 跳过)。`consensus` 策略下 `candidate_insert_chromosomes` 先用后赋值的潜伏
105
+ `NameError` 已**先在上游修**(已在上游同步修复)。
106
+ 另有一处**有意差异**:规范表 `segments` 的 `nm` 列在 NM 标签缺失时记 `-`(旧 14 列表记 0,
107
+ 该列不在 legacy 表里,故不影响对账)。
108
+ - B2 `parse_bam --self-test` 的 30+ 条口径断言并入 `alnkit selftest`。
109
+ - C1 `alnkit plot ribbon`:共线性丝带图,移植 `synteny_ribbon.py` v1.10.1;`--paf` 模式下
110
+ `blocks.tsv` 与 PNG 与旧脚本逐字节一致。相对旧版只加了一条输入校验:空标签直接报错
111
+ (旧版会画出一行无名轨道)。
112
+ - D2 `alnkit seg table`:BAM → 比对段表;`--columns legacy` 复现历史 14 列(与旧脚本
113
+ `alignment_table.py` 逐字节一致),默认写带基准后缀的规范列。含 CIGAR 简化视图与
114
+ read 轴镜像归正(`core/bam_segments.py`)。
115
+ - C2 `alnkit plot tracks`:单 read 比对片段轨道图(BAM / PAF / 段表三选一),
116
+ 由 `read_segment_tracks.py`(git 51bf68f)忠实移植;`segments.tsv` 与 PNG 与旧脚本逐字节一致。
117
+
118
+ - D6 `alnkit doctor`:Python / pysam / matplotlib / minimap2 / samtools / bwa 的可用性与版本。
119
+ - D6 `alnkit selftest`:坐标换算、表后缀规则、三套历史段表头的归一断言。
120
+ - D1–D3 契约层:`coords`(唯一 ±1 入口)、`tables`(列注册表 + 原子写 + 后缀校验)、
121
+ `segments`(`Segment` 模型 + 别名读取)、`external`(工具探测)。
122
+ - 文档骨架:`docs/index.md`、`docs/install.md`、`docs/quickstart.md`、`docs/concepts/coordinates.md`、
123
+ `docs/concepts/tables.md`(由 `core.tables` 生成)。
124
+
125
+ [Unreleased]: https://github.com/liuyinzhe/alnkit/compare/v0.2.0...HEAD
126
+ [0.2.0]: https://github.com/liuyinzhe/alnkit/releases/tag/v0.2.0
127
+ [0.1.1]: https://github.com/liuyinzhe/alnkit/releases/tag/v0.1.1
128
+ [0.1.0]: https://github.com/liuyinzhe/alnkit/releases/tag/v0.1.0