Skip to content

Reference ORF consequences

Install varcode[orf] for the optional orfdata reference layer. PyEnsembl supplies reference transcripts, orfdata supplies ORF models and evidence, and Varcode compares those objects with altered products. This includes upstream and overlapping ORFs, internal/downstream frames, and ORFs on transcripts annotated as noncoding. The bundled catalogue is human GRCh38; explicit species-specific catalogues use the same API.

Annotate ordinary and extra ORFs together

Supply a catalogue to the usual effects API. Varcode finds the overlapping records and resolves their transcripts using the variant's genome:

from orfdata import load_catalog
from pyensembl import cached_release
from varcode import Variant

genome = cached_release(95)  # provision the reference before annotation
variant = Variant("7", 66205486, "C", "G", genome=genome)
effects = variant.effects(extra_orfs=load_catalog())
for annotation in effects.orf_annotations:
    print(annotation.orf_id, annotation.effect.short_description)
    for outcome in annotation.outcomes:
        if outcome.mutant is not None:
            print(outcome.mutant.protein_sequence)

This returns the ordinary UTR consequences alongside the p.P2A consequence in c7riboseqorf56. Omitting extra_orfs retains ordinary annotation without loading ORFdata. extra_orfs also accepts a bound reference ORF or an iterable of bound ORFs, including ORFdata collections; VariantCollection.effects(extra_orfs=...) reuses an iterable across all variants. Several ORFs on one RNA remain separate. No MS threshold is imposed by Varcode.

Added entries are ordinary Varcode effect classes and participate in collection sorting and filtering. Their effect.orf is the bound reference; effect.reference_transcript is its original PyEnsembl RNA. The existing engine uses a private coding view in effect.transcript; its ID distinguishes the ORF for candidate grouping. Public effect.transcript_id and collection grouping / expression lookups use the original RNA identity. effect.orf_annotation holds native products, source evidence, and initiation-context changes. effects.orf_annotations selects these detailed annotations in collection order, including failures. Export them with annotation.to_dict() when JSON is needed. Generic effect/collection JSON serialization rejects these entries because its schema cannot preserve their coding models. Dataframe/CSV summaries add orf_id, orf_source and orf_unresolved_reason; from_csv rejects ORF rows rather than recomputing them against the ordinary CDS. Full generic round trips are tracked in #593.

Bound inputs must match the variant genome's reference and annotation context. Catalogue records resolve against that genome and retain their source identities. Reference-scope mismatches raise even with raise_on_error=False; per-record binding/calculation errors raise by default and become Failure entries with orf_annotation.unresolved_reason when that flag is false. ORFdata collection exclusions overlapping the variant are reported in the same way.

The annotator argument selects ordinary transcript annotation. Extra ORFs reuse Varcode's existing transcript-model engine, including patient germline hypotheses and known-cis collection effects. DNA phase queries use the original RNA identity. Observed RNA outcomes for the ordinary CDS cannot be directly reused for an extra ORF: such observations raise or produce a Failure until explicitly mapped with annotate_orf_rna_product, described below. This interface does not discover new ORFs or infer IRES activity, and unsupported translation models remain explicit.

Work with a selected reference and its products

from pyensembl import cached_release
from orfdata import load_catalog
from varcode import Variant, annotate_orf_variants

genome = cached_release(95)  # explicitly provision this reference beforehand
transcript = genome.transcript_by_id("ENST00000304842")
catalog = load_catalog()
reference = catalog.get("c7riboseqorf56").bind(transcript)
variant = Variant("7", 66205486, "C", "G", genome=genome)
annotation = annotate_orf_variants([variant], reference)
assert annotation.reference is reference
for outcome in annotation.outcomes:
    print(outcome.effect)
    if outcome.mutant is not None:
        print(outcome.mutant.protein_sequence)
        print(outcome.mutant.initiation_context.start_codon)

Select a known ORF explicitly by ID as above. To annotate every ORF on a transcript, iterate over catalog.for_transcript(transcript); a transcript can have zero, one or several ORFs.

for reference in catalog.for_transcript(transcript):
    annotation = annotate_orf_variants([variant], reference)
    print(annotation.orf_id, annotation.effect)

The TPST1 +4 substitution is P2A in c7riboseqorf56 and changes an initiation context base. Canonical variant.effects() still reports its ordinary UTR consequence. variant.orf_effects() discovers overlapping reference models and reports unavailable/mismatched models as unresolved.

ReferenceORF.model holds the ORF identity, species, assembly, coding blocks and protein; .evidence holds source observations, and .transcript is the original PyEnsembl object. Varcode's ORFAnnotation.reference retains that base object; .effect and .outcomes describe modifications, including alternative phase/splice products. Each ORFOutcome carries native .effect, .hypothesis, .baseline and .mutant objects. Products expose sequences, termination and an orfdata InitiationContext directly. Unavailable structural products remain None with an .unresolved_reason; failed reference binding is reported by annotation.unresolved_reason. An empty outcome tuple does not prove no effect. Use annotation.to_dict() only when exporting JSON. A private coding view adapts this ORF to the existing transcript-model engine. It does not relabel a noncoding PyEnsembl transcript.

Binding checks the entire spliced path, protein, stop, assembly and available species identity. Literal genomic REF mismatches raise, including VCF padding. Sequence unavailable for intronic edits remains unresolved. The initial binder supports complete, stopped ORFs with NCBI translation table 1; other tables are explicitly unsupported, never inferred from an MT-like contig name.

For RNA products, annotate_orf_rna_product(reference, product) accepts a RealizedTranscriptProduct with one (contig, position, strand) or None in evidence['base_origins'] per cDNA base. It validates the retained reference start and compares the conditional translation with the base ORF. Its ORFProductAnnotation exposes .reference, .effect, .product, .status and .reason. An unresolved result retains the supplied .cdna_sequence and .evidence but has no translated .product. Isovar owns read support and RNA reconstruction; Varcode owns the sequence consequence.

Reference peptides are projected through codon ancestry, retaining every copied occurrence and identifying lost/altered peptides. Retention remains reference MS evidence, never mutant translation or MHC presentation evidence. All Sid TPST1–CRCP alternatives lack the native KIILSKISV peptide; each keeps its own RNA support and unresolved polarity/initiation status.

The compatibility module varcode.uorf preserves the original upstream-specific call shapes and varcode[uorf] remains an installation alias. New code should use varcode.orf and the bound reference API above. annotate_orf_product retains its original dictionary return for existing RNA exporters; new Python code should use annotate_orf_rna_product. ORFAnnotation.data remains an export alias; construct annotations with native fields rather than a data dictionary. The model catalogue is not exhaustive ORF discovery: new starts and downstream CDS regulation are unassessed.

Reference identity

The ORF extras require ORFdata 0.2. A bound ReferenceORF retains its species, strain, assembly, annotation version and sequence fingerprints in both native and modified-product exports. RNA product metadata must agree with that context. For custom Genomes without taxonomy, use record.bind(transcript, context=...) before calling the generic annotation API. The compatibility uORF wrappers also accept reference_context=.... See ORFdata's reference guide.