Repository: cogent3/cogent3
Pull request #2322 (2025-05-20 00:41:49)

Tweaks to plugin support code
## Summary by Sourcery

Add explicit error for missing quick_tree plugin and allow optional storage_backend in storage driver getters

Bug Fixes:
- Raise ValueError in get_quick_tree_hook when no matching plugin extension is found

Enhancements:
- Accept None for storage_backend parameter in get_unaligned_storage_driver and get_aligned_storage_driver

Tests:
- Remove invalid "not present" hook parameter and add test to verify error is raised for missing quick_tree hook


Patch:
diff --git a/src/cogent3/_plugin.py b/src/cogent3/_plugin.py
index 86a893303..e64bd5afe 100644
--- a/src/cogent3/_plugin.py
+++ b/src/cogent3/_plugin.py
@@ -44,11 +44,14 @@ def get_quick_tree_hook(
         name="quick_tree",
         invoke_on_load=False,
     )
-    if name != "cogent3":
+    if name and name != "cogent3":
         for extension in mgr.extensions:
             if name is None or extension.module_name.startswith(name):
                 return extension.plugin()
 
+        msg = f"Could not find quick_tree plugin for {name!r}"
+        raise ValueError(msg)
+
     return cogent3.get_app("quick_tree")
 
 
@@ -185,7 +188,7 @@ def _get_driver(namespace: str, storage_backend: str) -> stevedore.driver.Driver
 
 
 def get_unaligned_storage_driver(
-    storage_backend: str,
+    storage_backend: str | None,
 ) -> typing.Optional["SeqsDataABC"]:
     """returns unaligned sequence storage driver
 
@@ -205,7 +208,7 @@ ALIGNED_SEQ_STORAGE_ENTRY_POINT = "cogent3.storage.aligned_seqs"
 
 
 def get_aligned_storage_driver(
-    storage_backend: str,
+    storage_backend: str | None,
 ) -> typing.Optional["AlignedSeqsDataABC"]:
     """returns aligned sequence storage driver
 


Test patch:
diff --git a/tests/test_core/test_new_alignment.py b/tests/test_core/test_new_alignment.py
index deac7c830..0b0648317 100644
--- a/tests/test_core/test_new_alignment.py
+++ b/tests/test_core/test_new_alignment.py
@@ -4914,7 +4914,7 @@ def brca1_data():
 
 
 @pytest.mark.parametrize("calc", ["hamming", None])
-@pytest.mark.parametrize("use_hook", ["cogent3", None, "not present"])
+@pytest.mark.parametrize("use_hook", ["cogent3", None])
 def test_alignment_quick_tree(calc, brca1_data, use_hook):
     """quick tree method returns tree"""
     aln = new_alignment.make_aligned_seqs(brca1_data, moltype="dna")[:100]
@@ -4925,6 +4925,13 @@ def test_alignment_quick_tree(calc, brca1_data, use_hook):
     assert set(tree.get_tip_names()) == set(aln.names)
 
 
+def test_alignment_quick_tree_missing_hook(brca1_data):
+    aln = new_alignment.make_aligned_seqs(brca1_data, moltype="dna")[:100]
+    aln = aln.take_seqs(["Human", "Rhesus", "HowlerMon", "Galago", "Mouse"])
+    with pytest.raises(ValueError):
+        aln.quick_tree(use_hook="missing_hook")
+
+
 @pytest.mark.skipif(not has_piqtree, reason="piqtree not installed")
 def test_alignment_quick_tree_third_party_hook():
     """use piqtree as a third party hook"""
diff --git a/tests/test_evolve/test_distance.py b/tests/test_evolve/test_distance.py
index f26f0ccdb..1733c6a4b 100644
--- a/tests/test_evolve/test_distance.py
+++ b/tests/test_evolve/test_distance.py
@@ -854,7 +854,7 @@ def test_take_dists():
     assert_allclose(got1.array.astype(float), got2.array.astype(float))
 
 
-@pytest.mark.parametrize("use_hook", ["cogent3", None, "not present"])
+@pytest.mark.parametrize("use_hook", ["cogent3", None])
 def test_build_phylogeny(use_hook):
     """build a NJ tree"""
     from cogent3 import make_tree