From f2722ad3688c4596c04a994506053454d4ea3edd Mon Sep 17 00:00:00 2001 From: Tali Herzka Date: Fri, 17 Dec 2021 00:07:47 -0800 Subject: [PATCH] Catch AttributeErrors stemming from ipython_genutils as ValidationErrors on read (#241) * Catch AttributeErrors thrown by ipython_genutils during reading and conversion as ValidationErrors * fix docstrings * catch attribute errors as validation errors while reading json * revert changes to converter (in another PR) --- nbformat/reader.py | 15 ++++++++++++++- nbformat/tests/test3_no_worksheets.ipynb | 7 +++++++ .../tests/test3_worksheet_with_no_cells.ipynb | 12 ++++++++++++ nbformat/tests/test_reader.py | 12 ++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 nbformat/tests/test3_no_worksheets.ipynb create mode 100644 nbformat/tests/test3_worksheet_with_no_cells.ipynb diff --git a/nbformat/reader.py b/nbformat/reader.py index dcc90031..465dac4a 100644 --- a/nbformat/reader.py +++ b/nbformat/reader.py @@ -4,6 +4,7 @@ # Distributed under the terms of the Modified BSD License. import json +from .validator import ValidationError class NotJSONError(ValueError): pass @@ -52,13 +53,24 @@ def reads(s, **kwargs): ------- nb : NotebookNode The notebook that was read. + + Raises + ------ + ValidationError + Notebook JSON for a given version is missing an expected key and cannot be read. + + NBFormatError + Specified major version is invalid or unsupported. """ from . import versions, NBFormatError nb_dict = parse_json(s, **kwargs) (major, minor) = get_version(nb_dict) if major in versions: - return versions[major].to_notebook_json(nb_dict, minor=minor) + try: + return versions[major].to_notebook_json(nb_dict, minor=minor) + except AttributeError as e: + raise ValidationError(f"The notebook is invalid and is missing an expected key: {e}") else: raise NBFormatError('Unsupported nbformat version %s' % major) @@ -80,3 +92,4 @@ def read(fp, **kwargs): The notebook that was read. """ return reads(fp.read(), **kwargs) + diff --git a/nbformat/tests/test3_no_worksheets.ipynb b/nbformat/tests/test3_no_worksheets.ipynb new file mode 100644 index 00000000..566159ea --- /dev/null +++ b/nbformat/tests/test3_no_worksheets.ipynb @@ -0,0 +1,7 @@ +{ + "metadata": { + "name": "" + }, + "nbformat": 3, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/nbformat/tests/test3_worksheet_with_no_cells.ipynb b/nbformat/tests/test3_worksheet_with_no_cells.ipynb new file mode 100644 index 00000000..552e961c --- /dev/null +++ b/nbformat/tests/test3_worksheet_with_no_cells.ipynb @@ -0,0 +1,12 @@ +{ + "metadata": { + "name": "" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "metadata": {} + } + ] +} \ No newline at end of file diff --git a/nbformat/tests/test_reader.py b/nbformat/tests/test_reader.py index 9b5f9b85..5130c94f 100644 --- a/nbformat/tests/test_reader.py +++ b/nbformat/tests/test_reader.py @@ -15,6 +15,7 @@ from .base import TestsBase from ..reader import read, get_version +from ..validator import ValidationError #----------------------------------------------------------------------------- # Classes and functions @@ -36,3 +37,14 @@ def test_read(self): nb = read(f) (major, minor) = get_version(nb) self.assertEqual(major, 2) + + def test_read_fails_on_missing_worksheets(self): + with self.fopen(u'test3_no_worksheets.ipynb', u'r') as f: + with self.assertRaisesRegex(ValidationError, r'worksheets'): + nb = read(f) + + def test_read_fails_on_missing_worksheet_cells(self): + with self.fopen(u'test3_worksheet_with_no_cells.ipynb', u'r') as f: + with self.assertRaisesRegex(ValidationError, r'cells'): + nb = read(f) + \ No newline at end of file