##// END OF EJS Templates
strip transient values to/from nb files...
MinRK -
Show More
@@ -1,346 +1,346 b''
1 1 {
2 2 "$schema": "http://json-schema.org/draft-04/schema#",
3 3 "description": "IPython Notebook v4.0 JSON schema.",
4 4 "type": "object",
5 5 "additionalProperties": false,
6 6 "required": ["metadata", "nbformat_minor", "nbformat", "cells"],
7 7 "properties": {
8 8 "metadata": {
9 9 "description": "Notebook root-level metadata.",
10 10 "type": "object",
11 11 "additionalProperties": true,
12 12 "properties": {
13 13 "kernel_info": {
14 14 "description": "Kernel information.",
15 15 "type": "object",
16 16 "required": ["name", "language"],
17 17 "properties": {
18 18 "name": {
19 19 "description": "Name of the kernel specification.",
20 20 "type": "string"
21 21 },
22 22 "language": {
23 23 "description": "The programming language which this kernel runs.",
24 24 "type": "string"
25 25 },
26 26 "codemirror_mode": {
27 27 "description": "The codemirror mode to use for code in this language.",
28 28 "type": "string"
29 29 }
30 30 }
31 31 },
32 32 "signature": {
33 33 "description": "Hash of the notebook.",
34 34 "type": "string"
35 35 },
36 36 "orig_nbformat": {
37 "description": "Original notebook format (major number) before converting the notebook between versions.",
37 "description": "Original notebook format (major number) before converting the notebook between versions. This should never be written to a file.",
38 38 "type": "integer",
39 39 "minimum": 1
40 40 }
41 41 }
42 42 },
43 43 "nbformat_minor": {
44 44 "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.",
45 45 "type": "integer",
46 46 "minimum": 0
47 47 },
48 48 "nbformat": {
49 49 "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.",
50 50 "type": "integer",
51 51 "minimum": 4,
52 52 "maximum": 4
53 53 },
54 54 "cells": {
55 55 "description": "Array of cells of the current notebook.",
56 56 "type": "array",
57 57 "items": {
58 58 "type": "object",
59 59 "oneOf": [
60 60 {"$ref": "#/definitions/raw_cell"},
61 61 {"$ref": "#/definitions/markdown_cell"},
62 62 {"$ref": "#/definitions/heading_cell"},
63 63 {"$ref": "#/definitions/code_cell"}
64 64 ]
65 65 }
66 66 }
67 67 },
68 68
69 69 "definitions": {
70 70
71 71 "raw_cell": {
72 72 "description": "Notebook raw nbconvert cell.",
73 73 "type": "object",
74 74 "additionalProperties": false,
75 75 "required": ["cell_type", "metadata", "source"],
76 76 "properties": {
77 77 "cell_type": {
78 78 "description": "String identifying the type of cell.",
79 79 "enum": ["raw"]
80 80 },
81 81 "metadata": {
82 82 "description": "Cell-level metadata.",
83 83 "type": "object",
84 84 "additionalProperties": true,
85 85 "properties": {
86 86 "format": {
87 87 "description": "Raw cell metadata format for nbconvert.",
88 88 "type": "string"
89 89 },
90 90 "name": {"$ref": "#/definitions/misc/metadata_name"},
91 91 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
92 92 }
93 93 },
94 94 "source": {"$ref": "#/definitions/misc/source"}
95 95 }
96 96 },
97 97
98 98 "markdown_cell": {
99 99 "description": "Notebook markdown cell.",
100 100 "type": "object",
101 101 "additionalProperties": false,
102 102 "required": ["cell_type", "metadata", "source"],
103 103 "properties": {
104 104 "cell_type": {
105 105 "description": "String identifying the type of cell.",
106 106 "enum": ["markdown"]
107 107 },
108 108 "metadata": {
109 109 "description": "Cell-level metadata.",
110 110 "type": "object",
111 111 "properties": {
112 112 "name": {"$ref": "#/definitions/misc/metadata_name"},
113 113 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
114 114 },
115 115 "additionalProperties": true
116 116 },
117 117 "source": {"$ref": "#/definitions/misc/source"}
118 118 }
119 119 },
120 120
121 121 "heading_cell": {
122 122 "description": "Notebook heading cell.",
123 123 "type": "object",
124 124 "additionalProperties": false,
125 125 "required": ["cell_type", "metadata", "source", "level"],
126 126 "properties": {
127 127 "cell_type": {
128 128 "description": "String identifying the type of cell.",
129 129 "enum": ["heading"]
130 130 },
131 131 "metadata": {
132 132 "description": "Cell-level metadata.",
133 133 "type": "object",
134 134 "properties": {
135 135 "name": {"$ref": "#/definitions/misc/metadata_name"},
136 136 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
137 137 },
138 138 "additionalProperties": true
139 139 },
140 140 "source": {"$ref": "#/definitions/misc/source"},
141 141 "level": {
142 142 "description": "Level of heading cells.",
143 143 "type": "integer",
144 144 "minimum": 1
145 145 }
146 146 }
147 147 },
148 148
149 149 "code_cell": {
150 150 "description": "Notebook code cell.",
151 151 "type": "object",
152 152 "additionalProperties": false,
153 153 "required": ["cell_type", "metadata", "source", "outputs", "prompt_number"],
154 154 "properties": {
155 155 "cell_type": {
156 156 "description": "String identifying the type of cell.",
157 157 "enum": ["code"]
158 158 },
159 159 "metadata": {
160 160 "description": "Cell-level metadata.",
161 161 "type": "object",
162 162 "additionalProperties": true,
163 163 "properties": {
164 164 "collapsed": {
165 165 "description": "Whether the cell is collapsed/expanded.",
166 166 "type": "boolean"
167 167 },
168 168 "autoscroll": {
169 169 "description": "Whether the cell's output is scrolled, unscrolled, or autoscrolled.",
170 170 "enum": [true, false, "auto"]
171 171 },
172 172 "name": {"$ref": "#/definitions/misc/metadata_name"},
173 173 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
174 174 }
175 175 },
176 176 "source": {"$ref": "#/definitions/misc/source"},
177 177 "outputs": {
178 178 "description": "Execution, display, or stream outputs.",
179 179 "type": "array",
180 180 "items": {"$ref": "#/definitions/output"}
181 181 },
182 182 "prompt_number": {
183 183 "description": "The code cell's prompt number. Will be null if the cell has not been run.",
184 184 "type": ["integer", "null"],
185 185 "minimum": 0
186 186 }
187 187 }
188 188 },
189 189 "output": {
190 190 "type": "object",
191 191 "oneOf": [
192 192 {"$ref": "#/definitions/execute_result"},
193 193 {"$ref": "#/definitions/display_data"},
194 194 {"$ref": "#/definitions/stream"},
195 195 {"$ref": "#/definitions/error"}
196 196 ]
197 197 },
198 198 "execute_result": {
199 199 "description": "Result of executing a code cell.",
200 200 "type": "object",
201 201 "additionalProperties": false,
202 202 "required": ["output_type", "metadata", "prompt_number"],
203 203 "properties": {
204 204 "output_type": {
205 205 "description": "Type of cell output.",
206 206 "enum": ["execute_result"]
207 207 },
208 208 "prompt_number": {
209 209 "description": "A result's prompt number.",
210 210 "type": ["integer"],
211 211 "minimum": 0
212 212 },
213 213 "application/json": {
214 214 "type": "object"
215 215 },
216 216 "metadata": {"$ref": "#/definitions/misc/output_metadata"}
217 217 },
218 218 "patternProperties": {
219 219 "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": {
220 220 "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
221 221 "$ref": "#/definitions/misc/multiline_string"
222 222 }
223 223 }
224 224 },
225 225
226 226 "display_data": {
227 227 "description": "Data displayed as a result of code cell execution.",
228 228 "type": "object",
229 229 "additionalProperties": false,
230 230 "required": ["output_type", "metadata"],
231 231 "properties": {
232 232 "output_type": {
233 233 "description": "Type of cell output.",
234 234 "enum": ["display_data"]
235 235 },
236 236 "application/json": {
237 237 "type": "object"
238 238 },
239 239 "metadata": {"$ref": "#/definitions/misc/output_metadata"}
240 240 },
241 241 "patternProperties": {
242 242 "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": {
243 243 "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
244 244 "$ref": "#/definitions/misc/multiline_string"
245 245 }
246 246 }
247 247 },
248 248
249 249 "stream": {
250 250 "description": "Stream output from a code cell.",
251 251 "type": "object",
252 252 "additionalProperties": false,
253 253 "required": ["output_type", "metadata", "name", "text"],
254 254 "properties": {
255 255 "output_type": {
256 256 "description": "Type of cell output.",
257 257 "enum": ["stream"]
258 258 },
259 259 "metadata": {"$ref": "#/definitions/misc/output_metadata"},
260 260 "name": {
261 261 "description": "The name of the stream (stdout, stderr).",
262 262 "type": "string"
263 263 },
264 264 "text": {
265 265 "description": "The stream's text output, represented as an array of strings.",
266 266 "$ref": "#/definitions/misc/multiline_string"
267 267 }
268 268 }
269 269 },
270 270
271 271 "error": {
272 272 "description": "Output of an error that occurred during code cell execution.",
273 273 "type": "object",
274 274 "additionalProperties": false,
275 275 "required": ["output_type", "metadata", "ename", "evalue", "traceback"],
276 276 "properties": {
277 277 "output_type": {
278 278 "description": "Type of cell output.",
279 279 "enum": ["error"]
280 280 },
281 281 "metadata": {"$ref": "#/definitions/misc/output_metadata"},
282 282 "ename": {
283 283 "description": "The name of the error.",
284 284 "type": "string"
285 285 },
286 286 "evalue": {
287 287 "description": "The value, or message, of the error.",
288 288 "type": "string"
289 289 },
290 290 "traceback": {
291 291 "description": "The error's traceback, represented as an array of strings.",
292 292 "type": "array",
293 293 "items": {"type": "string"}
294 294 }
295 295 }
296 296 },
297 297
298 298 "misc": {
299 299 "metadata_name": {
300 300 "description": "The cell's name. If present, must be a non-empty string.",
301 301 "type": "string",
302 302 "pattern": "^.+$"
303 303 },
304 304 "metadata_tags": {
305 305 "description": "The cell's tags. Tags must be unique, and must not contain commas.",
306 306 "type": "array",
307 307 "uniqueItems": true,
308 308 "items": {
309 309 "type": "string",
310 310 "pattern": "^[^,]+$"
311 311 }
312 312 },
313 313 "source": {
314 314 "description": "Contents of the cell, represented as an array of lines.",
315 315 "$ref": "#/definitions/misc/multiline_string"
316 316 },
317 317 "prompt_number": {
318 318 "description": "The code cell's prompt number. Will be null if the cell has not been run.",
319 319 "type": ["integer", "null"],
320 320 "minimum": 0
321 321 },
322 322 "mimetype": {
323 323 "patternProperties": {
324 324 "^[a-zA-Z0-9\\-\\+]+/[a-zA-Z0-9\\-\\+]+": {
325 325 "description": "The cell's mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
326 326 "$ref": "#/definitions/misc/multiline_string"
327 327 }
328 328 }
329 329 },
330 330 "output_metadata": {
331 331 "description": "Cell output metadata.",
332 332 "type": "object",
333 333 "additionalProperties": true
334 334 },
335 335 "multiline_string": {
336 336 "oneOf" : [
337 337 {"type": "string"},
338 338 {
339 339 "type": "array",
340 340 "items": {"type": "string"}
341 341 }
342 342 ]
343 343 }
344 344 }
345 345 }
346 346 }
@@ -1,55 +1,60 b''
1 1 """Read and write notebooks in JSON format."""
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 copy
7 7 import json
8 8
9 9 from IPython.utils import py3compat
10 10
11 11 from .nbbase import from_dict
12 12 from .rwbase import (
13 NotebookReader, NotebookWriter, rejoin_lines, split_lines
13 NotebookReader, NotebookWriter, rejoin_lines, split_lines, strip_transient
14 14 )
15 15
16 16
17 17 class BytesEncoder(json.JSONEncoder):
18 18 """A JSON encoder that accepts b64 (and other *ascii*) bytestrings."""
19 19 def default(self, obj):
20 20 if isinstance(obj, bytes):
21 21 return obj.decode('ascii')
22 22 return json.JSONEncoder.default(self, obj)
23 23
24 24
25 25 class JSONReader(NotebookReader):
26 26
27 27 def reads(self, s, **kwargs):
28 28 nb = json.loads(s, **kwargs)
29 29 nb = self.to_notebook(nb, **kwargs)
30 30 return nb
31 31
32 32 def to_notebook(self, d, **kwargs):
33 return rejoin_lines(from_dict(d))
33 nb = rejoin_lines(from_dict(d))
34 nb = strip_transient(nb)
35 return nb
34 36
35 37
36 38 class JSONWriter(NotebookWriter):
37 39
38 40 def writes(self, nb, **kwargs):
39 41 kwargs['cls'] = BytesEncoder
40 42 kwargs['indent'] = 1
41 43 kwargs['sort_keys'] = True
42 44 kwargs['separators'] = (',',': ')
45 # don't modify in-memory dict
46 nb = copy.deepcopy(nb)
43 47 if kwargs.pop('split_lines', True):
44 nb = split_lines(copy.deepcopy(nb))
48 nb = split_lines(nb)
49 nb = strip_transient(nb)
45 50 return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8')
46 51
47 52
48 53 _reader = JSONReader()
49 54 _writer = JSONWriter()
50 55
51 56 reads = _reader.reads
52 57 read = _reader.read
53 58 to_notebook = _reader.to_notebook
54 59 write = _writer.write
55 60 writes = _writer.writes
@@ -1,106 +1,118 b''
1 1 """Base classes and utilities for readers and writers."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 from IPython.utils import py3compat
7 7 from IPython.utils.py3compat import unicode_type, string_types
8 8
9 9 # output keys that are likely to have multiline values
10 10 _multiline_outputs = {
11 11 'text/plain',
12 12 'text/html',
13 13 'image/svg+xml',
14 14 'text/latex',
15 15 'application/javascript',
16 16 }
17 17
18 18
19 19 # FIXME: workaround for old splitlines()
20 20 def _join_lines(lines):
21 21 """join lines that have been written by splitlines()
22 22
23 23 Has logic to protect against `splitlines()`, which
24 24 should have been `splitlines(True)`
25 25 """
26 26 if lines and lines[0].endswith(('\n', '\r')):
27 27 # created by splitlines(True)
28 28 return u''.join(lines)
29 29 else:
30 30 # created by splitlines()
31 31 return u'\n'.join(lines)
32 32
33 33
34 34 def rejoin_lines(nb):
35 35 """rejoin multiline text into strings
36 36
37 37 For reversing effects of ``split_lines(nb)``.
38 38
39 39 This only rejoins lines that have been split, so if text objects were not split
40 40 they will pass through unchanged.
41 41
42 42 Used when reading JSON files that may have been passed through split_lines.
43 43 """
44 44 for cell in nb.cells:
45 45 if 'source' in cell and isinstance(cell.source, list):
46 46 cell.source = _join_lines(cell.source)
47 47 if cell.cell_type == 'code':
48 48 for output in cell.outputs:
49 49 for key in _multiline_outputs:
50 50 item = output.get(key, None)
51 51 if isinstance(item, list):
52 52 output[key] = _join_lines(item)
53 53 return nb
54 54
55 55
56 56 def split_lines(nb):
57 57 """split likely multiline text into lists of strings
58 58
59 59 For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will
60 60 reverse the effects of ``split_lines(nb)``.
61 61
62 62 Used when writing JSON files.
63 63 """
64 64 for cell in nb.cells:
65 65 source = cell.get('source', None)
66 66 if isinstance(source, string_types):
67 67 cell['source'] = source.splitlines(True)
68 68
69 69 if cell.cell_type == 'code':
70 70 for output in cell.outputs:
71 71 for key in _multiline_outputs:
72 72 item = output.get(key, None)
73 73 if isinstance(item, string_types):
74 74 output[key] = item.splitlines(True)
75 75 return nb
76 76
77 77
78 def strip_transient(nb):
79 """Strip transient values that shouldn't be stored in files.
80
81 This should be called in *both* read and write.
82 """
83 nb.metadata.pop('orig_nbformat', None)
84 nb.metadata.pop('orig_nbformat_minor', None)
85 for cell in nb.cells:
86 cell.metadata.pop('trusted', None)
87 return nb
88
89
78 90 class NotebookReader(object):
79 91 """A class for reading notebooks."""
80 92
81 93 def reads(self, s, **kwargs):
82 94 """Read a notebook from a string."""
83 95 raise NotImplementedError("loads must be implemented in a subclass")
84 96
85 97 def read(self, fp, **kwargs):
86 98 """Read a notebook from a file like object"""
87 99 nbs = fp.read()
88 100 if not py3compat.PY3 and not isinstance(nbs, unicode_type):
89 101 nbs = py3compat.str_to_unicode(nbs)
90 102 return self.reads(nbs, **kwargs)
91 103
92 104
93 105 class NotebookWriter(object):
94 106 """A class for writing notebooks."""
95 107
96 108 def writes(self, nb, **kwargs):
97 109 """Write a notebook to a string."""
98 110 raise NotImplementedError("loads must be implemented in a subclass")
99 111
100 112 def write(self, nb, fp, **kwargs):
101 113 """Write a notebook to a file like object"""
102 114 nbs = self.writes(nb,**kwargs)
103 115 if not py3compat.PY3 and not isinstance(nbs, unicode_type):
104 116 # this branch is likely only taken for JSON on Python 2
105 117 nbs = py3compat.str_to_unicode(nbs)
106 118 return fp.write(nbs)
General Comments 0
You need to be logged in to leave comments. Login now