Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion R/execution.r
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ should_store_history = function() {
!is.null(sh) && sh
},

should_stop_on_error = function() {
current_request$content$stop_on_error
},

send_error_msg = function(msg) {
if (is_silent()) return()
send_response('stream', current_request, 'iopub',
Expand Down Expand Up @@ -321,7 +325,7 @@ execute = function(request) {

send_response('execute_reply', request, 'shell', reply_content)

if (interrupted || !is.null(err$ename)) {
if (interrupted || (!is.null(err$ename) && should_stop_on_error())) {
# errors or interrupts should interrupt all currently queued messages,
# not only the currently running one...
abort_queued_messages()
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/jkt
32 changes: 31 additions & 1 deletion tests/testthat/test_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class IRkernelTests(jkt.KernelTests):

language_name = 'R'

def _execute_code(self, code, tests=True, silent=False, store_history=True):
def _execute_code(self, code, *, tests=True, silent=False, store_history=True):
self.flush_channels()

reply, output_msgs = self.execute_helper(code, silent=silent, store_history=store_history)
Expand Down Expand Up @@ -248,6 +248,36 @@ def test_should_not_increment_history(self):
self.assertEqual(execution_count_1, execution_count_2)
self.assertEqual(execution_count_1, execution_count_3)

def test_should_stop_on_error(self):
"""Stops remaining queued execution on error"""
# Sleep for a bit in the bad code, to ensure following messages actually get queued up
bad_code = 'Sys.sleep(2); bad(code)'
good_code = 'data.frame(x = 1:3)'
reply1, output_msgs1 = self.execute_helper(bad_code, stop_on_error=True)
reply2, output_msgs2 = self.execute_helper(good_code)
reply3, output_msgs3 = self.execute_helper(good_code)
execution_status_1 = reply1['content']['status']
execution_status_2 = reply2['content']['status']
execution_status_3 = reply3['content']['status']
self.assertEqual(execution_status_1, 'error')
self.assertEqual(execution_status_2, 'abort')
self.assertEqual(execution_status_3, 'abort')

def test_should_not_stop_on_error(self):
"""Continues remaining queued execution on error"""
# Sleep for a bit in the bad code, to ensure following messages actually get queued up
bad_code = 'Sys.sleep(2); bad(code)'
good_code = 'data.frame(x = 1:3)'
reply1, output_msgs1 = self.execute_helper(bad_code, stop_on_error=False)
reply2, output_msgs2 = self.execute_helper(good_code)
reply3, output_msgs3 = self.execute_helper(good_code)
execution_status_1 = reply1['content']['status']
execution_status_2 = reply2['content']['status']
execution_status_3 = reply3['content']['status']
self.assertEqual(execution_status_1, 'error')
self.assertEqual(execution_status_2, 'ok')
self.assertEqual(execution_status_3, 'ok')

def test_irkernel_inspects(self):
"""Test if object inspection works."""
self.flush_channels()
Expand Down