tooluniverse.intervar_tool 源代码
"""
InterVar Tool
InterVar implements the ACMG/AMP 2015 standards and guidelines for germline variant
interpretation. Given a genomic variant (chromosome, position, ref, alt), it returns
an ACMG/AMP classification (Pathogenic, Likely Pathogenic, Uncertain Significance,
Likely Benign, Benign) together with the evidence criteria that contributed to the
classification (PVS1, PS1-PS4, PM1-PM6, PP1-PP5, BA1, BP1-BP7, BS1-BS4).
API: http://wintervar.wglab.org/api_new.php
No authentication required.
"""
import requests
from typing import Dict, Any
from .base_tool import BaseTool
from .tool_registry import register_tool
INTERVAR_BASE_URL = "http://wintervar.wglab.org/api_new.php"
# ACMG criteria descriptions for user-friendly output
CRITERIA_DESCRIPTIONS = {
"PVS1": "Null variant in gene where LOF is disease mechanism",
"PS1": "Same amino acid change as established pathogenic variant",
"PS2": "De novo variant (confirmed parentage)",
"PS3": "Well-established functional studies support damaging effect",
"PS4": "Variant prevalence significantly increased in cases vs controls",
"PM1": "Located in mutational hot spot / critical domain without benign variation",
"PM2": "Absent or at extremely low frequency in population databases",
"PM3": "Detected in trans with pathogenic variant for recessive disorder",
"PM4": "Protein length changes due to in-frame indels or stop-loss",
"PM5": "Novel missense at position where different pathogenic missense known",
"PM6": "Assumed de novo without confirmation of parentage",
"PP1": "Co-segregation with disease in multiple affected family members",
"PP2": "Missense in gene with low rate of benign missense and pathogenic missense common",
"PP3": "Multiple computational evidence supporting deleterious effect",
"PP4": "Patient phenotype or family history highly specific for gene",
"PP5": "Reputable source recently reports variant as pathogenic",
"BA1": "Allele frequency > 5% in population databases",
"BP1": "Missense variant in gene where only truncating variants cause disease",
"BP2": "Observed in trans with pathogenic variant for dominant OR in cis with pathogenic",
"BP3": "In-frame indels in repetitive region without known function",
"BP4": "Multiple computational evidence suggest no impact on gene/gene product",
"BP5": "Variant found in case with alternate molecular basis for disease",
"BP6": "Reputable source recently reports variant as benign",
"BP7": "Synonymous variant with no predicted splice impact",
"BS1": "Allele frequency greater than expected for disorder",
"BS2": "Observed in healthy adult with full penetrance expected at early age",
"BS3": "Well-established functional studies show no damaging effect",
"BS4": "Lack of co-segregation in affected members of family",
}
[文档]
@register_tool("InterVarTool")
class InterVarTool(BaseTool):
"""
InterVar: ACMG/AMP 2015 germline variant interpretation tool.
Classifies germline variants as:
Pathogenic | Likely Pathogenic | Uncertain Significance |
Likely Benign | Benign
according to the ACMG/AMP 2015 standards and guidelines.
Returns individual evidence criteria (PVS1, PS1-PS4, PM1-PM6, PP1-PP5,
BA1, BP1-BP7, BS1-BS4) with their activation status.
Input: genomic coordinates (chr, pos, ref, alt) in hg19 or hg38.
No authentication required.
"""
[文档]
def __init__(self, tool_config: Dict[str, Any]):
super().__init__(tool_config)
self.timeout = tool_config.get("timeout", 30)
self.operation = tool_config.get("fields", {}).get("operation", "classify")
[文档]
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
op = self.operation
if op == "classify":
return self._classify_variant(arguments)
return {"status": "error", "error": f"Unknown operation: {op}"}
[文档]
@staticmethod
def _parse_variant_args(arguments: Dict[str, Any]):
"""Parse and validate genomic variant arguments. Returns (params, error_dict_or_None)."""
chrom = str(arguments.get("chrom", "")).replace("chr", "").strip()
pos = arguments.get("pos")
ref = str(arguments.get("ref", "")).strip().upper()
alt = str(arguments.get("alt", "")).strip().upper()
build = arguments.get("build", "hg19")
if not chrom:
return None, {"status": "error", "error": "chrom parameter is required"}
if pos is None:
return None, {"status": "error", "error": "pos parameter is required"}
if not ref:
return None, {"status": "error", "error": "ref parameter is required"}
if not alt:
return None, {"status": "error", "error": "alt parameter is required"}
if build not in ("hg19", "hg38"):
return None, {
"status": "error",
"error": f"Invalid build '{build}'. Must be 'hg19' or 'hg38'.",
}
params = {
"queryType": "position",
"build": build,
"chr": chrom,
"pos": int(pos),
"ref": ref,
"alt": alt,
}
return params, None
[文档]
def _classify_variant(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
params, err = self._parse_variant_args(arguments)
if err:
return err
try:
resp = requests.get(INTERVAR_BASE_URL, params=params, timeout=self.timeout)
resp.raise_for_status()
raw = resp.json()
except requests.exceptions.Timeout:
return {
"status": "error",
"error": f"InterVar API timeout after {self.timeout}s",
}
except requests.exceptions.RequestException as e:
return {"status": "error", "error": f"InterVar API request failed: {e}"}
except Exception as e:
return {"status": "error", "error": f"Failed to parse response: {e}"}
if not isinstance(raw, dict) or "Intervar" not in raw:
return {
"status": "error",
"error": "Unexpected response format from InterVar API",
"raw": raw,
}
classification = raw["Intervar"]
activated = {k: bool(v) for k, v in raw.items() if k in CRITERIA_DESCRIPTIONS}
active_criteria = [k for k, v in activated.items() if v]
return {
"status": "success",
"data": {
"classification": classification,
"variant": {
"chromosome": raw.get("Chromosome"),
"position": raw.get("Position"),
"ref_allele": raw.get("Ref_allele"),
"alt_allele": raw.get("Alt_allele"),
"gene": raw.get("Gene"),
"build": raw.get("Build"),
},
"active_criteria": active_criteria,
"criteria_detail": {
k: {
"active": activated[k],
"description": CRITERIA_DESCRIPTIONS[k],
}
for k in activated
},
},
"metadata": {
"source": "InterVar (wintervar.wglab.org)",
"guideline": "ACMG/AMP 2015 Standards and Guidelines",
"classification_categories": [
"Pathogenic",
"Likely pathogenic",
"Uncertain significance",
"Likely benign",
"Benign",
],
},
}