allelix 2.1.1__tar.gz → 2.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.
- {allelix-2.1.1 → allelix-2.2.0}/PKG-INFO +56 -38
- {allelix-2.1.1 → allelix-2.2.0}/README.md +53 -37
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/__init__.py +10 -12
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/base.py +0 -38
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/cadd.py +9 -7
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/clinvar.py +122 -57
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/_helpers.py +66 -4
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/_options.py +19 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/config.py +10 -18
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/db.py +231 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/focused.py +3 -3
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/utility.py +6 -36
- {allelix-2.1.1 → allelix-2.2.0}/allelix/config.py +34 -14
- {allelix-2.1.1 → allelix-2.2.0}/allelix/data/clinvar_clnsig_snapshot.yaml +13 -1
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/_versions.py +7 -1
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/cpic_loader.py +2 -2
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/gwas_loader.py +12 -2
- allelix-2.2.0/allelix/databases/manager.py +758 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/snpedia_parser.py +6 -4
- {allelix-2.1.1 → allelix-2.2.0}/allelix/exporters/plink.py +50 -1
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/__init__.py +2 -0
- allelix-2.2.0/allelix/parsers/ftdna_famfinder.py +175 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/__init__.py +3 -3
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/_pipeline.py +121 -5
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/diff.py +1 -1
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/html.py +54 -1
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/json_report.py +10 -2
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/terminal.py +38 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/utils/allele.py +18 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix.egg-info/PKG-INFO +56 -38
- {allelix-2.1.1 → allelix-2.2.0}/allelix.egg-info/SOURCES.txt +1 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix.egg-info/requires.txt +2 -0
- allelix-2.2.0/pyproject.toml +156 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_cli.py +474 -41
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_config.py +23 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_mock_data_invariants.py +0 -137
- allelix-2.1.1/allelix/databases/manager.py +0 -532
- allelix-2.1.1/pyproject.toml +0 -104
- {allelix-2.1.1 → allelix-2.2.0}/LICENSE +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/__init__.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/alphamissense.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/gnomad.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/gwas.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/pharmgkb.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/annotators/snpedia.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/__init__.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/cli/analyze.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/compare.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/data/__init__.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/data/high_value_snps.yaml +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/__init__.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/alphamissense_loader.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/cadd_loader.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/gnomad_loader.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/loader_utils.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/pharmgkb_loader.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/schema.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/databases/snpedia_loader.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/exporters/__init__.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/models.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/_helpers.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/ancestrydna.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/base.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/ftdna.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/ftdna_illumina.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/livingdna.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/myhappygenes.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/myheritage.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/twentythreeandme.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/parsers/vcf.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/py.typed +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/high_value.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/reports/methylation.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/utils/__init__.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix/utils/build_detect.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix.egg-info/dependency_links.txt +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix.egg-info/entry_points.txt +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/allelix.egg-info/top_level.txt +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/setup.cfg +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_cli_helpers.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_compare.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_end_to_end.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_models.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_registry.py +0 -0
- {allelix-2.1.1 → allelix-2.2.0}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: allelix
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Open-source genotype analysis toolkit. Format-agnostic ingestion, database-agnostic annotation, offline-first.
|
|
5
5
|
Author: Allelix
|
|
6
6
|
Maintainer-email: dial481 <dial481@users.noreply.github.com>
|
|
@@ -29,35 +29,33 @@ Requires-Dist: pysam>=0.22; extra == "cadd"
|
|
|
29
29
|
Provides-Extra: vcf-index
|
|
30
30
|
Requires-Dist: pysam>=0.22; extra == "vcf-index"
|
|
31
31
|
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
32
33
|
Requires-Dist: pre-commit>=3.7; extra == "dev"
|
|
33
34
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
34
35
|
Requires-Dist: pytest-cov<8,>=7; extra == "dev"
|
|
35
36
|
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
37
|
+
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
|
|
36
38
|
Dynamic: license-file
|
|
37
39
|
|
|
40
|
+
<div align="center">
|
|
41
|
+
|
|
42
|
+
<img src="https://allelix.io/apple-touch-icon.png" width="180" alt="Allelix" />
|
|
43
|
+
|
|
44
|
+
**Open-source genotype analysis. Format-agnostic. Offline-first.**
|
|
45
|
+
|
|
46
|
+
[Website](https://allelix.io) · [Quickstart](#quickstart) · [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md)
|
|
47
|
+
|
|
48
|
+
[](https://www.python.org/downloads/)
|
|
49
|
+
[](https://pypi.org/project/allelix/)
|
|
50
|
+
[](LICENSE)
|
|
51
|
+
[](https://github.com/allelix/allelix/actions/workflows/ci.yml)
|
|
52
|
+
[](#privacy)
|
|
53
|
+
|
|
54
|
+
</div>
|
|
55
|
+
|
|
38
56
|
# Allelix
|
|
39
57
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
> **Status:** Production — eight parser formats (including VCF + gVCF),
|
|
43
|
-
> four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three
|
|
44
|
-
> enrichment sources (gnomAD population frequencies + AlphaMissense
|
|
45
|
-
> pathogenicity + CADD deleteriousness), licensable-source gating for
|
|
46
|
-
> commercial users, dual-build ClinVar caches (GRCh37 + GRCh38),
|
|
47
|
-
> HTML/JSON/terminal reports, methylation + pharmacogenomics focused
|
|
48
|
-
> commands, report diffing, persistent config with commercial-mode
|
|
49
|
-
> safety switch. Build auto-detection from position data (ADR-0021).
|
|
50
|
-
> No regex on prose anywhere in production. **Latest: v2.1.0** —
|
|
51
|
-
> ADR-0035 'Cluster B' coordinated model change: `Variant.ref` carries
|
|
52
|
-
> the forward-strand reference allele, per-Annotation `alt` threading
|
|
53
|
-
> on GWAS / SNPedia / ClinPGx enables allele-specific gnomAD /
|
|
54
|
-
> AlphaMissense / CADD enrichment on array inputs, structured GWAS
|
|
55
|
-
> fields (`trait` / `p_value` / `phecode`) replace prose re-parsing in
|
|
56
|
-
> the rollup, and ClinVar / ClinPGx carrier matching is strand-aware
|
|
57
|
-
> with multi-allelic safety guard. JSON `schema_version` bumped 4 → 5
|
|
58
|
-
> (additive, v4 readers unaffected).
|
|
59
|
-
> Release notes:
|
|
60
|
-
> [`CHANGELOG.md`](https://github.com/allelix/allelix/blob/main/CHANGELOG.md).
|
|
58
|
+
> **Status:** Production. Eight parser formats (including VCF + gVCF), four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three enrichment sources (gnomAD + AlphaMissense + CADD), licensable-source gating for commercial users, dual-build ClinVar caches (GRCh37 + GRCh38), HTML/JSON/terminal reports, methylation + pharmacogenomics focused commands, report diffing, persistent config with commercial-mode safety switch. Build auto-detection from position data (ADR-0021). No regex on prose anywhere in production. The [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md) tracks every release.
|
|
61
59
|
|
|
62
60
|
## Quickstart
|
|
63
61
|
|
|
@@ -97,20 +95,22 @@ See [Development](#development) for source installs and running tests, [Managing
|
|
|
97
95
|
| MyHeritage DNA | ✓ | CSV, same structure as FTDNA. Detected by "MyHeritage" in comment header. Handles double-double-quoted field variant. |
|
|
98
96
|
| Living DNA | ✓ | Tab-delimited despite `.csv` extension. Handles AX-, AFFX-prefixed and CHR:POS positional SNP IDs. |
|
|
99
97
|
| FTDNA Illumina raw | ✓ | Tab-delimited variant of the FTDNA export (distinct from the CSV format above). `RSID/CHROMOSOME/POSITION/RESULT` columns. Build 37 default. |
|
|
98
|
+
| FTDNA FamFinder | ✓ | Third FTDNA file shape: tab-delimited with **separate `ALLELE1` / `ALLELE2` columns** instead of a concatenated `RESULT`. Detected by the `famfinder` substring in the file header plus the 5-column canonical header. Build 37 default. |
|
|
100
99
|
| VCF / gVCF | ✓ | REF/ALT encoding, `0/1` genotype notation. Plain VCF: absence at a position means reference. gVCF: explicit reference blocks (lines with `<NON_REF>` ALT and `END=` INFO) are skipped — they match nothing in any annotation database. Multi-sample files require `--sample <ID>`. Streams via stdlib; `.vcf.gz` handled transparently. Optional `pip install allelix[vcf-index]` enables pysam-backed tabix random access for fast `extract --snps` on huge VCFs. |
|
|
101
100
|
|
|
102
101
|
Adding a new format means adding one file to `allelix/parsers/` and registering an instance in the `PARSERS` list in `allelix/parsers/__init__.py`.
|
|
103
102
|
|
|
104
|
-
###
|
|
103
|
+
### Roadmap
|
|
105
104
|
|
|
106
|
-
|
|
|
105
|
+
| Release | Theme |
|
|
107
106
|
|---|---|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
107
|
+
| **v2.2** | Annotation model expansion (cross-source conflict surfacing, risk-allele display, structured MTAG flag), custom-panel UX improvements, methylation panel retune + citations, ClinVar source switch (VCF → `variant_summary.txt`), CLI cleanups (`db clean` / `db path`). |
|
|
108
|
+
| **v2.3** | Per-source magnitude decomposition, Good / Bad / Neutral annotation repute, JSON v3 (AI-legible output contract), plausibility flagging via zygosity × gnomAD MAF, ClinVar review-status weighting, functional-medicine +/− notation. |
|
|
109
|
+
| **v2.4** | ACMG/AMP automated classification engine, variant consequence annotation (VEP-equivalent). |
|
|
110
|
+
| **v2.5+** | CNVs and repeat-expansion support, dbSNP resolution for rsID-less VCFs, gnomAD genomes (non-coding population frequencies), supplemental genotype file merging. |
|
|
111
|
+
| **v3.0** | Ancestry estimation (PCA + 1KG/HGDP reference panels), Polygenic Risk Score (PRS) integration. |
|
|
112
|
+
|
|
113
|
+
Issues and milestones are tracked at [github.com/allelix/allelix/issues](https://github.com/allelix/allelix/issues). Annotator-level strand-aware carrier matching (R-1) shipped in v2.1.0's ADR-0035 cluster.
|
|
114
114
|
|
|
115
115
|
## Supported Databases
|
|
116
116
|
|
|
@@ -254,28 +254,44 @@ Allelix stores reference database caches at `~/.local/share/allelix/` (Linux/mac
|
|
|
254
254
|
**The caches are disposable and re-downloadable.** Everything here was fetched by `allelix db update` and can be re-fetched at any time. There's no per-user state in the cache — your genotype files never enter this directory. Safe to delete to reclaim space (or to force a full refresh if you suspect a cache went stale):
|
|
255
255
|
|
|
256
256
|
```bash
|
|
257
|
-
# Reclaim all ~16-22 GB
|
|
258
|
-
|
|
257
|
+
# Reclaim all ~16-22 GB, with size report and confirmation prompt
|
|
258
|
+
allelix db clean
|
|
259
|
+
|
|
260
|
+
# Preserve the CADD cache (avoids re-downloading the slowest one, ~5.8 GB)
|
|
261
|
+
allelix db clean --keep-cadd
|
|
262
|
+
|
|
263
|
+
# Show what would be deleted without acting
|
|
264
|
+
allelix db clean --dry-run
|
|
259
265
|
|
|
260
|
-
#
|
|
261
|
-
|
|
266
|
+
# Scripted use — skip the confirmation prompt
|
|
267
|
+
allelix db clean --yes
|
|
262
268
|
|
|
263
269
|
# Re-populate from scratch next time you analyze a file
|
|
264
270
|
allelix db update
|
|
265
271
|
```
|
|
266
272
|
|
|
267
|
-
|
|
273
|
+
`db clean` refuses to act on a directory that doesn't contain any recognized allelix cache files — a typo'd `--data-dir ~/Documents` won't result in `rm -rf` against an unrelated tree, even with `--yes`. Pass `--force` if you've staged caches under a non-standard name and want to delete them anyway.
|
|
274
|
+
|
|
275
|
+
For scripting and backup integration, `allelix db path` prints the resolved data directory:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
ALLELIX_DATA=$(allelix db path)
|
|
279
|
+
du -sh "$ALLELIX_DATA"
|
|
280
|
+
|
|
281
|
+
# --check additionally verifies the path is writable; exit non-zero if not
|
|
282
|
+
allelix db path --check
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**The one thing worth backing up: `config.toml`.** It lives separately (XDG config dir, typically `~/.config/allelix/config.toml`) and stores your license assertions (commercial-mode toggle, CADD opt-in confirmation) and per-source enable/disable settings. It's the only non-reproducible state in the install. The caches will rebuild on the next `db update`; `config.toml` won't. `allelix db clean` preserves `config.toml` even when it lives inside the data directory (older installs).
|
|
268
286
|
|
|
269
287
|
To fully uninstall allelix and reclaim everything:
|
|
270
288
|
|
|
271
289
|
```bash
|
|
272
290
|
pip uninstall allelix
|
|
273
|
-
|
|
291
|
+
allelix db clean --yes # reference database caches
|
|
274
292
|
rm -rf ~/.config/allelix/ # license + source-toggle config
|
|
275
293
|
```
|
|
276
294
|
|
|
277
|
-
A `allelix db clean` subcommand to automate the cache-clear step (with confirmation prompt and size report) is planned for v2.2 alongside `allelix db path` (prints the resolved data directory for scripting / backup integration).
|
|
278
|
-
|
|
279
295
|
## Data Sources & Licensing
|
|
280
296
|
|
|
281
297
|
Allelix source code is licensed under the **GNU Affero General Public License v3.0 or later** (AGPL-3.0-or-later). Allelix ships with **zero third-party data**. All reference databases are downloaded by the user at runtime via `allelix db update`. Each database retains its original license on the user's machine:
|
|
@@ -384,6 +400,8 @@ pytest
|
|
|
384
400
|
|
|
385
401
|
The pre-commit hook enforces `ruff check` + `ruff format --check`. If a commit is blocked, fix the underlying problem rather than skipping the hook.
|
|
386
402
|
|
|
403
|
+
For the full real-data release-validation battery — every parser format, VCF/gVCF, PLINK round-trip, edge cases, the GIAB/1000G corpus — see [`test_data/FULL_TEST_PROTOCOL.md`](test_data/FULL_TEST_PROTOCOL.md). That document is the project's real-data testing story; running `pytest` covers the fast suite that gates every commit.
|
|
404
|
+
|
|
387
405
|
## License
|
|
388
406
|
|
|
389
407
|
GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). See `LICENSE`.
|
|
@@ -1,26 +1,22 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://allelix.io/apple-touch-icon.png" width="180" alt="Allelix" />
|
|
4
|
+
|
|
5
|
+
**Open-source genotype analysis. Format-agnostic. Offline-first.**
|
|
6
|
+
|
|
7
|
+
[Website](https://allelix.io) · [Quickstart](#quickstart) · [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md)
|
|
8
|
+
|
|
9
|
+
[](https://www.python.org/downloads/)
|
|
10
|
+
[](https://pypi.org/project/allelix/)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
[](https://github.com/allelix/allelix/actions/workflows/ci.yml)
|
|
13
|
+
[](#privacy)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
1
17
|
# Allelix
|
|
2
18
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
> **Status:** Production — eight parser formats (including VCF + gVCF),
|
|
6
|
-
> four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three
|
|
7
|
-
> enrichment sources (gnomAD population frequencies + AlphaMissense
|
|
8
|
-
> pathogenicity + CADD deleteriousness), licensable-source gating for
|
|
9
|
-
> commercial users, dual-build ClinVar caches (GRCh37 + GRCh38),
|
|
10
|
-
> HTML/JSON/terminal reports, methylation + pharmacogenomics focused
|
|
11
|
-
> commands, report diffing, persistent config with commercial-mode
|
|
12
|
-
> safety switch. Build auto-detection from position data (ADR-0021).
|
|
13
|
-
> No regex on prose anywhere in production. **Latest: v2.1.0** —
|
|
14
|
-
> ADR-0035 'Cluster B' coordinated model change: `Variant.ref` carries
|
|
15
|
-
> the forward-strand reference allele, per-Annotation `alt` threading
|
|
16
|
-
> on GWAS / SNPedia / ClinPGx enables allele-specific gnomAD /
|
|
17
|
-
> AlphaMissense / CADD enrichment on array inputs, structured GWAS
|
|
18
|
-
> fields (`trait` / `p_value` / `phecode`) replace prose re-parsing in
|
|
19
|
-
> the rollup, and ClinVar / ClinPGx carrier matching is strand-aware
|
|
20
|
-
> with multi-allelic safety guard. JSON `schema_version` bumped 4 → 5
|
|
21
|
-
> (additive, v4 readers unaffected).
|
|
22
|
-
> Release notes:
|
|
23
|
-
> [`CHANGELOG.md`](https://github.com/allelix/allelix/blob/main/CHANGELOG.md).
|
|
19
|
+
> **Status:** Production. Eight parser formats (including VCF + gVCF), four annotators (ClinVar + ClinPGx + GWAS Catalog + SNPedia), three enrichment sources (gnomAD + AlphaMissense + CADD), licensable-source gating for commercial users, dual-build ClinVar caches (GRCh37 + GRCh38), HTML/JSON/terminal reports, methylation + pharmacogenomics focused commands, report diffing, persistent config with commercial-mode safety switch. Build auto-detection from position data (ADR-0021). No regex on prose anywhere in production. The [Changelog](https://github.com/allelix/allelix/blob/main/CHANGELOG.md) tracks every release.
|
|
24
20
|
|
|
25
21
|
## Quickstart
|
|
26
22
|
|
|
@@ -60,20 +56,22 @@ See [Development](#development) for source installs and running tests, [Managing
|
|
|
60
56
|
| MyHeritage DNA | ✓ | CSV, same structure as FTDNA. Detected by "MyHeritage" in comment header. Handles double-double-quoted field variant. |
|
|
61
57
|
| Living DNA | ✓ | Tab-delimited despite `.csv` extension. Handles AX-, AFFX-prefixed and CHR:POS positional SNP IDs. |
|
|
62
58
|
| FTDNA Illumina raw | ✓ | Tab-delimited variant of the FTDNA export (distinct from the CSV format above). `RSID/CHROMOSOME/POSITION/RESULT` columns. Build 37 default. |
|
|
59
|
+
| FTDNA FamFinder | ✓ | Third FTDNA file shape: tab-delimited with **separate `ALLELE1` / `ALLELE2` columns** instead of a concatenated `RESULT`. Detected by the `famfinder` substring in the file header plus the 5-column canonical header. Build 37 default. |
|
|
63
60
|
| VCF / gVCF | ✓ | REF/ALT encoding, `0/1` genotype notation. Plain VCF: absence at a position means reference. gVCF: explicit reference blocks (lines with `<NON_REF>` ALT and `END=` INFO) are skipped — they match nothing in any annotation database. Multi-sample files require `--sample <ID>`. Streams via stdlib; `.vcf.gz` handled transparently. Optional `pip install allelix[vcf-index]` enables pysam-backed tabix random access for fast `extract --snps` on huge VCFs. |
|
|
64
61
|
|
|
65
62
|
Adding a new format means adding one file to `allelix/parsers/` and registering an instance in the `PARSERS` list in `allelix/parsers/__init__.py`.
|
|
66
63
|
|
|
67
|
-
###
|
|
64
|
+
### Roadmap
|
|
68
65
|
|
|
69
|
-
|
|
|
66
|
+
| Release | Theme |
|
|
70
67
|
|---|---|
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
68
|
+
| **v2.2** | Annotation model expansion (cross-source conflict surfacing, risk-allele display, structured MTAG flag), custom-panel UX improvements, methylation panel retune + citations, ClinVar source switch (VCF → `variant_summary.txt`), CLI cleanups (`db clean` / `db path`). |
|
|
69
|
+
| **v2.3** | Per-source magnitude decomposition, Good / Bad / Neutral annotation repute, JSON v3 (AI-legible output contract), plausibility flagging via zygosity × gnomAD MAF, ClinVar review-status weighting, functional-medicine +/− notation. |
|
|
70
|
+
| **v2.4** | ACMG/AMP automated classification engine, variant consequence annotation (VEP-equivalent). |
|
|
71
|
+
| **v2.5+** | CNVs and repeat-expansion support, dbSNP resolution for rsID-less VCFs, gnomAD genomes (non-coding population frequencies), supplemental genotype file merging. |
|
|
72
|
+
| **v3.0** | Ancestry estimation (PCA + 1KG/HGDP reference panels), Polygenic Risk Score (PRS) integration. |
|
|
73
|
+
|
|
74
|
+
Issues and milestones are tracked at [github.com/allelix/allelix/issues](https://github.com/allelix/allelix/issues). Annotator-level strand-aware carrier matching (R-1) shipped in v2.1.0's ADR-0035 cluster.
|
|
77
75
|
|
|
78
76
|
## Supported Databases
|
|
79
77
|
|
|
@@ -217,28 +215,44 @@ Allelix stores reference database caches at `~/.local/share/allelix/` (Linux/mac
|
|
|
217
215
|
**The caches are disposable and re-downloadable.** Everything here was fetched by `allelix db update` and can be re-fetched at any time. There's no per-user state in the cache — your genotype files never enter this directory. Safe to delete to reclaim space (or to force a full refresh if you suspect a cache went stale):
|
|
218
216
|
|
|
219
217
|
```bash
|
|
220
|
-
# Reclaim all ~16-22 GB
|
|
221
|
-
|
|
218
|
+
# Reclaim all ~16-22 GB, with size report and confirmation prompt
|
|
219
|
+
allelix db clean
|
|
220
|
+
|
|
221
|
+
# Preserve the CADD cache (avoids re-downloading the slowest one, ~5.8 GB)
|
|
222
|
+
allelix db clean --keep-cadd
|
|
223
|
+
|
|
224
|
+
# Show what would be deleted without acting
|
|
225
|
+
allelix db clean --dry-run
|
|
222
226
|
|
|
223
|
-
#
|
|
224
|
-
|
|
227
|
+
# Scripted use — skip the confirmation prompt
|
|
228
|
+
allelix db clean --yes
|
|
225
229
|
|
|
226
230
|
# Re-populate from scratch next time you analyze a file
|
|
227
231
|
allelix db update
|
|
228
232
|
```
|
|
229
233
|
|
|
230
|
-
|
|
234
|
+
`db clean` refuses to act on a directory that doesn't contain any recognized allelix cache files — a typo'd `--data-dir ~/Documents` won't result in `rm -rf` against an unrelated tree, even with `--yes`. Pass `--force` if you've staged caches under a non-standard name and want to delete them anyway.
|
|
235
|
+
|
|
236
|
+
For scripting and backup integration, `allelix db path` prints the resolved data directory:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
ALLELIX_DATA=$(allelix db path)
|
|
240
|
+
du -sh "$ALLELIX_DATA"
|
|
241
|
+
|
|
242
|
+
# --check additionally verifies the path is writable; exit non-zero if not
|
|
243
|
+
allelix db path --check
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**The one thing worth backing up: `config.toml`.** It lives separately (XDG config dir, typically `~/.config/allelix/config.toml`) and stores your license assertions (commercial-mode toggle, CADD opt-in confirmation) and per-source enable/disable settings. It's the only non-reproducible state in the install. The caches will rebuild on the next `db update`; `config.toml` won't. `allelix db clean` preserves `config.toml` even when it lives inside the data directory (older installs).
|
|
231
247
|
|
|
232
248
|
To fully uninstall allelix and reclaim everything:
|
|
233
249
|
|
|
234
250
|
```bash
|
|
235
251
|
pip uninstall allelix
|
|
236
|
-
|
|
252
|
+
allelix db clean --yes # reference database caches
|
|
237
253
|
rm -rf ~/.config/allelix/ # license + source-toggle config
|
|
238
254
|
```
|
|
239
255
|
|
|
240
|
-
A `allelix db clean` subcommand to automate the cache-clear step (with confirmation prompt and size report) is planned for v2.2 alongside `allelix db path` (prints the resolved data directory for scripting / backup integration).
|
|
241
|
-
|
|
242
256
|
## Data Sources & Licensing
|
|
243
257
|
|
|
244
258
|
Allelix source code is licensed under the **GNU Affero General Public License v3.0 or later** (AGPL-3.0-or-later). Allelix ships with **zero third-party data**. All reference databases are downloaded by the user at runtime via `allelix db update`. Each database retains its original license on the user's machine:
|
|
@@ -347,6 +361,8 @@ pytest
|
|
|
347
361
|
|
|
348
362
|
The pre-commit hook enforces `ruff check` + `ruff format --check`. If a commit is blocked, fix the underlying problem rather than skipping the hook.
|
|
349
363
|
|
|
364
|
+
For the full real-data release-validation battery — every parser format, VCF/gVCF, PLINK round-trip, edge cases, the GIAB/1000G corpus — see [`test_data/FULL_TEST_PROTOCOL.md`](test_data/FULL_TEST_PROTOCOL.md). That document is the project's real-data testing story; running `pytest` covers the fast suite that gates every commit.
|
|
365
|
+
|
|
350
366
|
## License
|
|
351
367
|
|
|
352
368
|
GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). See `LICENSE`.
|
|
@@ -57,18 +57,16 @@ def get_annotators(
|
|
|
57
57
|
return [clinvar, pharmgkb, gwas, snpedia, gnomad, alphamissense, cadd]
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
]
|
|
71
|
-
}
|
|
60
|
+
_ANNOTATOR_CLASS_LIST: list[type[Annotator]] = [
|
|
61
|
+
ClinVarAnnotator,
|
|
62
|
+
PharmGKBAnnotator,
|
|
63
|
+
GWASCatalogAnnotator,
|
|
64
|
+
SNPediaAnnotator,
|
|
65
|
+
GnomadAnnotator,
|
|
66
|
+
AlphaMissenseAnnotator,
|
|
67
|
+
CaddAnnotator,
|
|
68
|
+
]
|
|
69
|
+
_ANNOTATOR_CLASSES: dict[str, type[Annotator]] = {cls.name: cls for cls in _ANNOTATOR_CLASS_LIST}
|
|
72
70
|
|
|
73
71
|
|
|
74
72
|
def get_annotator_class(name: str) -> type[Annotator] | None:
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import contextlib
|
|
8
7
|
from abc import ABC, abstractmethod
|
|
9
8
|
from dataclasses import dataclass
|
|
10
9
|
from enum import Enum, auto
|
|
@@ -141,43 +140,6 @@ class Annotator(ABC):
|
|
|
141
140
|
"""Bind the annotator to a data directory (created elsewhere)."""
|
|
142
141
|
self.data_dir = data_dir
|
|
143
142
|
|
|
144
|
-
def __del__(self) -> None:
|
|
145
|
-
"""Safety-net resource release on GC. Deliberately retained.
|
|
146
|
-
|
|
147
|
-
Status (v2.1.1 audit, GH #36):
|
|
148
|
-
- **Production callsites are clean.** ``run_analysis`` wires every
|
|
149
|
-
primary + enrichment annotator into ``contextlib.ExitStack``
|
|
150
|
-
(v2.0.2 fix). ``allelix/cli/utility.py`` lines 221 and 476 each
|
|
151
|
-
construct a ``GnomadAnnotator`` inside ``try / finally
|
|
152
|
-
gnomad.close()``. ``allelix/annotators/__init__.py`` returns a
|
|
153
|
-
list that the pipeline immediately wraps in ``ExitStack``.
|
|
154
|
-
- **Test callsites NOT yet clean.** ~27 sites in
|
|
155
|
-
``tests/reports/test_pipeline.py`` instantiate annotators
|
|
156
|
-
directly without a context manager or explicit close. The
|
|
157
|
-
pipeline closes them via its own ``ExitStack`` during
|
|
158
|
-
``run_analysis``, but the test still holds the closed-instance
|
|
159
|
-
reference, and the underlying sqlite3 ``Connection``'s GC
|
|
160
|
-
finalizer surfaces a ``ResourceWarning`` during the next test's
|
|
161
|
-
startup. pytest's ``error::PytestUnraisableExceptionWarning``
|
|
162
|
-
filter then converts it to a hard failure on the gate.
|
|
163
|
-
|
|
164
|
-
Removing ``__del__`` without first refactoring the test sites
|
|
165
|
-
therefore fails the gate (verified — 3 failures, all in
|
|
166
|
-
``tests/reports/test_pipeline.py``, triggered by leaks from
|
|
167
|
-
earlier tests in the same file). The test-site refactor is
|
|
168
|
-
tracked separately; ``__del__`` stays as the safety net until
|
|
169
|
-
that lands. v2.1.x task — see the follow-up issue filed at
|
|
170
|
-
``#36``-closure-time.
|
|
171
|
-
|
|
172
|
-
``contextlib.suppress(Exception)`` is deliberate — ``__del__``
|
|
173
|
-
must never raise. GC timing and shutdown-ordering edges are
|
|
174
|
-
explicitly silenced; this is exactly the "if you must keep
|
|
175
|
-
``__del__``, make absolutely sure it can never raise"
|
|
176
|
-
mitigation the audit recommended.
|
|
177
|
-
"""
|
|
178
|
-
with contextlib.suppress(Exception):
|
|
179
|
-
self.close()
|
|
180
|
-
|
|
181
143
|
def __enter__(self) -> Annotator:
|
|
182
144
|
"""Return self for `with` usage."""
|
|
183
145
|
return self
|
|
@@ -24,7 +24,7 @@ from __future__ import annotations
|
|
|
24
24
|
|
|
25
25
|
import logging
|
|
26
26
|
import sqlite3
|
|
27
|
-
from typing import TYPE_CHECKING, ClassVar
|
|
27
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
28
28
|
|
|
29
29
|
from allelix.annotators.base import Annotator, LicenseDescriptor
|
|
30
30
|
from allelix.databases._versions import CADD_SCHEMA_VERSION
|
|
@@ -90,9 +90,11 @@ class CaddAnnotator(Annotator):
|
|
|
90
90
|
self._conn: sqlite3.Connection | None = None
|
|
91
91
|
self._full_mode = full_mode
|
|
92
92
|
self._tabix_path = data_dir / CADD_FULL_FILENAME
|
|
93
|
-
|
|
93
|
+
# pysam ships no type stubs (see [tool.mypy.overrides]); the tabix
|
|
94
|
+
# handle is held as Any so call sites can use `.fetch()` / `.close()`.
|
|
95
|
+
self._tabix: Any = None
|
|
94
96
|
self._indel_tabix_path = data_dir / CADD_INDEL_FILENAME
|
|
95
|
-
self._indel_tabix:
|
|
97
|
+
self._indel_tabix: Any = None
|
|
96
98
|
|
|
97
99
|
def _connection(self) -> sqlite3.Connection:
|
|
98
100
|
if self._conn is None:
|
|
@@ -104,11 +106,11 @@ class CaddAnnotator(Annotator):
|
|
|
104
106
|
self._conn = sqlite3.connect(self._db_path)
|
|
105
107
|
return self._conn
|
|
106
108
|
|
|
107
|
-
def _open_tabix(self) ->
|
|
109
|
+
def _open_tabix(self) -> Any: # noqa: ANN401 — pysam ships no type stubs
|
|
108
110
|
"""Open the tabix file for full-mode queries."""
|
|
109
111
|
if self._tabix is None:
|
|
110
112
|
try:
|
|
111
|
-
import pysam
|
|
113
|
+
import pysam
|
|
112
114
|
except ImportError:
|
|
113
115
|
raise ImportError(
|
|
114
116
|
"Full CADD mode requires pysam. Install with: pip install 'allelix[cadd]'"
|
|
@@ -122,7 +124,7 @@ class CaddAnnotator(Annotator):
|
|
|
122
124
|
self._tabix = pysam.TabixFile(str(self._tabix_path))
|
|
123
125
|
return self._tabix
|
|
124
126
|
|
|
125
|
-
def _open_indel_tabix(self) ->
|
|
127
|
+
def _open_indel_tabix(self) -> Any: # noqa: ANN401 — pysam ships no type stubs
|
|
126
128
|
"""Open the indel tabix file. Returns None if file doesn't exist."""
|
|
127
129
|
if self._indel_tabix is None:
|
|
128
130
|
if not self._indel_tabix_path.exists():
|
|
@@ -131,7 +133,7 @@ class CaddAnnotator(Annotator):
|
|
|
131
133
|
if not tbi.exists():
|
|
132
134
|
return None
|
|
133
135
|
try:
|
|
134
|
-
import pysam
|
|
136
|
+
import pysam
|
|
135
137
|
except ImportError:
|
|
136
138
|
return None
|
|
137
139
|
self._indel_tabix = pysam.TabixFile(str(self._indel_tabix_path))
|