Skip to content

feat(annotator): let subclasses abort VCF annotation - #682

Open
NopeCharon wants to merge 1 commit into
ga4gh:mainfrom
NopeCharon:issue-605
Open

NopeCharon wants to merge 1 commit into
ga4gh:mainfrom
NopeCharon:issue-605

Conversation

@NopeCharon

Copy link
Copy Markdown

Closes #605.

Problem

AbstractVcfAnnotator.annotate() catches every exception raised while a record is processed, writes it to that record's VRS_Error INFO field and continues with the next record. That's correct for per-variant problems, but a child class can't signal an unrecoverable, global failure from on_vrs_object(). For example, AnyVar batch-inserts alleles in on_vrs_object(). If the database becomes unreachable, the annotator keeps iterating and retries the insert (and logs) on every following record.

Changes

  • Add VcfAnnotatorAbortError (a VcfAnnotatorError subclass). If it is raised while a record is processed, annotate() logs where it stopped and re-raises it instead of recording it in VRS_Error. The error then reaches the caller. Child classes can raise it directly, or chain a lower-level error with raise VcfAnnotatorAbortError(...) from e.
  • Close the input and output VCF files in a finally block, so an aborted run doesn't leave them open. A bgzipped output is finalized and can be read back. Most of the diff in annotate() is re-indentation from this; git diff -w shows the real change.
  • on_vrs_object_collection() (e.g. PKL/NDJSON dumps) does not run for an aborted annotation.
  • Document the error-handling behavior in the on_vrs_object() and annotate() docstrings.

Other exceptions behave as before.

Tests

Two tests in tests/extras/test_annotate_vcf.py use a small VcfAnnotator subclass that raises from on_vrs_object() at a chosen allele. Both reuse the existing test_annotate_vcf_rle.yaml cassette, since they annotate the same test_rle.vcf input:

  • test_annotate_vcf_record_error: a plain RuntimeError is still recorded in VRS_Error for that record, and annotation continues.
  • test_annotate_vcf_abort: VcfAnnotatorAbortError propagates out of annotate(). The PKL dump is not written, and the closed output VCF holds only the record annotated before the abort. This test fails without the change.

ruff check, ruff format --check and the full test suite (pytest --vcr-record=none, 204 passed) pass locally.

AbstractVcfAnnotator.annotate() catches every exception raised while
processing a record, writes it to that record's VRS_Error INFO field and
moves on to the next record. This is the right behavior for per-variant
problems, but leaves child classes no way to signal an unrecoverable,
global failure from hooks like on_vrs_object(). For example, an
implementation that batch-inserts alleles into a database keeps iterating
(and retrying the insert on every record) after the database goes away.

Add VcfAnnotatorAbortError, a VcfAnnotatorError subclass that annotate()
re-raises instead of recording, so annotation stops and the error reaches
the caller. The input and output VCF files are now closed in a finally
block so an aborted run doesn't leave them open, and the collection hook
(e.g. PKL/NDJSON dumps) is not run for an aborted annotation.

Closes ga4gh#605
@NopeCharon
NopeCharon requested review from a team as code owners October 31, 2026 16:44

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Subclass of AbstractVcfAnnotator can decide to abort annotation

1 participant