From 56c582716acbd2de07415dc649b7d290fd27b144 Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Mon, 2 Nov 2026 20:10:34 -0500 Subject: [PATCH 1/4] Give duplicated test method names distinct names so both run Eleven test methods share a name with an earlier method in the same class, so Python keeps only the last definition and the earlier one never runs. The collected count goes from 1152 to 1161. Nine are renames of the MISNAMED definition, which the body makes unambiguous: - test_dataio_newick_reader_rooting.py, in all four interpreter classes: the first of each pair parses "&u" and is named ...ucase, while its neighbour parses "&U". Renamed to ...lcase, matching test_with_rooted_token_lcase already in each class. - test_datamodel_tree_structure_and_iteration.py: the second test_leaf_node_iter_filtered calls ageorder_node_iter and sits in the Age-Order section beside test_ageorder_node_iter_unfiltered. - test_datamodel_charmatrix.py: the second test_setitem_by_idx_not_in_namespace subscripts by LABEL and expects KeyError; the second test_fill_taxa calls pack(), in CharacterMatrixFillAndPackTestCase. - test_datamodel_tree_list.py: the second test_remove calls tlist.reverse(). - test_dataio_tokenizer.py: the second test_comments captures comments into a dict rather than skipping them. Two are deletions, where the surviving definition already covers the dead one: - test_phylogenetic_distance_matrix.py: the two bodies are identical. - test_datamodel_tree_construction_copying_and_identity.py: the dead one is a strict prefix of the one that runs. --- tests/unittests/test_dataio_newick_reader_rooting.py | 8 ++++---- tests/unittests/test_dataio_tokenizer.py | 2 +- tests/unittests/test_datamodel_charmatrix.py | 4 ++-- ...tamodel_tree_construction_copying_and_identity.py | 7 ------- tests/unittests/test_datamodel_tree_list.py | 2 +- .../test_datamodel_tree_structure_and_iteration.py | 2 +- tests/unittests/test_phylogenetic_distance_matrix.py | 12 ------------ 7 files changed, 9 insertions(+), 28 deletions(-) diff --git a/tests/unittests/test_dataio_newick_reader_rooting.py b/tests/unittests/test_dataio_newick_reader_rooting.py index 750e9227c..7574bf743 100644 --- a/tests/unittests/test_dataio_newick_reader_rooting.py +++ b/tests/unittests/test_dataio_newick_reader_rooting.py @@ -72,7 +72,7 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="force-unrooted") self.assertIs(nr._parse_tree_rooting_state("&R"), False) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_lcase(self): nr = newickreader.NewickReader(rooting="force-unrooted") self.assertIs(nr._parse_tree_rooting_state("&u"), False) @@ -102,7 +102,7 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="force-rooted") self.assertIs(nr._parse_tree_rooting_state("&R"), True) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_lcase(self): nr = newickreader.NewickReader(rooting="force-rooted") self.assertIs(nr._parse_tree_rooting_state("&u"), True) @@ -132,7 +132,7 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="default-unrooted") self.assertIs(nr._parse_tree_rooting_state("&R"), True) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_lcase(self): nr = newickreader.NewickReader(rooting="default-unrooted") self.assertIs(nr._parse_tree_rooting_state("&u"), False) @@ -162,7 +162,7 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="default-rooted") self.assertIs(nr._parse_tree_rooting_state("&R"), True) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_lcase(self): nr = newickreader.NewickReader(rooting="default-rooted") self.assertIs(nr._parse_tree_rooting_state("&u"), False) diff --git a/tests/unittests/test_dataio_tokenizer.py b/tests/unittests/test_dataio_tokenizer.py index 37a12e132..ccc413c14 100644 --- a/tests/unittests/test_dataio_tokenizer.py +++ b/tests/unittests/test_dataio_tokenizer.py @@ -117,7 +117,7 @@ def test_captured_delimiters(self): ] self.check_tokenization(input_str, expected) - def test_comments(self): + def test_capture_comments(self): input_str = "([the quick]apple[brown],([fox]banjo,([jumps]cucumber[over the],[really]dogwood)[lazy]eggplant)) rhubarb[dog];"; expected_comments = { "apple" : ["the quick", "brown"], diff --git a/tests/unittests/test_datamodel_charmatrix.py b/tests/unittests/test_datamodel_charmatrix.py index 6f7cb078e..f2320af8f 100644 --- a/tests/unittests/test_datamodel_charmatrix.py +++ b/tests/unittests/test_datamodel_charmatrix.py @@ -142,7 +142,7 @@ def test_setitem_by_idx_not_in_namespace(self): with self.assertRaises(IndexError): char_matrix[len(tns)] = [] - def test_setitem_by_idx_not_in_namespace(self): + def test_setitem_by_label_not_in_namespace(self): tns = get_taxon_namespace(3) char_matrix = charmatrixmodel.CharacterMatrix() with self.assertRaises(KeyError): @@ -301,7 +301,7 @@ def test_fill_taxa(self): for taxon in tns: self.assertIn(taxon, char_matrix) - def test_fill_taxa(self): + def test_pack(self): tns = get_taxon_namespace(5) char_matrix = charmatrixmodel.CharacterMatrix(taxon_namespace=tns) s = ["z"] * 10 diff --git a/tests/unittests/test_datamodel_tree_construction_copying_and_identity.py b/tests/unittests/test_datamodel_tree_construction_copying_and_identity.py index 023f85d96..3cfe78880 100644 --- a/tests/unittests/test_datamodel_tree_construction_copying_and_identity.py +++ b/tests/unittests/test_datamodel_tree_construction_copying_and_identity.py @@ -177,13 +177,6 @@ def test_construction_from_another_tree_different_label(self): self.assertNotEqual(tree1.label, "tree2") self.assertNotEqual(tree1.label, tree2.label) - def test_construction_from_given_seed_node(self): - tree1, anodes1, lnodes1, inodes1 = self.get_tree( - suppress_internal_node_taxa=False, - suppress_leaf_node_taxa=False) - tree2 = dendropy.Tree(seed_node=tree1.seed_node) - self.assertIs(tree2.seed_node, tree1.seed_node) - def test_construction_from_given_seed_node(self): tree1, anodes1, lnodes1, inodes1 = self.get_tree( suppress_internal_node_taxa=False, diff --git a/tests/unittests/test_datamodel_tree_list.py b/tests/unittests/test_datamodel_tree_list.py index 116bc3158..d79394b19 100644 --- a/tests/unittests/test_datamodel_tree_list.py +++ b/tests/unittests/test_datamodel_tree_list.py @@ -474,7 +474,7 @@ def test_remove(self): self.assertEqual(len(tlist), 4) self.assertNotIn(t, tlist) - def test_remove(self): + def test_reverse(self): tlist = curated_test_tree_list.get_tree_list(5) clist = list(tlist._trees) tlist.reverse() diff --git a/tests/unittests/test_datamodel_tree_structure_and_iteration.py b/tests/unittests/test_datamodel_tree_structure_and_iteration.py index 8fa301b27..1f38f2877 100644 --- a/tests/unittests/test_datamodel_tree_structure_and_iteration.py +++ b/tests/unittests/test_datamodel_tree_structure_and_iteration.py @@ -400,7 +400,7 @@ def test_ageorder_node_iter_unfiltered_reversed(self): exp = [x[1] for x in nda] self.assertSequenceEqual(visited_labels, exp) - def test_leaf_node_iter_filtered(self): + def test_ageorder_node_iter_filtered(self): tree, anodes, lnodes, inodes = self.get_tree() f = lambda x: x.edge.length > 13 nodes = [nd for nd in tree.ageorder_node_iter(filter_fn=f)] diff --git a/tests/unittests/test_phylogenetic_distance_matrix.py b/tests/unittests/test_phylogenetic_distance_matrix.py index 20f213588..f14ca65ed 100644 --- a/tests/unittests/test_phylogenetic_distance_matrix.py +++ b/tests/unittests/test_phylogenetic_distance_matrix.py @@ -265,18 +265,6 @@ def test_max_pairwise_weighted_distance_taxa(self): obs_maxt = self.pdm.max_pairwise_distance_taxa(is_weighted_edge_distances=True) self.assertEqual(set(obs_maxt), maxt) - def test_max_pairwise_weighted_distance_taxa(self): - maxd = None - maxt = None - for taxon1 in self.tree.taxon_namespace: - for taxon2 in self.tree.taxon_namespace: - d = self.reference_pdm_weighted_table[taxon1.label, taxon2.label] - if maxd is None or d > maxd: - maxd = d - maxt = set([taxon1, taxon2]) - obs_maxt = self.pdm.max_pairwise_distance_taxa(is_weighted_edge_distances=True) - self.assertEqual(set(obs_maxt), maxt) - def test_max_pairwise_unweighted_distance_taxa(self): maxd = None maxts = [] From aa6f27dda49a1238dd6c308611f8bb575339d9f1 Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Mon, 2 Nov 2026 21:50:00 -0500 Subject: [PATCH 2/4] Address review: Ucase naming, a clearer name, and the F811 lint rule - rooting tests: keep the "&u" tests as ...ucase and rename the "&U" twins to ...Ucase, as requested, instead of renaming the lowercase ones to lcase. - charmatrix: test_pack -> test_pack_pads_taxa_to_equal_length. - lint.sh: select F811, which is the rule that catches this whole class. Scoped to tests/unittests, since that tree is now clean. Enabling F811 surfaced three more in the same tree, fixed here: - a second `class TestCharacterMatrixTaxa` replaced the first, so its test_basic_taxa (poll_taxa coverage) never ran. The second one tests purging, so it is now TestCharacterMatrixPurgeTaxonNamespace. - five duplicate `import sys` / `import os` lines across four test modules. tests/unittests + tests/smoketests: 1152 collected before the branch, 1162 now, with the same four pre-existing failures either side. --- lint.sh | 7 +++++++ .../test_dataio_newick_reader_rooting.py | 16 ++++++++-------- .../unittests/test_dataio_newick_reader_tree.py | 2 -- .../test_dataio_newick_reader_tree_iter.py | 1 - .../test_dataio_newick_reader_tree_list.py | 1 - tests/unittests/test_datamodel_charmatrix.py | 4 ++-- tests/unittests/test_fitch.py | 1 - 7 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lint.sh b/lint.sh index ef3e86448..933213cdf 100755 --- a/lint.sh +++ b/lint.sh @@ -5,3 +5,10 @@ set -e # lint for Python syntax errors or undefined names\ ruff check --format=github --select=E9,F63,F7,F82,W605 --extend-exclude=docs/source/schemas/interfaces,src/dendropy/dataio/_beast2_v2_7_8_lark_standalone.py --target-version=py37 . + +# F811 reports a name redefined before use, which is what a duplicated test +# method or class name is: Python keeps the last definition and the earlier +# test silently stops running. Scoped to tests/unittests because that tree is +# clean; `ruff check --select=F811 .` currently reports 2 more under +# tests/smoketests and 7 under src/ that need their own decisions. +ruff check --format=github --select=F811 --target-version=py37 tests/unittests diff --git a/tests/unittests/test_dataio_newick_reader_rooting.py b/tests/unittests/test_dataio_newick_reader_rooting.py index 7574bf743..8ec30102e 100644 --- a/tests/unittests/test_dataio_newick_reader_rooting.py +++ b/tests/unittests/test_dataio_newick_reader_rooting.py @@ -72,11 +72,11 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="force-unrooted") self.assertIs(nr._parse_tree_rooting_state("&R"), False) - def test_with_unrooted_token_lcase(self): + def test_with_unrooted_token_ucase(self): nr = newickreader.NewickReader(rooting="force-unrooted") self.assertIs(nr._parse_tree_rooting_state("&u"), False) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_Ucase(self): nr = newickreader.NewickReader(rooting="force-unrooted") self.assertIs(nr._parse_tree_rooting_state("&U"), False) @@ -102,11 +102,11 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="force-rooted") self.assertIs(nr._parse_tree_rooting_state("&R"), True) - def test_with_unrooted_token_lcase(self): + def test_with_unrooted_token_ucase(self): nr = newickreader.NewickReader(rooting="force-rooted") self.assertIs(nr._parse_tree_rooting_state("&u"), True) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_Ucase(self): nr = newickreader.NewickReader(rooting="force-rooted") self.assertIs(nr._parse_tree_rooting_state("&U"), True) @@ -132,11 +132,11 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="default-unrooted") self.assertIs(nr._parse_tree_rooting_state("&R"), True) - def test_with_unrooted_token_lcase(self): + def test_with_unrooted_token_ucase(self): nr = newickreader.NewickReader(rooting="default-unrooted") self.assertIs(nr._parse_tree_rooting_state("&u"), False) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_Ucase(self): nr = newickreader.NewickReader(rooting="default-unrooted") self.assertIs(nr._parse_tree_rooting_state("&U"), False) @@ -162,11 +162,11 @@ def test_with_rooted_token_ucase(self): nr = newickreader.NewickReader(rooting="default-rooted") self.assertIs(nr._parse_tree_rooting_state("&R"), True) - def test_with_unrooted_token_lcase(self): + def test_with_unrooted_token_ucase(self): nr = newickreader.NewickReader(rooting="default-rooted") self.assertIs(nr._parse_tree_rooting_state("&u"), False) - def test_with_unrooted_token_ucase(self): + def test_with_unrooted_token_Ucase(self): nr = newickreader.NewickReader(rooting="default-rooted") self.assertIs(nr._parse_tree_rooting_state("&U"), False) diff --git a/tests/unittests/test_dataio_newick_reader_tree.py b/tests/unittests/test_dataio_newick_reader_tree.py index 6d3e8f57e..dccd633ec 100644 --- a/tests/unittests/test_dataio_newick_reader_tree.py +++ b/tests/unittests/test_dataio_newick_reader_tree.py @@ -29,8 +29,6 @@ import dendropy from dendropy.utility import error from dendropy.dataio import newickreader -import os -import sys sys.path.insert(0, os.path.dirname(__file__)) from support import dendropytest from support import standard_file_test_trees diff --git a/tests/unittests/test_dataio_newick_reader_tree_iter.py b/tests/unittests/test_dataio_newick_reader_tree_iter.py index cd6ccf104..2039c56ea 100644 --- a/tests/unittests/test_dataio_newick_reader_tree_iter.py +++ b/tests/unittests/test_dataio_newick_reader_tree_iter.py @@ -26,7 +26,6 @@ import unittest import dendropy import os -import sys sys.path.insert(0, os.path.dirname(__file__)) from support import dendropytest from support import standard_file_test_trees diff --git a/tests/unittests/test_dataio_newick_reader_tree_list.py b/tests/unittests/test_dataio_newick_reader_tree_list.py index 4e4a35560..77d6fafb5 100644 --- a/tests/unittests/test_dataio_newick_reader_tree_list.py +++ b/tests/unittests/test_dataio_newick_reader_tree_list.py @@ -26,7 +26,6 @@ import unittest import dendropy import os -import sys sys.path.insert(0, os.path.dirname(__file__)) from support import dendropytest from support import standard_file_test_trees diff --git a/tests/unittests/test_datamodel_charmatrix.py b/tests/unittests/test_datamodel_charmatrix.py index f2320af8f..2d1117e86 100644 --- a/tests/unittests/test_datamodel_charmatrix.py +++ b/tests/unittests/test_datamodel_charmatrix.py @@ -301,7 +301,7 @@ def test_fill_taxa(self): for taxon in tns: self.assertIn(taxon, char_matrix) - def test_pack(self): + def test_pack_pads_taxa_to_equal_length(self): tns = get_taxon_namespace(5) char_matrix = charmatrixmodel.CharacterMatrix(taxon_namespace=tns) s = ["z"] * 10 @@ -1151,7 +1151,7 @@ def setUp(self): def test_basic_taxa(self): self.assertEqual(self.char_matrix.poll_taxa(), self.expected_taxa) -class TestCharacterMatrixTaxa(dendropytest.ExtendedTestCase): +class TestCharacterMatrixPurgeTaxonNamespace(dendropytest.ExtendedTestCase): def setUp(self): self.char_matrix = charmatrixmodel.CharacterMatrix() diff --git a/tests/unittests/test_fitch.py b/tests/unittests/test_fitch.py index fd902df3e..736035ceb 100644 --- a/tests/unittests/test_fitch.py +++ b/tests/unittests/test_fitch.py @@ -27,7 +27,6 @@ import random import unittest import math -import sys import dendropy from dendropy.calculate.treescore import fitch_down_pass sys.path.insert(0, os.path.dirname(__file__)) From 99cf051e5d270ddca2886c419cd77ac1ce831a83 Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Mon, 2 Nov 2026 23:54:34 -0500 Subject: [PATCH 3/4] Cut the F811 comment to one line, matching the one above it --- lint.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lint.sh b/lint.sh index 933213cdf..780357a4a 100755 --- a/lint.sh +++ b/lint.sh @@ -6,9 +6,5 @@ set -e # lint for Python syntax errors or undefined names\ ruff check --format=github --select=E9,F63,F7,F82,W605 --extend-exclude=docs/source/schemas/interfaces,src/dendropy/dataio/_beast2_v2_7_8_lark_standalone.py --target-version=py37 . -# F811 reports a name redefined before use, which is what a duplicated test -# method or class name is: Python keeps the last definition and the earlier -# test silently stops running. Scoped to tests/unittests because that tree is -# clean; `ruff check --select=F811 .` currently reports 2 more under -# tests/smoketests and 7 under src/ that need their own decisions. +# lint for duplicated test names, which stop the earlier test running ruff check --format=github --select=F811 --target-version=py37 tests/unittests From 8ad33bacdd87520f256795e8c9524c92e057e0fe Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 3 Nov 2026 01:24:54 -0500 Subject: [PATCH 4/4] Apply suggestion from @mmore500 --- lint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lint.sh b/lint.sh index 780357a4a..8256e4f62 100755 --- a/lint.sh +++ b/lint.sh @@ -6,5 +6,5 @@ set -e # lint for Python syntax errors or undefined names\ ruff check --format=github --select=E9,F63,F7,F82,W605 --extend-exclude=docs/source/schemas/interfaces,src/dendropy/dataio/_beast2_v2_7_8_lark_standalone.py --target-version=py37 . -# lint for duplicated test names, which stop the earlier test running +# lint for duplicated test names, which discards tests ruff check --format=github --select=F811 --target-version=py37 tests/unittests