Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented metadata for notebook format.

  • Loading branch information...
commit d919e2ec7d2631751fb3b60c2d0d22de351c7a7c 1 parent 33e3025
@ellisonbg ellisonbg authored
Showing with 185 additions and 149 deletions.
  1. +4 −4 IPython/frontend/html/notebook/notebookmanager.py
  2. +7 −3 IPython/frontend/html/notebook/static/js/notebook.js
  3. +33 −20 IPython/nbformat/current.py
  4. +4 −3 IPython/nbformat/v2/__init__.py
  5. +36 −13 IPython/nbformat/v2/nbbase.py
  6. +1 −65 IPython/nbformat/v2/nbxml.py
  7. +8 −7 IPython/nbformat/v2/tests/nbexamples.py
  8. +39 −15 IPython/nbformat/v2/tests/test_nbbase.py
  9. +3 −1 docs/examples/newparallel/helloworld.ipynb
  10. +3 −1 docs/examples/newparallel/options/mcpricer.ipynb
  11. +3 −1 docs/examples/newparallel/rmt/rmt.ipynb
  12. +3 −1 docs/examples/newparallel/task1.ipynb
  13. +3 −1 docs/examples/newparallel/taskmap.ipynb
  14. +5 −3 docs/examples/notebooks/basic_quantum.ipynb
  15. +3 −1 docs/examples/notebooks/decompose.ipynb
  16. +3 −1 docs/examples/notebooks/dense_coding.ipynb
  17. +3 −1 docs/examples/notebooks/formatting.ipynb
  18. +3 −1 docs/examples/notebooks/grovers.ipynb
  19. +3 −1 docs/examples/notebooks/qerror.ipynb
  20. +3 −1 docs/examples/notebooks/qft.ipynb
  21. +3 −1 docs/examples/notebooks/quantum_computing.ipynb
  22. +3 −1 docs/examples/notebooks/smooth_dos.ipynb
  23. +3 −1 docs/examples/notebooks/sympy.ipynb
  24. +3 −1 docs/examples/notebooks/teleportation.ipynb
  25. +3 −1 docs/examples/notebooks/text_analysis.ipynb
View
8 IPython/frontend/html/notebook/notebookmanager.py
@@ -147,10 +147,10 @@ def save_new_notebook(self, data, name=None, format=u'json'):
if name is None:
try:
- name = nb.name
+ name = nb.metadata.name
except AttributeError:
raise web.HTTPError(400)
- nb.name = name
+ nb.metadata.name = name
notebook_id = self.new_notebook_id(name)
self.save_notebook_object(notebook_id, nb)
@@ -167,7 +167,7 @@ def save_notebook(self, notebook_id, data, name=None, format=u'json'):
raise web.HTTPError(400)
if name is not None:
- nb.name = name
+ nb.metadata.name = name
self.save_notebook_object(notebook_id, nb)
def save_notebook_object(self, notebook_id, nb):
@@ -176,7 +176,7 @@ def save_notebook_object(self, notebook_id, nb):
raise web.HTTPError(404)
old_name = self.mapping[notebook_id]
try:
- new_name = nb.name
+ new_name = nb.metadata.name
except AttributeError:
raise web.HTTPError(400)
path = self.get_path_by_name(new_name)
View
10 IPython/frontend/html/notebook/static/js/notebook.js
@@ -21,6 +21,7 @@ var IPython = (function (IPython) {
this.kernel = null;
this.dirty = false;
this.msg_cell_map = {};
+ this.metadata = {};
this.style();
this.create_elements();
this.bind_events();
@@ -711,6 +712,8 @@ var IPython = (function (IPython) {
// Always delete cell 0 as they get renumbered as they are deleted.
this.delete_cell(0);
};
+ // Save the metadata
+ this.metadata = data.metadata;
// Only handle 1 worksheet for now.
var worksheet = data.worksheets[0];
if (worksheet !== undefined) {
@@ -744,7 +747,8 @@ var IPython = (function (IPython) {
};
data = {
// Only handle 1 worksheet for now.
- worksheets : [{cells:cell_array}]
+ worksheets : [{cells:cell_array}],
+ metadata : this.metadata
}
return data
};
@@ -755,7 +759,7 @@ var IPython = (function (IPython) {
var nbname = IPython.save_widget.get_notebook_name();
// We may want to move the name/id/nbformat logic inside toJSON?
var data = this.toJSON();
- data.name = nbname;
+ data.metadata.name = nbname;
data.nbformat = 2;
// We do the call with settings so we can set cache to false.
var settings = {
@@ -805,7 +809,7 @@ var IPython = (function (IPython) {
this.insert_code_cell_after();
};
IPython.save_widget.status_save();
- IPython.save_widget.set_notebook_name(data.name);
+ IPython.save_widget.set_notebook_name(data.metadata.name);
this.start_kernel();
this.dirty = false;
// fromJSON always selects the last cell inserted. We need to wait
View
53 IPython/nbformat/current.py
@@ -16,6 +16,7 @@
# Imports
#-----------------------------------------------------------------------------
+from __future__ import print_function
import json
from xml.etree import ElementTree as ET
import re
@@ -26,7 +27,7 @@
from IPython.nbformat.v2 import (
NotebookNode,
new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet,
- parse_filename
+ parse_filename, new_metadata, new_author
)
#-----------------------------------------------------------------------------
@@ -96,10 +97,6 @@ def reads_xml(s, **kwargs):
return nb
-def writes_xml(nb, **kwargs):
- return v2.writes_xml(nb, **kwargs)
-
-
def reads_py(s, **kwargs):
"""Read a .py notebook from a string and return the NotebookNode object."""
nbformat, s = parse_py(s, **kwargs)
@@ -125,9 +122,9 @@ def reads(s, format, **kwargs):
Parameters
----------
- s : str
- The raw string to read the notebook from.
- format : ('json','py')
+ s : unicode
+ The raw unicode string to read the notebook from.
+ format : (u'json', u'ipynb', u'py')
The format that the string is in.
Returns
@@ -135,11 +132,12 @@ def reads(s, format, **kwargs):
nb : NotebookNode
The notebook that was read.
"""
- if format == 'xml':
+ format = unicode(format)
+ if format == u'xml':
return reads_xml(s, **kwargs)
- elif format == 'json':
+ elif format == u'json' or format == u'ipynb':
return reads_json(s, **kwargs)
- elif format == 'py':
+ elif format == u'py':
return reads_py(s, **kwargs)
else:
raise NBFormatError('Unsupported format: %s' % format)
@@ -154,19 +152,20 @@ def writes(nb, format, **kwargs):
----------
nb : NotebookNode
The notebook to write.
- format : ('json','py')
+ format : (u'json', u'ipynb', u'py')
The format to write the notebook in.
Returns
-------
- s : str
+ s : unicode
The notebook string.
"""
- if format == 'xml':
- return writes_xml(nb, **kwargs)
- elif format == 'json':
+ format = unicode(format)
+ if format == u'xml':
+ raise NotImplementedError('Write to XML files is not implemented.')
+ elif format == u'json' or format == u'ipynb':
return writes_json(nb, **kwargs)
- elif format == 'py':
+ elif format == u'py':
return writes_py(nb, **kwargs)
else:
raise NBFormatError('Unsupported format: %s' % format)
@@ -182,7 +181,7 @@ def read(fp, format, **kwargs):
----------
fp : file
Any file-like object with a read method.
- format : ('json','py')
+ format : (u'json', u'ipynb', u'py')
The format that the string is in.
Returns
@@ -204,14 +203,28 @@ def write(nb, fp, format, **kwargs):
The notebook to write.
fp : file
Any file-like object with a write method.
- format : ('json','py')
+ format : (u'json', u'ipynb', u'py')
The format to write the notebook in.
Returns
-------
- s : str
+ s : unicode
The notebook string.
"""
return fp.write(writes(nb, format, **kwargs))
+def _convert_to_metadata():
+ """Convert to a notebook having notebook metadata."""
+ import glob
+ for fname in glob.glob('*.ipynb'):
+ print('Converting file:',fname)
+ with open(fname,'r') as f:
+ nb = read(f,u'json')
+ md = new_metadata()
+ if u'name' in nb:
+ md.name = nb.name
+ del nb[u'name']
+ nb.metadata = md
+ with open(fname,'w') as f:
+ write(nb, f, u'json')
View
7 IPython/nbformat/v2/__init__.py
@@ -18,15 +18,16 @@
from .nbbase import (
NotebookNode,
- new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet
+ new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet,
+ new_metadata, new_author
)
from .nbjson import reads as reads_json, writes as writes_json
from .nbjson import reads as read_json, writes as write_json
from .nbjson import to_notebook as to_notebook_json
-from .nbxml import reads as reads_xml, writes as writes_xml
-from .nbxml import reads as read_xml, writes as write_xml
+from .nbxml import reads as reads_xml
+from .nbxml import reads as read_xml
from .nbxml import to_notebook as to_notebook_xml
from .nbpy import reads as reads_py, writes as writes_py
View
49 IPython/nbformat/v2/nbbase.py
@@ -131,26 +131,49 @@ def new_worksheet(name=None, cells=None):
return ws
-def new_notebook(name=None, worksheets=None, author=None, email=None,
- created=None, saved=None, license=None):
+def new_notebook(metadata=None, worksheets=None):
"""Create a notebook by name, id and a list of worksheets."""
nb = NotebookNode()
nb.nbformat = 2
- if name is not None:
- nb.name = unicode(name)
if worksheets is None:
nb.worksheets = []
else:
nb.worksheets = list(worksheets)
- if author is not None:
- nb.author = unicode(author)
- if email is not None:
- nb.email = unicode(email)
+ if metadata is None:
+ nb.metadata = new_metadata()
+ else:
+ nb.metadata = NotebookNode(metadata)
+ return nb
+
+
+def new_metadata(name=None, authors=None, license=None, created=None,
+ modified=None, gistid=None):
+ """Create a new metadata node."""
+ metadata = NotebookNode()
+ if name is not None:
+ metadata.name = unicode(name)
+ if authors is not None:
+ metadata.authors = list(authors)
if created is not None:
- nb.created = unicode(created)
- if saved is not None:
- nb.saved = unicode(saved)
+ metadata.created = unicode(created)
+ if modified is not None:
+ metadata.modified = unicode(modified)
if license is not None:
- nb.license = unicode(license)
- return nb
+ metadata.license = unicode(license)
+ if gistid is not None:
+ metadata.gistid = unicode(gistid)
+ return metadata
+
+def new_author(name=None, email=None, affiliation=None, url=None):
+ """Create a new author."""
+ author = NotebookNode()
+ if name is not None:
+ author.name = unicode(name)
+ if email is not None:
+ author.email = unicode(email)
+ if affiliation is not None:
+ author.affiliation = unicode(affiliation)
+ if url is not None:
+ author.url = unicode(url)
+ return author
View
66 IPython/nbformat/v2/nbxml.py
@@ -178,74 +178,10 @@ def to_notebook(self, root, **kwargs):
email=nbemail,license=nblicense,saved=nbsaved,created=nbcreated)
return nb
-
-class XMLWriter(NotebookWriter):
-
- def writes(self, nb, **kwargs):
- warnings.warn('The XML notebook format is no longer supported, '
- 'please convert your notebooks to JSON.', DeprecationWarning)
- nb_e = ET.Element(u'notebook')
- _set_text(nb,u'name',nb_e,u'name')
- _set_text(nb,u'author',nb_e,u'author')
- _set_text(nb,u'email',nb_e,u'email')
- _set_text(nb,u'license',nb_e,u'license')
- _set_text(nb,u'created',nb_e,u'created')
- _set_text(nb,u'saved',nb_e,u'saved')
- _set_int(nb,u'nbformat',nb_e,u'nbformat')
- wss_e = ET.SubElement(nb_e,u'worksheets')
- for ws in nb.worksheets:
- ws_e = ET.SubElement(wss_e, u'worksheet')
- _set_text(ws,u'name',ws_e,u'name')
- cells_e = ET.SubElement(ws_e,u'cells')
- for cell in ws.cells:
- cell_type = cell.cell_type
- if cell_type == u'code':
- cell_e = ET.SubElement(cells_e, u'codecell')
- _set_text(cell,u'input',cell_e,u'input')
- _set_text(cell,u'language',cell_e,u'language')
- _set_int(cell,u'prompt_number',cell_e,u'prompt_number')
- _set_bool(cell,u'collapsed',cell_e,u'collapsed')
- outputs_e = ET.SubElement(cell_e, u'outputs')
- for output in cell.outputs:
- output_e = ET.SubElement(outputs_e, u'output')
- _set_text(output,u'output_type',output_e,u'output_type')
- _set_text(output,u'text',output_e,u'text')
- _set_binary(output,u'png',output_e,u'png')
- _set_binary(output,u'jpeg',output_e,u'jpeg')
- _set_text(output,u'html',output_e,u'html')
- _set_text(output,u'svg',output_e,u'svg')
- _set_text(output,u'latex',output_e,u'latex')
- _set_text(output,u'json',output_e,u'json')
- _set_text(output,u'javascript',output_e,u'javascript')
- _set_int(output,u'prompt_number',output_e,u'prompt_number')
- _set_text(output,u'etype',output_e,u'etype')
- _set_text(output,u'evalue',output_e,u'evalue')
- if u'traceback' in output:
- tb_e = ET.SubElement(output_e, u'traceback')
- for frame in output.traceback:
- frame_e = ET.SubElement(tb_e, u'frame')
- frame_e.text = frame
- elif cell_type == u'html':
- cell_e = ET.SubElement(cells_e, u'htmlcell')
- _set_text(cell,u'source',cell_e,u'source')
- _set_text(cell,u'rendered',cell_e,u'rendered')
- elif cell_type == u'markdown':
- cell_e = ET.SubElement(cells_e, u'markdowncell')
- _set_text(cell,u'source',cell_e,u'source')
- _set_text(cell,u'rendered',cell_e,u'rendered')
-
- indent(nb_e)
- txt = ET.tostring(nb_e, encoding="utf-8")
- txt = '<?xml version="1.0" encoding="utf-8"?>\n' + txt
- return txt
-
-
+
_reader = XMLReader()
-_writer = XMLWriter()
reads = _reader.reads
read = _reader.read
to_notebook = _reader.to_notebook
-write = _writer.write
-writes = _writer.writes
View
15 IPython/nbformat/v2/tests/nbexamples.py
@@ -1,6 +1,7 @@
from ..nbbase import (
NotebookNode,
- new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
+ new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
+ new_metadata, new_author
)
@@ -65,14 +66,14 @@
)]
))
+authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com',
+ affiliation=u'Fox',url=u'http://www.fox.com')]
+md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here',
+ modified=u'8601_goes_here',gistid=u'21341231',authors=authors)
+
nb0 = new_notebook(
- name='nb0',
worksheets=[ws, new_worksheet(name='worksheet2')],
- author='Bart Simpson',
- email='bsimpson@fox.com',
- saved='ISO8601_goes_here',
- created='ISO8601_goes_here',
- license='BSD'
+ metadata=md
)
nb0_py = """# <nbformat>2</nbformat>
View
54 IPython/nbformat/v2/tests/test_nbbase.py
@@ -2,23 +2,24 @@
from ..nbbase import (
NotebookNode,
- new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
+ new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
+ new_author, new_metadata
)
class TestCell(TestCase):
def test_empty_code_cell(self):
cc = new_code_cell()
- self.assertEquals(cc.cell_type,'code')
- self.assertEquals('input' not in cc, True)
- self.assertEquals('prompt_number' not in cc, True)
+ self.assertEquals(cc.cell_type,u'code')
+ self.assertEquals(u'input' not in cc, True)
+ self.assertEquals(u'prompt_number' not in cc, True)
self.assertEquals(cc.outputs, [])
self.assertEquals(cc.collapsed, False)
def test_code_cell(self):
cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
- cc.outputs = [new_output(output_type='pyout',
- output_svg='foo',output_text='10',prompt_number=0)]
+ cc.outputs = [new_output(output_type=u'pyout',
+ output_svg=u'foo',output_text=u'10',prompt_number=0)]
self.assertEquals(cc.input, u'a=10')
self.assertEquals(cc.prompt_number, 0)
self.assertEquals(cc.language, u'python')
@@ -39,8 +40,8 @@ def test_pyerr(self):
def test_empty_html_cell(self):
tc = new_text_cell(u'html')
self.assertEquals(tc.cell_type, u'html')
- self.assertEquals('source' not in tc, True)
- self.assertEquals('rendered' not in tc, True)
+ self.assertEquals(u'source' not in tc, True)
+ self.assertEquals(u'rendered' not in tc, True)
def test_html_cell(self):
tc = new_text_cell(u'html', 'hi', 'hi')
@@ -50,8 +51,8 @@ def test_html_cell(self):
def test_empty_markdown_cell(self):
tc = new_text_cell(u'markdown')
self.assertEquals(tc.cell_type, u'markdown')
- self.assertEquals('source' not in tc, True)
- self.assertEquals('rendered' not in tc, True)
+ self.assertEquals(u'source' not in tc, True)
+ self.assertEquals(u'rendered' not in tc, True)
def test_markdown_cell(self):
tc = new_text_cell(u'markdown', 'hi', 'hi')
@@ -64,11 +65,11 @@ class TestWorksheet(TestCase):
def test_empty_worksheet(self):
ws = new_worksheet()
self.assertEquals(ws.cells,[])
- self.assertEquals('name' not in ws, True)
+ self.assertEquals(u'name' not in ws, True)
def test_worksheet(self):
cells = [new_code_cell(), new_text_cell(u'html')]
- ws = new_worksheet(cells=cells,name='foo')
+ ws = new_worksheet(cells=cells,name=u'foo')
self.assertEquals(ws.cells,cells)
self.assertEquals(ws.name,u'foo')
@@ -77,13 +78,36 @@ class TestNotebook(TestCase):
def test_empty_notebook(self):
nb = new_notebook()
self.assertEquals(nb.worksheets, [])
- self.assertEquals('name' not in nb, True)
+ self.assertEquals(nb.metadata, NotebookNode())
self.assertEquals(nb.nbformat,2)
def test_notebook(self):
worksheets = [new_worksheet(),new_worksheet()]
- nb = new_notebook(name='foo',worksheets=worksheets)
- self.assertEquals(nb.name,u'foo')
+ metadata = new_metadata(name=u'foo')
+ nb = new_notebook(metadata=metadata,worksheets=worksheets)
+ self.assertEquals(nb.metadata.name,u'foo')
self.assertEquals(nb.worksheets,worksheets)
self.assertEquals(nb.nbformat,2)
+class TestMetadata(TestCase):
+
+ def test_empty_metadata(self):
+ md = new_metadata()
+ self.assertEquals(u'name' not in md, True)
+ self.assertEquals(u'authors' not in md, True)
+ self.assertEquals(u'license' not in md, True)
+ self.assertEquals(u'saved' not in md, True)
+ self.assertEquals(u'modified' not in md, True)
+ self.assertEquals(u'gistid' not in md, True)
+
+ def test_metadata(self):
+ authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')]
+ md = new_metadata(name=u'foo',license=u'BSD',created=u'today',
+ modified=u'now',gistid=u'21341231',authors=authors)
+ self.assertEquals(md.name, u'foo')
+ self.assertEquals(md.license, u'BSD')
+ self.assertEquals(md.created, u'today')
+ self.assertEquals(md.modified, u'now')
+ self.assertEquals(md.gistid, u'21341231')
+ self.assertEquals(md.authors, authors)
+
View
4 docs/examples/newparallel/helloworld.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "helloworld",
+ "metadata": {
+ "name": "helloworld"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/newparallel/options/mcpricer.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "mcpricer",
+ "metadata": {
+ "name": "mcpricer"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/newparallel/rmt/rmt.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "rmt",
+ "metadata": {
+ "name": "rmt"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/newparallel/task1.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "task_1",
+ "metadata": {
+ "name": "task_1"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/newparallel/taskmap.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "taskmap",
+ "metadata": {
+ "name": "taskmap"
+ },
"worksheets": [
{
"cells": [
View
8 docs/examples/notebooks/basic_quantum.ipynb
@@ -1,6 +1,4 @@
{
- "nbformat": 2,
- "name": "basic_quantum",
"worksheets": [
{
"cells": [
@@ -276,5 +274,9 @@
}
]
}
- ]
+ ],
+ "metadata": {
+ "name": "basic_quantum"
+ },
+ "nbformat": 2
}
View
4 docs/examples/notebooks/decompose.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "decompose",
+ "metadata": {
+ "name": "decompose"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/dense_coding.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "dense_coding",
+ "metadata": {
+ "name": "dense_coding"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/formatting.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "formatting",
+ "metadata": {
+ "name": "formatting"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/grovers.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "grovers",
+ "metadata": {
+ "name": "grovers"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/qerror.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "qerror",
+ "metadata": {
+ "name": "qerror"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/qft.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "qft",
+ "metadata": {
+ "name": "qft"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/quantum_computing.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "quantum_computing",
+ "metadata": {
+ "name": "quantum_computing"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/smooth_dos.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "dos",
+ "metadata": {
+ "name": "dos"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/sympy.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "sympy",
+ "metadata": {
+ "name": "sympy"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/teleportation.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "teleportation",
+ "metadata": {
+ "name": "teleportation"
+ },
"worksheets": [
{
"cells": [
View
4 docs/examples/notebooks/text_analysis.ipynb
@@ -1,6 +1,8 @@
{
"nbformat": 2,
- "name": "text_analysis",
+ "metadata": {
+ "name": "text_analysis"
+ },
"worksheets": [
{
"cells": [
Please sign in to comment.
Something went wrong with that request. Please try again.