Repository: cogent3/cogent3
Pull request #1344 (2023-04-03 06:51:58)

Misc patches

coveralls: ## Pull Request Test Coverage Report for [Build 4593751445](https://coveralls.io/builds/58492575)

* **0** of **0**   changed or added relevant lines in **0** files are covered.
* **45** unchanged lines in **3** files lost coverage.
* Overall coverage increased (+**0.09%**) to **91.528%**

---


|  Files with Coverage Reduction | New Missed Lines | % |
| :-----|--------------|--: |
| [.nox/test-3-10/Lib/site-packages/cogent3/maths/matrix_exponential_integration.py](https://coveralls.io/builds/58492575/source?filename=.nox%2Ftest-3-10%2FLib%2Fsite-packages%2Fcogent3%2Fmaths%2Fmatrix_exponential_integration.py#L93) | 1 | 92.98% |
| [.nox/test-3-10/Lib/site-packages/cogent3/maths/scipy_optimize.py](https://coveralls.io/builds/58492575/source?filename=.nox%2Ftest-3-10%2FLib%2Fsite-packages%2Fcogent3%2Fmaths%2Fscipy_optimize.py#L359) | 3 | 84.14% |
| [.nox/test-3-10/Lib/site-packages/cogent3/core/tree.py](https://coveralls.io/builds/58492575/source?filename=.nox%2Ftest-3-10%2FLib%2Fsite-packages%2Fcogent3%2Fcore%2Ftree.py#L1135) | 41 | 91.44% |
<!-- | **Total:** | **45** |  | -->

|  Totals | [![Coverage Status](https://coveralls.io/builds/58492575/badge)](https://coveralls.io/builds/58492575) |
| :-- | --: |
| Change from base [Build 4592247249](https://coveralls.io/builds/58487685): |  0.09% |
| Covered Lines: | 178206 |
| Relevant Lines: | 194702 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/changelog.d/20230324_161155_Gavin.Huttley.md b/changelog.d/20230324_161155_Gavin.Huttley.md
new file mode 100644
index 000000000..1300ddfd2
--- /dev/null
+++ b/changelog.d/20230324_161155_Gavin.Huttley.md
@@ -0,0 +1,41 @@
+<!--
+A new scriv changelog fragment.
+
+Uncomment the section that is right (remove the HTML comment wrapper).
+-->
+
+### Contributers
+
+-   AoboHill made their first contribution!
+-   pithirat-horvichien made their first contribution!
+
+<!--
+### ENH
+
+-   A bullet item for the ENH category.
+
+-->
+<!--
+### BUG
+
+-   A bullet item for the BUG category.
+
+-->
+<!--
+### DOC
+
+-   A bullet item for the DOC category.
+
+-->
+<!--
+### Deprecations
+
+-   A bullet item for the Deprecations category.
+
+-->
+<!--
+### Discontinued
+
+-   A bullet item for the Discontinued category.
+
+-->
diff --git a/pyproject.toml b/pyproject.toml
index 32fd7ad82..edb5df256 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -105,6 +105,7 @@ dev = ["black==21.12b",
        "pytest",
        "pytest-cov",
        "pytest-xdist",
+       "scriv",
        "sphinx",
        "sphinx-autobuild",
        "sphinx-gallery",
diff --git a/requirements.txt b/requirements.txt
index 7de8d0489..b3c835d04 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 chardet==5.1.0
-pillow==9.4.0
+pillow==9.5.0
 psutil==5.9.4
 numpy==1.24.2
 numba>0.48.0;python_version<'3.9'
@@ -7,6 +7,6 @@ numba>0.53; python_version>='3.9'
 numba>0.54; python_version>='3.10'
 scipy==1.10.1
 nox==2022.11.21
-plotly==5.13.1
+plotly==5.14.0
 typing_extensions>=3.7
 .[dev]
diff --git a/src/cogent3/core/tree.py b/src/cogent3/core/tree.py
index 2e605b411..0b64f2866 100644
--- a/src/cogent3/core/tree.py
+++ b/src/cogent3/core/tree.py
@@ -1070,13 +1070,8 @@ class TreeNode(object):
         """
         # linearize the tips in postorder.
         # .__start, .__stop compose the slice in tip_order.
-        if endpoints is None:
-            tip_order = list(self.tips())
-        else:
-            tip_order = []
-            for i, name in enumerate(endpoints):
-                node = self.get_node_matching_name(name)
-                tip_order.append(node)
+        tip_order = list(self.tips())
+
         for i, node in enumerate(tip_order):
             node.__start, node.__stop = i, i + 1
 
@@ -1114,8 +1109,19 @@ class TreeNode(object):
                 update_result()
 
         from_root = []
+        if endpoints is not None:
+            selected = {getattr(n, "name", n) for n in endpoints}
+            keys = list(result)
+            for a, b in keys:
+                if a in selected and b in selected:
+                    continue
+                result.pop((a, b))
+        else:
+            selected = {n.name for n in tip_order}
+
         for i, n in enumerate(tip_order):
-            from_root.append((n.name, tipdistances[i]))
+            if n.name in selected:
+                from_root.append((n.name, tipdistances[i]))
         return from_root, result
 
     def get_distances(self, endpoints=None):
@@ -2145,53 +2151,7 @@ class PhyloNode(TreeNode):
         """
         # linearize the tips in postorder.
         # .__start, .__stop compose the slice in tip_order.
-        if endpoints is None:
-            tip_order = list(self.tips())
-        else:
-            tip_order = []
-            for i, name in enumerate(endpoints):
-                node = self.get_node_matching_name(name)
-                tip_order.append(node)
-        for i, node in enumerate(tip_order):
-            node.__start, node.__stop = i, i + 1
-
-        num_tips = len(tip_order)
-        result = {}
-        # distances from tip to curr node
-        tipdistances = zeros((num_tips), float)
-
-        def update_result():
-            # set tip_tip distance between tips of different child
-            for child1, child2 in combinations(node.children, 2):
-                for tip1 in range(child1.__start, child1.__stop):
-                    for tip2 in range(child2.__start, child2.__stop):
-                        name1 = tip_order[tip1].name
-                        name2 = tip_order[tip2].name
-                        result[(name1, name2)] = tipdistances[tip1] + tipdistances[tip2]
-                        result[(name2, name1)] = tipdistances[tip1] + tipdistances[tip2]
-
-        for node in self.traverse(self_before=False, self_after=True):
-            if not node.children:
-                continue
-            # subtree with solved child wedges
-            starts, stops = [], []  # to calc ._start and ._stop for curr node
-            for child in node.children:
-                if hasattr(child, "length") and child.length is not None:
-                    child_len = child.length
-                else:
-                    child_len = 1  # default length
-                tipdistances[child.__start : child.__stop] += child_len
-                starts.append(child.__start)
-                stops.append(child.__stop)
-            node.__start, node.__stop = min(starts), max(stops)
-            # update result if nessessary
-            if len(node.children) > 1:  # not single child
-                update_result()
-
-        from_root = []
-        for i, n in enumerate(tip_order):
-            from_root.append((n.name, tipdistances[i]))
-        return from_root, result
+        return super()._get_distances(endpoints=endpoints)
 
     def get_distances(self, endpoints=None):
         """The distance matrix as a dictionary.


Test patch:
diff --git a/tests/test_core/test_tree.py b/tests/test_core/test_tree.py
index a0285f04b..5a4314fbd 100644
--- a/tests/test_core/test_tree.py
+++ b/tests/test_core/test_tree.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 """Tests of classes for dealing with trees and phylogeny.
 """
 import json
@@ -9,6 +8,8 @@ from copy import copy, deepcopy
 from tempfile import TemporaryDirectory
 from unittest import TestCase, main
 
+import pytest
+
 from numpy import array
 from numpy.testing import assert_allclose, assert_equal
 
@@ -2284,6 +2285,11 @@ class BigTreeSingleTests(TestTree):
         self.assertEqual(len(tips), 55)
 
 
-# run if called from command line
-if __name__ == "__main__":
-    main()
+@pytest.mark.parametrize("num_tips", (0, 3))
+def test_get_distances_endpoints(num_tips):
+    names = "G001280565", "G000009905", "G000183545", "G000184705"
+    nwk = "({}:0.4,({}:0.25,({}:0.03,{}:0.03):0.23):0.03)".format(*names)
+    tree = make_tree(nwk)
+    dists = tree.get_distances(endpoints=names[:num_tips] or None)
+    num = 4 if num_tips == 0 else num_tips
+    assert len(dists) == (num ** 2 - num)