Show More
@@ -0,0 +1,143 b'' | |||||
|
1 | """The IPython notebook format | |||
|
2 | ||||
|
3 | Use this module to read or write notebook files as particular nbformat versions. | |||
|
4 | """ | |||
|
5 | ||||
|
6 | # Copyright (c) IPython Development Team. | |||
|
7 | # Distributed under the terms of the Modified BSD License. | |||
|
8 | ||||
|
9 | from IPython.utils.log import get_logger | |||
|
10 | ||||
|
11 | from . import v1 | |||
|
12 | from . import v2 | |||
|
13 | from . import v3 | |||
|
14 | from . import v4 | |||
|
15 | ||||
|
16 | versions = { | |||
|
17 | 1: v1, | |||
|
18 | 2: v2, | |||
|
19 | 3: v3, | |||
|
20 | 4: v4, | |||
|
21 | } | |||
|
22 | ||||
|
23 | from .validator import validate, ValidationError | |||
|
24 | from .converter import convert | |||
|
25 | from . import reader | |||
|
26 | ||||
|
27 | from .v4 import ( | |||
|
28 | nbformat as current_nbformat, | |||
|
29 | nbformat_minor as current_nbformat_minor, | |||
|
30 | ) | |||
|
31 | ||||
|
32 | class NBFormatError(ValueError): | |||
|
33 | pass | |||
|
34 | ||||
|
35 | # no-conversion singleton | |||
|
36 | NO_CONVERT = object() | |||
|
37 | ||||
|
38 | def reads(s, as_version, **kwargs): | |||
|
39 | """Read a notebook from a string and return the NotebookNode object as the given version. | |||
|
40 | ||||
|
41 | The string can contain a notebook of any version. | |||
|
42 | The notebook will be returned `as_version`, converting, if necessary. | |||
|
43 | ||||
|
44 | Notebook format errors will be logged. | |||
|
45 | ||||
|
46 | Parameters | |||
|
47 | ---------- | |||
|
48 | s : unicode | |||
|
49 | The raw unicode string to read the notebook from. | |||
|
50 | as_version : int | |||
|
51 | The version of the notebook format to return. | |||
|
52 | The notebook will be converted, if necessary. | |||
|
53 | Pass nbformat.NO_CONVERT to prevent conversion. | |||
|
54 | ||||
|
55 | Returns | |||
|
56 | ------- | |||
|
57 | nb : NotebookNode | |||
|
58 | The notebook that was read. | |||
|
59 | """ | |||
|
60 | nb = reader.reads(s, **kwargs) | |||
|
61 | if as_version is not NO_CONVERT: | |||
|
62 | nb = convert(nb, as_version) | |||
|
63 | try: | |||
|
64 | validate(nb) | |||
|
65 | except ValidationError as e: | |||
|
66 | get_logger().error("Notebook JSON is invalid: %s", e) | |||
|
67 | return nb | |||
|
68 | ||||
|
69 | ||||
|
70 | def writes(nb, version, **kwargs): | |||
|
71 | """Write a notebook to a string in a given format in the given nbformat version. | |||
|
72 | ||||
|
73 | Any notebook format errors will be logged. | |||
|
74 | ||||
|
75 | Parameters | |||
|
76 | ---------- | |||
|
77 | nb : NotebookNode | |||
|
78 | The notebook to write. | |||
|
79 | version : int | |||
|
80 | The nbformat version to write. | |||
|
81 | If nb is not this version, it will be converted. | |||
|
82 | Pass nbformat.NO_CONVERT to prevent conversion. | |||
|
83 | ||||
|
84 | Returns | |||
|
85 | ------- | |||
|
86 | s : unicode | |||
|
87 | The notebook as a JSON string. | |||
|
88 | """ | |||
|
89 | if version is not NO_CONVERT: | |||
|
90 | nb = convert(nb, version) | |||
|
91 | else: | |||
|
92 | version, _ = reader.get_version(nb) | |||
|
93 | try: | |||
|
94 | validate(nb) | |||
|
95 | except ValidationError as e: | |||
|
96 | get_logger().error("Notebook JSON is invalid: %s", e) | |||
|
97 | return versions[version].writes_json(nb, **kwargs) | |||
|
98 | ||||
|
99 | ||||
|
100 | def read(fp, as_version, **kwargs): | |||
|
101 | """Read a notebook from a file as a NotebookNode of the given version. | |||
|
102 | ||||
|
103 | The string can contain a notebook of any version. | |||
|
104 | The notebook will be returned `as_version`, converting, if necessary. | |||
|
105 | ||||
|
106 | Notebook format errors will be logged. | |||
|
107 | ||||
|
108 | Parameters | |||
|
109 | ---------- | |||
|
110 | fp : file | |||
|
111 | Any file-like object with a read method. | |||
|
112 | as_version: int | |||
|
113 | The version of the notebook format to return. | |||
|
114 | The notebook will be converted, if necessary. | |||
|
115 | Pass nbformat.NO_CONVERT to prevent conversion. | |||
|
116 | ||||
|
117 | Returns | |||
|
118 | ------- | |||
|
119 | nb : NotebookNode | |||
|
120 | The notebook that was read. | |||
|
121 | """ | |||
|
122 | return reads(fp.read(), as_version, **kwargs) | |||
|
123 | ||||
|
124 | ||||
|
125 | def write(fp, nb, version, **kwargs): | |||
|
126 | """Write a notebook to a file in a given nbformat version. | |||
|
127 | ||||
|
128 | The file-like object must accept unicode input. | |||
|
129 | ||||
|
130 | Parameters | |||
|
131 | ---------- | |||
|
132 | fp : file | |||
|
133 | Any file-like object with a write method that accepts unicode. | |||
|
134 | nb : NotebookNode | |||
|
135 | The notebook to write. | |||
|
136 | version : int | |||
|
137 | The nbformat version to write. | |||
|
138 | If nb is not this version, it will be converted. | |||
|
139 | """ | |||
|
140 | s = writes(nb, version, **kwargs) | |||
|
141 | if isinstance(s, bytes): | |||
|
142 | s = s.decode('utf8') | |||
|
143 | return fp.write(s) |
@@ -3,7 +3,8 b'' | |||||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 |
from . |
|
6 | from . import versions | |
|
7 | from .reader import get_version | |||
7 |
|
8 | |||
8 |
|
9 | |||
9 | def convert(nb, to_version): |
|
10 | def convert(nb, to_version): | |
@@ -24,7 +25,7 b' def convert(nb, to_version):' | |||||
24 | # Get input notebook version. |
|
25 | # Get input notebook version. | |
25 | (version, version_minor) = get_version(nb) |
|
26 | (version, version_minor) = get_version(nb) | |
26 |
|
27 | |||
27 |
# Check if destination is |
|
28 | # Check if destination is target version, if so return contents | |
28 | if version == to_version: |
|
29 | if version == to_version: | |
29 | return nb |
|
30 | return nb | |
30 |
|
31 |
@@ -17,8 +17,8 b' from IPython.nbformat.v3 import (' | |||||
17 | from IPython.nbformat import v3 as _v_latest |
|
17 | from IPython.nbformat import v3 as _v_latest | |
18 |
|
18 | |||
19 | from .reader import reads as reader_reads |
|
19 | from .reader import reads as reader_reads | |
20 |
from . |
|
20 | from . import versions | |
21 | from .convert import convert |
|
21 | from .converter import convert | |
22 | from .validator import validate, ValidationError |
|
22 | from .validator import validate, ValidationError | |
23 |
|
23 | |||
24 | from IPython.utils.log import get_logger |
|
24 | from IPython.utils.log import get_logger |
@@ -5,19 +5,6 b'' | |||||
5 |
|
5 | |||
6 | import json |
|
6 | import json | |
7 |
|
7 | |||
8 | from . import v1 |
|
|||
9 | from . import v2 |
|
|||
10 | from . import v3 |
|
|||
11 | from . import v4 |
|
|||
12 |
|
||||
13 | versions = { |
|
|||
14 | 1: v1, |
|
|||
15 | 2: v2, |
|
|||
16 | 3: v3, |
|
|||
17 | 4: v4, |
|
|||
18 | } |
|
|||
19 |
|
||||
20 |
|
||||
21 | class NotJSONError(ValueError): |
|
8 | class NotJSONError(ValueError): | |
22 | pass |
|
9 | pass | |
23 |
|
10 | |||
@@ -66,7 +53,7 b' def reads(s, **kwargs):' | |||||
66 | nb : NotebookNode |
|
53 | nb : NotebookNode | |
67 | The notebook that was read. |
|
54 | The notebook that was read. | |
68 | """ |
|
55 | """ | |
69 |
from . |
|
56 | from . import versions, NBFormatError | |
70 |
|
57 | |||
71 | nb_dict = parse_json(s, **kwargs) |
|
58 | nb_dict = parse_json(s, **kwargs) | |
72 | (major, minor) = get_version(nb_dict) |
|
59 | (major, minor) = get_version(nb_dict) |
@@ -10,12 +10,13 b' from hmac import HMAC' | |||||
10 | import io |
|
10 | import io | |
11 | import os |
|
11 | import os | |
12 |
|
12 | |||
|
13 | from IPython.utils.io import atomic_writing | |||
13 | from IPython.utils.py3compat import string_types, unicode_type, cast_bytes |
|
14 | from IPython.utils.py3compat import string_types, unicode_type, cast_bytes | |
14 | from IPython.utils.traitlets import Instance, Bytes, Enum, Any, Unicode, Bool |
|
15 | from IPython.utils.traitlets import Instance, Bytes, Enum, Any, Unicode, Bool | |
15 | from IPython.config import LoggingConfigurable, MultipleInstanceError |
|
16 | from IPython.config import LoggingConfigurable, MultipleInstanceError | |
16 | from IPython.core.application import BaseIPythonApplication, base_flags |
|
17 | from IPython.core.application import BaseIPythonApplication, base_flags | |
17 |
|
18 | |||
18 |
from . |
|
19 | from . import read, write, NO_CONVERT | |
19 |
|
20 | |||
20 | try: |
|
21 | try: | |
21 | # Python 3 |
|
22 | # Python 3 | |
@@ -278,14 +279,14 b' class TrustNotebookApp(BaseIPythonApplication):' | |||||
278 | self.log.error("Notebook missing: %s" % notebook_path) |
|
279 | self.log.error("Notebook missing: %s" % notebook_path) | |
279 | self.exit(1) |
|
280 | self.exit(1) | |
280 | with io.open(notebook_path, encoding='utf8') as f: |
|
281 | with io.open(notebook_path, encoding='utf8') as f: | |
281 |
nb = read(f, |
|
282 | nb = read(f, NO_CONVERT) | |
282 | if self.notary.check_signature(nb): |
|
283 | if self.notary.check_signature(nb): | |
283 | print("Notebook already signed: %s" % notebook_path) |
|
284 | print("Notebook already signed: %s" % notebook_path) | |
284 | else: |
|
285 | else: | |
285 | print("Signing notebook: %s" % notebook_path) |
|
286 | print("Signing notebook: %s" % notebook_path) | |
286 | self.notary.sign(nb) |
|
287 | self.notary.sign(nb) | |
287 |
with |
|
288 | with atomic_writing(notebook_path) as f: | |
288 |
write(nb, |
|
289 | write(f, nb, NO_CONVERT) | |
289 |
|
290 | |||
290 | def generate_new_key(self): |
|
291 | def generate_new_key(self): | |
291 | """Generate a new notebook signature key""" |
|
292 | """Generate a new notebook signature key""" |
@@ -1,29 +1,25 b'' | |||||
1 | """ |
|
1 | """Test the APIs at the top-level of nbformat""" | |
2 | Contains tests class for current.py |
|
|||
3 | """ |
|
|||
4 |
|
2 | |||
5 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
6 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
7 |
|
5 | |||
8 | import io |
|
|||
9 | import json |
|
6 | import json | |
10 | import tempfile |
|
|||
11 |
|
7 | |||
12 | from .base import TestsBase |
|
8 | from .base import TestsBase | |
13 |
|
9 | |||
14 | from ..reader import get_version |
|
10 | from ..reader import get_version | |
15 |
from . |
|
11 | from IPython.nbformat import read, current_nbformat, writes | |
16 |
|
12 | |||
17 |
|
13 | |||
18 |
class Test |
|
14 | class TestAPI(TestsBase): | |
19 |
|
15 | |||
20 | def test_read(self): |
|
16 | def test_read(self): | |
21 | """Can older notebooks be opened and automatically converted to the current |
|
17 | """Can older notebooks be opened and automatically converted to the current | |
22 | nbformat?""" |
|
18 | nbformat?""" | |
23 |
|
19 | |||
24 | # Open a version 2 notebook. |
|
20 | # Open a version 2 notebook. | |
25 |
with self.fopen(u'test2.ipynb', |
|
21 | with self.fopen(u'test2.ipynb', 'r') as f: | |
26 | nb = read(f) |
|
22 | nb = read(f, as_version=current_nbformat) | |
27 |
|
23 | |||
28 | # Check that the notebook was upgraded to the latest version automatically. |
|
24 | # Check that the notebook was upgraded to the latest version automatically. | |
29 | (major, minor) = get_version(nb) |
|
25 | (major, minor) = get_version(nb) | |
@@ -33,7 +29,7 b' class TestCurrent(TestsBase):' | |||||
33 | """dowgrade a v3 notebook to v2""" |
|
29 | """dowgrade a v3 notebook to v2""" | |
34 | # Open a version 3 notebook. |
|
30 | # Open a version 3 notebook. | |
35 | with self.fopen(u'test3.ipynb', 'r') as f: |
|
31 | with self.fopen(u'test3.ipynb', 'r') as f: | |
36 |
nb = read(f, |
|
32 | nb = read(f, as_version=3) | |
37 |
|
33 | |||
38 | jsons = writes(nb, version=2) |
|
34 | jsons = writes(nb, version=2) | |
39 | nb2 = json.loads(jsons) |
|
35 | nb2 = json.loads(jsons) |
@@ -5,9 +5,9 b'' | |||||
5 |
|
5 | |||
6 | from .base import TestsBase |
|
6 | from .base import TestsBase | |
7 |
|
7 | |||
8 | from ..convert import convert |
|
8 | from ..converter import convert | |
9 | from ..reader import read, get_version |
|
9 | from ..reader import read, get_version | |
10 |
from .. |
|
10 | from .. import current_nbformat | |
11 |
|
11 | |||
12 |
|
12 | |||
13 | class TestConvert(TestsBase): |
|
13 | class TestConvert(TestsBase): |
@@ -3,10 +3,9 b'' | |||||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 | from .. import sign |
|
|||
7 | from .base import TestsBase |
|
6 | from .base import TestsBase | |
8 |
|
7 | |||
9 |
from . |
|
8 | from IPython.nbformat import read, sign | |
10 | from IPython.core.getipython import get_ipython |
|
9 | from IPython.core.getipython import get_ipython | |
11 |
|
10 | |||
12 |
|
11 | |||
@@ -18,7 +17,7 b' class TestNotary(TestsBase):' | |||||
18 | profile_dir=get_ipython().profile_dir |
|
17 | profile_dir=get_ipython().profile_dir | |
19 | ) |
|
18 | ) | |
20 | with self.fopen(u'test3.ipynb', u'r') as f: |
|
19 | with self.fopen(u'test3.ipynb', u'r') as f: | |
21 |
self.nb = read(f, |
|
20 | self.nb = read(f, as_version=4) | |
22 |
|
21 | |||
23 | def test_algorithms(self): |
|
22 | def test_algorithms(self): | |
24 | last_sig = '' |
|
23 | last_sig = '' |
@@ -7,7 +7,7 b' import os' | |||||
7 |
|
7 | |||
8 | from .base import TestsBase |
|
8 | from .base import TestsBase | |
9 | from jsonschema import ValidationError |
|
9 | from jsonschema import ValidationError | |
10 |
from . |
|
10 | from IPython.nbformat import read | |
11 | from ..validator import isvalid, validate |
|
11 | from ..validator import isvalid, validate | |
12 |
|
12 | |||
13 |
|
13 | |||
@@ -16,21 +16,21 b' class TestValidator(TestsBase):' | |||||
16 | def test_nb2(self): |
|
16 | def test_nb2(self): | |
17 | """Test that a v2 notebook converted to current passes validation""" |
|
17 | """Test that a v2 notebook converted to current passes validation""" | |
18 | with self.fopen(u'test2.ipynb', u'r') as f: |
|
18 | with self.fopen(u'test2.ipynb', u'r') as f: | |
19 |
nb = read(f, |
|
19 | nb = read(f, as_version=4) | |
20 | validate(nb) |
|
20 | validate(nb) | |
21 | self.assertEqual(isvalid(nb), True) |
|
21 | self.assertEqual(isvalid(nb), True) | |
22 |
|
22 | |||
23 | def test_nb3(self): |
|
23 | def test_nb3(self): | |
24 | """Test that a v3 notebook passes validation""" |
|
24 | """Test that a v3 notebook passes validation""" | |
25 | with self.fopen(u'test3.ipynb', u'r') as f: |
|
25 | with self.fopen(u'test3.ipynb', u'r') as f: | |
26 |
nb = read(f, |
|
26 | nb = read(f, as_version=4) | |
27 | validate(nb) |
|
27 | validate(nb) | |
28 | self.assertEqual(isvalid(nb), True) |
|
28 | self.assertEqual(isvalid(nb), True) | |
29 |
|
29 | |||
30 | def test_nb4(self): |
|
30 | def test_nb4(self): | |
31 | """Test that a v4 notebook passes validation""" |
|
31 | """Test that a v4 notebook passes validation""" | |
32 | with self.fopen(u'test4.ipynb', u'r') as f: |
|
32 | with self.fopen(u'test4.ipynb', u'r') as f: | |
33 |
nb = read(f, |
|
33 | nb = read(f, as_version=4) | |
34 | validate(nb) |
|
34 | validate(nb) | |
35 | self.assertEqual(isvalid(nb), True) |
|
35 | self.assertEqual(isvalid(nb), True) | |
36 |
|
36 | |||
@@ -41,7 +41,7 b' class TestValidator(TestsBase):' | |||||
41 | # - invalid cell type |
|
41 | # - invalid cell type | |
42 | # - invalid output_type |
|
42 | # - invalid output_type | |
43 | with self.fopen(u'invalid.ipynb', u'r') as f: |
|
43 | with self.fopen(u'invalid.ipynb', u'r') as f: | |
44 |
nb = read(f, |
|
44 | nb = read(f, as_version=4) | |
45 | with self.assertRaises(ValidationError): |
|
45 | with self.assertRaises(ValidationError): | |
46 | validate(nb) |
|
46 | validate(nb) | |
47 | self.assertEqual(isvalid(nb), False) |
|
47 | self.assertEqual(isvalid(nb), False) | |
@@ -49,7 +49,7 b' class TestValidator(TestsBase):' | |||||
49 | def test_future(self): |
|
49 | def test_future(self): | |
50 | """Test than a notebook from the future with extra keys passes validation""" |
|
50 | """Test than a notebook from the future with extra keys passes validation""" | |
51 | with self.fopen(u'test4plus.ipynb', u'r') as f: |
|
51 | with self.fopen(u'test4plus.ipynb', u'r') as f: | |
52 | nb = read(f) |
|
52 | nb = read(f, as_version=4) | |
53 | with self.assertRaises(ValidationError): |
|
53 | with self.assertRaises(ValidationError): | |
54 | validate(nb, version=4) |
|
54 | validate(nb, version=4) | |
55 |
|
55 |
@@ -16,7 +16,7 b' from IPython.utils.log import get_logger' | |||||
16 |
|
16 | |||
17 | def _warn_if_invalid(nb, version): |
|
17 | def _warn_if_invalid(nb, version): | |
18 | """Log validation errors, if there are any.""" |
|
18 | """Log validation errors, if there are any.""" | |
19 |
from IPython.nbformat |
|
19 | from IPython.nbformat import validate, ValidationError | |
20 | try: |
|
20 | try: | |
21 | validate(nb, version=version) |
|
21 | validate(nb, version=version) | |
22 | except ValidationError as e: |
|
22 | except ValidationError as e: |
@@ -19,7 +19,7 b" nbformat_schema = 'nbformat.v4.schema.json'" | |||||
19 |
|
19 | |||
20 | def validate(node, ref=None): |
|
20 | def validate(node, ref=None): | |
21 | """validate a v4 node""" |
|
21 | """validate a v4 node""" | |
22 |
from .. |
|
22 | from .. import validate | |
23 | return validate(node, ref=ref, version=nbformat) |
|
23 | return validate(node, ref=ref, version=nbformat) | |
24 |
|
24 | |||
25 |
|
25 |
@@ -2,7 +2,7 b' import copy' | |||||
2 |
|
2 | |||
3 | import nose.tools as nt |
|
3 | import nose.tools as nt | |
4 |
|
4 | |||
5 |
from IPython.nbformat |
|
5 | from IPython.nbformat import validate | |
6 | from .. import convert |
|
6 | from .. import convert | |
7 |
|
7 | |||
8 | from . import nbexamples |
|
8 | from . import nbexamples |
@@ -43,7 +43,8 b' def _relax_additional_properties(obj):' | |||||
43 | def get_validator(version=None, version_minor=None): |
|
43 | def get_validator(version=None, version_minor=None): | |
44 | """Load the JSON schema into a Validator""" |
|
44 | """Load the JSON schema into a Validator""" | |
45 | if version is None: |
|
45 | if version is None: | |
46 |
from . |
|
46 | from .. import current_nbformat | |
|
47 | version = current_nbformat | |||
47 |
|
48 | |||
48 | v = import_item("IPython.nbformat.v%s" % version) |
|
49 | v = import_item("IPython.nbformat.v%s" % version) | |
49 | current_minor = v.nbformat_minor |
|
50 | current_minor = v.nbformat_minor |
General Comments 0
You need to be logged in to leave comments.
Login now