test_execute.py
149 lines
| 5.8 KiB
| text/x-python
|
PythonLexer
Julia Evans
|
r17074 | """ | ||
Julia Evans
|
r17075 | Module with tests for the execute preprocessor. | ||
Julia Evans
|
r17074 | """ | ||
# Copyright (c) IPython Development Team. | ||||
# Distributed under the terms of the Modified BSD License. | ||||
import copy | ||||
MinRK
|
r17101 | import glob | ||
MinRK
|
r18605 | import io | ||
Julia Evans
|
r17082 | import os | ||
import re | ||||
Julia Evans
|
r17074 | |||
Jessica B. Hamrick
|
r20749 | try: | ||
from queue import Empty # Py 3 | ||||
except ImportError: | ||||
from Queue import Empty # Py 2 | ||||
MinRK
|
r18605 | from IPython import nbformat | ||
Julia Evans
|
r17074 | |||
from .base import PreprocessorTestsBase | ||||
from ..execute import ExecutePreprocessor | ||||
MinRK
|
r17091 | from IPython.nbconvert.filters import strip_ansi | ||
Jessica B. Hamrick
|
r20749 | from nose.tools import assert_raises | ||
MinRK
|
r17091 | |||
addr_pat = re.compile(r'0x[0-9a-f]{7,9}') | ||||
Julia Evans
|
r17074 | |||
class TestExecute(PreprocessorTestsBase): | ||||
"""Contains test functions for execute.py""" | ||||
Julia Evans
|
r17084 | @staticmethod | ||
MinRK
|
r17092 | def normalize_output(output): | ||
Julia Evans
|
r17084 | """ | ||
MinRK
|
r17092 | Normalizes outputs for comparison. | ||
Julia Evans
|
r17084 | """ | ||
MinRK
|
r17092 | output = dict(output) | ||
if 'metadata' in output: | ||||
del output['metadata'] | ||||
MinRK
|
r18589 | if 'text' in output: | ||
output['text'] = re.sub(addr_pat, '<HEXADDR>', output['text']) | ||||
if 'text/plain' in output.get('data', {}): | ||||
output['data']['text/plain'] = \ | ||||
re.sub(addr_pat, '<HEXADDR>', output['data']['text/plain']) | ||||
MinRK
|
r17092 | if 'traceback' in output: | ||
MinRK
|
r17091 | tb = [] | ||
MinRK
|
r17092 | for line in output['traceback']: | ||
MinRK
|
r17091 | tb.append(strip_ansi(line)) | ||
MinRK
|
r17092 | output['traceback'] = tb | ||
MinRK
|
r17091 | |||
MinRK
|
r17092 | return output | ||
Julia Evans
|
r17082 | |||
def assert_notebooks_equal(self, expected, actual): | ||||
MinRK
|
r18580 | expected_cells = expected['cells'] | ||
actual_cells = actual['cells'] | ||||
MinRK
|
r18602 | self.assertEqual(len(expected_cells), len(actual_cells)) | ||
Julia Evans
|
r17082 | |||
Julia Evans
|
r17084 | for expected_cell, actual_cell in zip(expected_cells, actual_cells): | ||
expected_outputs = expected_cell.get('outputs', []) | ||||
actual_outputs = actual_cell.get('outputs', []) | ||||
MinRK
|
r17092 | normalized_expected_outputs = list(map(self.normalize_output, expected_outputs)) | ||
normalized_actual_outputs = list(map(self.normalize_output, actual_outputs)) | ||||
MinRK
|
r18602 | self.assertEqual(normalized_expected_outputs, normalized_actual_outputs) | ||
Julia Evans
|
r17082 | |||
MinRK
|
r18587 | expected_execution_count = expected_cell.get('execution_count', None) | ||
actual_execution_count = actual_cell.get('execution_count', None) | ||||
MinRK
|
r18602 | self.assertEqual(expected_execution_count, actual_execution_count) | ||
Jessica B. Hamrick
|
r17823 | |||
Julia Evans
|
r17074 | |||
Jessica B. Hamrick
|
r20748 | def build_preprocessor(self, opts): | ||
Julia Evans
|
r17074 | """Make an instance of a preprocessor""" | ||
preprocessor = ExecutePreprocessor() | ||||
preprocessor.enabled = True | ||||
Jessica B. Hamrick
|
r20748 | for opt in opts: | ||
setattr(preprocessor, opt, opts[opt]) | ||||
Julia Evans
|
r17074 | return preprocessor | ||
Julia Evans
|
r17082 | |||
Julia Evans
|
r17074 | def test_constructor(self): | ||
"""Can a ExecutePreprocessor be constructed?""" | ||||
Jessica B. Hamrick
|
r20748 | self.build_preprocessor({}) | ||
Julia Evans
|
r17074 | |||
Julia Evans
|
r17082 | |||
Jessica B. Hamrick
|
r20748 | def run_notebook(self, filename, opts, resources): | ||
"""Loads and runs a notebook, returning both the version prior to | ||||
running it and the version after running it. | ||||
""" | ||||
with io.open(filename) as f: | ||||
input_nb = nbformat.read(f, 4) | ||||
preprocessor = self.build_preprocessor(opts) | ||||
cleaned_input_nb = copy.deepcopy(input_nb) | ||||
for cell in cleaned_input_nb.cells: | ||||
if 'execution_count' in cell: | ||||
del cell['execution_count'] | ||||
cell['outputs'] = [] | ||||
output_nb, _ = preprocessor(cleaned_input_nb, resources) | ||||
return input_nb, output_nb | ||||
Julia Evans
|
r17082 | def test_run_notebooks(self): | ||
"""Runs a series of test notebooks and compares them to their actual output""" | ||||
current_dir = os.path.dirname(__file__) | ||||
MinRK
|
r17101 | input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb')) | ||
Julia Evans
|
r17082 | for filename in input_files: | ||
Jessica B. Hamrick
|
r20530 | if os.path.basename(filename) == "Disable Stdin.ipynb": | ||
Jessica B. Hamrick
|
r20748 | continue | ||
elif os.path.basename(filename) == "Interrupt.ipynb": | ||||
opts = dict(timeout=1, interrupt_on_timeout=True) | ||||
Jessica B. Hamrick
|
r20530 | else: | ||
Jessica B. Hamrick
|
r20748 | opts = {} | ||
res = self.build_resources() | ||||
res['metadata']['path'] = os.path.dirname(filename) | ||||
input_nb, output_nb = self.run_notebook(filename, opts, res) | ||||
self.assert_notebooks_equal(input_nb, output_nb) | ||||
Jessica B. Hamrick
|
r20647 | |||
def test_empty_path(self): | ||||
"""Can the kernel be started when the path is empty?""" | ||||
current_dir = os.path.dirname(__file__) | ||||
filename = os.path.join(current_dir, 'files', 'HelloWorld.ipynb') | ||||
res = self.build_resources() | ||||
res['metadata']['path'] = '' | ||||
Jessica B. Hamrick
|
r20748 | input_nb, output_nb = self.run_notebook(filename, {}, res) | ||
self.assert_notebooks_equal(input_nb, output_nb) | ||||
def test_disable_stdin(self): | ||||
"""Test disabling standard input""" | ||||
current_dir = os.path.dirname(__file__) | ||||
filename = os.path.join(current_dir, 'files', 'Disable Stdin.ipynb') | ||||
res = self.build_resources() | ||||
res['metadata']['path'] = os.path.dirname(filename) | ||||
input_nb, output_nb = self.run_notebook(filename, {}, res) | ||||
# We need to special-case this particular notebook, because the | ||||
# traceback contains machine-specific stuff like where IPython | ||||
# is installed. It is sufficient here to just check that an error | ||||
# was thrown, and that it was a StdinNotImplementedError | ||||
self.assertEqual(len(output_nb['cells']), 1) | ||||
self.assertEqual(len(output_nb['cells'][0]['outputs']), 1) | ||||
output = output_nb['cells'][0]['outputs'][0] | ||||
self.assertEqual(output['output_type'], 'error') | ||||
self.assertEqual(output['ename'], 'StdinNotImplementedError') | ||||
self.assertEqual(output['evalue'], 'raw_input was called, but this frontend does not support input requests.') | ||||
Jessica B. Hamrick
|
r20749 | |||
def test_timeout(self): | ||||
"""Check that an error is raised when a computation times out""" | ||||
current_dir = os.path.dirname(__file__) | ||||
filename = os.path.join(current_dir, 'files', 'Interrupt.ipynb') | ||||
assert_raises(Empty, self.run_notebook, filename, dict(timeout=1)) | ||||