Skip to content

Commit e370c31

Browse files
committed
Patch RenumberTips
1 parent 0e041b3 commit e370c31

File tree

4 files changed

+42
-7
lines changed

4 files changed

+42
-7
lines changed

R/DropTip.R

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,11 @@ DropTip.list <- function(tree, tip, preorder = TRUE, check = TRUE) {
281281
if (all(vapply(tree, inherits, logical(1), "phylo"))) {
282282
DropTip.multiPhylo(tree, tip, preorder, check)
283283
} else {
284-
NextMethod()
284+
stop("Expected a list of `phylo` objects, but not all elements inherit ",
285+
"from \"phylo\".\n Classes found: ",
286+
paste(unique(vapply(tree, function(x) paste(class(x), collapse = "/"),
287+
character(1))),
288+
collapse = ", "))
285289
}
286290
}
287291

@@ -291,7 +295,11 @@ KeepTip.list <- function(tree, tip, preorder = TRUE, check = TRUE) {
291295
if (all(vapply(tree, inherits, logical(1), "phylo"))) {
292296
KeepTip.multiPhylo(tree, tip, preorder, check)
293297
} else {
294-
NextMethod()
298+
stop("Expected a list of `phylo` objects, but not all elements inherit ",
299+
"from \"phylo\".\n Classes found: ",
300+
paste(unique(vapply(tree, function(x) paste(class(x), collapse = "/"),
301+
character(1))),
302+
collapse = ", "))
295303
}
296304
}
297305

src/renumber_tips.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
using namespace Rcpp;
33

44
// Apply a precomputed tip permutation to every tree in batch.
5-
// Returns a plain list of modified phylo objects (shallow-cloned, with new
5+
// Returns a list of modified phylo objects (cloned, with new
66
// edge matrices, updated tip.label, and "preorder" downgraded to "cladewise").
7+
// Preserves the class attribute (typically "phylo") on each element.
78
// [[Rcpp::export]]
89
Rcpp::List renumber_tips_batch(
910
Rcpp::List trees,
@@ -15,10 +16,11 @@ Rcpp::List renumber_tips_batch(
1516
Rcpp::List result(n_trees);
1617

1718
for (int i = 0; i < n_trees; ++i) {
18-
// Shallow-clone the phylo list so other components are shared
19-
Rcpp::List tree_i = Rcpp::clone(
20-
Rcpp::as<Rcpp::List>(trees[i])
21-
);
19+
SEXP orig = trees[i];
20+
SEXP orig_class = Rf_getAttrib(orig, R_ClassSymbol);
21+
22+
// Clone the phylo list (as<List> may strip class; restored below)
23+
Rcpp::List tree_i = Rcpp::clone(Rcpp::as<Rcpp::List>(orig));
2224

2325
// Clone and permute the edge matrix
2426
Rcpp::IntegerMatrix edge = Rcpp::clone(
@@ -44,6 +46,12 @@ Rcpp::List renumber_tips_batch(
4446
}
4547
}
4648

49+
// Restore class last, after all modifications, to ensure it sticks.
50+
// Use Rf_setAttrib on the underlying SEXP to bypass Rcpp wrappers.
51+
if (orig_class != R_NilValue) {
52+
Rf_setAttrib(Rcpp::wrap(tree_i), R_ClassSymbol, orig_class);
53+
}
54+
4755
result[i] = tree_i;
4856
}
4957

tests/testthat/test-DropTip.R

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,9 @@ test_that("KeepTipPreorder()/Postorder()", {
250250
expect_equal(KeepTipPostorder(post, !logical(9)),
251251
post)
252252
})
253+
254+
test_that("DropTip.list / KeepTip.list error on non-phylo elements", {
255+
bad_list <- list(list(a = 1), list(b = 2))
256+
expect_error(DropTip(bad_list, "x"), "not all elements inherit")
257+
expect_error(KeepTip(bad_list, "x"), "not all elements inherit")
258+
})

tests/testthat/test-tree_numbering.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,19 @@ test_that("RenumberTips.multiPhylo() materializes tip.label", {
218218
expect_equal(result[[2]][["tip.label"]], labs)
219219
})
220220

221+
test_that("RenumberTips.multiPhylo() preserves phylo class on elements", {
222+
labs <- paste0("t", 1:6)
223+
mp <- structure(
224+
list(BalancedTree(6), PectinateTree(6)),
225+
TipLabel = labs,
226+
class = "multiPhylo"
227+
)
228+
result <- RenumberTips(mp, rev(labs))
229+
# Each element should retain class "phylo", not be downgraded to "list"
230+
expect_s3_class(.subset2(result, 1), "phylo")
231+
expect_s3_class(.subset2(result, 2), "phylo")
232+
})
233+
221234
test_that("RenumberTips.multiPhylo() handles unlabelled different orderings", {
222235
# Trees with different tip orderings in an unlabelled multiPhylo
223236
tree_abc <- read.tree(text = "(a, (b, c));")

0 commit comments

Comments
 (0)