##// END OF EJS Templates
Merge pull request #6991 from minrk/unhandled-types...
Thomas Kluyver -
r19117:bc59b4a1 merge
parent child Browse files
Show More
@@ -53,7 +53,9 b' define(['
53 get: function() { return that._metadata; },
53 get: function() { return that._metadata; },
54 set: function(value) {
54 set: function(value) {
55 that._metadata = value;
55 that._metadata = value;
56 that.celltoolbar.rebuild();
56 if (that.celltoolbar) {
57 that.celltoolbar.rebuild();
58 }
57 }
59 }
58 });
60 });
59
61
@@ -194,11 +196,11 b' define(['
194 if((cur.line !== 0 || cur.ch !==0) && event.keyCode === 38){
196 if((cur.line !== 0 || cur.ch !==0) && event.keyCode === 38){
195 event._ipkmIgnore = true;
197 event._ipkmIgnore = true;
196 }
198 }
197 var nLastLine = editor.lastLine()
199 var nLastLine = editor.lastLine();
198 if( ( event.keyCode === 40)
200 if ((event.keyCode === 40) &&
199 && (( cur.line !== nLastLine)
201 ((cur.line !== nLastLine) ||
200 || ( cur.ch !== editor.getLineHandle(nLastLine).text.length))
202 (cur.ch !== editor.getLineHandle(nLastLine).text.length))
201 ){
203 ) {
202 event._ipkmIgnore = true;
204 event._ipkmIgnore = true;
203 }
205 }
204 // if this is an edit_shortcuts shortcut, the global keyboard/shortcut
206 // if this is an edit_shortcuts shortcut, the global keyboard/shortcut
@@ -255,6 +257,14 b' define(['
255 };
257 };
256
258
257 /**
259 /**
260 * should be overritten by subclass
261 * @method execute
262 */
263 Cell.prototype.execute = function () {
264 return;
265 };
266
267 /**
258 * handle cell level logic when a cell is rendered
268 * handle cell level logic when a cell is rendered
259 * @method render
269 * @method render
260 * @return is the action being taken
270 * @return is the action being taken
@@ -386,7 +396,9 b' define(['
386 * @method refresh
396 * @method refresh
387 */
397 */
388 Cell.prototype.refresh = function () {
398 Cell.prototype.refresh = function () {
389 this.code_mirror.refresh();
399 if (this.code_mirror) {
400 this.code_mirror.refresh();
401 }
390 };
402 };
391
403
392 /**
404 /**
@@ -590,8 +602,74 b' define(['
590 this.code_mirror.setOption('mode', default_mode);
602 this.code_mirror.setOption('mode', default_mode);
591 };
603 };
592
604
605 var UnrecognizedCell = function (options) {
606 /** Constructor for unrecognized cells */
607 Cell.apply(this, arguments);
608 this.cell_type = 'unrecognized';
609 this.celltoolbar = null;
610 this.data = {};
611
612 Object.seal(this);
613 };
614
615 UnrecognizedCell.prototype = Object.create(Cell.prototype);
616
617
618 // cannot merge or split unrecognized cells
619 UnrecognizedCell.prototype.is_mergeable = function () {
620 return false;
621 };
622
623 UnrecognizedCell.prototype.is_splittable = function () {
624 return false;
625 };
626
627 UnrecognizedCell.prototype.toJSON = function () {
628 // deepcopy the metadata so copied cells don't share the same object
629 return JSON.parse(JSON.stringify(this.data));
630 };
631
632 UnrecognizedCell.prototype.fromJSON = function (data) {
633 this.data = data;
634 if (data.metadata !== undefined) {
635 this.metadata = data.metadata;
636 } else {
637 data.metadata = this.metadata;
638 }
639 this.element.find('.inner_cell').find("a").text("Unrecognized cell type: " + data.cell_type);
640 };
641
642 UnrecognizedCell.prototype.create_element = function () {
643 Cell.prototype.create_element.apply(this, arguments);
644 var cell = this.element = $("<div>").addClass('cell unrecognized_cell');
645 cell.attr('tabindex','2');
646
647 var prompt = $('<div/>').addClass('prompt input_prompt');
648 cell.append(prompt);
649 var inner_cell = $('<div/>').addClass('inner_cell');
650 inner_cell.append(
651 $("<a>")
652 .attr("href", "#")
653 .text("Unrecognized cell type")
654 );
655 cell.append(inner_cell);
656 this.element = cell;
657 };
658
659 UnrecognizedCell.prototype.bind_events = function () {
660 Cell.prototype.bind_events.apply(this, arguments);
661 var cell = this;
662
663 this.element.find('.inner_cell').find("a").click(function () {
664 cell.events.trigger('unrecognized_cell.Cell', {cell: cell})
665 });
666 };
667
593 // Backwards compatibility.
668 // Backwards compatibility.
594 IPython.Cell = Cell;
669 IPython.Cell = Cell;
595
670
596 return {'Cell': Cell};
671 return {
672 Cell: Cell,
673 UnrecognizedCell: UnrecognizedCell
674 };
597 });
675 });
@@ -6,6 +6,7 b' define(['
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 'base/js/dialog',
8 'base/js/dialog',
9 'notebook/js/cell',
9 'notebook/js/textcell',
10 'notebook/js/textcell',
10 'notebook/js/codecell',
11 'notebook/js/codecell',
11 'services/sessions/session',
12 'services/sessions/session',
@@ -22,13 +23,14 b' define(['
22 'notebook/js/scrollmanager'
23 'notebook/js/scrollmanager'
23 ], function (
24 ], function (
24 IPython,
25 IPython,
25 $,
26 $,
26 utils,
27 utils,
27 dialog,
28 dialog,
28 textcell,
29 cellmod,
29 codecell,
30 textcell,
31 codecell,
30 session,
32 session,
31 celltoolbar,
33 celltoolbar,
32 marked,
34 marked,
33 CodeMirror,
35 CodeMirror,
34 runMode,
36 runMode,
@@ -147,7 +149,7 b' define(['
147 this.minimum_autosave_interval = 120000;
149 this.minimum_autosave_interval = 120000;
148 this.notebook_name_blacklist_re = /[\/\\:]/;
150 this.notebook_name_blacklist_re = /[\/\\:]/;
149 this.nbformat = 4; // Increment this when changing the nbformat
151 this.nbformat = 4; // Increment this when changing the nbformat
150 this.nbformat_minor = 0; // Increment this when changing the nbformat
152 this.nbformat_minor = this.current_nbformat_minor = 0; // Increment this when changing the nbformat
151 this.codemirror_mode = 'ipython';
153 this.codemirror_mode = 'ipython';
152 this.create_elements();
154 this.create_elements();
153 this.bind_events();
155 this.bind_events();
@@ -211,6 +213,14 b' define(['
211 that.dirty = true;
213 that.dirty = true;
212 });
214 });
213
215
216 this.events.on('unrecognized_cell.Cell', function () {
217 that.warn_nbformat_minor();
218 });
219
220 this.events.on('unrecognized_output.OutputArea', function () {
221 that.warn_nbformat_minor();
222 });
223
214 this.events.on('set_dirty.Notebook', function (event, data) {
224 this.events.on('set_dirty.Notebook', function (event, data) {
215 that.dirty = data.value;
225 that.dirty = data.value;
216 });
226 });
@@ -304,6 +314,28 b' define(['
304 return null;
314 return null;
305 };
315 };
306 };
316 };
317
318 Notebook.prototype.warn_nbformat_minor = function (event) {
319 // trigger a warning dialog about missing functionality from newer minor versions
320 var v = 'v' + this.nbformat + '.';
321 var orig_vs = v + this.nbformat_minor;
322 var this_vs = v + this.current_nbformat_minor;
323 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
324 this_vs + ". You can still work with this notebook, but cell and output types " +
325 "introduced in later notebook versions will not be available.";
326
327 dialog.modal({
328 notebook: this,
329 keyboard_manager: this.keyboard_manager,
330 title : "Newer Notebook",
331 body : msg,
332 buttons : {
333 OK : {
334 "class" : "btn-danger"
335 }
336 }
337 });
338 }
307
339
308 /**
340 /**
309 * Set the dirty flag, and trigger the set_dirty.Notebook event
341 * Set the dirty flag, and trigger the set_dirty.Notebook event
@@ -900,7 +932,8 b' define(['
900 cell = new textcell.RawCell(cell_options);
932 cell = new textcell.RawCell(cell_options);
901 break;
933 break;
902 default:
934 default:
903 console.log("invalid cell type: ", type);
935 console.log("Unrecognized cell type: ", type, cellmod);
936 cell = new cellmod.UnrecognizedCell(cell_options);
904 }
937 }
905
938
906 if(this._insert_element_at_index(cell.element,index)) {
939 if(this._insert_element_at_index(cell.element,index)) {
@@ -2222,26 +2255,8 b' define(['
2222 }
2255 }
2223 }
2256 }
2224 });
2257 });
2225 } else if (orig_nbformat_minor !== undefined && nbmodel.nbformat_minor < orig_nbformat_minor) {
2258 } else if (this.nbformat_minor < nbmodel.nbformat_minor) {
2226 var that = this;
2259 this.nbformat_minor = nbmodel.nbformat_minor;
2227 var orig_vs = 'v' + nbmodel.nbformat + '.' + orig_nbformat_minor;
2228 var this_vs = 'v' + nbmodel.nbformat + '.' + this.nbformat_minor;
2229 msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
2230 this_vs + ". You can still work with this notebook, but some features " +
2231 "introduced in later notebook versions may not be available.";
2232
2233 dialog.modal({
2234 notebook: this,
2235 keyboard_manager: this.keyboard_manager,
2236 title : "Newer Notebook",
2237 body : msg,
2238 buttons : {
2239 OK : {
2240 class : "btn-danger"
2241 }
2242 }
2243 });
2244
2245 }
2260 }
2246
2261
2247 // Create the session after the notebook is completely loaded to prevent
2262 // Create the session after the notebook is completely loaded to prevent
@@ -245,7 +245,7 b' define(['
245 'text/plain'
245 'text/plain'
246 ];
246 ];
247
247
248 OutputArea.prototype.validate_output = function (json) {
248 OutputArea.prototype.validate_mimebundle = function (json) {
249 // scrub invalid outputs
249 // scrub invalid outputs
250 var data = json.data;
250 var data = json.data;
251 $.map(OutputArea.output_types, function(key){
251 $.map(OutputArea.output_types, function(key){
@@ -263,11 +263,6 b' define(['
263 OutputArea.prototype.append_output = function (json) {
263 OutputArea.prototype.append_output = function (json) {
264 this.expand();
264 this.expand();
265
265
266 // validate output data types
267 if (json.data) {
268 json = this.validate_output(json);
269 }
270
271 // Clear the output if clear is queued.
266 // Clear the output if clear is queued.
272 var needs_height_reset = false;
267 var needs_height_reset = false;
273 if (this.clear_queued) {
268 if (this.clear_queued) {
@@ -276,14 +271,25 b' define(['
276 }
271 }
277
272
278 var record_output = true;
273 var record_output = true;
279
274 switch(json.output_type) {
280 if (json.output_type === 'execute_result') {
275 case 'execute_result':
281 this.append_execute_result(json);
276 json = this.validate_mimebundle(json);
282 } else if (json.output_type === 'error') {
277 this.append_execute_result(json);
283 this.append_error(json);
278 break;
284 } else if (json.output_type === 'stream') {
279 case 'stream':
285 // append_stream might have merged the output with earlier stream output
280 // append_stream might have merged the output with earlier stream output
286 record_output = this.append_stream(json);
281 record_output = this.append_stream(json);
282 break;
283 case 'error':
284 this.append_error(json);
285 break;
286 case 'display_data':
287 // append handled below
288 json = this.validate_mimebundle(json);
289 break;
290 default:
291 console.log("unrecognized output type: " + json.output_type);
292 this.append_unrecognized(json);
287 }
293 }
288
294
289 // We must release the animation fixed height in a callback since Gecko
295 // We must release the animation fixed height in a callback since Gecko
@@ -485,6 +491,23 b' define(['
485 };
491 };
486
492
487
493
494 OutputArea.prototype.append_unrecognized = function (json) {
495 var that = this;
496 var toinsert = this.create_output_area();
497 var subarea = $('<div/>').addClass('output_subarea output_unrecognized');
498 toinsert.append(subarea);
499 subarea.append(
500 $("<a>")
501 .attr("href", "#")
502 .text("Unrecognized output: " + json.output_type)
503 .click(function () {
504 that.events.trigger('unrecognized_output.OutputArea', {output: json})
505 })
506 );
507 this._safe_append(toinsert);
508 };
509
510
488 OutputArea.prototype.append_display_data = function (json, handle_inserted) {
511 OutputArea.prototype.append_display_data = function (json, handle_inserted) {
489 var toinsert = this.create_output_area();
512 var toinsert = this.create_output_area();
490 if (this.append_mime_type(json, toinsert, handle_inserted)) {
513 if (this.append_mime_type(json, toinsert, handle_inserted)) {
@@ -338,7 +338,7 b' define(['
338 var textcell = {
338 var textcell = {
339 TextCell: TextCell,
339 TextCell: TextCell,
340 MarkdownCell: MarkdownCell,
340 MarkdownCell: MarkdownCell,
341 RawCell: RawCell,
341 RawCell: RawCell
342 };
342 };
343 return textcell;
343 return textcell;
344 });
344 });
@@ -61,3 +61,34 b' div.prompt:empty {'
61 padding-top: 0;
61 padding-top: 0;
62 padding-bottom: 0;
62 padding-bottom: 0;
63 }
63 }
64
65 div.unrecognized_cell {
66 // from text_cell
67 padding: 5px 5px 5px 0px;
68 .hbox();
69
70 .inner_cell {
71 .border-radius(@border-radius-base);
72 padding: 5px;
73 font-weight: bold;
74 color: red;
75 border: 1px solid @light_border_color;
76 background: darken(@cell_background, 5%);
77 // remove decoration from link
78 a {
79 color: inherit;
80 text-decoration: none;
81
82 &:hover {
83 color: inherit;
84 text-decoration: none;
85 }
86 }
87 }
88 }
89 @media (max-width: 480px) {
90 // remove prompt indentation on small screens
91 div.unrecognized_cell > div.prompt {
92 display: none;
93 }
94 }
@@ -172,3 +172,19 b' input.raw_input:focus {'
172 p.p-space {
172 p.p-space {
173 margin-bottom: 10px;
173 margin-bottom: 10px;
174 }
174 }
175
176 div.output_unrecognized {
177 padding: 5px;
178 font-weight: bold;
179 color: red;
180 // remove decoration from link
181 a {
182 color: inherit;
183 text-decoration: none;
184
185 &:hover {
186 color: inherit;
187 text-decoration: none;
188 }
189 }
190 } No newline at end of file
@@ -419,6 +419,44 b' div.prompt:empty {'
419 padding-top: 0;
419 padding-top: 0;
420 padding-bottom: 0;
420 padding-bottom: 0;
421 }
421 }
422 div.unrecognized_cell {
423 padding: 5px 5px 5px 0px;
424 /* Old browsers */
425 display: -webkit-box;
426 -webkit-box-orient: horizontal;
427 -webkit-box-align: stretch;
428 display: -moz-box;
429 -moz-box-orient: horizontal;
430 -moz-box-align: stretch;
431 display: box;
432 box-orient: horizontal;
433 box-align: stretch;
434 /* Modern browsers */
435 display: flex;
436 flex-direction: row;
437 align-items: stretch;
438 }
439 div.unrecognized_cell .inner_cell {
440 border-radius: 4px;
441 padding: 5px;
442 font-weight: bold;
443 color: red;
444 border: 1px solid #cfcfcf;
445 background: #eaeaea;
446 }
447 div.unrecognized_cell .inner_cell a {
448 color: inherit;
449 text-decoration: none;
450 }
451 div.unrecognized_cell .inner_cell a:hover {
452 color: inherit;
453 text-decoration: none;
454 }
455 @media (max-width: 480px) {
456 div.unrecognized_cell > div.prompt {
457 display: none;
458 }
459 }
422 /* any special styling for code cells that are currently running goes here */
460 /* any special styling for code cells that are currently running goes here */
423 div.input {
461 div.input {
424 page-break-inside: avoid;
462 page-break-inside: avoid;
@@ -888,6 +926,19 b' input.raw_input:focus {'
888 p.p-space {
926 p.p-space {
889 margin-bottom: 10px;
927 margin-bottom: 10px;
890 }
928 }
929 div.output_unrecognized {
930 padding: 5px;
931 font-weight: bold;
932 color: red;
933 }
934 div.output_unrecognized a {
935 color: inherit;
936 text-decoration: none;
937 }
938 div.output_unrecognized a:hover {
939 color: inherit;
940 text-decoration: none;
941 }
891 .rendered_html {
942 .rendered_html {
892 color: #000000;
943 color: #000000;
893 /* any extras will just be numbers: */
944 /* any extras will just be numbers: */
@@ -8291,6 +8291,44 b' div.prompt:empty {'
8291 padding-top: 0;
8291 padding-top: 0;
8292 padding-bottom: 0;
8292 padding-bottom: 0;
8293 }
8293 }
8294 div.unrecognized_cell {
8295 padding: 5px 5px 5px 0px;
8296 /* Old browsers */
8297 display: -webkit-box;
8298 -webkit-box-orient: horizontal;
8299 -webkit-box-align: stretch;
8300 display: -moz-box;
8301 -moz-box-orient: horizontal;
8302 -moz-box-align: stretch;
8303 display: box;
8304 box-orient: horizontal;
8305 box-align: stretch;
8306 /* Modern browsers */
8307 display: flex;
8308 flex-direction: row;
8309 align-items: stretch;
8310 }
8311 div.unrecognized_cell .inner_cell {
8312 border-radius: 4px;
8313 padding: 5px;
8314 font-weight: bold;
8315 color: red;
8316 border: 1px solid #cfcfcf;
8317 background: #eaeaea;
8318 }
8319 div.unrecognized_cell .inner_cell a {
8320 color: inherit;
8321 text-decoration: none;
8322 }
8323 div.unrecognized_cell .inner_cell a:hover {
8324 color: inherit;
8325 text-decoration: none;
8326 }
8327 @media (max-width: 480px) {
8328 div.unrecognized_cell > div.prompt {
8329 display: none;
8330 }
8331 }
8294 /* any special styling for code cells that are currently running goes here */
8332 /* any special styling for code cells that are currently running goes here */
8295 div.input {
8333 div.input {
8296 page-break-inside: avoid;
8334 page-break-inside: avoid;
@@ -8760,6 +8798,19 b' input.raw_input:focus {'
8760 p.p-space {
8798 p.p-space {
8761 margin-bottom: 10px;
8799 margin-bottom: 10px;
8762 }
8800 }
8801 div.output_unrecognized {
8802 padding: 5px;
8803 font-weight: bold;
8804 color: red;
8805 }
8806 div.output_unrecognized a {
8807 color: inherit;
8808 text-decoration: none;
8809 }
8810 div.output_unrecognized a:hover {
8811 color: inherit;
8812 text-decoration: none;
8813 }
8763 .rendered_html {
8814 .rendered_html {
8764 color: #000000;
8815 color: #000000;
8765 /* any extras will just be numbers: */
8816 /* any extras will just be numbers: */
@@ -306,6 +306,41 b''
306 "from IPython.display import Image\n",
306 "from IPython.display import Image\n",
307 "Image(\"http://ipython.org/_static/IPy_header.png\")"
307 "Image(\"http://ipython.org/_static/IPy_header.png\")"
308 ]
308 ]
309 },
310 {
311 "cell_type": "future cell",
312 "metadata": {},
313 "key": "value"
314 },
315 {
316 "cell_type": "code",
317 "execution_count": 99,
318 "metadata": {},
319 "outputs": [
320 {
321 "name": "stdout",
322 "output_type": "stream",
323 "text": [
324 "hello\n"
325 ]
326 },
327 {
328 "output_type": "future output",
329 "some key": [
330 "some data"
331 ]
332 },
333 {
334 "name": "stdout",
335 "output_type": "stream",
336 "text": [
337 "hello again\n"
338 ]
339 }
340 ],
341 "source": [
342 "future_output()"
343 ]
309 }
344 }
310 ],
345 ],
311 "metadata": {},
346 "metadata": {},
@@ -54,18 +54,19 b''
54 "cells": {
54 "cells": {
55 "description": "Array of cells of the current notebook.",
55 "description": "Array of cells of the current notebook.",
56 "type": "array",
56 "type": "array",
57 "items": {
57 "items": {"$ref": "#/definitions/cell"}
58 "type": "object",
59 "oneOf": [
60 {"$ref": "#/definitions/raw_cell"},
61 {"$ref": "#/definitions/markdown_cell"},
62 {"$ref": "#/definitions/code_cell"}
63 ]
64 }
65 }
58 }
66 },
59 },
67
60
68 "definitions": {
61 "definitions": {
62 "cell": {
63 "type": "object",
64 "oneOf": [
65 {"$ref": "#/definitions/raw_cell"},
66 {"$ref": "#/definitions/markdown_cell"},
67 {"$ref": "#/definitions/code_cell"}
68 ]
69 },
69
70
70 "raw_cell": {
71 "raw_cell": {
71 "description": "Notebook raw nbconvert cell.",
72 "description": "Notebook raw nbconvert cell.",
@@ -157,6 +158,31 b''
157 }
158 }
158 }
159 }
159 },
160 },
161
162 "unrecognized_cell": {
163 "description": "Unrecognized cell from a future minor-revision to the notebook format.",
164 "type": "object",
165 "additionalProperties": true,
166 "required": ["cell_type", "metadata"],
167 "properties": {
168 "cell_type": {
169 "description": "String identifying the type of cell.",
170 "not" : {
171 "enum": ["markdown", "code", "raw"]
172 }
173 },
174 "metadata": {
175 "description": "Cell-level metadata.",
176 "type": "object",
177 "properties": {
178 "name": {"$ref": "#/definitions/misc/metadata_name"},
179 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
180 },
181 "additionalProperties": true
182 }
183 }
184 },
185
160 "output": {
186 "output": {
161 "type": "object",
187 "type": "object",
162 "oneOf": [
188 "oneOf": [
@@ -249,6 +275,21 b''
249 }
275 }
250 },
276 },
251
277
278 "unrecognized_output": {
279 "description": "Unrecognized output from a future minor-revision to the notebook format.",
280 "type": "object",
281 "additionalProperties": true,
282 "required": ["output_type"],
283 "properties": {
284 "output_type": {
285 "description": "Type of cell output.",
286 "not": {
287 "enum": ["execute_result", "display_data", "stream", "error"]
288 }
289 }
290 }
291 },
292
252 "misc": {
293 "misc": {
253 "metadata_name": {
294 "metadata_name": {
254 "description": "The cell's name. If present, must be a non-empty string.",
295 "description": "The cell's name. If present, must be a non-empty string.",
@@ -30,7 +30,6 b' def _relax_additional_properties(obj):'
30 if isinstance(obj, dict):
30 if isinstance(obj, dict):
31 for key, value in obj.items():
31 for key, value in obj.items():
32 if key == 'additionalProperties':
32 if key == 'additionalProperties':
33 print(obj)
34 value = True
33 value = True
35 else:
34 else:
36 value = _relax_additional_properties(value)
35 value = _relax_additional_properties(value)
@@ -40,6 +39,15 b' def _relax_additional_properties(obj):'
40 obj[i] = _relax_additional_properties(value)
39 obj[i] = _relax_additional_properties(value)
41 return obj
40 return obj
42
41
42 def _allow_undefined(schema):
43 schema['definitions']['cell']['oneOf'].append(
44 {"$ref": "#/definitions/unrecognized_cell"}
45 )
46 schema['definitions']['output']['oneOf'].append(
47 {"$ref": "#/definitions/unrecognized_output"}
48 )
49 return schema
50
43 def get_validator(version=None, version_minor=None):
51 def get_validator(version=None, version_minor=None):
44 """Load the JSON schema into a Validator"""
52 """Load the JSON schema into a Validator"""
45 if version is None:
53 if version is None:
@@ -66,6 +74,8 b' def get_validator(version=None, version_minor=None):'
66 if current_minor < version_minor:
74 if current_minor < version_minor:
67 # notebook from the future, relax all `additionalProperties: False` requirements
75 # notebook from the future, relax all `additionalProperties: False` requirements
68 schema_json = _relax_additional_properties(schema_json)
76 schema_json = _relax_additional_properties(schema_json)
77 # and allow undefined cell types and outputs
78 schema_json = _allow_undefined(schema_json)
69
79
70 validators[version_tuple] = Validator(schema_json)
80 validators[version_tuple] = Validator(schema_json)
71 return validators[version_tuple]
81 return validators[version_tuple]
General Comments 0
You need to be logged in to leave comments. Login now