hgvs Parser
In one line: a formal PEG grammar that turns an HGVS string into a structured object — the one part of the library that needs no database.
Basic use
import hgvs.parser
hp = hgvs.parser.Parser() # construct ONCE — it compiles a grammar
var = hp.parse_hgvs_variant("NM_000546.6:c.215C>G")
var # SequenceVariant(ac=NM_000546.6, type=c, ...)
str(var) # 'NM_000546.6:c.215C>G' — round-trips
Construct the parser once and reuse it. Parser() compiles a PEG grammar, which takes on the order of a second. Doing it inside a loop over 10,000 variants is a self-inflicted 3-hour job.
Why not regex
A regex like r"c\.(\d+)([ACGT])>([ACGT])" handles the simplest case and fails on everything else:
c.215C>G substitution
c.76_78del range deletion
c.76_77insT insertion between bases
c.-24+5G>A intronic, in the 5'UTR
c.*12-8del intronic, in the 3'UTR
c.76TG[8] a tandem repeat
c.[215C>G;847C>T] two variants in cis
p.(Arg175His) a predicted protein change
p.Arg175ProfsTer13 a frameshift with a downstream stop
g.7676154_7676156delinsAC a delins
The HGVS grammar handles all of these. It also rejects malformed input with a HGVSParseError rather than silently matching a prefix — which is the property that actually matters in a pipeline. A regex that half-matches gives you wrong data with no error.
Error handling
from hgvs.exceptions import HGVSParseError
def safe_parse(hp, s):
try:
return hp.parse_hgvs_variant(s)
except HGVSParseError as e:
return None, str(e)
HGVSParseError means the string is not valid HGVS syntax. It says nothing about whether the variant is real — that is hgvs Validator's job. A parse succeeding tells you the string is well-formed, not that base 215 of that transcript is actually a C.
Parsing thousands of clinician-entered strings, expect a 5–20% failure rate from legacy notation, typos, and Excel damage. Log the failures; do not discard them silently.
Parsing sub-components
hp.parse_c_variant("NM_000546.6:c.215C>G")
hp.parse_g_variant("NC_000017.11:g.7676154G>C")
hp.parse_p_variant("NP_000537.3:p.(Arg175His)")
hp.parse_c_posedit("215C>G") # just the position + edit
hp.parse_c_interval("215_218")
hp.parse_hgvs_position("c.215")
Useful when you have the accession in one column and the change in another — a common shape for spreadsheets from clinical labs.
Round-tripping and normalising formatting
str(hp.parse_hgvs_variant("NM_000546.6:c.215C>G")) # 'NM_000546.6:c.215C>G'
Parsing then re-stringifying gives you canonical formatting — consistent spacing, consistent representation. It does not give you canonical coordinates; that requires hgvs Normalizer and sequence data.
import hgvs.config
hgvs.config.global_config.formatting.max_ref_length = 0 # omit long ref sequences
The config controls how variants are rendered — for example whether c.76_78delCTT prints the deleted bases or just c.76_78del.
Batch parsing
import pandas as pd
from hgvs.exceptions import HGVSParseError
hp = hgvs.parser.Parser()
def parse_column(series):
parsed, errors = [], []
for s in series:
try:
parsed.append(hp.parse_hgvs_variant(s))
errors.append(None)
except HGVSParseError as e:
parsed.append(None)
errors.append(str(e))
return pd.DataFrame({"variant": parsed, "parse_error": errors},
index=series.index)
result = df.join(parse_column(df["hgvs"]))
print(f"{result['parse_error'].notna().sum()} of {len(result)} failed to parse")
print(result.loc[result["parse_error"].notna(), "hgvs"].head(20).tolist())
Printing the failures is the important line — the failure patterns usually reveal one systematic problem (a missing accession prefix, a legacy IVS notation) that you can fix in bulk.
Cleaning before parsing
Common fixable problems in real-world data:
def tidy(s):
s = str(s).strip()
s = s.replace("–", "-").replace("—", "-") # en/em dash → hyphen
s = s.replace(">", ">") # HTML-escaped >
s = re.sub(r"\s+", "", s) # internal whitespace
if ":" not in s and default_accession:
s = f"{default_accession}:{s}" # add a missing accession
return s
Word processors substituting en-dashes for hyphens is a genuinely common cause of parse failures in variant lists pasted from documents.
Do not "fix" the semantics. Repairing whitespace and dashes is safe. Rewriting c.76_77insG to c.76dup is a normalization decision that belongs to hgvs Normalizer with sequence data behind it, not to a cleanup regex.
Performance
Parsing is pure computation — no network, no database — and runs at roughly 1,000–10,000 variants per second depending on complexity. It will not be your bottleneck. Projection and normalization, which hit UTA and Data Providers, will be.
Common mistakes
- Constructing
Parser()in a loop. - Regex instead of the parser.
- Assuming a successful parse means a valid variant. Use hgvs Validator.
- Discarding parse failures instead of logging them.
- Stripping the accession version during cleanup.
- Catching bare
Exceptionand masking real bugs. CatchHGVSParseError. - Rewriting semantics during cleanup.
- Expecting round-tripping to normalize coordinates. It normalizes formatting only.
See also
SequenceVariant · HGVS Nomenclature · hgvs Normalizer · hgvs Validator · hgvs easy · String Accessor