Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log2file #293

Merged
merged 8 commits into from
Apr 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
322 changes: 173 additions & 149 deletions R/execution.r
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ NULL

setClassUnion('recordedplotOrNULL', members = c('recordedplot', 'NULL'))

setClassUnion('listOrNULL', members = c('list', 'NULL'))

displayenv <- environment(publish_mimebundle)

# create an empty named list
Expand Down Expand Up @@ -59,6 +61,7 @@ format_stack <- function(calls) {
paste0(tb, line_refs)
}


Executor <- setRefClass(
'Executor',
fields = list(
Expand All @@ -68,179 +71,191 @@ Executor <- setRefClass(
payload = 'list',
err = 'list',
interrupted = 'logical',
last_recorded_plot = 'recordedplotOrNULL'),
last_recorded_plot = 'recordedplotOrNULL',
current_request = 'listOrNULL',
nframe = 'integer'),
methods = list(

is.silent = function() {
current_request$content$silent
},

send_error_msg = function(msg) {
if (!is_silent()) return()
send_response('stream', current_request, 'iopub',
list(name = 'stderr', text = msg))

},

display_data = function(data, metadata = NULL) {
if (is.null(metadata)) {
metadata <- namedlist()
}
send_response('display_data', current_request, 'iopub', list(
source = 'R display func',
data = data,
metadata = metadata))

invisible(TRUE)
},

page = function(mimebundle) {
payload <<- c(payload, list(list(source = 'page', data = mimebundle)))
},

# .Last doesn’t seem to work, so replicating behavior
quit = function(save = 'default', status = 0, runLast = TRUE) {
save <- switch(save,
default = , yes = TRUE,
no = FALSE,
ask = ask('Save workspace image? [y/n/c]: '),
stop('unknown `save` value'))
if (is.null(save)) return() # cancel
if (runLast) {
if (!is.null(.GlobalEnv$.Last)) .GlobalEnv$.Last()
if (!is.null(.GlobalEnv$.Last.sys)) .GlobalEnv$.Last.sys()
}
if (save) NULL # TODO: actually save history
payload <<- c(payload, list(list(source = 'ask_exit')))
},

handle_error = function(e) {
log_debug('Error output: %s', toString(e))
calls <- head(sys.calls()[-seq_len(nframe + 1L)], -3)

msg <- paste0(toString(e), 'Traceback:\n')
stack_info <- format_stack(calls)

err <<- list(ename = 'ERROR', evalue = toString(e), traceback = as.list(c(msg, stack_info)))
if (!is.silent()) {
send_response('error', current_request, 'iopub', c(err, list(
execution_count = execution_count)))
}
},

send_plot = function(plotobj) {
formats <- namedlist()
metadata <- namedlist()
for (mime in getOption('jupyter.plot_mimetypes')) {
tryCatch({
formats[[mime]] <- mime2repr[[mime]](plotobj, attr(plotobj, '.irkernel_width'), attr(plotobj, '.irkernel_height'))
}, error = handle_error)
# Isolating SVGs (putting them in an iframe) avoids strange
# interactions with CSS on the page.
if (identical(mime, 'image/svg+xml')) {
metadata[[mime]] <- list(isolated = TRUE)
}
}
publish_mimebundle(formats, metadata)
},

handle_display_error = function(e){
# This is used with withCallingHandler and only has two additional
# calls at the end instead of the 3 for tryCatch... (-2 at the end)
# we also remove the tryCatch and mime2repr stuff at the head of the callstack (+7)
calls <- head(sys.calls()[-seq_len(nframe + 7L)], -2)
stack_info <- format_stack(calls)
msg <- sprintf('ERROR while rich displaying an object: %s\nTraceback:\n%s\n',
toString(e),
paste(stack_info, collapse = '\n'))
log_debug(msg)
send_error_msg(msg)
},

handle_value = function(obj) {
log_debug("Value output...")
mimebundle <- prepare_mimebundle(obj, .self$handle_display_error)
if (length(intersect(class(obj), getOption('jupyter.pager_classes'))) > 0) {
log_debug('Showing pager: %s', paste(capture.output(str(mimebundle$data)), collapse = '\n'))
page(mimebundle)
} else {
log_debug('Sending display_data: %s', paste(capture.output(str(mimebundle$data)), collapse = '\n'))
send_response('display_data', current_request, 'iopub', mimebundle)
}
},

stream = function(output, streamname) {
log_debug('Stream output: %s', output)
send_response('stream', current_request, 'iopub', list(
name = streamname,
text = paste(output, collapse = '\n')))
},

handle_graphics = function(plotobj) {
log_debug("Graphics output...")
if (!plot_builds_upon(last_recorded_plot, plotobj)) {
log_debug('Sending plot...')
send_plot(last_recorded_plot)
}
# need to be set here to capture the size and have it available when the plot is sent
attr(plotobj, '.irkernel_width') <- getOption('repr.plot.width', repr_option_defaults$repr.plot.width)
attr(plotobj, '.irkernel_height') <- getOption('repr.plot.height', repr_option_defaults$repr.plot.height)
last_recorded_plot <<- plotobj
},

handle_message = function(o) {
log_debug('Message output: %s', o)
stream(paste(o$message, collapse = ''), 'stderr')
},

handle_warning = function(o) {
call <- if (is.null(o$call)) '' else paste('In', deparse(o$call)[[1]])
log_debug('Warning output: %s', sprintf('Warning message:\n%s: %s', call, o$message))
stream(sprintf('Warning message:\n%s: %s', call, o$message), 'stderr')
},

execute = function(request) {
send_response('status', request, 'iopub', list(
execution_state = 'busy'))
send_response('execute_input', request, 'iopub', list(
code = request$content$code,
execution_count = execution_count))

silent <- request$content$silent

display_data <- function(data, metadata = NULL) {
if (is.null(metadata)) {
metadata <- namedlist()
}
send_response('display_data', request, 'iopub', list(
source = 'R display func',
data = data,
metadata = metadata))

invisible(TRUE)
}

# Make the current request available to other functions
current_request <<- request
# reset ...
payload <<- list()
err <<- list()

# Push the display function into the IRdisplay namespace
# This looks awkward, but we do need to get a reference to the execution
# state into a global environment.
# TODO: move to initialize?
unlockBinding('base_display', displayenv)
assign('base_display', display_data, pos = displayenv)

payload <<- list()

page <- function(mimebundle) {
payload <<- c(payload, list(list(source = 'page', data = mimebundle)))
}

options(pager = function(files, header, title, delete.file) {
text <- title
for (path in files) {
text <- c(text, header, readLines(path))
}
if (delete.file) file.remove(files)
page(list('text/plain' = paste(text, collapse = '\n')))
})

# .Last doesn’t seem to work, so replicating behavior
quit <- function(save = 'default', status = 0, runLast = TRUE) {
save <- switch(save,
default = , yes = TRUE,
no = FALSE,
ask = ask('Save workspace image? [y/n/c]: '),
stop('unknown `save` value'))
if (is.null(save)) return() # cancel
if (runLast) {
if (!is.null(.GlobalEnv$.Last)) .GlobalEnv$.Last()
if (!is.null(.GlobalEnv$.Last.sys)) .GlobalEnv$.Last.sys()
}
if (save) NULL # TODO: actually save history
payload <<- c(payload, list(list(source = 'ask_exit')))
}
assign('base_display', .self$display_data, pos = displayenv)

# shade base::quit
assign('quit', quit, envir = .GlobalEnv)
assign('q', quit, envir = .GlobalEnv)

send_plot <- function(plotobj) {
formats <- namedlist()
metadata <- namedlist()
for (mime in getOption('jupyter.plot_mimetypes')) {
tryCatch({
formats[[mime]] <- mime2repr[[mime]](plotobj, attr(plotobj, '.irkernel_width'), attr(plotobj, '.irkernel_height'))
}, error = handle_error)
# Isolating SVGs (putting them in an iframe) avoids strange
# interactions with CSS on the page.
if (identical(mime, 'image/svg+xml')) {
metadata[[mime]] <- list(isolated = TRUE)
}
}
publish_mimebundle(formats, metadata)
}
assign('quit', .self$quit, envir = .GlobalEnv)
assign('q', .self$quit, envir = .GlobalEnv)

err <<- list()
nframe <- NULL # find out stack depth in notebook cell

# find out stack depth in notebook cell
# TODO: maybe replace with a single call on first execute and rest reuse the value?
tryCatch(evaluate(
'stop()',
stop_on_error = 1L,
output_handler = new_output_handler(error = function(e) nframe <<- sys.nframe())))

handle_error <- function(e) {
calls <- head(sys.calls()[-seq_len(nframe + 1L)], -3)

msg <- paste0(toString(e), 'Traceback:\n')
stack_info <- format_stack(calls)

err <<- list(ename = 'ERROR', evalue = toString(e), traceback = as.list(c(msg, stack_info)))
if (!silent) {
send_response('error', request, 'iopub', c(err, list(
execution_count = execution_count)))
}
}

if (silent) {
stream <- function(s, n) {}
handle_value <- identity
handle_graphics <- identity
handle_message <- identity
handle_warning <- identity
oh <- if (is.silent()) {
new_output_handler(
text = identity,
graphics = identity,
message = identity,
warning = identity,
error = identity,
value = identity)
} else {
handle_display_error <- function(e){
# This is used with withCallingHandler and only has two additional
# calls at the end instead of the 3 for tryCatch... (-2 at the end)
# we also remove the tryCatch and mime2repr stuff at the head of the callstack (+7)
calls <- head(sys.calls()[-seq_len(nframe + 7L)], -2)
stack_info <- format_stack(calls)
msg <- sprintf('ERROR while rich displaying an object: %s\nTraceback:\n%s\n',
toString(e),
paste(stack_info, collapse='\n'))
log_debug(msg)
if (!silent) {
send_response('stream', request, 'iopub', list(
name = 'stderr',
text = msg))
}
}
handle_value <- function(obj) {
mimebundle <- prepare_mimebundle(obj, handle_display_error)
if (length(intersect(class(obj), getOption('jupyter.pager_classes'))) > 0) {
log_debug('Showing pager: %s', paste(capture.output(str(mimebundle$data)), collapse = '\n'))
page(mimebundle)
} else {
log_debug('Sending display_data: %s', paste(capture.output(str(mimebundle$data)), collapse = '\n'))
send_response('display_data', request, 'iopub', mimebundle)
}
}

stream <- function(output, streamname) {
send_response('stream', request, 'iopub', list(
name = streamname,
text = paste(output, collapse = '\n')))
}

handle_graphics <- function(plotobj) {
if (!plot_builds_upon(last_recorded_plot, plotobj)) {
send_plot(last_recorded_plot)
}
# need to be set here to capture the size and have it available when the plot is sent
attr(plotobj, '.irkernel_width') <- getOption('repr.plot.width', repr_option_defaults$repr.plot.width)
attr(plotobj, '.irkernel_height') <- getOption('repr.plot.height', repr_option_defaults$repr.plot.height)
last_recorded_plot <<- plotobj
}

handle_message <- function(o) {
stream(paste(o$message, collapse = ''), 'stderr')
}

handle_warning <- function(o) {
call <- if (is.null(o$call)) '' else paste('In', deparse(o$call)[[1]])
stream(sprintf('Warning message:\n%s: %s', call, o$message), 'stderr')
}
new_output_handler(
text = function(o) stream(o, 'stdout'),
graphics = .self$handle_graphics,
message = .self$handle_message,
warning = .self$handle_warning,
error = .self$handle_error,
value = .self$handle_value)
}

oh <- new_output_handler(
text = function(o) stream(o, 'stdout'),
graphics = handle_graphics,
message = handle_message,
warning = handle_warning,
error = handle_error,
value = handle_value)

interrupted <<- FALSE
last_recorded_plot <<- NULL

log_debug('Executing code: %s', request$content$code)
tryCatch(
evaluate(
request$content$code,
Expand All @@ -250,7 +265,7 @@ execute = function(request) {
interrupt = function(cond) interrupted <<- TRUE,
error = handle_error) # evaluate does not catch errors in parsing

if ((!silent) & (!is.null(last_recorded_plot))) {
if ((!is.silent()) & (!is.null(last_recorded_plot))) {
send_plot(last_recorded_plot)
}

Expand Down Expand Up @@ -279,14 +294,23 @@ execute = function(request) {
abort_queued_messages()
}

if (!silent) {
if (!is.silent()) {
execution_count <<- execution_count + 1L
}
},

initialize = function(...) {
execution_count <<- 1L
err <<- list()
options(pager = function(files, header, title, delete.file) {
text <- title
for (path in files) {
text <- c(text, header, readLines(path))
}
if (delete.file) file.remove(files)
page(list('text/plain' = paste(text, collapse = '\n')))
})

callSuper(...)
})
)
1 change: 1 addition & 0 deletions R/kernel.r
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ main <- function(connection_file = '') {
# pass it as a separate command line argument.
connection_file <- commandArgs(TRUE)[[1]]
}
log_debug('Starting the R kernel...')
kernel <- Kernel$new(connection_file = connection_file)
kernel$run()
}