just_dna_enricher.civic_draft¶
just_dna_enricher.civic_draft ¶
Draft direction-axis rows from the CIViC snapshot (RM152).
The axis is direction, not clin_sig, and that is the whole reason this provider exists. S84
proposed CIViC as a clinical-significance authority and the measurement refused it: of CIViC's 3,103
germline evidence items, five carry an ACMG tier this format can receive and zero are benign-class,
so a clinical-significance disagreement is unsayable. What the same measurement found is 1,458 germline
items on Predisposition/Protectiveness — this format's direction (risk/protective). RM152
rejected a drafter partly because it would "write rows whose significance column is empty"; that is
true of clin_sig, where 812 germline items are NA, and false of direction, where the NA
count is zero. The rejection was measured on the axis the report aimed at rather than the one that
survives, which is why this provider is that one.
A flag on the existing command, never a second command — draft-panel --source civic, the shape
--source pubmind set. A separate command is for a provider writing different tables; this writes
the ones every panel draft writes.
It reads the snapshot and never the network. civic build pins a dated release; this reads its
parquet. That keeps the acquisition gate where it belongs and means a draft is reproducible from a
named dataset rather than from whatever the API served that afternoon (@currency-asks-the-source-not-the-cache).
The skip guard is derived from VariantRow, never restated beside it. This is a recorded scar:
pgx_draft restated the rule as "no rsID and no position" while the model wants rsID or
chrom+start, and draft --gene CYP2C9 died on an unhandled pydantic error. CIViC supplies a live
example of the shape that kills a restated guard — variant 1770 carries a build and a start and a
referenceBases with no chromosome, which passes any "has a position?" test and is not a position.
So the guard here asks the model, and the model's refusal is the answer.
A contested variant is withheld, never resolved. Where CIViC's own evidence puts a variant in both
camps, picking one is mode() over an unsorted group. The rows stay in the snapshot, the variant gets
no drafted row, and the count is reported.
Every excluded row is counted in the RESULT, not in this docstring. That was the reporter's own objection to a drafter and it is correct: a filter whose scope is narrower than its name hides what it removed. The snapshot already counted the somatic majority; this counts what it withholds on top.
CivicDraftError ¶
Bases: RuntimeError
The draft cannot run: no snapshot, or one that is present and will not answer.
CivicDraftResult
dataclass
¶
CivicDraftResult(
reports: list[DraftReport] = list(),
warnings: list[str] = list(),
withheld: dict[str, int] = dict(),
candidates: int = 0,
caid_resolved_by_rsid: int = 0,
caid_resolved_by_coordinate: int = 0,
caid_anchored_indels: int = 0,
dataset: str | None = None,
skipped: bool = False,
refuted_beside_claim: list[
tuple[str, str, str]
] = list(),
refutation_basis: str | None = None,
)
What a CIViC draft did — and, in equal detail, what it did not write.
added
property
¶
Rows added across every table this run wrote — variants and their studies.
outcome_for ¶
How many variants.csv rows landed in one outcome — added, already_present, invalid.
Source code in enricher/src/just_dna_enricher/civic_draft.py
accounts_for_every_candidate ¶
Every admitted row is either drafted, already there, refused, or withheld by name.
An equality, not a floor. A provider that quietly drops a row it cannot handle looks exactly
like one with nothing to say about it, and the difference is the whole of what a drafted
module's author needs to know. invalid is inside the sum rather than outside it: a row the
table refused is still a row this pass has to account for.
Source code in enricher/src/just_dna_enricher/civic_draft.py
civic_dataset_label ¶
The snapshot's dataset, or None when there is no snapshot or it names none.
None is an unknown release, never a fabricated one — the same answer the sibling labels give.
Source code in enricher/src/just_dna_enricher/civic_draft.py
identity_refused_by_model ¶
None when VariantRow accepts these identity cells, else the model's own complaint.
Thin wrapper over drafting.identity_refused_by_model, kept because this name is what the
withheld-reason vocabulary and this module's tests both use. The implementation moved to the
scaffold in RM228, and with it went the message parsing: this function used to branch on
"identifier" in message or "positional" in message or "chrom" in message, consuming pydantic's
rendered text as an API — a string that moves on a dependency bump with nothing to notice. The
probe now pre-fills every non-identity field with values the model is known to accept, so any
ValidationError reaching it is an identity refusal and no inspection is needed.
Source code in enricher/src/just_dna_enricher/civic_draft.py
trait_curie ¶
CIViC's bare Disease Ontology number as an ontology CURIE, or None.
trait_efo_id is not an EFO-only column, and reading the name as though it were is a mistake
this provider made once. The field takes any ontology CURIE — its own description says
"EFO/MONDO/OBA/HP", the validator accepts any PREFIX:LOCAL token, and cells are multi-valued —
so DOID:1612 belongs in it. The first version of this provider put the DOID in conclusion
prose instead, reasoning that a DOID in an EFO column would be a wrong identifier; the premise was
false, and the effect was to bury a structured id nothing could join on. Every CIViC germline
direction row carries a DOID, so the cost was the whole column.
CIViC publishes the number bare (1612), which is not a CURIE; the prefix is added here rather
than stored upstream, because a bare integer in this column would fail the validator and a reader
cannot tell which ontology it came from.
Source code in enricher/src/just_dna_enricher/civic_draft.py
draft_panel_from_civic ¶
draft_panel_from_civic(
spec_dir: Path,
genes: Sequence[str] = (),
*,
snapshot: Path | None = None,
declared_use: str = "unstated",
offline: bool = False,
registry: ClingenAlleleClient | None = None,
dry_run: bool = False,
) -> CivicDraftResult
Append direction-axis rows from the CIViC snapshot, with everything withheld accounted for.
genes filters; empty drafts every variant in the snapshot. The gene filter is applied first and
counted separately from the withholding, because "CIViC has nothing for this gene" and "CIViC has
something and we would not write it" are different answers an author needs told apart.
The counts land on the result, never only in a log line. The snapshot already recorded the
somatic majority it dropped; this records what it withheld on top, and
accounts_for_every_candidate() is an equality over both.
Source code in enricher/src/just_dna_enricher/civic_draft.py
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | |