From 4b0e672ce5e6112b26a5ed42113fda628c7002ec 2011-07-29 17:15:22 From: Brian E. Granger Date: 2011-07-29 17:15:22 Subject: [PATCH] Updates to basic notebook format. * The format now handles multiple output blocks. * XML now as worksheets, cells and outputs tags. --- diff --git a/IPython/nbformat/nbbase.py b/IPython/nbformat/nbbase.py index 5bda71a..3696dc5 100644 --- a/IPython/nbformat/nbbase.py +++ b/IPython/nbformat/nbbase.py @@ -10,18 +10,13 @@ class NotebookNode(Struct): pass -def new_code_cell(input=None, prompt_number=None, output_text=None, output_png=None, +def new_output(output_type=None, output_text=None, output_png=None, output_html=None, output_svg=None, output_latex=None, output_json=None, output_javascript=None): """Create a new code cell with input and output""" - cell = NotebookNode() - cell.cell_type = 'code' - if input is not None: - cell.input = unicode(input) - if prompt_number is not None: - cell.prompt_number = int(prompt_number) - output = NotebookNode() + if output_type is not None: + output.output_type = unicode(output_type) if output_text is not None: output.text = unicode(output_text) if output_png is not None: @@ -37,16 +32,32 @@ def new_code_cell(input=None, prompt_number=None, output_text=None, output_png=N if output_javascript is not None: output.javascript = unicode(output_javascript) - cell.output = output - return cell + return output +def new_code_cell(input=None, prompt_number=None, outputs=None, language=u'python'): + """Create a new code cell with input and output""" + cell = NotebookNode() + cell.cell_type = u'code' + if language is not None: + cell.language = unicode(language) + if input is not None: + cell.input = unicode(input) + if prompt_number is not None: + cell.prompt_number = int(prompt_number) + if outputs is None: + cell.outputs = [] + else: + cell.outputs = outputs + + return cell + def new_text_cell(text=None): """Create a new text cell.""" cell = NotebookNode() if text is not None: cell.text = unicode(text) - cell.cell_type = 'text' + cell.cell_type = u'text' return cell diff --git a/IPython/nbformat/nbxml.py b/IPython/nbformat/nbxml.py index 5c854fd..2d97864 100644 --- a/IPython/nbformat/nbxml.py +++ b/IPython/nbformat/nbxml.py @@ -3,8 +3,9 @@ from xml.etree import ElementTree as ET from .rwbase import NotebookReader, NotebookWriter -from .nbbase import new_code_cell, new_text_cell, new_worksheet, new_notebook - +from .nbbase import ( + new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output +) def indent(elem, level=0): i = "\n" + level*" " @@ -30,6 +31,26 @@ def _get_text(e, tag): return sub_e.text +def _set_text(nbnode, attr, parent, tag): + if attr in nbnode: + e = ET.SubElement(parent, tag) + e.text = nbnode[attr] + + +def _get_int(e, tag): + sub_e = e.find(tag) + if sub_e is None: + return None + else: + return int(sub_e.text) + + +def _set_int(nbnode, attr, parent, tag): + if attr in nbnode: + e = ET.SubElement(parent, tag) + e.text = unicode(nbnode[attr]) + + class XMLReader(NotebookReader): def reads(self, s, **kwargs): @@ -39,14 +60,17 @@ class XMLReader(NotebookReader): nbid = _get_text(root,'id') worksheets = [] - for ws_e in root.getiterator('worksheet'): + for ws_e in root.find('worksheets').getiterator('worksheet'): wsname = _get_text(ws_e,'name') cells = [] - for cell_e in ws_e.getiterator(): + for cell_e in ws_e.find('cells').getiterator(): if cell_e.tag == 'codecell': input = _get_text(cell_e,'input') - output_e = cell_e.find('output') - if output_e is not None: + prompt_number = _get_int(cell_e,'prompt_number') + language = _get_text(cell_e,'language') + outputs = [] + for output_e in cell_e.find('outputs').getiterator('output'): + output_type = _get_text(output_e,'output_type') output_text = _get_text(output_e,'text') output_png = _get_text(output_e,'png') output_svg = _get_text(output_e,'svg') @@ -54,11 +78,14 @@ class XMLReader(NotebookReader): output_latex = _get_text(output_e,'latex') output_json = _get_text(output_e,'json') output_javascript = _get_text(output_e,'javascript') - cc = new_code_cell(input=input,output_png=output_png, - output_text=output_text,output_svg=output_svg, - output_html=output_html,output_latex=output_latex, - output_json=output_json,output_javascript=output_javascript - ) + output = new_output(output_type=output_type,output_png=output_png, + output_text=output_text,output_svg=output_svg, + output_html=output_html,output_latex=output_latex, + output_json=output_json,output_javascript=output_javascript + ) + outputs.append(output) + cc = new_code_cell(input=input,prompt_number=prompt_number, + language=language,outputs=outputs) cells.append(cc) if cell_e.tag == 'textcell': text = _get_text(cell_e,'text') @@ -74,57 +101,34 @@ class XMLWriter(NotebookWriter): def writes(self, nb, **kwargs): nb_e = ET.Element('notebook') - if 'name' in nb: - name_e = ET.SubElement(nb_e, 'name') - name_e.text = nb.name - if 'id' in nb: - id_e = ET.SubElement(nb_e, 'id') - id_e.text = nb.id + _set_text(nb,'name',nb_e,'name') + _set_text(nb,'id',nb_e,'id') + wss_e = ET.SubElement(nb_e,'worksheets') for ws in nb.worksheets: - ws_e = ET.SubElement(nb_e, 'worksheet') - if 'name' in ws: - ws_name_e = ET.SubElement(ws_e, 'name') - ws_name_e.text = ws.name + ws_e = ET.SubElement(wss_e, 'worksheet') + _set_text(ws,'name',ws_e,'name') + cells_e = ET.SubElement(ws_e,'cells') for cell in ws.cells: cell_type = cell.cell_type if cell_type == 'code': - output = cell.output - cell_e = ET.SubElement(ws_e, 'codecell') - output_e = ET.SubElement(cell_e, 'output') - - if 'input' in cell: - input_e = ET.SubElement(cell_e, 'input') - input_e.text = cell.input - if 'prompt_number' in cell: - prompt_number_e = ET.SubElement(cell_e, 'prompt_number') - input_e.text = cell.prompt_number - - if 'text' in output: - text_e = ET.SubElement(output_e, 'text') - text_e.text = output.text - if 'png' in output: - png_e = ET.SubElement(output_e, 'png') - png_e.text = output.png - if 'html' in output: - html_e = ET.SubElement(output_e, 'html') - html_e.text = output.html - if 'svg' in output: - svg_e = ET.SubElement(output_e, 'svg') - svg_e.text = output.svg - if 'latex' in output: - latex_e = ET.SubElement(output_e, 'latex') - latex_e.text = output.latex - if 'json' in output: - json_e = ET.SubElement(output_e, 'json') - json_e.text = output.json - if 'javascript' in output: - javascript_e = ET.SubElement(output_e, 'javascript') - javascript_e.text = output.javascript + cell_e = ET.SubElement(cells_e, 'codecell') + _set_text(cell,'input',cell_e,'input') + _set_text(cell,'language',cell_e,'language') + _set_int(cell,'prompt_number',cell_e,'prompt_number') + outputs_e = ET.SubElement(cell_e, 'outputs') + for output in cell.outputs: + output_e = ET.SubElement(outputs_e, 'output') + _set_text(output,'output_type',output_e,'output_type') + _set_text(output,'text',output_e,'text') + _set_text(output,'png',output_e,'png') + _set_text(output,'html',output_e,'html') + _set_text(output,'svg',output_e,'svg') + _set_text(output,'latex',output_e,'latex') + _set_text(output,'json',output_e,'json') + _set_text(output,'javascript',output_e,'javascript') elif cell_type == 'text': - cell_e = ET.SubElement(ws_e, 'textcell') - if 'text' in cell: - cell_text_e = ET.SubElement(cell_e, 'text') - cell_text_e.text = cell.text + cell_e = ET.SubElement(cells_e, 'textcell') + _set_text(cell,'text',cell_e,'text') indent(nb_e) txt = ET.tostring(nb_e, encoding="utf-8") diff --git a/IPython/nbformat/tests/nbexamples.py b/IPython/nbformat/tests/nbexamples.py index 9173701..bd6206e 100644 --- a/IPython/nbformat/tests/nbexamples.py +++ b/IPython/nbformat/tests/nbexamples.py @@ -1,6 +1,6 @@ from IPython.nbformat.nbbase import ( NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook + new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output ) @@ -13,22 +13,37 @@ ws.cells.append(new_text_cell( ws.cells.append(new_code_cell( - input='import numpy' + input='import numpy', + prompt_number=1 )) ws.cells.append(new_code_cell( - input='a = numpy.random.rand(100)' + input='a = numpy.random.rand(100)', + prompt_number=2 )) ws.cells.append(new_code_cell( input='print a', - output_text='', - output_html='The HTML rep', - output_latex='$a$', - output_png=b'data', - output_svg='', - output_json='json data', - output_javascript='var i=0;' + prompt_number=3, + outputs=[new_output( + output_type=u'pyout', + output_text=u'', + output_html=u'The HTML rep', + output_latex=u'$a$', + output_png=b'data', + output_svg=u'', + output_json=u'json data', + output_javascript=u'var i=0;' + ),new_output( + output_type=u'display_data', + output_text=u'', + output_html=u'The HTML rep', + output_latex=u'$a$', + output_png=b'data', + output_svg=u'', + output_json=u'json data', + output_javascript=u'var i=0;' + )] )) nb0 = new_notebook( diff --git a/IPython/nbformat/tests/test_nbbase.py b/IPython/nbformat/tests/test_nbbase.py index c0df3e9..875f0d2 100644 --- a/IPython/nbformat/tests/test_nbbase.py +++ b/IPython/nbformat/tests/test_nbbase.py @@ -2,7 +2,7 @@ from unittest import TestCase from IPython.nbformat.nbbase import ( NotebookNode, - new_code_cell, new_text_cell, new_worksheet, new_notebook + new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output ) class TestCell(TestCase): @@ -12,14 +12,16 @@ class TestCell(TestCase): self.assertEquals(cc.cell_type,'code') self.assertEquals('input' not in cc, True) self.assertEquals('prompt_number' not in cc, True) - self.assertEquals(cc.output, NotebookNode()) + self.assertEquals(cc.outputs, []) def test_code_cell(self): - cc = new_code_cell(input='a=10', prompt_number=0, output_svg='foo', output_text='10') + cc = new_code_cell(input='a=10', prompt_number=0) + cc.outputs = [new_output(output_type='pyout',output_svg='foo',output_text='10')] self.assertEquals(cc.input, u'a=10') self.assertEquals(cc.prompt_number, 0) - self.assertEquals(cc.output.svg, u'foo') - self.assertEquals(cc.output.text, u'10') + self.assertEquals(cc.language, u'python') + self.assertEquals(cc.outputs[0].svg, u'foo') + self.assertEquals(cc.outputs[0].text, u'10') def test_empty_text_cell(self): tc = new_text_cell() diff --git a/IPython/nbformat/tests/test_xml.py b/IPython/nbformat/tests/test_xml.py index 04afba4..0a1a660 100644 --- a/IPython/nbformat/tests/test_xml.py +++ b/IPython/nbformat/tests/test_xml.py @@ -2,11 +2,17 @@ from unittest import TestCase from IPython.nbformat.nbxml import reads, writes from IPython.nbformat.tests.nbexamples import nb0 - +import pprint class TestXML(TestCase): def test_roundtrip(self): s = writes(nb0) +# print +# print pprint.pformat(nb0,indent=2) +# print +# print pprint.pformat(reads(s),indent=2) +# print +# print s self.assertEquals(reads(s),nb0) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 12149c8..c1b69ec 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -299,7 +299,7 @@ def make_runners(): # Packages to be tested via nose, that only depend on the stdlib nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib', - 'scripts', 'testing', 'utils' ] + 'scripts', 'testing', 'utils', 'nbformat' ] if have['zmq']: nose_pkg_names.append('parallel') diff --git a/setupbase.py b/setupbase.py index ba83d52..2868103 100644 --- a/setupbase.py +++ b/setupbase.py @@ -126,6 +126,7 @@ def find_packages(): add_package(packages, 'frontend.qt.console', tests=True) add_package(packages, 'frontend.terminal', tests=True) add_package(packages, 'lib', tests=True) + add_package(packages, 'nbformat', tests=True) add_package(packages, 'parallel', tests=True, scripts=True, others=['apps','engine','client','controller']) add_package(packages, 'quarantine', tests=True)