Show More
@@ -0,0 +1,164 b'' | |||||
|
1 | { | |||
|
2 | "metadata": { | |||
|
3 | "cell_tags": [ | |||
|
4 | [ | |||
|
5 | "<None>", | |||
|
6 | null | |||
|
7 | ] | |||
|
8 | ], | |||
|
9 | "name": "" | |||
|
10 | }, | |||
|
11 | "nbformat": 3, | |||
|
12 | "nbformat_minor": 5, | |||
|
13 | "extra": 5, | |||
|
14 | "worksheets": [ | |||
|
15 | { | |||
|
16 | "cells": [ | |||
|
17 | { | |||
|
18 | "cell_type": "heading", | |||
|
19 | "level": 1, | |||
|
20 | "metadata": {}, | |||
|
21 | "source": [ | |||
|
22 | "nbconvert latex test" | |||
|
23 | ] | |||
|
24 | }, | |||
|
25 | { | |||
|
26 | "cell_type": "markdown", | |||
|
27 | "extra_key": ["list"], | |||
|
28 | "metadata": {}, | |||
|
29 | "source": [ | |||
|
30 | "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis." | |||
|
31 | ] | |||
|
32 | }, | |||
|
33 | { | |||
|
34 | "cell_type": "heading", | |||
|
35 | "level": 2, | |||
|
36 | "metadata": {}, | |||
|
37 | "another_attr": {}, | |||
|
38 | "source": [ | |||
|
39 | "Printed Using Python" | |||
|
40 | ] | |||
|
41 | }, | |||
|
42 | { | |||
|
43 | "cell_type": "code", | |||
|
44 | "collapsed": false, | |||
|
45 | "key": "value", | |||
|
46 | "input": [ | |||
|
47 | "print(\"hello\")" | |||
|
48 | ], | |||
|
49 | "language": "python", | |||
|
50 | "metadata": {}, | |||
|
51 | "outputs": [ | |||
|
52 | { | |||
|
53 | "output_type": "stream", | |||
|
54 | "meta": 5, | |||
|
55 | "stream": "stdout", | |||
|
56 | "text": [ | |||
|
57 | "hello\n" | |||
|
58 | ] | |||
|
59 | } | |||
|
60 | ], | |||
|
61 | "prompt_number": 1 | |||
|
62 | }, | |||
|
63 | { | |||
|
64 | "cell_type": "heading", | |||
|
65 | "level": 2, | |||
|
66 | "metadata": {}, | |||
|
67 | "source": [ | |||
|
68 | "Pyout" | |||
|
69 | ] | |||
|
70 | }, | |||
|
71 | { | |||
|
72 | "cell_type": "code", | |||
|
73 | "collapsed": false, | |||
|
74 | "input": [ | |||
|
75 | "from IPython.display import HTML\n", | |||
|
76 | "HTML(\"\"\"\n", | |||
|
77 | "<script>\n", | |||
|
78 | "console.log(\"hello\");\n", | |||
|
79 | "</script>\n", | |||
|
80 | "<b>HTML</b>\n", | |||
|
81 | "\"\"\")" | |||
|
82 | ], | |||
|
83 | "language": "python", | |||
|
84 | "metadata": {}, | |||
|
85 | "outputs": [ | |||
|
86 | { | |||
|
87 | "html": [ | |||
|
88 | "\n", | |||
|
89 | "<script>\n", | |||
|
90 | "console.log(\"hello\");\n", | |||
|
91 | "</script>\n", | |||
|
92 | "<b>HTML</b>\n" | |||
|
93 | ], | |||
|
94 | "metadata": {}, | |||
|
95 | "output_type": "pyout", | |||
|
96 | "key": "value", | |||
|
97 | "prompt_number": 3, | |||
|
98 | "text": [ | |||
|
99 | "<IPython.core.display.HTML at 0x1112757d0>" | |||
|
100 | ] | |||
|
101 | } | |||
|
102 | ], | |||
|
103 | "prompt_number": 3 | |||
|
104 | }, | |||
|
105 | { | |||
|
106 | "cell_type": "code", | |||
|
107 | "collapsed": false, | |||
|
108 | "input": [ | |||
|
109 | "%%javascript\n", | |||
|
110 | "console.log(\"hi\");" | |||
|
111 | ], | |||
|
112 | "language": "python", | |||
|
113 | "metadata": {}, | |||
|
114 | "outputs": [ | |||
|
115 | { | |||
|
116 | "javascript": [ | |||
|
117 | "console.log(\"hi\");" | |||
|
118 | ], | |||
|
119 | "metadata": {}, | |||
|
120 | "output_type": "display_data", | |||
|
121 | "text": [ | |||
|
122 | "<IPython.core.display.Javascript at 0x1112b4b50>" | |||
|
123 | ] | |||
|
124 | } | |||
|
125 | ], | |||
|
126 | "prompt_number": 7 | |||
|
127 | }, | |||
|
128 | { | |||
|
129 | "cell_type": "heading", | |||
|
130 | "level": 3, | |||
|
131 | "metadata": {}, | |||
|
132 | "source": [ | |||
|
133 | "Image" | |||
|
134 | ] | |||
|
135 | }, | |||
|
136 | { | |||
|
137 | "cell_type": "code", | |||
|
138 | "collapsed": false, | |||
|
139 | "input": [ | |||
|
140 | "from IPython.display import Image\n", | |||
|
141 | "Image(\"http://ipython.org/_static/IPy_header.png\")" | |||
|
142 | ], | |||
|
143 | "language": "python", | |||
|
144 | "metadata": {}, | |||
|
145 | "outputs": [ | |||
|
146 | { | |||
|
147 | "metadata": {}, | |||
|
148 | "output_type": "pyout", | |||
|
149 | "more": "data", | |||
|
150 | "png": "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\n", | |||
|
151 | "prompt_number": 6, | |||
|
152 | "text": [ | |||
|
153 | "<IPython.core.display.Image at 0x111275490>" | |||
|
154 | ] | |||
|
155 | } | |||
|
156 | ], | |||
|
157 | "prompt_number": 6 | |||
|
158 | } | |||
|
159 | ], | |||
|
160 | "keys": ["value", "s"], | |||
|
161 | "metadata": {} | |||
|
162 | } | |||
|
163 | ] | |||
|
164 | } No newline at end of file |
@@ -0,0 +1,363 b'' | |||||
|
1 | { | |||
|
2 | "$schema": "http://json-schema.org/draft-04/schema#", | |||
|
3 | "description": "IPython Notebook v3.0 JSON schema.", | |||
|
4 | "type": "object", | |||
|
5 | "additionalProperties": false, | |||
|
6 | "required": ["metadata", "nbformat_minor", "nbformat", "worksheets"], | |||
|
7 | "properties": { | |||
|
8 | "metadata": { | |||
|
9 | "description": "Notebook root-level metadata.", | |||
|
10 | "type": "object", | |||
|
11 | "additionalProperties": true, | |||
|
12 | "properties": { | |||
|
13 | "kernel_info": { | |||
|
14 | "description": "Kernel information.", | |||
|
15 | "type": "object", | |||
|
16 | "required": ["name", "language"], | |||
|
17 | "properties": { | |||
|
18 | "name": { | |||
|
19 | "description": "Name of the kernel specification.", | |||
|
20 | "type": "string" | |||
|
21 | }, | |||
|
22 | "language": { | |||
|
23 | "description": "The programming language which this kernel runs.", | |||
|
24 | "type": "string" | |||
|
25 | }, | |||
|
26 | "codemirror_mode": { | |||
|
27 | "description": "The codemirror mode to use for code in this language.", | |||
|
28 | "type": "string" | |||
|
29 | } | |||
|
30 | } | |||
|
31 | }, | |||
|
32 | "signature": { | |||
|
33 | "description": "Hash of the notebook.", | |||
|
34 | "type": "string" | |||
|
35 | } | |||
|
36 | } | |||
|
37 | }, | |||
|
38 | "nbformat_minor": { | |||
|
39 | "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.", | |||
|
40 | "type": "integer", | |||
|
41 | "minimum": 0 | |||
|
42 | }, | |||
|
43 | "nbformat": { | |||
|
44 | "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.", | |||
|
45 | "type": "integer", | |||
|
46 | "minimum": 3, | |||
|
47 | "maximum": 3 | |||
|
48 | }, | |||
|
49 | "orig_nbformat": { | |||
|
50 | "description": "Original notebook format (major number) before converting the notebook between versions.", | |||
|
51 | "type": "integer", | |||
|
52 | "minimum": 1 | |||
|
53 | }, | |||
|
54 | "worksheets" : { | |||
|
55 | "description": "Array of worksheets", | |||
|
56 | "type": "array", | |||
|
57 | "items": {"$ref": "#/definitions/worksheet"} | |||
|
58 | } | |||
|
59 | }, | |||
|
60 | ||||
|
61 | "definitions": { | |||
|
62 | "worksheet": { | |||
|
63 | "additionalProperties": false, | |||
|
64 | "required" : ["cells"], | |||
|
65 | "properties":{ | |||
|
66 | "cells": { | |||
|
67 | "description": "Array of cells of the current notebook.", | |||
|
68 | "type": "array", | |||
|
69 | "items": { | |||
|
70 | "type": "object", | |||
|
71 | "oneOf": [ | |||
|
72 | {"$ref": "#/definitions/raw_cell"}, | |||
|
73 | {"$ref": "#/definitions/markdown_cell"}, | |||
|
74 | {"$ref": "#/definitions/heading_cell"}, | |||
|
75 | {"$ref": "#/definitions/code_cell"} | |||
|
76 | ] | |||
|
77 | } | |||
|
78 | }, | |||
|
79 | "metadata": { | |||
|
80 | "type": "object", | |||
|
81 | "description": "metadata of the current worksheet" | |||
|
82 | } | |||
|
83 | } | |||
|
84 | }, | |||
|
85 | "raw_cell": { | |||
|
86 | "description": "Notebook raw nbconvert cell.", | |||
|
87 | "type": "object", | |||
|
88 | "additionalProperties": false, | |||
|
89 | "required": ["cell_type", "source"], | |||
|
90 | "properties": { | |||
|
91 | "cell_type": { | |||
|
92 | "description": "String identifying the type of cell.", | |||
|
93 | "enum": ["raw"] | |||
|
94 | }, | |||
|
95 | "metadata": { | |||
|
96 | "description": "Cell-level metadata.", | |||
|
97 | "type": "object", | |||
|
98 | "additionalProperties": true, | |||
|
99 | "properties": { | |||
|
100 | "format": { | |||
|
101 | "description": "Raw cell metadata format for nbconvert.", | |||
|
102 | "type": "string" | |||
|
103 | }, | |||
|
104 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |||
|
105 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |||
|
106 | } | |||
|
107 | }, | |||
|
108 | "source": {"$ref": "#/definitions/misc/source"} | |||
|
109 | } | |||
|
110 | }, | |||
|
111 | ||||
|
112 | "markdown_cell": { | |||
|
113 | "description": "Notebook markdown cell.", | |||
|
114 | "type": "object", | |||
|
115 | "additionalProperties": false, | |||
|
116 | "required": ["cell_type", "source"], | |||
|
117 | "properties": { | |||
|
118 | "cell_type": { | |||
|
119 | "description": "String identifying the type of cell.", | |||
|
120 | "enum": ["markdown", "html"] | |||
|
121 | }, | |||
|
122 | "metadata": { | |||
|
123 | "description": "Cell-level metadata.", | |||
|
124 | "type": "object", | |||
|
125 | "properties": { | |||
|
126 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |||
|
127 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |||
|
128 | }, | |||
|
129 | "additionalProperties": true | |||
|
130 | }, | |||
|
131 | "source": {"$ref": "#/definitions/misc/source"} | |||
|
132 | } | |||
|
133 | }, | |||
|
134 | ||||
|
135 | "heading_cell": { | |||
|
136 | "description": "Notebook heading cell.", | |||
|
137 | "type": "object", | |||
|
138 | "additionalProperties": false, | |||
|
139 | "required": ["cell_type", "source", "level"], | |||
|
140 | "properties": { | |||
|
141 | "cell_type": { | |||
|
142 | "description": "String identifying the type of cell.", | |||
|
143 | "enum": ["heading"] | |||
|
144 | }, | |||
|
145 | "metadata": { | |||
|
146 | "description": "Cell-level metadata.", | |||
|
147 | "type": "object", | |||
|
148 | "additionalProperties": true | |||
|
149 | }, | |||
|
150 | "source": {"$ref": "#/definitions/misc/source"}, | |||
|
151 | "level": { | |||
|
152 | "description": "Level of heading cells.", | |||
|
153 | "type": "integer", | |||
|
154 | "minimum": 1 | |||
|
155 | } | |||
|
156 | } | |||
|
157 | }, | |||
|
158 | ||||
|
159 | "code_cell": { | |||
|
160 | "description": "Notebook code cell.", | |||
|
161 | "type": "object", | |||
|
162 | "additionalProperties": false, | |||
|
163 | "required": ["cell_type", "input", "outputs", "language"], | |||
|
164 | "properties": { | |||
|
165 | "cell_type": { | |||
|
166 | "description": "String identifying the type of cell.", | |||
|
167 | "enum": ["code"] | |||
|
168 | }, | |||
|
169 | "language": { | |||
|
170 | "description": "The cell's language (always Python)", | |||
|
171 | "type": "string" | |||
|
172 | }, | |||
|
173 | "collapsed": { | |||
|
174 | "description": "Whether the cell is collapsed/expanded.", | |||
|
175 | "type": "boolean" | |||
|
176 | }, | |||
|
177 | "metadata": { | |||
|
178 | "description": "Cell-level metadata.", | |||
|
179 | "type": "object", | |||
|
180 | "additionalProperties": true | |||
|
181 | }, | |||
|
182 | "input": {"$ref": "#/definitions/misc/source"}, | |||
|
183 | "outputs": { | |||
|
184 | "description": "Execution, display, or stream outputs.", | |||
|
185 | "type": "array", | |||
|
186 | "items": {"$ref": "#/definitions/output"} | |||
|
187 | }, | |||
|
188 | "prompt_number": { | |||
|
189 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", | |||
|
190 | "type": ["integer", "null"], | |||
|
191 | "minimum": 0 | |||
|
192 | } | |||
|
193 | } | |||
|
194 | }, | |||
|
195 | "output": { | |||
|
196 | "type": "object", | |||
|
197 | "oneOf": [ | |||
|
198 | {"$ref": "#/definitions/pyout"}, | |||
|
199 | {"$ref": "#/definitions/display_data"}, | |||
|
200 | {"$ref": "#/definitions/stream"}, | |||
|
201 | {"$ref": "#/definitions/pyerr"} | |||
|
202 | ] | |||
|
203 | }, | |||
|
204 | "pyout": { | |||
|
205 | "description": "Result of executing a code cell.", | |||
|
206 | "type": "object", | |||
|
207 | "additionalProperties": false, | |||
|
208 | "required": ["output_type", "prompt_number"], | |||
|
209 | "properties": { | |||
|
210 | "output_type": { | |||
|
211 | "description": "Type of cell output.", | |||
|
212 | "enum": ["pyout"] | |||
|
213 | }, | |||
|
214 | "prompt_number": { | |||
|
215 | "description": "A result's prompt number.", | |||
|
216 | "type": ["integer"], | |||
|
217 | "minimum": 0 | |||
|
218 | }, | |||
|
219 | "text": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
220 | "latex": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
221 | "png": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
222 | "jpeg": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
223 | "svg": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
224 | "html": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
225 | "javascript": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
226 | "json": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
227 | "pdf": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
228 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} | |||
|
229 | }, | |||
|
230 | "patternProperties": { | |||
|
231 | "^[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { | |||
|
232 | "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", | |||
|
233 | "$ref": "#/definitions/misc/multiline_string" | |||
|
234 | } | |||
|
235 | } | |||
|
236 | }, | |||
|
237 | ||||
|
238 | "display_data": { | |||
|
239 | "description": "Data displayed as a result of code cell execution.", | |||
|
240 | "type": "object", | |||
|
241 | "additionalProperties": false, | |||
|
242 | "required": ["output_type"], | |||
|
243 | "properties": { | |||
|
244 | "output_type": { | |||
|
245 | "description": "Type of cell output.", | |||
|
246 | "enum": ["display_data"] | |||
|
247 | }, | |||
|
248 | "text": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
249 | "latex": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
250 | "png": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
251 | "jpeg": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
252 | "svg": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
253 | "html": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
254 | "javascript": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
255 | "json": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
256 | "pdf": {"$ref": "#/definitions/misc/multiline_string"}, | |||
|
257 | "metadata": {"$ref": "#/definitions/misc/output_metadata"} | |||
|
258 | }, | |||
|
259 | "patternProperties": { | |||
|
260 | "[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": { | |||
|
261 | "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.", | |||
|
262 | "$ref": "#/definitions/misc/multiline_string" | |||
|
263 | } | |||
|
264 | } | |||
|
265 | }, | |||
|
266 | ||||
|
267 | "stream": { | |||
|
268 | "description": "Stream output from a code cell.", | |||
|
269 | "type": "object", | |||
|
270 | "additionalProperties": false, | |||
|
271 | "required": ["output_type", "stream", "text"], | |||
|
272 | "properties": { | |||
|
273 | "output_type": { | |||
|
274 | "description": "Type of cell output.", | |||
|
275 | "enum": ["stream"] | |||
|
276 | }, | |||
|
277 | "stream": { | |||
|
278 | "description": "The stream type/destination.", | |||
|
279 | "type": "string" | |||
|
280 | }, | |||
|
281 | "text": { | |||
|
282 | "description": "The stream's text output, represented as an array of strings.", | |||
|
283 | "$ref": "#/definitions/misc/multiline_string" | |||
|
284 | } | |||
|
285 | } | |||
|
286 | }, | |||
|
287 | ||||
|
288 | "pyerr": { | |||
|
289 | "description": "Output of an error that occurred during code cell execution.", | |||
|
290 | "type": "object", | |||
|
291 | "additionalProperties": false, | |||
|
292 | "required": ["output_type", "ename", "evalue", "traceback"], | |||
|
293 | "properties": { | |||
|
294 | "output_type": { | |||
|
295 | "description": "Type of cell output.", | |||
|
296 | "enum": ["pyerr"] | |||
|
297 | }, | |||
|
298 | "metadata": {"$ref": "#/definitions/misc/output_metadata"}, | |||
|
299 | "ename": { | |||
|
300 | "description": "The name of the error.", | |||
|
301 | "type": "string" | |||
|
302 | }, | |||
|
303 | "evalue": { | |||
|
304 | "description": "The value, or message, of the error.", | |||
|
305 | "type": "string" | |||
|
306 | }, | |||
|
307 | "traceback": { | |||
|
308 | "description": "The error's traceback, represented as an array of strings.", | |||
|
309 | "type": "array", | |||
|
310 | "items": {"type": "string"} | |||
|
311 | } | |||
|
312 | } | |||
|
313 | }, | |||
|
314 | ||||
|
315 | "misc": { | |||
|
316 | "metadata_name": { | |||
|
317 | "description": "The cell's name. If present, must be a non-empty string.", | |||
|
318 | "type": "string", | |||
|
319 | "pattern": "^.+$" | |||
|
320 | }, | |||
|
321 | "metadata_tags": { | |||
|
322 | "description": "The cell's tags. Tags must be unique, and must not contain commas.", | |||
|
323 | "type": "array", | |||
|
324 | "uniqueItems": true, | |||
|
325 | "items": { | |||
|
326 | "type": "string", | |||
|
327 | "pattern": "^[^,]+$" | |||
|
328 | } | |||
|
329 | }, | |||
|
330 | "source": { | |||
|
331 | "description": "Contents of the cell, represented as an array of lines.", | |||
|
332 | "$ref": "#/definitions/misc/multiline_string" | |||
|
333 | }, | |||
|
334 | "prompt_number": { | |||
|
335 | "description": "The code cell's prompt number. Will be null if the cell has not been run.", | |||
|
336 | "type": ["integer", "null"], | |||
|
337 | "minimum": 0 | |||
|
338 | }, | |||
|
339 | "mimetype": { | |||
|
340 | "patternProperties": { | |||
|
341 | "^[a-zA-Z0-9\\-\\+]+/[a-zA-Z0-9\\-\\+]+": { | |||
|
342 | "description": "The cell's mimetype output (e.g. text/plain), represented as either an array of strings or a string.", | |||
|
343 | "$ref": "#/definitions/misc/multiline_string" | |||
|
344 | } | |||
|
345 | } | |||
|
346 | }, | |||
|
347 | "output_metadata": { | |||
|
348 | "description": "Cell output metadata.", | |||
|
349 | "type": "object", | |||
|
350 | "additionalProperties": true | |||
|
351 | }, | |||
|
352 | "multiline_string": { | |||
|
353 | "oneOf" : [ | |||
|
354 | {"type": "string"}, | |||
|
355 | { | |||
|
356 | "type": "array", | |||
|
357 | "items": {"type": "string"} | |||
|
358 | } | |||
|
359 | ] | |||
|
360 | } | |||
|
361 | } | |||
|
362 | } | |||
|
363 | } |
@@ -176,6 +176,7 b' class FileContentsManager(ContentsManager):' | |||||
176 | model['created'] = created |
|
176 | model['created'] = created | |
177 | model['content'] = None |
|
177 | model['content'] = None | |
178 | model['format'] = None |
|
178 | model['format'] = None | |
|
179 | model['message'] = None | |||
179 | return model |
|
180 | return model | |
180 |
|
181 | |||
181 | def _dir_model(self, name, path='', content=True): |
|
182 | def _dir_model(self, name, path='', content=True): | |
@@ -258,6 +259,7 b' class FileContentsManager(ContentsManager):' | |||||
258 | self.mark_trusted_cells(nb, name, path) |
|
259 | self.mark_trusted_cells(nb, name, path) | |
259 | model['content'] = nb |
|
260 | model['content'] = nb | |
260 | model['format'] = 'json' |
|
261 | model['format'] = 'json' | |
|
262 | self.validate_notebook_model(model) | |||
261 | return model |
|
263 | return model | |
262 |
|
264 | |||
263 | def get_model(self, name, path='', content=True): |
|
265 | def get_model(self, name, path='', content=True): | |
@@ -301,7 +303,7 b' class FileContentsManager(ContentsManager):' | |||||
301 | nb['metadata']['name'] = u'' |
|
303 | nb['metadata']['name'] = u'' | |
302 |
|
304 | |||
303 | with atomic_writing(os_path, encoding='utf-8') as f: |
|
305 | with atomic_writing(os_path, encoding='utf-8') as f: | |
304 |
current.write(nb, f, |
|
306 | current.write(nb, f, version=nb.nbformat) | |
305 |
|
307 | |||
306 | def _save_file(self, os_path, model, name='', path=''): |
|
308 | def _save_file(self, os_path, model, name='', path=''): | |
307 | """save a non-notebook file""" |
|
309 | """save a non-notebook file""" | |
@@ -366,7 +368,14 b' class FileContentsManager(ContentsManager):' | |||||
366 | except Exception as e: |
|
368 | except Exception as e: | |
367 | raise web.HTTPError(400, u'Unexpected error while saving file: %s %s' % (os_path, e)) |
|
369 | raise web.HTTPError(400, u'Unexpected error while saving file: %s %s' % (os_path, e)) | |
368 |
|
370 | |||
|
371 | validation_message = None | |||
|
372 | if model['type'] == 'notebook': | |||
|
373 | self.validate_notebook_model(model) | |||
|
374 | validation_message = model.get('message', None) | |||
|
375 | ||||
369 | model = self.get_model(new_name, new_path, content=False) |
|
376 | model = self.get_model(new_name, new_path, content=False) | |
|
377 | if validation_message: | |||
|
378 | model['message'] = validation_message | |||
370 | return model |
|
379 | return model | |
371 |
|
380 | |||
372 | def update(self, model, name, path=''): |
|
381 | def update(self, model, name, path=''): |
@@ -5,6 +5,7 b'' | |||||
5 |
|
5 | |||
6 | from fnmatch import fnmatch |
|
6 | from fnmatch import fnmatch | |
7 | import itertools |
|
7 | import itertools | |
|
8 | import json | |||
8 | import os |
|
9 | import os | |
9 |
|
10 | |||
10 | from tornado.web import HTTPError |
|
11 | from tornado.web import HTTPError | |
@@ -216,6 +217,16 b' class ContentsManager(LoggingConfigurable):' | |||||
216 | break |
|
217 | break | |
217 | return name |
|
218 | return name | |
218 |
|
219 | |||
|
220 | def validate_notebook_model(self, model): | |||
|
221 | """Add failed-validation message to model""" | |||
|
222 | try: | |||
|
223 | current.validate(model['content']) | |||
|
224 | except current.ValidationError as e: | |||
|
225 | model['message'] = 'Notebook Validation failed: {}:\n{}'.format( | |||
|
226 | e.message, json.dumps(e.instance, indent=1, default=lambda obj: '<UNKNOWN>'), | |||
|
227 | ) | |||
|
228 | return model | |||
|
229 | ||||
219 | def create_file(self, model=None, path='', ext='.ipynb'): |
|
230 | def create_file(self, model=None, path='', ext='.ipynb'): | |
220 | """Create a new file or directory and return its model with no content.""" |
|
231 | """Create a new file or directory and return its model with no content.""" | |
221 | path = path.strip('/') |
|
232 | path = path.strip('/') | |
@@ -304,6 +315,8 b' class ContentsManager(LoggingConfigurable):' | |||||
304 | path : string |
|
315 | path : string | |
305 | The notebook's directory (for logging) |
|
316 | The notebook's directory (for logging) | |
306 | """ |
|
317 | """ | |
|
318 | if nb['nbformat'] != current.nbformat: | |||
|
319 | return | |||
307 | if self.notary.check_cells(nb): |
|
320 | if self.notary.check_cells(nb): | |
308 | self.notary.sign(nb) |
|
321 | self.notary.sign(nb) | |
309 | else: |
|
322 | else: |
@@ -311,13 +311,13 b' class TestContentsManager(TestCase):' | |||||
311 | cm.mark_trusted_cells(nb, name, path) |
|
311 | cm.mark_trusted_cells(nb, name, path) | |
312 | for cell in nb.worksheets[0].cells: |
|
312 | for cell in nb.worksheets[0].cells: | |
313 | if cell.cell_type == 'code': |
|
313 | if cell.cell_type == 'code': | |
314 | assert not cell.trusted |
|
314 | assert not cell.metadata.trusted | |
315 |
|
315 | |||
316 | cm.trust_notebook(name, path) |
|
316 | cm.trust_notebook(name, path) | |
317 | nb = cm.get_model(name, path)['content'] |
|
317 | nb = cm.get_model(name, path)['content'] | |
318 | for cell in nb.worksheets[0].cells: |
|
318 | for cell in nb.worksheets[0].cells: | |
319 | if cell.cell_type == 'code': |
|
319 | if cell.cell_type == 'code': | |
320 | assert cell.trusted |
|
320 | assert cell.metadata.trusted | |
321 |
|
321 | |||
322 | def test_check_and_sign(self): |
|
322 | def test_check_and_sign(self): | |
323 | cm = self.contents_manager |
|
323 | cm = self.contents_manager |
@@ -472,7 +472,7 b' define([' | |||||
472 | } else { |
|
472 | } else { | |
473 | this.set_input_prompt(); |
|
473 | this.set_input_prompt(); | |
474 | } |
|
474 | } | |
475 | this.output_area.trusted = data.trusted || false; |
|
475 | this.output_area.trusted = data.metadata.trusted || false; | |
476 | this.output_area.fromJSON(data.outputs); |
|
476 | this.output_area.fromJSON(data.outputs); | |
477 | if (data.collapsed !== undefined) { |
|
477 | if (data.collapsed !== undefined) { | |
478 | if (data.collapsed) { |
|
478 | if (data.collapsed) { | |
@@ -495,8 +495,8 b' define([' | |||||
495 | var outputs = this.output_area.toJSON(); |
|
495 | var outputs = this.output_area.toJSON(); | |
496 | data.outputs = outputs; |
|
496 | data.outputs = outputs; | |
497 | data.language = 'python'; |
|
497 | data.language = 'python'; | |
498 | data.trusted = this.output_area.trusted; |
|
498 | data.metadata.trusted = this.output_area.trusted; | |
499 | data.collapsed = this.collapsed; |
|
499 | data.collapsed = this.output_area.collapsed; | |
500 | return data; |
|
500 | return data; | |
501 | }; |
|
501 | }; | |
502 |
|
502 |
@@ -1792,6 +1792,7 b' define([' | |||||
1792 | * @param {Object} data JSON representation of a notebook |
|
1792 | * @param {Object} data JSON representation of a notebook | |
1793 | */ |
|
1793 | */ | |
1794 | Notebook.prototype.fromJSON = function (data) { |
|
1794 | Notebook.prototype.fromJSON = function (data) { | |
|
1795 | ||||
1795 | var content = data.content; |
|
1796 | var content = data.content; | |
1796 | var ncells = this.ncells(); |
|
1797 | var ncells = this.ncells(); | |
1797 | var i; |
|
1798 | var i; | |
@@ -1941,6 +1942,7 b' define([' | |||||
1941 | type : "PUT", |
|
1942 | type : "PUT", | |
1942 | data : JSON.stringify(model), |
|
1943 | data : JSON.stringify(model), | |
1943 | headers : {'Content-Type': 'application/json'}, |
|
1944 | headers : {'Content-Type': 'application/json'}, | |
|
1945 | dataType : "json", | |||
1944 | success : $.proxy(this.save_notebook_success, this, start), |
|
1946 | success : $.proxy(this.save_notebook_success, this, start), | |
1945 | error : $.proxy(this.save_notebook_error, this) |
|
1947 | error : $.proxy(this.save_notebook_error, this) | |
1946 | }; |
|
1948 | }; | |
@@ -1970,6 +1972,30 b' define([' | |||||
1970 | */ |
|
1972 | */ | |
1971 | Notebook.prototype.save_notebook_success = function (start, data, status, xhr) { |
|
1973 | Notebook.prototype.save_notebook_success = function (start, data, status, xhr) { | |
1972 | this.set_dirty(false); |
|
1974 | this.set_dirty(false); | |
|
1975 | if (data.message) { | |||
|
1976 | // save succeeded, but validation failed. | |||
|
1977 | var body = $("<div>"); | |||
|
1978 | var title = "Notebook validation failed"; | |||
|
1979 | ||||
|
1980 | body.append($("<p>").text( | |||
|
1981 | "The save operation succeeded," + | |||
|
1982 | " but the notebook does not appear to be valid." + | |||
|
1983 | " The validation error was:" | |||
|
1984 | )).append($("<div>").addClass("validation-error").append( | |||
|
1985 | $("<pre>").text(data.message) | |||
|
1986 | )); | |||
|
1987 | dialog.modal({ | |||
|
1988 | notebook: this, | |||
|
1989 | keyboard_manager: this.keyboard_manager, | |||
|
1990 | title: title, | |||
|
1991 | body: body, | |||
|
1992 | buttons : { | |||
|
1993 | OK : { | |||
|
1994 | "class" : "btn-primary" | |||
|
1995 | } | |||
|
1996 | } | |||
|
1997 | }); | |||
|
1998 | } | |||
1973 | this.events.trigger('notebook_saved.Notebook'); |
|
1999 | this.events.trigger('notebook_saved.Notebook'); | |
1974 | this._update_autosave_interval(start); |
|
2000 | this._update_autosave_interval(start); | |
1975 | if (this._checkpoint_after_save) { |
|
2001 | if (this._checkpoint_after_save) { | |
@@ -2244,7 +2270,57 b' define([' | |||||
2244 | * @param {jqXHR} xhr jQuery Ajax object |
|
2270 | * @param {jqXHR} xhr jQuery Ajax object | |
2245 | */ |
|
2271 | */ | |
2246 | Notebook.prototype.load_notebook_success = function (data, status, xhr) { |
|
2272 | Notebook.prototype.load_notebook_success = function (data, status, xhr) { | |
2247 | this.fromJSON(data); |
|
2273 | var failed; | |
|
2274 | try { | |||
|
2275 | this.fromJSON(data); | |||
|
2276 | } catch (e) { | |||
|
2277 | failed = e; | |||
|
2278 | console.log("Notebook failed to load from JSON:", e); | |||
|
2279 | } | |||
|
2280 | if (failed || data.message) { | |||
|
2281 | // *either* fromJSON failed or validation failed | |||
|
2282 | var body = $("<div>"); | |||
|
2283 | var title; | |||
|
2284 | if (failed) { | |||
|
2285 | title = "Notebook failed to load"; | |||
|
2286 | body.append($("<p>").text( | |||
|
2287 | "The error was: " | |||
|
2288 | )).append($("<div>").addClass("js-error").text( | |||
|
2289 | failed.toString() | |||
|
2290 | )).append($("<p>").text( | |||
|
2291 | "See the error console for details." | |||
|
2292 | )); | |||
|
2293 | } else { | |||
|
2294 | title = "Notebook validation failed"; | |||
|
2295 | } | |||
|
2296 | ||||
|
2297 | if (data.message) { | |||
|
2298 | var msg; | |||
|
2299 | if (failed) { | |||
|
2300 | msg = "The notebook also failed validation:" | |||
|
2301 | } else { | |||
|
2302 | msg = "An invalid notebook may not function properly." + | |||
|
2303 | " The validation error was:" | |||
|
2304 | } | |||
|
2305 | body.append($("<p>").text( | |||
|
2306 | msg | |||
|
2307 | )).append($("<div>").addClass("validation-error").append( | |||
|
2308 | $("<pre>").text(data.message) | |||
|
2309 | )); | |||
|
2310 | } | |||
|
2311 | ||||
|
2312 | dialog.modal({ | |||
|
2313 | notebook: this, | |||
|
2314 | keyboard_manager: this.keyboard_manager, | |||
|
2315 | title: title, | |||
|
2316 | body: body, | |||
|
2317 | buttons : { | |||
|
2318 | OK : { | |||
|
2319 | "class" : "btn-primary" | |||
|
2320 | } | |||
|
2321 | } | |||
|
2322 | }); | |||
|
2323 | } | |||
2248 | if (this.ncells() === 0) { |
|
2324 | if (this.ncells() === 0) { | |
2249 | this.insert_cell_below('code'); |
|
2325 | this.insert_cell_below('code'); | |
2250 | this.edit_mode(0); |
|
2326 | this.edit_mode(0); |
@@ -4,6 +4,7 b' from .slides import SlidesExporter' | |||||
4 | from .templateexporter import TemplateExporter |
|
4 | from .templateexporter import TemplateExporter | |
5 | from .latex import LatexExporter |
|
5 | from .latex import LatexExporter | |
6 | from .markdown import MarkdownExporter |
|
6 | from .markdown import MarkdownExporter | |
|
7 | from .notebook import NotebookExporter | |||
7 | from .pdf import PDFExporter |
|
8 | from .pdf import PDFExporter | |
8 | from .python import PythonExporter |
|
9 | from .python import PythonExporter | |
9 | from .rst import RSTExporter |
|
10 | from .rst import RSTExporter |
@@ -5,11 +5,18 b'' | |||||
5 |
|
5 | |||
6 | from .exporter import Exporter |
|
6 | from .exporter import Exporter | |
7 | from IPython.nbformat import current as nbformat |
|
7 | from IPython.nbformat import current as nbformat | |
|
8 | from IPython.utils.traitlets import Enum | |||
8 |
|
9 | |||
9 | class NotebookExporter(Exporter): |
|
10 | class NotebookExporter(Exporter): | |
10 | """ |
|
11 | """Exports to an IPython notebook.""" | |
11 | Exports an IPython notebook. |
|
12 | ||
12 | """ |
|
13 | nbformat_version = Enum(list(range(2, nbformat.current_nbformat + 1)), | |
|
14 | default_value=nbformat.current_nbformat, | |||
|
15 | config=True, | |||
|
16 | help="""The nbformat version to write. | |||
|
17 | Use this to downgrade notebooks. | |||
|
18 | """ | |||
|
19 | ) | |||
13 | def _file_extension_default(self): |
|
20 | def _file_extension_default(self): | |
14 | return 'ipynb' |
|
21 | return 'ipynb' | |
15 |
|
22 | |||
@@ -17,5 +24,9 b' class NotebookExporter(Exporter):' | |||||
17 |
|
24 | |||
18 | def from_notebook_node(self, nb, resources=None, **kw): |
|
25 | def from_notebook_node(self, nb, resources=None, **kw): | |
19 | nb_copy, resources = super(NotebookExporter, self).from_notebook_node(nb, resources, **kw) |
|
26 | nb_copy, resources = super(NotebookExporter, self).from_notebook_node(nb, resources, **kw) | |
20 | output = nbformat.writes_json(nb_copy) |
|
27 | if self.nbformat_version != nbformat.current_nbformat: | |
|
28 | resources['output_suffix'] = '.v%i' % self.nbformat_version | |||
|
29 | else: | |||
|
30 | resources['output_suffix'] = '.nbconvert' | |||
|
31 | output = nbformat.writes(nb_copy, version=self.nbformat_version) | |||
21 | return output, resources |
|
32 | return output, resources |
@@ -3,9 +3,13 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 | import json | |||
|
7 | ||||
6 | from .base import ExportersTestsBase |
|
8 | from .base import ExportersTestsBase | |
7 | from ..notebook import NotebookExporter |
|
9 | from ..notebook import NotebookExporter | |
8 |
|
10 | |||
|
11 | from IPython.testing.tools import assert_big_text_equal | |||
|
12 | ||||
9 | class TestNotebookExporter(ExportersTestsBase): |
|
13 | class TestNotebookExporter(ExportersTestsBase): | |
10 | """Contains test functions for notebook.py""" |
|
14 | """Contains test functions for notebook.py""" | |
11 |
|
15 | |||
@@ -17,6 +21,18 b' class TestNotebookExporter(ExportersTestsBase):' | |||||
17 | """ |
|
21 | """ | |
18 | with open(self._get_notebook()) as f: |
|
22 | with open(self._get_notebook()) as f: | |
19 | file_contents = f.read() |
|
23 | file_contents = f.read() | |
20 |
(output, resources) = |
|
24 | (output, resources) = self.exporter_class().from_filename(self._get_notebook()) | |
21 | assert len(output) > 0 |
|
25 | assert len(output) > 0 | |
22 |
assert |
|
26 | assert_big_text_equal(output, file_contents) | |
|
27 | ||||
|
28 | def test_downgrade_3(self): | |||
|
29 | exporter = self.exporter_class(nbformat_version=3) | |||
|
30 | (output, resources) = exporter.from_filename(self._get_notebook()) | |||
|
31 | nb = json.loads(output) | |||
|
32 | self.assertEqual(nb['nbformat'], 3) | |||
|
33 | ||||
|
34 | def test_downgrade_2(self): | |||
|
35 | exporter = self.exporter_class(nbformat_version=2) | |||
|
36 | (output, resources) = exporter.from_filename(self._get_notebook()) | |||
|
37 | nb = json.loads(output) | |||
|
38 | self.assertEqual(nb['nbformat'], 2) |
@@ -53,6 +53,7 b' nbconvert_aliases.update({' | |||||
53 | 'post': 'NbConvertApp.postprocessor_class', |
|
53 | 'post': 'NbConvertApp.postprocessor_class', | |
54 | 'output': 'NbConvertApp.output_base', |
|
54 | 'output': 'NbConvertApp.output_base', | |
55 | 'reveal-prefix': 'RevealHelpPreprocessor.url_prefix', |
|
55 | 'reveal-prefix': 'RevealHelpPreprocessor.url_prefix', | |
|
56 | 'nbformat': 'NotebookExporter.nbformat_version', | |||
56 | }) |
|
57 | }) | |
57 |
|
58 | |||
58 | nbconvert_flags = {} |
|
59 | nbconvert_flags = {} | |
@@ -92,7 +93,7 b' class NbConvertApp(BaseIPythonApplication):' | |||||
92 | WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""") |
|
93 | WARNING: THE COMMANDLINE INTERFACE MAY CHANGE IN FUTURE RELEASES.""") | |
93 |
|
94 | |||
94 | output_base = Unicode('', config=True, help='''overwrite base name use for output files. |
|
95 | output_base = Unicode('', config=True, help='''overwrite base name use for output files. | |
95 |
can only |
|
96 | can only be used when converting one notebook at a time. | |
96 | ''') |
|
97 | ''') | |
97 |
|
98 | |||
98 | examples = Unicode(u""" |
|
99 | examples = Unicode(u""" | |
@@ -298,6 +299,8 b' class NbConvertApp(BaseIPythonApplication):' | |||||
298 | exc_info=True) |
|
299 | exc_info=True) | |
299 | self.exit(1) |
|
300 | self.exit(1) | |
300 | else: |
|
301 | else: | |
|
302 | if 'output_suffix' in resources and not self.output_base: | |||
|
303 | notebook_name += resources['output_suffix'] | |||
301 | write_results = self.writer.write(output, resources, notebook_name=notebook_name) |
|
304 | write_results = self.writer.write(output, resources, notebook_name=notebook_name) | |
302 |
|
305 | |||
303 | #Post-process if post processor has been defined. |
|
306 | #Post-process if post processor has been defined. |
@@ -1,27 +1,14 b'' | |||||
1 | """ |
|
1 | """Tests for the coalescestreams preprocessor""" | |
2 | Module with tests for the coalescestreams preprocessor |
|
|||
3 | """ |
|
|||
4 |
|
2 | |||
5 | #----------------------------------------------------------------------------- |
|
3 | # Copyright (c) IPython Development Team. | |
6 | # Copyright (c) 2013, the IPython Development Team. |
|
|||
7 | # |
|
|||
8 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
9 | # |
|
|||
10 | # The full license is in the file COPYING.txt, distributed with this software. |
|
|||
11 | #----------------------------------------------------------------------------- |
|
|||
12 |
|
5 | |||
13 | #----------------------------------------------------------------------------- |
|
|||
14 | # Imports |
|
|||
15 | #----------------------------------------------------------------------------- |
|
|||
16 | from IPython.nbformat import current as nbformat |
|
6 | from IPython.nbformat import current as nbformat | |
17 |
|
7 | |||
18 | from .base import PreprocessorTestsBase |
|
8 | from .base import PreprocessorTestsBase | |
19 | from ..coalescestreams import coalesce_streams |
|
9 | from ..coalescestreams import coalesce_streams | |
20 |
|
10 | |||
21 |
|
11 | |||
22 | #----------------------------------------------------------------------------- |
|
|||
23 | # Class |
|
|||
24 | #----------------------------------------------------------------------------- |
|
|||
25 | class TestCoalesceStreams(PreprocessorTestsBase): |
|
12 | class TestCoalesceStreams(PreprocessorTestsBase): | |
26 | """Contains test functions for coalescestreams.py""" |
|
13 | """Contains test functions for coalescestreams.py""" | |
27 |
|
14 | |||
@@ -47,7 +34,7 b' class TestCoalesceStreams(PreprocessorTestsBase):' | |||||
47 | nbformat.new_output(output_type="stream", stream="stdout", output_text="6"), |
|
34 | nbformat.new_output(output_type="stream", stream="stdout", output_text="6"), | |
48 | nbformat.new_output(output_type="stream", stream="stdout", output_text="7")] |
|
35 | nbformat.new_output(output_type="stream", stream="stdout", output_text="7")] | |
49 | cells=[nbformat.new_code_cell(input="# None", prompt_number=1,outputs=outputs)] |
|
36 | cells=[nbformat.new_code_cell(input="# None", prompt_number=1,outputs=outputs)] | |
50 |
worksheets = [nbformat.new_worksheet( |
|
37 | worksheets = [nbformat.new_worksheet(cells=cells)] | |
51 |
|
38 | |||
52 | nb = nbformat.new_notebook(name="notebook1", worksheets=worksheets) |
|
39 | nb = nbformat.new_notebook(name="notebook1", worksheets=worksheets) | |
53 | res = self.build_resources() |
|
40 | res = self.build_resources() | |
@@ -64,7 +51,7 b' class TestCoalesceStreams(PreprocessorTestsBase):' | |||||
64 | nbformat.new_output(output_type="stream", stream="stdout", output_text="\rc\n"), |
|
51 | nbformat.new_output(output_type="stream", stream="stdout", output_text="\rc\n"), | |
65 | nbformat.new_output(output_type="stream", stream="stdout", output_text="z\rz\rd")] |
|
52 | nbformat.new_output(output_type="stream", stream="stdout", output_text="z\rz\rd")] | |
66 | cells=[nbformat.new_code_cell(input="# None", prompt_number=1,outputs=outputs)] |
|
53 | cells=[nbformat.new_code_cell(input="# None", prompt_number=1,outputs=outputs)] | |
67 |
worksheets = [nbformat.new_worksheet( |
|
54 | worksheets = [nbformat.new_worksheet(cells=cells)] | |
68 |
|
55 | |||
69 | nb = nbformat.new_notebook(name="notebook1", worksheets=worksheets) |
|
56 | nb = nbformat.new_notebook(name="notebook1", worksheets=worksheets) | |
70 | res = self.build_resources() |
|
57 | res = self.build_resources() |
@@ -1,18 +1,7 b'' | |||||
1 | """ |
|
1 | """Tests for the revealhelp preprocessor""" | |
2 | Module with tests for the revealhelp preprocessor |
|
|||
3 | """ |
|
|||
4 |
|
2 | |||
5 | #----------------------------------------------------------------------------- |
|
3 | # Copyright (c) IPython Development Team. | |
6 | # Copyright (c) 2013, the IPython Development Team. |
|
|||
7 | # |
|
|||
8 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
9 | # |
|
|||
10 | # The full license is in the file COPYING.txt, distributed with this software. |
|
|||
11 | #----------------------------------------------------------------------------- |
|
|||
12 |
|
||||
13 | #----------------------------------------------------------------------------- |
|
|||
14 | # Imports |
|
|||
15 | #----------------------------------------------------------------------------- |
|
|||
16 |
|
5 | |||
17 | from IPython.nbformat import current as nbformat |
|
6 | from IPython.nbformat import current as nbformat | |
18 |
|
7 | |||
@@ -20,10 +9,6 b' from .base import PreprocessorTestsBase' | |||||
20 | from ..revealhelp import RevealHelpPreprocessor |
|
9 | from ..revealhelp import RevealHelpPreprocessor | |
21 |
|
10 | |||
22 |
|
11 | |||
23 | #----------------------------------------------------------------------------- |
|
|||
24 | # Class |
|
|||
25 | #----------------------------------------------------------------------------- |
|
|||
26 |
|
||||
27 | class Testrevealhelp(PreprocessorTestsBase): |
|
12 | class Testrevealhelp(PreprocessorTestsBase): | |
28 | """Contains test functions for revealhelp.py""" |
|
13 | """Contains test functions for revealhelp.py""" | |
29 |
|
14 | |||
@@ -41,7 +26,7 b' class Testrevealhelp(PreprocessorTestsBase):' | |||||
41 | nbformat.new_code_cell(input="", prompt_number=2, outputs=outputs), |
|
26 | nbformat.new_code_cell(input="", prompt_number=2, outputs=outputs), | |
42 | nbformat.new_text_cell('markdown', source="", metadata=slide_metadata), |
|
27 | nbformat.new_text_cell('markdown', source="", metadata=slide_metadata), | |
43 | nbformat.new_text_cell('markdown', source="", metadata=subslide_metadata)] |
|
28 | nbformat.new_text_cell('markdown', source="", metadata=subslide_metadata)] | |
44 |
worksheets = [nbformat.new_worksheet( |
|
29 | worksheets = [nbformat.new_worksheet(cells=cells)] | |
45 |
|
30 | |||
46 | return nbformat.new_notebook(name="notebook1", worksheets=worksheets) |
|
31 | return nbformat.new_notebook(name="notebook1", worksheets=worksheets) | |
47 |
|
32 |
@@ -1,23 +1,25 b'' | |||||
1 | """The official API for working with notebooks in the current format version.""" |
|
1 | """The official API for working with notebooks in the current format version.""" | |
2 |
|
2 | |||
|
3 | # Copyright (c) IPython Development Team. | |||
|
4 | # Distributed under the terms of the Modified BSD License. | |||
|
5 | ||||
3 | from __future__ import print_function |
|
6 | from __future__ import print_function | |
4 |
|
7 | |||
5 | import re |
|
8 | import re | |
6 |
|
9 | import warnings | ||
7 | from IPython.utils.py3compat import unicode_type |
|
|||
8 |
|
10 | |||
9 | from IPython.nbformat.v3 import ( |
|
11 | from IPython.nbformat.v3 import ( | |
10 | NotebookNode, |
|
12 | NotebookNode, | |
11 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, |
|
13 | new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet, | |
12 | parse_filename, new_metadata, new_author, new_heading_cell, nbformat, |
|
14 | parse_filename, new_metadata, new_author, new_heading_cell, nbformat, | |
13 | nbformat_minor, nbformat_schema, to_notebook_json |
|
15 | nbformat_minor, nbformat_schema, to_notebook_json, | |
14 | ) |
|
16 | ) | |
15 | from IPython.nbformat import v3 as _v_latest |
|
17 | from IPython.nbformat import v3 as _v_latest | |
16 |
|
18 | |||
17 | from .reader import reads as reader_reads |
|
19 | from .reader import reads as reader_reads | |
18 | from .reader import versions |
|
20 | from .reader import versions | |
19 | from .convert import convert |
|
21 | from .convert import convert | |
20 | from .validator import validate |
|
22 | from .validator import validate, ValidationError | |
21 |
|
23 | |||
22 | from IPython.utils.log import get_logger |
|
24 | from IPython.utils.log import get_logger | |
23 |
|
25 | |||
@@ -37,6 +39,11 b' class NBFormatError(ValueError):' | |||||
37 | pass |
|
39 | pass | |
38 |
|
40 | |||
39 |
|
41 | |||
|
42 | def _warn_format(): | |||
|
43 | warnings.warn("""Non-JSON file support in nbformat is deprecated. | |||
|
44 | Use nbconvert to create files of other formats.""") | |||
|
45 | ||||
|
46 | ||||
40 | def parse_py(s, **kwargs): |
|
47 | def parse_py(s, **kwargs): | |
41 | """Parse a string into a (nbformat, string) tuple.""" |
|
48 | """Parse a string into a (nbformat, string) tuple.""" | |
42 | nbf = current_nbformat |
|
49 | nbf = current_nbformat | |
@@ -54,36 +61,18 b' def parse_py(s, **kwargs):' | |||||
54 |
|
61 | |||
55 |
|
62 | |||
56 | def reads_json(nbjson, **kwargs): |
|
63 | def reads_json(nbjson, **kwargs): | |
57 | """Read a JSON notebook from a string and return the NotebookNode |
|
64 | """DEPRECATED, use reads""" | |
58 | object. Report if any JSON format errors are detected. |
|
65 | warnings.warn("reads_json is deprecated, use reads") | |
59 |
|
66 | return reads(nbjson) | ||
60 | """ |
|
|||
61 | nb = reader_reads(nbjson, **kwargs) |
|
|||
62 | nb_current = convert(nb, current_nbformat) |
|
|||
63 | errors = validate(nb_current) |
|
|||
64 | if errors: |
|
|||
65 | get_logger().error( |
|
|||
66 | "Notebook JSON is invalid (%d errors detected during read)", |
|
|||
67 | len(errors)) |
|
|||
68 | return nb_current |
|
|||
69 |
|
||||
70 |
|
67 | |||
71 | def writes_json(nb, **kwargs): |
|
68 | def writes_json(nb, **kwargs): | |
72 | """Take a NotebookNode object and write out a JSON string. Report if |
|
69 | """DEPRECATED, use writes""" | |
73 | any JSON format errors are detected. |
|
70 | warnings.warn("writes_json is deprecated, use writes") | |
74 |
|
71 | return writes(nb, **kwargs) | ||
75 | """ |
|
|||
76 | errors = validate(nb) |
|
|||
77 | if errors: |
|
|||
78 | get_logger().error( |
|
|||
79 | "Notebook JSON is invalid (%d errors detected during write)", |
|
|||
80 | len(errors)) |
|
|||
81 | nbjson = versions[current_nbformat].writes_json(nb, **kwargs) |
|
|||
82 | return nbjson |
|
|||
83 |
|
||||
84 |
|
72 | |||
85 | def reads_py(s, **kwargs): |
|
73 | def reads_py(s, **kwargs): | |
86 | """Read a .py notebook from a string and return the NotebookNode object.""" |
|
74 | """DEPRECATED: use nbconvert""" | |
|
75 | _warn_format() | |||
87 | nbf, nbm, s = parse_py(s, **kwargs) |
|
76 | nbf, nbm, s = parse_py(s, **kwargs) | |
88 | if nbf in (2, 3): |
|
77 | if nbf in (2, 3): | |
89 | nb = versions[nbf].to_notebook_py(s, **kwargs) |
|
78 | nb = versions[nbf].to_notebook_py(s, **kwargs) | |
@@ -91,16 +80,16 b' def reads_py(s, **kwargs):' | |||||
91 | raise NBFormatError('Unsupported PY nbformat version: %i' % nbf) |
|
80 | raise NBFormatError('Unsupported PY nbformat version: %i' % nbf) | |
92 | return nb |
|
81 | return nb | |
93 |
|
82 | |||
94 |
|
||||
95 | def writes_py(nb, **kwargs): |
|
83 | def writes_py(nb, **kwargs): | |
96 | # nbformat 3 is the latest format that supports py |
|
84 | """DEPRECATED: use nbconvert""" | |
|
85 | _warn_format() | |||
97 | return versions[3].writes_py(nb, **kwargs) |
|
86 | return versions[3].writes_py(nb, **kwargs) | |
98 |
|
87 | |||
99 |
|
88 | |||
100 | # High level API |
|
89 | # High level API | |
101 |
|
90 | |||
102 |
|
91 | |||
103 | def reads(s, format, **kwargs): |
|
92 | def reads(s, format='DEPRECATED', version=current_nbformat, **kwargs): | |
104 | """Read a notebook from a string and return the NotebookNode object. |
|
93 | """Read a notebook from a string and return the NotebookNode object. | |
105 |
|
94 | |||
106 | This function properly handles notebooks of any version. The notebook |
|
95 | This function properly handles notebooks of any version. The notebook | |
@@ -110,24 +99,24 b' def reads(s, format, **kwargs):' | |||||
110 | ---------- |
|
99 | ---------- | |
111 | s : unicode |
|
100 | s : unicode | |
112 | The raw unicode string to read the notebook from. |
|
101 | The raw unicode string to read the notebook from. | |
113 | format : (u'json', u'ipynb', u'py') |
|
|||
114 | The format that the string is in. |
|
|||
115 |
|
102 | |||
116 | Returns |
|
103 | Returns | |
117 | ------- |
|
104 | ------- | |
118 | nb : NotebookNode |
|
105 | nb : NotebookNode | |
119 | The notebook that was read. |
|
106 | The notebook that was read. | |
120 | """ |
|
107 | """ | |
121 | format = unicode_type(format) |
|
108 | if format not in {'DEPRECATED', 'json'}: | |
122 | if format == u'json' or format == u'ipynb': |
|
109 | _warn_format() | |
123 |
|
|
110 | nb = reader_reads(s, **kwargs) | |
124 | elif format == u'py': |
|
111 | nb = convert(nb, version) | |
125 | return reads_py(s, **kwargs) |
|
112 | try: | |
126 | else: |
|
113 | validate(nb) | |
127 | raise NBFormatError('Unsupported format: %s' % format) |
|
114 | except ValidationError as e: | |
|
115 | get_logger().error("Notebook JSON is invalid: %s", e) | |||
|
116 | return nb | |||
128 |
|
117 | |||
129 |
|
118 | |||
130 | def writes(nb, format, **kwargs): |
|
119 | def writes(nb, format='DEPRECATED', version=current_nbformat, **kwargs): | |
131 | """Write a notebook to a string in a given format in the current nbformat version. |
|
120 | """Write a notebook to a string in a given format in the current nbformat version. | |
132 |
|
121 | |||
133 | This function always writes the notebook in the current nbformat version. |
|
122 | This function always writes the notebook in the current nbformat version. | |
@@ -136,24 +125,26 b' def writes(nb, format, **kwargs):' | |||||
136 | ---------- |
|
125 | ---------- | |
137 | nb : NotebookNode |
|
126 | nb : NotebookNode | |
138 | The notebook to write. |
|
127 | The notebook to write. | |
139 | format : (u'json', u'ipynb', u'py') |
|
128 | version : int | |
140 |
The format to write |
|
129 | The nbformat version to write. | |
|
130 | Used for downgrading notebooks. | |||
141 |
|
131 | |||
142 | Returns |
|
132 | Returns | |
143 | ------- |
|
133 | ------- | |
144 | s : unicode |
|
134 | s : unicode | |
145 | The notebook string. |
|
135 | The notebook string. | |
146 | """ |
|
136 | """ | |
147 | format = unicode_type(format) |
|
137 | if format not in {'DEPRECATED', 'json'}: | |
148 | if format == u'json' or format == u'ipynb': |
|
138 | _warn_format() | |
149 | return writes_json(nb, **kwargs) |
|
139 | nb = convert(nb, version) | |
150 | elif format == u'py': |
|
140 | try: | |
151 | return writes_py(nb, **kwargs) |
|
141 | validate(nb) | |
152 | else: |
|
142 | except ValidationError as e: | |
153 | raise NBFormatError('Unsupported format: %s' % format) |
|
143 | get_logger().error("Notebook JSON is invalid: %s", e) | |
|
144 | return versions[version].writes_json(nb, **kwargs) | |||
154 |
|
145 | |||
155 |
|
146 | |||
156 | def read(fp, format, **kwargs): |
|
147 | def read(fp, format='DEPRECATED', **kwargs): | |
157 | """Read a notebook from a file and return the NotebookNode object. |
|
148 | """Read a notebook from a file and return the NotebookNode object. | |
158 |
|
149 | |||
159 | This function properly handles notebooks of any version. The notebook |
|
150 | This function properly handles notebooks of any version. The notebook | |
@@ -163,18 +154,16 b' def read(fp, format, **kwargs):' | |||||
163 | ---------- |
|
154 | ---------- | |
164 | fp : file |
|
155 | fp : file | |
165 | Any file-like object with a read method. |
|
156 | Any file-like object with a read method. | |
166 | format : (u'json', u'ipynb', u'py') |
|
|||
167 | The format that the string is in. |
|
|||
168 |
|
157 | |||
169 | Returns |
|
158 | Returns | |
170 | ------- |
|
159 | ------- | |
171 | nb : NotebookNode |
|
160 | nb : NotebookNode | |
172 | The notebook that was read. |
|
161 | The notebook that was read. | |
173 | """ |
|
162 | """ | |
174 |
return reads(fp.read(), |
|
163 | return reads(fp.read(), **kwargs) | |
175 |
|
164 | |||
176 |
|
165 | |||
177 | def write(nb, fp, format, **kwargs): |
|
166 | def write(nb, fp, format='DEPRECATED', **kwargs): | |
178 | """Write a notebook to a file in a given format in the current nbformat version. |
|
167 | """Write a notebook to a file in a given format in the current nbformat version. | |
179 |
|
168 | |||
180 | This function always writes the notebook in the current nbformat version. |
|
169 | This function always writes the notebook in the current nbformat version. | |
@@ -185,28 +174,9 b' def write(nb, fp, format, **kwargs):' | |||||
185 | The notebook to write. |
|
174 | The notebook to write. | |
186 | fp : file |
|
175 | fp : file | |
187 | Any file-like object with a write method. |
|
176 | Any file-like object with a write method. | |
188 | format : (u'json', u'ipynb', u'py') |
|
|||
189 | The format to write the notebook in. |
|
|||
190 |
|
||||
191 | Returns |
|
|||
192 | ------- |
|
|||
193 | s : unicode |
|
|||
194 | The notebook string. |
|
|||
195 | """ |
|
177 | """ | |
196 |
|
|
178 | s = writes(nb, **kwargs) | |
197 |
|
179 | if isinstance(s, bytes): | ||
198 | def _convert_to_metadata(): |
|
180 | s = s.decode('utf8') | |
199 | """Convert to a notebook having notebook metadata.""" |
|
181 | return fp.write(s) | |
200 | import glob |
|
|||
201 | for fname in glob.glob('*.ipynb'): |
|
|||
202 | print('Converting file:',fname) |
|
|||
203 | with open(fname,'r') as f: |
|
|||
204 | nb = read(f,u'json') |
|
|||
205 | md = new_metadata() |
|
|||
206 | if u'name' in nb: |
|
|||
207 | md.name = nb.name |
|
|||
208 | del nb[u'name'] |
|
|||
209 | nb.metadata = md |
|
|||
210 | with open(fname,'w') as f: |
|
|||
211 | write(nb, f, u'json') |
|
|||
212 |
|
182 |
@@ -1,14 +1,7 b'' | |||||
1 | """Functions for signing notebooks""" |
|
1 | """Functions for signing notebooks""" | |
2 | #----------------------------------------------------------------------------- |
|
|||
3 | # Copyright (C) 2014, The IPython Development Team |
|
|||
4 | # |
|
|||
5 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
6 | # the file COPYING, distributed as part of this software. |
|
|||
7 | #----------------------------------------------------------------------------- |
|
|||
8 |
|
2 | |||
9 | #----------------------------------------------------------------------------- |
|
3 | # Copyright (c) IPython Development Team. | |
10 | # Imports |
|
4 | # Distributed under the terms of the Modified BSD License. | |
11 | #----------------------------------------------------------------------------- |
|
|||
12 |
|
5 | |||
13 | import base64 |
|
6 | import base64 | |
14 | from contextlib import contextmanager |
|
7 | from contextlib import contextmanager | |
@@ -24,15 +17,14 b' from IPython.core.application import BaseIPythonApplication, base_flags' | |||||
24 |
|
17 | |||
25 | from .current import read, write |
|
18 | from .current import read, write | |
26 |
|
19 | |||
27 | #----------------------------------------------------------------------------- |
|
20 | ||
28 | # Code |
|
|||
29 | #----------------------------------------------------------------------------- |
|
|||
30 | try: |
|
21 | try: | |
31 | # Python 3 |
|
22 | # Python 3 | |
32 | algorithms = hashlib.algorithms_guaranteed |
|
23 | algorithms = hashlib.algorithms_guaranteed | |
33 | except AttributeError: |
|
24 | except AttributeError: | |
34 | algorithms = hashlib.algorithms |
|
25 | algorithms = hashlib.algorithms | |
35 |
|
26 | |||
|
27 | ||||
36 | def yield_everything(obj): |
|
28 | def yield_everything(obj): | |
37 | """Yield every item in a container as bytes |
|
29 | """Yield every item in a container as bytes | |
38 |
|
30 | |||
@@ -184,7 +176,7 b' class NotebookNotary(LoggingConfigurable):' | |||||
184 | def mark_cells(self, nb, trusted): |
|
176 | def mark_cells(self, nb, trusted): | |
185 | """Mark cells as trusted if the notebook's signature can be verified |
|
177 | """Mark cells as trusted if the notebook's signature can be verified | |
186 |
|
178 | |||
187 | Sets ``cell.trusted = True | False`` on all code cells, |
|
179 | Sets ``cell.metadata.trusted = True | False`` on all code cells, | |
188 | depending on whether the stored signature can be verified. |
|
180 | depending on whether the stored signature can be verified. | |
189 |
|
181 | |||
190 | This function is the inverse of check_cells |
|
182 | This function is the inverse of check_cells | |
@@ -194,7 +186,7 b' class NotebookNotary(LoggingConfigurable):' | |||||
194 | return |
|
186 | return | |
195 | for cell in nb['worksheets'][0]['cells']: |
|
187 | for cell in nb['worksheets'][0]['cells']: | |
196 | if cell['cell_type'] == 'code': |
|
188 | if cell['cell_type'] == 'code': | |
197 | cell['trusted'] = trusted |
|
189 | cell['metadata']['trusted'] = trusted | |
198 |
|
190 | |||
199 | def _check_cell(self, cell): |
|
191 | def _check_cell(self, cell): | |
200 | """Do we trust an individual cell? |
|
192 | """Do we trust an individual cell? | |
@@ -208,7 +200,7 b' class NotebookNotary(LoggingConfigurable):' | |||||
208 | it will always be trusted. |
|
200 | it will always be trusted. | |
209 | """ |
|
201 | """ | |
210 | # explicitly trusted |
|
202 | # explicitly trusted | |
211 | if cell.pop("trusted", False): |
|
203 | if cell['metadata'].pop("trusted", False): | |
212 | return True |
|
204 | return True | |
213 |
|
205 | |||
214 | # explicitly safe output |
|
206 | # explicitly safe output | |
@@ -243,6 +235,7 b' class NotebookNotary(LoggingConfigurable):' | |||||
243 | # only distrust a cell if it actually has some output to distrust |
|
235 | # only distrust a cell if it actually has some output to distrust | |
244 | if not self._check_cell(cell): |
|
236 | if not self._check_cell(cell): | |
245 | trusted = False |
|
237 | trusted = False | |
|
238 | ||||
246 | return trusted |
|
239 | return trusted | |
247 |
|
240 | |||
248 |
|
241 |
@@ -1,25 +1,19 b'' | |||||
1 | """ |
|
1 | """ | |
2 | Contains tests class for current.py |
|
2 | Contains tests class for current.py | |
3 | """ |
|
3 | """ | |
4 | #----------------------------------------------------------------------------- |
|
|||
5 | # Copyright (C) 2013 The IPython Development Team |
|
|||
6 | # |
|
|||
7 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
8 | # the file COPYING, distributed as part of this software. |
|
|||
9 | #----------------------------------------------------------------------------- |
|
|||
10 |
|
4 | |||
11 | #----------------------------------------------------------------------------- |
|
5 | # Copyright (c) IPython Development Team. | |
12 | # Imports |
|
6 | # Distributed under the terms of the Modified BSD License. | |
13 | #----------------------------------------------------------------------------- |
|
7 | ||
|
8 | import io | |||
|
9 | import json | |||
|
10 | import tempfile | |||
14 |
|
11 | |||
15 | from .base import TestsBase |
|
12 | from .base import TestsBase | |
16 |
|
13 | |||
17 | from ..reader import get_version |
|
14 | from ..reader import get_version | |
18 | from ..current import read, current_nbformat |
|
15 | from ..current import read, current_nbformat, validate, writes | |
19 |
|
16 | |||
20 | #----------------------------------------------------------------------------- |
|
|||
21 | # Classes and functions |
|
|||
22 | #----------------------------------------------------------------------------- |
|
|||
23 |
|
17 | |||
24 | class TestCurrent(TestsBase): |
|
18 | class TestCurrent(TestsBase): | |
25 |
|
19 | |||
@@ -29,8 +23,19 b' class TestCurrent(TestsBase):' | |||||
29 |
|
23 | |||
30 | # Open a version 2 notebook. |
|
24 | # Open a version 2 notebook. | |
31 | with self.fopen(u'test2.ipynb', u'r') as f: |
|
25 | with self.fopen(u'test2.ipynb', u'r') as f: | |
32 |
nb = read(f |
|
26 | nb = read(f) | |
33 |
|
27 | |||
34 | # Check that the notebook was upgraded to the latest version automatically. |
|
28 | # Check that the notebook was upgraded to the latest version automatically. | |
35 | (major, minor) = get_version(nb) |
|
29 | (major, minor) = get_version(nb) | |
36 | self.assertEqual(major, current_nbformat) |
|
30 | self.assertEqual(major, current_nbformat) | |
|
31 | ||||
|
32 | def test_write_downgrade_2(self): | |||
|
33 | """dowgrade a v3 notebook to v2""" | |||
|
34 | # Open a version 3 notebook. | |||
|
35 | with self.fopen(u'test3.ipynb', 'r') as f: | |||
|
36 | nb = read(f, u'json') | |||
|
37 | ||||
|
38 | jsons = writes(nb, version=2) | |||
|
39 | nb2 = json.loads(jsons) | |||
|
40 | (major, minor) = get_version(nb2) | |||
|
41 | self.assertEqual(major, 2) |
@@ -83,21 +83,23 b' class TestNotary(TestsBase):' | |||||
83 | cells = self.nb.worksheets[0].cells |
|
83 | cells = self.nb.worksheets[0].cells | |
84 | self.notary.mark_cells(self.nb, False) |
|
84 | self.notary.mark_cells(self.nb, False) | |
85 | for cell in cells: |
|
85 | for cell in cells: | |
|
86 | self.assertNotIn('trusted', cell) | |||
86 | if cell.cell_type == 'code': |
|
87 | if cell.cell_type == 'code': | |
87 | self.assertIn('trusted', cell) |
|
88 | self.assertIn('trusted', cell.metadata) | |
88 | self.assertFalse(cell.trusted) |
|
89 | self.assertFalse(cell.metadata.trusted) | |
89 | else: |
|
90 | else: | |
90 | self.assertNotIn('trusted', cell) |
|
91 | self.assertNotIn('trusted', cell.metadata) | |
91 |
|
92 | |||
92 | def test_mark_cells_trusted(self): |
|
93 | def test_mark_cells_trusted(self): | |
93 | cells = self.nb.worksheets[0].cells |
|
94 | cells = self.nb.worksheets[0].cells | |
94 | self.notary.mark_cells(self.nb, True) |
|
95 | self.notary.mark_cells(self.nb, True) | |
95 | for cell in cells: |
|
96 | for cell in cells: | |
|
97 | self.assertNotIn('trusted', cell) | |||
96 | if cell.cell_type == 'code': |
|
98 | if cell.cell_type == 'code': | |
97 | self.assertIn('trusted', cell) |
|
99 | self.assertIn('trusted', cell.metadata) | |
98 | self.assertTrue(cell.trusted) |
|
100 | self.assertTrue(cell.metadata.trusted) | |
99 | else: |
|
101 | else: | |
100 | self.assertNotIn('trusted', cell) |
|
102 | self.assertNotIn('trusted', cell.metadata) | |
101 |
|
103 | |||
102 | def test_check_cells(self): |
|
104 | def test_check_cells(self): | |
103 | nb = self.nb |
|
105 | nb = self.nb |
@@ -1,23 +1,14 b'' | |||||
1 | """ |
|
1 | """Test nbformat.validator""" | |
2 | Contains tests class for validator.py |
|
|||
3 | """ |
|
|||
4 | #----------------------------------------------------------------------------- |
|
|||
5 | # Copyright (C) 2014 The IPython Development Team |
|
|||
6 | # |
|
|||
7 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
8 | # the file COPYING, distributed as part of this software. |
|
|||
9 | #----------------------------------------------------------------------------- |
|
|||
10 |
|
2 | |||
11 | #----------------------------------------------------------------------------- |
|
3 | # Copyright (c) IPython Development Team. | |
12 | # Imports |
|
4 | # Distributed under the terms of the Modified BSD License. | |
13 | #----------------------------------------------------------------------------- |
|
|||
14 |
|
5 | |||
15 | import os |
|
6 | import os | |
16 |
|
7 | |||
17 | from .base import TestsBase |
|
8 | from .base import TestsBase | |
18 |
from jsonschema import |
|
9 | from jsonschema import ValidationError | |
19 | from ..current import read |
|
10 | from ..current import read | |
20 |
from ..validator import |
|
11 | from ..validator import isvalid, validate | |
21 |
|
12 | |||
22 |
|
13 | |||
23 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
@@ -26,22 +17,18 b' from ..validator import schema_path, isvalid, validate, resolve_ref' | |||||
26 |
|
17 | |||
27 | class TestValidator(TestsBase): |
|
18 | class TestValidator(TestsBase): | |
28 |
|
19 | |||
29 | def test_schema_path(self): |
|
|||
30 | """Test that the schema path exists""" |
|
|||
31 | self.assertEqual(os.path.exists(schema_path), True) |
|
|||
32 |
|
||||
33 | def test_nb2(self): |
|
20 | def test_nb2(self): | |
34 | """Test that a v2 notebook converted to v3 passes validation""" |
|
21 | """Test that a v2 notebook converted to v3 passes validation""" | |
35 | with self.fopen(u'test2.ipynb', u'r') as f: |
|
22 | with self.fopen(u'test2.ipynb', u'r') as f: | |
36 | nb = read(f, u'json') |
|
23 | nb = read(f, u'json') | |
37 |
|
|
24 | validate(nb) | |
38 | self.assertEqual(isvalid(nb), True) |
|
25 | self.assertEqual(isvalid(nb), True) | |
39 |
|
26 | |||
40 | def test_nb3(self): |
|
27 | def test_nb3(self): | |
41 | """Test that a v3 notebook passes validation""" |
|
28 | """Test that a v3 notebook passes validation""" | |
42 | with self.fopen(u'test3.ipynb', u'r') as f: |
|
29 | with self.fopen(u'test3.ipynb', u'r') as f: | |
43 | nb = read(f, u'json') |
|
30 | nb = read(f, u'json') | |
44 |
|
|
31 | validate(nb) | |
45 | self.assertEqual(isvalid(nb), True) |
|
32 | self.assertEqual(isvalid(nb), True) | |
46 |
|
33 | |||
47 | def test_invalid(self): |
|
34 | def test_invalid(self): | |
@@ -52,22 +39,16 b' class TestValidator(TestsBase):' | |||||
52 | # - one cell has an invalid level |
|
39 | # - one cell has an invalid level | |
53 | with self.fopen(u'invalid.ipynb', u'r') as f: |
|
40 | with self.fopen(u'invalid.ipynb', u'r') as f: | |
54 | nb = read(f, u'json') |
|
41 | nb = read(f, u'json') | |
55 |
self.assert |
|
42 | with self.assertRaises(ValidationError): | |
|
43 | validate(nb) | |||
56 | self.assertEqual(isvalid(nb), False) |
|
44 | self.assertEqual(isvalid(nb), False) | |
57 |
|
45 | |||
58 |
def test_re |
|
46 | def test_future(self): | |
59 | """Test that references are correctly resolved""" |
|
47 | """Test than a notebook from the future with extra keys passes validation""" | |
60 | # make sure it resolves the ref correctly |
|
48 | with self.fopen(u'test3plus.ipynb', u'r') as f: | |
61 | json = {"abc": "def", "ghi": {"$ref": "/abc"}} |
|
49 | nb = read(f) | |
62 | resolved = resolve_ref(json) |
|
50 | with self.assertRaises(ValidationError): | |
63 | self.assertEqual(resolved, {"abc": "def", "ghi": "def"}) |
|
51 | validate(nb, version=3) | |
64 |
|
||||
65 | # make sure it throws an error if the ref is not by itself |
|
|||
66 | json = {"abc": "def", "ghi": {"$ref": "/abc", "foo": "bar"}} |
|
|||
67 | with self.assertRaises(SchemaError): |
|
|||
68 | resolved = resolve_ref(json) |
|
|||
69 |
|
52 | |||
70 | # make sure it can handle json with no reference |
|
53 | self.assertEqual(isvalid(nb, version=3), False) | |
71 | json = {"abc": "def"} |
|
54 | self.assertEqual(isvalid(nb), True) | |
72 | resolved = resolve_ref(json) |
|
|||
73 | self.assertEqual(resolved, json) |
|
@@ -42,6 +42,9 b' from .convert import downgrade, upgrade' | |||||
42 | # Code |
|
42 | # Code | |
43 | #----------------------------------------------------------------------------- |
|
43 | #----------------------------------------------------------------------------- | |
44 |
|
44 | |||
|
45 | nbformat = 2 | |||
|
46 | nbformat_minor = 0 | |||
|
47 | ||||
45 | def parse_filename(fname): |
|
48 | def parse_filename(fname): | |
46 | """Parse a notebook filename. |
|
49 | """Parse a notebook filename. | |
47 |
|
50 |
@@ -1,22 +1,7 b'' | |||||
1 | """Code for converting notebooks to and from the v2 format. |
|
1 | """Code for converting notebooks to and from the v2 format.""" | |
2 |
|
2 | |||
3 | Authors: |
|
3 | # Copyright (c) IPython Development Team. | |
4 |
|
4 | # Distributed under the terms of the Modified BSD License. | ||
5 | * Brian Granger |
|
|||
6 | * Min RK |
|
|||
7 | * Jonathan Frederic |
|
|||
8 | """ |
|
|||
9 |
|
||||
10 | #----------------------------------------------------------------------------- |
|
|||
11 | # Copyright (C) 2008-2011 The IPython Development Team |
|
|||
12 | # |
|
|||
13 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
14 | # the file COPYING, distributed as part of this software. |
|
|||
15 | #----------------------------------------------------------------------------- |
|
|||
16 |
|
||||
17 | #----------------------------------------------------------------------------- |
|
|||
18 | # Imports |
|
|||
19 | #----------------------------------------------------------------------------- |
|
|||
20 |
|
5 | |||
21 | from .nbbase import ( |
|
6 | from .nbbase import ( | |
22 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, |
|
7 | new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output, | |
@@ -25,9 +10,21 b' from .nbbase import (' | |||||
25 |
|
10 | |||
26 | from IPython.nbformat import v2 |
|
11 | from IPython.nbformat import v2 | |
27 |
|
12 | |||
28 | #----------------------------------------------------------------------------- |
|
13 | def _unbytes(obj): | |
29 | # Code |
|
14 | """There should be no bytes objects in a notebook | |
30 | #----------------------------------------------------------------------------- |
|
15 | ||
|
16 | v2 stores png/jpeg as b64 ascii bytes | |||
|
17 | """ | |||
|
18 | if isinstance(obj, dict): | |||
|
19 | for k,v in obj.items(): | |||
|
20 | obj[k] = _unbytes(v) | |||
|
21 | elif isinstance(obj, list): | |||
|
22 | for i,v in enumerate(obj): | |||
|
23 | obj[i] = _unbytes(v) | |||
|
24 | elif isinstance(obj, bytes): | |||
|
25 | # only valid bytes are b64-encoded ascii | |||
|
26 | obj = obj.decode('ascii') | |||
|
27 | return obj | |||
31 |
|
28 | |||
32 | def upgrade(nb, from_version=2, from_minor=0): |
|
29 | def upgrade(nb, from_version=2, from_minor=0): | |
33 | """Convert a notebook to v3. |
|
30 | """Convert a notebook to v3. | |
@@ -47,6 +44,10 b' def upgrade(nb, from_version=2, from_minor=0):' | |||||
47 | nb.nbformat_minor = nbformat_minor |
|
44 | nb.nbformat_minor = nbformat_minor | |
48 |
|
45 | |||
49 | nb.orig_nbformat = 2 |
|
46 | nb.orig_nbformat = 2 | |
|
47 | nb = _unbytes(nb) | |||
|
48 | for ws in nb['worksheets']: | |||
|
49 | for cell in ws['cells']: | |||
|
50 | cell.setdefault('metadata', {}) | |||
50 | return nb |
|
51 | return nb | |
51 | elif from_version == 3: |
|
52 | elif from_version == 3: | |
52 | if from_minor != nbformat_minor: |
|
53 | if from_minor != nbformat_minor: |
@@ -22,7 +22,7 b' from IPython.utils.py3compat import cast_unicode, unicode_type' | |||||
22 | # Change this when incrementing the nbformat version |
|
22 | # Change this when incrementing the nbformat version | |
23 | nbformat = 3 |
|
23 | nbformat = 3 | |
24 | nbformat_minor = 0 |
|
24 | nbformat_minor = 0 | |
25 |
nbformat_schema = ' |
|
25 | nbformat_schema = 'nbformat.v3.schema.json' | |
26 |
|
26 | |||
27 | class NotebookNode(Struct): |
|
27 | class NotebookNode(Struct): | |
28 | pass |
|
28 | pass | |
@@ -53,7 +53,6 b' def new_output(output_type, output_text=None, output_png=None,' | |||||
53 | metadata = {} |
|
53 | metadata = {} | |
54 | if not isinstance(metadata, dict): |
|
54 | if not isinstance(metadata, dict): | |
55 | raise TypeError("metadata must be dict") |
|
55 | raise TypeError("metadata must be dict") | |
56 | output.metadata = metadata |
|
|||
57 |
|
56 | |||
58 | if output_type != 'pyerr': |
|
57 | if output_type != 'pyerr': | |
59 | if output_text is not None: |
|
58 | if output_text is not None: | |
@@ -87,6 +86,8 b' def new_output(output_type, output_text=None, output_png=None,' | |||||
87 |
|
86 | |||
88 | if output_type == u'stream': |
|
87 | if output_type == u'stream': | |
89 | output.stream = 'stdout' if stream is None else cast_unicode(stream) |
|
88 | output.stream = 'stdout' if stream is None else cast_unicode(stream) | |
|
89 | else: | |||
|
90 | output.metadata = metadata | |||
90 |
|
91 | |||
91 | return output |
|
92 | return output | |
92 |
|
93 | |||
@@ -121,21 +122,17 b' def new_text_cell(cell_type, source=None, rendered=None, metadata=None):' | |||||
121 | cell_type = 'raw' |
|
122 | cell_type = 'raw' | |
122 | if source is not None: |
|
123 | if source is not None: | |
123 | cell.source = cast_unicode(source) |
|
124 | cell.source = cast_unicode(source) | |
124 | if rendered is not None: |
|
|||
125 | cell.rendered = cast_unicode(rendered) |
|
|||
126 | cell.metadata = NotebookNode(metadata or {}) |
|
125 | cell.metadata = NotebookNode(metadata or {}) | |
127 | cell.cell_type = cell_type |
|
126 | cell.cell_type = cell_type | |
128 | return cell |
|
127 | return cell | |
129 |
|
128 | |||
130 |
|
129 | |||
131 |
def new_heading_cell(source=None, rendered=None |
|
130 | def new_heading_cell(source=None, level=1, rendered=None, metadata=None): | |
132 | """Create a new section cell with a given integer level.""" |
|
131 | """Create a new section cell with a given integer level.""" | |
133 | cell = NotebookNode() |
|
132 | cell = NotebookNode() | |
134 | cell.cell_type = u'heading' |
|
133 | cell.cell_type = u'heading' | |
135 | if source is not None: |
|
134 | if source is not None: | |
136 | cell.source = cast_unicode(source) |
|
135 | cell.source = cast_unicode(source) | |
137 | if rendered is not None: |
|
|||
138 | cell.rendered = cast_unicode(rendered) |
|
|||
139 | cell.level = int(level) |
|
136 | cell.level = int(level) | |
140 | cell.metadata = NotebookNode(metadata or {}) |
|
137 | cell.metadata = NotebookNode(metadata or {}) | |
141 | return cell |
|
138 | return cell | |
@@ -144,8 +141,6 b' def new_heading_cell(source=None, rendered=None, level=1, metadata=None):' | |||||
144 | def new_worksheet(name=None, cells=None, metadata=None): |
|
141 | def new_worksheet(name=None, cells=None, metadata=None): | |
145 | """Create a worksheet by name with with a list of cells.""" |
|
142 | """Create a worksheet by name with with a list of cells.""" | |
146 | ws = NotebookNode() |
|
143 | ws = NotebookNode() | |
147 | if name is not None: |
|
|||
148 | ws.name = cast_unicode(name) |
|
|||
149 | if cells is None: |
|
144 | if cells is None: | |
150 | ws.cells = [] |
|
145 | ws.cells = [] | |
151 | else: |
|
146 | else: |
@@ -1,34 +1,19 b'' | |||||
1 | """Read and write notebooks in JSON format. |
|
1 | """Read and write notebooks in JSON format.""" | |
2 |
|
2 | |||
3 | Authors: |
|
3 | # Copyright (c) IPython Development Team. | |
4 |
|
4 | # Distributed under the terms of the Modified BSD License. | ||
5 | * Brian Granger |
|
|||
6 | """ |
|
|||
7 |
|
||||
8 | #----------------------------------------------------------------------------- |
|
|||
9 | # Copyright (C) 2008-2011 The IPython Development Team |
|
|||
10 | # |
|
|||
11 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
12 | # the file COPYING, distributed as part of this software. |
|
|||
13 | #----------------------------------------------------------------------------- |
|
|||
14 |
|
||||
15 | #----------------------------------------------------------------------------- |
|
|||
16 | # Imports |
|
|||
17 | #----------------------------------------------------------------------------- |
|
|||
18 |
|
5 | |||
19 | import copy |
|
6 | import copy | |
20 | import json |
|
7 | import json | |
21 |
|
8 | |||
22 | from .nbbase import from_dict |
|
9 | from .nbbase import from_dict | |
23 | from .rwbase import ( |
|
10 | from .rwbase import ( | |
24 | NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines |
|
11 | NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines, | |
|
12 | strip_transient, | |||
25 | ) |
|
13 | ) | |
26 |
|
14 | |||
27 | from IPython.utils import py3compat |
|
15 | from IPython.utils import py3compat | |
28 |
|
16 | |||
29 | #----------------------------------------------------------------------------- |
|
|||
30 | # Code |
|
|||
31 | #----------------------------------------------------------------------------- |
|
|||
32 |
|
17 | |||
33 | class BytesEncoder(json.JSONEncoder): |
|
18 | class BytesEncoder(json.JSONEncoder): | |
34 | """A JSON encoder that accepts b64 (and other *ascii*) bytestrings.""" |
|
19 | """A JSON encoder that accepts b64 (and other *ascii*) bytestrings.""" | |
@@ -43,6 +28,7 b' class JSONReader(NotebookReader):' | |||||
43 | def reads(self, s, **kwargs): |
|
28 | def reads(self, s, **kwargs): | |
44 | nb = json.loads(s, **kwargs) |
|
29 | nb = json.loads(s, **kwargs) | |
45 | nb = self.to_notebook(nb, **kwargs) |
|
30 | nb = self.to_notebook(nb, **kwargs) | |
|
31 | nb = strip_transient(nb) | |||
46 | return nb |
|
32 | return nb | |
47 |
|
33 | |||
48 | def to_notebook(self, d, **kwargs): |
|
34 | def to_notebook(self, d, **kwargs): | |
@@ -56,8 +42,10 b' class JSONWriter(NotebookWriter):' | |||||
56 | kwargs['indent'] = 1 |
|
42 | kwargs['indent'] = 1 | |
57 | kwargs['sort_keys'] = True |
|
43 | kwargs['sort_keys'] = True | |
58 | kwargs['separators'] = (',',': ') |
|
44 | kwargs['separators'] = (',',': ') | |
|
45 | nb = copy.deepcopy(nb) | |||
|
46 | nb = strip_transient(nb) | |||
59 | if kwargs.pop('split_lines', True): |
|
47 | if kwargs.pop('split_lines', True): | |
60 |
nb = split_lines( |
|
48 | nb = split_lines(nb) | |
61 | return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') |
|
49 | return py3compat.str_to_unicode(json.dumps(nb, **kwargs), 'utf-8') | |
62 |
|
50 | |||
63 |
|
51 |
@@ -1,30 +1,13 b'' | |||||
1 | """Base classes and utilities for readers and writers. |
|
1 | """Base classes and utilities for readers and writers.""" | |
2 |
|
2 | |||
3 | Authors: |
|
3 | # Copyright (c) IPython Development Team. | |
4 |
|
4 | # Distributed under the terms of the Modified BSD License. | ||
5 | * Brian Granger |
|
|||
6 | """ |
|
|||
7 |
|
||||
8 | #----------------------------------------------------------------------------- |
|
|||
9 | # Copyright (C) 2008-2011 The IPython Development Team |
|
|||
10 | # |
|
|||
11 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
12 | # the file COPYING, distributed as part of this software. |
|
|||
13 | #----------------------------------------------------------------------------- |
|
|||
14 |
|
||||
15 | #----------------------------------------------------------------------------- |
|
|||
16 | # Imports |
|
|||
17 | #----------------------------------------------------------------------------- |
|
|||
18 |
|
5 | |||
19 | from base64 import encodestring, decodestring |
|
6 | from base64 import encodestring, decodestring | |
20 | import pprint |
|
|||
21 |
|
7 | |||
22 | from IPython.utils import py3compat |
|
8 | from IPython.utils import py3compat | |
23 | from IPython.utils.py3compat import str_to_bytes, unicode_type, string_types |
|
9 | from IPython.utils.py3compat import str_to_bytes, unicode_type, string_types | |
24 |
|
10 | |||
25 | #----------------------------------------------------------------------------- |
|
|||
26 | # Code |
|
|||
27 | #----------------------------------------------------------------------------- |
|
|||
28 |
|
11 | |||
29 | def restore_bytes(nb): |
|
12 | def restore_bytes(nb): | |
30 | """Restore bytes of image data from unicode-only formats. |
|
13 | """Restore bytes of image data from unicode-only formats. | |
@@ -157,6 +140,19 b' def base64_encode(nb):' | |||||
157 | return nb |
|
140 | return nb | |
158 |
|
141 | |||
159 |
|
142 | |||
|
143 | def strip_transient(nb): | |||
|
144 | """Strip transient values that shouldn't be stored in files. | |||
|
145 | ||||
|
146 | This should be called in *both* read and write. | |||
|
147 | """ | |||
|
148 | nb.pop('orig_nbformat', None) | |||
|
149 | nb.pop('orig_nbformat_minor', None) | |||
|
150 | for ws in nb['worksheets']: | |||
|
151 | for cell in ws['cells']: | |||
|
152 | cell.get('metadata', {}).pop('trusted', None) | |||
|
153 | return nb | |||
|
154 | ||||
|
155 | ||||
160 | class NotebookReader(object): |
|
156 | class NotebookReader(object): | |
161 | """A class for reading notebooks.""" |
|
157 | """A class for reading notebooks.""" | |
162 |
|
158 |
@@ -13,12 +13,11 b' from ..nbbase import (' | |||||
13 | png = encodestring(os.urandom(5)).decode('ascii') |
|
13 | png = encodestring(os.urandom(5)).decode('ascii') | |
14 | jpeg = encodestring(os.urandom(6)).decode('ascii') |
|
14 | jpeg = encodestring(os.urandom(6)).decode('ascii') | |
15 |
|
15 | |||
16 |
ws = new_worksheet( |
|
16 | ws = new_worksheet() | |
17 |
|
17 | |||
18 | ws.cells.append(new_text_cell( |
|
18 | ws.cells.append(new_text_cell( | |
19 | u'html', |
|
19 | u'html', | |
20 | source='Some NumPy Examples', |
|
20 | source='Some NumPy Examples', | |
21 | rendered='Some NumPy Examples' |
|
|||
22 | )) |
|
21 | )) | |
23 |
|
22 | |||
24 |
|
23 | |||
@@ -31,7 +30,6 b' ws.cells.append(new_code_cell(' | |||||
31 | ws.cells.append(new_text_cell( |
|
30 | ws.cells.append(new_text_cell( | |
32 | u'markdown', |
|
31 | u'markdown', | |
33 | source='A random array', |
|
32 | source='A random array', | |
34 | rendered='A random array' |
|
|||
35 | )) |
|
33 | )) | |
36 |
|
34 | |||
37 | ws.cells.append(new_text_cell( |
|
35 | ws.cells.append(new_text_cell( | |
@@ -70,7 +68,7 b' ws.cells.append(new_code_cell(' | |||||
70 | output_png=png, |
|
68 | output_png=png, | |
71 | output_jpeg=jpeg, |
|
69 | output_jpeg=jpeg, | |
72 | output_svg=u'<svg>', |
|
70 | output_svg=u'<svg>', | |
73 | output_json=u'json data', |
|
71 | output_json=u'{"json": "data"}', | |
74 | output_javascript=u'var i=0;', |
|
72 | output_javascript=u'var i=0;', | |
75 | prompt_number=3 |
|
73 | prompt_number=3 | |
76 | ),new_output( |
|
74 | ),new_output( | |
@@ -81,7 +79,7 b' ws.cells.append(new_code_cell(' | |||||
81 | output_png=png, |
|
79 | output_png=png, | |
82 | output_jpeg=jpeg, |
|
80 | output_jpeg=jpeg, | |
83 | output_svg=u'<svg>', |
|
81 | output_svg=u'<svg>', | |
84 | output_json=u'json data', |
|
82 | output_json=u'{"json": "data"}', | |
85 | output_javascript=u'var i=0;' |
|
83 | output_javascript=u'var i=0;' | |
86 | ),new_output( |
|
84 | ),new_output( | |
87 | output_type=u'pyerr', |
|
85 | output_type=u'pyerr', | |
@@ -104,7 +102,7 b" md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here'," | |||||
104 | modified=u'8601_goes_here',gistid=u'21341231',authors=authors) |
|
102 | modified=u'8601_goes_here',gistid=u'21341231',authors=authors) | |
105 |
|
103 | |||
106 | nb0 = new_notebook( |
|
104 | nb0 = new_notebook( | |
107 |
worksheets=[ws, new_worksheet( |
|
105 | worksheets=[ws, new_worksheet()], | |
108 | metadata=md |
|
106 | metadata=md | |
109 | ) |
|
107 | ) | |
110 |
|
108 |
@@ -1,9 +1,11 b'' | |||||
1 |
import |
|
1 | import copy | |
|
2 | import json | |||
2 | from base64 import decodestring |
|
3 | from base64 import decodestring | |
3 | from unittest import TestCase |
|
4 | from unittest import TestCase | |
4 |
|
5 | |||
5 | from IPython.utils.py3compat import unicode_type |
|
6 | from IPython.utils.py3compat import unicode_type | |
6 | from ..nbjson import reads, writes |
|
7 | from ..nbjson import reads, writes | |
|
8 | from ..nbbase import from_dict | |||
7 | from .. import nbjson |
|
9 | from .. import nbjson | |
8 | from .nbexamples import nb0 |
|
10 | from .nbexamples import nb0 | |
9 |
|
11 | |||
@@ -31,6 +33,35 b' class TestJSON(formattest.NBFormatTest, TestCase):' | |||||
31 | s = writes(nb0, split_lines=True) |
|
33 | s = writes(nb0, split_lines=True) | |
32 | self.assertEqual(nbjson.reads(s),nb0) |
|
34 | self.assertEqual(nbjson.reads(s),nb0) | |
33 |
|
35 | |||
|
36 | def test_strip_transient(self): | |||
|
37 | """transient values aren't written to files""" | |||
|
38 | nb = copy.deepcopy(nb0) | |||
|
39 | nb.orig_nbformat = 2 | |||
|
40 | nb.orig_nbformat_minor = 3 | |||
|
41 | nb.worksheets[0].cells[0].metadata.trusted = False | |||
|
42 | nbs = nbjson.writes(nb) | |||
|
43 | ||||
|
44 | nb2 = from_dict(json.loads(nbs)) | |||
|
45 | self.assertNotIn('orig_nbformat', nb2) | |||
|
46 | self.assertNotIn('orig_nbformat_minor', nb2) | |||
|
47 | for cell in nb2.worksheets[0].cells: | |||
|
48 | self.assertNotIn('trusted', cell.metadata) | |||
|
49 | ||||
|
50 | def test_to_json(self): | |||
|
51 | """to_notebook_json doesn't strip transient""" | |||
|
52 | nb = copy.deepcopy(nb0) | |||
|
53 | nb.orig_nbformat = 2 | |||
|
54 | nb.orig_nbformat_minor = 3 | |||
|
55 | nb.worksheets[0].cells[0].metadata.trusted = False | |||
|
56 | nbs = json.dumps(nb) | |||
|
57 | nb2 = nbjson.to_notebook(json.loads(nbs)) | |||
|
58 | ||||
|
59 | nb2 = from_dict(json.loads(nbs)) | |||
|
60 | self.assertIn('orig_nbformat', nb2) | |||
|
61 | self.assertIn('orig_nbformat_minor', nb2) | |||
|
62 | cell = nb2.worksheets[0].cells[0] | |||
|
63 | self.assertIn('trusted', cell.metadata) | |||
|
64 | ||||
34 | def test_read_png(self): |
|
65 | def test_read_png(self): | |
35 | """PNG output data is b64 unicode""" |
|
66 | """PNG output data is b64 unicode""" | |
36 | s = writes(nb0) |
|
67 | s = writes(nb0) |
@@ -41,45 +41,37 b' class TestCell(TestCase):' | |||||
41 | tc = new_text_cell(u'html') |
|
41 | tc = new_text_cell(u'html') | |
42 | self.assertEqual(tc.cell_type, u'html') |
|
42 | self.assertEqual(tc.cell_type, u'html') | |
43 | self.assertEqual(u'source' not in tc, True) |
|
43 | self.assertEqual(u'source' not in tc, True) | |
44 | self.assertEqual(u'rendered' not in tc, True) |
|
|||
45 |
|
44 | |||
46 | def test_html_cell(self): |
|
45 | def test_html_cell(self): | |
47 |
tc = new_text_cell(u'html', 'hi' |
|
46 | tc = new_text_cell(u'html', 'hi') | |
48 | self.assertEqual(tc.source, u'hi') |
|
47 | self.assertEqual(tc.source, u'hi') | |
49 | self.assertEqual(tc.rendered, u'hi') |
|
|||
50 |
|
48 | |||
51 | def test_empty_markdown_cell(self): |
|
49 | def test_empty_markdown_cell(self): | |
52 | tc = new_text_cell(u'markdown') |
|
50 | tc = new_text_cell(u'markdown') | |
53 | self.assertEqual(tc.cell_type, u'markdown') |
|
51 | self.assertEqual(tc.cell_type, u'markdown') | |
54 | self.assertEqual(u'source' not in tc, True) |
|
52 | self.assertEqual(u'source' not in tc, True) | |
55 | self.assertEqual(u'rendered' not in tc, True) |
|
|||
56 |
|
53 | |||
57 | def test_markdown_cell(self): |
|
54 | def test_markdown_cell(self): | |
58 |
tc = new_text_cell(u'markdown', 'hi' |
|
55 | tc = new_text_cell(u'markdown', 'hi') | |
59 | self.assertEqual(tc.source, u'hi') |
|
56 | self.assertEqual(tc.source, u'hi') | |
60 | self.assertEqual(tc.rendered, u'hi') |
|
|||
61 |
|
57 | |||
62 | def test_empty_raw_cell(self): |
|
58 | def test_empty_raw_cell(self): | |
63 | tc = new_text_cell(u'raw') |
|
59 | tc = new_text_cell(u'raw') | |
64 | self.assertEqual(tc.cell_type, u'raw') |
|
60 | self.assertEqual(tc.cell_type, u'raw') | |
65 | self.assertEqual(u'source' not in tc, True) |
|
61 | self.assertEqual(u'source' not in tc, True) | |
66 | self.assertEqual(u'rendered' not in tc, True) |
|
|||
67 |
|
62 | |||
68 | def test_raw_cell(self): |
|
63 | def test_raw_cell(self): | |
69 |
tc = new_text_cell(u'raw', 'hi' |
|
64 | tc = new_text_cell(u'raw', 'hi') | |
70 | self.assertEqual(tc.source, u'hi') |
|
65 | self.assertEqual(tc.source, u'hi') | |
71 | self.assertEqual(tc.rendered, u'hi') |
|
|||
72 |
|
66 | |||
73 | def test_empty_heading_cell(self): |
|
67 | def test_empty_heading_cell(self): | |
74 | tc = new_heading_cell() |
|
68 | tc = new_heading_cell() | |
75 | self.assertEqual(tc.cell_type, u'heading') |
|
69 | self.assertEqual(tc.cell_type, u'heading') | |
76 | self.assertEqual(u'source' not in tc, True) |
|
70 | self.assertEqual(u'source' not in tc, True) | |
77 | self.assertEqual(u'rendered' not in tc, True) |
|
|||
78 |
|
71 | |||
79 | def test_heading_cell(self): |
|
72 | def test_heading_cell(self): | |
80 |
tc = new_heading_cell(u'hi', |
|
73 | tc = new_heading_cell(u'hi', level=2) | |
81 | self.assertEqual(tc.source, u'hi') |
|
74 | self.assertEqual(tc.source, u'hi') | |
82 | self.assertEqual(tc.rendered, u'hi') |
|
|||
83 | self.assertEqual(tc.level, 2) |
|
75 | self.assertEqual(tc.level, 2) | |
84 |
|
76 | |||
85 |
|
77 | |||
@@ -92,9 +84,8 b' class TestWorksheet(TestCase):' | |||||
92 |
|
84 | |||
93 | def test_worksheet(self): |
|
85 | def test_worksheet(self): | |
94 | cells = [new_code_cell(), new_text_cell(u'html')] |
|
86 | cells = [new_code_cell(), new_text_cell(u'html')] | |
95 |
ws = new_worksheet(cells=cells |
|
87 | ws = new_worksheet(cells=cells) | |
96 | self.assertEqual(ws.cells,cells) |
|
88 | self.assertEqual(ws.cells,cells) | |
97 | self.assertEqual(ws.name,u'foo') |
|
|||
98 |
|
89 | |||
99 | class TestNotebook(TestCase): |
|
90 | class TestNotebook(TestCase): | |
100 |
|
91 |
@@ -1,112 +1,146 b'' | |||||
|
1 | # Copyright (c) IPython Development Team. | |||
|
2 | # Distributed under the terms of the Modified BSD License. | |||
|
3 | ||||
1 | from __future__ import print_function |
|
4 | from __future__ import print_function | |
2 | import json |
|
5 | import json | |
3 | import os |
|
6 | import os | |
|
7 | import warnings | |||
4 |
|
8 | |||
5 | try: |
|
9 | try: | |
6 |
from jsonschema import |
|
10 | from jsonschema import ValidationError | |
7 |
from jsonschema import Draft |
|
11 | from jsonschema import Draft4Validator as Validator | |
8 | except ImportError as e: |
|
12 | except ImportError as e: | |
9 | verbose_msg = """ |
|
13 | verbose_msg = """ | |
10 |
|
14 | |||
11 |
IPython depends on the jsonschema package: |
|
15 | IPython notebook format depends on the jsonschema package: | |
12 |
|
16 | |||
13 | Please install it first. |
|
17 | https://pypi.python.org/pypi/jsonschema | |
14 | """ |
|
|||
15 | raise ImportError(str(e) + verbose_msg) |
|
|||
16 |
|
||||
17 | try: |
|
|||
18 | import jsonpointer as jsonpointer |
|
|||
19 | except ImportError as e: |
|
|||
20 | verbose_msg = """ |
|
|||
21 |
|
||||
22 | IPython depends on the jsonpointer package: https://pypi.python.org/pypi/jsonpointer |
|
|||
23 |
|
18 | |||
24 | Please install it first. |
|
19 | Please install it first. | |
25 | """ |
|
20 | """ | |
26 | raise ImportError(str(e) + verbose_msg) |
|
21 | raise ImportError(str(e) + verbose_msg) | |
27 |
|
22 | |||
28 |
from IPython.utils. |
|
23 | from IPython.utils.importstring import import_item | |
29 |
|
||||
30 |
|
24 | |||
31 | from .current import nbformat, nbformat_schema |
|
|||
32 | schema_path = os.path.join( |
|
|||
33 | os.path.dirname(__file__), "v%d" % nbformat, nbformat_schema) |
|
|||
34 |
|
25 | |||
|
26 | validators = {} | |||
35 |
|
27 | |||
36 | def isvalid(nbjson): |
|
28 | def _relax_additional_properties(obj): | |
|
29 | """relax any `additionalProperties`""" | |||
|
30 | if isinstance(obj, dict): | |||
|
31 | for key, value in obj.items(): | |||
|
32 | if key == 'additionalProperties': | |||
|
33 | print(obj) | |||
|
34 | value = True | |||
|
35 | else: | |||
|
36 | value = _relax_additional_properties(value) | |||
|
37 | obj[key] = value | |||
|
38 | elif isinstance(obj, list): | |||
|
39 | for i, value in enumerate(obj): | |||
|
40 | obj[i] = _relax_additional_properties(value) | |||
|
41 | return obj | |||
|
42 | ||||
|
43 | def get_validator(version=None, version_minor=None): | |||
|
44 | """Load the JSON schema into a Validator""" | |||
|
45 | if version is None: | |||
|
46 | from .current import nbformat as version | |||
|
47 | ||||
|
48 | v = import_item("IPython.nbformat.v%s" % version) | |||
|
49 | current_minor = v.nbformat_minor | |||
|
50 | if version_minor is None: | |||
|
51 | version_minor = current_minor | |||
|
52 | ||||
|
53 | version_tuple = (version, version_minor) | |||
|
54 | ||||
|
55 | if version_tuple not in validators: | |||
|
56 | try: | |||
|
57 | v.nbformat_schema | |||
|
58 | except AttributeError: | |||
|
59 | # no validator | |||
|
60 | return None | |||
|
61 | schema_path = os.path.join(os.path.dirname(v.__file__), v.nbformat_schema) | |||
|
62 | with open(schema_path) as f: | |||
|
63 | schema_json = json.load(f) | |||
|
64 | ||||
|
65 | if current_minor < version_minor: | |||
|
66 | # notebook from the future, relax all `additionalProperties: False` requirements | |||
|
67 | schema_json = _relax_additional_properties(schema_json) | |||
|
68 | ||||
|
69 | validators[version_tuple] = Validator(schema_json) | |||
|
70 | return validators[version_tuple] | |||
|
71 | ||||
|
72 | def isvalid(nbjson, ref=None, version=None, version_minor=None): | |||
37 | """Checks whether the given notebook JSON conforms to the current |
|
73 | """Checks whether the given notebook JSON conforms to the current | |
38 | notebook format schema. Returns True if the JSON is valid, and |
|
74 | notebook format schema. Returns True if the JSON is valid, and | |
39 | False otherwise. |
|
75 | False otherwise. | |
40 |
|
76 | |||
41 | To see the individual errors that were encountered, please use the |
|
77 | To see the individual errors that were encountered, please use the | |
42 | `validate` function instead. |
|
78 | `validate` function instead. | |
43 |
|
||||
44 | """ |
|
79 | """ | |
45 |
|
80 | try: | ||
46 | errors = validate(nbjson) |
|
81 | validate(nbjson, ref, version, version_minor) | |
47 | return errors == [] |
|
82 | except ValidationError: | |
|
83 | return False | |||
|
84 | else: | |||
|
85 | return True | |||
48 |
|
86 | |||
49 |
|
87 | |||
50 | def validate(nbjson): |
|
88 | def better_validation_error(error, version, version_minor): | |
51 | """Checks whether the given notebook JSON conforms to the current |
|
89 | """Get better ValidationError on oneOf failures | |
52 | notebook format schema, and returns the list of errors. |
|
|||
53 |
|
90 | |||
|
91 | oneOf errors aren't informative. | |||
|
92 | if it's a cell type or output_type error, | |||
|
93 | try validating directly based on the type for a better error message | |||
54 | """ |
|
94 | """ | |
|
95 | key = error.schema_path[-1] | |||
|
96 | if key.endswith('Of'): | |||
|
97 | ||||
|
98 | ref = None | |||
|
99 | if isinstance(error.instance, dict): | |||
|
100 | if 'cell_type' in error.instance: | |||
|
101 | ref = error.instance['cell_type'] + "_cell" | |||
|
102 | elif 'output_type' in error.instance: | |||
|
103 | ref = error.instance['output_type'] | |||
|
104 | ||||
|
105 | if ref: | |||
|
106 | try: | |||
|
107 | validate(error.instance, | |||
|
108 | ref, | |||
|
109 | version=version, | |||
|
110 | version_minor=version_minor, | |||
|
111 | ) | |||
|
112 | except ValidationError as e: | |||
|
113 | return better_validation_error(e, version, version_minor) | |||
|
114 | except: | |||
|
115 | # if it fails for some reason, | |||
|
116 | # let the original error through | |||
|
117 | pass | |||
|
118 | ||||
|
119 | return error | |||
|
120 | ||||
|
121 | ||||
|
122 | def validate(nbjson, ref=None, version=None, version_minor=None): | |||
|
123 | """Checks whether the given notebook JSON conforms to the current | |||
|
124 | notebook format schema. | |||
55 |
|
|
125 | ||
56 | # load the schema file |
|
126 | Raises ValidationError if not valid. | |
57 | with open(schema_path, 'r') as fh: |
|
|||
58 | schema_json = json.load(fh) |
|
|||
59 |
|
||||
60 | # resolve internal references |
|
|||
61 | schema = resolve_ref(schema_json) |
|
|||
62 | schema = jsonpointer.resolve_pointer(schema, '/notebook') |
|
|||
63 |
|
||||
64 | # count how many errors there are |
|
|||
65 | v = Validator(schema) |
|
|||
66 | errors = list(v.iter_errors(nbjson)) |
|
|||
67 | return errors |
|
|||
68 |
|
||||
69 |
|
||||
70 | def resolve_ref(json, schema=None): |
|
|||
71 | """Resolve internal references within the given JSON. This essentially |
|
|||
72 | means that dictionaries of this form: |
|
|||
73 |
|
||||
74 | {"$ref": "/somepointer"} |
|
|||
75 |
|
||||
76 | will be replaced with the resolved reference to `/somepointer`. |
|
|||
77 | This only supports local reference to the same JSON file. |
|
|||
78 |
|
||||
79 | """ |
|
127 | """ | |
|
128 | if version is None: | |||
|
129 | from .reader import get_version | |||
|
130 | (version, version_minor) = get_version(nbjson) | |||
80 |
|
131 | |||
81 | if not schema: |
|
132 | validator = get_validator(version, version_minor) | |
82 | schema = json |
|
|||
83 |
|
||||
84 | # if it's a list, resolve references for each item in the list |
|
|||
85 | if type(json) is list: |
|
|||
86 | resolved = [] |
|
|||
87 | for item in json: |
|
|||
88 | resolved.append(resolve_ref(item, schema=schema)) |
|
|||
89 |
|
||||
90 | # if it's a dictionary, resolve references for each item in the |
|
|||
91 | # dictionary |
|
|||
92 | elif type(json) is dict: |
|
|||
93 | resolved = {} |
|
|||
94 | for key, ref in iteritems(json): |
|
|||
95 |
|
||||
96 | # if the key is equal to $ref, then replace the entire |
|
|||
97 | # dictionary with the resolved value |
|
|||
98 | if key == '$ref': |
|
|||
99 | if len(json) != 1: |
|
|||
100 | raise SchemaError( |
|
|||
101 | "objects containing a $ref should only have one item") |
|
|||
102 | pointer = jsonpointer.resolve_pointer(schema, ref) |
|
|||
103 | resolved = resolve_ref(pointer, schema=schema) |
|
|||
104 |
|
133 | |||
105 | else: |
|
134 | if validator is None: | |
106 | resolved[key] = resolve_ref(ref, schema=schema) |
|
135 | # no validator | |
|
136 | warnings.warn("No schema for validating v%s notebooks" % version, UserWarning) | |||
|
137 | return | |||
107 |
|
138 | |||
108 | # otherwise it's a normal object, so just return it |
|
139 | try: | |
109 | else: |
|
140 | if ref: | |
110 | resolved = json |
|
141 | return validator.validate(nbjson, {'$ref' : '#/definitions/%s' % ref}) | |
|
142 | else: | |||
|
143 | return validator.validate(nbjson) | |||
|
144 | except ValidationError as e: | |||
|
145 | raise better_validation_error(e, version, version_minor) | |||
111 |
|
146 | |||
112 | return resolved |
|
@@ -14,19 +14,11 b' itself from the command line. There are two ways of running this script:' | |||||
14 |
|
14 | |||
15 | """ |
|
15 | """ | |
16 |
|
16 | |||
17 | #----------------------------------------------------------------------------- |
|
17 | # Copyright (c) IPython Development Team. | |
18 | # Copyright (C) 2009-2011 The IPython Development Team |
|
18 | # Distributed under the terms of the Modified BSD License. | |
19 | # |
|
|||
20 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
21 | # the file COPYING, distributed as part of this software. |
|
|||
22 | #----------------------------------------------------------------------------- |
|
|||
23 |
|
19 | |||
24 | #----------------------------------------------------------------------------- |
|
|||
25 | # Imports |
|
|||
26 | #----------------------------------------------------------------------------- |
|
|||
27 | from __future__ import print_function |
|
20 | from __future__ import print_function | |
28 |
|
21 | |||
29 | # Stdlib |
|
|||
30 | import glob |
|
22 | import glob | |
31 | from io import BytesIO |
|
23 | from io import BytesIO | |
32 | import os |
|
24 | import os | |
@@ -35,7 +27,6 b' import sys' | |||||
35 | from threading import Thread, Lock, Event |
|
27 | from threading import Thread, Lock, Event | |
36 | import warnings |
|
28 | import warnings | |
37 |
|
29 | |||
38 | # Now, proceed to import nose itself |
|
|||
39 | import nose.plugins.builtin |
|
30 | import nose.plugins.builtin | |
40 | from nose.plugins.xunit import Xunit |
|
31 | from nose.plugins.xunit import Xunit | |
41 | from nose import SkipTest |
|
32 | from nose import SkipTest | |
@@ -43,7 +34,6 b' from nose.core import TestProgram' | |||||
43 | from nose.plugins import Plugin |
|
34 | from nose.plugins import Plugin | |
44 | from nose.util import safe_str |
|
35 | from nose.util import safe_str | |
45 |
|
36 | |||
46 | # Our own imports |
|
|||
47 | from IPython.utils.process import is_cmd_found |
|
37 | from IPython.utils.process import is_cmd_found | |
48 | from IPython.utils.importstring import import_item |
|
38 | from IPython.utils.importstring import import_item | |
49 | from IPython.testing.plugin.ipdoctest import IPythonDoctest |
|
39 | from IPython.testing.plugin.ipdoctest import IPythonDoctest | |
@@ -148,7 +138,6 b" have['mistune'] = test_for('mistune')" | |||||
148 | have['requests'] = test_for('requests') |
|
138 | have['requests'] = test_for('requests') | |
149 | have['sphinx'] = test_for('sphinx') |
|
139 | have['sphinx'] = test_for('sphinx') | |
150 | have['jsonschema'] = test_for('jsonschema') |
|
140 | have['jsonschema'] = test_for('jsonschema') | |
151 | have['jsonpointer'] = test_for('jsonpointer') |
|
|||
152 | have['casperjs'] = is_cmd_found('casperjs') |
|
141 | have['casperjs'] = is_cmd_found('casperjs') | |
153 | have['phantomjs'] = is_cmd_found('phantomjs') |
|
142 | have['phantomjs'] = is_cmd_found('phantomjs') | |
154 | have['slimerjs'] = is_cmd_found('slimerjs') |
|
143 | have['slimerjs'] = is_cmd_found('slimerjs') | |
@@ -268,7 +257,7 b" test_sections['qt'].requires('zmq', 'qt', 'pygments')" | |||||
268 |
|
257 | |||
269 | # html: |
|
258 | # html: | |
270 | sec = test_sections['html'] |
|
259 | sec = test_sections['html'] | |
271 |
sec.requires('zmq', 'tornado', 'requests', 'sqlite3', 'jsonschema' |
|
260 | sec.requires('zmq', 'tornado', 'requests', 'sqlite3', 'jsonschema') | |
272 | # The notebook 'static' directory contains JS, css and other |
|
261 | # The notebook 'static' directory contains JS, css and other | |
273 | # files for web serving. Occasionally projects may put a .py |
|
262 | # files for web serving. Occasionally projects may put a .py | |
274 | # file in there (MathJax ships a conf.py), so we might as |
|
263 | # file in there (MathJax ships a conf.py), so we might as | |
@@ -286,7 +275,7 b" test_sections['config'].exclude('profile')" | |||||
286 |
|
275 | |||
287 | # nbconvert: |
|
276 | # nbconvert: | |
288 | sec = test_sections['nbconvert'] |
|
277 | sec = test_sections['nbconvert'] | |
289 |
sec.requires('pygments', 'jinja2', 'jsonschema', ' |
|
278 | sec.requires('pygments', 'jinja2', 'jsonschema', 'mistune') | |
290 | # Exclude nbconvert directories containing config files used to test. |
|
279 | # Exclude nbconvert directories containing config files used to test. | |
291 | # Executing the config files with iptest would cause an exception. |
|
280 | # Executing the config files with iptest would cause an exception. | |
292 | sec.exclude('tests.files') |
|
281 | sec.exclude('tests.files') | |
@@ -296,7 +285,7 b" if not have['tornado']:" | |||||
296 | sec.exclude('nbconvert.post_processors.tests.test_serve') |
|
285 | sec.exclude('nbconvert.post_processors.tests.test_serve') | |
297 |
|
286 | |||
298 | # nbformat: |
|
287 | # nbformat: | |
299 |
test_sections['nbformat'].requires('jsonschema' |
|
288 | test_sections['nbformat'].requires('jsonschema') | |
300 |
|
289 | |||
301 | #----------------------------------------------------------------------------- |
|
290 | #----------------------------------------------------------------------------- | |
302 | # Functions and classes |
|
291 | # Functions and classes |
@@ -218,7 +218,7 b' def all_js_groups():' | |||||
218 | class JSController(TestController): |
|
218 | class JSController(TestController): | |
219 | """Run CasperJS tests """ |
|
219 | """Run CasperJS tests """ | |
220 | requirements = ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3', |
|
220 | requirements = ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3', | |
221 |
'jsonschema' |
|
221 | 'jsonschema'] | |
222 | display_slimer_output = False |
|
222 | display_slimer_output = False | |
223 |
|
223 | |||
224 | def __init__(self, section, xunit=True, engine='phantomjs'): |
|
224 | def __init__(self, section, xunit=True, engine='phantomjs'): |
@@ -465,3 +465,23 b" def help_all_output_test(subcommand=''):" | |||||
465 | nt.assert_in("Class parameters", out) |
|
465 | nt.assert_in("Class parameters", out) | |
466 | return out, err |
|
466 | return out, err | |
467 |
|
467 | |||
|
468 | def assert_big_text_equal(a, b, chunk_size=80): | |||
|
469 | """assert that large strings are equal | |||
|
470 | ||||
|
471 | Zooms in on first chunk that differs, | |||
|
472 | to give better info than vanilla assertEqual for large text blobs. | |||
|
473 | """ | |||
|
474 | for i in range(0, len(a), chunk_size): | |||
|
475 | chunk_a = a[i:i + chunk_size] | |||
|
476 | chunk_b = b[i:i + chunk_size] | |||
|
477 | nt.assert_equal(chunk_a, chunk_b, "[offset: %i]\n%r != \n%r" % ( | |||
|
478 | i, chunk_a, chunk_b)) | |||
|
479 | ||||
|
480 | if len(a) > len(b): | |||
|
481 | nt.fail("Length doesn't match (%i > %i). Extra text:\n%r" % ( | |||
|
482 | len(a), len(b), a[len(b):] | |||
|
483 | )) | |||
|
484 | elif len(a) < len(b): | |||
|
485 | nt.fail("Length doesn't match (%i < %i). Extra text:\n%r" % ( | |||
|
486 | len(a), len(b), b[len(a):] | |||
|
487 | )) |
@@ -275,7 +275,7 b' extras_require = dict(' | |||||
275 | doc = ['Sphinx>=1.1', 'numpydoc'], |
|
275 | doc = ['Sphinx>=1.1', 'numpydoc'], | |
276 | test = ['nose>=0.10.1'], |
|
276 | test = ['nose>=0.10.1'], | |
277 | terminal = [], |
|
277 | terminal = [], | |
278 |
nbformat = ['jsonschema>=2.0' |
|
278 | nbformat = ['jsonschema>=2.0'], | |
279 | notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.3.1'], |
|
279 | notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.3.1'], | |
280 | nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1'] |
|
280 | nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1'] | |
281 | ) |
|
281 | ) |
@@ -194,7 +194,10 b' def find_package_data():' | |||||
194 | 'preprocessors/tests/files/*.*', |
|
194 | 'preprocessors/tests/files/*.*', | |
195 | ], |
|
195 | ], | |
196 | 'IPython.nbconvert.filters' : ['marked.js'], |
|
196 | 'IPython.nbconvert.filters' : ['marked.js'], | |
197 |
'IPython.nbformat' : [ |
|
197 | 'IPython.nbformat' : [ | |
|
198 | 'tests/*.ipynb', | |||
|
199 | 'v3/nbformat.v3.schema.json', | |||
|
200 | ] | |||
198 | } |
|
201 | } | |
199 |
|
202 | |||
200 | return package_data |
|
203 | return package_data |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now