Skip to content

Commit

Permalink
dill caching engine for knitr, with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tmastny committed Apr 18, 2018
1 parent b52ecaa commit c345ce2
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 31 deletions.
60 changes: 29 additions & 31 deletions R/knitr-engine.R
Original file line number Diff line number Diff line change
Expand Up @@ -189,16 +189,14 @@ eng_python_initialize <- function(options, context, envir) {
use_python(options$engine.path[[1]])

if (options$cache > 0) {
load_module <- tryCatch(
import("dill"),
error = function(c) {
py_error <- py_last_error()
if(py_error$type == "ImportError" && py_error$value == "No module named dill") {
warning("The Python module dill was not found. This module is needed for full cache functionality.")
"No dill"
}})
if (load_module != "No dill")
py_run_string("import dill")
module <- tryCatch(import("dill"), error = identity)
if (inherits(module, "error")) {
if (module$message == "ImportError: No module named dill") {
warning("The Python module dill was not found. This module is needed for full cache functionality.")
} else {
stop(module$message)
}
}
}
eng_python_initialize_matplotlib(options, context, envir)
}
Expand Down Expand Up @@ -292,18 +290,20 @@ eng_python_wrap <- function(outputs, options) {
}

save_python_session <- function(cache_path) {
dill <- tryCatch(
import("dill"),
error = function(c) {
py_error <- py_last_error()
if(py_error$type == "ImportError" && py_error$value == "No module named dill") {
"No dill"
}})
if (dill == "No dill") return()

py_run_string("globals().pop('r')")
py_run_string("globals().pop('R')")
dill$dump_session(filename = paste0(cache_path, ".pkl"), byref = TRUE)
module <- tryCatch(import("dill"), error = identity)
if (inherits(module, "error")) {
if (module$message == "ImportError: No module named dill") return()
signalCondition(module$message)
}

r_objs_exist <- "all(r_obj in globals() for r_obj in ('r', 'R'))"
r_is_R <- "isinstance(r, R)"
if (py_eval(r_objs_exist) && py_eval(r_is_R)) {
py_run_string("globals().pop('r')")
py_run_string("globals().pop('R')")
}

module$dump_session(filename = paste0(cache_path, ".pkl"), byref = TRUE)
}

#' A reticulate cache engine for Knitr
Expand All @@ -327,15 +327,13 @@ save_python_session <- function(cache_path) {
#'
#' @export
cache_eng_python <- function(cache_path) {
dill <- tryCatch(
import("dill"),
error = function(c) {
py_error <- py_last_error()
if(py_error$type == "ImportError" && py_error$value == "No module named dill") {
"No dill"
}})
if (dill == "No dill") return()
dill$load_session(filename = paste0(cache_path, ".pkl"))
module <- tryCatch(import("dill"), error = identity)
if (inherits(module, "error")) {
if (module$message == "ImportError: No module named dill") return()
stop(module$message)
}

module$load_session(filename = paste0(cache_path, ".pkl"))
}


60 changes: 60 additions & 0 deletions R/python.R
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,66 @@ summary.python.builtin.object <- function(object, ...) {
str(object)
}


#' Convert between Python and R objects
#'
#' @inheritParams import
#' @param x Object to convert
#'
#' @return Converted object
#'
#' @name r-py-conversion
#' @export
py_to_r <- function(x) {

ensure_python_initialized()

if (!inherits(x, "python.builtin.object"))
stop("Object to convert is not a Python object")

# get the default wrapper
x <- py_ref_to_r(x)

# allow customization of the wrapper
wrapper <- py_to_r_wrapper(x)
attributes(wrapper) <- attributes(x)

# return the wrapper
wrapper
}

#' R wrapper for Python objects
#'
#' S3 method to create a custom R wrapper for a Python object.
#' The default wrapper is either an R environment or an R function
#' (for callable python objects).
#'
#' @param x Python object
#'
#' @export
py_to_r_wrapper <- function(x) {
UseMethod("py_to_r_wrapper")
}

#' @export
py_to_r_wrapper.default <- function(x) {
x
}





#' @rdname r-py-conversion
#' @export
r_to_py <- function(x, convert = FALSE) {

ensure_python_initialized()

r_to_py_impl(x, convert = convert)
}


#' @export
`$.python.builtin.module` <- function(x, name) {

Expand Down
2 changes: 2 additions & 0 deletions tests/testthat/test-python-cache-engine.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ test_that("An R Markdown document can be rendered with cache using reticulate",
skip_if_not_installed("rmarkdown")
skip_if_not_installed("callr")

unlink("resources/eng-reticulate-cache-test_cache/", recursive = TRUE)

path <- callr::r(
function() {
rmarkdown::render("resources/eng-reticulate-cache-test.Rmd", quiet = TRUE, envir = new.env())
Expand Down

0 comments on commit c345ce2

Please sign in to comment.