Skip to content

Commit

Permalink
added cache_eng_python to add Python session caching between chunks. …
Browse files Browse the repository at this point in the history
…Addresses knitr #1505
  • Loading branch information
tmastny committed Apr 18, 2018
1 parent 228624b commit b52ecaa
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 3 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ S3method(summary,python.builtin.object)
S3method(with,python.builtin.object)
export("%as%")
export(array_reshape)
export(cache_eng_python)
export(conda_binary)
export(conda_create)
export(conda_install)
Expand Down
67 changes: 64 additions & 3 deletions R/knitr-engine.R
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ eng_python <- function(options) {
}

eng_python_synchronize_after()

if(options$cache > 0) {
save_python_session(options$hash)
}
wrap <- getOption("reticulate.engine.wrap", eng_python_wrap)
wrap(outputs, options)

Expand All @@ -186,8 +188,18 @@ eng_python_initialize <- function(options, context, envir) {
if (is.character(options$engine.path))
use_python(options$engine.path[[1]])

ensure_python_initialized()

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")
}
eng_python_initialize_matplotlib(options, context, envir)
}

Expand Down Expand Up @@ -278,3 +290,52 @@ eng_python_wrap <- function(outputs, options) {
wrap <- yoink("knitr", "wrap")
wrap(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)
}

#' A reticulate cache engine for Knitr
#'
#' This provides a `reticulate` cache engine for `knitr`. The cache engine
#' allows `knitr` to save and load Python sessions between cached chunks. The
#' cache engine depends on the `dill` Python module. Therefore, you must have
#' `dill` installed in your Python environment.
#'
#' The engine can be activated by setting (for example)
#'
#' ```
#' knitr::cache_engines$set(python = reticulate::cache_eng_python)
#' ```
#'
#' Typically, this will be set within a document's setup chunk, or by the
#' environment requesting that Python chunks be processed by this engine.
#'
#' @param cache_path
#' The path to save the chunk cache, as provided by `knitr` during chunk execution.
#'
#' @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"))
}


24 changes: 24 additions & 0 deletions man/cache_eng_python.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b52ecaa

Please sign in to comment.