diff --git a/.Rbuildignore b/.Rbuildignore index 9ec14f40..be195ffe 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -10,3 +10,4 @@ example-notebooks/.*$ ^\.travis.yml$ Dockerfile test_ir.py +cran-comments.md diff --git a/DESCRIPTION b/DESCRIPTION index 76573bec..9cefa289 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,16 +1,13 @@ Package: IRkernel -Title: Native R kernel for the Jupyter notebook -Description: This package provides a native interface to the R kernel from the - Jupyter notebook. +Title: Native R Kernel for the Jupyter Notebook +Description: The R kernel for the jupyter environment executes R code which the + frontend (Jupyter Notebook or other frontends) submits to the kernel via the + network. Version: 0.6 -Authors@R: c(person("Thomas", "Kluyver", role = c("aut", "cre"), - email = "thomas@kluyver.me.uk"), - person("Philipp", "A.", role = "aut", - email = "flying-sheep@web.de"), - person("Karthik", "Ram", role = "aut", - email = "karthik.ram@gmail.com")) -Author: Thomas Kluyver -Maintainer: Thomas Kluyver +Authors@R: c(person("Thomas", "Kluyver", role = c("aut", "cre"), email = "thomas@kluyver.me.uk"), + person("Philipp", "A.", role = "aut", email = "flying-sheep@web.de"), + person("Jan", "Schulz", role = "aut", email = "jasc@gmx.net"), + person("Karthik", "Ram", role = "aut", email = "karthik.ram@gmail.com")) Depends: R (>= 3.0.1) License: MIT + file LICENSE @@ -28,6 +25,7 @@ Imports: Collate: 'logging.r' 'comm_manager.r' + 'environment.r' 'options.r' 'execution.r' 'handlers.r' diff --git a/R/environment.r b/R/environment.r new file mode 100644 index 00000000..66af3a96 --- /dev/null +++ b/R/environment.r @@ -0,0 +1,20 @@ +# Everthing related to the environment which takes functions which shadow base R functions. +# This is needed to build in our own needs, like properly shutting down the kernel +# when `quit()` is called. + +add_to_user_searchpath <- function(name, FN) { + assign(name, FN, 'jupyter:irkernel') +} + +get_shadowenv <- function() { + as.environment('jupyter:irkernel') +} + +# Adds functions which do not need any access to the executer into the users searchpath +init_shadowenv <- function() { + # add the accessors to the shadow env itself, so they are actually accessable + # from everywhere... + add_to_user_searchpath('.irk.get_shadowenv', get_shadowenv) + add_to_user_searchpath('.irk.add_to_user_searchpath', add_to_user_searchpath) + +} diff --git a/R/execution.r b/R/execution.r index 9b0a6e63..10017465 100644 --- a/R/execution.r +++ b/R/execution.r @@ -115,7 +115,7 @@ quit = function(save = 'default', status = 0, runLast = TRUE) { if (!is.null(.GlobalEnv$.Last.sys)) .GlobalEnv$.Last.sys() } if (save) NULL # TODO: actually save history - payload <<- c(payload, list(list(source = 'ask_exit', keepkernel = FALSE))) + payload <<- c(.self$payload, list(list(source = 'ask_exit', keepkernel = FALSE))) }, handle_error = function(e) { @@ -215,9 +215,9 @@ execute = function(request) { err <<- list() # shade base::quit - assign('quit', .self$quit, envir = .GlobalEnv) - assign('q', .self$quit, envir = .GlobalEnv) - + add_to_user_searchpath('quit', .self$quit) + add_to_user_searchpath('q', .self$quit) + # find out stack depth in notebook cell # TODO: maybe replace with a single call on first execute and rest reuse the value? tryCatch(evaluate( @@ -250,12 +250,12 @@ execute = function(request) { # Workaround to warn user when code contains potential problematic code # https://github.com/IRkernel/repr/issues/28#issuecomment-208810772 # See https://github.com/hadley/evaluate/issues/66 - if(.Platform$OS.type == 'windows') { + if (.Platform$OS.type == 'windows') { # strip whitespace, because trailing newlines would trip the test... code <- gsub('^\\s+|\\s+$', '', request$content$code) real_len <- nchar(code) r_len <- nchar(paste(capture.output(cat(code)), collapse = '\n')) - if (real_len != r_len){ + if (real_len != r_len) { msg = c('Your code contains a unicode char which cannot be displayed in your ', 'current locale and R will silently convert it to an escaped form when the ', 'R kernel executes this code. This can lead to subtle errors if you use ', @@ -264,7 +264,6 @@ execute = function(request) { send_error_msg(paste(msg, collapse = '\n')) } } - tryCatch( evaluate( request$content$code, @@ -318,7 +317,14 @@ initialize = function(...) { page(list('text/plain' = paste(text, collapse = '\n'))) }) options(jupyter.base_display_func = .self$display_data) + # Create the shadow env here and detach it finalize + # so it's available for the whole lifetime of the kernel. + attach(NULL, name = 'jupyter:irkernel') + init_shadowenv() callSuper(...) +}, +finalize = function() { + detach("jupyter:irkernel") }) ) diff --git a/R/kernel.r b/R/kernel.r index 6e81c7c3..a4bfec87 100644 --- a/R/kernel.r +++ b/R/kernel.r @@ -166,7 +166,7 @@ abort_queued_messages = function() { c(.pbd_env$ZMQ.PO$POLLIN), # type 0) # zero timeout, only what's already there log_debug('abort loop: after poll') - if(bitwAnd(zmq.poll.get.revents(1), .pbd_env$ZMQ.PO$POLLIN)) { + if (bitwAnd(zmq.poll.get.revents(1), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('abort loop: found msg') abort_shell_msg() } else { @@ -343,13 +343,13 @@ run = function() { # the easiest seems to be to handle this in a big if .. else if .. else # clause... # https://github.com/IRkernel/IRkernel/pull/266 - if(bitwAnd(zmq.poll.get.revents(1), .pbd_env$ZMQ.PO$POLLIN)) { + if (bitwAnd(zmq.poll.get.revents(1), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('main loop: hb') hb_reply() - } else if(bitwAnd(zmq.poll.get.revents(2), .pbd_env$ZMQ.PO$POLLIN)) { + } else if (bitwAnd(zmq.poll.get.revents(2), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('main loop: shell') handle_shell() - } else if(bitwAnd(zmq.poll.get.revents(3), .pbd_env$ZMQ.PO$POLLIN)) { + } else if (bitwAnd(zmq.poll.get.revents(3), .pbd_env$ZMQ.PO$POLLIN)) { log_debug('main loop: control') handle_control() } else { diff --git a/cran-comments.md b/cran-comments.md new file mode 100644 index 00000000..3fb64d30 --- /dev/null +++ b/cran-comments.md @@ -0,0 +1,33 @@ +## Release summary + +This package is new on CRAN. It contains the R kernel for the Jupyter +ecosystem. The kernel executes R code, which the frontend (Jupyter Notebook or +other frontends) submits to the kernel via the network. + +## Test environments + +* local Win7 64bit install, R 3.2.5, R 3.3.0 and r-devel (3.4) +* Ubuntu 12.04 (on travis-ci), oldrelease, release, and r-devel + +## R CMD check results + +There are no WARNINGs and 1 NOTEs. + +Note: + +* Found the following calls to attach(): + File 'IRkernel/R/execution.r': + attach(NULL, name = "jupyter:irkernel") + See section 'Good practice' in '?attach'. + + We use this additional environment to add functions so that regular "stuff" + like `quit()` works in the IRkernel environment (in this case to shutdown the + kernel). We added the "good practice" call to `detach` in `finalize` so that + this environment is available as long as the R kernel is running.. + +## Downstream dependencies + +It is assumed that there won't be any code dependencies on this package, as it +implements an application without any API apart from the startup function and the +implemented Jupyter Messaging spec. It's usually started as +`R --slave -e IRkernel::main() --args {connection_file}`.