fix: default BUSCO lineage when predict cannot resolve taxonomy - #94
Merged
nextgenusfs merged 1 commit intoAug 24, 2026
Merged
Conversation
`funannotate2 predict` crashed with "AttributeError: 'bool' object has no
attribute 'get'" when neither the JGI taxonomy lookup nor the training-data
fallback yielded a taxonomy (e.g. a novel/unpublished organism, or offline).
Separately, for a non-empty taxonomy that matched nothing in busco_taxonomy it
selected a *random* BUSCO lineage: best_taxonomy() falls back to
random.choice(), and that pick is always itself a valid key, so a
"result not in busco_taxonomy" check can never catch it.
Add busco_lineage_from_taxonomy() in utilities.py, which resolves a valid
lineage deterministically: it returns the default unless the taxonomy genuinely
overlaps the BUSCO reference on superkingdom/kingdom, and otherwise returns the
matched lineage. Route predict() through it, defaulting to the "fungi" lineage
and logging a clear warning (naming the species) whenever taxonomy can't be
resolved. Also harden the offline branch to use params.get("taxonomy") so a
legacy params file without the key no longer KeyErrors before the guard runs.
Adds regression, determinism (per-kingdom invariant), and edge-case
(non-string / partial / exact-match) tests in test_utilities_taxonomy.py.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #93.
funannotate2 predictaborts withAttributeError: 'bool' object has no attribute 'get'when no taxonomy is available for the species:lookup_taxonomy()returnsFalseon any JGI API failure (offline, 5xx, unrecognized name), and the training-data fallbackparams["taxonomy"]is alsoFalsefor a novel/unpublished organism. The crash lands at the BUSCO-lineage selection step — after the ab initio predictions have already run — so a long run is lost to a late failure on exactly the "taxonomy unavailable" case.While fixing this I also found a latent, separate issue on the same path: for a non-empty taxonomy that matches nothing in
busco_taxonomy,best_taxonomy()falls through torandom.choice(), so a random (but valid) BUSCO lineage is selected non-deterministically — and because the pick is always a valid key, aresult in busco_taxonomycheck can't catch it.What this does
busco_lineage_from_taxonomy()inutilities.py— a small pure helper that resolves a valid lineage deterministically. It returns a default (fungi) unless the taxonomy genuinely overlaps the reference on superkingdom/kingdom, and otherwise returns the matched lineage. This closes both the crash and the random-lineage path.predict()through the helper, defaulting to thefungilineage and logging a clear warning that names the species and flags that a generic lineage is unreliable for a non-fungal genome (there is no--busco-lineage/--taxonomyoverride onpredict, so it self-heals rather than aborting).params.get("taxonomy"), so a params file that predates thetaxonomykey no longerKeyErrors before the guard runs.Tests
Adds regression, determinism, and edge-case coverage in
tests/unit/test_utilities_taxonomy.py: the#93crash inputs (False/None), a per-kingdom determinism invariant (so a futurebusco_taxonomyedit can't silently reintroduce the random tie-break), and non-string / partial / exact-match cases. All taxonomy unit tests pass locally.Note — possible follow-up
I scoped this PR to
predictto match the issue. The same "taxonomy can beFalse" pattern also reacheschoose_best_busco_species()inannotate.pyandtrain.py(andchoose_best_augustus_species()intrain.py), sofunannotate2 annotate/traincan hit the same crash class on their default (no--busco-lineage/--augustus-species) path. Happy to send a focused follow-up routing those call sites through the same helper if you'd like it — kept out of this PR to keep it reviewable.🤖 Generated with Claude Code