##// END OF EJS Templates
Use Draft4 JSON Schema for both v3 and v4...
MinRK -
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 """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
@@ -17,7 +20,7 b' from IPython.nbformat import v3 as _v_latest'
17 from .reader import reads as reader_reads
20 from .reader import reads as reader_reads
18 from .reader import versions
21 from .reader import versions
19 from .convert import convert
22 from .convert import convert
20 from .validator import validate
23 from .validator import validate, ValidationError
21
24
22 from IPython.utils.log import get_logger
25 from IPython.utils.log import get_logger
23
26
@@ -60,11 +63,10 b' def reads_json(nbjson, **kwargs):'
60 """
63 """
61 nb = reader_reads(nbjson, **kwargs)
64 nb = reader_reads(nbjson, **kwargs)
62 nb_current = convert(nb, current_nbformat)
65 nb_current = convert(nb, current_nbformat)
63 errors = validate(nb_current)
66 try:
64 if errors:
67 validate(nb_current)
65 get_logger().error(
68 except ValidationError as e:
66 "Notebook JSON is invalid (%d errors detected during read)",
69 get_logger().error("Notebook JSON is invalid: %s", e)
67 len(errors))
68 return nb_current
70 return nb_current
69
71
70
72
@@ -73,11 +75,10 b' def writes_json(nb, **kwargs):'
73 any JSON format errors are detected.
75 any JSON format errors are detected.
74
76
75 """
77 """
76 errors = validate(nb)
78 try:
77 if errors:
79 validate(nb)
78 get_logger().error(
80 except ValidationError as e:
79 "Notebook JSON is invalid (%d errors detected during write)",
81 get_logger().error("Notebook JSON is invalid: %s", e)
80 len(errors))
81 nbjson = versions[current_nbformat].writes_json(nb, **kwargs)
82 nbjson = versions[current_nbformat].writes_json(nb, **kwargs)
82 return nbjson
83 return nbjson
83
84
@@ -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 SchemaError
9 from jsonschema import ValidationError
19 from ..current import read
10 from ..current import read
20 from ..validator import schema_path, isvalid, validate, resolve_ref
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 self.assertEqual(validate(nb), [])
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 self.assertEqual(validate(nb), [])
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,7 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.assertEqual(len(validate(nb)), 3)
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_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 # 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 = 'v3.withref.json'
25 nbformat_schema = 'nbformat.v3.schema.json'
26
26
27 class NotebookNode(Struct):
27 class NotebookNode(Struct):
28 pass
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 from __future__ import print_function
4 from __future__ import print_function
2 import json
5 import json
3 import os
6 import os
4
7
5 try:
8 try:
6 from jsonschema import SchemaError
9 from jsonschema import ValidationError
7 from jsonschema import Draft3Validator as Validator
10 from jsonschema import Draft4Validator as Validator
8 except ImportError as e:
11 except ImportError as e:
9 verbose_msg = """
12 verbose_msg = """
10
13
11 IPython depends on the jsonschema package: https://pypi.python.org/pypi/jsonschema
14 IPython notebook format depends on the jsonschema package:
12
15
13 Please install it first.
16 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
17
24 Please install it first.
18 Please install it first.
25 """
19 """
26 raise ImportError(str(e) + verbose_msg)
20 raise ImportError(str(e) + verbose_msg)
27
21
28 from IPython.utils.py3compat import iteritems
22 from IPython.utils.importstring import import_item
29
23
30
24
31 from .current import nbformat, nbformat_schema
25 validators = {}
32 schema_path = os.path.join(
33 os.path.dirname(__file__), "v%d" % nbformat, nbformat_schema)
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 """Checks whether the given notebook JSON conforms to the current
41 """Checks whether the given notebook JSON conforms to the current
38 notebook format schema. Returns True if the JSON is valid, and
42 notebook format schema. Returns True if the JSON is valid, and
39 False otherwise.
43 False otherwise.
40
44
41 To see the individual errors that were encountered, please use the
45 To see the individual errors that were encountered, please use the
42 `validate` function instead.
46 `validate` function instead.
43
44 """
47 """
45
48 try:
46 errors = validate(nbjson)
49 validate(nbjson, ref, version)
47 return errors == []
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 """Checks whether the given notebook JSON conforms to the current
57 """Checks whether the given notebook JSON conforms to the current
52 notebook format schema, and returns the list of errors.
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
66 validator = get_validator(version)
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 """
80
67
81 if not schema:
68 if ref:
82 schema = json
69 return validator.validate(nbjson, {'$ref' : '#/definitions/%s' % ref})
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
109 else:
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 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', 'jsonpointer']
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'):
@@ -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', 'jsonpointer>=1.3'],
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' : ['tests/*.ipynb','v3/v3.withref.json']
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