Skip to content

Effect types

Use this page to look up a class after reading the effect annotation guide. Definitions below are generated from the source docstrings; this is reference material, not a required first read.

Effect families

Question Examples
Coding changes Substitution, Insertion, Deletion, FrameShift, PrematureStop, Silent
Noncoding and untranslated regions Intronic, FivePrimeUTR, ThreePrimeUTR, NoncodingTranscript, Intergenic
Splice effects SpliceOutcomeSet, with NormalSplicing, ExonSkipping, IntronRetention, or cryptic-site candidates
Structural effects StructuralVariantEffect, GeneFusion, TranslocationToIntergenic
Linked variants and phase HaplotypeEffect, PhaseCandidateSet
Inherited allele overlap GermlineAlleleOverlap: no new allele sequence; LOH unassessed
Unknown results and failures Unresolved, IncompleteTranscript, Failure

These labels describe predictions and their limits, not clinical significance.

Two distinctions are worth keeping in mind while reading:

  • Effects that carry a protein consequence vs. location-only effects. Coding effects (Substitution, FrameShift, PrematureStop, …) and the splice mechanism effects (NormalSplicing, ExonSkipping, …) describe a change to the protein. The splice-signal disruption effects (SpliceDonor, SpliceAcceptor, IntronicSpliceSite, ExonicSpliceSite, all sharing the SpliceSite base) and the region effects (Intronic, FivePrimeUTR, …) describe where a variant landed and carry no protein consequence on their own.
  • Single effects vs. multi-outcome containers. Most effects are a single answer. MultiOutcomeEffect subclasses (SpliceOutcomeSet, ExonicSpliceSite, the structural-variant effects, HaplotypeEffect, PhaseCandidateSet) bundle several candidate effects when the protein-level outcome isn't deterministic; each exposes .candidates, .most_likely_effect, and .highest_priority_effect.

Severity ordering across types is set by effect_priority.

Coding effects

varcode.effects.effect_classes.Silent(variant, transcript, aa_pos, aa_ref)

Bases: CodingMutation

Mutation to an exon of a coding region which doesn't change the amino acid sequence.

PARAMETER DESCRIPTION
variant

TYPE: Variant

transcript

TYPE: Transcript

aa_pos

Offset of first synonymous codon in protein sequence

TYPE: int

aa_ref

Reference amino acid(s) at offset

TYPE: str or Seq

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_pos,
        aa_ref):
    """
    Parameters
    ----------
    variant : Variant

    transcript : Transcript

    aa_pos : int
        Offset of first synonymous codon in protein sequence

    aa_ref : str or Bio.Seq
        Reference amino acid(s) at offset
    """
    CodingMutation.__init__(
        self,
        variant=variant,
        transcript=transcript)
    self.aa_pos = aa_pos
    self.aa_ref = bio_seq_to_str(aa_ref)

varcode.effects.effect_classes.AlternateStartCodon(variant, transcript, ref_codon, alt_codon)

Bases: Silent

Change to the start codon (e.g. ATG>CTG) but without changing the starting amino acid from methionine.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        ref_codon,
        alt_codon):
    Silent.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_pos=0,
        aa_ref=transcript.protein_sequence[0])
    self.ref_codon = bio_seq_to_str(ref_codon)
    self.alt_codon = bio_seq_to_str(alt_codon)

varcode.effects.effect_classes.StartLoss(variant, transcript)

Bases: NonsilentCodingMutation

When a start codon is lost it's difficult to determine if there is an alternative Kozak consensus sequence (either before or after the original) from which an alternative start codon can be inferred.

TODO: - look for downstream alternative start codon to predict new coding sequence (probably also requires matching pattern of preceding ~6nt) - If an alternative start codon is changed to ATG then we should make a StrongerStartCodon effect which is effectively silent - If ATG is changed to the two common alternative codons then we should make a WeakerStartCodon effect which is also effectively silent.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript):
    NonsilentCodingMutation.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=0,
        aa_mutation_end_offset=1,
        aa_ref=transcript.protein_sequence[0])

varcode.effects.effect_classes.Substitution(variant, transcript, aa_mutation_start_offset, aa_ref, aa_alt)

Bases: KnownAminoAcidChange

Single amino acid substitution, e.g. BRAF-001 V600E

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        aa_ref,
        aa_alt):
    if len(aa_ref) != 1:
        raise ValueError(
            "Simple substitution can't have aa_ref='%s'" % (aa_ref,))
    if len(aa_alt) != 1:
        raise ValueError(
            "Simple substitution can't have aa_alt='%s'" % (aa_alt,))
    KnownAminoAcidChange.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_ref=aa_ref,
        aa_alt=aa_alt)

varcode.effects.effect_classes.ComplexSubstitution(variant, transcript, aa_mutation_start_offset, aa_ref, aa_alt)

Bases: KnownAminoAcidChange

In-frame substitution of multiple amino acids, e.g. TP53-002 p.391FY>QQQ Can change the length of the protein sequence but since it has non-empty ref and alt strings, is more complicated than an insertion or deletion alone.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        aa_ref,
        aa_alt):
    if len(aa_ref) == 1 and len(aa_alt) == 1:
        raise ValueError(
            "ComplexSubstitution can't have aa_ref='%s' and aa_alt='%s'" % (
                aa_ref, aa_alt))
    KnownAminoAcidChange.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_ref=aa_ref,
        aa_alt=aa_alt)

varcode.effects.effect_classes.Insertion(variant, transcript, aa_mutation_start_offset, aa_alt)

Bases: KnownAminoAcidChange

In-frame insertion of one or more amino acids.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        aa_alt):
    KnownAminoAcidChange.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_ref="",
        aa_alt=aa_alt)

varcode.effects.effect_classes.Deletion(variant, transcript, aa_mutation_start_offset, aa_ref)

Bases: KnownAminoAcidChange

In-frame deletion of one or more amino acids.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        aa_ref):
    KnownAminoAcidChange.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_ref=aa_ref,
        aa_alt="")

varcode.effects.effect_classes.PrematureStop(variant, transcript, aa_mutation_start_offset, aa_ref='', aa_alt='')

Bases: KnownAminoAcidChange

In-frame insertion of codons containing a stop codon. May also involve insertion/deletion/substitution of other amino acids preceding the stop.

Insertion of premature stop codon, possibly preceded by a substitution of aa_ref amino acids for aa_alt alternative residues.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        aa_ref="",
        aa_alt=""):
    """
    Insertion of premature stop codon, possibly preceded by a substitution
    of `aa_ref` amino acids for `aa_alt` alternative residues.
    """
    if "*" in aa_ref:
        raise ValueError(
            ("Unexpected aa_ref = '%s', should only include amino acids "
             "before the new stop codon.") % aa_ref)
    if "*" in aa_alt:
        raise ValueError(
            ("Unexpected aa_ref = '%s', should only include amino acids "
             "before the new stop codon.") % aa_alt)
    KnownAminoAcidChange.__init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_ref=aa_ref,
        aa_alt=aa_alt)
    self.stop_codon_offset = aa_mutation_start_offset + len(aa_alt)

    if self.stop_codon_offset >= len(transcript.protein_sequence):
        raise ValueError(
            ("Premature stop codon cannot be at position %d"
             " since the original protein of %s has length %d") % (
                self.stop_codon_offset,
                transcript,
                len(transcript.protein_sequence)))

varcode.effects.effect_classes.StopLoss(variant, transcript, aa_ref, aa_alt)

Bases: KnownAminoAcidChange

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_ref,
        aa_alt):
    # StopLoss assumes that we deleted some codons ending with a
    # stop codon
    if "*" in aa_ref:
        raise ValueError(
            "StopLoss aa_ref '%s' should not contain '*'" % (
                aa_ref,))
    if len(aa_alt) == 0:
        raise ValueError(
            "If no amino acids added by StopLoss then it should be Silent")
    # subtract 1 for the stop codon
    n_ref_amino_acids = len(aa_ref)
    protein_length = len(transcript.protein_sequence)
    aa_mutation_start_offset = protein_length - n_ref_amino_acids
    KnownAminoAcidChange.__init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_alt=aa_alt,
        aa_ref=aa_ref)

extended_protein_sequence property

Deprecated name for aa_alt

varcode.effects.effect_classes.FrameShift(variant, transcript, aa_mutation_start_offset, shifted_sequence)

Bases: KnownAminoAcidChange

Frameshift mutation preserves all the amino acids up to aa_mutation_start_offset and then replaces the rest of the protein with new (frameshifted) sequence. Unlike an insertion, where we denote with aa_ref as the chracter before the variant sequence, a frameshift starts at aa_ref.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        shifted_sequence):
    """Frameshift mutation preserves all the amino acids up to
    aa_mutation_start_offset and then replaces the rest of the protein with
    new (frameshifted) sequence. Unlike an insertion, where we denote with
    aa_ref as the chracter before the variant sequence, a frameshift starts
    at aa_ref.
    """
    aa_ref = transcript.protein_sequence[aa_mutation_start_offset:]
    KnownAminoAcidChange.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_ref=aa_ref,
        aa_alt=shifted_sequence)

varcode.effects.effect_classes.FrameShiftTruncation(variant, transcript, stop_codon_offset, aa_ref='')

Bases: PrematureStop, FrameShift

A frame-shift mutation which immediately introduces a stop codon.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        stop_codon_offset,
        aa_ref=""):
    PrematureStop.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=stop_codon_offset,
        aa_ref=aa_ref,
        aa_alt="")

varcode.effects.effect_classes.ExonLoss(variant, transcript, exons)

Bases: Exonic

Deletion of one or more exons in a transcript.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, exons):
    Exonic.__init__(self, variant, transcript)
    self.exons = exons

Noncoding effects

varcode.effects.effect_classes.Intergenic(variant)

Bases: MutationEffect

Variant has unknown effect if it occurs between genes

Source code in varcode/effects/effect_classes.py
def __init__(self, variant):
    self.variant = variant

varcode.effects.effect_classes.NoncodingTranscript(variant, transcript)

Bases: TranscriptMutationEffect

Any mutation to a transcript with a non-coding biotype

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

varcode.effects.effect_classes.FivePrimeUTR(variant, transcript)

Bases: TranscriptMutationEffect

Any mutation to the 5' untranslated region (before the start codon) of coding transcript.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

varcode.effects.effect_classes.ThreePrimeUTR(variant, transcript)

Bases: TranscriptMutationEffect

Any mutation to the 3' untranslated region (after the stop codon) of coding transcript.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

varcode.effects.effect_classes.Intronic(variant, transcript, nearest_exon, distance_to_exon)

Bases: TranscriptMutationEffect

Mutation in an intronic region of a coding transcript

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, nearest_exon, distance_to_exon):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    self.nearest_exon = nearest_exon
    self.distance_to_exon = distance_to_exon

Splice effects

See the splice guide for candidate access.

varcode.SpliceOutcomeSet(variant, transcript, candidates=None, disrupted_signal_class=None, *, splice_effect=None, genomic_sequence=None, mechanism_order=None, dna_candidates=None, rna_evidence=(), added_candidates=(), excluded_candidates=(), candidate_rna_evidence=())

Bases: MultiOutcomeEffect, TranscriptMutationEffect

A splice-disrupting variant's effect, expressed as a set of plausible mechanisms rather than a single Effect.

Implements the :class:MultiOutcomeEffect protocol: downstream consumers can write isinstance(effect, MultiOutcomeEffect) to catch this and any future multi-outcome wrapper (RNA evidence, germline-aware, etc.) uniformly.

This set holds two distinct things — keep them straight:

  • The disruption — where the splice signal was hit. Stored as :attr:disrupted_signal_class, which is the :class:~varcode.effects.effect_classes.SpliceSite subclass (a type, e.g. SpliceDonor — not an Effect instance). It's metadata used for priority lookup. The corresponding Effect instance is reachable on every candidate via candidate.effect.splice_signal.
  • The protein outcomes — what the spliceosome might do. Stored as :attr:candidates, a tuple[EffectCandidate, ...]. Each candidate's effect is a :class:~varcode.effects.effect_classes.SpliceMechanismEffect subclass (:class:NormalSplicing, :class:ExonSkipping, :class:IntronRetention, :class:CrypticDonor, or :class:CrypticAcceptor) — class identity is the mechanism. These are the effects that carry a protein consequence: aa_ref / aa_alt / mutant_protein_sequence / mutant_transcript, populated when the protein math resolved, None when only the mechanism is predicted.

For back-compat, :attr:short_description delegates to the most likely candidate. Constructed by :func:enumerate_splice_outcomes as part of every Variant.effects() / Variant.effect_on_transcript(...) / VariantCollection.effects() call (always-on as of varcode 6.0).

RNA evidence reconciliation

:meth:with_rna_evidence returns a new set rather than mutating this one. The new set keeps dna_candidates for audit, narrows candidates to RNA-observed mechanisms, records DNA predictions absent from RNA as excluded_candidates, records observed mechanisms absent from the DNA prior as added_candidates, and exposes per-candidate support through candidate_rna_evidence / :meth:rna_evidence_for.

Serialization is inherited from :class:Serializable — no overrides needed now that there's no enum to stringify.

Source code in varcode/splice_outcomes.py
def __init__(
        self, variant, transcript, candidates=None,
        disrupted_signal_class=None,
        *,
        splice_effect=None,
        genomic_sequence=None,
        mechanism_order=None,
        dna_candidates=None, rna_evidence=(), added_candidates=(),
        excluded_candidates=(), candidate_rna_evidence=()):
    # SpliceOutcomeSet is both a MultiOutcomeEffect (candidate
    # set) and a TranscriptMutationEffect (carries variant, gene,
    # transcript). Initialising via TranscriptMutationEffect sets
    # all three; MultiOutcomeEffect carries no extra state.
    TranscriptMutationEffect.__init__(self, variant, transcript)
    # The SpliceSite *subclass* (a type, not an instance) of the
    # disruption this set replaced — SpliceDonor, SpliceAcceptor,
    # ExonicSpliceSite, or IntronicSpliceSite. Used for priority
    # lookup; the disruption *instance* lives on each candidate's
    # effect.splice_signal.
    self.disrupted_signal_class = disrupted_signal_class
    if candidates is not None:
        # Materialized path — RNA-reconciliation rebuilds,
        # deserialization, tests with explicit candidate lists.
        self._candidates_cache = tuple(candidates)
        self._normal_splicing_eager = next(
            (c for c in self._candidates_cache
             if isinstance(c.effect, NormalSplicing)),
            None)
        self._lazy_state = None
    else:
        # Lazy path — enumerate_splice_outcomes uses this. The
        # NormalSplicing candidate is computed eagerly because it's
        # cheap (just wraps the existing coding effect) and is the
        # fast path for ``effect_if_splicing_unchanged`` /
        # ``alternate_effect``. Expensive candidates (ExonSkipping,
        # IntronRetention, cryptic) are deferred until ``.candidates``
        # is read.
        if splice_effect is None or mechanism_order is None:
            raise ValueError(
                "SpliceOutcomeSet needs either explicit ``candidates`` "
                "or (``splice_effect`` + ``mechanism_order``) for "
                "lazy construction.")
        self._normal_splicing_eager = (
            _build_normal_splicing_candidate(splice_effect))
        self._candidates_cache = None
        self._lazy_state = (splice_effect, mechanism_order, genomic_sequence)
    self._explicit_dna_candidates = (
        None if dna_candidates is None else tuple(dna_candidates))
    self.rna_evidence = tuple(rna_evidence)
    self.added_candidates = tuple(added_candidates)
    self.excluded_candidates = tuple(excluded_candidates)
    self.candidate_rna_evidence = tuple(candidate_rna_evidence)

priority_class property

Delegate priority lookup to the disrupted-signal class so a SpliceOutcomeSet sorts as if it were the original splice effect.

Read by :func:varcode.effects.effect_priority.

effect_if_splicing_unchanged property

The coding consequence that applies if the spliceosome still splices normally despite the disrupted signal — i.e. the protein consequence of the underlying nucleotide change on its own (a :class:MutationEffect such as :class:Substitution, not a :class:SpliceMechanismEffect).

Resolves to the :class:NormalSplicing candidate's :attr:NormalSplicing.coding_effect. Returns None when there is no :class:NormalSplicing candidate or it carries no coding consequence (e.g. a purely intronic disruption, where a nucleotide change outside the CDS leaves the protein untouched if splicing proceeds).

This is the canonical "alternative outcome" accessor, alongside :attr:most_likely_effect (the top predicted splicing mechanism) and :attr:candidates (every plausible mechanism). Unlike the old ExonicSpliceSite.alternate_effect it works for intronic disruptions too.

candidate_proteins property

Mapping from each mechanism class to its computed mutant protein sequence (empty string when the protein is not computable from cDNA alone — i.e. intron retention and cryptic splice without a genomic_sequence provider).

Keyed by class object (e.g. ExonSkipping) rather than by enum string — match the candidate-iteration shape.

mutant_protein_sequences property

Set of distinct non-empty mutant protein sequences across all candidates.

with_rna_evidence(observed_candidates)

Return a new set reconciled with RNA-observed splice evidence.

RNA evidence is treated as a refinement of the DNA-predicted mechanism set: observed mechanisms replace their broad DNA predictions, unobserved DNA-predicted mechanisms are recorded as excluded, and observed mechanisms absent from the DNA prediction are recorded as added. The original set is left untouched.

Source code in varcode/splice_outcomes.py
def with_rna_evidence(self, observed_candidates):
    """Return a new set reconciled with RNA-observed splice evidence.

    RNA evidence is treated as a refinement of the DNA-predicted
    mechanism set: observed mechanisms replace their broad DNA
    predictions, unobserved DNA-predicted mechanisms are recorded as
    excluded, and observed mechanisms absent from the DNA prediction
    are recorded as added. The original set is left untouched.
    """
    observed = tuple(observed_candidates)
    if not observed:
        return self

    combined_evidence = self.rna_evidence + observed
    splice_evidence = tuple(
        c for c in combined_evidence
        if isinstance(c.effect, SpliceMechanismEffect))
    if not splice_evidence:
        return SpliceOutcomeSet(
            variant=self.variant,
            transcript=self.transcript,
            candidates=self.candidates + observed,
            disrupted_signal_class=self.disrupted_signal_class,
            dna_candidates=self.dna_candidates,
            rna_evidence=combined_evidence,
            added_candidates=observed,
            excluded_candidates=self.excluded_candidates,
            candidate_rna_evidence=self.candidate_rna_evidence,
        )

    dna_by_mechanism = {
        type(candidate.effect): candidate
        for candidate in self.dna_candidates
    }
    evidence_by_mechanism = {}
    evidence_by_signature = {}
    representative_by_signature = {}
    for candidate in splice_evidence:
        mechanism = type(candidate.effect)
        evidence_by_mechanism.setdefault(mechanism, []).append(candidate)
        signature = _splice_candidate_signature(candidate)
        evidence_by_signature.setdefault(signature, []).append(candidate)
        representative_by_signature.setdefault(signature, candidate)

    current = []
    excluded = []
    added = []
    seen_signatures = set()

    def add_current_observed(candidate):
        signature = _splice_candidate_signature(candidate)
        if signature in seen_signatures:
            return None
        seen_signatures.add(signature)
        representative = representative_by_signature[signature]
        current.append(representative)
        return representative

    for dna_candidate in self.dna_candidates:
        mechanism = type(dna_candidate.effect)
        observed_for_mechanism = tuple(
            evidence_by_mechanism.get(mechanism, ()))
        if observed_for_mechanism:
            for candidate in observed_for_mechanism:
                add_current_observed(candidate)
        else:
            excluded.append(dna_candidate)

    for candidate in splice_evidence:
        mechanism = type(candidate.effect)
        if mechanism not in dna_by_mechanism:
            representative = add_current_observed(candidate)
            if representative is not None:
                added.append(representative)

    support = tuple(
        SpliceCandidateRNAEvidence(
            candidate=candidate,
            rna_evidence=tuple(evidence_by_signature.get(
                _splice_candidate_signature(candidate), ())))
        for candidate in current
    )

    return SpliceOutcomeSet(
        variant=self.variant,
        transcript=self.transcript,
        candidates=current,
        disrupted_signal_class=self.disrupted_signal_class,
        dna_candidates=self.dna_candidates,
        rna_evidence=combined_evidence,
        added_candidates=added,
        excluded_candidates=excluded,
        candidate_rna_evidence=support,
    )

rna_evidence_for(candidate)

RNA-observed candidates supporting candidate.

Source code in varcode/splice_outcomes.py
def rna_evidence_for(self, candidate):
    """RNA-observed candidates supporting ``candidate``."""
    candidate_signature = _splice_candidate_signature(candidate)
    for entry in self.candidate_rna_evidence:
        if entry.candidate is candidate or entry.candidate == candidate:
            return entry.rna_evidence
        if _splice_candidate_signature(entry.candidate) == candidate_signature:
            return entry.rna_evidence
    return ()

varcode.effects.effect_classes.SpliceSite

Bases: object

Marker base for the four splice-signal disruption effects: :class:SpliceDonor, :class:SpliceAcceptor, :class:IntronicSpliceSite, and :class:ExonicSpliceSite.

A SpliceSite effect answers where a variant hit a splice signal — a position fact (which boundary, how close). It does not describe the protein consequence: from DNA alone you can't say how the spliceosome will respond. That downstream protein-level outcome is modeled separately by :class:SpliceMechanismEffect subclasses (exon skipping, intron retention, cryptic-site use, normal splicing).

So the two halves of splice handling are:

  • SpliceSite → where the signal was disrupted.
  • SpliceMechanismEffect → what the spliceosome does, and the protein change that results.

:func:varcode.splice_outcomes.enumerate_splice_outcomes bridges them: given a SpliceSite disruption it produces a :class:~varcode.splice_outcomes.SpliceOutcomeSet of plausible mechanisms.

varcode.effects.effect_classes.IntronicSpliceSite(variant, transcript, nearest_exon, distance_to_exon)

Bases: Intronic, SpliceSite

Mutations near exon boundaries, excluding the first two and last two nucleotides in an intron, since those are known to more confidently affect splicing and are given their own effect classes below.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, nearest_exon, distance_to_exon):
    Intronic.__init__(
        self, variant, transcript, nearest_exon, distance_to_exon)

varcode.effects.effect_classes.SpliceDonor(variant, transcript, nearest_exon, distance_to_exon)

Bases: IntronicSpliceSite

Mutation in the first two intron residues.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, nearest_exon, distance_to_exon):
    IntronicSpliceSite.__init__(
        self, variant, transcript, nearest_exon, distance_to_exon)

varcode.effects.effect_classes.SpliceAcceptor(variant, transcript, nearest_exon, distance_to_exon)

Bases: IntronicSpliceSite

Mutation in the last two intron residues.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, nearest_exon, distance_to_exon):
    Intronic.__init__(
        self, variant, transcript, nearest_exon, distance_to_exon)

varcode.effects.effect_classes.ExonicSpliceSite(variant, transcript, exon, alternate_effect)

Bases: Exonic, SpliceSite, MultiOutcomeEffect

Mutation in the last three nucleotides before an intron or in the first nucleotide after an intron.

Expresses the two plausible outcomes of a splice-adjacent exonic variant — splice-signal disruption vs. the underlying coding change if splicing proceeds normally — via the :class:MultiOutcomeEffect protocol (#299, #382). :attr:candidates yields a 2-tuple of :class:~varcode.effect_candidates.EffectCandidate objects; alternate_effect stays on the instance as a first-class field for back-compat with callers that depended on it.

Note: as of varcode 6.0, ExonicSpliceSite no longer surfaces as the top-level effect at the user-facing API — splice-disrupting variants are always wrapped in :class:~varcode.splice_outcomes.SpliceOutcomeSet. ExonicSpliceSite survives as splice_set.disrupted_signal_class (a type) and as the splice_signal reference on each candidate (an instance).

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, exon, alternate_effect):
    Exonic.__init__(self, variant, transcript)
    self.exon = exon
    self.alternate_effect = alternate_effect

mutant_protein_sequence property

TODO: determine when exonic splice variants cause exon skipping vs. translation of the underlying modified coding sequence.

For now just pretending like there is no effect on splicing.

candidates property

The two plausible outcomes wrapped as :class:~varcode.effect_candidates.EffectCandidate:

Position [0] is the splice-disruption outcome (this effect itself); position [1] is the coding change if splicing proceeds. Returns a 1-tuple when alternate_effect is None. Extra candidates attached via :meth:_combine_with_extra_candidates (e.g. from RNA evidence) come after.

priority_class property

ExonicSpliceSite priority is used directly — no delegation, since this class IS the splice-adjacent effect rather than a wrapper around one.

varcode.effects.effect_classes.SpliceMechanismEffect(variant, transcript, splice_signal, protein_effect=None, mutant_transcript=None, aa_ref=None, aa_alt=None, aa_mutation_start_offset=None, aa_mutation_end_offset=None, mutant_protein_sequence=None)

Bases: TranscriptMutationEffect

Base for effects describing what the splice machinery does downstream of a disrupted splice signal.

Concrete subclasses: :class:NormalSplicing, :class:ExonSkipping, :class:IntronRetention, :class:CrypticDonor, :class:CrypticAcceptor. Class identity is the mechanism; instances of this base are not constructed directly.

Protein vocab fields are optional — None means "predicted mechanism, exact protein not computable from cached cDNA alone." When resolved, the fields follow the same conventions as :class:KnownAminoAcidChange so consumers can read them uniformly.

PARAMETER DESCRIPTION
variant

TYPE: Variant

transcript

TYPE: Transcript

splice_signal

The splice-signal-disruption Effect instance describing where the disruption was — a :class:SpliceSite (one of SpliceDonor / SpliceAcceptor / IntronicSpliceSite / ExonicSpliceSite). Lets consumers reach effect.splice_signal.nearest_exon, effect.splice_signal.distance_to_exon, etc. without carrying those fields redundantly on every mechanism subclass.

TYPE: SpliceSite

protein_effect

Classified protein-level consequence of this splice mechanism (e.g. Deletion, FrameShift, PrematureStop) when the protein sequence was resolved. The mechanism object keeps its own class identity while delegating severity metadata to this classified consequence.

TYPE: MutationEffect or None DEFAULT: None

mutant_transcript

TYPE: MutantTranscript or None DEFAULT: None

aa_ref

TYPE: str or None DEFAULT: None

aa_alt

TYPE: str or None DEFAULT: None

aa_mutation_start_offset

TYPE: int or None DEFAULT: None

aa_mutation_end_offset

TYPE: int or None DEFAULT: None

mutant_protein_sequence

TYPE: str or None DEFAULT: None

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, transcript, splice_signal,
        protein_effect=None,
        mutant_transcript=None,
        aa_ref=None, aa_alt=None,
        aa_mutation_start_offset=None,
        aa_mutation_end_offset=None,
        mutant_protein_sequence=None):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    self.splice_signal = splice_signal
    self.protein_effect = protein_effect
    self.mutant_transcript = mutant_transcript
    self.aa_ref = aa_ref
    self.aa_alt = aa_alt
    self.aa_mutation_start_offset = aa_mutation_start_offset
    self.aa_mutation_end_offset = aa_mutation_end_offset
    self.mutant_protein_sequence = mutant_protein_sequence

resolved: bool property

True when the protein math succeeded for this mechanism — i.e. :attr:mutant_protein_sequence is populated. Convenience for consumers that want to branch on "do we have a concrete protein for this mechanism?"

varcode.effects.effect_classes.NormalSplicing(variant, transcript, splice_signal, coding_effect=None)

Bases: SpliceMechanismEffect

Canonical splicing proceeds despite the disruption.

The splice signal was hit, but the spliceosome handles it; the protein consequence (if any) is whatever the underlying nucleotide change normally produces — a :class:Substitution for an :class:ExonicSpliceSite, no protein change for a purely intronic disruption. The underlying coding change is carried as :attr:coding_effect; when there isn't one (intronic variant), it's None.

Note: this class is special among :class:SpliceMechanismEffect subclasses — it doesn't itself transform the protein, so all the protein-vocab attributes (aa_ref, aa_alt, mutant_protein_sequence, mutant_transcript, aa_mutation_*_offset) are delegating descriptors that read through to coding_effect. Construction therefore calls :class:TranscriptMutationEffect's __init__ directly rather than :class:SpliceMechanismEffect's — the latter would set those names as plain instance attributes and shadow the descriptors. The other four mechanisms (skipping, retention, cryptic donor/acceptor) actually transform the protein and carry their own protein vocab as instance state.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, splice_signal,
             coding_effect=None):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    self.splice_signal = splice_signal
    self.coding_effect = coding_effect

varcode.effects.effect_classes.ExonSkipping(variant, transcript, splice_signal, affected_exon, in_frame, mutant_transcript=None, protein_effect=None, aa_ref=None, aa_alt=None, aa_mutation_start_offset=None, aa_mutation_end_offset=None, mutant_protein_sequence=None)

Bases: SpliceMechanismEffect

The affected exon is excluded from the mature transcript.

When in-frame (the exon's length is divisible by 3), the result is a clean amino-acid deletion plus an optional boundary-codon reshape. When out-of-frame, a frameshift propagates from the new exon junction through the rest of the transcript.

Parameters beyond the base class

affected_exon : pyensembl.Exon The skipped exon. in_frame : bool True when len(affected_exon) % 3 == 0 — the exon-skip is codon-aligned and the downstream sequence keeps its frame.

Note on aa_ref / aa_alt semantics

The AA-level fields come from :func:~varcode.effects.classify.classify_from_protein_diff, so what they mean depends on in_frame:

  • In-frame skip (in_frame=True): aa_ref is the contiguous run of amino acids removed from the reference protein (including the boundary-codon reshape when the exon boundary lands mid-codon). aa_alt is the reshaped boundary codon's translation (or "" for a clean codon-aligned skip).
  • Out-of-frame skip (in_frame=False): aa_ref is the reference AA at the divergence point (where the frame breaks after the new exon junction); aa_alt is the first frameshifted AA. The downstream protein continues in the new frame until a premature stop — read the full sequence from :attr:mutant_protein_sequence, not from aa_alt.
Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, splice_signal, affected_exon,
             in_frame, mutant_transcript=None,
             protein_effect=None,
             aa_ref=None, aa_alt=None,
             aa_mutation_start_offset=None,
             aa_mutation_end_offset=None,
             mutant_protein_sequence=None):
    SpliceMechanismEffect.__init__(
        self, variant, transcript, splice_signal,
        protein_effect=protein_effect,
        mutant_transcript=mutant_transcript,
        aa_ref=aa_ref, aa_alt=aa_alt,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_mutation_end_offset=aa_mutation_end_offset,
        mutant_protein_sequence=mutant_protein_sequence)
    self.affected_exon = affected_exon
    self.in_frame = in_frame

varcode.effects.effect_classes.IntronRetention(variant, transcript, splice_signal, retained_intron_start=None, retained_intron_end=None, side=None, mutant_transcript=None, protein_effect=None, aa_ref=None, aa_alt=None, aa_mutation_start_offset=None, aa_mutation_end_offset=None, mutant_protein_sequence=None)

Bases: SpliceMechanismEffect

The intron stays in the mature transcript; translation typically hits a premature stop inside the retained intron.

Parameters beyond the base class

retained_intron_start, retained_intron_end : int or None Genomic coordinates of the retained intron (1-based inclusive). Populated when the adjacent-exon geometry identifies which intron is being retained; None when that can't be determined (e.g. transcript missing the adjacent exon, splice boundary ambiguous). side : str or None "donor" or "acceptor" — which splice boundary failed, causing the intron to be retained. None when the side can't be inferred from the splice classification.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, splice_signal,
             retained_intron_start=None, retained_intron_end=None,
             side=None,
             mutant_transcript=None,
             protein_effect=None,
             aa_ref=None, aa_alt=None,
             aa_mutation_start_offset=None,
             aa_mutation_end_offset=None,
             mutant_protein_sequence=None):
    SpliceMechanismEffect.__init__(
        self, variant, transcript, splice_signal,
        protein_effect=protein_effect,
        mutant_transcript=mutant_transcript,
        aa_ref=aa_ref, aa_alt=aa_alt,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_mutation_end_offset=aa_mutation_end_offset,
        mutant_protein_sequence=mutant_protein_sequence)
    self.retained_intron_start = retained_intron_start
    self.retained_intron_end = retained_intron_end
    self.side = side

varcode.effects.effect_classes.CrypticSpliceSiteEffect(variant, transcript, splice_signal, affected_exon, cryptic_genomic_position=None, motif_score=None, exon_length_delta=None, mutant_transcript=None, protein_effect=None, aa_ref=None, aa_alt=None, aa_mutation_start_offset=None, aa_mutation_end_offset=None, mutant_protein_sequence=None)

Bases: SpliceMechanismEffect

Base for cryptic donor / acceptor effects. Carries the cryptic motif's position and score, plus the resulting exon length delta.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, splice_signal, affected_exon,
             cryptic_genomic_position=None, motif_score=None,
             exon_length_delta=None,
             mutant_transcript=None,
             protein_effect=None,
             aa_ref=None, aa_alt=None,
             aa_mutation_start_offset=None,
             aa_mutation_end_offset=None,
             mutant_protein_sequence=None):
    SpliceMechanismEffect.__init__(
        self, variant, transcript, splice_signal,
        protein_effect=protein_effect,
        mutant_transcript=mutant_transcript,
        aa_ref=aa_ref, aa_alt=aa_alt,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_mutation_end_offset=aa_mutation_end_offset,
        mutant_protein_sequence=mutant_protein_sequence)
    self.affected_exon = affected_exon
    self.cryptic_genomic_position = cryptic_genomic_position
    self.motif_score = motif_score
    self.exon_length_delta = exon_length_delta

varcode.effects.effect_classes.CrypticDonor(variant, transcript, splice_signal, affected_exon, cryptic_genomic_position=None, motif_score=None, exon_length_delta=None, mutant_transcript=None, protein_effect=None, aa_ref=None, aa_alt=None, aa_mutation_start_offset=None, aa_mutation_end_offset=None, mutant_protein_sequence=None)

Bases: CrypticSpliceSiteEffect

A cryptic GT donor is used instead of the disrupted canonical donor; the exon is extended (cryptic site downstream) or truncated (cryptic site upstream).

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, splice_signal, affected_exon,
             cryptic_genomic_position=None, motif_score=None,
             exon_length_delta=None,
             mutant_transcript=None,
             protein_effect=None,
             aa_ref=None, aa_alt=None,
             aa_mutation_start_offset=None,
             aa_mutation_end_offset=None,
             mutant_protein_sequence=None):
    SpliceMechanismEffect.__init__(
        self, variant, transcript, splice_signal,
        protein_effect=protein_effect,
        mutant_transcript=mutant_transcript,
        aa_ref=aa_ref, aa_alt=aa_alt,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_mutation_end_offset=aa_mutation_end_offset,
        mutant_protein_sequence=mutant_protein_sequence)
    self.affected_exon = affected_exon
    self.cryptic_genomic_position = cryptic_genomic_position
    self.motif_score = motif_score
    self.exon_length_delta = exon_length_delta

varcode.effects.effect_classes.CrypticAcceptor(variant, transcript, splice_signal, affected_exon, cryptic_genomic_position=None, motif_score=None, exon_length_delta=None, mutant_transcript=None, protein_effect=None, aa_ref=None, aa_alt=None, aa_mutation_start_offset=None, aa_mutation_end_offset=None, mutant_protein_sequence=None)

Bases: CrypticSpliceSiteEffect

A cryptic AG acceptor is used instead of the disrupted canonical acceptor; the exon is extended (cryptic site upstream) or truncated (cryptic site downstream).

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, splice_signal, affected_exon,
             cryptic_genomic_position=None, motif_score=None,
             exon_length_delta=None,
             mutant_transcript=None,
             protein_effect=None,
             aa_ref=None, aa_alt=None,
             aa_mutation_start_offset=None,
             aa_mutation_end_offset=None,
             mutant_protein_sequence=None):
    SpliceMechanismEffect.__init__(
        self, variant, transcript, splice_signal,
        protein_effect=protein_effect,
        mutant_transcript=mutant_transcript,
        aa_ref=aa_ref, aa_alt=aa_alt,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_mutation_end_offset=aa_mutation_end_offset,
        mutant_protein_sequence=mutant_protein_sequence)
    self.affected_exon = affected_exon
    self.cryptic_genomic_position = cryptic_genomic_position
    self.motif_score = motif_score
    self.exon_length_delta = exon_length_delta

varcode.effects.effect_classes.CrypticExonCandidate(variant, contig, interval_start, interval_end, donor_score=None, acceptor_score=None)

Bases: MutationEffect

A region where an SV has brought novel sequence into range of the transcript, and motif scoring flags a plausible new splice acceptor / donor pair. Produced by PR 11's cryptic-exon enumerator; attached as additional :class:EffectCandidate entries on SV effects rather than standalone.

Not a :class:TranscriptMutationEffect because the candidate region may not overlap any existing transcript — it's a new exon hypothesis. Carries the contig / interval and the motif scores as plain fields; external predictors (SpliceAI, Pangolin) attach their own scores via the enclosing :class:EffectCandidate.evidence dict.

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, contig, interval_start, interval_end,
        donor_score=None, acceptor_score=None):
    MutationEffect.__init__(self, variant)
    self.contig = contig
    self.interval_start = interval_start
    self.interval_end = interval_end
    self.donor_score = donor_score
    self.acceptor_score = acceptor_score

Structural effects

varcode.effects.effect_classes.StructuralVariantEffect(variant, transcript, primary_effects=None, mutant_transcript=None)

Bases: TranscriptMutationEffect, MultiOutcomeEffect

Base class for effects of a :class:StructuralVariant on a specific transcript. Local models contain consequence effects in :attr:candidates; their description follows the first prediction and their priority follows the highest-priority candidate. Gene fusions and translocations retain their specialized descriptions.

:attr:candidates always returns a tuple of :class:~varcode.effect_candidates.EffectCandidate objects. Primary candidates carry source="varcode"; cryptic-exon candidates attached via :meth:_attach_cryptic_candidates carry source="varcode_motif"; splice-outcome candidates attached via :meth:_attach_splice_outcomes carry source="varcode_splice".

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, transcript,
        primary_effects=None, mutant_transcript=None):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    # Primary classifications: either the subclass's own effect
    # (``self``) or a caller-supplied tuple of
    # :class:`MutationEffect` instances. Lifted into
    # :class:`EffectCandidate` shape on access.
    self._primary_effects = (
        tuple(primary_effects) if primary_effects is not None
        else (self,))
    self.mutant_transcript = mutant_transcript
    # Cryptic-exon candidates nominated by
    # :func:`varcode.cryptic_exons.enumerate_from_structural_variant`
    # (#337). Kept separate from primary effects because their
    # entries carry different source / evidence.
    self._cryptic_candidates = ()
    # Splice-outcome candidates attached by the SV annotator when
    # an SV breakpoint lands in a canonical splice window (#341).
    # Pre-constructed :class:`~varcode.EffectCandidate` tuples; the
    # annotator re-sources them as ``"varcode_splice"`` and
    # enriches evidence with ``sv_type`` before attaching.
    self._splice_candidates = ()

mutant_protein_sequence property

Protein carried by the realized structural transcript, if any.

modifies_coding_sequence property

True if any candidate changes CDS, None if unresolved, else False.

Protein equality alone does not establish coding-sequence equality.

modifies_protein_sequence property

True if any candidate changes protein, None if unresolved, else False.

A set with an unchanged primary and a changed alternative returns True. False requires every candidate to be known unchanged; None is not silent.

candidates property

Unified :class:~varcode.EffectCandidate view over primary SV classifications, attached cryptic candidates, and any splice-outcome candidates (#339, #337, #341, #382).

Primary candidates carry source="varcode"; cryptic-exon candidates carry source="varcode_motif"; splice-outcome candidates carry source="varcode_splice". Each source marks provenance so external scorers (SpliceAI, Pangolin, RNA evidence) can filter before rescoring.

Legacy event-type classes remain importable; the default annotator emits transcript consequences.

varcode.effects.effect_classes.LargeDeletion(variant, transcript, affected_exons, primary_effects=None, mutant_transcript=None)

Bases: StructuralVariantEffect

A deletion (<DEL> / <CN0>) that removes one or more exons — or an entire gene. Carries the list of affected exons for downstream analysis; the single outcome is this effect itself (callers that want to add RNA evidence or SpliceAI scoring construct additional outcomes and wrap the result).

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, transcript, affected_exons,
        primary_effects=None, mutant_transcript=None):
    StructuralVariantEffect.__init__(
        self, variant, transcript,
        primary_effects=primary_effects,
        mutant_transcript=mutant_transcript)
    self.affected_exons = tuple(affected_exons)

varcode.effects.effect_classes.LargeDuplication(variant, transcript, affected_exons, primary_effects=None, mutant_transcript=None)

Bases: StructuralVariantEffect

A tandem duplication (<DUP>) overlapping exons. Biologically may produce a copy-number increase, a fused reading frame if junctions land in-frame, or a regulatory effect. Varcode reports the affected exons and leaves scoring to downstream tools.

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, transcript, affected_exons,
        primary_effects=None, mutant_transcript=None):
    StructuralVariantEffect.__init__(
        self, variant, transcript,
        primary_effects=primary_effects,
        mutant_transcript=mutant_transcript)
    self.affected_exons = tuple(affected_exons)

varcode.effects.effect_classes.Inversion(variant, transcript, primary_effects=None, mutant_transcript=None)

Bases: StructuralVariantEffect

An inversion (<INV>) that flips a stretch of a transcript. Depending on whether breakpoints fall in exons or introns, the consequence is very different (exonic: likely disruptive; purely intronic: may or may not affect splicing). Reported as a single outcome here; subclasses / callers can enrich with cryptic- splice candidates per PR 11.

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, transcript,
        primary_effects=None, mutant_transcript=None):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    # Primary classifications: either the subclass's own effect
    # (``self``) or a caller-supplied tuple of
    # :class:`MutationEffect` instances. Lifted into
    # :class:`EffectCandidate` shape on access.
    self._primary_effects = (
        tuple(primary_effects) if primary_effects is not None
        else (self,))
    self.mutant_transcript = mutant_transcript
    # Cryptic-exon candidates nominated by
    # :func:`varcode.cryptic_exons.enumerate_from_structural_variant`
    # (#337). Kept separate from primary effects because their
    # entries carry different source / evidence.
    self._cryptic_candidates = ()
    # Splice-outcome candidates attached by the SV annotator when
    # an SV breakpoint lands in a canonical splice window (#341).
    # Pre-constructed :class:`~varcode.EffectCandidate` tuples; the
    # annotator re-sources them as ``"varcode_splice"`` and
    # enriches evidence with ``sv_type`` before attaching.
    self._splice_candidates = ()

varcode.effects.effect_classes.GeneFusion(variant, transcript, partner_transcript, mutant_transcript=None, primary_effects=None, five_prime_transcript=None, three_prime_transcript=None)

Bases: StructuralVariantEffect

A structural variant joining transcript to a sense-oriented transcript in another gene — the canonical fusion shape. Breakends produce it, and so do deletions, duplications and inversions with one end in each gene.

The default annotator retains every compatible annotated partner isoform and junction in :attr:candidates, with no count cap. The first is the historical primary; producer order is not a probability ranking. Distinct transcript pairs remain separate even when their proteins match. Missing sequence leaves that candidate's transcript/protein unresolved.

transcript is the transcript being annotated and partner_transcript the other one; five_prime_transcript and three_prime_transcript say which is which (by default transcript is the 5' partner). When the annotator has enough context, :attr:mutant_transcript is built from :class:ReferenceSegment entries describing the fused allele. Predicting the exact fused-protein sequence requires knowing which exons are retained, which typically needs RNA evidence — outcomes beyond "this is a plausible fusion" are imported with :func:varcode.make_fusion_outcome or supplied by tools attaching :class:EffectCandidate objects with their own source tag. An RNA-observed gene fusion need not encode a complete protein.

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, transcript, partner_transcript,
        mutant_transcript=None, primary_effects=None,
        five_prime_transcript=None, three_prime_transcript=None):
    StructuralVariantEffect.__init__(
        self, variant, transcript,
        primary_effects=primary_effects,
        mutant_transcript=mutant_transcript)
    self.partner_transcript = partner_transcript
    self.five_prime_transcript = (
        transcript if five_prime_transcript is None
        else five_prime_transcript)
    self.three_prime_transcript = (
        partner_transcript if three_prime_transcript is None
        else three_prime_transcript)

varcode.effects.effect_classes.TranslocationToIntergenic(variant, transcript, primary_effects=None, mutant_transcript=None)

Bases: StructuralVariantEffect

A breakend that doesn't form a gene fusion: its mate lies in intergenic space, or the join meets a gene in an orientation that can't read sense-to-sense into it (e.g. two genes' 5' ends joined head to head). The downstream consequence depends on whether the sequence beyond the breakpoint contains cryptic splice / ORF signals — reported as a single outcome here, with PR 11's cryptic-exon enumerator adding candidate outcomes when applicable.

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variant, transcript,
        primary_effects=None, mutant_transcript=None):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    # Primary classifications: either the subclass's own effect
    # (``self``) or a caller-supplied tuple of
    # :class:`MutationEffect` instances. Lifted into
    # :class:`EffectCandidate` shape on access.
    self._primary_effects = (
        tuple(primary_effects) if primary_effects is not None
        else (self,))
    self.mutant_transcript = mutant_transcript
    # Cryptic-exon candidates nominated by
    # :func:`varcode.cryptic_exons.enumerate_from_structural_variant`
    # (#337). Kept separate from primary effects because their
    # entries carry different source / evidence.
    self._cryptic_candidates = ()
    # Splice-outcome candidates attached by the SV annotator when
    # an SV breakpoint lands in a canonical splice window (#341).
    # Pre-constructed :class:`~varcode.EffectCandidate` tuples; the
    # annotator re-sources them as ``"varcode_splice"`` and
    # enriches evidence with ``sv_type`` before attaching.
    self._splice_candidates = ()

Haplotype effects

varcode.effects.effect_classes.HaplotypeEffect(variants, transcript, mutant_transcript, phase_source=None)

Bases: TranscriptMutationEffect, MultiOutcomeEffect

Joint effect of two or more cis variants on the same transcript (#269).

Emitted by :meth:VariantCollection.effects when a phase_resolver (VCF PS tag, Isovar assembly, or any other :class:PhaseResolver) groups cis variants together and :func:varcode.mutant_transcript.apply_variants_to_transcript can build a combined mutant cDNA. The per-variant effects stay on the collection — this is additive, not a replacement.

Downstream consumers that want haplotype-level context (peptide prediction, ASE, compound het interpretation) read the :attr:mutant_transcript here. Consumers that want per-variant HGVS or annotation granularity iterate the per-variant effects as before.

Source code in varcode/effects/effect_classes.py
def __init__(
        self, variants, transcript, mutant_transcript,
        phase_source=None):
    # The HaplotypeEffect is scoped to a set of variants — the
    # :class:`MutationEffect.variant` slot takes the first one
    # as a back-compat anchor so existing single-variant
    # consumers don't blow up, but real consumers read
    # :attr:`variants`.
    assert len(variants) >= 2, (
        "HaplotypeEffect requires ≥ 2 cis variants; got %d" % len(variants))
    TranscriptMutationEffect.__init__(self, variants[0], transcript)
    self.variants = tuple(variants)
    self.mutant_transcript = mutant_transcript
    # Which resolver produced the phase grouping (e.g. "vcf_ps"
    # for DNA-PS-tag phasing, "read_phasing" for an RNA / long-
    # read source). Useful for downstream filtering and for
    # auditing whether the cis call came from DNA-only phasing
    # or RNA-assembly evidence.
    self.phase_source = phase_source

candidates property

Single-outcome wrapping: the haplotype IS the outcome, lifted into the uniform :class:EffectCandidate shape so consumers iterate :attr:candidates the same way across all :class:MultiOutcomeEffect subclasses (#382). Extra candidates attached via :meth:_combine_with_extra_candidates (e.g. from RNA evidence) come after.

mutant_protein_sequence property

Joint protein translated from the haplotype's cDNA, or None if the edits don't land after the CDS start.

short_description property

HGVS haplotype notation: [c.1A>T;c.5G>C] for cis.

Per-variant short descriptions are synthesized from each variant's genomic coords when the per-variant effect isn't available here — the transcript-level HGVS would require re-running the per-variant classifier, which HaplotypeEffect deliberately doesn't do (that work lives on the per-variant effects that coexist in the collection).

varcode.effects.effect_classes.PhaseCandidateSet(variant, transcript, candidates, hypotheses, germline_variants)

Bases: TranscriptMutationEffect, MultiOutcomeEffect

Possibility set across phase hypotheses when a somatic variant and one or more germline variants share a window on a transcript and phase between them is unknown.

The somatic effect at this locus depends on which haplotype the somatic landed on, and without phase data we can't say which. The honest output is the set of plausible effects, one per hypothesis. most_likely returns the highest-priority candidate; :attr:candidates exposes the full set with per-hypothesis evidence keys (phase_state, haplotype, germline_variants) so consumers — including RNA-evidence integrations from #259 — can align across axes.

Emitted by :func:varcode.germline.predict_germline_aware_effect. Sibling of :class:HaplotypeEffect: that one captures the known-cis multi-variant case; this one captures the unknown-phase possibility set.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        candidates,
        hypotheses,
        germline_variants):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    if len(candidates) != len(hypotheses):
        raise ValueError(
            "PhaseCandidateSet needs one candidate per "
            "hypothesis; got %d candidates and %d hypotheses." % (
                len(candidates), len(hypotheses)))
    if not candidates:
        raise ValueError(
            "PhaseCandidateSet requires at least one candidate.")
    self._candidates_raw = tuple(candidates)
    self._hypotheses = tuple(hypotheses)
    self.germline_variants = tuple(germline_variants)

candidates property

One :class:EffectCandidate per hypothesis, sorted by underlying effect priority (most-severe first), carrying the phase metadata needed to align with RNA-evidence outcomes (#259, #382).

evidence keys: phase_state ("phased" / "implicit" / "unknown" / "too_many_hypotheses"), haplotype (opaque tag), germline_variants (tuple of the cis germline variants on that hypothesis's haplotype).

short_description property

"?<most_likely_effect>" — the leading ? flags the ambiguity. Consumers wanting the full possibility set read :attr:candidates.

mutant_protein_sequence property

Most-likely candidate's mutant protein. Consumers iterating over hypotheses pull per-candidate sequences from :attr:candidates.

varcode.effects.effect_classes.GermlineAlleleOverlap(variant, transcript)

Bases: TranscriptMutationEffect

This reported allele is already present in the supplied germline.

No new allele sequence is established. This does not assess allele dosage, loss of the other allele, expression, or the allele's pathogenicity.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

Unknown results

varcode.effects.effect_classes.Unresolved(variant, transcript, mechanism, reason=None)

Bases: TranscriptMutationEffect

An effect that could not be resolved with this model or evidence.

Unlike :class:Failure, this is not an annotation error. A hypothesis may require missing genomic sequence or an RNA assembly. Alternatively, mechanism="unsupported_annotation" means the selected annotator returned NotImplemented for this input. reason explains why; unresolved does not mean the variant is harmless.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript, mechanism, reason=None):
    TranscriptMutationEffect.__init__(self, variant, transcript)
    self.mechanism = mechanism
    self.reason = reason

varcode.effects.effect_classes.IncompleteTranscript(variant, transcript)

Bases: TranscriptMutationEffect

Any mutation to an incompletely annotated transcript with a coding biotype

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

varcode.effects.effect_classes.Failure(variant, transcript=None, error=None)

Bases: TranscriptMutationEffect

Special placeholder effect for when we want to suppress errors but still need to create a non-empty list of effects for each variant.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript=None, error=None):
    MutationEffect.__init__(self, variant)
    self.transcript = transcript
    self.gene = transcript.gene if transcript is not None else None
    self.error = error

Base classes

varcode.effects.effect_classes.MutationEffect(variant)

Bases: Serializable

Base class for mutation effects.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant):
    self.variant = variant

short_description property

A short but human-readable description of the effect. Defaults to class name for most of the non-coding effects, but is more informative for coding ones.

original_protein_sequence property

Amino acid sequence of a coding transcript (without the nucleotide variant/mutation)

__lt__(other)

Effects are ordered by their associated variants, which have comparison implement in terms of their chromosomal locations.

Source code in varcode/effects/effect_classes.py
def __lt__(self, other):
    """
    Effects are ordered by their associated variants, which have
    comparison implement in terms of their chromosomal locations.
    """
    return self.variant < other.variant

varcode.effects.effect_classes.MultiOutcomeEffect(variant)

Bases: MutationEffect

Marker base class for effects that represent a set of plausible outcomes rather than a single deterministic effect.

Subclasses must expose:

  • :attr:candidates — tuple of :class:~varcode.effect_candidates.EffectCandidate objects in producer order. Each entry pairs an inner :class:MutationEffect (concrete or placeholder) with its provenance — source (producer) and evidence dict. The :attr:effects helper unwraps to the inner Effects when callers don't need provenance.
  • :attr:priority_class — effect class whose priority this set adopts (read by :func:varcode.effects.effect_priority).

Downstream consumers filter for multi-outcome results with isinstance(effect, MultiOutcomeEffect), so new wrappers (RNA evidence #259, germline-aware #268, SV-at-breakpoint) implement the same protocol uniformly (#382).

External integrations (RNA evidence, SpliceAI scoring, etc.) attach extra candidates post-hoc via the _extra_candidates slot — subclasses that override :attr:candidates must include those extras in their returned tuple. The :meth:_combine_with_extra_candidates helper does the right thing.

Picking the candidate

Two orthogonal "best candidate" notions are available; pick the one that matches your question:

  • Most likely: the first candidate after producer ordering. Producers preserve their own deterministic order. :attr:most_likely_candidate returns the wrapped :class:EffectCandidate (provenance + inner effect); :attr:most_likely_effect returns just the inner :class:MutationEffect. Always equal to candidates[0] / effects[0].

  • Highest priority: top by varcode's effect-priority ordering (see :func:~varcode.effects.effect_priority) — the most protein-disruptive candidate regardless of producer order. :attr:highest_priority_candidate and :attr:highest_priority_effect are the analogous accessors. Use this for clinical / functional filtering ("flag if any candidate is at least a frameshift"), since a disruptive candidate sitting behind a less-disruptive primary candidate should still light up.

The two coincide when producer order and priority ranking agree, which is common but not guaranteed. Pick consciously.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant):
    self.variant = variant

effects property

Tuple of inner :class:MutationEffect objects, in :attr:candidates order. Convenience for callers that don't need per-candidate provenance — equivalent to tuple(c.effect for c in self.candidates).

most_likely_candidate property

The first :class:EffectCandidate in producer order. Pairs the inner effect with its source / evidence provenance.

For just the inner :class:MutationEffect, use :attr:most_likely_effect. For the most protein-disruptive candidate (independent of producer order), use :attr:highest_priority_candidate.

most_likely_effect property

The :class:MutationEffect of :attr:most_likely_candidate. Equivalent to most_likely_candidate.effect / effects[0] — given here so callers that don't need provenance don't have to reach through the wrapper.

highest_priority_candidate property

The :class:EffectCandidate whose inner effect has the highest :func:~varcode.effects.effect_priority (most protein-disruptive). Pure priority ranking — producer order deliberately doesn't factor in, so a frameshift sitting behind a less-disruptive primary candidate still surfaces here.

Ties on priority resolve to the first matching entry of :attr:candidates, preserving the subclass's candidate order.

Behavior is deterministic.

highest_priority_effect property

The inner :class:MutationEffect of :attr:highest_priority_candidate. Use when you want the worst-case effect for clinical / functional filtering and don't need provenance.

varcode.effects.effect_classes.Intragenic(variant, gene)

Bases: MutationEffect

Variant within boundaries of a gene but does not overlap introns or exons of any transcript. This seems very peculiar but apparently does happen sometimes, maybe some genes have two distinct sets of exons which are never simultaneously expressed?

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, gene):
    MutationEffect.__init__(self, variant)
    self.gene = gene

varcode.effects.effect_classes.TranscriptMutationEffect(variant, transcript)

Bases: Intragenic

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

varcode.effects.effect_classes.Exonic(variant, transcript)

Bases: TranscriptMutationEffect

Any mutation which affects the contents of an exon (coding region or UTRs)

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

varcode.effects.effect_classes.CodingMutation(variant, transcript)

Bases: Exonic

Base class for all mutations which result in a modified coding sequence.

Source code in varcode/effects/effect_classes.py
def __init__(self, variant, transcript):
    Intragenic.__init__(self, variant, gene=transcript.gene)
    self.transcript = transcript

varcode.effects.effect_classes.NonsilentCodingMutation(variant, transcript, aa_mutation_start_offset, aa_mutation_end_offset, aa_ref)

Bases: CodingMutation

All coding mutations other than silent codon substitutions

variant : Variant

transcript : Transcript

aa_mutation_start_offset : int Offset of first modified amino acid in protein (starting from 0)

aa_mutation_end_offset : int Offset after last mutated amino acid (half-open coordinates)

aa_ref : str Amino acid string of what used to be at aa_mutation_start_offset in the wildtype (unmutated) protein.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        aa_mutation_end_offset,
        aa_ref):
    """
    variant : Variant

    transcript : Transcript

    aa_mutation_start_offset : int
        Offset of first modified amino acid in protein (starting from 0)

    aa_mutation_end_offset : int
        Offset after last mutated amino acid (half-open coordinates)

    aa_ref : str
        Amino acid string of what used to be at aa_mutation_start_offset
        in the wildtype (unmutated) protein.
    """
    CodingMutation.__init__(
        self,
        variant=variant,
        transcript=transcript)
    self.aa_mutation_start_offset = aa_mutation_start_offset
    self.aa_mutation_end_offset = aa_mutation_end_offset
    self.aa_ref = bio_seq_to_str(aa_ref)

varcode.effects.effect_classes.KnownAminoAcidChange(variant, transcript, aa_mutation_start_offset, aa_ref, aa_alt)

Bases: NonsilentCodingMutation

Coding mutations in which we can predict what the new/mutant protein sequence will be.

Source code in varcode/effects/effect_classes.py
def __init__(
        self,
        variant,
        transcript,
        aa_mutation_start_offset,
        aa_ref,
        aa_alt):
    NonsilentCodingMutation.__init__(
        self,
        variant=variant,
        transcript=transcript,
        aa_mutation_start_offset=aa_mutation_start_offset,
        aa_mutation_end_offset=aa_mutation_start_offset + len(aa_alt),
        aa_ref=aa_ref)
    self.aa_alt = bio_seq_to_str(aa_alt)