From 7b36574cd5fbd83cf2cc07dd1f2c719bba13f585 2012-10-03 15:23:43 From: Matthias BUSSONNIER Date: 2012-10-03 15:23:43 Subject: [PATCH] create a ipynbv3 json schema and a validator cf http://json-schema.org/ http://tools.ietf.org/html/draft-zyp-json-schema-03 autogenerated from http://www.jsonschema.net/index.html# then tweeked. This version makes all our notedooks in docs/example/notebooks valid --- diff --git a/IPython/nbformat/v3/v3.withref.json b/IPython/nbformat/v3/v3.withref.json new file mode 100644 index 0000000..cc0031a --- /dev/null +++ b/IPython/nbformat/v3/v3.withref.json @@ -0,0 +1,166 @@ +{ + "description": "custom json structure with references to generate notebook schema", + "notebook":{ + "type": "object", + "description": "notebook v3.0 root schema", + "$schema": "http://json-schema.org/draft-03/schema", + "id": "#notebook", + "required": true, + "additionalProperties": false, + "properties":{ + "metadata": { + "type": "object", + "id": "metadata", + "required": true, + "description": "the metadata atribute can contain any additionnal information", + "additionalProperties": true, + "properties":{ + "name": { + "id": "name", + "description": "the title of the notebook", + "type": "string", + "id": "name", + "required": true + } + } + }, + "nbformat_minor": { + "description": "Notebook format, minor number. Incremented for slight variation of notebook format.", + "type": "number", + "id": "nbformat_minor", + "required": true + }, + "nbformat": { + "description": "Notebook format, major number. Incremented between backward incompatible change is introduced.", + "type": "number", + "id": "nbformat", + "required": true + }, + "worksheets": { + "description": "Array of worksheet, not used by the current implementation of ipython yet", + "type": "array", + "id": "worksheets", + "required": true, + "items": {"$ref": "/worksheet"} + } + } + }, + + "worksheet": { + "additionalProperties": false, + "properties":{ + "cells": { + "type": "array", + "$schema": "http://json-schema.org/draft-03/schema", + "description": "array of cells of the current worksheet", + "id": "#cells", + "required": true, + "items": {"$ref": "/any_cell"} + + }, + "metadata": { + "type": "object", + "description": "metadata of the current worksheet", + "id": "metadata", + "required": true + } + } + }, + + "text_cell": { + "type": "object", + "description": "scheme for text cel and childrenm (level only optionnal argument for HEader cell)", + "$schema": "http://json-schema.org/draft-03/schema", + "id": "#cell", + "required": true, + "additionalProperties": false, + "properties":{ + "cell_type": { + "type": "string", + "id": "cell_type", + "required": true + }, + "level": { + "type": "number", + "id": "level", + "required": false + }, + "metadata": { + "type": "object", + "id": "metadata", + "required": true + }, + "source": { + "description": "for code cell, the source code", + "type": "array", + "id": "source", + "required": true, + "items": + { + "type": "string", + "description": "each item represent one line of the source code written, terminated by \n", + "id": "0", + "required": true + } + } + } + + }, + + "any_cell": { + "description": "Meta cell type that match any cell type", + "type": [{"$ref": "/text_cell"},{"$ref":"/code_cell"}], + "$schema": "http://json-schema.org/draft-03/schema" + }, + + "code_cell":{ + "type": "object", + "$schema": "http://json-schema.org/draft-03/schema", + "description": "Cell used to execute code", + "id": "#cell", + "required": true, + "additionalProperties": false, + "properties":{ + "cell_type": { + "type": "string", + "id": "cell_type", + "required": true + }, + "metadata": { + "type": "object", + "id": "metadata", + "required": true + }, + "collapsed": { + "type": "boolean", + "required": true + }, + "input": { + "description": "user input for text cells", + "type": "array", + "id": "input", + "required": true, + "items": + { + "type": "string", + "id": "input", + "required": true + } + }, + "outputs": { + "description": "output for code cell, to be definied", + "required": true, + "type": "array" + }, + "prompt_number": { + "type": ["number","string"], + "minimum": 0 + }, + "language": { + "type": "string", + "required": true + } + } + + } +} diff --git a/IPython/nbformat/v3/validator.py b/IPython/nbformat/v3/validator.py new file mode 100755 index 0000000..d739edf --- /dev/null +++ b/IPython/nbformat/v3/validator.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# -*- coding: utf8 -*- + +from jsonschema import Validator, validate, ValidationError +import jsonpointer +import argparse +import traceback +import json + +v = Validator(); +def nbvalidate(nbjson, schema='v3.withref.json', key=None,verbose=True): + v3schema = resolve_ref(json.load(open(schema,'r'))) + if key : + v3schema = jsonpointer.resolve_pointer(v3schema,key) + errors = 0 + for error in v.iter_errors(nbjson, v3schema): + errors = errors + 1 + if verbose: + print(error) + return errors + +def resolve_ref(json, base=None): + """return a json with resolved internal references + + only support local reference to the same json + """ + if not base : + base = json + + temp = None + if type(json) is list: + temp = []; + for item in json: + temp.append(resolve_ref(item, base=base)) + elif type(json) is dict: + temp = {}; + for key,value in json.iteritems(): + if key == '$ref': + return resolve_ref(jsonpointer.resolve_pointer(base,value), base=base) + else : + temp[key]=resolve_ref(value, base=base) + else : + return json + return temp + +def convert(namein, nameout, indent=2): + """resolve the references of namein, save the result in nameout""" + jsn = None + with open(namein) as file : + jsn = json.load(file) + v = resolve_ref(jsn, base=jsn) + x = jsonpointer.resolve_pointer(v, '/notebook') + with open(nameout,'w') as file: + json.dump(x,file,indent=indent) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-s', '--schema', + type=str, default='v3.withref.json') + + parser.add_argument('-k', '--key', + type=str, default='/notebook', + help='subkey to extract json schema from json file') + + parser.add_argument("-v", "--verbose", action="store_true", + help="increase output verbosity") + + parser.add_argument('filename', + type=str, + help="file to validate", + nargs='*', + metavar='names') + + args = parser.parse_args() + for name in args.filename : + nerror = nbvalidate(json.load(open(name,'r')), + schema=args.schema, + key=args.key, + verbose=args.verbose) + if nerror is 0: + print u"[Pass]",name + else : + print u"[ ]",name,'(%d)'%(nerror) + if args.verbose : + print '==================================================' + +