Skip to content

Commit

Permalink
Ending notebook execution early with sys.exit without raising an exce…
Browse files Browse the repository at this point in the history
…ption (#449)

Support using sys.exit to end execution early without raising a papermill exception
  • Loading branch information
yusuphisms authored and MSeal committed Dec 9, 2019
1 parent 16d4785 commit 0ee0da7
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 0 deletions.
2 changes: 2 additions & 0 deletions papermill/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ def raise_for_execution_errors(nb, output_path):

for output in cell.outputs:
if output.output_type == "error":
if output.ename == "SystemExit" and (output.evalue == "" or output.evalue == "0"):
continue
error = PapermillExecutionError(
exec_count=cell.execution_count,
source=cell.source,
Expand Down
52 changes: 52 additions & 0 deletions papermill/tests/notebooks/sysexit.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"sys.exit()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Cell should not execute.\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "dev",
"language": "python",
"name": "dev"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
52 changes: 52 additions & 0 deletions papermill/tests/notebooks/sysexit0.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"sys.exit(0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Cell should not execute.\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "dev",
"language": "python",
"name": "dev"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
52 changes: 52 additions & 0 deletions papermill/tests/notebooks/sysexit1.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"sys.exit(1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"Cell should not execute.\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "dev",
"language": "python",
"name": "dev"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
47 changes: 47 additions & 0 deletions papermill/tests/test_execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,50 @@ def test_execution_respects_cwd_assignment(self):
self.assertTrue(
os.path.isfile(os.path.join(self.base_test_dir, self.nb_test_executed_fname))
)


class TestSysExit(unittest.TestCase):
def setUp(self):
self.test_dir = tempfile.mkdtemp()

def tearDown(self):
shutil.rmtree(self.test_dir)

def test_sys_exit(self):
notebook_name = 'sysexit.ipynb'
result_path = os.path.join(self.test_dir, 'output_{}'.format(notebook_name))
execute_notebook(get_notebook_path(notebook_name), result_path)
nb = load_notebook_node(result_path)
self.assertEqual(nb.cells[0].cell_type, "code")
self.assertEqual(nb.cells[0].execution_count, 1)
self.assertEqual(nb.cells[1].execution_count, 2)
self.assertEqual(nb.cells[1].outputs[0].output_type, 'error')
self.assertEqual(nb.cells[1].outputs[0].ename, 'SystemExit')
self.assertEqual(nb.cells[1].outputs[0].evalue, '')
self.assertEqual(nb.cells[2].execution_count, None)

def test_sys_exit0(self):
notebook_name = 'sysexit0.ipynb'
result_path = os.path.join(self.test_dir, 'output_{}'.format(notebook_name))
execute_notebook(get_notebook_path(notebook_name), result_path)
nb = load_notebook_node(result_path)
self.assertEqual(nb.cells[0].cell_type, "code")
self.assertEqual(nb.cells[0].execution_count, 1)
self.assertEqual(nb.cells[1].execution_count, 2)
self.assertEqual(nb.cells[1].outputs[0].output_type, 'error')
self.assertEqual(nb.cells[1].outputs[0].ename, 'SystemExit')
self.assertEqual(nb.cells[1].outputs[0].evalue, '0')
self.assertEqual(nb.cells[2].execution_count, None)

def test_sys_exit1(self):
notebook_name = 'sysexit1.ipynb'
result_path = os.path.join(self.test_dir, 'output_{}'.format(notebook_name))
with self.assertRaises(PapermillExecutionError):
execute_notebook(get_notebook_path(notebook_name), result_path)
nb = load_notebook_node(result_path)
self.assertEqual(nb.cells[0].cell_type, "code")
self.assertEqual(nb.cells[0].outputs[0].output_type, "display_data")
self.assertEqual(nb.cells[1].execution_count, 1)
self.assertEqual(nb.cells[2].execution_count, 2)
self.assertEqual(nb.cells[2].outputs[0].output_type, 'error')
self.assertEqual(nb.cells[3].execution_count, None)

0 comments on commit 0ee0da7

Please sign in to comment.