vartriage 0.1.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 (108) hide show
  1. vartriage-0.1.0/.github/workflows/ci.yml +35 -0
  2. vartriage-0.1.0/.github/workflows/publish.yml +29 -0
  3. vartriage-0.1.0/.gitignore +47 -0
  4. vartriage-0.1.0/CONTRIBUTING.md +120 -0
  5. vartriage-0.1.0/LICENSE +21 -0
  6. vartriage-0.1.0/PKG-INFO +343 -0
  7. vartriage-0.1.0/README.md +296 -0
  8. vartriage-0.1.0/docs/api/annotation.md +3 -0
  9. vartriage-0.1.0/docs/api/classification.md +3 -0
  10. vartriage-0.1.0/docs/api/config.md +13 -0
  11. vartriage-0.1.0/docs/api/exceptions.md +9 -0
  12. vartriage-0.1.0/docs/api/filter.md +3 -0
  13. vartriage-0.1.0/docs/api/index.md +22 -0
  14. vartriage-0.1.0/docs/api/models.md +23 -0
  15. vartriage-0.1.0/docs/api/parser.md +3 -0
  16. vartriage-0.1.0/docs/api/pipeline.md +3 -0
  17. vartriage-0.1.0/docs/api/prioritization.md +3 -0
  18. vartriage-0.1.0/docs/api/reporting.md +3 -0
  19. vartriage-0.1.0/docs/architecture.md +109 -0
  20. vartriage-0.1.0/docs/changelog.md +17 -0
  21. vartriage-0.1.0/docs/configuration.md +175 -0
  22. vartriage-0.1.0/docs/getting-started.md +78 -0
  23. vartriage-0.1.0/docs/index.md +32 -0
  24. vartriage-0.1.0/docs/pipeline-stages.md +162 -0
  25. vartriage-0.1.0/docs/reference-files.md +160 -0
  26. vartriage-0.1.0/docs/tutorial.md +129 -0
  27. vartriage-0.1.0/mkdocs.yml +68 -0
  28. vartriage-0.1.0/pyproject.toml +101 -0
  29. vartriage-0.1.0/tests/__init__.py +0 -0
  30. vartriage-0.1.0/tests/conftest.py +40 -0
  31. vartriage-0.1.0/tests/generators/__init__.py +1 -0
  32. vartriage-0.1.0/tests/generators/variants.py +258 -0
  33. vartriage-0.1.0/tests/generators/vcf.py +217 -0
  34. vartriage-0.1.0/tests/integration/__init__.py +0 -0
  35. vartriage-0.1.0/tests/integration/test_performance.py +290 -0
  36. vartriage-0.1.0/tests/integration/test_pipeline_e2e.py +861 -0
  37. vartriage-0.1.0/tests/invariants/__init__.py +0 -0
  38. vartriage-0.1.0/tests/invariants/test_annotation.py +366 -0
  39. vartriage-0.1.0/tests/invariants/test_classification.py +421 -0
  40. vartriage-0.1.0/tests/invariants/test_filtering.py +254 -0
  41. vartriage-0.1.0/tests/invariants/test_parsing.py +161 -0
  42. vartriage-0.1.0/tests/invariants/test_prioritization.py +430 -0
  43. vartriage-0.1.0/tests/invariants/test_serialization.py +245 -0
  44. vartriage-0.1.0/tests/invariants/test_streaming_properties.py +352 -0
  45. vartriage-0.1.0/tests/invariants/test_warnings.py +672 -0
  46. vartriage-0.1.0/tests/test_annotation_engine_smoke.py +279 -0
  47. vartriage-0.1.0/tests/test_consequence_smoke.py +180 -0
  48. vartriage-0.1.0/tests/test_frequency_smoke.py +178 -0
  49. vartriage-0.1.0/tests/test_pipeline_smoke.py +377 -0
  50. vartriage-0.1.0/tests/unit/__init__.py +0 -0
  51. vartriage-0.1.0/tests/unit/test_acmg_classify_wiring.py +173 -0
  52. vartriage-0.1.0/tests/unit/test_acmg_evidence_tags.py +273 -0
  53. vartriage-0.1.0/tests/unit/test_batch.py +118 -0
  54. vartriage-0.1.0/tests/unit/test_combining.py +93 -0
  55. vartriage-0.1.0/tests/unit/test_csv_writer.py +201 -0
  56. vartriage-0.1.0/tests/unit/test_edge_cases.py +552 -0
  57. vartriage-0.1.0/tests/unit/test_frequency_filter.py +157 -0
  58. vartriage-0.1.0/tests/unit/test_pdf_writer.py +179 -0
  59. vartriage-0.1.0/tests/unit/test_pypi_readiness.py +492 -0
  60. vartriage-0.1.0/tests/unit/test_quality_filter.py +138 -0
  61. vartriage-0.1.0/tests/unit/test_report_generator.py +208 -0
  62. vartriage-0.1.0/tests/unit/test_scoring.py +265 -0
  63. vartriage-0.1.0/tests/unit/test_vcf_parser.py +176 -0
  64. vartriage-0.1.0/tests/unit/test_vectorized.py +338 -0
  65. vartriage-0.1.0/tests/unit/test_warning_accumulator.py +263 -0
  66. vartriage-0.1.0/uv.lock +1813 -0
  67. vartriage-0.1.0/vartriage/__init__.py +95 -0
  68. vartriage-0.1.0/vartriage/_internal/__init__.py +4 -0
  69. vartriage-0.1.0/vartriage/_internal/batch.py +131 -0
  70. vartriage-0.1.0/vartriage/_internal/interval_tree.py +466 -0
  71. vartriage-0.1.0/vartriage/_internal/vectorized.py +502 -0
  72. vartriage-0.1.0/vartriage/_internal/warning_accumulator.py +280 -0
  73. vartriage-0.1.0/vartriage/annotation/__init__.py +1 -0
  74. vartriage-0.1.0/vartriage/annotation/clinvar.py +176 -0
  75. vartriage-0.1.0/vartriage/annotation/clinvar_polars.py +192 -0
  76. vartriage-0.1.0/vartriage/annotation/consequence.py +161 -0
  77. vartriage-0.1.0/vartriage/annotation/consequence_pyranges.py +388 -0
  78. vartriage-0.1.0/vartriage/annotation/engine.py +349 -0
  79. vartriage-0.1.0/vartriage/annotation/frequency.py +162 -0
  80. vartriage-0.1.0/vartriage/annotation/frequency_polars.py +206 -0
  81. vartriage-0.1.0/vartriage/classification/__init__.py +1 -0
  82. vartriage-0.1.0/vartriage/classification/acmg.py +230 -0
  83. vartriage-0.1.0/vartriage/classification/combining.py +105 -0
  84. vartriage-0.1.0/vartriage/cli.py +188 -0
  85. vartriage-0.1.0/vartriage/exceptions.py +10 -0
  86. vartriage-0.1.0/vartriage/filter/__init__.py +5 -0
  87. vartriage-0.1.0/vartriage/filter/quality_filter.py +113 -0
  88. vartriage-0.1.0/vartriage/io/__init__.py +1 -0
  89. vartriage-0.1.0/vartriage/io/exceptions.py +124 -0
  90. vartriage-0.1.0/vartriage/io/vcf_parser.py +349 -0
  91. vartriage-0.1.0/vartriage/models/__init__.py +29 -0
  92. vartriage-0.1.0/vartriage/models/config.py +184 -0
  93. vartriage-0.1.0/vartriage/models/variant.py +268 -0
  94. vartriage-0.1.0/vartriage/models/warnings.py +54 -0
  95. vartriage-0.1.0/vartriage/pipeline.py +244 -0
  96. vartriage-0.1.0/vartriage/prioritization/__init__.py +1 -0
  97. vartriage-0.1.0/vartriage/prioritization/engine.py +223 -0
  98. vartriage-0.1.0/vartriage/prioritization/frequency_filter.py +93 -0
  99. vartriage-0.1.0/vartriage/prioritization/score_loader.py +176 -0
  100. vartriage-0.1.0/vartriage/prioritization/scoring.py +290 -0
  101. vartriage-0.1.0/vartriage/protocols.py +211 -0
  102. vartriage-0.1.0/vartriage/py.typed +0 -0
  103. vartriage-0.1.0/vartriage/reporting/__init__.py +1 -0
  104. vartriage-0.1.0/vartriage/reporting/csv_writer.py +139 -0
  105. vartriage-0.1.0/vartriage/reporting/generator.py +155 -0
  106. vartriage-0.1.0/vartriage/reporting/json_writer.py +118 -0
  107. vartriage-0.1.0/vartriage/reporting/pdf_fallback.py +48 -0
  108. vartriage-0.1.0/vartriage/reporting/pdf_writer.py +256 -0
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, "feature/**", "fix/**", "docs/**"]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.10", "3.11", "3.12"]
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python ${{ matrix.python-version }}
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+
23
+ - name: Install dependencies
24
+ run: pip install -e ".[dev]"
25
+
26
+ - name: Run tests
27
+ run: pytest
28
+
29
+ - name: Run mypy
30
+ run: mypy --strict --python-version=${{ matrix.python-version }} vartriage/
31
+
32
+ - name: Build package
33
+ run: |
34
+ pip install build
35
+ python -m build
@@ -0,0 +1,29 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+
22
+ - name: Install build tools
23
+ run: pip install build
24
+
25
+ - name: Build package
26
+ run: python -m build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,47 @@
1
+ # Python bytecode
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+
6
+ # Virtual environments
7
+ .venv/
8
+ venv/
9
+ env/
10
+
11
+ # Build and distribution
12
+ *.egg-info/
13
+ dist/
14
+ build/
15
+
16
+ # Tool caches
17
+ .mypy_cache/
18
+ .pytest_cache/
19
+ .ruff_cache/
20
+ .hypothesis/
21
+
22
+ # Coverage
23
+ .coverage
24
+ htmlcov/
25
+
26
+ # MkDocs build output
27
+ site/
28
+
29
+ # Environment variables
30
+ .env
31
+
32
+ # macOS
33
+ .DS_Store
34
+
35
+ # Archives
36
+ archives/
37
+
38
+ # Temp test files
39
+ test_*.tmp.py
40
+
41
+ # UV lock (optional, remove this line if you want to track it)
42
+ # uv.lock
43
+
44
+ .history
45
+ .qodo
46
+ .kiro
47
+ .vscode
@@ -0,0 +1,120 @@
1
+ # Contributing to vartriage
2
+
3
+ Thanks for considering a contribution. Here's how to get set up, run tests, and open a PR.
4
+
5
+ ## Development Setup
6
+
7
+ Clone the repository and install in editable mode with development dependencies:
8
+
9
+ ```bash
10
+ git clone https://github.com/Behordeun/vartriage.git
11
+ cd vartriage
12
+ pip install -e ".[dev]"
13
+ ```
14
+
15
+ This installs pytest, hypothesis, pytest-cov, and mypy alongside the core package.
16
+
17
+ ### Accelerated Backends
18
+
19
+ For the optional fast backends (polars, pyranges) and PDF support:
20
+
21
+ ```bash
22
+ pip install -e ".[all]"
23
+ ```
24
+
25
+ This pulls in polars, pyranges, and reportlab.
26
+
27
+ ## Running Tests
28
+
29
+ Run the full test suite with:
30
+
31
+ ```bash
32
+ pytest
33
+ ```
34
+
35
+ A passing run looks like:
36
+
37
+ ```text
38
+ tests/ ... 383 passed in Xs
39
+ ```
40
+
41
+ The project uses [Hypothesis](https://hypothesis.readthedocs.io/) for property-based testing with three profiles:
42
+
43
+ | Profile | Max Examples | Usage |
44
+ | --------- | ------------ | ------------------------------ |
45
+ | `dev` | 50 | Default for local development |
46
+ | `ci` | 500 | Used in CI pipelines |
47
+ | `debug` | 10 | Quick iteration when debugging |
48
+
49
+ Switch profiles via the `HYPOTHESIS_PROFILE` environment variable:
50
+
51
+ ```bash
52
+ HYPOTHESIS_PROFILE=ci pytest
53
+ ```
54
+
55
+ To skip slow performance benchmarks during local development:
56
+
57
+ ```bash
58
+ pytest -m "not slow"
59
+ ```
60
+
61
+ ## Type Checking
62
+
63
+ Strict mypy is enforced:
64
+
65
+ ```bash
66
+ mypy --strict
67
+ ```
68
+
69
+ This uses the config in `pyproject.toml` (Python 3.10 target, strict mode). A clean run means zero errors.
70
+
71
+ ## Code Style
72
+
73
+ We use **Black** for formatting and **ruff** for linting. Before opening a PR:
74
+
75
+ ```bash
76
+ black .
77
+ ruff check .
78
+ ```
79
+
80
+ Fix any auto-fixable lint issues with:
81
+
82
+ ```bash
83
+ ruff check --fix .
84
+ ```
85
+
86
+ ## Branch Naming
87
+
88
+ Use the following prefixes for your branches:
89
+
90
+ - `feature/` — new functionality (e.g., `feature/streaming-reports`)
91
+ - `fix/` — bug fixes (e.g., `fix/score-loader-nan-handling`)
92
+ - `docs/` — documentation changes (e.g., `docs/update-api-reference`)
93
+
94
+ ## Pull Request Process
95
+
96
+ 1. Create a branch from `main` using the naming convention above.
97
+ 2. Make your changes, keeping commits focused on a single logical change.
98
+ 3. Make sure CI passes:
99
+ - `pytest` (full suite)
100
+ - `mypy --strict` (zero errors)
101
+ - Black + ruff (formatting/lint)
102
+ 4. Open a pull request against `main`.
103
+ 5. PRs require at least one approval before merging.
104
+ 6. Keep the PR description short: what changed, what you tested, open questions if any.
105
+
106
+ ## Project Structure
107
+
108
+ ```text
109
+ vartriage/
110
+ ├── annotation/ # Variant annotation engine
111
+ ├── classification/ # ACMG classification and combining rules
112
+ ├── models/ # Data models (Variant, AnnotatedVariant, etc.)
113
+ ├── prioritization/ # Scoring and prioritization engine
114
+ ├── reporting/ # Report generation (JSON, CSV, PDF)
115
+ ├── _internal/ # Internal utilities
116
+ ├── protocols.py # Protocol interfaces
117
+ ├── exceptions.py # Warning and exception hierarchy
118
+ ├── cli.py # Command-line interface
119
+ └── py.typed # PEP 561 marker
120
+ ```
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Muhammad Abiodun SULAIMAN, Bolaji Fatai OYEYEMI
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.
@@ -0,0 +1,343 @@
1
+ Metadata-Version: 2.4
2
+ Name: vartriage
3
+ Version: 0.1.0
4
+ Summary: A streaming pipeline library for identifying and classifying pathogenic genetic variants from VCF data
5
+ Project-URL: Homepage, https://github.com/Behordeun/vartriage
6
+ Project-URL: Documentation, https://github.com/Behordeun/vartriage#readme
7
+ Project-URL: Repository, https://github.com/Behordeun/vartriage
8
+ Project-URL: Issues, https://github.com/Behordeun/vartriage/issues
9
+ Author: Muhammad Abiodun SULAIMAN, Bolaji Fatai OYEYEMI
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: acmg,bioinformatics,genomics,pathogenicity,variants,vcf
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: numpy<3.0,>=1.24.0
23
+ Requires-Dist: pysam<1.0,>=0.22.0
24
+ Provides-Extra: accelerated
25
+ Requires-Dist: polars<2.0,>=0.20.0; extra == 'accelerated'
26
+ Requires-Dist: pyranges<1.0,>=0.1.0; extra == 'accelerated'
27
+ Provides-Extra: all
28
+ Requires-Dist: polars<2.0,>=0.20.0; extra == 'all'
29
+ Requires-Dist: pyranges<1.0,>=0.1.0; extra == 'all'
30
+ Requires-Dist: reportlab<5.0,>=4.0; extra == 'all'
31
+ Provides-Extra: dev
32
+ Requires-Dist: hypothesis<7.0,>=6.0; extra == 'dev'
33
+ Requires-Dist: mypy<2.0,>=1.0; extra == 'dev'
34
+ Requires-Dist: pytest-cov<6.0,>=4.0; extra == 'dev'
35
+ Requires-Dist: pytest<9.0,>=7.0; extra == 'dev'
36
+ Provides-Extra: docs
37
+ Requires-Dist: mkdocs-material<10.0,>=9.0; extra == 'docs'
38
+ Requires-Dist: mkdocs<2.0,>=1.5; extra == 'docs'
39
+ Requires-Dist: mkdocstrings[python]<1.0,>=0.24; extra == 'docs'
40
+ Provides-Extra: pdf
41
+ Requires-Dist: reportlab<5.0,>=4.0; extra == 'pdf'
42
+ Provides-Extra: test
43
+ Requires-Dist: hypothesis<7.0,>=6.0; extra == 'test'
44
+ Requires-Dist: pytest-cov<6.0,>=4.0; extra == 'test'
45
+ Requires-Dist: pytest<9.0,>=7.0; extra == 'test'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # vartriage
49
+
50
+ Variant prioritization pipeline for whole-genome sequencing data. Reads a VCF, applies quality filters, annotates functional consequence and population frequency, computes pathogenicity scores, runs ACMG/AMP evidence classification, and writes a ranked candidate list in JSON, CSV, or PDF.
51
+
52
+ Processes 4M+ variant WGS files under 2GB memory via batched iterators.
53
+
54
+ ## Install
55
+
56
+ ```bash
57
+ pip install vartriage
58
+ ```
59
+
60
+ With faster annotation backends (polars + pyranges):
61
+
62
+ ```bash
63
+ pip install vartriage[accelerated]
64
+ ```
65
+
66
+ With PDF report support:
67
+
68
+ ```bash
69
+ pip install vartriage[pdf]
70
+ ```
71
+
72
+ All optional extras:
73
+
74
+ ```bash
75
+ pip install vartriage[all]
76
+ ```
77
+
78
+ ## Usage
79
+
80
+ ```python
81
+ from pathlib import Path
82
+ from vartriage import (
83
+ Pipeline, PipelineConfig, AnnotationConfig,
84
+ PrioritizationConfig, QualityFilterConfig, ReportConfig,
85
+ )
86
+
87
+ config = PipelineConfig(
88
+ vcf_path=Path("sample.vcf.gz"),
89
+ output_path=Path("candidates.json"),
90
+ quality_filter=QualityFilterConfig(min_qual=30.0),
91
+ annotation=AnnotationConfig(
92
+ gene_annotation_path=Path("gencode.v44.gtf"),
93
+ gnomad_path=Path("gnomad.v4.sites.tsv"),
94
+ clinvar_path=Path("clinvar_20240101.tsv"),
95
+ ),
96
+ prioritization=PrioritizationConfig(
97
+ max_allele_frequency=0.01,
98
+ cadd_scores_path=Path("cadd_scores.tsv"),
99
+ revel_scores_path=Path("revel_scores.tsv"),
100
+ ),
101
+ report=ReportConfig(output_format="json"),
102
+ )
103
+
104
+ pipeline = Pipeline(config)
105
+ pipeline.run()
106
+ ```
107
+
108
+ Individual stages work on their own:
109
+
110
+ ```python
111
+ from vartriage import VCFParser, QualityFilter, QualityFilterConfig
112
+
113
+ with VCFParser(Path("input.vcf.gz")) as parser:
114
+ qf = QualityFilter(QualityFilterConfig(min_qual=30.0))
115
+ for variant in qf.apply(iter(parser)):
116
+ print(f"{variant.chrom}:{variant.pos} {variant.ref}>{variant.alt}")
117
+ ```
118
+
119
+ ## Command Line
120
+
121
+ After installation, the `vartriage` command is available:
122
+
123
+ ```bash
124
+ vartriage --vcf sample.vcf.gz --output candidates.json
125
+ ```
126
+
127
+ With annotation and scoring references:
128
+
129
+ ```bash
130
+ vartriage \
131
+ --vcf sample.vcf.gz \
132
+ --output report.json \
133
+ --output-format json \
134
+ --gene-annotation gencode.v44.gtf \
135
+ --gnomad gnomad.v4.sites.tsv \
136
+ --clinvar clinvar_20240101.tsv \
137
+ --cadd-scores cadd_scores.tsv \
138
+ --revel-scores revel_scores.tsv
139
+ ```
140
+
141
+ Run `vartriage --help` for all options.
142
+
143
+ ## Pipeline stages
144
+
145
+ ```text
146
+ VCFParser > QualityFilter > AnnotationEngine > PrioritizationEngine > ACMGClassifier > ReportGenerator
147
+ ```
148
+
149
+ ### Quality filtering
150
+
151
+ Drops variants where:
152
+
153
+ - `FILTER` is not `PASS` or `.`
154
+ - `QUAL` is below the threshold (default 20)
155
+ - `QUAL` field is missing (emits a warning)
156
+
157
+ Passing variants keep their original order.
158
+
159
+ ### Annotation
160
+
161
+ Adds three annotations to each surviving variant:
162
+
163
+ **Functional consequence:** Looked up against gene models (GTF/GFF). Splice_Site applies within 2bp of an exon-intron boundary. When multiple transcripts disagree, the most damaging consequence wins. Severity ranking (highest first): Frameshift, Nonsense, Splice_Site, Missense, In_Frame_Insertion, In_Frame_Deletion, Synonymous, Intergenic.
164
+
165
+ **Population frequency:** Matched against gnomAD by (chrom, pos, ref, alt). Variants not found get `frequency_unknown=True` and a `MissingDataWarning`.
166
+
167
+ **ClinVar assertion:** Pathogenic, Likely_Pathogenic, VUS, Likely_Benign, or Benign when available.
168
+
169
+ ### Prioritization
170
+
171
+ Two phases:
172
+
173
+ 1. Frequency gate: drops variants with AF above the threshold (default 0.01). Variants marked `frequency_unknown` always pass.
174
+ 2. Composite scoring: normalizes CADD Phred (divide by 99, cap at 1.0) and REVEL (already 0-1), then computes:
175
+
176
+ ```text
177
+ composite = (REVEL x 0.6) + (CADD_normalized x 0.4)
178
+ ```
179
+
180
+ Falls back to the single available score when only one source exists. Output sorted descending by composite rank; variants without scores go last.
181
+
182
+ ### ACMG classification
183
+
184
+ Evidence tagging per ACMG/AMP 2015:
185
+
186
+ | Tag | Strength | Condition |
187
+ | ---- | ----------- | ----------------------------------------- |
188
+ | PVS1 | Very Strong | Nonsense or Frameshift |
189
+ | PM2 | Moderate | gnomAD AF < 0.0001 |
190
+ | PP3 | Supporting | REVEL > 0.7 |
191
+ | PP5 | Supporting | ClinVar Pathogenic, no conflicting Benign |
192
+
193
+ Tags combine per standard rules into: Pathogenic, Likely_Pathogenic, or VUS. If a data source is unavailable, the corresponding tag is omitted.
194
+
195
+ ### Report output
196
+
197
+ Fields in all formats:
198
+
199
+ | Field | Description |
200
+ | -------------------------- | --------------------------- |
201
+ | `chromosome` | Chromosome name |
202
+ | `position` | 1-based position |
203
+ | `ref_allele` | Reference allele |
204
+ | `alt_allele` | Alternate allele |
205
+ | `functional_consequence` | Most severe consequence |
206
+ | `allele_frequency` | gnomAD AF (null if unknown) |
207
+ | `composite_rank` | Pathogenicity score 0-1 |
208
+ | `clinvar_assertion` | ClinVar significance |
209
+ | `acmg_classification` | Final classification |
210
+ | `evidence_tags` | Applied evidence codes |
211
+
212
+ Null values: `null` in JSON, empty in CSV, `N/A` in PDF.
213
+
214
+ ## Configuration
215
+
216
+ ### QualityFilterConfig
217
+
218
+ | Field | Type | Default | Range |
219
+ | ------------ | ----- | ------- | -------------- |
220
+ | `min_qual` | float | 20.0 | 0 to 1,000,000 |
221
+
222
+ ### AnnotationConfig
223
+
224
+ | Field | Type | Default | Notes |
225
+ | ------------------------ | ---- | -------- | ---------------------- |
226
+ | `gene_annotation_path` | Path | required | GTF/GFF |
227
+ | `gnomad_path` | Path | required | TSV (see format below) |
228
+ | `clinvar_path` | Path | None | TSV (see format below) |
229
+ | `batch_size` | int | 10,000 | 1,000 to 100,000 |
230
+
231
+ ### PrioritizationConfig
232
+
233
+ | Field | Type | Default | Range |
234
+ | ------------------------ | ----- | ------- | ---------------- |
235
+ | `max_allele_frequency` | float | 0.01 | 0.0 to 1.0 |
236
+ | `cadd_scores_path` | Path | None | CADD Phred TSV |
237
+ | `revel_scores_path` | Path | None | REVEL scores TSV |
238
+ | `batch_size` | int | 10,000 | 1,000 to 100,000 |
239
+
240
+ ### ReportConfig
241
+
242
+ | Field | Type | Default | Options |
243
+ | ----------------- | ---- | ---------- | -------------------------------- |
244
+ | `output_format` | str | `"json"` | `"json"`, `"csv"`, `"pdf"` |
245
+
246
+ ### MissingDataConfig
247
+
248
+ | Field | Type | Default | Notes |
249
+ | --------------------- | ---- | ------- | ----------------------------- |
250
+ | `warning_threshold` | int | 1000 | Summary warning when exceeded |
251
+
252
+ ## Reference file formats
253
+
254
+ All reference files are tab-separated with a header row.
255
+
256
+ **gnomAD:**
257
+
258
+ ```tsv
259
+ chrom pos ref alt af
260
+ chr1 12345 A G 0.00032
261
+ ```
262
+
263
+ **ClinVar:**
264
+
265
+ ```tsv
266
+ chrom pos ref alt clinical_significance
267
+ chr1 12345 A G Pathogenic
268
+ ```
269
+
270
+ Recognized values: `Pathogenic`, `Likely pathogenic`, `Uncertain significance`, `Likely benign`, `Benign`.
271
+
272
+ **CADD / REVEL:**
273
+
274
+ ```tsv
275
+ chrom pos ref alt score
276
+ chr1 12345 A G 28.5
277
+ ```
278
+
279
+ ## Missing data handling
280
+
281
+ Variants absent from gnomAD are never dropped. They get `frequency_unknown=True` and pass the frequency filter. Same for ClinVar: no match means `clinvar_unknown=True`.
282
+
283
+ A `MissingDataWarning` is emitted per lookup miss. Once the total exceeds `warning_threshold`, a summary fires with the count and contributing sources.
284
+
285
+ ```python
286
+ pipeline.run()
287
+ acc = pipeline.warning_accumulator
288
+ print(f"{acc.total_count} missing data events across {acc.sources}")
289
+ ```
290
+
291
+ ## Dependencies
292
+
293
+ | Package | Required | Extra | Purpose |
294
+ | --------- | -------- | ----------------- | ----------------------------- |
295
+ | pysam | yes | n/a | VCF streaming (htslib) |
296
+ | numpy | yes | n/a | Score normalization |
297
+ | polars | no | `[accelerated]` | Batch frequency/ClinVar joins |
298
+ | pyranges | no | `[accelerated]` | Interval overlap queries |
299
+ | reportlab | no | `[pdf]` | PDF report generation |
300
+
301
+ Without optional extras, the library uses pure-Python fallbacks (dict-based lookups, bisect-based interval tree). Correct output either way; the accelerated path runs faster on large reference files.
302
+
303
+ ## Error handling
304
+
305
+ Invalid configuration raises `ValueError` or `FileNotFoundError` at construction time, before any variants are processed.
306
+
307
+ During processing, missing reference data does not crash. The library assigns null values, sets flags, and continues. After a run, inspect `pipeline.warning_accumulator` to see how many lookup misses occurred and which sources were affected.
308
+
309
+ ## Tests
310
+
311
+ ```bash
312
+ pytest tests/ # full suite
313
+ pytest tests/ -m "not slow" # skip performance benchmarks
314
+ mypy --strict vartriage/ # type checking
315
+ ```
316
+
317
+ Tests pass. mypy strict, 0 errors.
318
+
319
+ ## Project layout
320
+
321
+ ```text
322
+ vartriage/
323
+ pipeline.py # Top-level orchestrator
324
+ protocols.py # Protocol interfaces for swappable backends
325
+ io/ # VCF parsing, exceptions
326
+ filter/ # Quality-based exclusion
327
+ annotation/ # Consequence, frequency, ClinVar lookups
328
+ prioritization/ # AF gating + pathogenicity scoring
329
+ classification/ # ACMG evidence tagging + combining
330
+ reporting/ # JSON, CSV, PDF output
331
+ models/ # Dataclasses, enums, configs, warnings
332
+ _internal/ # Batch utils, interval tree, vectorized ops
333
+ ```
334
+
335
+ ## Requirements
336
+
337
+ - Python >= 3.10
338
+ - pysam >= 0.22.0
339
+ - numpy >= 1.24.0
340
+
341
+ ## License
342
+
343
+ MIT