diff --git a/NAMESPACE b/NAMESPACE index 512e13a52..01e133f27 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -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) diff --git a/R/knitr-engine.R b/R/knitr-engine.R index a3e4b22e9..f4db73d31 100644 --- a/R/knitr-engine.R +++ b/R/knitr-engine.R @@ -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) @@ -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) } @@ -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")) +} + + diff --git a/man/cache_eng_python.Rd b/man/cache_eng_python.Rd new file mode 100644 index 000000000..d8fd64ef0 --- /dev/null +++ b/man/cache_eng_python.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/knitr-engine.R +\name{cache_eng_python} +\alias{cache_eng_python} +\title{A reticulate cache engine for Knitr} +\usage{ +cache_eng_python(cache_path) +} +\arguments{ +\item{cache_path}{The path to save the chunk cache, as provided by \code{knitr} during chunk execution.} +} +\description{ +This provides a \code{reticulate} cache engine for \code{knitr}. The cache engine +allows \code{knitr} to save and load Python sessions between cached chunks. The +cache engine depends on the \code{dill} Python module. Therefore, you must have +\code{dill} installed in your Python environment. +} +\details{ +The engine can be activated by setting (for example)\preformatted{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. +}