gseek 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 (112) hide show
  1. gseek-0.2.0/.editorconfig +18 -0
  2. gseek-0.2.0/.gitignore +58 -0
  3. gseek-0.2.0/.pre-commit-config.yaml +35 -0
  4. gseek-0.2.0/.python-version +1 -0
  5. gseek-0.2.0/AGENTS.md +198 -0
  6. gseek-0.2.0/CHANGELOG.md +151 -0
  7. gseek-0.2.0/CONTRIBUTING.md +126 -0
  8. gseek-0.2.0/LICENSE +21 -0
  9. gseek-0.2.0/PKG-INFO +252 -0
  10. gseek-0.2.0/README.md +216 -0
  11. gseek-0.2.0/dev/adapter-matrix.md +627 -0
  12. gseek-0.2.0/dev/compatibility.md +321 -0
  13. gseek-0.2.0/dev/decisions/0001-mummer4.md +79 -0
  14. gseek-0.2.0/dev/decisions/0002-project-rename.md +70 -0
  15. gseek-0.2.0/dev/decisions/README.md +15 -0
  16. gseek-0.2.0/dev/development-plan.md +1072 -0
  17. gseek-0.2.0/dev/releasing.md +143 -0
  18. gseek-0.2.0/dev/research.md +253 -0
  19. gseek-0.2.0/docs/api.md +1631 -0
  20. gseek-0.2.0/docs/cli.md +113 -0
  21. gseek-0.2.0/docs/errors.md +99 -0
  22. gseek-0.2.0/docs/index.md +23 -0
  23. gseek-0.2.0/docs/quickstart.md +146 -0
  24. gseek-0.2.0/pyproject.toml +137 -0
  25. gseek-0.2.0/src/gseek/__init__.py +198 -0
  26. gseek-0.2.0/src/gseek/__main__.py +8 -0
  27. gseek-0.2.0/src/gseek/adapter.py +292 -0
  28. gseek-0.2.0/src/gseek/adapters/__init__.py +17 -0
  29. gseek-0.2.0/src/gseek/adapters/base.py +214 -0
  30. gseek-0.2.0/src/gseek/adapters/blast.py +395 -0
  31. gseek-0.2.0/src/gseek/adapters/bwa.py +396 -0
  32. gseek-0.2.0/src/gseek/adapters/kma.py +284 -0
  33. gseek-0.2.0/src/gseek/adapters/mash.py +326 -0
  34. gseek-0.2.0/src/gseek/adapters/minimap2.py +346 -0
  35. gseek-0.2.0/src/gseek/adapters/mummer.py +241 -0
  36. gseek-0.2.0/src/gseek/adapters/skani.py +243 -0
  37. gseek-0.2.0/src/gseek/adapters/sourmash.py +446 -0
  38. gseek-0.2.0/src/gseek/api.py +261 -0
  39. gseek-0.2.0/src/gseek/capabilities.py +132 -0
  40. gseek-0.2.0/src/gseek/cli.py +345 -0
  41. gseek-0.2.0/src/gseek/errors.py +245 -0
  42. gseek-0.2.0/src/gseek/execution.py +792 -0
  43. gseek-0.2.0/src/gseek/index.py +443 -0
  44. gseek-0.2.0/src/gseek/io.py +427 -0
  45. gseek-0.2.0/src/gseek/model/__init__.py +32 -0
  46. gseek-0.2.0/src/gseek/model/alignment.py +612 -0
  47. gseek-0.2.0/src/gseek/model/common.py +148 -0
  48. gseek-0.2.0/src/gseek/model/distance.py +202 -0
  49. gseek-0.2.0/src/gseek/model/run.py +220 -0
  50. gseek-0.2.0/src/gseek/provenance.py +373 -0
  51. gseek-0.2.0/src/gseek/py.typed +0 -0
  52. gseek-0.2.0/src/gseek/registry.py +206 -0
  53. gseek-0.2.0/src/gseek/replay.py +161 -0
  54. gseek-0.2.0/src/gseek/runner.py +627 -0
  55. gseek-0.2.0/src/gseek/types.py +205 -0
  56. gseek-0.2.0/src/gseek/version.py +7 -0
  57. gseek-0.2.0/src/gseek/views.py +129 -0
  58. gseek-0.2.0/tests/conftest.py +219 -0
  59. gseek-0.2.0/tests/fixtures/README.md +80 -0
  60. gseek-0.2.0/tests/fixtures/blast/blastn_nucl.tsv +2 -0
  61. gseek-0.2.0/tests/fixtures/bwa/align.sam +6 -0
  62. gseek-0.2.0/tests/fixtures/kma/align.res +3 -0
  63. gseek-0.2.0/tests/fixtures/mash/dist.tsv +2 -0
  64. gseek-0.2.0/tests/fixtures/mash/screen.tsv +2 -0
  65. gseek-0.2.0/tests/fixtures/minimap2/align.paf +2 -0
  66. gseek-0.2.0/tests/fixtures/mummer/coords.txt +6 -0
  67. gseek-0.2.0/tests/fixtures/skani/search.tsv +2 -0
  68. gseek-0.2.0/tests/fixtures/sourmash/gather.csv +3 -0
  69. gseek-0.2.0/tests/fixtures/sourmash/search.csv +3 -0
  70. gseek-0.2.0/tests/integration/__init__.py +0 -0
  71. gseek-0.2.0/tests/integration/test_external_reference.py +98 -0
  72. gseek-0.2.0/tests/integration/test_m1_adapters.py +134 -0
  73. gseek-0.2.0/tests/integration/test_m2_adapters.py +128 -0
  74. gseek-0.2.0/tests/integration/test_m3_adapters.py +165 -0
  75. gseek-0.2.0/tests/integration/test_m4_adapters.py +144 -0
  76. gseek-0.2.0/tests/integration/test_replay_matrix.py +105 -0
  77. gseek-0.2.0/tests/parity/test_real_tool_fixtures.py +278 -0
  78. gseek-0.2.0/tests/test_adapter_helpers.py +74 -0
  79. gseek-0.2.0/tests/test_adapter_more.py +153 -0
  80. gseek-0.2.0/tests/test_adapter_validation.py +88 -0
  81. gseek-0.2.0/tests/test_api.py +110 -0
  82. gseek-0.2.0/tests/test_blast_adapter.py +422 -0
  83. gseek-0.2.0/tests/test_bwa_adapter.py +294 -0
  84. gseek-0.2.0/tests/test_cli.py +121 -0
  85. gseek-0.2.0/tests/test_cli_more.py +182 -0
  86. gseek-0.2.0/tests/test_distance.py +37 -0
  87. gseek-0.2.0/tests/test_docs.py +48 -0
  88. gseek-0.2.0/tests/test_docs_links.py +26 -0
  89. gseek-0.2.0/tests/test_execution.py +146 -0
  90. gseek-0.2.0/tests/test_execution_more.py +208 -0
  91. gseek-0.2.0/tests/test_index.py +168 -0
  92. gseek-0.2.0/tests/test_index_more.py +185 -0
  93. gseek-0.2.0/tests/test_io.py +129 -0
  94. gseek-0.2.0/tests/test_io_more.py +110 -0
  95. gseek-0.2.0/tests/test_kma_adapter.py +273 -0
  96. gseek-0.2.0/tests/test_mash_adapter.py +262 -0
  97. gseek-0.2.0/tests/test_minimap2_adapter.py +312 -0
  98. gseek-0.2.0/tests/test_model.py +231 -0
  99. gseek-0.2.0/tests/test_model_more.py +203 -0
  100. gseek-0.2.0/tests/test_mummer_adapter.py +308 -0
  101. gseek-0.2.0/tests/test_project_identity.py +78 -0
  102. gseek-0.2.0/tests/test_properties.py +28 -0
  103. gseek-0.2.0/tests/test_provenance.py +144 -0
  104. gseek-0.2.0/tests/test_registry.py +76 -0
  105. gseek-0.2.0/tests/test_registry_builtins.py +97 -0
  106. gseek-0.2.0/tests/test_registry_more.py +91 -0
  107. gseek-0.2.0/tests/test_replay.py +188 -0
  108. gseek-0.2.0/tests/test_runner.py +334 -0
  109. gseek-0.2.0/tests/test_skani_adapter.py +186 -0
  110. gseek-0.2.0/tests/test_sourmash_adapter.py +313 -0
  111. gseek-0.2.0/tests/test_types.py +59 -0
  112. gseek-0.2.0/tests/test_views.py +127 -0
@@ -0,0 +1,18 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.{md,markdown,yml,yaml,json,toml}]
12
+ indent_size = 2
13
+
14
+ [*.{diff,patch}]
15
+ trim_trailing_whitespace = false
16
+
17
+ [Makefile]
18
+ indent_style = tab
gseek-0.2.0/.gitignore ADDED
@@ -0,0 +1,58 @@
1
+ # pixi environments
2
+ .pixi/*
3
+ !.pixi/config.toml
4
+
5
+ # Python
6
+ __pycache__/
7
+ *.py[cod]
8
+ *.egg-info/
9
+ .eggs/
10
+ build/
11
+ dist/
12
+ .venv/
13
+ venv/
14
+ pip-wheel-metadata/
15
+ .uv-cache/
16
+ .uv/
17
+
18
+ # Tool caches and local scratch
19
+ .scratch/
20
+ .pytest_cache/
21
+ .ruff_cache/
22
+ .pyright/
23
+ .mypy_cache/
24
+ .hypothesis/
25
+ .benchmarks/
26
+ .tox/
27
+ .nox/
28
+ .coverage
29
+ .coverage.*
30
+ coverage.xml
31
+ coverage.json
32
+ htmlcov/
33
+
34
+ # Local environment/secrets
35
+ .env
36
+ .env.*
37
+ !.env.example
38
+ .direnv/
39
+ AGENTS.local.md
40
+ *.log
41
+ *.prof
42
+
43
+ # Docs
44
+ site/
45
+ docs-site/
46
+ _build/
47
+
48
+ # Editors
49
+ .idea/
50
+ .vscode/
51
+ *.code-workspace
52
+ *.swp
53
+ *.swo
54
+ .DS_Store
55
+
56
+ # Patch leftovers
57
+ *.orig
58
+ *.rej
@@ -0,0 +1,35 @@
1
+ default_install_hook_types: [pre-commit, pre-push]
2
+ default_stages: [pre-commit]
3
+ exclude: ^pixi\.lock$
4
+
5
+ repos:
6
+ - repo: https://github.com/pre-commit/pre-commit-hooks
7
+ rev: v5.0.0
8
+ hooks:
9
+ - id: check-yaml
10
+ - id: check-toml
11
+ - id: check-added-large-files
12
+ args: [--maxkb=1000]
13
+ - id: check-merge-conflict
14
+ - id: debug-statements
15
+ - id: end-of-file-fixer
16
+ - id: trailing-whitespace
17
+ args: [--markdown-linebreak-ext=md]
18
+ - id: mixed-line-ending
19
+ args: [--fix=lf]
20
+
21
+ - repo: https://github.com/astral-sh/ruff-pre-commit
22
+ rev: v0.17.1
23
+ hooks:
24
+ - id: ruff
25
+ args: [--fix]
26
+ - id: ruff-format
27
+
28
+ - repo: local
29
+ hooks:
30
+ - id: pytest
31
+ name: pytest (pre-push)
32
+ entry: pixi run test
33
+ language: system
34
+ pass_filenames: false
35
+ stages: [pre-push]
@@ -0,0 +1 @@
1
+ 3.12
gseek-0.2.0/AGENTS.md ADDED
@@ -0,0 +1,198 @@
1
+ # AGENTS.md
2
+
3
+ 本文件面向在本仓库工作的 AI agent 与人类贡献者。它定义**不可协商的工程约定**。开始任何任务前,先读:
4
+
5
+ 1. `README.md`
6
+ 2. `docs/api.md`
7
+ 3. `dev/development-plan.md`
8
+ 4. `dev/adapter-matrix.md`
9
+ 5. `dev/compatibility.md`
10
+ 6. `dev/decisions/` 下的 ADR
11
+
12
+ ## 1. 项目身份
13
+
14
+ | 项 | 值 |
15
+ | --- | --- |
16
+ | 项目名 | **gseek** |
17
+ | 导入包 | `gseek` |
18
+ | PyPI 分发名 | `gseek` |
19
+ | CLI | `gseek` |
20
+ | Python | `>=3.12` |
21
+ | 运行时依赖 | **零**(stdlib only) |
22
+ | 原项目名 | `gcore`(因 PyPI 名称被 Gcore 占用,2026-10-22 更名) |
23
+
24
+ 不要在新增代码、文档、schema、环境变量中重新引入 `gcore`。更名细节见 `dev/decisions/0002-project-rename.md`。
25
+
26
+ ## 2. 当前状态
27
+
28
+ - M0 基座 + M1/M2/M3/M4 适配器完成:结果模型、执行层、索引缓存、manifest、Runner、API、CLI。
29
+ - `gseek backends` 现在包含 **blast**、**minimap2**、**kma**、**mummer**、**bwa**、**mash**、**sourmash**、**skani**;真实工具集成测试通过。
30
+ - BLAST 支持核酸与蛋白任务;mash 支持 dist/screen;sourmash 支持 search/gather;`gseek replay` 已实现。
31
+ - 消费者迁移/parity(gside/gapit/gmlst)与 1.0 发布尚未完成。
32
+
33
+ ## 3. TDD 是强制流程
34
+
35
+ **没有失败的测试,不写生产代码。**
36
+
37
+ ### 3.1 Red-Green-Refactor
38
+
39
+ 每个行为变更按以下顺序:
40
+
41
+ 1. **Red**:先写一个最小测试,表达期望行为。
42
+ - 新功能:`tests/test_<area>.py::test_<behavior>`
43
+ - Bug 修复:先写复现该 bug 的回归测试
44
+ - 重命名/重构:先写“新契约”测试(例如 `tests/test_project_identity.py`)
45
+ 2. **确认失败**:运行该测试,确认失败原因是“行为缺失”,不是拼写/导入/夹具错误。
46
+ ```bash
47
+ pixi run test tests/test_area.py::test_behavior
48
+ ```
49
+ 如果测试因为错误原因失败,先修测试。
50
+ 3. **Green**:写**最少**的生产代码让该测试通过。不要顺手实现未测试的功能。
51
+ 4. **确认通过**:只跑目标测试 + 相关模块测试。
52
+ 5. **Refactor**:在测试全绿的前提下重构,保持行为不变。
53
+ 6. **全量门禁**:
54
+ ```bash
55
+ pixi run check
56
+ ```
57
+ 必须同时通过 `ruff`、`pyright`、全部 `pytest`。
58
+
59
+ ### 3.2 例外
60
+
61
+ - 纯文档、注释、README、ADR:不需要生产代码测试,但必须更新相关文档链接。
62
+ - 纯配置(CI、pixi、pre-commit):如果影响构建/测试行为,先加一个验证命令或测试。
63
+ - 纯格式化:可以在测试绿的前提下直接执行,随后跑全量门禁。
64
+
65
+ ### 3.3 适配器开发的 TDD 顺序
66
+
67
+ 实现一个适配器时,测试顺序固定:
68
+
69
+ 1. `BackendSpec` 能力/工具/版本约束测试。
70
+ 2. 命令规划测试(argv、cwd、env、输出路径、超时)。
71
+ 3. 解析器 golden 测试(真实输出 fixture,含反向、gapped、空结果、CRLF)。
72
+ 4. 坐标/identity/coverage 归一化测试。
73
+ 5. 索引 key / artifacts 测试。
74
+ 6. 集成测试(`@pytest.mark.integration`,无工具时 skip)。
75
+ 7. 消费者 parity 测试(gmlst/gapit/gside 的现有 golden)。
76
+
77
+ 只写命令规划、不写解析,或只写解析、不写错误路径,都不算完成。
78
+
79
+ ## 4. 架构边界
80
+
81
+ ```text
82
+ api → runner → adapters → execution / index / io / model
83
+ │
84
+ └→ capabilities / errors
85
+ ```
86
+
87
+ 必须遵守:
88
+
89
+ 1. **只有 `execution.py` 启动子进程。** 适配器不得直接 `subprocess`。
90
+ 2. **适配器是纯规划器/解析器。** `plan_index`/`plan_align` 返回命令;`parse_align` 返回记录。
91
+ 3. **不做业务结论。** 不实现 allele calling、ST 查找、物种规则、抗性判定。
92
+ 4. **不丢原始记录。** 归并是显式视图(`best_per_query_target`、`deduplicate_intervals` 等)。
93
+ 5. **坐标统一。** 0-based half-open、正向序列坐标、strand 单独字段。
94
+ 6. **identity/coverage 带来源。** 保留 `identity_method`、原始 `NM`/`nmatch`/`alen`。
95
+ 7. **索引内容寻址。** 不用 mtime;key 包含 adapter 版本、语义参数、target 内容哈希、工具版本。
96
+ 8. **默认确定性。** 无 shell、绝对路径、`LC_ALL=C`、稳定排序。
97
+ 9. **零运行时依赖。** 新增第三方库必须先有 ADR;可选功能放 extras。
98
+ 10. **schema 版本化。** `gseek.alignment/1`、`gseek.run/1` 等;破坏性变更升版本。
99
+
100
+ ## 5. MUMmer 版本决策
101
+
102
+ **目标:MUMmer 4.x,不是 MUMmer 3。**
103
+
104
+ 依据:
105
+
106
+ - `gmlst` 的 pixi 依赖为 `mummer4 = ">=4.0"`。
107
+ - 当前测试环境 conda 包:`mummer4-4.0.1-pl5321h9948957_0`。
108
+ - `nucmer --version` 与 `mummer --version` 均输出 `4.0.1`。
109
+ - `show-coords -rcl -T` 的 MUMmer4 输出为 13 列(`[TAGS]` 表头 + 两个 tag 列)。
110
+
111
+ 适配器要求:
112
+
113
+ - `ToolRequirement(binary="nucmer", version_args=("--version",), min_version=(4, 0, 0))`。
114
+ - 使用 `nucmer` + `show-coords -rcl -T`,不依赖 MUMmer3 的旧参数/输出。
115
+ - MUMmer3 不在 1.0 范围内;如需支持,新增独立适配器与 ADR,不要在同一解析器里猜版本。
116
+ - 反向命中用 `S2 > E2` 判断,不能硬编码 `+`。
117
+
118
+ 决策记录:`dev/decisions/0001-mummer4.md`。
119
+
120
+ ## 6. 代码规范
121
+
122
+ - 行宽 100;`ruff` 规则 `E,W,F,I,UP,B,C4,SIM,RET,RUF`;`ruff format`。
123
+ - 类型:`pyright` standard 必须 0 error;新增核心模块尽量使用精确类型,避免 `Any`。
124
+ - 公共 API 必须有 docstring 与 `__all__`。
125
+ - 单文件建议 ≤ 350 行;超过时按职责拆分。
126
+ - 使用 `pathlib.Path`,不要拼字符串路径。
127
+ - 异常使用 `gseek.errors` 的类型化错误;不要抛裸 `RuntimeError`。
128
+ - 测试使用 `tmp_path`;单元测试不得依赖网络或外部二进制。
129
+ - 需要外部工具的测试标记 `@pytest.mark.integration`,无工具时 `pytest.skip`。
130
+
131
+ ## 7. 目录约定
132
+
133
+ ```text
134
+ src/gseek/
135
+ ├── api.py # 便捷入口
136
+ ├── adapter.py # 请求/计划/协议
137
+ ├── capabilities.py # 能力声明
138
+ ├── execution.py # 唯一子进程层
139
+ ├── index.py # 内容寻址索引
140
+ ├── io.py # FASTA/FASTQ
141
+ ├── model/ # 结果与 manifest
142
+ ├── provenance.py # hash/recipe/manifest
143
+ ├── registry.py # 适配器注册
144
+ ├── runner.py # 编排
145
+ ├── adapters/ # M1–M3 + M4 protein/gather/skani
146
+ └── cli.py
147
+ tests/
148
+ ├── test_*.py # 单元/契约
149
+ ├── fixtures/ # 真实输出(后续)
150
+ ├── parity/ # 消费者 parity(后续)
151
+ └── integration/ # 外部工具(M1–M4 已加入)
152
+ docs/
153
+ └── api.md # 公共 API 参考(用户/适配器作者)
154
+ dev/
155
+ ├── development-plan.md
156
+ ├── adapter-matrix.md
157
+ ├── compatibility.md
158
+ ├── research.md
159
+ └── decisions/ # ADR
160
+ ```
161
+
162
+ ## 8. 验证命令
163
+
164
+ ```bash
165
+ pixi install # 首次
166
+ pixi run test # 全量单测
167
+ pixi run test-cov # 覆盖率(fail_under=85)
168
+ pixi run lint # ruff check + format --check
169
+ pixi run typecheck # pyright
170
+ pixi run check # lint + typecheck + test
171
+ pixi run pre-commit # 全部 pre-commit hook
172
+ pixi run test tests/test_x.py::test_y # 目标测试
173
+ ```
174
+
175
+ 提交前必须:
176
+
177
+ - [ ] 先有失败测试(Red),并确认失败原因。
178
+ - [ ] 目标测试通过(Green)。
179
+ - [ ] `pixi run check` 全绿。
180
+ - [ ] 新行为有测试;bug 有回归测试。
181
+ - [ ] 文档/ADR/CHANGELOG 按需更新。
182
+ - [ ] 没有提交 `dist/`、`.pixi/`、`.scratch/`、缓存或临时文件。
183
+
184
+ ## 9. 安全与可复现
185
+
186
+ - 永不使用 `shell=True`;argv 列表逐项传入。
187
+ - replay **不执行 manifest 中的任意 argv**;只按 adapter 重新规划。
188
+ - manifest 不记录密钥;环境变量只记录 allowlist。
189
+ - 所有输出路径必须位于 workspace 或 index staging 内。
190
+ - 不静默吞掉解析错误;错误必须带文件/行号/后端。
191
+ - 外部工具缺失/版本过旧必须给出可操作提示。
192
+
193
+ ## 10. 提交与发布
194
+
195
+ - 提交信息用英文、祈使句、短标题;正文说明测试与行为。
196
+ - PR 必须包含:行为说明、测试说明、验证命令、文档影响。
197
+ - 版本遵循 SemVer;1.0 前 API 可调整,但 schema 变更必须记录。
198
+ - 发布前:更新 `CHANGELOG.md`、`src/gseek/version.py`、跑 `pixi run check`、构建 wheel/sdist 并在干净环境安装验证。
@@ -0,0 +1,151 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] - 2026-10-24
10
+
11
+ ### Added
12
+
13
+ - **0.2.0 release preparation: first PyPI release target.**
14
+ - `gseek.distance(..., external_reference=True)` for pre-built distance
15
+ artifacts: mash `.msh` and sourmash `.sig`/`.zip` are consumed directly,
16
+ without index construction or reference re-sketching. External artifacts are
17
+ recorded as `InputKind.SKETCH`; replay re-passes the flag.
18
+ - mash `reads=True` params append `-m 2 -r` to the query sketch for
19
+ error-filtered FASTQ distance.
20
+ - sourmash gather/search parse `query_name` per row and expose
21
+ `reference_name`, `reference_md5`, and `f_unique_weighted` tags.
22
+ - `gseek distance --external-reference` exposes the pre-built-artifact path in
23
+ the CLI.
24
+ - `gseek --error-format {json,text}`; JSON remains the default for automation,
25
+ text is available for humans.
26
+ - User-facing docs: `docs/index.md`, `docs/quickstart.md`, `docs/cli.md`,
27
+ `docs/errors.md`, plus a relative-link regression test.
28
+ - `AGENTS.md`: mandatory TDD workflow, architecture boundaries, MUMmer4 policy.
29
+ - `CONTRIBUTING.md`, `CHANGELOG.md`, `.editorconfig`, `.pre-commit-config.yaml`.
30
+ - ADR-0001: target MUMmer **4.x**, not MUMmer3.
31
+ - ADR-0002: rename from `gcore` to `gseek`.
32
+ - Project identity tests (`tests/test_project_identity.py`) written before the
33
+ rename, covering import name, schemas, env vars, and CLI.
34
+ - **M1 adapters**:
35
+ - BLAST+ `blastn` adapter with `makeblastdb` target indexes, outfmt-6
36
+ streaming parser, reverse-strand coordinates, gap accounting, target
37
+ filtering, and `index_policy=none` subject mode.
38
+ - minimap2 adapter with explicit presets, PAF streaming parser, FASTA/FASTQ,
39
+ paired reads, primary/secondary filtering, `cg`-based gap counts, and
40
+ target indexes.
41
+ - Built-in adapter registry (`gseek.backends()` now lists `blast` and
42
+ `minimap2`).
43
+ - Prefix index entries (e.g. BLAST `targets` backed by `targets.nhr`) in
44
+ `IndexStore`.
45
+ - **M2 adapters**:
46
+ - KMA adapter with `kma index` target databases, `.res` parsing (no
47
+ coordinates), assembly/FASTQ/paired modes, depth, and template-level
48
+ identity/coverage.
49
+ - MUMmer4 `nucmer` + `show-coords -rcl -T` adapter, multi-step execution,
50
+ reverse-strand coordinates, no persistent index, and explicit MUMmer4
51
+ version gate.
52
+ - Built-in registry now lists `blast`, `minimap2`, `kma`, and `mummer`.
53
+ - **M3 adapters**:
54
+ - BWA-MEM adapter with `bwa index` target prefixes, SAM/CIGAR streaming,
55
+ reverse-strand query intervals, soft-clip accounting, paired reads, and
56
+ secondary/supplementary flags.
57
+ - mash adapter with `mash sketch`, `mash dist`, and reads `screen` mode;
58
+ MinHash distance/containment records.
59
+ - sourmash adapter with DNA sketches, `sourmash search` CSV, and
60
+ Jaccard/containment semantics.
61
+ - CIGAR helper now tracks leading/trailing soft and hard clips.
62
+ - **M4 features**:
63
+ - BLAST protein tasks: `blastp`, `blastx`, `tblastn`, `tblastx`, with
64
+ protein/nucleotide `makeblastdb` selection and SEG defaults.
65
+ - sourmash `gather` mode with `--threshold-bp` and gather CSV parsing.
66
+ - skani ANI adapter with sketch/search databases, ANI and aligned-fraction
67
+ records.
68
+ - Safe `gseek.replay` / `gseek replay` with `result_hash` in run manifests;
69
+ replay never executes recorded argv.
70
+ - Unit/contract tests for all eight adapters, plus real-tool integration tests
71
+ for index reuse, manifest verification, FASTQ mapping, thread invariance,
72
+ KMA paired reads, MUMmer reverse-strand hits, BWA paired reads, mash
73
+ dist/screen, sourmash search/gather, skani ANI, and manifest replay.
74
+
75
+ ### Changed
76
+
77
+ - **Renamed the project from `gcore` to `gseek`.** PyPI's `gcore` is already
78
+ owned by the Gcore Python API. Distribution, import package, CLI, environment
79
+ variables (`GSEEK_*`), schemas (`gseek.*`), and plugin entry point group are
80
+ now all `gseek`.
81
+ - `GcoreError` → `GseekError`.
82
+
83
+ ### Fixed
84
+
85
+ - `result_hash` is now computed over a canonical total order, so multi-record
86
+ `replay --check` no longer depends on parser or tool output order.
87
+ - `index_policy=rebuild` now actually replaces the published index; the cache
88
+ layer gained `publish(replace=...)` and returns `cache_hit=False` after a
89
+ rebuild.
90
+ - Tool paths resolved by `ToolResolver` (`overrides`, `GSEEK_<BINARY>`,
91
+ `extra_paths`, `GSEEK_PATH_PREPEND`) are bound into `Executor` and used for
92
+ execution; manifest commands now record the absolute executable.
93
+ - Index-only parameters (KMA `-k`, BWA `-a/-b`, skani `-c/-m`) are accepted by
94
+ the alignment/distance planners and no longer make end-to-end runs fail.
95
+ - Manifests record absolute input/target paths; `verify` resolves legacy
96
+ relative paths against the manifest directory, matching `replay`.
97
+ - Corrupt `index.json` values (for example a JSON array) are treated as cache
98
+ misses; `IndexStore(enabled=False)` rejects writes and Runner skips indexing.
99
+ - Probe caching now keys on resolved path/pattern/min_version/role, re-raises
100
+ cached missing tools under `strict=True`, and does not raise for optional
101
+ outdated tools. `BaseAdapter` distinguishes `ToolNotFoundError` from
102
+ `ToolVersionError` and forwards `ToolRequirement.hint`.
103
+ - BLAST always passes `-task` where supported (not `tblastx`), so `blastn` is
104
+ no longer silently megablast; protein tasks reject `-perc_identity`.
105
+ - minimap2 identity prefers `NM` (`paf_nm`) and falls back to `nmatch/alen`
106
+ (`paf_matches`); records expose `identity_from_nm`, `identity_from_matches`,
107
+ and `identity_nmatch_nm` parity views.
108
+ - JSON/TSV and ingestion fixes: deterministic set serialization, truthful
109
+ JSONL footer status, coordinate-less records preserved by
110
+ `deduplicate_intervals`, strict FASTQ record counting, streamed stderr
111
+ capped during drain, and executor-based manifest environment capture.
112
+ - CI integration now installs `skani` and runs nightly in addition to manual
113
+ dispatch.
114
+ - Added `external_reference=True` to `gseek.distance()`: mash/sourmash
115
+ adapters can consume pre-built `.msh`/`.sig`/`.zip` artifacts without
116
+ indexing or re-sketching references. External artifacts are recorded as
117
+ `InputKind.SKETCH` and replay re-passes the flag.
118
+ - Added real-tool golden fixtures under `tests/fixtures/`, field/formula parity
119
+ tests for gside/gapit/gmlst, and an 8-backend real replay matrix. Sourmash
120
+ reference IDs now fall back from signature name to a genome-like filename to
121
+ the unique `md5`, so references inside one combined `.sig` no longer collide.
122
+
123
+ ## [0.1.0] - 2026-10-22
124
+
125
+ ### Added
126
+
127
+ - Project foundation:
128
+ - `gseek.model`: `AlignmentRecord`, `AlignmentResult`, `DistanceResult`,
129
+ `RunManifest`, `IndexRef`, `CommandRecord`.
130
+ - `gseek.execution`: deterministic subprocess execution, timeouts, streaming,
131
+ stderr draining, tool resolution/version probing.
132
+ - `gseek.index`: content-addressed index cache, file locks, staging + atomic
133
+ publish, GC.
134
+ - `gseek.provenance`: SHA-256, canonical JSON, recipe hash, manifest
135
+ read/write/verify.
136
+ - `gseek.adapter`, `gseek.registry`, `gseek.runner`: adapter protocol,
137
+ registry, end-to-end orchestration.
138
+ - `gseek.api` and `gseek` CLI: align/distance/backends/doctor/index/manifest.
139
+ - Documentation:
140
+ - `docs/api.md`
141
+ - `dev/development-plan.md`
142
+ - `dev/research.md`
143
+ - `dev/adapter-matrix.md`
144
+ - `dev/compatibility.md`
145
+ - 250 unit/contract tests + 21 integration tests; 88% coverage; ruff + pyright clean.
146
+ - MIT license, pixi environment, GitHub Actions CI.
147
+
148
+ ### Notes
149
+
150
+ - M1–M4 adapter features (including protein BLAST, gather, skani, replay)
151
+ are implemented. Consumer migration/parity is still pending.
@@ -0,0 +1,126 @@
1
+ # Contributing to gseek
2
+
3
+ 感谢贡献。`gseek` 是 gside/gapit/gmlst 共用的 DNA 比对基础设施;正确性、可复现性和向后兼容比“多写代码”更重要。
4
+
5
+ ## 1. 开发环境
6
+
7
+ ```bash
8
+ pixi install
9
+ pixi run check
10
+ ```
11
+
12
+ 需要 Python ≥ 3.12。外部比对工具(BLAST+、minimap2、MUMmer4、KMA、BWA、mash、sourmash)只在集成测试中需要,不随包安装。
13
+
14
+ ## 2. TDD:先失败,再实现
15
+
16
+ **没有失败的测试,不写生产代码。** 详细规则见 [AGENTS.md](AGENTS.md)。
17
+
18
+ ### 2.1 最小示例
19
+
20
+ 假设要新增 `gseek.views.best_per_query`:
21
+
22
+ 1. 在 `tests/test_views.py` 写测试:
23
+ ```python
24
+ def test_best_per_query_keeps_highest_identity() -> None:
25
+ ...
26
+ assert best[0].identity == 99.0
27
+ ```
28
+ 2. 运行并确认失败:
29
+ ```bash
30
+ pixi run test tests/test_views.py::test_best_per_query_keeps_highest_identity
31
+ ```
32
+ 失败原因必须是 `AttributeError`/`ImportError` 等“功能不存在”,不能是测试写错。
33
+ 3. 写最少实现。
34
+ 4. 目标测试通过。
35
+ 5. 跑全量:
36
+ ```bash
37
+ pixi run check
38
+ ```
39
+ 6. 在绿的前提下重构。
40
+
41
+ ### 2.2 Bug 修复
42
+
43
+ 先写回归测试,确认它能在当前代码上复现 bug;再修复。禁止“先修再看”。
44
+
45
+ ### 2.3 重构/重命名
46
+
47
+ 先写新契约测试(例如 `tests/test_project_identity.py` 对 `gseek` 的断言),确认红;再改代码;最后全绿。
48
+
49
+ ## 3. 测试分层
50
+
51
+ | 层级 | 位置 | 依赖外部工具 | 说明 |
52
+ | --- | --- | --- | --- |
53
+ | 单元 | `tests/test_*.py` | 否 | 模型、解析、命令规划、hash、index |
54
+ | golden | `tests/fixtures/` | 否 | 真实工具输出,逐字段断言 |
55
+ | 集成 | `tests/integration/` | 是 | `@pytest.mark.integration`,无工具 skip |
56
+ | parity | `tests/parity/` | 部分 | 与 gside/gapit/gmlst 旧模型对比 |
57
+
58
+ 要求:
59
+
60
+ - 单元测试不联网、不依赖 PATH 里的工具。
61
+ - 所有临时文件用 `tmp_path`。
62
+ - 不 mock 掉被测逻辑;只 mock 进程边界(`Executor`/resolver)。
63
+ - 解析器测试必须覆盖:正常、反向、gapped、空结果、坏行、CRLF/空白。
64
+ - 新适配器必须包含命令规划测试与真实输出 golden。
65
+
66
+ ## 4. 架构红线
67
+
68
+ - 只有 `src/gseek/execution.py` 启动子进程。
69
+ - 适配器只做规划/解析,不做生物学判定。
70
+ - 结果模型无损;归并是显式视图。
71
+ - 坐标 0-based half-open;strand 单独字段。
72
+ - 索引内容寻址,不用 mtime。
73
+ - 核心零运行时依赖。
74
+ - 不使用 `shell=True`。
75
+ - 具体规则见 [AGENTS.md](AGENTS.md)。
76
+
77
+ ## 5. 代码风格
78
+
79
+ ```bash
80
+ pixi run format
81
+ pixi run lint
82
+ pixi run typecheck
83
+ ```
84
+
85
+ - `ruff` + `ruff format`,行宽 100。
86
+ - `pyright` standard 0 error。
87
+ - 公共 API 写 docstring 和类型注解。
88
+ - 异常使用 `gseek.errors`。
89
+ - 单文件建议 ≤ 350 行。
90
+
91
+ ## 6. 文档
92
+
93
+ - 公共 API/行为变化更新 `docs/api.md`;设计/架构说明更新 `dev/` 对应文档。
94
+ - 架构/版本/命名决策写 ADR:`dev/decisions/NNNN-title.md`。
95
+ - 用户可见变化更新 `CHANGELOG.md`。
96
+ - MUMmer:目标为 **MUMmer 4.x**,见 [ADR-0001](dev/decisions/0001-mummer4.md)。
97
+
98
+ ## 7. 提交与 PR
99
+
100
+ 提交信息用英文祈使句:
101
+
102
+ ```text
103
+ Add FASTA duplicate-ID validation
104
+ Fix PAF reverse-strand coordinate normalization
105
+ Rename package to gseek
106
+ ```
107
+
108
+ PR 描述包含:
109
+
110
+ 1. 行为变化(用户可见)
111
+ 2. 测试说明(先失败的测试是哪一个)
112
+ 3. 验证命令与结果
113
+ 4. 文档/CHANGELOG/ADR 影响
114
+
115
+ ## 8. 发布
116
+
117
+ 1. 更新 `src/gseek/version.py` 与 `pyproject.toml` 的版本。
118
+ 2. 更新 `CHANGELOG.md`。
119
+ 3. `pixi run check`。
120
+ 4. `python -m build` + `twine check dist/*`。
121
+ 5. 在干净 venv 中 `pip install dist/*.whl`,跑 `gseek --version` 和最小 API 冒烟。
122
+ 6. 打 tag、发布 PyPI/conda。
123
+
124
+ ## 9. 许可证
125
+
126
+ 贡献即同意以 MIT 许可证发布。详见 [LICENSE](LICENSE)。
gseek-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gseek contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.