##// END OF EJS Templates
Make nbformat.(read|write) accept file-like object or path
Thomas Kluyver -
Show More
@@ -1,150 +1,161 b''
1 1 """The IPython notebook format
2 2
3 3 Use this module to read or write notebook files as particular nbformat versions.
4 4 """
5 5
6 6 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 import io
9 from IPython.utils import py3compat
8 10
9 11 from IPython.utils.log import get_logger
10 12
11 13 from . import v1
12 14 from . import v2
13 15 from . import v3
14 16 from . import v4
15 17
16 18 __all__ = ['versions', 'validate', 'ValidationError', 'convert', 'from_dict',
17 19 'NotebookNode', 'current_nbformat', 'current_nbformat_minor',
18 20 'NBFormatError', 'NO_CONVERT', 'reads', 'read', 'writes', 'write']
19 21
20 22 versions = {
21 23 1: v1,
22 24 2: v2,
23 25 3: v3,
24 26 4: v4,
25 27 }
26 28
27 29 from .validator import validate, ValidationError
28 30 from .converter import convert
29 31 from . import reader
30 32 from .notebooknode import from_dict, NotebookNode
31 33
32 34 from .v4 import (
33 35 nbformat as current_nbformat,
34 36 nbformat_minor as current_nbformat_minor,
35 37 )
36 38
37 39 class NBFormatError(ValueError):
38 40 pass
39 41
40 42 # no-conversion singleton
41 43 NO_CONVERT = object()
42 44
43 45 def reads(s, as_version, **kwargs):
44 46 """Read a notebook from a string and return the NotebookNode object as the given version.
45 47
46 48 The string can contain a notebook of any version.
47 49 The notebook will be returned `as_version`, converting, if necessary.
48 50
49 51 Notebook format errors will be logged.
50 52
51 53 Parameters
52 54 ----------
53 55 s : unicode
54 56 The raw unicode string to read the notebook from.
55 57 as_version : int
56 58 The version of the notebook format to return.
57 59 The notebook will be converted, if necessary.
58 60 Pass nbformat.NO_CONVERT to prevent conversion.
59 61
60 62 Returns
61 63 -------
62 64 nb : NotebookNode
63 65 The notebook that was read.
64 66 """
65 67 nb = reader.reads(s, **kwargs)
66 68 if as_version is not NO_CONVERT:
67 69 nb = convert(nb, as_version)
68 70 try:
69 71 validate(nb)
70 72 except ValidationError as e:
71 73 get_logger().error("Notebook JSON is invalid: %s", e)
72 74 return nb
73 75
74 76
75 77 def writes(nb, version=NO_CONVERT, **kwargs):
76 78 """Write a notebook to a string in a given format in the given nbformat version.
77 79
78 80 Any notebook format errors will be logged.
79 81
80 82 Parameters
81 83 ----------
82 84 nb : NotebookNode
83 85 The notebook to write.
84 86 version : int, optional
85 87 The nbformat version to write.
86 88 If unspecified, or specified as nbformat.NO_CONVERT,
87 89 the notebook's own version will be used and no conversion performed.
88 90
89 91 Returns
90 92 -------
91 93 s : unicode
92 94 The notebook as a JSON string.
93 95 """
94 96 if version is not NO_CONVERT:
95 97 nb = convert(nb, version)
96 98 else:
97 99 version, _ = reader.get_version(nb)
98 100 try:
99 101 validate(nb)
100 102 except ValidationError as e:
101 103 get_logger().error("Notebook JSON is invalid: %s", e)
102 104 return versions[version].writes_json(nb, **kwargs)
103 105
104 106
105 107 def read(fp, as_version, **kwargs):
106 108 """Read a notebook from a file as a NotebookNode of the given version.
107 109
108 110 The string can contain a notebook of any version.
109 111 The notebook will be returned `as_version`, converting, if necessary.
110 112
111 113 Notebook format errors will be logged.
112 114
113 115 Parameters
114 116 ----------
115 fp : file
116 Any file-like object with a read method.
117 fp : file or str
118 Any file-like object with a read method, or a path to a file.
117 119 as_version: int
118 120 The version of the notebook format to return.
119 121 The notebook will be converted, if necessary.
120 122 Pass nbformat.NO_CONVERT to prevent conversion.
121 123
122 124 Returns
123 125 -------
124 126 nb : NotebookNode
125 127 The notebook that was read.
126 128 """
129 if isinstance(fp, py3compat.string_types):
130 with io.open(fp, encoding='utf-8') as f:
131 return read(f, as_version, **kwargs)
132
127 133 return reads(fp.read(), as_version, **kwargs)
128 134
129 135
130 136 def write(nb, fp, version=NO_CONVERT, **kwargs):
131 137 """Write a notebook to a file in a given nbformat version.
132 138
133 139 The file-like object must accept unicode input.
134 140
135 141 Parameters
136 142 ----------
137 143 nb : NotebookNode
138 144 The notebook to write.
139 fp : file
140 Any file-like object with a write method that accepts unicode.
145 fp : file or str
146 Any file-like object with a write method that accepts unicode, or
147 a path to write a file.
141 148 version : int, optional
142 149 The nbformat version to write.
143 150 If nb is not this version, it will be converted.
144 151 If unspecified, or specified as nbformat.NO_CONVERT,
145 152 the notebook's own version will be used and no conversion performed.
146 153 """
154 if isinstance(fp, py3compat.string_types):
155 with open(fp, 'w', encoding='utf-8') as f:
156 return write(nb, f, version=version, **kwargs)
157
147 158 s = writes(nb, version, **kwargs)
148 159 if isinstance(s, bytes):
149 160 s = s.decode('utf8')
150 161 return fp.write(s)
@@ -1,37 +1,49 b''
1 1 """Test the APIs at the top-level of nbformat"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import json
7 import os
7 8
8 9 from .base import TestsBase
9 10
11 from IPython.utils.tempdir import TemporaryDirectory
10 12 from ..reader import get_version
11 from IPython.nbformat import read, current_nbformat, writes
13 from IPython.nbformat import read, current_nbformat, writes, write
12 14
13 15
14 16 class TestAPI(TestsBase):
15 17
16 18 def test_read(self):
17 19 """Can older notebooks be opened and automatically converted to the current
18 20 nbformat?"""
19 21
20 22 # Open a version 2 notebook.
21 23 with self.fopen(u'test2.ipynb', 'r') as f:
22 24 nb = read(f, as_version=current_nbformat)
23 25
24 26 # Check that the notebook was upgraded to the latest version automatically.
25 27 (major, minor) = get_version(nb)
26 28 self.assertEqual(major, current_nbformat)
27 29
28 30 def test_write_downgrade_2(self):
29 31 """dowgrade a v3 notebook to v2"""
30 32 # Open a version 3 notebook.
31 33 with self.fopen(u'test3.ipynb', 'r') as f:
32 34 nb = read(f, as_version=3)
33 35
34 36 jsons = writes(nb, version=2)
35 37 nb2 = json.loads(jsons)
36 38 (major, minor) = get_version(nb2)
37 39 self.assertEqual(major, 2)
40
41 def test_read_write_path(self):
42 """read() and write() take filesystem paths"""
43 path = os.path.join(self._get_files_path(), u'test4.ipynb')
44 nb = read(path, as_version=4)
45
46 with TemporaryDirectory() as td:
47 dest = os.path.join(td, 'echidna.ipynb')
48 write(nb, dest)
49 assert os.path.isfile(dest)
General Comments 0
You need to be logged in to leave comments. Login now