Show More
@@ -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"] | |
|
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", "collapsed", "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 | } |
@@ -1,5 +1,8 b'' | |||
|
1 | 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 | 6 | from __future__ import print_function |
|
4 | 7 | |
|
5 | 8 | import re |
@@ -17,7 +20,7 b' from IPython.nbformat import v3 as _v_latest' | |||
|
17 | 20 | from .reader import reads as reader_reads |
|
18 | 21 | from .reader import versions |
|
19 | 22 | from .convert import convert |
|
20 | from .validator import validate | |
|
23 | from .validator import validate, ValidationError | |
|
21 | 24 | |
|
22 | 25 | from IPython.utils.log import get_logger |
|
23 | 26 | |
@@ -60,11 +63,10 b' def reads_json(nbjson, **kwargs):' | |||
|
60 | 63 | """ |
|
61 | 64 | nb = reader_reads(nbjson, **kwargs) |
|
62 | 65 | 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)) | |
|
66 | try: | |
|
67 | validate(nb_current) | |
|
68 | except ValidationError as e: | |
|
69 | get_logger().error("Notebook JSON is invalid: %s", e) | |
|
68 | 70 | return nb_current |
|
69 | 71 | |
|
70 | 72 | |
@@ -73,11 +75,10 b' def writes_json(nb, **kwargs):' | |||
|
73 | 75 | any JSON format errors are detected. |
|
74 | 76 | |
|
75 | 77 | """ |
|
76 | errors = validate(nb) | |
|
77 | if errors: | |
|
78 | get_logger().error( | |
|
79 | "Notebook JSON is invalid (%d errors detected during write)", | |
|
80 | len(errors)) | |
|
78 | try: | |
|
79 | validate(nb) | |
|
80 | except ValidationError as e: | |
|
81 | get_logger().error("Notebook JSON is invalid: %s", e) | |
|
81 | 82 | nbjson = versions[current_nbformat].writes_json(nb, **kwargs) |
|
82 | 83 | return nbjson |
|
83 | 84 |
@@ -1,23 +1,14 b'' | |||
|
1 | """ | |
|
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 | #----------------------------------------------------------------------------- | |
|
1 | """Test nbformat.validator""" | |
|
10 | 2 | |
|
11 | #----------------------------------------------------------------------------- | |
|
12 | # Imports | |
|
13 | #----------------------------------------------------------------------------- | |
|
3 | # Copyright (c) IPython Development Team. | |
|
4 | # Distributed under the terms of the Modified BSD License. | |
|
14 | 5 | |
|
15 | 6 | import os |
|
16 | 7 | |
|
17 | 8 | from .base import TestsBase |
|
18 |
from jsonschema import |
|
|
9 | from jsonschema import ValidationError | |
|
19 | 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 | 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 | 20 | def test_nb2(self): |
|
34 | 21 | """Test that a v2 notebook converted to v3 passes validation""" |
|
35 | 22 | with self.fopen(u'test2.ipynb', u'r') as f: |
|
36 | 23 | nb = read(f, u'json') |
|
37 |
|
|
|
24 | validate(nb) | |
|
38 | 25 | self.assertEqual(isvalid(nb), True) |
|
39 | 26 | |
|
40 | 27 | def test_nb3(self): |
|
41 | 28 | """Test that a v3 notebook passes validation""" |
|
42 | 29 | with self.fopen(u'test3.ipynb', u'r') as f: |
|
43 | 30 | nb = read(f, u'json') |
|
44 |
|
|
|
31 | validate(nb) | |
|
45 | 32 | self.assertEqual(isvalid(nb), True) |
|
46 | 33 | |
|
47 | 34 | def test_invalid(self): |
@@ -52,22 +39,7 b' class TestValidator(TestsBase):' | |||
|
52 | 39 | # - one cell has an invalid level |
|
53 | 40 | with self.fopen(u'invalid.ipynb', u'r') as f: |
|
54 | 41 | nb = read(f, u'json') |
|
55 |
self.assert |
|
|
42 | with self.assertRaises(ValidationError): | |
|
43 | validate(nb) | |
|
56 | 44 | self.assertEqual(isvalid(nb), False) |
|
57 | 45 | |
|
58 | def test_resolve_ref(self): | |
|
59 | """Test that references are correctly resolved""" | |
|
60 | # make sure it resolves the ref correctly | |
|
61 | json = {"abc": "def", "ghi": {"$ref": "/abc"}} | |
|
62 | resolved = resolve_ref(json) | |
|
63 | self.assertEqual(resolved, {"abc": "def", "ghi": "def"}) | |
|
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 | ||
|
70 | # make sure it can handle json with no reference | |
|
71 | json = {"abc": "def"} | |
|
72 | resolved = resolve_ref(json) | |
|
73 | self.assertEqual(resolved, json) |
@@ -22,7 +22,7 b' from IPython.utils.py3compat import cast_unicode, unicode_type' | |||
|
22 | 22 | # Change this when incrementing the nbformat version |
|
23 | 23 | nbformat = 3 |
|
24 | 24 | nbformat_minor = 0 |
|
25 |
nbformat_schema = ' |
|
|
25 | nbformat_schema = 'nbformat.v3.schema.json' | |
|
26 | 26 | |
|
27 | 27 | class NotebookNode(Struct): |
|
28 | 28 | pass |
@@ -1,112 +1,72 b'' | |||
|
1 | # Copyright (c) IPython Development Team. | |
|
2 | # Distributed under the terms of the Modified BSD License. | |
|
3 | ||
|
1 | 4 | from __future__ import print_function |
|
2 | 5 | import json |
|
3 | 6 | import os |
|
4 | 7 | |
|
5 | 8 | try: |
|
6 |
from jsonschema import |
|
|
7 |
from jsonschema import Draft |
|
|
9 | from jsonschema import ValidationError | |
|
10 | from jsonschema import Draft4Validator as Validator | |
|
8 | 11 | except ImportError as e: |
|
9 | 12 | verbose_msg = """ |
|
10 | 13 | |
|
11 |
IPython depends on the jsonschema package: |
|
|
14 | IPython notebook format depends on the jsonschema package: | |
|
12 | 15 | |
|
13 | Please install it first. | |
|
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 | |
|
16 | https://pypi.python.org/pypi/jsonschema | |
|
23 | 17 | |
|
24 | 18 | Please install it first. |
|
25 | 19 | """ |
|
26 | 20 | raise ImportError(str(e) + verbose_msg) |
|
27 | 21 | |
|
28 |
from IPython.utils. |
|
|
22 | from IPython.utils.importstring import import_item | |
|
29 | 23 | |
|
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) | |
|
25 | validators = {} | |
|
34 | 26 | |
|
27 | def get_validator(version=None): | |
|
28 | """Load the JSON schema into a Validator""" | |
|
29 | if version is None: | |
|
30 | from .current import nbformat as version | |
|
35 | 31 | |
|
36 | def isvalid(nbjson): | |
|
32 | if version not in validators: | |
|
33 | v = import_item("IPython.nbformat.v%s" % version) | |
|
34 | schema_path = os.path.join(os.path.dirname(v.__file__), v.nbformat_schema) | |
|
35 | with open(schema_path) as f: | |
|
36 | schema_json = json.load(f) | |
|
37 | validators[version] = Validator(schema_json) | |
|
38 | return validators[version] | |
|
39 | ||
|
40 | def isvalid(nbjson, ref=None, version=None): | |
|
37 | 41 | """Checks whether the given notebook JSON conforms to the current |
|
38 | 42 | notebook format schema. Returns True if the JSON is valid, and |
|
39 | 43 | False otherwise. |
|
40 | 44 | |
|
41 | 45 | To see the individual errors that were encountered, please use the |
|
42 | 46 | `validate` function instead. |
|
43 | ||
|
44 | 47 | """ |
|
45 | ||
|
46 |
|
|
|
47 | return errors == [] | |
|
48 | try: | |
|
49 | validate(nbjson, ref, version) | |
|
50 | except ValidationError: | |
|
51 | return False | |
|
52 | else: | |
|
53 | return True | |
|
48 | 54 | |
|
49 | 55 | |
|
50 | def validate(nbjson): | |
|
56 | def validate(nbjson, ref=None, version=None): | |
|
51 | 57 | """Checks whether the given notebook JSON conforms to the current |
|
52 |
notebook format schema |
|
|
58 | notebook format schema. | |
|
53 | 59 | |
|
60 | Raises ValidationError if not valid. | |
|
54 | 61 | """ |
|
62 | if version is None: | |
|
63 | from .current import nbformat | |
|
64 | version = nbjson.get('nbformat', nbformat) | |
|
55 | 65 | |
|
56 | # load the schema file | |
|
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 | """ | |
|
66 | validator = get_validator(version) | |
|
80 | 67 | |
|
81 |
if |
|
|
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 | ||
|
105 | else: | |
|
106 | resolved[key] = resolve_ref(ref, schema=schema) | |
|
107 | ||
|
108 | # otherwise it's a normal object, so just return it | |
|
68 | if ref: | |
|
69 | return validator.validate(nbjson, {'$ref' : '#/definitions/%s' % ref}) | |
|
109 | 70 | else: |
|
110 | resolved = json | |
|
71 | return validator.validate(nbjson) | |
|
111 | 72 | |
|
112 | return resolved |
@@ -218,7 +218,7 b' def all_js_groups():' | |||
|
218 | 218 | class JSController(TestController): |
|
219 | 219 | """Run CasperJS tests """ |
|
220 | 220 | requirements = ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3', |
|
221 |
'jsonschema' |
|
|
221 | 'jsonschema'] | |
|
222 | 222 | display_slimer_output = False |
|
223 | 223 | |
|
224 | 224 | def __init__(self, section, xunit=True, engine='phantomjs'): |
@@ -275,7 +275,7 b' extras_require = dict(' | |||
|
275 | 275 | doc = ['Sphinx>=1.1', 'numpydoc'], |
|
276 | 276 | test = ['nose>=0.10.1'], |
|
277 | 277 | terminal = [], |
|
278 |
nbformat = ['jsonschema>=2.0' |
|
|
278 | nbformat = ['jsonschema>=2.0'], | |
|
279 | 279 | notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2', 'pygments', 'mistune>=0.3.1'], |
|
280 | 280 | nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1'] |
|
281 | 281 | ) |
@@ -194,7 +194,10 b' def find_package_data():' | |||
|
194 | 194 | 'preprocessors/tests/files/*.*', |
|
195 | 195 | ], |
|
196 | 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 | 203 | return package_data |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now