Skip to content

Rename Outcome -> EffectCandidate; document purpose; drop description field - #381

Merged
iskandr merged 1 commit into
mainfrom
effect-candidate-rename
May 15, 2026
Merged

Rename Outcome -> EffectCandidate; document purpose; drop description field#381
iskandr merged 1 commit into
mainfrom
effect-candidate-rename

Conversation

@iskandr

@iskandr iskandr commented May 14, 2026

Copy link
Copy Markdown
Contributor

Re-creating PR #380, which auto-closed when its base branch (#379's generic-phasing-api) was deleted on merge. Rebased onto current main.

Summary

Three cleanups on the multi-outcome wrapper:

  1. Rename OutcomeEffectCandidate. The class wraps an Effect with provenance — "candidate effect with metadata" reads honestly. Module varcode.outcomesvarcode.effect_candidates; helper outcomes_from_candidatescandidates_from_effects; test file renamed in lockstep.

  2. Drop EffectCandidate.description. Pure passthrough to effect.short_description; producers wanting a richer narrative attach it to the underlying Effect, not the wrapper. make_rna_outcome(description=...) kwarg also removed.

  3. Module docstring explains why the wrapper exists. Previously framed as "minimal type for unifying multi-outcome shapes" with the actual rationale buried. Now leads with: the same MutationEffect instance can appear in multiple multi-outcome contexts with different metadata per context (e.g. a splice candidate re-surfaced by the SV annotator with a different source tag and sv_type in evidence). Without the wrapper, the alternatives are copy-everywhere, metadata-on-Effect (wrong: forces one labeling across contexts), or sidecar id() dicts. Documents that the wrapper is the cheapest answer.

Also: scrub aspirational "isovar" / "exacto" / "longread_assembly" example tags from varcode docstrings — those integrations don't exist yet; naming them as canonical examples implied a dependency that hadn't shipped.

What didn't change

  • MultiOutcomeEffect.candidates and .outcomes are kept as two complementary first-class accessors (raw tuple[MutationEffect, ...] vs wrapped tuple[EffectCandidate, ...]). The misleading "back-compat for 2.x" framing on .candidates is dropped — both serve distinct, legitimate needs.

    I tried collapsing to a single accessor (.candidates returning wrapped, .effects for raw) and reverted. The migration broke ~30 splice/RNA tests because SpliceOutcomeSet.candidates has deep history of returning SpliceCandidate (a different domain-specific type) and serialization round-trips depend on the shape. Collapsing requires either widespread test migration or back-compat shims that defeat the cleanup. Kept the pragmatic landing — documented sharply.

Test plan

  • pytest tests/ — 1188 pass, 2 pre-existing skips.
  • New test pins pytest.raises(TypeError) on the removed description= kwarg so it can't slip back via copy/paste.
  • tests/test_outcomes.pytests/test_effect_candidates.py (git rename + test method names updated test_outcome_*test_effect_candidate_*).
  • No remaining Outcome or outcomes_from_candidates references anywhere.
  • No "isovar" / "exacto" / "longread_assembly" strings in varcode source.

References

…tion

Three cleanups on the multi-outcome wrapper:

1. Rename ``Outcome`` -> ``EffectCandidate``. The class wraps an
   Effect with provenance — "candidate effect with metadata" reads
   honestly. Module ``varcode.outcomes`` -> ``varcode.effect_candidates``;
   helper ``outcomes_from_candidates`` -> ``candidates_from_effects``;
   test file renamed in lockstep.

2. Drop ``EffectCandidate.description``. Pure passthrough to
   ``effect.short_description``; producers wanting a richer
   narrative attach it to the underlying Effect, not the wrapper.
   ``make_rna_outcome(description=...)`` kwarg also removed.

3. Module docstring now explains *why* the wrapper exists rather
   than just describing it: the same MutationEffect instance can
   appear in multiple multi-outcome contexts with different metadata
   per context (e.g. a splice candidate re-surfaced by the SV
   annotator with a different source tag). Without the wrapper, the
   alternatives are copy-everywhere, metadata-on-Effect (wrong: forces
   one labeling across contexts), or sidecar id() dicts.

Also: scrub aspirational "isovar" / "exacto" / "longread_assembly"
example tags from varcode docstrings — those integrations don't
exist yet; naming them as canonical examples implied a dependency
that hadn't shipped.

Hard rename, no deprecation alias. The class was only exported as
varcode.Outcome — update imports to varcode.EffectCandidate. The
MultiOutcomeEffect.candidates / .outcomes dual access stays
(distinct, complementary; raw vs wrapped); the "back-compat" framing
on .candidates is dropped.

1188 tests pass.
@iskandr
iskandr merged commit 3187bb4 into main May 15, 2026
8 checks passed
@iskandr
iskandr deleted the effect-candidate-rename branch May 15, 2026 00:24
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.

1 participant