Skip to content

Commit c4d652b

Browse files
committed
More prepping for release
1 parent b2c9942 commit c4d652b

14 files changed

Lines changed: 160 additions & 83 deletions

RcppTskit/DESCRIPTION

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ Authors@R: c(
99
person("Tskit Developers", role = "cph",
1010
comment = "Authors of included tskit C library")
1111
)
12-
Description: `Tskit` enables performant storage, manipulation, and
12+
Description: 'Tskit' enables performant storage, manipulation, and
1313
analysis of ancestral recombination graphs (ARGs) using succinct tree
14-
sequence encoding. See https://tskit.dev for project news,
15-
documentation, and tutorials. `Tskit` provides Python, C, and Rust
14+
sequence encoding. See <https://tskit.dev> for project news,
15+
documentation, and tutorials. 'Tskit' provides Python, C, and Rust
1616
application programming interfaces (APIs). The Python API can be
17-
called from R via the `reticulate` R package to seamlessly load and
17+
called from R via the 'reticulate' R package to seamlessly load and
1818
analyse a tree sequence as described at
19-
https://tskit.dev/tutorials/tskitr.html. `RcppTskit` provides R
20-
access to the `tskit` C API for use cases where the `reticulate`
19+
<https://tskit.dev/tutorials/tskitr.html>. 'RcppTskit' provides R
20+
access to the 'tskit' C API for use cases where the 'reticulate'
2121
option is not optimal. For example, for high-performance and low-level
22-
work with tree sequences. Currently, `RcppTskit` provides a limited
22+
work with tree sequences. Currently, 'RcppTskit' provides a limited
2323
number of R functions due to the availability of extensive Python API
24-
and the `reticulate` option.
24+
and the 'reticulate' option.
2525
License: MIT + file LICENSE
2626
URL: https://github.com/HighlanderLab/RcppTskit
2727
BugReports: https://github.com/HighlanderLab/RcppTskit/issues

RcppTskit/NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Generated by roxygen2: do not edit by hand
22

33
export(TreeSequence)
4+
export(check_tskit_py)
45
export(get_tskit_py)
56
export(kastore_version)
67
export(ts_load)

RcppTskit/R/Class-TreeSequence.R

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,14 @@ TreeSequence <- R6Class(
106106
#' ts_r$num_samples() # 160
107107
#'
108108
#' # Transfer the tree sequence to reticulate Python and use tskit Python API
109-
#' ts_py <- ts_r$r_to_py()
110-
#' is(ts_py)
111-
#' ts_py$num_samples # 160
112-
#' ts2_py <- ts_py$simplify(samples = c(0L, 1L, 2L, 3L))
113-
#' ts2_py$num_samples # 4
109+
#' tskit <- get_tskit_py()
110+
#' if (check_tskit_py(tskit)) {
111+
#' ts_py <- ts_r$r_to_py()
112+
#' is(ts_py)
113+
#' ts_py$num_samples # 160
114+
#' ts2_py <- ts_py$simplify(samples = c(0L, 1L, 2L, 3L))
115+
#' ts2_py$num_samples # 4
116+
#' }
114117
r_to_py = function(tskit_module = get_tskit_py(), cleanup = TRUE) {
115118
ts_r_to_py_ptr(
116119
self$pointer,

RcppTskit/R/RcppTskit.R

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,41 @@
33
#' @title Get the reticulate Python tskit module
44
#' @description This function imports the reticulate Python \code{tskit} module
55
#' and if it is not yet installed, then it attempts to install it first.
6-
#' @param obj_name character name of the object holding \code{tskit} reticulate
6+
#' @param object_name character name of the object holding \code{tskit} reticulate
77
#' Python module. If this object exists in the global R environment and is a
88
#' reticulate Python object, then it is returned. Otherwise, the function
99
#' attempts to install and import tskit before returning it. If \code{NULL},
1010
#' then the function directly attempts to install and import tskit before
1111
#' returning it.
12+
#' @param object reticulate Python module object, hopefully.
13+
#' @param stop logical for throwing an error in \code{check_tskit_py}.
1214
#' @details This function is meant for users running \code{tskit <- get_tskit_py()}
1315
#' or similar code, but also by other functions in this package that need the
1416
#' \code{tskit} reticulate Python module. The point of \code{get_tskit_py} is
1517
#' to avoid importing the module repeatedly, if it has been imported already.
16-
#' @return \code{tskit} reticulate Python module.
18+
#' @return \code{get_tskit_py} returns \code{tskit} reticulate Python module.
19+
#' \code{check_tskit_py} returns \code{TRUE} if
1720
#' @examples
1821
#' tskit <- get_tskit_py()
1922
#' is(tskit)
20-
#' tskit$ALLELES_01
23+
#' if (check_tskit_py(tskit)) {
24+
#' tskit$ALLELES_01
25+
#' }
2126
#' @export
22-
get_tskit_py <- function(obj_name = "tskit") {
23-
test <- !is.null(obj_name) &&
24-
exists(obj_name, envir = .GlobalEnv, inherits = FALSE)
27+
get_tskit_py <- function(object_name = "tskit") {
28+
test <- !is.null(object_name) &&
29+
exists(object_name, envir = .GlobalEnv, inherits = FALSE)
2530
if (test) {
26-
tskit <- get(obj_name, envir = .GlobalEnv, inherits = FALSE)
31+
tskit <- get(object_name, envir = .GlobalEnv, inherits = FALSE)
2732
test <- reticulate::is_py_object(tskit) &&
2833
is(tskit) == "python.builtin.module"
2934
if (test) {
3035
return(tskit)
3136
} else {
3237
txt <- paste0(
3338
"Object '",
34-
obj_name,
35-
"' exists in the global environment but is not a reticulate Python module"
39+
object_name,
40+
"' exists in the global environment but is not a reticulate Python module!"
3641
)
3742
stop(txt)
3843
}
@@ -42,13 +47,31 @@ get_tskit_py <- function(obj_name = "tskit") {
4247
# nocov start
4348
if (!reticulate::py_module_available("tskit")) {
4449
txt <- "Python module 'tskit' is not available. Attempting to install it ..."
45-
cat(txt)
50+
message(txt)
4651
reticulate::py_require("tskit")
4752
}
4853
# nocov end
4954
return(reticulate::import("tskit", delay_load = TRUE))
5055
}
5156

57+
#' @describeIn get_tskit_py Test if \code{get_tskit_py} returned a reticulate Python module object
58+
#' @export
59+
check_tskit_py <- function(object, stop = FALSE) {
60+
test <- reticulate::is_py_object(object) &&
61+
("python.builtin.module" %in% is(object))
62+
if (test) {
63+
return(TRUE)
64+
} else {
65+
msg <- "object must be a reticulate Python module object!"
66+
if (stop) {
67+
stop(msg)
68+
} else {
69+
message(msg)
70+
}
71+
return(FALSE)
72+
}
73+
}
74+
5275
#' @title Load a tree sequence from a file
5376
#' @param file a string specifying the full path of the tree sequence file.
5477
#' @param options integer bitwise options (see details at
@@ -182,9 +205,7 @@ ts_r_to_py_ptr <- function(ts, tskit_module = get_tskit_py(), cleanup = TRUE) {
182205
if (!is(ts, "externalptr")) {
183206
stop("ts must be an object of externalptr class!")
184207
}
185-
if (!reticulate::is_py_object(tskit_module)) {
186-
stop("tskit_module must be a reticulate Python module object!")
187-
}
208+
check_tskit_py(tskit_module, stop = TRUE)
188209
ts_file <- tempfile(fileext = ".trees")
189210
if (cleanup) {
190211
on.exit(file.remove(ts_file))
@@ -247,16 +268,18 @@ ts_py_to_r_ptr <- function(ts, cleanup = TRUE) {
247268
#'
248269
#' # Use the tskit Python API to work with a tree sequence (via reticulate)
249270
#' tskit <- get_tskit_py()
250-
#' ts_py <- tskit$load(ts_file)
251-
#' is(ts_py)
252-
#' ts_py$num_samples # 160
253-
#' ts2_py <- ts_py$simplify(samples = c(0L, 1L, 2L, 3L))
254-
#' ts2_py$num_samples # 4
271+
#' if (check_tskit_py(tskit)) {
272+
#' ts_py <- tskit$load(ts_file)
273+
#' is(ts_py)
274+
#' ts_py$num_samples # 160
275+
#' ts2_py <- ts_py$simplify(samples = c(0L, 1L, 2L, 3L))
276+
#' ts2_py$num_samples # 4
255277
#'
256-
#' # Transfer the tree sequence to R and use RcppTskit
257-
#' ts2_r <- ts_py_to_r(ts2_py)
258-
#' is(ts2_r)
259-
#' ts2_r$num_samples() # 4
278+
#' # Transfer the tree sequence to R and use RcppTskit
279+
#' ts2_r <- ts_py_to_r(ts2_py)
280+
#' is(ts2_r)
281+
#' ts2_r$num_samples() # 4
282+
#' }
260283
#' @export
261284
ts_py_to_r <- function(ts, cleanup = TRUE) {
262285
ptr <- ts_py_to_r_ptr(ts = ts, cleanup = cleanup)

RcppTskit/man/TreeSequence.Rd

Lines changed: 16 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RcppTskit/man/get_tskit_py.Rd

Lines changed: 19 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RcppTskit/man/ts_py_to_r.Rd

Lines changed: 11 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RcppTskit/notes_pkg_dev.Rmd

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
## Next TODOs
44

5+
# TODO: Create a minimal package to demonstrate how to link against RcppTskit and call tskit C API
6+
https://github.com/HighlanderLab/RcppTskit/issues/48
7+
8+
9+
510
TODO: Add citation for tskit to DESCRIPTION file #46
611
https://github.com/HighlanderLab/RcppTskit/issues/46
712

8-
# TODO: Create a minimal package to demonstrate how to link against RcppTskit and call tskit C API
9-
1013
# Release (TODO)
1114
# TODO: Tag a release #15
1215
# https://github.com/HighlanderLab/RcppTskit/issues/15

RcppTskit/tests/testthat/test_TreeSequence.R

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
context("TreeSequence$new()")
2-
31
test_that("TreeSequence$new() works", {
42
ts_file <- system.file("examples/test.trees", package = "RcppTskit")
53
expect_error(TreeSequence$new(), regexp = "Provide a file name or a pointer!")

RcppTskit/tests/testthat/test_get_tskit_py.R

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
context("get_tskit_py()")
2-
31
test_that("get_tskit_py() works", {
42
# Testing that get_tskit_py() fails with a non-module object
53
# Next two lines ensure that testthat is looking into the global environment
64
# as is get_tskit_py()
75
assign("rubbish", "something_else_than_a_py_module", envir = .GlobalEnv)
86
on.exit(rm("rubbish", envir = .GlobalEnv), add = TRUE)
97
expect_error(
10-
get_tskit_py(obj_name = "rubbish"),
8+
get_tskit_py(object_name = "rubbish"),
119
regexp = "Object 'rubbish' exists in the global environment but is not a reticulate Python module"
1210
)
1311

@@ -42,9 +40,40 @@ test_that("get_tskit_py() works", {
4240
expect_equal(tskit$`__name__`, tskit2$`__name__`)
4341

4442
# Re-importing
45-
tskit3 <- get_tskit_py(obj_name = NULL)
43+
tskit3 <- get_tskit_py(object_name = NULL)
4644
# lobstr::obj_addr(tskit3)
4745
# "0x161ec00f0" --> different address because we are obtaining a new object
4846
# but it is still the same module
4947
expect_equal(tskit$`__name__`, tskit3$`__name__`)
5048
})
49+
50+
test_that("check_tskit_py() validates python module objects", {
51+
expect_message(
52+
expect_false(check_tskit_py(1)),
53+
"object must be a reticulate Python module object!"
54+
)
55+
expect_error(
56+
check_tskit_py(1, stop = TRUE),
57+
"object must be a reticulate Python module object!"
58+
)
59+
60+
if (!reticulate::py_available(initialize = FALSE)) {
61+
skip("Python not available for reticulate tests.")
62+
}
63+
64+
obj <- reticulate::py_eval("1")
65+
expect_message(
66+
expect_false(check_tskit_py(obj)),
67+
"object must be a reticulate Python module object"
68+
)
69+
70+
sys <- reticulate::import("sys")
71+
expect_silent(expect_true(check_tskit_py(sys)))
72+
73+
if (reticulate::py_module_available("tskit")) {
74+
tskit <- get_tskit_py()
75+
expect_true(check_tskit_py(tskit))
76+
} else {
77+
skip("tskit module not available for reticulate tests.")
78+
}
79+
})

0 commit comments

Comments
 (0)