From 4b64980ac3fcd1170112d73b52c43517a02dede9 Mon Sep 17 00:00:00 2001 From: Tim Mastny Date: Thu, 19 Apr 2018 15:00:52 -0500 Subject: [PATCH] cache engine API (#1518) * added cache_engines object and cache_engine function to make API for engine-specific caches * changes based on feedback. tested in reticulate #167 * not sure how this stuff got in * add @tmastny to the list of ctb, and a news item * the argument of the cache function is not the cache path, but chunk options --- DESCRIPTION | 1 + NAMESPACE | 1 + NEWS.md | 4 ++++ R/block.R | 1 + R/engine.R | 37 +++++++++++++++++++++++++++++++++++++ man/cache_engines.Rd | 30 ++++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+) create mode 100644 man/cache_engines.Rd diff --git a/DESCRIPTION b/DESCRIPTION index ade84ac932..f35eae5d47 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -84,6 +84,7 @@ Authors@R: c( person("Thibaut", "Assus", role = "ctb"), person("Thibaut", "Lamadon", role = "ctb"), person("Thomas", "Leeper", role = "ctb"), + person("Tim", "Mastny", role = "ctb"), person("Tom", "Torsney-Weir", role = "ctb"), person("Trevor", "Davis", role = "ctb"), person("Viktoras", "Veitas", role = "ctb"), diff --git a/NAMESPACE b/NAMESPACE index a52e210ab5..77e44988e4 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -26,6 +26,7 @@ export(all_labels) export(all_patterns) export(all_rcpp_labels) export(asis_output) +export(cache_engines) export(clean_cache) export(combine_words) export(current_input) diff --git a/NEWS.md b/NEWS.md index 0601587563..4cde919fa8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # CHANGES IN knitr VERSION 1.21 (unreleased) +## NEW FEATURES + +- Added a new object `cache_engines` for other language engines to handle caching. See `?knitr::cache_engines` for details (thanks, @tmastny, #1518). + ## BUG FIXES - `valign` in `kable_latex()` does not put the float alignment to the correct location (thanks, @haozhu233, #1487, #1519). diff --git a/R/block.R b/R/block.R index bbf0e174e6..27eabba211 100644 --- a/R/block.R +++ b/R/block.R @@ -72,6 +72,7 @@ call_block = function(block) { params$engine != 'Rcpp') { if (opts_knit$get('verbose')) message(' loading cache from ', hash) cache$load(hash, lazy = params$cache.lazy) + cache_engine(params) if (!params$include) return('') if (params$cache == 3) return(cache$output(hash)) } diff --git a/R/engine.R b/R/engine.R index 2b8bac4671..4cc6359b47 100644 --- a/R/engine.R +++ b/R/engine.R @@ -31,6 +31,26 @@ #' names(knit_engines$get()) knit_engines = new_defaults() + +#' Cache engines of other languages +#' +#' This object controls how to load cached environments from languages other +#' than R (when the chunk option \code{engine} is not \code{'R'}). Each +#' component in this object is a function that takes the current path to the +#' chunk cache and loads it into the language environment. +#' +#' The cache engine function has one argument \code{options}, a list containing +#' all chunk options. Note that \code{options$hash} is the path to the current +#' chunk cache with the chunk's hash, but without any file extension, and the +#' language engine may write a cache database to this path (with an extension). +#' +#' The cache engine function should load the cache environment and should know +#' the extension appropriate for the language. +#' @references See \url{https://github.com/rstudio/reticulate/pull/167} for an +#' implementation of a cache engine for Python. +#' @export +cache_engines = new_defaults() + #' An output wrapper for language engine output #' #' If you have designed a language engine, you may call this function in the end @@ -178,6 +198,15 @@ eng_python = function(options) { } } +cache_eng_python = function(options) { + if (isFALSE(options$python.reticulate)) return() + # TODO: change this hack to reticulate::cache_eng_python(options) after + # https://github.com/rstudio/reticulate/pull/167 is merged and released + if (!'cache_eng_python' %in% ls(asNamespace('reticulate'))) return() + fun = getFromNamespace('cache_eng_python', 'reticulate') + fun(options) +} + ## Java # e.g. see http://cran.rstudio.com/package=jvmr @@ -637,6 +666,8 @@ knit_engines$set( python = eng_python, julia = eng_julia ) +cache_engines$set(python = cache_eng_python) + get_engine = function(name) { fun = knit_engines$get(name) if (is.function(fun)) return(fun) @@ -649,6 +680,12 @@ get_engine = function(name) { } } +cache_engine = function(options) { + cache_fun = cache_engines$get(options$engine) + if (!is.function(cache_fun)) return() + cache_fun(options) +} + # possible values for engines (for auto-completion in RStudio) opts_chunk_attr$engine = as.list(sort(c('R', names(knit_engines$get())))) opts_chunk_attr[c('engine.path', 'engine.opts')] = list('character', 'character') diff --git a/man/cache_engines.Rd b/man/cache_engines.Rd new file mode 100644 index 0000000000..343553fc36 --- /dev/null +++ b/man/cache_engines.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/engine.R +\docType{data} +\name{cache_engines} +\alias{cache_engines} +\title{Cache engines of other languages} +\format{An object of class \code{list} of length 5.} +\usage{ +cache_engines +} +\description{ +This object controls how to load cached environments from languages other +than R (when the chunk option \code{engine} is not \code{'R'}). Each +component in this object is a function that takes the current path to the +chunk cache and loads it into the language environment. +} +\details{ +The cache engine function has one argument \code{options}, a list containing +all chunk options. Note that \code{options$hash} is the path to the current +chunk cache with the chunk's hash, but without any file extension, and the +language engine may write a cache database to this path (with an extension). + +The cache engine function should load the cache environment and should know +the extension appropriate for the language. +} +\references{ +See \url{https://github.com/rstudio/reticulate/pull/167} for an + implementation of a cache engine for Python. +} +\keyword{datasets}